Skip to content

Add win-fix-code-integrity - #151

Open
Marcus Ferreira (mvaferreira) wants to merge 6 commits into
Azure:mainfrom
mvaferreira:rsl-win-fix-code-integrity
Open

Add win-fix-code-integrity#151
Marcus Ferreira (mvaferreira) wants to merge 6 commits into
Azure:mainfrom
mvaferreira:rsl-win-fix-code-integrity

Conversation

@mvaferreira

@mvaferreira Marcus Ferreira (mvaferreira) commented Sep 10, 2026

Copy link
Copy Markdown

What this adds

win-fix-code-integrity - one scenario script and its own map.json entry.

Finds the driver that Code Integrity is blocking and disables that driver, instead of turning off the protection.

The catalog entry a support engineer reads when choosing it:

Finds the driver that Code Integrity is blocking and disables that one driver, instead of turning off Memory Integrity or Credential Guard. Uses the offline Code Integrity event log to name the culprit and a portable executable scan for writable and executable sections as corroboration. Only a refusal from the last 30 days, naming a third-party driver whose image can actually be checked on the disk, authorises a change; stale, undated or unreadable evidence is reported for a decision instead. The offline Secure Boot state, read from the Measured Boot log, and any testsigning or nointegritychecks override are reported as context only: measurement shows the boot manager drops those overrides and the guest still boots, so they are not treated as a fault. A protection being enabled is never treated as a fault: nothing is changed without evidence that it broke this VM. Boot-critical and Azure platform drivers are reported, never disabled. Pass disableProtection=true only as a last resort. NOTE: use option --run-on-repair.

How it works

Runs against the broken OS disk attached to a rescue VM by "az vm repair create". It answers the question "which driver is stopping this VM from booting" using evidence taken from the offline disk, and disables only the driver that evidence names. Memory Integrity, Credential Guard and VBS stay enabled.

The rule this script is built around: a protection being enabled is not a fault. Millions of VMs run Memory Integrity and Credential Guard without trouble, so "HVCI is on" is never reported as a problem and never triggers a change. Something is only repaired when there is positive evidence that it is what broke this particular VM.

Parameters

Parameter Effect
detectOnly "true" to report the evidence and make no writes at all. Defaults to "false".
disableProtection "true" to clear the Memory Integrity, Credential Guard and LSA protection settings that are actually enabled. Last resort. Defaults to "false".
windowsDrive Drive letter of the offline Windows installation, for example "F". Only needed when more than one Windows installation is attached and the automatically selected one is not the right one.

Conventions followed

  • Dot-sources .\src\windows\common\setup\init.ps1 and returns $STATUS_SUCCESS or $STATUS_ERROR.
  • Logging goes through the logger functions only; no Write-Host.
  • The detect summary is printed after the per-finding list, because az vm run-command keeps only the last 4096 characters of the output stream, so a summary printed first is the first thing a long run loses.
  • Evidence-driven: findings are gathered first and only what the evidence names is changed, so a healthy image produces no writes.

Testing

Historical product-path acceptance: the recorded az vm repair run --run-on-repair --preview
batch covered a healthy zero-write baseline, a blocked driver named from the offline CI log,
repair, independent verification, an idempotent rerun, and a successful boot after
az vm repair restore. Memory Integrity and Credential Guard stayed enabled. Later Gen2
Secure Boot/vTPM experiments established that boot-manager overrides are context, not a
proven no-boot fault; the script reflects that correction.

September 10 integration: writing callers now use strict control-set selection from #146.
The shared registry suite passed 140/140 on PS5.1 and PS7; 33 native synthetic-hive assertions
covered selector validation, cross-scope lifecycle and a write persisted only to ControlSet002.
Those are helper/integration results, not a new full per-generation scenario acceptance run.

Series

First wave of four independent scenario PRs. The shared helpers in #143, #146 and #147 are
already merged. This PR adds no helper files and changes no existing scenario; its only existing
file change is appending this run-id to map.json, preserving every upstream entry.

