fix(bootstrap): fail closed on verified checkouts
This commit is contained in:
@@ -661,17 +661,17 @@ EOF
|
||||
# ─── 服务启动 ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
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 commit
|
||||
repo=$(manifest_field anything-analyzer repoUrl)
|
||||
commit=$(manifest_field anything-analyzer pinnedCommit)
|
||||
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=''
|
||||
pnpm_package=$(manifest_dependency pnpm package) || return 1
|
||||
pnpm_version=$(manifest_dependency pnpm version) || return 1
|
||||
|
||||
@@ -752,10 +752,6 @@ function Start-AnythingAnalyzerService {
|
||||
$AuthToken = Ensure-AnythingAnalyzerMcpConfig -Port ([int]$Definition.servicePort)
|
||||
}
|
||||
|
||||
if (Test-ReverseTcpPort -Port ([int]$Definition.servicePort)) {
|
||||
return
|
||||
}
|
||||
|
||||
$repoDir = [string]$Definition.installDir
|
||||
$checkoutDefinition = [pscustomobject]@{
|
||||
repo = [string]$Definition.repoUrl
|
||||
@@ -763,6 +759,10 @@ function Start-AnythingAnalyzerService {
|
||||
}
|
||||
Ensure-GitCloneInstall -Definition $checkoutDefinition -TargetPath $repoDir | Out-Null
|
||||
|
||||
if (Test-ReverseTcpPort -Port ([int]$Definition.servicePort)) {
|
||||
return
|
||||
}
|
||||
|
||||
Ensure-Pnpm
|
||||
$vsBuildToolsError = ''
|
||||
if (Test-ReverseIsWindows) {
|
||||
@@ -842,7 +842,7 @@ function Ensure-Capability {
|
||||
}
|
||||
|
||||
$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
|
||||
try {
|
||||
$toolSpec = Resolve-ReverseToolSpec -Name $Name
|
||||
@@ -1053,6 +1053,12 @@ function Expand-CapabilityDependencies {
|
||||
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
|
||||
$results = @()
|
||||
|
||||
@@ -1112,3 +1118,6 @@ if (-not $SkipRefresh) {
|
||||
}
|
||||
|
||||
$results | ConvertTo-Json -Depth 5
|
||||
if (-not (Test-BootstrapResultsSucceeded -Results $results)) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ case "$name:${1:-}" in
|
||||
esac
|
||||
;;
|
||||
nc:-z)
|
||||
[[ "${STUB_NC_PREOCCUPIED:-0}" != 1 ]] || exit 0
|
||||
count=0; [[ ! -f "$STUB_NC_STATE" ]] || count="$(cat "$STUB_NC_STATE")"
|
||||
printf '%s\n' "$((count + 1))" > "$STUB_NC_STATE"
|
||||
(( count > 0 )) && exit 0 || exit 1
|
||||
@@ -93,7 +94,7 @@ run_kali() {
|
||||
rm -f "$SCRATCH/nc-count"
|
||||
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:-}" \
|
||||
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_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 ]]
|
||||
touch "$kali_dir/.stub-dirty"
|
||||
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"
|
||||
: > "$CALL_LOG"
|
||||
|
||||
@@ -46,7 +46,9 @@ try {
|
||||
|
||||
$failedTarget = Join-Path $scratch 'failed'
|
||||
$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 (@(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 (-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'
|
||||
}
|
||||
finally {
|
||||
|
||||
Reference in New Issue
Block a user