Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cspell.config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ language: en,ja
useGitignore: true
version: '0.2'
words:
- AKIAEXAMPLE
- anomalyco
- curlrc
- desync
Expand Down
34 changes: 34 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,40 @@ jobs:
shell: pwsh
run: Invoke-Pester tests/powershell/ -Output Detailed

powershell51-tests:
name: PowerShell 5.1 tests (Pester)
needs: detect-changes
# Advisory only: not registered in the ruleset's required-check set
# yet, so a failure here does not block merges (#166). Promotion to
# required is a later decision once this leg proves stable.
# always() overrides the default "skip if a need failed" behavior
# so a failed/cancelled detect-changes fails open to running the
# real job, rather than silently skipping it (which would satisfy
# the required-status-check gate without ever having run).
if: |
always() &&
(needs.detect-changes.result != 'success' || needs.detect-changes.outputs.requires_full_ci == 'true')
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: Confirm Windows PowerShell 5.1
shell: powershell
run: |
$PSVersionTable.PSVersion
if ($PSVersionTable.PSVersion.Major -ne 5) {
throw "Expected Windows PowerShell 5.1 (major version 5), got $($PSVersionTable.PSVersion)"
}
- name: Install Pester if needed
shell: powershell
run: |
if (-not (Get-Module -ListAvailable Pester |
Where-Object { $_.Version -ge [version]'5.0' })) {
Install-Module Pester -MinimumVersion 5.0 -Force -SkipPublisherCheck -Scope CurrentUser
}
Comment thread
kurone-kito marked this conversation as resolved.
Comment thread
kurone-kito marked this conversation as resolved.
- name: Run Pester tests
shell: powershell
run: Invoke-Pester tests/powershell/ -Output Detailed
Comment thread
kurone-kito marked this conversation as resolved.
Outdated

