Skip to content

Fix state mutation bug in Get-AutotaskAPIResource#75

Open
BackupNerd wants to merge 2 commits intoKelvinTegelaar:masterfrom
BackupNerd:fix/state-mutation-get-resource
Open

Fix state mutation bug in Get-AutotaskAPIResource#75
BackupNerd wants to merge 2 commits intoKelvinTegelaar:masterfrom
BackupNerd:fix/state-mutation-get-resource

Conversation

@BackupNerd
Copy link

Pull Request: Fix State Mutation Bug in Get-AutotaskAPIResource

Summary

Fixes a critical bug where Get-AutotaskAPIResource mutates the global $Script:Queries table, causing subsequent calls to New-AutotaskAPIResource to fail with HTTP 404 errors.

Problem

Symptom

New-AutotaskAPIResource -Resource Products fails with 404 error after calling Get-AutotaskAPIResource -Resource Products.

Root Cause

In Get-AutotaskAPIResource.ps1 line 57, the code directly modifies the $Script:Queries table:

$ResourceURL = @(($Script:Index[$resource] | Where-Object { $_.Get -eq $resource }))[0]
$ResourceURL.name = $ResourceURL.name.replace("/query", "/{PARENTID}")  # BUG: Mutates shared state!

This changes the global Name property from /V1.0/Products/query to /V1.0/Products/{PARENTID} permanently.

When New-AutotaskAPIResource later queries the same table:

$ResourceURL = (($Script:Queries | Where-Object { $_.'Post' -eq $Resource }).Name | Select-Object -first 1)

It now selects /V1.0/Products/{PARENTID} (first match) instead of /V1.0/Products/query, which after -replace '/query', '' results in an invalid endpoint.

Impact

  • Severity: High - Core POST functionality broken after any GET operation
  • Affected Resources: All resources with /query endpoints
  • Reproducibility: 100% - Happens every time GET is called before POST

Solution

Clone the object before modification instead of mutating the shared reference:

$ResourceURL = @(($Script:Index[$resource] | Where-Object { $_.Get -eq $resource }))[0]
# BUGFIX: Clone the object instead of mutating the global $Script:Queries table
$ResourceURL = [PSCustomObject]@{
    Index  = $ResourceURL.Index
    Name   = $ResourceURL.Name.replace("/query", "/{PARENTID}")
    Get    = $ResourceURL.Get
    Post   = $ResourceURL.Post
    Patch  = $ResourceURL.Patch
    Delete = $ResourceURL.Delete
}

Testing

Test Case 1: Verify No Table Corruption

# Before fix: Table gets corrupted
Get-AutotaskAPIResource -Resource Products  # Mutates $Script:Queries
New-AutotaskAPIResource -Resource Products  # Fails with 404

# After fix: Table unchanged
Get-AutotaskAPIResource -Resource Products  # No mutation
New-AutotaskAPIResource -Resource Products  # Works correctly

Test Results

  • $Script:Queries table unchanged after GET operations
  • ✅ POST operations succeed after GET operations
  • ✅ All existing functionality preserved

See Test-ModuleFix.ps1 for complete test suite.

Files Changed

  • Public/Get-AutotaskAPIResource.ps1 (lines 53-62)

Backward Compatibility

This fix has no breaking changes:

  • All existing GET operations work identically
  • All existing POST/PATCH/DELETE operations work identically
  • Only difference: Shared state is no longer mutated (correct behavior)

Additional Notes

This same pattern may exist in other cmdlets. Recommend audit of:

  • Set-AutotaskAPIResource.ps1
  • Remove-AutotaskAPIResource.ps1
  • New-AutotaskBody.ps1

Any code that modifies $Script:Queries entries should clone before mutation.


Verification Steps for Reviewer

  1. Clone repository
  2. Apply this PR
  3. Run Test-ModuleFix.ps1
  4. Verify all tests pass
  5. Expected output:
    ✓ No corruption - table unchanged (FIX WORKING!)
    ✓ Product created successfully - ID: [number]
    ✓ ALL TESTS PASSED - MODULE FIX VERIFIED!
    

Issue: State mutation causing 404 errors in New-AutotaskAPIResource
Fix: Clone objects instead of mutating shared $Script:Queries table
Risk: Low - Identical behavior, better isolation
Testing: Comprehensive test suite included

- Fixed line 57 which mutated global $Script:Queries table
- Changed from direct property mutation to object cloning
- Prevents POST operations from failing with 404 after GET calls
- Affects all resources with /query endpoints (Products, etc.)
- Backward compatible - identical behavior without side effects
- Includes comprehensive test suite (Test-ModuleFix.ps1)
- Test-ModuleFix.ps1 validates the bug fix
- Tests verify $Script:Queries table remains unchanged after GET
- Tests confirm POST operations succeed after GET operations
- Includes before/after comparison of Queries table
- All tests passed (product ID 29683482 created successfully)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant