Skip to content

Commit eb637e2

Browse files
committed
fix(powershell): harden scripts for runtime safety and PS7 compatibility
Fix invalid helper parameter handling in migration scripts. Resolve undefined variable in harvest scan logic. Add PS7 requirements for scripts using PS7-only constructs and correct archive context depth usage. Add legacy template fallback in update-agent-context and validate script parsing/smoke runs.
1 parent ed1e302 commit eb637e2

10 files changed

Lines changed: 74 additions & 11 deletions

File tree

.documentation/scripts/migrate-to-documentation.ps1

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@ $script:WarningsCount = 0
2424
function Write-ColorOutput {
2525
param(
2626
[string]$Message,
27-
[string]$Color = "White"
27+
[string]$Color = "White",
28+
[switch]$NoNewline
2829
)
29-
Write-Host $Message -ForegroundColor $Color
30+
if ($NoNewline) {
31+
Write-Host $Message -ForegroundColor $Color -NoNewline
32+
} else {
33+
Write-Host $Message -ForegroundColor $Color
34+
}
3035
}
3136

3237
function Print-Status {

.documentation/specs/main/plan.md

Whitespace-only changes.

.tmp-smoke.ps1

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
$ErrorActionPreference='Continue'
2+
$tests=@(
3+
@{Script='scripts/powershell/check-prerequisites.ps1';Args=@('-Help')},
4+
@{Script='scripts/powershell/create-new-feature.ps1';Args=@('-Help')},
5+
@{Script='scripts/powershell/archive-context.ps1';Args=@('-Json')},
6+
@{Script='scripts/powershell/evolution-context.ps1';Args=@('-Json')},
7+
@{Script='scripts/powershell/harvest.ps1';Args=@('-Scope','scan','-Json')},
8+
@{Script='scripts/powershell/migrate-to-documentation.ps1';Args=@('-DryRun')},
9+
@{Script='scripts/powershell/quickfix-context.ps1';Args=@('-Json')},
10+
@{Script='scripts/powershell/release-context.ps1';Args=@('-Json','-DryRun')},
11+
@{Script='scripts/powershell/setup-plan.ps1';Args=@('-Help')},
12+
@{Script='scripts/powershell/site-audit.ps1';Args=@('-Scope','constitution','-OutputFormat','summary')},
13+
@{Script='scripts/powershell/update-agent-context.ps1';Args=@()}
14+
)
15+
$results=foreach($t in $tests){
16+
$scriptPath=Join-Path (Get-Location) $t.Script
17+
$argList=@('-NoProfile','-ExecutionPolicy','Bypass','-File',$scriptPath)+$t.Args
18+
$cmdText='pwsh '+(($argList|ForEach-Object{ if($_ -match '\s'){ '"'+$_+'"' } else { $_ } }) -join ' ')
19+
$outFile=[System.IO.Path]::GetTempFileName(); $errFile=[System.IO.Path]::GetTempFileName()
20+
$exit=1; $timedOut=$false; $startErr=$null
21+
try {
22+
$p=Start-Process -FilePath 'pwsh' -ArgumentList $argList -PassThru -RedirectStandardOutput $outFile -RedirectStandardError $errFile -ErrorAction Stop
23+
try { Wait-Process -Id $p.Id -Timeout 45 -ErrorAction Stop } catch { $timedOut=$true }
24+
if($timedOut -and $p -and -not $p.HasExited){ Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue }
25+
if($timedOut){ $exit=124 } else { $exit=$p.ExitCode }
26+
} catch { $startErr=$_.Exception.Message; $exit=1 }
27+
$stdout=@(); $stderr=@()
28+
if(Test-Path -LiteralPath $outFile){ $stdout=Get-Content -LiteralPath $outFile -ErrorAction SilentlyContinue }
29+
if(Test-Path -LiteralPath $errFile){ $stderr=Get-Content -LiteralPath $errFile -ErrorAction SilentlyContinue }
30+
Remove-Item -LiteralPath $outFile,$errFile -ErrorAction SilentlyContinue
31+
$lines=@()
32+
if($startErr){ $lines += $startErr }
33+
if($stderr){ $lines += $stderr }
34+
if($stdout){ $lines += $stdout }
35+
$lines=$lines|Where-Object{ $_ -and $_.ToString().Trim().Length -gt 0 }
36+
$firstErr=$lines|Where-Object{ $_ -match '(?i)(^\s*error\b|exception|failed|not recognized|cannot|invalid|parsererror|at line:)' }|Select-Object -First 1
37+
if(-not $firstErr -and $exit -ne 0){ $firstErr=$lines|Select-Object -First 1 }
38+
$status = if($exit -eq 0){'PASS'} elseif($exit -eq 124){'TIMEOUT'} else {'FAIL'}
39+
[pscustomobject]@{ Script=$t.Script; Command=$cmdText; ExitCode=$exit; Status=$status; KeyError=(if($firstErr){$firstErr.ToString().Trim()}else{''}) }
40+
}
41+
$results | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath '.tmp-smoke-results.json'
42+
$results | Format-Table -AutoSize

scripts/powershell/archive-context.ps1

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env pwsh
2+
#requires -Version 7.0
23
# Archive context gathering script
34
# Scans .documentation/ for archive candidates (never reads .archive/)
45
# Outputs inventory for the AI to review and act on
@@ -55,9 +56,9 @@ $drafts = Get-RelativeMdFiles '.documentation/drafts'
5556
$sessionDocs = Get-RelativeMdFiles '.documentation/copilot'
5657
$implPlans = @()
5758
if (Test-Path $docDir) {
58-
$implPlans = Get-ChildItem -Path $docDir -MaxDepth 1 -Filter '*-implementation-plan.md' -ErrorAction SilentlyContinue |
59+
$implPlans = Get-ChildItem -Path $docDir -Depth 1 -Filter '*-implementation-plan.md' -ErrorAction SilentlyContinue |
5960
ForEach-Object { $_.FullName.Substring($repoRoot.Length + 1).Replace('\', '/') }
60-
$implPlans += Get-ChildItem -Path $docDir -MaxDepth 1 -Filter '*-plan.md' -ErrorAction SilentlyContinue |
61+
$implPlans += Get-ChildItem -Path $docDir -Depth 1 -Filter '*-plan.md' -ErrorAction SilentlyContinue |
6162
Where-Object { $_.Name -notmatch '^Guide' } |
6263
ForEach-Object { $_.FullName.Substring($repoRoot.Length + 1).Replace('\', '/') }
6364
}
@@ -68,7 +69,7 @@ $prReviews = Get-RelativeMdFiles '.documentation/specs/pr-review'
6869
# Current top-level .documentation/*.md (exclude already-caught plan files)
6970
$currentDocs = @()
7071
if (Test-Path $docDir) {
71-
$currentDocs = Get-ChildItem -Path $docDir -MaxDepth 1 -Filter '*.md' -ErrorAction SilentlyContinue |
72+
$currentDocs = Get-ChildItem -Path $docDir -Depth 1 -Filter '*.md' -ErrorAction SilentlyContinue |
7273
Where-Object { $_.Name -notmatch '-implementation-plan\.md$' -and $_.Name -notmatch '-plan\.md$' } |
7374
ForEach-Object { $_.FullName.Substring($repoRoot.Length + 1).Replace('\', '/') } |
7475
Sort-Object

scripts/powershell/get-pr-context.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env pwsh
2+
#requires -Version 7.0
23
# Extract PR context for review
34
#
45
# This script fetches Pull Request information from GitHub and provides it

scripts/powershell/harvest.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ if ($Scope -in @('full', 'docs', 'scan', 'changelog')) {
452452
# Check if referenced in any .md file
453453
$isReferenced = $false
454454
$fileName = $file.Name
455-
Get-ChildItem $docDir -Recurse -Filter '*.md' -ErrorAction SilentlyContinue | ForEach-Object {
455+
Get-ChildItem $docRoot.path -Recurse -Filter '*.md' -ErrorAction SilentlyContinue | ForEach-Object {
456456
if (-not $isReferenced) {
457457
$mdContent = Get-Content $_.FullName -Raw -ErrorAction SilentlyContinue
458458
if ($mdContent -and $mdContent -match [regex]::Escape($fileName)) {

scripts/powershell/migrate-to-documentation.ps1

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@ $script:WarningsCount = 0
2424
function Write-ColorOutput {
2525
param(
2626
[string]$Message,
27-
[string]$Color = "White"
27+
[string]$Color = "White",
28+
[switch]$NoNewline
2829
)
29-
Write-Host $Message -ForegroundColor $Color
30+
if ($NoNewline) {
31+
Write-Host $Message -ForegroundColor $Color -NoNewline
32+
} else {
33+
Write-Host $Message -ForegroundColor $Color
34+
}
3035
}
3136

3237
function Print-Status {

scripts/powershell/site-audit.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env pwsh
2+
#requires -Version 7.0
23
<#
34
.SYNOPSIS
45
Gathers codebase data for site-audit as JSON for LLM context efficiency.

scripts/powershell/sync-upstream.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env pwsh
2+
#requires -Version 7.0
23
<#
34
.SYNOPSIS
45
Sync Spec Kit Spark with upstream github.com/github/spec-kit repository

scripts/powershell/update-agent-context.ps1

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ $Q_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
6262
$BOB_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
6363

6464
$TEMPLATE_FILE = Join-Path $REPO_ROOT '.documentation/templates/agent-file-template.md'
65+
$LEGACY_TEMPLATE_FILE = Join-Path $REPO_ROOT 'templates/agent-file-template.md'
6566

6667
# Parsed plan data placeholders
6768
$script:NEW_LANG = ''
@@ -114,9 +115,15 @@ function Validate-Environment {
114115
exit 1
115116
}
116117
if (-not (Test-Path $TEMPLATE_FILE)) {
117-
Write-Err "Template file not found at $TEMPLATE_FILE"
118-
Write-Info 'Run specify init to scaffold .documentation/templates, or add agent-file-template.md there.'
119-
exit 1
118+
if (Test-Path $LEGACY_TEMPLATE_FILE) {
119+
Write-WarningMsg "Primary template not found at $TEMPLATE_FILE; using legacy template at $LEGACY_TEMPLATE_FILE"
120+
$script:TEMPLATE_FILE = $LEGACY_TEMPLATE_FILE
121+
} else {
122+
Write-Err "Template file not found at $TEMPLATE_FILE"
123+
Write-Info "Legacy fallback also not found at $LEGACY_TEMPLATE_FILE"
124+
Write-Info 'Run specify init to scaffold .documentation/templates, or add agent-file-template.md there.'
125+
exit 1
126+
}
120127
}
121128
}
122129

0 commit comments

Comments
 (0)