Marcus Ferreira and others added 5 commits September 8, 2026 14:19
Finds the driver that Code Integrity is blocking and disables that driver, instead of turning off the protection.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cf64bab1-6099-4e7e-aef4-57ffea10ce6b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: cf64bab1-6099-4e7e-aef4-57ffea10ce6b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: cf64bab1-6099-4e7e-aef4-57ffea10ce6b
@mvaferreira

Copy link
Copy Markdown
Author

Automated review using the supplied PR Review Agent

Reviewed head: ff8230f837d10eda1dc398f8c32ef32f2b2c7c03
Agent recommendation: request changes
Finding-table counts: 0 Critical / 9 Warning / 8 Info

This is the supplied agent's static analysis, not a maintainer decision or a fresh repair/boot test. Findings have not been independently reproduced. No source or Azure resources were changed during review. The original report is retained locally; only leading process narration and local prompt-path provenance were normalized for posting. Finding text is unchanged.

Full automated review report

PR Review: #151 — Add win-fix-code-integrity

Generated: 2026-09-10
Target: Azure/repair-script-library → main

Reviewed from the pinned packet snapshots only. Changed files: map.json, src/windows/win-fix-code-integrity.ps1 (new, 760 lines). No helper file is added or modified by this PR; helper behaviour below is cited as the contract the new script must satisfy.


Findings

Critical

File Line/Context Issue Recommendation
None found

Init sourcing (. .\src\windows\common\setup\init.ps1, line 118), $STATUS_SUCCESS/$STATUS_ERROR on every exit path (657, 720, 741, 754, 759), and map.json correctness all pass. Destructive writes sit inside try/catch (677–686, 756–760), and Invoke-WithHive supplies its own finally for hive unload, so no unhandled-destructive-error condition was traced.

Warning

