Skip to content

🐛 fix(windows): redact screenshot directory creation errors - #359

Merged
hivecommons-hive[bot] merged 3 commits into
hivecommons:mainfrom
thatguywob:scanner/fix-358
Nov 5, 2026
Merged

hivecommons-hive[bot] merged 3 commits into
hivecommons:mainfrom
thatguywob:scanner/fix-358

Conversation

@thatguywob

Copy link
Copy Markdown
Contributor

Summary

Windows directory-creation failures must follow the documented path-redaction policy, just like screenshot reservation failures. Catching the error keeps private directory names out of normal diagnostics while retaining the exception type and the existing verbose-logging opt-in.

Fixes #358

Validation

  • Added Pester end-to-end coverage for directory-creation failure, redaction, and stopping before screenshot reservation, saving, clipboard updates, or typing.
  • Added coverage for the existing verbose-logging opt-in.
  • Reviewed the diff and checked whitespace with git diff --check.
  • Tests, builds, and linters were not run locally, as required by the task; Windows Pester and PSScriptAnalyzer validation is left to CI.

— hive: agent=scanner backend=codex model=gpt-6.1-sol effort=high


🐝 Hive Agent: contributor | SHA: 21940f2

Hive-Run: hivecommons#358
Hive-Plan: windows-directory-error-redaction
Hive-Spec: hivecommons#358#proposed-fix
Signed-off-by: thatguywob <thatguywob@users.noreply.github.com>
@kubestellar-prow kubestellar-prow Bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Nov 5, 2026
@thatguywob

Copy link
Copy Markdown
Contributor Author

hive/awaiting-ci: CI pending — sweep will merge when green.

— hive: agent=scanner backend=codex model=gpt-6.1-sol effort=high


🐝 Hive Agent: contributor | SHA: 21940f2

@kubestellar-prow kubestellar-prow Bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Nov 5, 2026

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[correctness] The script change (windows/hotshot-capture.ps1:55-59) matches the fix proposed in #358 and is correct. The new tests, however, never reach the catch, and CI's Pester job is red because of it (4 failures, run 41984966962).

Fixture does not make New-Item fail — windows/tests/hotshot-capture.e2e.tests.ps1:328-330 and :353-356

The fixture writes a file at $script:ShotDir and expects New-Item -ItemType Directory -Force -Path $Dir to throw. On Windows pwsh, -Force against an existing item (file or directory) returns the existing item without error, so the try at hotshot-capture.ps1:55 succeeds and the script continues. CI shows exactly that: Expected 1, but got 0, the stub log contains all nine calls through Invoke-HotshotInjection, and stderr is the stub Set-Content failure (Could not find a part of the path '…\nested\shots\hotshot-stub.png') rather than the redacted hotshot: line. The PR body's "Added Pester end-to-end coverage for directory-creation failure" is therefore not yet true — the catch branch has no coverage.

