test(smoke): execute and extend Codex UTF-8 regression
CI / routing tests (ubuntu-latest) (push) Canceled after 0s
CI / routing tests (windows-latest) (push) Canceled after 0s
CI / shell script syntax check (push) Canceled after 0s
CI / field-journal leak scan (push) Canceled after 0s
CI / case contract test (ctf-demo) (push) Canceled after 0s
CI / version consistency (push) Canceled after 0s
CI / routing tests (ubuntu-latest) (push) Canceled after 0s
CI / routing tests (windows-latest) (push) Canceled after 0s
CI / shell script syntax check (push) Canceled after 0s
CI / field-journal leak scan (push) Canceled after 0s
CI / case contract test (ctf-demo) (push) Canceled after 0s
CI / version consistency (push) Canceled after 0s
This commit is contained in:
+209
-222
@@ -1,231 +1,218 @@
|
||||
#Requires -Version 5.1
|
||||
# reverse-skill smoke entrypoint: verify + script parse + master-route sample matrix.
|
||||
# Usage:
|
||||
# powershell -NoProfile -ExecutionPolicy Bypass -File skills/scripts/smoke.ps1
|
||||
# powershell -File skills/scripts/smoke.ps1 -LogDir C:\path\to\logs
|
||||
param(
|
||||
[string] $LogDir = '',
|
||||
[string] $PackageRoot = ''
|
||||
)
|
||||
$ErrorActionPreference = 'Continue'
|
||||
|
||||
$scriptDir = $PSScriptRoot
|
||||
if (-not $scriptDir) { $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path }
|
||||
$skillsRoot = Split-Path -Parent $scriptDir
|
||||
if (-not $PackageRoot) { $PackageRoot = Split-Path -Parent $skillsRoot }
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($LogDir)) {
|
||||
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$tmpBase = if ($env:TEMP) { $env:TEMP } else { [System.IO.Path]::GetTempPath() }
|
||||
$LogDir = Join-Path $tmpBase ("rs-smoke-{0}" -f $stamp)
|
||||
}
|
||||
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
|
||||
|
||||
$fail = New-Object System.Collections.Generic.List[string]
|
||||
function Ok([string] $m) { Write-Host ("[OK] {0}" -f $m) -ForegroundColor Green }
|
||||
function Bad([string] $m) {
|
||||
Write-Host ("[FAIL] {0}" -f $m) -ForegroundColor Red
|
||||
[void]$fail.Add($m)
|
||||
}
|
||||
|
||||
# Prefer the same host that launched smoke (pwsh on GHA windows-latest).
|
||||
# Bare "powershell" often resolves to Windows PowerShell 5.1, which mis-parses
|
||||
# UTF-8 scripts without BOM when nested from pwsh.
|
||||
$SmokeHostExe = $null
|
||||
try {
|
||||
$procPath = (Get-Process -Id $PID -ErrorAction Stop).Path
|
||||
if ($procPath -and (Test-Path -LiteralPath $procPath)) { $SmokeHostExe = $procPath }
|
||||
} catch { }
|
||||
if (-not $SmokeHostExe) {
|
||||
$cmd = Get-Command pwsh -ErrorAction SilentlyContinue
|
||||
if ($cmd -and $cmd.Source) {
|
||||
$SmokeHostExe = $cmd.Source
|
||||
} else {
|
||||
$SmokeHostExe = Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe'
|
||||
}
|
||||
}
|
||||
Write-Host ("=== reverse-skill smoke | LogDir={0} | Host={1} ===" -f $LogDir, $SmokeHostExe)
|
||||
|
||||
# --- 1) routing coherence ---
|
||||
$verify = Join-Path $scriptDir 'verify-routing-coherence.ps1'
|
||||
if (-not (Test-Path -LiteralPath $verify)) {
|
||||
Bad 'verify-routing-coherence.ps1 missing'
|
||||
$verifyExit = 1
|
||||
} else {
|
||||
$vLog = Join-Path $LogDir '01-verify.txt'
|
||||
& $SmokeHostExe -NoProfile -ExecutionPolicy Bypass -File $verify 2>&1 | Tee-Object -FilePath $vLog | Out-Null
|
||||
$verifyExit = $LASTEXITCODE
|
||||
if ($verifyExit -eq 0) { Ok 'verify-routing-coherence exit 0' } else { Bad ("verify-routing-coherence exit {0}" -f $verifyExit) }
|
||||
}
|
||||
|
||||
# --- 2) parse key scripts ---
|
||||
$scripts = @(
|
||||
'verify-routing-coherence.ps1',
|
||||
'master-route.ps1',
|
||||
'case-init.ps1',
|
||||
'lib/WorkRoot.ps1',
|
||||
'lib/RouteScope.ps1',
|
||||
'bootstrap-reverse.ps1',
|
||||
'refresh-tool-index.ps1',
|
||||
'smoke.ps1',
|
||||
'append-evidence.ps1',
|
||||
'case-guard.ps1',
|
||||
'test-routing.ps1',
|
||||
'extract-summaries.ps1',
|
||||
#Requires -Version 5.1
|
||||
# reverse-skill smoke entrypoint: verify + script parse + master-route sample matrix.
|
||||
# Usage:
|
||||
# powershell -NoProfile -ExecutionPolicy Bypass -File skills/scripts/smoke.ps1
|
||||
# powershell -File skills/scripts/smoke.ps1 -LogDir C:\path\to\logs
|
||||
param(
|
||||
[string] $LogDir = '',
|
||||
[string] $PackageRoot = ''
|
||||
)
|
||||
$ErrorActionPreference = 'Continue'
|
||||
|
||||
$scriptDir = $PSScriptRoot
|
||||
if (-not $scriptDir) { $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path }
|
||||
$skillsRoot = Split-Path -Parent $scriptDir
|
||||
if (-not $PackageRoot) { $PackageRoot = Split-Path -Parent $skillsRoot }
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($LogDir)) {
|
||||
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$tmpBase = if ($env:TEMP) { $env:TEMP } else { [System.IO.Path]::GetTempPath() }
|
||||
$LogDir = Join-Path $tmpBase ("rs-smoke-{0}" -f $stamp)
|
||||
}
|
||||
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
|
||||
|
||||
$fail = New-Object System.Collections.Generic.List[string]
|
||||
function Ok([string] $m) { Write-Host ("[OK] {0}" -f $m) -ForegroundColor Green }
|
||||
function Bad([string] $m) {
|
||||
Write-Host ("[FAIL] {0}" -f $m) -ForegroundColor Red
|
||||
[void]$fail.Add($m)
|
||||
}
|
||||
|
||||
# Prefer the same host that launched smoke (pwsh on GHA windows-latest).
|
||||
# Bare "powershell" often resolves to Windows PowerShell 5.1, which mis-parses
|
||||
# UTF-8 scripts without BOM when nested from pwsh.
|
||||
$SmokeHostExe = $null
|
||||
try {
|
||||
$procPath = (Get-Process -Id $PID -ErrorAction Stop).Path
|
||||
if ($procPath -and (Test-Path -LiteralPath $procPath)) { $SmokeHostExe = $procPath }
|
||||
} catch { }
|
||||
if (-not $SmokeHostExe) {
|
||||
$cmd = Get-Command pwsh -ErrorAction SilentlyContinue
|
||||
if ($cmd -and $cmd.Source) {
|
||||
$SmokeHostExe = $cmd.Source
|
||||
} else {
|
||||
$SmokeHostExe = Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe'
|
||||
}
|
||||
}
|
||||
Write-Host ("=== reverse-skill smoke | LogDir={0} | Host={1} ===" -f $LogDir, $SmokeHostExe)
|
||||
|
||||
# --- 1) routing coherence ---
|
||||
$verify = Join-Path $scriptDir 'verify-routing-coherence.ps1'
|
||||
if (-not (Test-Path -LiteralPath $verify)) {
|
||||
Bad 'verify-routing-coherence.ps1 missing'
|
||||
$verifyExit = 1
|
||||
} else {
|
||||
$vLog = Join-Path $LogDir '01-verify.txt'
|
||||
& $SmokeHostExe -NoProfile -ExecutionPolicy Bypass -File $verify 2>&1 | Tee-Object -FilePath $vLog | Out-Null
|
||||
$verifyExit = $LASTEXITCODE
|
||||
if ($verifyExit -eq 0) { Ok 'verify-routing-coherence exit 0' } else { Bad ("verify-routing-coherence exit {0}" -f $verifyExit) }
|
||||
}
|
||||
|
||||
# --- 2) parse key scripts ---
|
||||
$scripts = @(
|
||||
'verify-routing-coherence.ps1',
|
||||
'master-route.ps1',
|
||||
'case-init.ps1',
|
||||
'lib\WorkRoot.ps1',
|
||||
'bootstrap-reverse.ps1',
|
||||
'refresh-tool-index.ps1',
|
||||
'smoke.ps1',
|
||||
'append-evidence.ps1',
|
||||
'case-guard.ps1',
|
||||
'test-routing.ps1',
|
||||
'extract-summaries.ps1'
|
||||
'test-bootstrap-codex-encoding.ps1'
|
||||
)
|
||||
$parseOk = 0
|
||||
$parseFail = 0
|
||||
$parseLog = New-Object System.Collections.Generic.List[string]
|
||||
foreach ($name in $scripts) {
|
||||
$p = Join-Path $scriptDir $name
|
||||
if (-not (Test-Path -LiteralPath $p)) {
|
||||
# append-evidence is required for P0; others should exist
|
||||
if ($name -eq 'append-evidence.ps1' -or $name -eq 'smoke.ps1') {
|
||||
Bad ("script missing: {0}" -f $name)
|
||||
$parseFail++
|
||||
[void]$parseLog.Add("MISSING $name")
|
||||
}
|
||||
continue
|
||||
}
|
||||
$errs = $null
|
||||
$tokens = $null
|
||||
$null = [System.Management.Automation.Language.Parser]::ParseFile($p, [ref]$tokens, [ref]$errs)
|
||||
if ($errs -and $errs.Count -gt 0) {
|
||||
Bad ("parse fail {0}: {1}" -f $name, $errs[0].Message)
|
||||
$parseFail++
|
||||
[void]$parseLog.Add("FAIL $name $($errs[0].Message)")
|
||||
} else {
|
||||
Ok ("parse {0}" -f $name)
|
||||
$parseOk++
|
||||
[void]$parseLog.Add("OK $name")
|
||||
}
|
||||
}
|
||||
$idaScripts = @(
|
||||
'ida-reverse/scripts/start.ps1',
|
||||
'ida-reverse/scripts/open.ps1',
|
||||
'ida-reverse/scripts/watchdog.ps1',
|
||||
'ida-reverse/scripts/install-autostart.ps1',
|
||||
'ida-reverse/scripts/start-gui.ps1',
|
||||
'ida-reverse/scripts/IdaOpenHelpers.ps1'
|
||||
)
|
||||
foreach ($rel in $idaScripts) {
|
||||
$p = Join-Path $skillsRoot $rel
|
||||
$name = $rel
|
||||
if (-not (Test-Path -LiteralPath $p)) {
|
||||
Bad ("script missing: {0}" -f $name)
|
||||
$parseFail++
|
||||
[void]$parseLog.Add("MISSING $name")
|
||||
continue
|
||||
}
|
||||
$errs = $null
|
||||
$tokens = $null
|
||||
$null = [System.Management.Automation.Language.Parser]::ParseFile($p, [ref]$tokens, [ref]$errs)
|
||||
if ($errs -and $errs.Count -gt 0) {
|
||||
Bad ("parse fail {0}: {1}" -f $name, $errs[0].Message)
|
||||
$parseFail++
|
||||
[void]$parseLog.Add("FAIL $name $($errs[0].Message)")
|
||||
} else {
|
||||
Ok ("parse {0}" -f $name)
|
||||
$parseOk++
|
||||
[void]$parseLog.Add("OK $name")
|
||||
}
|
||||
}
|
||||
$parseOk = 0
|
||||
$parseFail = 0
|
||||
$parseLog = New-Object System.Collections.Generic.List[string]
|
||||
foreach ($name in $scripts) {
|
||||
$p = Join-Path $scriptDir $name
|
||||
if (-not (Test-Path -LiteralPath $p)) {
|
||||
# append-evidence is required for P0; others should exist
|
||||
if ($name -eq 'append-evidence.ps1' -or $name -eq 'smoke.ps1') {
|
||||
Bad ("script missing: {0}" -f $name)
|
||||
$parseFail++
|
||||
[void]$parseLog.Add("MISSING $name")
|
||||
}
|
||||
continue
|
||||
}
|
||||
$errs = $null
|
||||
$tokens = $null
|
||||
$null = [System.Management.Automation.Language.Parser]::ParseFile($p, [ref]$tokens, [ref]$errs)
|
||||
if ($errs -and $errs.Count -gt 0) {
|
||||
Bad ("parse fail {0}: {1}" -f $name, $errs[0].Message)
|
||||
$parseFail++
|
||||
[void]$parseLog.Add("FAIL $name $($errs[0].Message)")
|
||||
} else {
|
||||
Ok ("parse {0}" -f $name)
|
||||
$parseOk++
|
||||
[void]$parseLog.Add("OK $name")
|
||||
}
|
||||
}
|
||||
$parseLog -join [Environment]::NewLine | Set-Content (Join-Path $LogDir '02-parse.txt') -Encoding UTF8
|
||||
|
||||
# --- 3) master-route sample matrix ---
|
||||
$mr = Join-Path $scriptDir 'master-route.ps1'
|
||||
$cases = @(
|
||||
@{ Name = 'apk'; Hint = 'decompile APK with jadx apktool smali'; Expect = 'apk-reverse' },
|
||||
@{ Name = 'js'; Hint = 'js reverse frontend sign jshook encrypted param'; Expect = 'js-reverse' },
|
||||
@{ Name = 'ida'; Hint = 'IDA decompile PE binary disassemble'; Expect = 'ida-reverse' },
|
||||
@{ Name = 'pentest'; Hint = 'nmap nuclei sqlmap ffuf pentest bug bounty'; Expect = 'pentest-tools' },
|
||||
@{ Name = 'llm'; Hint = 'LLM prompt inject jailbreak agent security garak'; Expect = 'llm-security' },
|
||||
@{ Name = 'zh-apk'; Hint = '安卓 APK 加固 反编译'; Expect = 'apk-reverse' },
|
||||
@{ Name = 'zh-pentest'; Hint = '渗透测试 端口扫描 SQL注入'; Expect = 'pentest-tools' },
|
||||
@{ Name = 'zh-js'; Hint = '前端签名 JS逆向 加密参数'; Expect = 'js-reverse' },
|
||||
@{ Name = 'evidence'; Hint = 'case review evidence chain traceability'; Expect = 'case-review' }
|
||||
)
|
||||
$routeOk = 0
|
||||
$routeFail = 0
|
||||
$routeSummary = New-Object System.Collections.Generic.List[string]
|
||||
if (-not (Test-Path -LiteralPath $mr)) {
|
||||
Bad 'master-route.ps1 missing'
|
||||
# --- 3) Codex config UTF-8 round-trip regression ---
|
||||
$encodingTest = Join-Path $scriptDir 'test-bootstrap-codex-encoding.ps1'
|
||||
if (-not (Test-Path -LiteralPath $encodingTest)) {
|
||||
Bad 'test-bootstrap-codex-encoding.ps1 missing'
|
||||
} else {
|
||||
foreach ($c in $cases) {
|
||||
$outFile = Join-Path $LogDir ("route-{0}.txt" -f $c.Name)
|
||||
$raw = & $SmokeHostExe -NoProfile -ExecutionPolicy Bypass -File $mr -Hint $c.Hint 2>&1 | Out-String
|
||||
$raw | Set-Content -Path $outFile -Encoding UTF8
|
||||
if ($raw -match [regex]::Escape($c.Expect)) {
|
||||
Ok ("route {0} -> {1}" -f $c.Name, $c.Expect)
|
||||
$routeOk++
|
||||
[void]$routeSummary.Add("PASS $($c.Name)")
|
||||
} else {
|
||||
Bad ("route {0} expect {1}" -f $c.Name, $c.Expect)
|
||||
$routeFail++
|
||||
[void]$routeSummary.Add("FAIL $($c.Name)")
|
||||
}
|
||||
}
|
||||
}
|
||||
$routeSummary -join [Environment]::NewLine | Set-Content (Join-Path $LogDir '03-route-summary.txt') -Encoding UTF8
|
||||
|
||||
# --- 4) Evidence ID immutability ---
|
||||
$appendEvidence = Join-Path $scriptDir 'append-evidence.ps1'
|
||||
$evidenceCase = Join-Path $LogDir 'evidence-immutability'
|
||||
if (-not (Test-Path -LiteralPath $appendEvidence)) {
|
||||
Bad 'append-evidence.ps1 missing for immutability check'
|
||||
} else {
|
||||
New-Item -ItemType Directory -Path $evidenceCase -Force | Out-Null
|
||||
& $SmokeHostExe -NoProfile -ExecutionPolicy Bypass -File $appendEvidence `
|
||||
-CaseRoot $evidenceCase `
|
||||
-Id 'E-IMMUTABLE' `
|
||||
-Title 'first write' `
|
||||
-ReproCommand 'echo first' 2>&1 | Out-Null
|
||||
$firstEvidenceExit = $LASTEXITCODE
|
||||
if ($firstEvidenceExit -ne 0) {
|
||||
Bad ("initial Evidence append exit {0}" -f $firstEvidenceExit)
|
||||
$encodingLog = Join-Path $LogDir '03-codex-encoding.txt'
|
||||
& $SmokeHostExe -NoProfile -ExecutionPolicy Bypass -File $encodingTest `
|
||||
-ScratchDir (Join-Path $LogDir 'codex-encoding') 2>&1 |
|
||||
Tee-Object -FilePath $encodingLog | Out-Null
|
||||
$encodingExit = $LASTEXITCODE
|
||||
if ($encodingExit -eq 0) {
|
||||
Ok 'Codex config UTF-8 round-trip regression'
|
||||
} else {
|
||||
$evidencePath = Join-Path $evidenceCase 'evidence/E-IMMUTABLE.md'
|
||||
$indexPath = Join-Path $evidenceCase 'evidence/INDEX.md'
|
||||
$beforeEvidence = (Get-FileHash -LiteralPath $evidencePath -Algorithm SHA256).Hash
|
||||
$beforeIndex = (Get-FileHash -LiteralPath $indexPath -Algorithm SHA256).Hash
|
||||
|
||||
& $SmokeHostExe -NoProfile -ExecutionPolicy Bypass -File $appendEvidence `
|
||||
-CaseRoot $evidenceCase `
|
||||
-Id 'E-IMMUTABLE' `
|
||||
-Title 'second write' `
|
||||
-ReproCommand 'echo second' 2>&1 | Out-Null
|
||||
$duplicateEvidenceExit = $LASTEXITCODE
|
||||
|
||||
$afterEvidence = (Get-FileHash -LiteralPath $evidencePath -Algorithm SHA256).Hash
|
||||
$afterIndex = (Get-FileHash -LiteralPath $indexPath -Algorithm SHA256).Hash
|
||||
if ($duplicateEvidenceExit -eq 0) {
|
||||
Bad 'duplicate Evidence ID was accepted'
|
||||
} elseif ($beforeEvidence -ne $afterEvidence) {
|
||||
Bad 'existing Evidence changed after duplicate append'
|
||||
} elseif ($beforeIndex -ne $afterIndex) {
|
||||
Bad 'Evidence index changed after duplicate append'
|
||||
} else {
|
||||
Ok 'duplicate Evidence ID rejected without mutation'
|
||||
}
|
||||
Bad ("Codex config UTF-8 regression exit {0}" -f $encodingExit)
|
||||
}
|
||||
}
|
||||
|
||||
# --- summary ---
|
||||
$summary = @(
|
||||
"VERIFY_EXIT=$verifyExit",
|
||||
"PARSE ok=$parseOk fail=$parseFail",
|
||||
"ROUTE ok=$routeOk fail=$routeFail / $($cases.Count)",
|
||||
"FAIL_COUNT=$($fail.Count)",
|
||||
"LogDir=$LogDir"
|
||||
)
|
||||
$summary -join [Environment]::NewLine | Set-Content (Join-Path $LogDir 'SUMMARY.txt') -Encoding UTF8
|
||||
Write-Host '=== SMOKE SUMMARY ==='
|
||||
$summary | ForEach-Object { Write-Host $_ }
|
||||
if ($fail.Count -gt 0) {
|
||||
$fail | Set-Content (Join-Path $LogDir 'failures.txt') -Encoding UTF8
|
||||
Write-Host 'OVERALL: FAIL' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
Write-Host 'OVERALL: ALL PASS' -ForegroundColor Green
|
||||
exit 0
|
||||
# --- 4) master-route sample matrix ---
|
||||
$mr = Join-Path $scriptDir 'master-route.ps1'
|
||||
$cases = @(
|
||||
@{ Name = 'apk'; Hint = 'decompile APK with jadx apktool smali'; Expect = 'apk-reverse' },
|
||||
@{ Name = 'js'; Hint = 'js reverse frontend sign jshook encrypted param'; Expect = 'js-reverse' },
|
||||
@{ Name = 'ida'; Hint = 'IDA decompile PE binary disassemble'; Expect = 'ida-reverse' },
|
||||
@{ Name = 'pentest'; Hint = 'nmap nuclei sqlmap ffuf pentest bug bounty'; Expect = 'pentest-tools' },
|
||||
@{ Name = 'llm'; Hint = 'LLM prompt inject jailbreak agent security garak'; Expect = 'llm-security' },
|
||||
@{ Name = 'zh-apk'; Hint = '安卓 APK 加固 反编译'; Expect = 'apk-reverse' },
|
||||
@{ Name = 'zh-pentest'; Hint = '渗透测试 端口扫描 SQL注入'; Expect = 'pentest-tools' },
|
||||
@{ Name = 'zh-js'; Hint = '前端签名 JS逆向 加密参数'; Expect = 'js-reverse' },
|
||||
@{ Name = 'evidence'; Hint = 'case review evidence chain traceability'; Expect = 'case-review' }
|
||||
)
|
||||
$routeOk = 0
|
||||
$routeFail = 0
|
||||
$routeSummary = New-Object System.Collections.Generic.List[string]
|
||||
if (-not (Test-Path -LiteralPath $mr)) {
|
||||
Bad 'master-route.ps1 missing'
|
||||
} else {
|
||||
foreach ($c in $cases) {
|
||||
$outFile = Join-Path $LogDir ("route-{0}.txt" -f $c.Name)
|
||||
$raw = & $SmokeHostExe -NoProfile -ExecutionPolicy Bypass -File $mr -Hint $c.Hint 2>&1 | Out-String
|
||||
$raw | Set-Content -Path $outFile -Encoding UTF8
|
||||
if ($raw -match [regex]::Escape($c.Expect)) {
|
||||
Ok ("route {0} -> {1}" -f $c.Name, $c.Expect)
|
||||
$routeOk++
|
||||
[void]$routeSummary.Add("PASS $($c.Name)")
|
||||
} else {
|
||||
Bad ("route {0} expect {1}" -f $c.Name, $c.Expect)
|
||||
$routeFail++
|
||||
[void]$routeSummary.Add("FAIL $($c.Name)")
|
||||
}
|
||||
}
|
||||
}
|
||||
$routeSummary -join [Environment]::NewLine | Set-Content (Join-Path $LogDir '03-route-summary.txt') -Encoding UTF8
|
||||
|
||||
# --- 5) Evidence ID immutability ---
|
||||
$appendEvidence = Join-Path $scriptDir 'append-evidence.ps1'
|
||||
$evidenceCase = Join-Path $LogDir 'evidence-immutability'
|
||||
if (-not (Test-Path -LiteralPath $appendEvidence)) {
|
||||
Bad 'append-evidence.ps1 missing for immutability check'
|
||||
} else {
|
||||
New-Item -ItemType Directory -Path $evidenceCase -Force | Out-Null
|
||||
& $SmokeHostExe -NoProfile -ExecutionPolicy Bypass -File $appendEvidence `
|
||||
-CaseRoot $evidenceCase `
|
||||
-Id 'E-IMMUTABLE' `
|
||||
-Title 'first write' `
|
||||
-ReproCommand 'echo first' 2>&1 | Out-Null
|
||||
$firstEvidenceExit = $LASTEXITCODE
|
||||
if ($firstEvidenceExit -ne 0) {
|
||||
Bad ("initial Evidence append exit {0}" -f $firstEvidenceExit)
|
||||
} else {
|
||||
$evidencePath = Join-Path $evidenceCase 'evidence\E-IMMUTABLE.md'
|
||||
$indexPath = Join-Path $evidenceCase 'evidence\INDEX.md'
|
||||
$beforeEvidence = (Get-FileHash -LiteralPath $evidencePath -Algorithm SHA256).Hash
|
||||
$beforeIndex = (Get-FileHash -LiteralPath $indexPath -Algorithm SHA256).Hash
|
||||
|
||||
& $SmokeHostExe -NoProfile -ExecutionPolicy Bypass -File $appendEvidence `
|
||||
-CaseRoot $evidenceCase `
|
||||
-Id 'E-IMMUTABLE' `
|
||||
-Title 'second write' `
|
||||
-ReproCommand 'echo second' 2>&1 | Out-Null
|
||||
$duplicateEvidenceExit = $LASTEXITCODE
|
||||
|
||||
$afterEvidence = (Get-FileHash -LiteralPath $evidencePath -Algorithm SHA256).Hash
|
||||
$afterIndex = (Get-FileHash -LiteralPath $indexPath -Algorithm SHA256).Hash
|
||||
if ($duplicateEvidenceExit -eq 0) {
|
||||
Bad 'duplicate Evidence ID was accepted'
|
||||
} elseif ($beforeEvidence -ne $afterEvidence) {
|
||||
Bad 'existing Evidence changed after duplicate append'
|
||||
} elseif ($beforeIndex -ne $afterIndex) {
|
||||
Bad 'Evidence index changed after duplicate append'
|
||||
} else {
|
||||
Ok 'duplicate Evidence ID rejected without mutation'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- summary ---
|
||||
$summary = @(
|
||||
"VERIFY_EXIT=$verifyExit",
|
||||
"PARSE ok=$parseOk fail=$parseFail",
|
||||
"ROUTE ok=$routeOk fail=$routeFail / $($cases.Count)",
|
||||
"FAIL_COUNT=$($fail.Count)",
|
||||
"LogDir=$LogDir"
|
||||
)
|
||||
$summary -join [Environment]::NewLine | Set-Content (Join-Path $LogDir 'SUMMARY.txt') -Encoding UTF8
|
||||
Write-Host '=== SMOKE SUMMARY ==='
|
||||
$summary | ForEach-Object { Write-Host $_ }
|
||||
if ($fail.Count -gt 0) {
|
||||
$fail | Set-Content (Join-Path $LogDir 'failures.txt') -Encoding UTF8
|
||||
Write-Host 'OVERALL: FAIL' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
Write-Host 'OVERALL: ALL PASS' -ForegroundColor Green
|
||||
exit 0
|
||||
|
||||
|
||||
@@ -65,6 +65,11 @@ function Test-CodexConfigRoundTrip {
|
||||
command = 'cmd'
|
||||
args = @('/c', 'echo', '中文参数')
|
||||
}
|
||||
Set-CodexMcpServer -ServerName 'encoding-test' -ServerDefinition @{
|
||||
type = 'stdio'
|
||||
command = 'cmd'
|
||||
args = @('/c', 'echo', '中文参数')
|
||||
}
|
||||
}
|
||||
finally {
|
||||
$env:CODEX_CONFIG_PATH = $oldConfigPath
|
||||
@@ -80,6 +85,7 @@ function Test-CodexConfigRoundTrip {
|
||||
}
|
||||
Assert-True ($text.Contains("[projects.'e:\codex目录\blender脚本管理器']")) "$Name preserves Chinese TOML path and closing quote"
|
||||
Assert-True ($text.Contains('[mcp_servers.encoding-test]')) "$Name adds MCP server"
|
||||
Assert-True (([regex]::Matches($text, '(?m)^\[mcp_servers\.encoding-test\]\r?$')).Count -eq 1) "$Name updates MCP server idempotently"
|
||||
Assert-True ($text.Contains('中文参数')) "$Name preserves new Chinese values"
|
||||
if ($Newline -eq "`r`n") {
|
||||
Assert-True (-not ($text -replace "`r`n", '').Contains("`n")) "$Name preserves CRLF newlines"
|
||||
@@ -89,6 +95,22 @@ function Test-CodexConfigRoundTrip {
|
||||
Test-CodexConfigRoundTrip -Name 'utf8-no-bom-crlf' -WithBom $false -Newline "`r`n"
|
||||
Test-CodexConfigRoundTrip -Name 'utf8-bom-lf' -WithBom $true -Newline "`n"
|
||||
|
||||
$newPath = Join-Path $ScratchDir 'new-config.toml'
|
||||
$oldConfigPath = $env:CODEX_CONFIG_PATH
|
||||
try {
|
||||
$env:CODEX_CONFIG_PATH = $newPath
|
||||
Set-CodexMcpServer -ServerName 'new-config-test' -ServerDefinition @{ command = '中文命令' }
|
||||
}
|
||||
finally {
|
||||
$env:CODEX_CONFIG_PATH = $oldConfigPath
|
||||
}
|
||||
$newBytes = [System.IO.File]::ReadAllBytes($newPath)
|
||||
$newHasBom = $newBytes.Length -ge 3 -and $newBytes[0] -eq 0xEF -and $newBytes[1] -eq 0xBB -and $newBytes[2] -eq 0xBF
|
||||
Assert-True (-not $newHasBom) 'new config uses UTF-8 without BOM'
|
||||
$newText = [System.Text.Encoding]::UTF8.GetString($newBytes)
|
||||
Assert-True ($newText.Contains('[mcp_servers.new-config-test]')) 'new config contains MCP server block'
|
||||
Assert-True ($newText.Contains('中文命令')) 'new config preserves Chinese values'
|
||||
|
||||
$invalidPath = Join-Path $ScratchDir 'invalid-utf8.toml'
|
||||
[System.IO.File]::WriteAllBytes($invalidPath, [byte[]](0x5B, 0x80, 0x5D))
|
||||
$oldConfigPath = $env:CODEX_CONFIG_PATH
|
||||
|
||||
Reference in New Issue
Block a user