File Line/Context Issue Recommendation
src/windows/win-fix-code-integrity.ps1 557–760 (try/catch, no finally) The documented required caller contract is not met. src/windows/common/helpers/README.md ("Required caller contract") states a map.json script must "Always release temporary drive letters and flush helper logs in finally, including when discovery fails partway through", and ships a verbatim template doing so. Get-OfflineWindowsDisk's .OUTPUTS repeats it: "AssignedDriveLetters holds the letters this run assigned; pass each to Remove-OfflineDriveLetter, or call Clear-OfflineDriveLetter, in the caller's finally." OfflineRepairCommon.ps1 repeats it a third time. The script calls neither function, and the two early return $STATUS_SUCCESS (657, 720) plus the catch (756) all bypass cleanup. Two demonstrated consequences: (a) Disable-Protection buffers the reg add restore command at 531 before writing at 532 — if 532 throws after earlier values were already cleared, the restore lines for the cleared values are never flushed, so a partially-disabled security posture is left with its rollback instructions discarded; (b) drive letters assigned to EFI/Recovery partitions stay mounted on the rescue VM. Get-PartitionExistingRoot reclaims them on a later run when QueryDosDevice is available, so exhaustion is bounded in the normal case but not when that Add-Type fell back to mountvol. Wrap 558–754 and add finally { if (Get-Command Clear-OfflineDriveLetter -EA SilentlyContinue) { Clear-OfflineDriveLetter }; if (Get-Command Write-OfflineRepairLog -EA SilentlyContinue) { Write-OfflineRepairLog } }, and return the status after cleanup, per the README template.
src/windows/win-fix-code-integrity.ps1 359 (IsMicrosoft = ($vendor -match 'Microsoft')), fed by 345–348 The classifier guarding an automatic write uses the weakest available signal, and the repo ships a helper documented against exactly this. IsMicrosoft is derived solely from VersionInfo.CompanyName. Test-OfflineFileSignature in OfflineRepairCommon.ps1 exists for this decision and states the version resource "is unsigned data that any file can carry, so it never sets IsMicrosoft", offering IsLikelyMicrosoft with the guidance: "Use this when a false negative is the more dangerous answer, for example when deciding which drivers to leave alone." Consequence: a driver with an absent or blank version resource (including one whose image is missing, where $vendor stays '' at 343) is classified third-party and becomes eligible for the automatic Start=4 write at 501; conversely a forged CompanyName exempts a driver from it. Call Test-OfflineFileSignature on $driver.ResolvedPath and gate the disable on -not $sig.IsLikelyMicrosoft, retaining Vendor for reporting only.
src/windows/win-fix-code-integrity.ps1 333, 335–336 and 387–390 (-ErrorAction SilentlyContinue) Access denial is conflated with absence, producing a false clean result. The helper suite deliberately eliminates this: Get-OfflineRegistryDword "Returns null only for an absent key/value. A wrong type, access denial or any other native read failure throws"; Get-OfflineHiveKeyState returns Unknown rather than Absent; the README states "Access denial is not absence." Here, a Services subtree that cannot be enumerated yields an empty inventory, so Get-AllFinding logs "no driver service loads that image" and the run reports "No code integrity boot failure was found" (715). Likewise an unreadable Control\Lsa/DeviceGuard/Policies key makes Get-ProtectionState report every protection off, so Disable-Protection changes nothing and the script prints "No protection value needed clearing: they were already off" (710). The repo ships Use-OfflinePrivilegedRegistry.ps1 for keys that deny SYSTEM. Use -ErrorAction Stop with an explicit catch that distinguishes absence from denial, or read through Get-OfflineRegistryDword; report an indeterminate read as unknown, never as clean.
src/windows/win-fix-code-integrity.ps1 544–545 vs 666, 700; header 105 The SOFTWARE hive is written but never backed up, and the header misstates what is. Disable-Protection writes EnableVirtualizationBasedSecurity and HypervisorEnforcedCodeIntegrity under HKLM:\BROKENSOFTWARE\Policies\..., while Backup-OfflineHiveFile is only ever called with -Hive 'SYSTEM'. Line 105 claims "The SYSTEM hive file and the BCD store are backed up next to themselves before the first write" — the BCD store is never written or backed up (only Test-BcdStorePath, Get-BcdPreferredOsGuid, Get-BcdLoaderDetail are used), and SOFTWARE, which is written, is omitted. Rollback rests solely on the logged reg add lines, which the missing finally can discard. Back up SOFTWARE before 704 when disableProtection is set (Backup-OfflineHiveFile -Hive 'SOFTWARE'), and correct line 105 to state what is actually backed up.
src/windows/win-fix-code-integrity.ps1 30–32 and 37–40 vs 88–99, 441–444 The header .DESCRIPTION contradicts the implementation and the rest of the same header. Evidence source 3 (30–32) asserts testsigning/nointegritychecks "will stop a Secure Boot machine from booting", and "Causes detected and repaired" items 2 and 3 (37–40) promise "Repaired by turning test signing off" and "Repaired by removing the override." Neither is implemented: Get-AllFinding (441–486) creates findings only from Code Integrity block events, $bcdState is used purely for the context messages at 592–601, and the .NOTES block at 88–99 explicitly documents the measured reversal. map.json's description is correct, so the blast radius is an engineer reading the file header. Delete items 2 and 3 from "Causes detected and repaired" and rewrite evidence source 3 to match the .NOTES measurement.
src/windows/win-fix-code-integrity.ps1 271, 478–480, 501 Code Integrity evidence carries no recency bound, so a stale block event triggers a live write. Get-WinEvent -MaxEvents 200 returns the most recent matching events with no time filter. LastSeenUtc is computed and printed in the finding message but is never used as a gate, so any driver named anywhere in those 200 events — including a block from months ago, since updated or superseded — becomes a BlockedDriver finding and is set to Start=4 on any non-detectOnly run. Disabling a driver the guest no longer fails on is an unnecessary functional change. Bound the evidence window (a -MaxEventAgeDays parameter, or events at or after the most recent boot attempt), and report anything older as a lead requiring detectOnly confirmation.
src/windows/win-fix-code-integrity.ps1 20–22 vs 271, 478–480 The stated evidence hierarchy is not implemented. The header distinguishes 3033/3077 ("name the exact image that was refused") from 3004/3023 ("record signature failures"), and says source 1 "is the only evidence strong enough to justify disabling a driver on its own." The XPath filter at 271 treats all four IDs identically, and Get-AllFinding weights every resulting filename the same, so an event of the weaker class alone is sufficient to disable a driver. (This review does not assert the semantics of any individual event ID; the finding is the internal inconsistency.) Either restrict the auto-repair path to the IDs the header names as authoritative and demote the others to corroboration, or amend the header to state that all four are treated equally, with the rationale.
src/windows/win-fix-code-integrity.ps1 274–277 (-match 'No events were found') A repair decision hangs on a localized English exception string, contrary to a convention the helper suite states repeatedly (Use-OfflineRegistryHive.ps1 v1.3 "Removed localised-output decisions"; README "determined through registry APIs rather than localized reg.exe messages"). On a non-English rescue VM the message will not match, so an empty-but-healthy log falls through to the generic branch and the run reports "Code Integrity evidence is unavailable" (565) instead of the clean negative "the Code Integrity log contains no block events". Those two messages point an engineer at different next actions. Match $_.FullyQualifiedErrorId (NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand), or drop -ErrorAction Stop and branch on $events.Count.
PR description — "Testing" n/a No end-to-end scenario acceptance run is recorded for this head. The PR states the acceptance batch is historical and against a version whose behaviour was since corrected (testsigning/nointegritychecks no longer repaired), and that the September 10 work is "helper/integration results, not a new full per-generation scenario acceptance run." doc/adding_new_scripts.md notes that --custom-script-file testing cannot pass parameters, so detectOnly, disableProtection and windowsDrive cannot be exercised by the documented local test path before merge. Record a fresh --run-on-repair run against this head covering: healthy zero-write baseline, blocked-driver detect + repair + idempotent re-run, and successful boot after az vm repair restore, on both Gen1 and Gen2.