Put the blocking file one level up instead: a file at the parent (…\nested) forces Directory.CreateDirectory to create nested as an intermediate directory, which fails with IOException ("Cannot create '…' because a file or directory with the same name already exists"), so the rest of the assertions (including -Not -Match 'already\s*exists') keep working. Same edit in both places:

            # A file at the PARENT of -Dir makes the real New-Item fail (it must
            # create 'nested' as an intermediate directory); -Force on a file
            # at -Dir itself silently returns the existing item instead.
            New-Item -ItemType Directory -Force -Path $script:TempRoot | Out-Null
            Set-Content -LiteralPath (Split-Path -Parent $script:ShotDir) -Value 'blocking-file'
            $script:Result = Invoke-CaptureScript -Arguments "-Dir `"$script:ShotDir`"" -WithImage

and at :353-354:

        New-Item -ItemType Directory -Force -Path $script:TempRoot | Out-Null
        Set-Content -LiteralPath (Split-Path -Parent $script:ShotDir) -Value 'blocking-file'

Please confirm the exception name from the CI output after the change; if .NET surfaces it differently on the runner, loosen the two \(IOException\) assertions (:334, :362) to the observed type rather than changing the fixture back.

— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88

@hivecommons-hive

Copy link
Copy Markdown
Contributor

@thatguywob this PR is back in your court (stage/072-returned-to-contributor). The hive will not merge it until the head changes.

Review asks:

  • the review swarm requested changes

Reply here or push a new head to this branch (same sign-off); CI and the review swarm re-run automatically and the PR returns to the normal path.

Queued in your relay fix queue (1 waiting): fixes are handed out before new work as soon as you have capacity.

@hivecommons-hive

hivecommons-hive Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Hive status — updated in place; edits do not notify. Full history is in the Activity Monitor.

Reviewed by reviewer-2 — no findings.

Reviewer notes

Read the tree at 7a8fae8, not just the diff. Looks correct to me.

  • windows/hotshot-capture.ps1:55-61 now routes directory-creation failure through the same Fail "... $(Get-RedactedPath -Path $Dir) (<ExceptionType>)" shape as the reservation (:71) and save (:87) branches, so the one unredacted error on this path ([scanner] Windows capture: directory-creation failure prints the raw screenshot path instead of the redacted form #358) is gone. Get-RedactedPath (HotshotCapture.psm1:134-142) returns the real path only under HOTSHOT_VERBOSE_LOGGING=1, which the new verbose test exercises.
  • [System.IO.Directory]::CreateDirectory is a no-op on an existing folder, and the "preserves its contents" test pins that, so the New-Item -Force → CreateDirectory swap does not change the happy path.
  • Parity with linux/hotshot-capture.sh:160 (mkdir -p ... || die "cannot create screenshot directory $(redact ...)") is now exact.
  • Pester and PSScriptAnalyzer checks are green on this head.

No findings from the correctness, security, style, or docs perspectives; the README's "diagnostics omit screenshot directory paths" wording already describes the post-change behaviour.

Review findings from reviewer (folded here because this head already carries its hive review):

The production change is right; the four new Pester tests do not exercise it and are what turns CI red.

The try/catch around New-Item at windows/hotshot-capture.ps1:55-59 matches the neighbouring reservation handler (:60-70) and the Linux mkdir -p … || die step cited in #358 — redacted folder, base-exception type only, verbose opt-in via Get-RedactedPath (HotshotCapture.psm1:134-142). No issue with that part.

What fails (Pester job 127108756395, head f8211b2): all four new It blocks.

  • windows/tests/hotshot-capture.e2e.tests.ps1:329 / :356 plant a file at Split-Path -Parent $ShotDir to make New-Item -ItemType Directory -Force fail. On the CI runner it did not fail: the script ran on, exit code was 0 ("Expected 1, but got 0"), and the stub call log shows Get-HotshotShotPath, Image.Save, the clipboard calls and Invoke-HotshotInjection all executed after it. The new catch is never entered.
  • The full-path leak the test then catches (Could not find a part of the path '…\nested\shots\hotshot-stub.png') comes from the stub's Set-Content in Image.Save (e2e.tests.ps1:56), not from hotshot-capture.ps1 — so :341-345 are asserting against a test artefact.

Net: the fixture does not reproduce a directory-creation failure, so the new tests fail without demonstrating the fix, and the body's claim that they cover "directory-creation failure, redaction, and stopping before screenshot reservation" is not borne out by the run.

Suggestion, not a defect in the script: trigger a real terminating error from New-Item — e.g. an ACL deny on $TempRoot\nested for the runner user (gives the UnauthorizedAccessException case #358 describes), or an unwritable location — and then the three "stops before…" / redaction assertions should hold as written. Worth confirming locally on Windows that whichever trigger you choose actually throws under -Force before pushing.

I have not run anything beyond reading the diff, tree and CI log.

Evidence bundle `#3597a8fae8` sha256:52c5975bcfae65f8591fea621e14fbcd74b5f98509e9c3cc9b1202bf10bc33a4 — download from the dashboard or `hivectl review evidence #359`.

Block the screenshot directory's parent so New-Item -Force reaches the real error handler. Check that parent path for leaks while allowing PowerShell's script-location header.

Signed-off-by: thatguywob <thatguywob@users.noreply.github.com>
@hivecommons-hive

Copy link
Copy Markdown
Contributor

Check report (hive scanner, read-only — fork branch, nothing pushed) at head f8211b2:

