fix: 口令会随 -Verbose 落进日志(DEBUG 下打印整条命令行)
缺陷:Invoke-ExternalCommand 在 DEBUG 级打印整条命令行,而 7z / RAR 只接受命令行 口令(-p<口令>),所以口令必然出现在参数表里。一旦 -Verbose(Backup.ps1 / Restore.ps1 都会因它打开 DEBUG),logs\*.log 里就是明文口令 —— 与 BackupConfig.psd1 和文档里 "口令不落盘、不写进仓库"的承诺直接冲突。 修法:打印前把 -p 参数换成占位符;真正执行的仍然是原参数。在**参数级别**替换而不是 对拼好的命令行做正则 —— 含空格的口令会被引号包起来("-pmy pass"),正则在那种形态上 很容易漏掉,而漏掉的代价是口令明文入日志。 回归断言(零依赖与 Pester 各一份):打开 DEBUG、把日志指向临时目录、带一个哨兵口令 跑一次外部命令,然后读日志文件断言哨兵不在里面、占位符在里面。另加一条"测试的测试": 断言那行 DEBUG 记录确实写进去了 —— 否则前两条会在"压根没记录"时空跑通过。 断言有效性做了红绿证明:把遮蔽改回 $startInfo.Arguments 后断言变红并指名"口令明文 进了日志",还原后转绿。 验收:test.ps1 9/9 全绿;tests\Run-RealSmoke.ps1 4/4 全绿。
This commit is contained in:
1 parent
d32d4b511f
commit
e17cdcda79
3 files changed
+59
-1
No files matched your search
+11
-1
@@ -262,7 +262,17 @@ function Invoke-ExternalCommand {
|
||||
$startInfo.WorkingDirectory = $WorkingDirectory
|
||||
}
|
||||
|
||||
Write-Log ('执行: {0} {1}' -f $FilePath, $startInfo.Arguments) -Level DEBUG
|
||||
# 打印的那一行必须把口令遮蔽掉:7z / RAR 只接受命令行口令(`-p<口令>`),所以口令
|
||||
# 必然出现在参数表里;一旦 -Verbose 打开 DEBUG,整条命令行就会落进 logs\*.log ——
|
||||
# 而 BackupConfig.psd1 与文档都承诺过"口令不落盘、不写进仓库"。真正执行的仍然是
|
||||
# $startInfo.Arguments,这里只改日志。
|
||||
#
|
||||
# 在**参数级别**遮蔽,而不是对拼好的命令行做正则:含空格的口令会被引号包起来
|
||||
# ("-pmy pass"),正则在那种形态上很容易漏掉,而漏掉的代价是口令明文入日志。
|
||||
$loggableArguments = @($ArgumentList | ForEach-Object {
|
||||
if ($_ -is [string] -and $_ -like '-p*') { '-p<口令已隐藏>' } else { $_ }
|
||||
})
|
||||
Write-Log ('执行: {0} {1}' -f $FilePath, (ConvertTo-NativeArgumentString -ArgumentList $loggableArguments)) -Level DEBUG
|
||||
|
||||
$process = [System.Diagnostics.Process]::Start($startInfo)
|
||||
try {
|
||||
|
||||
@@ -1116,6 +1116,29 @@ Describe 'Resolve-BackupEntry:条目解析' {
|
||||
Describe '外部命令退出码(旧实现的核心缺陷)' {
|
||||
# ============================================================================
|
||||
|
||||
It '口令不会进日志:DEBUG 下打印的命令行要遮蔽 -p 参数' {
|
||||
$sandbox = Join-Path $env:TEMP ("bnr-secret-" + [guid]::NewGuid().ToString('N').Substring(0, 8))
|
||||
New-Item -ItemType Directory -Path $sandbox -Force | Out-Null
|
||||
$sentinel = 'SENTINEL-PW-9f3a'
|
||||
$logPath = $null
|
||||
try {
|
||||
$logPath = Start-BaknretLog -Directory $sandbox -Prefix 'secret'
|
||||
Set-BaknretDebug
|
||||
$null = Invoke-ExternalCommand -FilePath 'cmd.exe' -ArgumentList @('/c', 'exit 0', "-p$sentinel")
|
||||
} finally {
|
||||
Set-BaknretDebug -Enabled:$false
|
||||
Stop-BaknretLog
|
||||
}
|
||||
|
||||
$logText = Get-Content -Encoding UTF8 -LiteralPath $logPath -Raw
|
||||
# 这条是"测试的测试":没有它,万一 DEBUG 那行压根没写进去,后面两条会空跑通过
|
||||
$logText | Should -Match '执行:'
|
||||
$logText | Should -Not -Match ([regex]::Escape($sentinel))
|
||||
$logText | Should -Match '口令已隐藏'
|
||||
|
||||
Remove-Item -LiteralPath $sandbox -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
It 'Invoke-ExternalCommand 能拿到真实退出码' {
|
||||
(Invoke-ExternalCommand -FilePath 'cmd.exe' -ArgumentList @('/c', 'exit 7')) | Should -Be 7
|
||||
}
|
||||
|
||||
@@ -1191,6 +1191,31 @@ if (-not $sevenZip) {
|
||||
Write-Host "`n== 外部命令退出码 ==" -ForegroundColor Cyan
|
||||
# ============================================================================
|
||||
|
||||
Test-Case '口令不会进日志:DEBUG 下打印的命令行要遮蔽 -p 参数' {
|
||||
# 7z / RAR 只接受命令行口令,所以口令必然出现在参数表里。一旦 -Verbose 打开 DEBUG,
|
||||
# 整条命令行就会落进 logs\*.log —— 而 BackupConfig.psd1 与文档都承诺过"口令不落盘"。
|
||||
$sandbox = Join-Path $env:TEMP ("bnr-secret-" + [guid]::NewGuid().ToString('N').Substring(0, 8))
|
||||
New-Item -ItemType Directory -Path $sandbox -Force | Out-Null
|
||||
$sentinel = 'SENTINEL-PW-9f3a'
|
||||
$logPath = $null
|
||||
try {
|
||||
$logPath = Start-BaknretLog -Directory $sandbox -Prefix 'secret'
|
||||
Set-BaknretDebug
|
||||
$null = Invoke-ExternalCommand -FilePath 'cmd.exe' -ArgumentList @('/c', 'exit 0', "-p$sentinel")
|
||||
} finally {
|
||||
Set-BaknretDebug -Enabled:$false
|
||||
Stop-BaknretLog
|
||||
}
|
||||
|
||||
$logText = Get-Content -Encoding UTF8 -LiteralPath $logPath -Raw
|
||||
# 这条是"测试的测试":没有它,万一 DEBUG 那行压根没写进去,后面两条会空跑通过
|
||||
Assert-True ($logText -match '执行:') '日志里没有那行 DEBUG 的命令行记录,这条断言就是空跑'
|
||||
Assert-False ($logText -match [regex]::Escape($sentinel)) '口令明文进了日志'
|
||||
Assert-True ($logText -match '口令已隐藏') '日志里应当出现遮蔽占位符'
|
||||
|
||||
Remove-Item -LiteralPath $sandbox -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
Test-Case 'Invoke-ExternalCommand 能拿到真实退出码(旧实现用 Start-Process 拿不到)' {
|
||||
$code = Invoke-ExternalCommand -FilePath 'cmd.exe' -ArgumentList @('/c', 'exit 7')
|
||||
Assert-Equal 7 $code
|
||||
|
||||
Reference in new issue
Block a user