Skip to content

fix(test): resolve 13 Windows-only Pester failures#139

Merged
kurone-kito merged 4 commits into
masterfrom
issue/110-fix-ci-resolve-13-windows-only-pester
May 19, 2026
Merged

fix(test): resolve 13 Windows-only Pester failures#139
kurone-kito merged 4 commits into
masterfrom
issue/110-fix-ci-resolve-13-windows-only-pester

Conversation

@kurone-kito
Copy link
Copy Markdown
Owner

@kurone-kito kurone-kito commented May 19, 2026

Summary

Fixes all 13 Windows-only Pester CI failures blocking promotion of
PowerShell tests (Pester) to a required check (issue #110).

  • secret-status.Tests.ps1 (8 failures): escape backslashes in
    Write-Manifest before embedding the home-dir path into a JSON
    here-string — Windows paths with backslashes produced invalid JSON,
    causing the script under test to exit 2 on every invocation.
  • 01-path.Tests.ps1 (1 failure): change the registry-sync
    disable sentinel from '' to ';'; Windows silently deletes
    environment variables set to empty string, so
    Get-RegistryUserPath fell through to the real registry and
    appended live user PATH entries to the reconciled result.
  • 30-mise.Tests.ps1 (2 failures): add
    -Skip:($null -eq (Get-Command 'ghq' ...)) to the two It blocks
    that use Mock ghq; Pester cannot mock a non-existent command, and
    ghq is not installed on the windows-latest runner.
  • set-openssh-default-shell.Tests.ps1 and
    sync-openssh-authorized-keys.Tests.ps1 (1 failure each):
    add a skip guard on the non-elevated assertion; windows-latest
    runs as Administrator, so Test-DotfilesAdminElevation returns
    $true and the Should -BeFalse assertion fails. The skip
    condition uses $IsWindows -and ... to avoid calling
    WindowsIdentity::GetCurrent() at discovery time on non-Windows
    hosts.

Test plan

  • CI: PowerShell tests (Pester) passes on windows-latest with
    0 failures (13 environment-specific skips expected alongside the
    existing 20 platform skips)
  • CI: Bash tests (bats), Lua syntax check, and Linting workflow remain green

Closes #110

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests

    • Added conditional skips for platform- and tool-dependent tests (ghq presence and Windows elevation) to avoid false failures.
    • Improved test isolation by disabling registry PATH sync during runs.
    • Fixed manifest generation in tests to correctly escape backslash-containing home-directory and file paths.
  • Chores

    • Updated spellchecker allowlist to include HKLM.

Review Change Stack

- secret-status: escape backslashes in Write-Manifest JSON here-string
  (Windows paths with backslashes produced invalid JSON → exit 2)
- 01-path: use ';' sentinel instead of '' to disable registry sync;
  Windows deletes env vars set to empty string, causing
  Get-RegistryUserPath to fall through to the real registry
- 30-mise: skip ghq mock tests when ghq is not installed on runner
- set-openssh-default-shell, sync-openssh-authorized-keys: skip the
  non-elevated assertion when the session is running as Administrator
  (guards with $IsWindows to avoid WindowsIdentity on non-Windows)

Closes #110

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

fix(test): resolve 13 Windows-only Pester failures

- secret-status: escape backslashes in Write-Manifest JSON here-string
  (Windows paths with backslashes produced invalid JSON → exit 2)
- 01-path: use ';' sentinel instead of '' to disable registry sync;
  Windows deletes env vars set to empty string, causing
  Get-RegistryUserPath to fall through to the real registry
- 30-mise: skip ghq mock tests when ghq is not installed on runner
- set-openssh-default-shell, sync-openssh-authorized-keys: skip the
  non-elevated assertion when the session is running as Administrator
  (guards with $IsWindows to avoid WindowsIdentity on non-Windows)

Closes #110

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 19, 2026 10:24
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 95d14f03-2f44-4482-bf1d-eb6f946dd31b

📥 Commits

Reviewing files that changed from the base of the PR and between 9b17e70 and 408397f.

📒 Files selected for processing (2)
  • tests/powershell/set-openssh-default-shell.Tests.ps1
  • tests/powershell/sync-openssh-authorized-keys.Tests.ps1
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/powershell/sync-openssh-authorized-keys.Tests.ps1
  • tests/powershell/set-openssh-default-shell.Tests.ps1

📝 Walkthrough

Walkthrough

PowerShell Pester tests updated: registry PATH sentinel set to ';', HomeDir/backslashes escaped for JSON, conditional -Skip guards added for missing ghq and admin-elevation tests, and HKLM added to spellchecker allowlist.

Changes

Windows-only Pester test environment fixes

Layer / File(s) Summary
Test harness registry PATH bypass
tests/powershell/01-path.Tests.ps1
Test setup now sets DOTFILES_TEST_REGISTRY_USER_PATH to ';' (non-null sentinel) so empty split entries are produced and the $norm -ne '' guard prevents fallback to the real Windows registry.
JSON manifest generation with Windows path escaping
tests/powershell/secret-status.Tests.ps1
script:Write-Manifest escapes backslashes in $script:HomeDir (doubling \) before interpolating into secret-deploy-manifest.json's homeDir field; missing-file test uses escaped absPath.
Conditional test skips for missing tools and privilege state
tests/powershell/30-mise.Tests.ps1, tests/powershell/set-openssh-default-shell.Tests.ps1, tests/powershell/sync-openssh-authorized-keys.Tests.ps1
Two 30-mise tests add -Skip when ghq is absent; set-openssh-default-shell and sync-openssh-authorized-keys tests add -Skip conditions tied to Windows Administrator session state.
Spellchecker allowlist update
.cspell.config.yml
Adds HKLM to the words allowlist used by the spell checker.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • kurone-kito/dotfiles#82: Updates .cspell.config.yml to allow HKLM/hklm; overlaps with the spellchecker change in this PR.

Suggested labels

bug

Poem

🐰 I hopped through tests with careful eye,
I doubled slashes so JSON won't cry,
A semicolon sentinel holds the path true,
Skips where tools or privileges are few,
HKLM whispered, and spellchecks flew.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(test): resolve 13 Windows-only Pester failures' clearly and specifically identifies the main change—fixing 13 Windows-only test failures in the Pester test suite.
Description check ✅ Passed The PR description provides a comprehensive summary of the 13 failures, their fixes, and a test plan with acceptance criteria, fully addressing the template requirements.
Linked Issues check ✅ Passed All five code changes directly address the 13 Windows-only failures listed in #110: escaping backslashes in JSON paths [secret-status.Tests.ps1], fixing registry-sync sentinel [01-path.Tests.ps1], skipping when ghq unavailable [30-mise.Tests.ps1], and adding elevation/admin skip guards [set-openssh-default-shell.Tests.ps1 and sync-openssh-authorized-keys.Tests.ps1].
Out of Scope Changes check ✅ Passed All changes are in-scope test and configuration fixes: test guards, escape sequences, and spellchecker allowlist—no unrelated functionality or script logic changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue/110-fix-ci-resolve-13-windows-only-pester

Comment @coderabbitai help to get the list of available commands and usage tips.

HKLM (HKEY_LOCAL_MACHINE) appears in the OpenSSH default-shell and
authorized-keys Pester tests; add it to the project dictionary so the
linter does not flag it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

chore(cspell): add HKLM to project word list

HKLM (HKEY_LOCAL_MACHINE) appears in the OpenSSH default-shell and
authorized-keys Pester tests; add it to the project dictionary so the
linter does not flag it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 01f504a38b

ℹ️ 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".

}