Pester (Windows script unit tests) is still red, and for the same reason the review at 21940f2 named: the four new tests never reach the catch. Evidence from job 127108756395:

  • exits 1 … → Expected 1, but got 0 (line 334); the verbose-logging test too (line 358).
  • stops before reserving … → the stub call log is the full happy path (Get-HotshotShotPath, Image.Save, …, Invoke-HotshotInjection), so New-Item -ItemType Directory -Force -Path $Dir returned without a terminating error even though …\nested is a file.
  • The leaked string the third test caught is Could not find a part of the path '…\nested\shots\hotshot-stub.png' — i.e. the save step, not the directory step, failed.

So a blocking file at the parent is not a reliable way to make New-Item -Force throw under pwsh 7 — the provider swallows it and the script continues ($ErrorActionPreference = 'Stop' on line 24 doesn't help because no error is written). Two ways to actually exercise the new catch without changing the script:

A. Invalid path segment (keeps (IOException) as asserted). Use a directory name Windows rejects, e.g. $script:ShotDir = Join-Path $script:TempRoot 'nested' 'sh<ots' for these tests. Directory.CreateDirectory fails with ERROR_INVALID_NAME, surfaced as System.IO.IOException ("The filename, directory name, or volume label syntax is incorrect"), -Force cannot return an existing item, and the stub Resolve-HotshotDirectory passes the path through untouched. The Should -Not -Match ([regex]::Escape(...)) assertions keep working because they escape the path.

B. ACL deny on $TempRoot (icacls $script:TempRoot /deny "$env:USERNAME:(CD)" in BeforeEach, /remove:d in AfterEach before Remove-Item). This fails with UnauthorizedAccessException, so the \(IOException\) assertions would need to become \(UnauthorizedAccessException\).

Either way, drop the Set-Content … 'blocking-file' lines — they currently create a parent file that New-Item -Force tolerates. The script change itself (windows/hotshot-capture.ps1:55-59) is fine and matches #358.


🐝 Hive Agent: scanner | Instance: hosted-available-oke-11-placeholder-r05x | SHA: unknown

— hive: agent=scanner backend=copilot model=claude-fable-5.1 copilot=1.0.88

@hivecommons-hive

Copy link
Copy Markdown
Contributor

@thatguywob this PR is back in your court (stage/072-returned-to-contributor). The hive will not merge it until the head changes.

Failing checks:

  • Pester (Windows script unit tests)

Reply here or push a new head to this branch (same sign-off); CI and the review swarm re-run automatically and the PR returns to the normal path.

Queued in your relay fix queue (1 waiting): fixes are handed out before new work as soon as you have capacity.

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The production change is right; the new Pester fixture does not exercise it, and all four new tests fail in CI on this head.

windows/hotshot-capture.ps1:55-59 is exactly the shape #358 proposed and matches the cannot reserve / could not save handlers directly below it (same Get-RedactedPath + GetBaseException().GetType().Name idiom). No concerns with that hunk.

The fixture is the problem. windows/tests/hotshot-capture.e2e.tests.ps1:329 and :355 block creation by writing a file at TempRoot\nested, expecting New-Item -ItemType Directory -Force -Path …\nested\shots to throw. On the CI runner it does not reach the catch: the Pester run for f8211b2 (CI run 41986623226) shows

  • exits 1 with a hotshot-prefixed error … → Expected 1, but got 0
  • stops before reserving, saving, … → call log is the full 9-call sequence through Invoke-HotshotInjection, not @('Start-Process','Wait-HotshotClipboardImage')
  • does not leak … → the only error on stderr is the stub's Set-Content failing later: Could not find a part of the path '…\nested\shots\hotshot-stub.png' — raw path and all, because that error comes from the stub Image.Save (e2e.tests.ps1:56), not from the script
  • the verbose-logging case → Expected 1, but got 0 for the same reason

So on this head the script runs to completion and exits 0 with the blocking file in place, and the catch at :57 is never entered — the PR validates nothing about the behaviour it changes (and the body's "Tests … were not run locally" is accurate; CI is the first run).

Suggestion: drive the failure the way the sibling cases do rather than through the filesystem. The stub module already exports functions the script calls, and a function wins command precedence over a cmdlet, so a New-Item function in $script:StubModule that throws [System.UnauthorizedAccessException] (the real case in #358: ACL-denied parent) when HOTSHOT_TEST_MKDIR_FAIL=1, wired up as a -MkdirFails switch on Invoke-CaptureScript like -ReserveFails/-SaveFails, would exercise the catch deterministically and let the assertions check (UnauthorizedAccessException). Alternatively an icacls … /deny on TempRoot\nested, but that needs cleanup and is slower.

Also worth re-checking the expectation '\(IOException\)' once the fixture actually throws — the base-exception type depends on how the failure is induced.

— hive: agent=reviewer-2 backend=copilot model=claude-fable-5.1 copilot=1.0.88

Use Directory.CreateDirectory so file collisions reach the redacted failure handler instead of being suppressed by New-Item -Force. Exercise collisions at the target and parent, and preserve existing directory contents.

Signed-off-by: thatguywob <thatguywob@users.noreply.github.com>

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read the change against the tree at 7a8fae8; this looks correct to me.

  • windows/hotshot-capture.ps1:55-61 — [System.IO.Directory]::CreateDirectory wrapped in try/catch routes through Fail + Get-RedactedPath, exactly like the cannot reserve sibling at line 71 and the Linux step at linux/hotshot-capture.sh:160. GetBaseException() correctly unwraps PowerShell's MethodInvocationException, so the test's (IOException) assertion holds for both the blocking-parent and blocking-dir cases.
  • Get-RedactedPath (HotshotCapture.psm1:134-142) returns the fixed redaction placeholder unless HOTSHOT_VERBOSE_LOGGING is set, so the new Pester assertions on the placeholder and the verbose opt-in test check the real contract, not a side effect.
  • Existing-directory behaviour is preserved (CreateDirectory is a no-op on an existing folder) and is covered by the new "preserves its contents" test.

Closes #358 as stated; no scope beyond it. Windows Pester and PSScriptAnalyzer checks are green on this head. Nothing for a human to decide here beyond the merge itself.

— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Ready for a human merge: verdict approved @7a8fae8, 7/7 checks green, DCO yes, soak 10m0s elapsed. Blocked only by role/contributor (no verified hive claim or registry tier).

The hive never approves on your behalf: /lgtm /approve (or merge) if you accept it.

@hivecommons-hive

Copy link
Copy Markdown
Contributor

/lgtm

Posted by @clubanderson from the Hive dashboard; the merge gate decides from here.

@kubestellar-prow

Copy link
Copy Markdown

@hivecommons-hive[bot]: changing LGTM is restricted to collaborators

Details

In response to this:

/lgtm

Posted by @clubanderson from the Hive dashboard; the merge gate decides from here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@hivecommons-hive

Copy link
Copy Markdown
Contributor

/approve

Posted by @clubanderson from the Hive dashboard; the merge gate decides from here.

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by @clubanderson for Hive auto-merge on green CI.

Approved from the Hive dashboard by @clubanderson as the owner decision on a Ready-for-human-merge pull request; the hive's merge sweep merges it on green CI.

@kubestellar-prow

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: hivecommons-hive[bot]
Once this PR has been reviewed and has the lgtm label, please assign kellyaa for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubestellar-prow

Copy link
Copy Markdown

@hivecommons-hive[bot]: changing LGTM is restricted to collaborators

Details

In response to this:

Approved by @clubanderson for Hive auto-merge on green CI.

Approved from the Hive dashboard by @clubanderson as the owner decision on a Ready-for-human-merge pull request; the hive's merge sweep merges it on green CI.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@hivecommons-hive hivecommons-hive Bot added the lgtm Indicates that a PR is ready to be merged. label Nov 5, 2026
@hivecommons-hive

Copy link
Copy Markdown
Contributor

Hive queued this PR but could not set the prow/lgtm commit status, so Prow may strip the lgtm label and the auto-merge queue may not hold.

@hivecommons-hive
hivecommons-hive Bot merged commit 9620698 into hivecommons:main Nov 5, 2026
11 of 12 checks passed
@hivecommons-hive

Copy link
Copy Markdown
Contributor

merged by Hive on behalf of @clubanderson, who approved this head (operator-approval:clubanderson) with "Approve and let hive merge": author @thatguywob holds no trusted-author role; CI green at 7a8fae8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has signed the DCO. lgtm Indicates that a PR is ready to be merged. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[scanner] Windows capture: directory-creation failure prints the raw screenshot path instead of the redacted form

1 participant