fix(bootstrap): fail closed on verified checkouts

This commit is contained in:
Atirna
2026-08-14 12:36:31 +05:30
parent ee9217b8af
commit 41ee697f54
4 changed files with 95 additions and 12 deletions
+5 -5
View File
@@ -661,17 +661,17 @@ EOF
# ─── 服务启动 ────────────────────────────────────────────────────────────────────── # ─── 服务启动 ──────────────────────────────────────────────────────────────────────
start_anything_analyzer() { start_anything_analyzer() {
if test_tcp_port 23816 2>/dev/null; then
log_ok "anything-analyzer 已在运行 (port 23816)"
return 0
fi
local repo_dir="$HOME/tools/anything-analyzer" local repo_dir="$HOME/tools/anything-analyzer"
local repo commit local repo commit
repo=$(manifest_field anything-analyzer repoUrl) repo=$(manifest_field anything-analyzer repoUrl)
commit=$(manifest_field anything-analyzer pinnedCommit) commit=$(manifest_field anything-analyzer pinnedCommit)
install_git_commit "$repo" "$commit" "$repo_dir" || return 1 install_git_commit "$repo" "$commit" "$repo_dir" || return 1
if test_tcp_port 23816 2>/dev/null; then
log_ok "anything-analyzer 已在运行 (port 23816)"
return 0
fi
local pnpm_package pnpm_version current_pnpm_version='' local pnpm_package pnpm_version current_pnpm_version=''
pnpm_package=$(manifest_dependency pnpm package) || return 1 pnpm_package=$(manifest_dependency pnpm package) || return 1
pnpm_version=$(manifest_dependency pnpm version) || return 1 pnpm_version=$(manifest_dependency pnpm version) || return 1
+14 -5
View File
@@ -752,10 +752,6 @@ function Start-AnythingAnalyzerService {
$AuthToken = Ensure-AnythingAnalyzerMcpConfig -Port ([int]$Definition.servicePort) $AuthToken = Ensure-AnythingAnalyzerMcpConfig -Port ([int]$Definition.servicePort)
} }
if (Test-ReverseTcpPort -Port ([int]$Definition.servicePort)) {
return
}
$repoDir = [string]$Definition.installDir $repoDir = [string]$Definition.installDir
$checkoutDefinition = [pscustomobject]@{ $checkoutDefinition = [pscustomobject]@{
repo = [string]$Definition.repoUrl repo = [string]$Definition.repoUrl
@@ -763,6 +759,10 @@ function Start-AnythingAnalyzerService {
} }
Ensure-GitCloneInstall -Definition $checkoutDefinition -TargetPath $repoDir | Out-Null Ensure-GitCloneInstall -Definition $checkoutDefinition -TargetPath $repoDir | Out-Null
if (Test-ReverseTcpPort -Port ([int]$Definition.servicePort)) {
return
}
Ensure-Pnpm Ensure-Pnpm
$vsBuildToolsError = '' $vsBuildToolsError = ''
if (Test-ReverseIsWindows) { if (Test-ReverseIsWindows) {
@@ -842,7 +842,7 @@ function Ensure-Capability {
} }
$existingState = Get-ReverseCapabilityState -Name $Name $existingState = Get-ReverseCapabilityState -Name $Name
if ($existingState -and -not $definition.PSObject.Properties['mcpNames']) { if ($existingState -and -not $definition.PSObject.Properties['mcpNames'] -and $definition.bootstrapKind -ne 'git-clone') {
$toolSpec = $null $toolSpec = $null
try { try {
$toolSpec = Resolve-ReverseToolSpec -Name $Name $toolSpec = Resolve-ReverseToolSpec -Name $Name
@@ -1053,6 +1053,12 @@ function Expand-CapabilityDependencies {
return $ordered return $ordered
} }
function Test-BootstrapResultsSucceeded {
param([Parameter(Mandatory = $true)][object[]]$Results)
return (@($Results | Where-Object { $_.status -eq 'failed' }).Count -eq 0)
}
$expandedCapabilities = Expand-CapabilityDependencies -Names $Capability $expandedCapabilities = Expand-CapabilityDependencies -Names $Capability
$results = @() $results = @()
@@ -1112,3 +1118,6 @@ if (-not $SkipRefresh) {
} }
$results | ConvertTo-Json -Depth 5 $results | ConvertTo-Json -Depth 5
if (-not (Test-BootstrapResultsSucceeded -Results $results)) {
exit 1
}
+4 -1
View File
@@ -49,6 +49,7 @@ case "$name:${1:-}" in
esac esac
;; ;;
nc:-z) nc:-z)
[[ "${STUB_NC_PREOCCUPIED:-0}" != 1 ]] || exit 0
count=0; [[ ! -f "$STUB_NC_STATE" ]] || count="$(cat "$STUB_NC_STATE")" count=0; [[ ! -f "$STUB_NC_STATE" ]] || count="$(cat "$STUB_NC_STATE")"
printf '%s\n' "$((count + 1))" > "$STUB_NC_STATE" printf '%s\n' "$((count + 1))" > "$STUB_NC_STATE"
(( count > 0 )) && exit 0 || exit 1 (( count > 0 )) && exit 0 || exit 1
@@ -93,7 +94,7 @@ run_kali() {
rm -f "$SCRATCH/nc-count" rm -f "$SCRATCH/nc-count"
env PATH="$STUB_BIN:/opt/homebrew/bin:/usr/bin:/bin" HOME="$SCRATCH/home" \ env PATH="$STUB_BIN:/opt/homebrew/bin:/usr/bin:/bin" HOME="$SCRATCH/home" \
CALL_LOG="$CALL_LOG" STUB_NC_STATE="$SCRATCH/nc-count" STUB_PNPM_VERSION="${STUB_PNPM_VERSION:-}" \ CALL_LOG="$CALL_LOG" STUB_NC_STATE="$SCRATCH/nc-count" STUB_PNPM_VERSION="${STUB_PNPM_VERSION:-}" \
STUB_FAIL_FETCH="${STUB_FAIL_FETCH:-0}" bash "$KALI_BOOTSTRAP" "$@" STUB_FAIL_FETCH="${STUB_FAIL_FETCH:-0}" STUB_NC_PREOCCUPIED="${STUB_NC_PREOCCUPIED:-0}" bash "$KALI_BOOTSTRAP" "$@"
} }
expect_line() { grep -Fqx "$1" "$CALL_LOG" || { echo "missing argv: $1" >&2; cat "$CALL_LOG" >&2; return 1; }; } expect_line() { grep -Fqx "$1" "$CALL_LOG" || { echo "missing argv: $1" >&2; cat "$CALL_LOG" >&2; return 1; }; }
expect_fragment() { grep -Fq "$1" "$CALL_LOG" || { echo "missing argv fragment: $1" >&2; cat "$CALL_LOG" >&2; return 1; }; } expect_fragment() { grep -Fq "$1" "$CALL_LOG" || { echo "missing argv fragment: $1" >&2; cat "$CALL_LOG" >&2; return 1; }; }
@@ -215,6 +216,8 @@ if (( BASH_VERSINFO[0] >= 4 )); then
[[ $(grep -c '|status|--porcelain|--untracked-files=all' "$CALL_LOG") -ge 2 ]] [[ $(grep -c '|status|--porcelain|--untracked-files=all' "$CALL_LOG") -ge 2 ]]
touch "$kali_dir/.stub-dirty" touch "$kali_dir/.stub-dirty"
rejects_without_pnpm run_kali anything-analyzer --start-services --skip-refresh rejects_without_pnpm run_kali anything-analyzer --start-services --skip-refresh
STUB_NC_PREOCCUPIED=1 rejects_without_pnpm run_kali anything-analyzer --start-services --skip-refresh
expect_fragment '|status|--porcelain|--untracked-files=all'
rm -rf "$kali_dir" rm -rf "$kali_dir"
: > "$CALL_LOG" : > "$CALL_LOG"
+72 -1
View File
@@ -46,7 +46,9 @@ try {
$failedTarget = Join-Path $scratch 'failed' $failedTarget = Join-Path $scratch 'failed'
$badDefinition = [pscustomobject]@{ repo = (Join-Path $scratch 'missing'); pinnedCommit = $pin } $badDefinition = [pscustomobject]@{ repo = (Join-Path $scratch 'missing'); pinnedCommit = $pin }
try { Ensure-GitCloneInstall -Definition $badDefinition -TargetPath $failedTarget | Out-Null; throw 'failed fetch accepted' } catch {} $failedFetchRejected = $false
try { Ensure-GitCloneInstall -Definition $badDefinition -TargetPath $failedTarget | Out-Null } catch { $failedFetchRejected = $true }
Assert-True $failedFetchRejected 'failed fetch accepted'
Assert-True (-not (Test-Path $failedTarget)) 'failed fetch poisoned final path' Assert-True (-not (Test-Path $failedTarget)) 'failed fetch poisoned final path'
Assert-True (@(Get-ChildItem $scratch -Filter '.reverse-bootstrap-*').Count -eq 0) 'failed fetch left staging path' Assert-True (@(Get-ChildItem $scratch -Filter '.reverse-bootstrap-*').Count -eq 0) 'failed fetch left staging path'
@@ -108,6 +110,75 @@ printf "pnpm|%s\n" "$*" >> "$BOOTSTRAP_PS_LOG"
Assert-True $dirtyRejected 'post-install dirty checkout accepted or rejection reason changed' Assert-True $dirtyRejected 'post-install dirty checkout accepted or rejection reason changed'
Assert-True (-not (Test-Path (Join-Path $target 'pnpm-workspace.yaml'))) 'generated workspace file was not removed' Assert-True (-not (Test-Path (Join-Path $target 'pnpm-workspace.yaml'))) 'generated workspace file was not removed'
Invoke-Git -Arguments @('-C', $target, 'config', 'user.email', 'test@example.invalid')
Invoke-Git -Arguments @('-C', $target, 'config', 'user.name', 'test')
Invoke-Git -Arguments @('-C', $target, 'commit', '--allow-empty', '--quiet', '-m', 'wrong checkout')
$wrongCommitRejected = $false
try { Ensure-GitCloneInstall -Definition $definition -TargetPath $target | Out-Null } catch { $wrongCommitRejected = $_.Exception.Message -match 'expected' }
Assert-True $wrongCommitRejected 'clean wrong-commit checkout accepted'
$publicProfile = [Environment]::GetFolderPath([Environment+SpecialFolder]::UserProfile)
$publicTools = Join-Path $publicProfile 'Tools'
$publicTarget = Join-Path $publicTools 'SecLists'
if (Test-Path -LiteralPath $publicTarget) {
Write-Host 'SKIP: public bootstrap exit regression (existing SecLists checkout)'
}
else {
$createdPublicTools = -not (Test-Path -LiteralPath $publicTools)
try {
New-Item -ItemType Directory -Path $publicTarget -Force | Out-Null
Invoke-Git -Arguments @('-C', $publicTarget, 'init', '--quiet')
Invoke-Git -Arguments @('-C', $publicTarget, 'config', 'user.email', 'test@example.invalid')
Invoke-Git -Arguments @('-C', $publicTarget, 'config', 'user.name', 'test')
Set-Content (Join-Path $publicTarget 'fixture.txt') 'wrong checkout'
Invoke-Git -Arguments @('-C', $publicTarget, 'add', 'fixture.txt')
Invoke-Git -Arguments @('-C', $publicTarget, 'commit', '--quiet', '-m', 'fixture')
$powerShellHost = if ($PSVersionTable.PSEdition -eq 'Desktop') { Join-Path $PSHOME 'powershell.exe' } else { Join-Path $PSHOME 'pwsh' }
$childOutput = @(& $powerShellHost -NoProfile -ExecutionPolicy Bypass -File (Join-Path $PSScriptRoot 'bootstrap-reverse.ps1') -Capability seclists -SkipRefresh)
$childExitCode = $LASTEXITCODE
$childResult = ($childOutput -join [Environment]::NewLine) | ConvertFrom-Json
Assert-True ($childExitCode -ne 0) 'failed public bootstrap exited successfully'
Assert-True ($childResult.status -eq 'failed') 'failed public bootstrap did not report failed status'
Assert-True ($childResult.error -match 'Checkout verification failed') 'failed public bootstrap did not report checkout verification'
}
finally {
Remove-Item -LiteralPath $publicTarget -Recurse -Force -ErrorAction SilentlyContinue
if ($createdPublicTools -and (Test-Path -LiteralPath $publicTools) -and (@(Get-ChildItem -LiteralPath $publicTools -Force).Count -eq 0)) {
Remove-Item -LiteralPath $publicTools -Force -ErrorAction SilentlyContinue
}
}
}
. (Join-Path $PSScriptRoot 'bootstrap-reverse.ps1') -Capability '__test_missing__' -SkipRefresh | Out-Null
$script:gitCloneDefinition = [pscustomobject]@{ name = 'test-git-clone'; bootstrapKind = 'git-clone'; canAutoInstall = $true }
$script:gitCloneVerifierCalled = $false
function Get-ReverseBootstrapDefinition { param([string]$Name) return $script:gitCloneDefinition }
function Get-ReverseCapabilityState { param([string]$Name) return [pscustomobject]@{ Ready = $true } }
function Resolve-ReverseToolSpec { param([string]$Name) return [pscustomobject]@{ Available = $true } }
function Ensure-GitCloneInstall {
param($Definition, [string]$TargetPath)
$script:gitCloneVerifierCalled = $true
return [pscustomobject]@{ Verified = $true }
}
$gitCloneResult = Ensure-Capability -Name 'test-git-clone'
Assert-True $script:gitCloneVerifierCalled 'available git-clone capability skipped checkout verification'
Assert-True $gitCloneResult.Verified 'git-clone capability did not return checkout verification result'
$script:serviceCheckoutVerifierCalled = $false
function Ensure-GitCloneInstall {
param($Definition, [string]$TargetPath)
$script:serviceCheckoutVerifierCalled = $true
}
function Test-ReverseTcpPort { param([int]$Port) return $true }
Start-AnythingAnalyzerService -Definition ([pscustomobject]@{
installDir = (Join-Path $scratch 'anything-analyzer')
repoUrl = $source
pinnedCommit = $pin
servicePort = 23816
}) -AuthToken 'test-token'
Assert-True $script:serviceCheckoutVerifierCalled 'running Anything Analyzer service skipped checkout verification'
Write-Host 'PowerShell bootstrap supply-chain regression passed' Write-Host 'PowerShell bootstrap supply-chain regression passed'
} }
finally { finally {