Info

File Line/Context Suggestion
src/windows/win-fix-code-integrity.ps1 579 (Get-OfflineSystemRootPath -Strict:(-not $isDetectOnly)) A detectOnly=true preview uses tolerant selection, which may fall back to ControlSet001, while a repair run resolves Current strictly or throws. The preview can therefore describe a different control set than a repair would write to, or succeed where the repair run would fail outright. The chosen set is disclosed at 588; consider using -Strict for detection too and reporting the failure explicitly.
src/windows/win-fix-code-integrity.ps1 673, 705, 725 Writes land only in the Current control set. Get-OfflineReferencedControlSetName -Strict is provided for writers that need Default/LastKnownGood as well. Whether a repeatedly-bugchecking modern guest is auto-switched to LastKnownGood was not established in this review; if it is not, single-set coverage is correct and this can be dismissed.
src/windows/win-fix-code-integrity.ps1 385 'HKLM:\BROKENSOFTWARE\Policies\...' is the one write target not derived from a helper; it hardcodes Use-OfflineRegistryHive's internal HKLM\BROKEN<HIVE> mount naming. It matches the documented convention today and fails safe (Test-Path at 530 returns $false if unmounted), but it will not follow a helper-side rename.
src/windows/win-fix-code-integrity.ps1 501, 532 Assert-OfflineTarget is not called before either write. Not a demonstrated defect — both paths derive from a mounted BROKEN* root — but the gate's own help says "Call this before enabling a privilege, taking ownership, writing, or deleting", and an explicit call would make the guarantee local rather than inherited.
src/windows/win-fix-code-integrity.ps1 724 The verification block mounts 'SYSTEM','SOFTWARE' but its body reads only SYSTEM. Dropping SOFTWARE removes an unnecessary mount/unmount cycle from the path most likely to hit an unload failure.
src/windows/win-fix-code-integrity.ps1 194–197 Get-PeWritableExecutableSection treats a single $stream.Read(...,8192) as complete; a short read would be reported as "file is too small to be a PE image". Loop until 8192 bytes or EOF.
src/windows/win-fix-code-integrity.ps1 352, 679 KeyPath is captured but never used (Repair-Finding rebuilds the path at 499), and Repaired is set but never read (the summary uses $repairedCount). Harmless; remove or use.
map.json 75 The description is roughly 750 characters, far longer than any sibling entry, and is printed by az vm repair list-scripts. Consider trimming to the operative sentence plus the --run-on-repair note. Content is accurate.