It 'appends ghq-cloned owner paths from chezmoi-ghq-trusted-paths' {
It 'appends ghq-cloned owner paths from chezmoi-ghq-trusted-paths' -Skip:($null -eq (Get-Command 'ghq' -ErrorAction SilentlyContinue)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not skip mocked ghq tests based on host tools

On Windows CI or developer machines that do not have a real ghq executable installed, this -Skip condition prevents the test from running even though the test body immediately mocks both Get-Command ghq and the ghq root call. That means the ghq-trust path behavior is no longer covered in the common environment where ghq is absent; the same host-tool guard was also added to the blank-line case below, so regressions in this mocked flow can pass undetected.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Rejecting: Pester 5 cannot mock a non-existent external command — it must be discoverable via Get-Command before the mock can wrap it. When ghq is absent, Mock ghq { ... } throws CommandNotFoundException during test setup rather than deferring to the mock body. The -Skip guard is therefore the correct fix; the alternative (mocking Get-Command 'ghq' to return a fake object, then also providing a stand-in function named ghq) would be a more invasive rewrite of the test structure than warranted. The test already has a companion case ('skips ghq trusted paths when ghq is not installed') that exercises the no-ghq code path without mocking the binary.


function script:Write-Manifest {
param([string]$CategoriesJson)
$escapedHomeDir = $script:HomeDir.Replace('\', '\\')
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Escape every Windows path in generated manifest JSON

Escaping only homeDir still leaves Windows runs broken for test cases that embed other paths inside CategoriesJson: for example the unskipped “secret file missing is MISSING” case writes "absPath":"$f", where $f contains backslashes on Windows, so the manifest remains invalid JSON and secret-status.ps1 exits 2 before the test can assert MISSING. Build the manifest data with ConvertTo-Json or ensure all interpolated JSON strings in the categories are escaped, not just this top-level field.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in commit 9b17e70 — the 'secret file missing is MISSING' test embeds $f (a Windows path) directly into the categories JSON here-string. Added $fJson = $f.Replace('\\', '\\\\') and used $fJson in the interpolation. All other tests that embed Windows paths in JSON are already skipped on Windows (-Skip:($IsWindows -eq $true)).

Comment on lines +32 to +34
It 'Test-DotfilesAdminElevation returns false for non-elevated session' -Skip:(
$IsWindows -and
([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use a PS5-safe elevated skip guard

On Windows PowerShell 5.1, $IsWindows is undefined and therefore $null, so this -and short-circuits to false and the elevated-session skip never applies; an elevated PS5 Invoke-Pester still runs the assertion and fails. The same guard was added to sync-openssh-authorized-keys.Tests.ps1, so use a PS5-safe Windows check for both elevated skips.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in commit 408397f — replaced $IsWindows -and ... with [System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT -and .... This check is available in both PS5 and PS7, correctly returns false on non-Windows (short-circuiting the WindowsIdentity call), and is not affected by the undefined $IsWindows in Windows PowerShell 5.1.

The 'secret file missing is MISSING' test embeds a Windows path via
$f directly into a JSON heredoc.  Backslashes in the path produce
invalid JSON on Windows.  Escape before interpolation using the same
.Replace pattern applied to Write-Manifest.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

fix(test): escape inline JSON path in secret-status missing test

The 'secret file missing is MISSING' test embeds a Windows path via
$f directly into a JSON heredoc.  Backslashes in the path produce
invalid JSON on Windows.  Escape before interpolation using the same
.Replace pattern applied to Write-Manifest.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR targets Windows-only Pester CI failures (issue #110) so the PowerShell tests (Pester) workflow can be promoted to a required check by removing environment-specific breakages on windows-latest.

Changes:

  • Add Windows-admin-session skip guards for the Test-DotfilesAdminElevation returns false... assertions in the OpenSSH-related test suites.
  • Make 01-path tests reliably disable registry PATH syncing on Windows by using a non-empty sentinel value for DOTFILES_TEST_REGISTRY_USER_PATH.
  • Skip 30-mise ghq-related tests when ghq is not available (to avoid Pester mock limitations).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/powershell/sync-openssh-authorized-keys.Tests.ps1 Skips the “non-elevated session” assertion when running under an elevated Windows runner.
tests/powershell/set-openssh-default-shell.Tests.ps1 Skips the “non-elevated session” assertion when running under an elevated Windows runner.
tests/powershell/secret-status.Tests.ps1 Attempts to fix Windows JSON parsing failures by escaping backslashes in the manifest homeDir value.
tests/powershell/30-mise.Tests.ps1 Skips ghq-dependent tests when ghq is missing (Windows runner environment).
tests/powershell/01-path.Tests.ps1 Uses ; as a non-empty sentinel to prevent Windows from deleting the test override env var.

Comment on lines 21 to 31
function script:Write-Manifest {
param([string]$CategoriesJson)
$escapedHomeDir = $script:HomeDir.Replace('\', '\\')
$body = @"
{
"version": 1,
"manager": "bitwarden",
"os": "linux",
"homeDir": "$script:HomeDir",
"homeDir": "$escapedHomeDir",
"ghqRoot": "",
"categories": $CategoriesJson
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in commit 9b17e70 — the 'secret file missing is MISSING' test was the only non-Windows-skipped case that embedded a Windows path in the categories JSON. Added $fJson = $f.Replace('\\', '\\\\') there. All other tests that contain Windows paths in JSON categories are guarded with -Skip:($IsWindows -eq $true).

$IsWindows is undefined (null) in Windows PowerShell 5.1, so
'$IsWindows -and ...' short-circuits to false on PS5, leaving
elevated PS5 runners unguarded.  Replace with
OSVersion.Platform -eq Win32NT which is available in both PS5 and
PS7 and short-circuits safely on non-Windows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

fix(test): use OSVersion.Platform for PS5-safe elevation skip guard

$IsWindows is undefined (null) in Windows PowerShell 5.1, so
'$IsWindows -and ...' short-circuits to false on PS5, leaving
elevated PS5 runners unguarded.  Replace with
OSVersion.Platform -eq Win32NT which is available in both PS5 and
PS7 and short-circuits safely on non-Windows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@kurone-kito
Copy link
Copy Markdown
Owner Author

E6 snapshot — all review threads acted on, CI green on head SHA 408397f.

Dispositions:

  • Codex thread (30-mise.Tests.ps1:339 — do not skip ghq tests): Rejected — Pester 5 cannot mock non-existent external commands; Mock ghq throws CommandNotFoundException at setup time when ghq is absent. The skip is the correct fix.
  • Codex thread (secret-status.Tests.ps1:23 — escape every Windows path): Accepted — fixed in commit 9b17e70.
  • Codex thread (set-openssh-default-shell.Tests.ps1:34 — PS5-safe guard): Accepted — fixed in commit 408397f (OSVersion.Platform -eq Win32NT).
  • Copilot thread (secret-status.Tests.ps1:31 — escape paths in categories): Accepted — fixed in commit 9b17e70.

claude-code-44806616: IDD automation marker. Do not edit.

@kurone-kito kurone-kito merged commit 4a0b2ed into master May 19, 2026
9 checks passed
@kurone-kito kurone-kito deleted the issue/110-fix-ci-resolve-13-windows-only-pester branch May 19, 2026 10:36
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.

fix(ci): resolve 13 Windows-only Pester failures and promote to required

2 participants