Skip to content

AzLocal.UpdateManagement v0.8.77: fix two production strict-mode crashes (Step.05/06/07)#83

Merged
NeilBird merged 1 commit into
mainfrom
users/nebird/development
Jun 14, 2026
Merged

AzLocal.UpdateManagement v0.8.77: fix two production strict-mode crashes (Step.05/06/07)#83
NeilBird merged 1 commit into
mainfrom
users/nebird/development

Conversation

@NeilBird

Copy link
Copy Markdown
Owner

Summary

Patch release. Fixes two production strict-mode crashes that surfaced in Step.05 / Step.06 / Step.07 of the bundled apply-updates pipelines. Both bugs share the same root cause: bare $obj.Prop property access under Set-StrictMode -Version Latest throws when Prop is absent on a PSCustomObject instead of returning $null.

Resolves no open issue (regressions found by live customer production traces, not filed).

What changed

Bug 1 - Start-AzLocalClusterUpdate (Step.07 main entry)

Production emitted Error processing cluster '<Name>': The property 'UpdateStartWindow' cannot be found on this object. for clusters whose tag bag did not include UpdateStartWindow / UpdateExclusionsWindow. The old if ($clusterTags -and $clusterTags.$($script:UpdateStartWindowTagName)) threw before -and short-circuited because bare .$() member access on a missing PSCustomObject property is strict-mode-fatal.

Fix: branch on $clusterTags -is [System.Collections.IDictionary] and use .Contains() for hashtables / PSObject.Properties[...] for PSCustomObject tag bags. The semantic intent ("absent = any time eligible / no window restriction") is preserved: the outer if ($windowTagValue -or $exclusionTagValue) correctly skips the schedule gate when both are $null.

Bug 2 - Test-AzLocalClusterHealth (Step.05/06 readiness gate)

Production emitted Checking: <Cluster>... Error: The property 'healthCheckResult' cannot be found on this object. for clusters whose ARM update summary genuinely had no healthCheckResult field (typical for clusters not yet probed). The catch block then flagged the cluster HealthState=Error / Passed=$false, and the readiness gate falsely treated it as blocked, poisoning Step.5 / Step.7 / Step.9 readiness output. The same bare-access pattern was present in Get-HealthCheckFailureSummary (Private helper) and Get-AzLocalFleetStatusData (Public, -IncludeHealthDetails).

Fix: all three sites now use the PSObject.Properties[...] guard; Test-AzLocalClusterHealth correctly classifies such clusters as HealthState="No Data" / Passed=$true and continues.

Tests

Two new Pester regression contexts feed the minimal real-world property-less shapes and assert Should -Not -Throw plus the correct downstream classification. Both bugs were invisible to parse-time analysis - only runtime against the property-less shape triggers the strict-mode throw.

Total: 1143  Passed: 1142  Failed: 0  Skipped: 1  Duration: 00:01:47

Pipeline templates

GENERATED_AGAINST_MODULE_VERSION bumped from '0.8.76' to '0.8.77' across all 22 bundled pipeline templates (11 github-actions + 11 azure-devops).

API surface

No public API change or new exports (still 60).

See CHANGELOG.md for the full v0.8.77 entry.

…hes (Step.05/06/07)

Patch release. Both bugs share the same root cause: bare `$obj.Prop` property
access under `Set-StrictMode -Version Latest` THROWS when `Prop` is absent on
a PSCustomObject instead of returning $null. Fixes use the
`$obj.PSObject.Properties['Prop'] -and $obj.Prop` guard idiom (and
`IDictionary.Contains()` for tag bags returned by Invoke-AzRestJson).

Bug 1 - Start-AzLocalClusterUpdate (Step.07 entry):
  Production emitted "Error processing cluster '<Name>': The property
  'UpdateStartWindow' cannot be found on this object." for clusters whose tag
  bag did not include UpdateStartWindow / UpdateExclusionsWindow. The old
  `if ($clusterTags -and $clusterTags.$($script:UpdateStartWindowTagName))`
  threw before -and could short-circuit because bare .$() member access on a
  missing PSCustomObject property is strict-mode-fatal. New code branches on
  `$clusterTags -is [System.Collections.IDictionary]` and uses `.Contains()`
  for hashtables or `PSObject.Properties[...]` for PSCustomObject tag bags.
  Semantic intent ("absent = any time eligible / no window restriction") is
  preserved: the outer `if ($windowTagValue -or $exclusionTagValue)` correctly
  skips the schedule gate when both are $null.

Bug 2 - Test-AzLocalClusterHealth (Step.05/06 readiness gate):
  Production emitted "Checking: <Cluster>... Error: The property
  'healthCheckResult' cannot be found on this object." for clusters whose ARM
  update summary genuinely had no `healthCheckResult` field (typical for
  clusters that have not been probed yet). The catch block then flagged the
  cluster HealthState=Error / Passed=$false, and the readiness gate falsely
  treated the cluster as blocked, poisoning Step.5 / Step.7 / Step.9 readiness
  output. The same pattern was present in Get-HealthCheckFailureSummary
  (Private helper) and Get-AzLocalFleetStatusData (Public,
  -IncludeHealthDetails). All three sites now use the PSObject.Properties[]
  guard; Test-AzLocalClusterHealth correctly classifies such clusters as
  HealthState="No Data" / Passed=$true and continues.

Tests: two new Pester regression contexts feed the minimal real-world
property-less shapes and assert Should -Not -Throw plus the correct downstream
classification. Both bugs were invisible to parse-time analysis - only runtime
against the property-less shape triggers the strict-mode throw.

GENERATED_AGAINST_MODULE_VERSION bumped from 0.8.76 to 0.8.77 across all 22
bundled pipeline templates (github-actions + azure-devops).

Pester: 1142 passed / 0 failed / 1 skipped.

No public API change or new exports (still 60).
@NeilBird
NeilBird merged commit e6e2363 into main Jun 14, 2026
2 checks passed
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