Operational Risk Assessment

Factor Rating Notes
Scope Low One new scenario script plus one appended map.json entry. No helper file added or changed; no existing scenario touched. Blast radius is limited to callers of this run-id.
Destructive ops Medium Offline registry writes only: Start=4 on one service (501), and, behind non-default disableProtection=true, nine security-relevant values including HVCI, Credential Guard and LSA PPL (537–545). No file deletion, no BCD write, no disk-layout change. The design is genuinely conservative — Microsoft, boot-critical and platform drivers are reported and never disabled (466–476), and a healthy image produces no writes.
Rollback possible Partial SYSTEM hive backed up before the first write (666, 700) and per-value reg add restore commands are logged (503, 531). SOFTWARE is written but not backed up, and the logged restore lines can be lost on the failure path because of the missing finally.
Testing documented No Historical only, per the PR's own caveat. No end-to-end scenario acceptance run for this head; the documented local test path cannot pass this script's parameters.
Gen compatibility Gen1+Gen2 (delegated) Generation handling lives entirely in Get-OfflineWindowsDisk, which derives Generation from partition style and selects EFI\Microsoft\Boot\BCD vs Boot\BCD accordingly; the script consumes .BcdStorePath and adds no generation-specific logic. Per-generation acceptance is not recorded for this head.

Overall Risk: Medium 🟡


Validation

Assessed by reading the pinned head snapshot; results agree with the launcher's deterministic checks.

  • map.json valid: pass — verified by reading the full file. Balanced brackets, no trailing commas; the new object at lines 72–76 uses the "key" : value spacing and tab indentation of its neighbours.
  • map.json paths exist: pass — src/windows/win-fix-code-integrity.ps1 is present in the head snapshot's src/windows/ listing.
  • Duplicate IDs: none — win-fix-code-integrity appears once across all 29 entries and follows the win-* convention.
  • Upstream entries preserved: pass — the diff is a pure 5-line insertion between win-enable-nested-hyperv and win-toggle-safe-mode; no existing entry is modified or removed.
  • Helper references resolve: pass — Get-OfflineWindowsDisk exposes .WindowsPath, .WindowsDrive, .DiskNumber, .ProductName, .BuildNumber, .BcdStorePath; Get-OfflineSecureBootState -WindowsDrive returns .Known/.Enabled/.Source; Get-BcdLoaderDetail returns .RawText. Resolve-OfflineImagePath accepts the 'F:' form supplied. Invoke-WithHive's inert-snapshot contract preserves $Finding.Data.Service/.Start (no serialization depth loss), and Add-OfflineRepairLog is silent, so Repair-Finding's boolean and Disable-Protection's count are uncontaminated.
  • PowerShell parse errors: none reported by the launcher (Validation.PowerShellParseErrors empty). No parser was executed during this review.
  • Not performed in this review: no repair script was executed, no Azure operation, no hive mount, no disk or boot test. Packet records RepairScriptsExecuted: false, AzureOperationsPerformed: false.

Recommendation

request changes

The design is sound and unusually disciplined — evidence-gated repair, protections left enabled by default, boot-critical and platform drivers reported rather than disabled, verification re-read from fresh state at 724 rather than trusting the writes. Nothing here blocks merge on the Critical criteria. But eight warnings stand, three of them substantive and mechanical to fix: the missing finally (a contract the helper suite states in three separate places, and the path by which rollback instructions can be lost), IsMicrosoft derived from the unsigned version resource against explicit helper guidance, and access denial silently reported as a clean result. The header's "Causes detected and repaired" items 2 and 3 describe behaviour the script does not have and should not ship as written. A fresh end-to-end acceptance run against this head would close the testing gap.

