fix(bootstrap): fail closed on verified checkouts
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user