Repository navigation
feat(machine-health): add the optional elevated pass - #9067
Conversation
The session writes a one-command script with New-ElevatedLaunch, shows it with its SHA-256, and launches it behind UAC only after the owner's yes. The elevated side checks the hash over the bytes it runs, runs only the elevation-matrix checks from their shipped scripts, and writes only the pre-created result file, opened without following reparse points and matched by file ID. A standard run imports it with -ElevatedResultPath. The orchestrator gains two exclusive parameter sets; the -ResultPath branch exits before any directory, lock, log or approval read. The banner and report point to the pass instead of a transcript command. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t junction swap The skill now runs the elevated launch as a background command and imports only after its completion notice, so the wait for UAC and the admin-gated checks never cuts the pass short. A new test swaps the logs folder for a junction to a same-named file and shows the file ID check refuses it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Launch: the model no longer quotes the argument string. Start-ElevatedLaunch takes the launch record, rebuilt by Get-ElevatedLaunch from the state root and the shown hash, and refuses a string that differs from the rebuild. New-ElevatedLaunch refuses any path holding a control character or one of the five single-quote characters, and records the file ID from the handle that created the result file. Write: CreateFileW adds anonymous SECURITY_SQOS_PRESENT and refuses a non-disk handle; the file ID is the 64-bit volume serial and 128-bit FileIdInfo ID, its format held once in Test-FileIdFormat. The document records the writer's user SID. Import: refuses a document whose elevated is not true or whose SID is not the importing user's, keeps only elevation-matrix ids (dropped ones are counted in an INFO note), and copies the log lines to the run log. The history's ran ids are derived from the final results. New-UnknownCheckResult moves to lib, and one per-check timeout serves both dispatch loops. SKILL.md states who can give the yes and records the upstream pointers; elevation-matrix.md states the mechanism and the wider residual risk. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e elevated pass Move the elevated-result format string to Get-ElevatedResultFormat.ps1 so Import-ElevatedResult no longer dot-sources Write-ElevatedResult, and dot-source Write-ElevatedResult only inside the orchestrator's -ResultPath branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… tighten the elevated pass - SKILL.md: every PowerShell command is the roots block plus one line. Claude Code substitutes the plugin root, data folder and report_dir into a single-quoted here-string behind a '|' sentinel, so no character in a path (U+2018 to U+201B, ', $( )) reaches the parser as code. The block applies the resolution fallbacks; the main orchestrator call gains a template. - Import appends elevated results for matrix checks the run did not dispatch, refuses a result older than -MaxAge (24 h) before the run started, and words a foreign user_sid as another account's result. - New-ElevatedLaunch refuses a token without a linked admin token, stamps names with InvariantCulture; Get-ElevatedLaunch reads ResultPath and ResultFileId from the script and refuses a stamp mismatch; Start-ElevatedLaunch launches $PSHOME\pwsh.exe. - Get-RanCheckId extracted from the orchestrator, counting imported ids. - Tests: SKILL.md template parse with hostile roots, orchestrator import and -ResultPath overlay-script cases, exit-code propagation, th-TH stamp. - Docs: elevation-matrix.md mechanism and residual risk, elevated_checks in output-schema.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 499339aabd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
claude-review reviewed Incremental review of PR #9067 (head 18f7e1d0), since 8b5f501: no findings. The only change is one hunk in
|
…nt findings - The import rerun after an elevated pass adds -DryRun when the audit was a dry run, so approving the pass never enables a held-back remediation. - The roots block no longer restates how Claude Code substitutes the tokens; the pointer record carries it. Blank-root match uses [ \t] instead of \s and fenced script paths use forward slashes (shell-portability gate). - README no longer says elevation is never offered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
claude-security-review reviewed No security findings in the incremental change (8b5f501 → 18f7e1d0). The change is one edit to
Everything else in the PR is unchanged since 8b5f501 and was reviewed then. |
…e portability baseline entry The roots block held a literal tab inside its character class; it now reads [ \t]. elevation-matrix.md has no portability hits left, so its baseline entry goes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… not cover Step 3 now says, before the yes, that the hash covers only the one-command script and that the orchestrator, lib and check scripts, module paths and environment it uses are trusted as the owner's own (the accepted residual risk). A stronger trust anchor is tracked in #9071. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No related issue: phase 9 of the owner-approved machine-health checkup extension plan (ADR 0081 series).
Summary
Adds an optional elevated pass to
/machine-health:audit. The session prepares a one-command script, shows it and its SHA-256 to the owner, and only on the owner's explicit yes in that session launches it behind UAC. The elevated run executes only the elevation-matrix checks and writes one result file; a later standard run imports it. A-p(headless) or--scheduledrun never offers the pass.Fix
-ResultPath/-ResultFileId(elevated pass) and-ElevatedResultPath(import). The elevated branch runs before any directory creation, lock or log; reads mutes throughGet-MuteStateonly; dispatches only shipped catalog scripts that have an elevation-matrix row (the per-machine overlay can switch a check off, never change its script); writes nothing but the result file.New-ElevatedLaunch/Start-ElevatedLaunch/Get-ElevatedLaunch: pre-create the result file and record its 128-bit file ID from the creating handle; the launch block reads the script bytes once, exits 3 on a hash mismatch, and runs those same bytes; the launch string is rebuilt from the record, never written by the model; paths with control characters or'/U+2018-U+201B are refused; the interpreter is$PSHOME\pwsh.exe, not a PATH lookup; refuses unless the token is a split admin token.Write-ElevatedResult: opens without following reparse points, refuses non-disk handles, reparse points and a file whose ID is not the recorded one, writes through that handle.Import-ElevatedResult: accepts onlyelevated-result/1,elevated: true, the importing user's SID,ran_atafter the file's creation and within 24 h, and results passingAssert-CheckResult; replaces or appends results for matrix ids and lists them inlatest.jsonelevated_checks.audit/SKILL.md: every command takes the plugin, data and report roots from a single-quoted here-string with a|line prefix, so no substituted path is typed inside a quoted literal (a root holding U+2019 could otherwise break out and inject code).Write-ElevationBanner: noStart-Transcript.elevation-matrix.md"How to run elevated" and residual risk;output-schema.mddocumentselevated_checks.Verification
run-tests.ps1, pre-existing non-Windows skip).$( ), roots starting'@/’@, quotes, spaces) parsed withParser::ParseInputgive the same command list as a benign root, 0 parse errors; 40/40 roots bind exactly; no canary file created.New-ElevatedLaunchrefused 27/27 hostile roots; a non-elevated round trip returned the child's exit code 5 with exact paths; one tampered byte gives exit 3 without running the orchestrator.<StateBase>listing differs only in the result file's length.Get-ApprovalStateinInvoke-MachineHealthCheck.ps1appears only after the-ResultPathbranch's exits (branch 156-229, exits 163/225/228; dot-source 233, call 593).git grep Start-Transcript -- plugins/machine-health/skills/audit/scripts: no output.<StateBase>listing andelevated_checkson the owner's host.Related
🤖 Generated with Claude Code