This is an automated review against the pinned snapshots, not a human maintainer approval. Severity assignments follow the supplied prompt's criteria; findings where the consequence could not be established from the source are marked as such.


Provenance

Field Value
PR #151
Title Add win-fix-code-integrity
State at review open
Head SHA ff8230f837d10eda1dc398f8c32ef32f2b2c7c03
Base SHA 3cdb744e1592c1aa0e6c5840bea43e5b8a1911ad
Merge base 3cdb744e1592c1aa0e6c5840bea43e5b8a1911ad
Head repository https://github.com/mvaferreira/repair-script-library
Prompt PR-Review-Agent.md, SHA256 5451BA5C325F61E34FE63B9AF99322A17D70E55210CAF23F5CE27E0F839D8F70
Agent rsl-pr-review
Packet generated 2026-09-10T19:19:19Z

Addresses the PR151 review findings.

  - Trust comes from Test-OfflineFileSignature, so a valid Microsoft
    Authenticode signature protects a driver whose CompanyName is blank. The
    CompanyName claim is still honoured on top of it, so nothing previously
    excluded becomes eligible.
  - A named image that is missing, empty, unreadable or not parseable is a
    manual lead, not an automatic Start=4.
  - Get-KernelDriverInventory throws when the Services key or a service key
    cannot be read, instead of returning a clean, empty inventory.
  - Get-ProtectionState reads every value through Get-OfflineRegistryDword,
    so a denied read or a wrong value type throws rather than being reported
    as "protection off". An absent value still means unconfigured.
  - A refusal older than 30 days, or one with no readable timestamp, is
    reported for a decision and never authorises a write.
  - The main flow follows the helper caller contract: a labelled single-pass
    loop, a top-level finally that releases discovery-owned drive letters and
    flushes the buffered helper log, and the status returned after cleanup.
  - The opt-in branch backs up SOFTWARE as well as SYSTEM before mounting.
  - An empty log is classified by the NoMatchingEventsFound error identity
    instead of an English message.
  - The header no longer claims a BCD backup or Secure Boot/testsigning
    repairs the script does not perform, and map.json records the recency and
    checkability limits on automatic repair.

Validated with the local mocked harness (41 checks, no registry, disk or hive
access) and the log-ordering audit. The Azure create/run/restore acceptance
cycle was performed previously against the pre-review script.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mvaferreira

Copy link
Copy Markdown
Author

Review findings implemented

Publication head: f46f475b1dd4a4ce19d9c7fe00ae9de95fcb553b

The earlier automated report remains a static review of
ff8230f837d10eda1dc398f8c32ef32f2b2c7c03. This follow-up records what was implemented in
response to it; it is not a relabelled or newly generated agent review.