lua-syntax:
name: Lua syntax check
needs: detect-changes
Expand Down
2 changes: 1 addition & 1 deletion home/dot_local/bin/executable_secret-deploy-state.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ function Invoke-Record {

$tmp = "$statePath.tmp.$([System.Guid]::NewGuid().ToString('N'))"
try {
Set-Content -LiteralPath $tmp -Value $merged -Encoding utf8NoBOM -NoNewline
[System.IO.File]::WriteAllText($tmp, $merged, [System.Text.UTF8Encoding]::new($false))
Set-RestrictedAcl -Path $tmp
Move-Item -LiteralPath $tmp -Destination $statePath -Force
} catch {
Expand Down
2 changes: 1 addition & 1 deletion tests/powershell/02-cargo.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ BeforeAll {
) '02-cargo.ps1'
}

Describe '02-cargo (Unix pwsh)' -Skip:($IsWindows -eq $true) {
Describe '02-cargo (Unix pwsh)' -Skip:($IsWindows -ne $false) {

BeforeEach {
$script:OriginalHome = $HOME
Expand Down
8 changes: 4 additions & 4 deletions tests/powershell/25-deploy-secret-files.Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BeforeAll {
$script:Fixture = Join-Path $PSScriptRoot 'fixtures' '25-deploy-secret-files.ps1'
$script:Template = Join-Path $PSScriptRoot '..' '..' 'home' `
$script:Fixture = Join-Path (Join-Path $PSScriptRoot 'fixtures') '25-deploy-secret-files.ps1'
$script:Template = Join-Path (Join-Path (Join-Path (Join-Path $PSScriptRoot '..') '..') 'home') `
'run_onchange_after_25-deploy-secret-files.ps1.tmpl'
$script:TemplateContent = Get-Content -Raw $script:Template
}
Expand Down Expand Up @@ -48,15 +48,15 @@ Describe '25-deploy-secret-files template' {

It 'deploys .aws/credentials with correct content' {
& $script:Fixture
$path = Join-Path $env:DOTFILES_TEST_HOME '.aws' 'credentials'
$path = Join-Path (Join-Path $env:DOTFILES_TEST_HOME '.aws') 'credentials'
$path | Should -Exist
$content = Get-Content -Raw $path
$content | Should -Match 'aws_access_key_id = AKIAEXAMPLE'
}

It 'deploys .docker/config.json with correct content' {
& $script:Fixture
$path = Join-Path $env:DOTFILES_TEST_HOME '.docker' 'config.json'
$path = Join-Path (Join-Path $env:DOTFILES_TEST_HOME '.docker') 'config.json'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
$path | Should -Exist
$content = Get-Content -Raw $path
$content | Should -Match '"auths"'
Expand Down
6 changes: 5 additions & 1 deletion tests/powershell/fixtures/generate-authorized-keys.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ $homeDir = if ($env:AUTHORIZED_KEYS_HOME) {

$sshDir = Join-Path $homeDir '.ssh'
$authorized = Join-Path $sshDir 'authorized_keys'
# [System.IO.File] does not understand PS provider paths (e.g. TestDrive:\...),
# so resolve to a real filesystem path before using it with .NET I/O below.
$authorized = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($authorized)
$beginMarker = '# >>> chezmoi managed keys >>>'
$endMarker = '# <<< chezmoi managed keys <<<'

Expand Down Expand Up @@ -72,7 +75,8 @@ if ($hasValidBlock) {
$outLines += $endMarker
}

($outLines -join "`n") + "`n" | Set-Content -Path $authorized -Encoding utf8NoBOM -NoNewline
$authorizedContent = ($outLines -join "`n") + "`n"
[System.IO.File]::WriteAllText($authorized, $authorizedContent, [System.Text.UTF8Encoding]::new($false))

icacls $authorized /inheritance:r `
/grant:r "${env:USERNAME}:(F)" `
Expand Down
16 changes: 12 additions & 4 deletions tests/powershell/fixtures/generate-git-profiles.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,22 @@ else {
}
New-Item -ItemType Directory -Path $profilesDir -Force | Out-Null

# [System.IO.File] does not understand PS provider paths (e.g. TestDrive:\...),
# so resolve to a real filesystem path before using it with .NET I/O below.
$profilesDir = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($profilesDir)

$utf8NoBom = [System.Text.UTF8Encoding]::new($false)

$profilePath = Join-Path $profilesDir 'personal'
@'
$personalProfile = @'
[user]
email = "personal@example.com"
name = "Personal User"
'@ | Set-Content -Path $profilePath -Encoding utf8NoBOM
'@
[System.IO.File]::WriteAllText($profilePath, $personalProfile, $utf8NoBom)

$profilePath = Join-Path $profilesDir 'work'
@'
$workProfile = @'
[user]
email = "work@example.com"
name = "Work User"
Expand All @@ -43,7 +50,8 @@ $profilePath = Join-Path $profilesDir 'work'
[tag]
forceSignAnnotated = true
gpgsign = true
'@ | Set-Content -Path $profilePath -Encoding utf8NoBOM
'@
[System.IO.File]::WriteAllText($profilePath, $workProfile, $utf8NoBom)

$validProfiles = @(
'personal'
Expand Down
59 changes: 37 additions & 22 deletions tests/powershell/generate-authorized-keys.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ BeforeAll {
$script:Fixture = Join-Path $PSScriptRoot 'fixtures/generate-authorized-keys.ps1'
$script:BeginMarker = '# >>> chezmoi managed keys >>>'
$script:EndMarker = '# <<< chezmoi managed keys <<<'

# PS5.1 does not recognize the utf8NoBOM encoding literal accepted by
# Set-Content on PS6+, so write test fixtures via .NET directly.
function script:Set-TestFileUtf8NoBom {
param(
[Parameter(Mandatory, ValueFromPipeline)][AllowEmptyString()][string[]]$Value,
[Parameter(Mandatory)][string]$Path
)
begin { $lines = @() }
process { $lines += $Value }
end {
$content = ($lines -join "`n") + "`n"
[System.IO.File]::WriteAllText($Path, $content, [System.Text.UTF8Encoding]::new($false))
}
}
}

Describe 'generate-authorized-keys' {
Expand Down Expand Up @@ -41,9 +56,9 @@ Describe 'generate-authorized-keys' {

It 'creates a managed block from the available public keys' {
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')
'ssh-ed25519 BBBB secondary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'secondary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'secondary.pub')

& $script:Fixture

Expand All @@ -58,7 +73,7 @@ Describe 'generate-authorized-keys' {

It 'skips missing public keys and keeps the remaining file content' {
'ssh-ed25519 BBBB secondary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'secondary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'secondary.pub')

& $script:Fixture

Expand All @@ -77,9 +92,9 @@ Describe 'generate-authorized-keys' {
}

It 'preserves a foreign line that predates the managed block' {
'ssh-rsa FOREIGN from-cloud-provider' | Set-Content -Path $script:Authorized -Encoding utf8NoBOM
'ssh-rsa FOREIGN from-cloud-provider' | Set-TestFileUtf8NoBom -Path $script:Authorized
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')

& $script:Fixture

Expand All @@ -90,9 +105,9 @@ Describe 'generate-authorized-keys' {

It 'does not duplicate a legacy key already present in an unmarked file' {
@('ssh-ed25519 AAAA primary@test', 'ssh-rsa FOREIGN other-machine') |
Set-Content -Path $script:Authorized -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path $script:Authorized
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')

& $script:Fixture

Expand All @@ -103,15 +118,15 @@ Describe 'generate-authorized-keys' {

It 'preserves foreign lines on both sides of an existing managed block' {
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')
& $script:Fixture

$existing = Get-Content $script:Authorized
@('ssh-rsa FOREIGN-BEFORE ssh-copy-id') + $existing + @('ssh-rsa FOREIGN-AFTER manually-added') |
Set-Content -Path $script:Authorized -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path $script:Authorized

'ssh-ed25519 BBBB secondary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'secondary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'secondary.pub')
& $script:Fixture

$content = Get-Content $script:Authorized
Expand All @@ -123,9 +138,9 @@ Describe 'generate-authorized-keys' {

It 'removes a key from the managed block when it disappears from config' {
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')
'ssh-ed25519 BBBB secondary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'secondary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'secondary.pub')
& $script:Fixture

Remove-Item (Join-Path $script:SshDir.FullName 'primary.pub')
Expand All @@ -138,7 +153,7 @@ Describe 'generate-authorized-keys' {

It 'produces no diff when re-run with unchanged keys' {
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')
& $script:Fixture
$before = Get-Content $script:Authorized -Raw

Expand All @@ -150,9 +165,9 @@ Describe 'generate-authorized-keys' {

It 'falls back to append instead of dropping content when the end marker is missing' {
@('ssh-rsa FOREIGN untouched', $script:BeginMarker, 'ssh-rsa STALE stale-key') |
Set-Content -Path $script:Authorized -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path $script:Authorized
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')

$warnings = & $script:Fixture 3>&1 | Where-Object { $_ -is [System.Management.Automation.WarningRecord] }

Expand All @@ -168,9 +183,9 @@ Describe 'generate-authorized-keys' {
$script:BeginMarker, 'ssh-rsa OLD1 old', $script:EndMarker,
'ssh-rsa FOREIGN between-blocks',
$script:BeginMarker, 'ssh-rsa OLD2 old', $script:EndMarker
) | Set-Content -Path $script:Authorized -Encoding utf8NoBOM
) | Set-TestFileUtf8NoBom -Path $script:Authorized
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')

$warnings = & $script:Fixture 3>&1 | Where-Object { $_ -is [System.Management.Automation.WarningRecord] }

Expand All @@ -182,7 +197,7 @@ Describe 'generate-authorized-keys' {

It 'does not warn about malformed markers on a normal run' {
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')

$warnings = & $script:Fixture 3>&1 | Where-Object { $_ -is [System.Management.Automation.WarningRecord] }

Expand All @@ -191,9 +206,9 @@ Describe 'generate-authorized-keys' {

It 'converges on the same block count after repeated runs when the end marker was missing' {
@('ssh-rsa FOREIGN untouched', $script:BeginMarker, 'ssh-rsa STALE stale-key') |
Set-Content -Path $script:Authorized -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path $script:Authorized
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')

& $script:Fixture | Out-Null
$countAfterRun1 = (Get-Content $script:Authorized | Where-Object { $_ -eq $script:BeginMarker }).Count
Expand All @@ -220,9 +235,9 @@ Describe 'generate-authorized-keys' {
$script:BeginMarker, 'ssh-rsa OLD1 old', $script:EndMarker,
'ssh-rsa FOREIGN between-blocks',
$script:BeginMarker, 'ssh-rsa OLD2 old', $script:EndMarker
) | Set-Content -Path $script:Authorized -Encoding utf8NoBOM
) | Set-TestFileUtf8NoBom -Path $script:Authorized
'ssh-ed25519 AAAA primary@test' |
Set-Content -Path (Join-Path $script:SshDir.FullName 'primary.pub') -Encoding utf8NoBOM
Set-TestFileUtf8NoBom -Path (Join-Path $script:SshDir.FullName 'primary.pub')

& $script:Fixture | Out-Null
& $script:Fixture | Out-Null
Expand Down
2 changes: 1 addition & 1 deletion tests/powershell/secret-deploy-state.Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Tests for the secret-deploy-state pwsh helper.

BeforeAll {
$script:ScriptPath = Join-Path $PSScriptRoot '..' '..' 'home' 'dot_local' 'bin' 'executable_secret-deploy-state.ps1'
$script:ScriptPath = Join-Path (Join-Path (Join-Path (Join-Path (Join-Path (Join-Path $PSScriptRoot '..') '..') 'home') 'dot_local') 'bin') 'executable_secret-deploy-state.ps1'

# A real-world path can contain an apostrophe (e.g. a Windows
# username like O'Connor), which would otherwise break the
Expand Down
12 changes: 6 additions & 6 deletions tests/powershell/secret-status.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# manifest, which works on any host.

BeforeAll {
$script:ScriptPath = Join-Path $PSScriptRoot '..' '..' 'home' 'dot_local' 'bin' 'executable_secret-status.ps1'
$script:ScriptPath = Join-Path (Join-Path (Join-Path (Join-Path (Join-Path (Join-Path $PSScriptRoot '..') '..') 'home') 'dot_local') 'bin') 'executable_secret-status.ps1'
$script:TmpRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("secret-status-" + [Guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Force -Path $TmpRoot | Out-Null
$script:HomeDir = Join-Path $TmpRoot 'home'
Expand Down Expand Up @@ -92,7 +92,7 @@ Describe 'secret-status.ps1' {
@($obj.rows | Where-Object status -eq 'MISSING').Count | Should -BeGreaterThan 0
}

It 'secret file present with correct mode is OK' -Skip:($IsWindows -eq $true) {
It 'secret file present with correct mode is OK' -Skip:($IsWindows -ne $false) {
$f = Join-Path $HomeDir 'secret.txt'
Set-Content -LiteralPath $f -Value 'secret'
& chmod 600 $f
Expand All @@ -107,7 +107,7 @@ Describe 'secret-status.ps1' {
$r.Output | Should -Match 'OK'
}

It 'secret file with wrong mode is WARN' -Skip:($IsWindows -eq $true) {
It 'secret file with wrong mode is WARN' -Skip:($IsWindows -ne $false) {
$f = Join-Path $HomeDir 'secret-bad.txt'
Set-Content -LiteralPath $f -Value 'secret'
& chmod 644 $f
Expand Down Expand Up @@ -156,7 +156,7 @@ Describe 'secret-status.ps1' {
$r.Output | Should -Match 'ghq root unresolved'
}

It 'env file warns when filename not in .gitignore' -Skip:($IsWindows -eq $true) {
It 'env file warns when filename not in .gitignore' -Skip:($IsWindows -ne $false) {
$repo = Join-Path $HomeDir 'repo-warn'
New-Item -ItemType Directory -Force -Path (Join-Path $repo '.git') | Out-Null
$envPath = Join-Path $repo '.env'
Expand All @@ -175,7 +175,7 @@ Describe 'secret-status.ps1' {
$r.Output | Should -Match 'not in .gitignore'
}

It 'env file OK when gitignore lists filename' -Skip:($IsWindows -eq $true) {
It 'env file OK when gitignore lists filename' -Skip:($IsWindows -ne $false) {
$repo = Join-Path $HomeDir 'repo-ok'
New-Item -ItemType Directory -Force -Path (Join-Path $repo '.git') | Out-Null
$envPath = Join-Path $repo '.env'
Expand Down Expand Up @@ -210,7 +210,7 @@ Describe 'secret-status.ps1' {
}
}

Describe 'secret-status.ps1 DRIFT detection' -Skip:($IsWindows -eq $true) {
Describe 'secret-status.ps1 DRIFT detection' -Skip:($IsWindows -ne $false) {
BeforeAll {
$script:StatePath = Join-Path $HomeDir '.config/chezmoi/secret-deploy-state.json'
$script:OrigHome = $env:HOME
Expand Down
Loading
Loading