Finding Disposition
W1: the documented required caller contract is not met The main flow is a labelled single-pass loop with a top-level finally that releases discovery-owned drive letters and flushes the buffered helper log through the script logger. The single final status is returned after that cleanup, so it stays at the end of the output stream.
W2: the classifier guarding an automatic write uses the weakest available signal Trust now comes from Test-OfflineFileSignature, so a valid Microsoft Authenticode signature protects a driver whose CompanyName is blank. The CompanyName claim is still honoured on top of the signature, so nothing that was previously excluded becomes eligible — a Microsoft-labelled driver with a HashMismatch signature is still reported rather than disabled. Vendor is retained for reporting only.
W3: access denial is conflated with absence, producing a false clean result Get-KernelDriverInventory now throws when the Services key or an individual service key cannot be read, instead of returning a clean, empty inventory — a driver that silently drops out of the list is a driver the repair never considers. Get-ProtectionState reads every value through Get-OfflineRegistryDword, so a denied read or a wrong value type throws rather than being reported as "protection off"; an absent value still means unconfigured. Separately, an image that is missing, empty, unreadable or not parseable by Authenticode is now a visible manual lead rather than an automatic Start=4.
W4: the SOFTWARE hive is written but never backed up, and the header misstates what is The opt-in branch backs up SOFTWARE as well as SYSTEM, while both are still unmounted, before the write. The header no longer claims a BCD backup — the BCD store is never written — and now states what is actually backed up and that those .bak-<timestamp> files survive az vm repair restore.
W5: the header .DESCRIPTION contradicts the implementation The two "Causes detected and repaired" items describing testsigning/nointegritychecks repairs are gone, along with the claim that those overrides stop a Secure Boot machine from booting. Evidence source 3 now reads as context only, consistent with the measurements already recorded in .NOTES.
W6: Code Integrity evidence carries no recency bound A refusal older than 30 days, or one carrying no readable timestamp, is reported for a decision and never authorises a write. The evidence is deliberately still surfaced: stale evidence is demoted to a manual lead rather than filtered out, so a disk is never reported clean because its log was old.
W7: the stated evidence hierarchy is not implemented Resolved in favour of the implementation. 3033/3077 and 3004/3023 are treated alike, and the header now says so rather than describing a distinction the code does not make. Discarding 3004/3023 would have narrowed real detection on no evidence.
W8: a repair decision hangs on a localized English exception string An empty log is classified by the NoMatchingEventsFound error identity instead of the message text, so a non-English rescue host cannot mistake "no events" for "log unreadable".
W9: no end-to-end scenario acceptance run is recorded for this head Accepted as accurate, and still accurate — see the testing note below.
I1: tolerant control-set selection during detectOnly Not changed. Detection is deliberately tolerant and writes are strict; the behaviour is documented rather than altered.
I2: writes land only in the Current control set Not changed, intentionally. Broadening to Default/LastKnownGood without scenario evidence would widen the blast radius.
I3: the hardcoded HKLM:\BROKENSOFTWARE\... policy path Not changed. It is the mount point the helper itself establishes, and it is only reachable inside that helper's callback.
I4: Assert-OfflineTarget is not called before either write Not changed. As the report notes, this is not a demonstrated defect — both paths derive from a mounted BROKEN* root — and adding an unexercised guard to a write path is the kind of change that needs its own acceptance run.
I5: the verification block mounts SOFTWARE but reads only SYSTEM Fixed; the verification pass now mounts SYSTEM only, removing an unnecessary mount/unmount cycle.
I6: Get-PeWritableExecutableSection assumes a single complete read The header block is now read in a loop until it is full or the file ends, so a short read is no longer reported as "file is too small to be a PE image".
I7: KeyPath unused and Repaired never read Not changed. Both are harmless, and Repaired is part of the finding shape shared with the other scenarios.
I8: map.json description length Left long, and slightly longer: it now records the recency and checkability limits on automatic repair, which an engineer choosing the script needs to know. Several sibling entries are of comparable length.

Testing scope, stated plainly — this is W9's honest answer: the changes above were
validated with the local mocked harness for this PR (41 checks, one per finding, executed with
no registry, disk, hive or Azure access), a parse check, the mandatory-parameter audit and the
log-ordering audit. The az vm repair run --run-on-repair --preview product-path batch
described in the PR description was performed earlier, against the pre-remediation script, and
was not repeated for this head. W9 therefore still stands: there is no fresh full
per-generation scenario acceptance run behind this exact commit, and the PR description should
be read with that in mind. What did change is the direction of the remaining risk — every
behavioural change here removes a write rather than adding one, so an untested path now fails
closed and reports, where before it could act on evidence it could not prove.

Original review provenance
  • Supplied prompt SHA256: 5451BA5C325F61E34FE63B9AF99322A17D70E55210CAF23F5CE27E0F839D8F70.
  • Original finding-table counts: 0 Critical / 9 Warning / 8 Info.
  • Preserved original report.
  • Its recommendation belongs to the old reviewed head; no maintainer approval is implied.

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