fix(bootstrap): harden pinned checkout promotion

This commit is contained in:
Atirna
2026-08-13 03:00:49 +05:30
parent e8faca63ed
commit 1d929bf5db
7 changed files with 400 additions and 291 deletions
+10
View File
@@ -23,6 +23,16 @@
"metasploitmcp — Metasploit MCP Server (apt install metasploitmcp, port 8085)",
"hexstrike-ai — 150+ 安全工具 MCP 自动化 (apt install hexstrike-ai)"
],
"bootstrapDependencies": {
"pipx": {
"package": "pipx==1.16.5",
"version": "1.16.5"
},
"pnpm": {
"package": "pnpm@10.24.0",
"version": "10.24.0"
}
},
"capabilities": [
{
"name": "jadx",
+56 -12
View File
@@ -132,13 +132,24 @@ install_git_commit() {
local install_dir="$3"
if [[ -d "$install_dir/.git" ]]; then
local current
current=$(git -C "$install_dir" rev-parse HEAD 2>/dev/null || true)
local current status
if ! current=$(git -C "$install_dir" rev-parse HEAD 2>/dev/null); then
log_err "无法解析现有 checkout HEAD: $install_dir"
return 1
fi
if [[ "$current" != "$commit" ]]; then
log_err "Existing checkout is not at pinned commit $commit: $install_dir"
log_err "Move it aside explicitly, then retry; bootstrap will not overwrite local changes."
return 1
fi
if ! status=$(git -C "$install_dir" status --porcelain --untracked-files=all); then
log_err "无法检查 checkout 状态: $install_dir"
return 1
fi
if [[ -n "$status" ]]; then
log_err "现有 checkout 含本地修改,拒绝执行: $install_dir"
return 1
fi
return 0
fi
if [[ -e "$install_dir" ]]; then
@@ -146,15 +157,33 @@ install_git_commit() {
return 1
fi
mkdir -p "$(dirname "$install_dir")"
git init -q "$install_dir"
git -C "$install_dir" remote add origin "$repo"
git -C "$install_dir" fetch --depth 1 origin "$commit"
git -C "$install_dir" checkout -q --detach FETCH_HEAD
local resolved
resolved=$(git -C "$install_dir" rev-parse HEAD)
local parent stage resolved status
parent=$(dirname "$install_dir")
mkdir -p "$parent"
stage=$(mktemp -d "$parent/.reverse-bootstrap-XXXXXX") || return 1
if ! git init -q "$stage" ||
! git -C "$stage" remote add origin "$repo" ||
! git -C "$stage" fetch --depth 1 origin "$commit" ||
! git -C "$stage" checkout -q --detach FETCH_HEAD; then
rm -rf "$stage"
return 1
fi
if ! resolved=$(git -C "$stage" rev-parse HEAD); then
rm -rf "$stage"
return 1
fi
if [[ "$resolved" != "$commit" ]]; then
log_err "Pinned checkout verification failed (expected $commit, got $resolved)"
rm -rf "$stage"
return 1
fi
if ! status=$(git -C "$stage" status --porcelain --untracked-files=all) || [[ -n "$status" ]]; then
log_err "Staged checkout is not clean: $stage"
rm -rf "$stage"
return 1
fi
if ! mv -T "$stage" "$install_dir"; then
rm -rf "$stage"
return 1
fi
}
@@ -331,6 +360,13 @@ manifest_field() {
'.capabilities[] | select(.name == $name) | .[$field] // empty' "$KALI_MANIFEST"
}
manifest_dependency() {
local name="$1"
local field="$2"
jq -er --arg name "$name" --arg field "$field" \
'.bootstrapDependencies[$name][$field] // empty' "$KALI_MANIFEST"
}
install_manifest_release() {
local capability="$1"
local repo asset_regex install_dir release_tag asset_sha256
@@ -636,11 +672,19 @@ start_anything_analyzer() {
commit=$(manifest_field anything-analyzer pinnedCommit)
install_git_commit "$repo" "$commit" "$repo_dir" || return 1
if ! command -v pnpm &>/dev/null; then
npm install -g pnpm
local pnpm_package pnpm_version current_pnpm_version=''
pnpm_package=$(manifest_dependency pnpm package) || return 1
pnpm_version=$(manifest_dependency pnpm version) || return 1
if command -v pnpm &>/dev/null; then
current_pnpm_version=$(pnpm --version 2>/dev/null | head -n1 | tr -d '[:space:]')
fi
if [[ "$current_pnpm_version" != "$pnpm_version" ]]; then
npm install -g "$pnpm_package" || return 1
fi
(cd "$repo_dir" && pnpm install && nohup pnpm dev > /tmp/anything-analyzer.log 2>&1 &)
(cd "$repo_dir" && pnpm install --frozen-lockfile) || return 1
install_git_commit "$repo" "$commit" "$repo_dir" || return 1
(cd "$repo_dir" && nohup pnpm dev > /tmp/anything-analyzer.log 2>&1 &)
log_info "等待 anything-analyzer 启动 (port 23816) ..."
if wait_for_port 23816 120; then
+10
View File
@@ -1,4 +1,14 @@
{
"bootstrapDependencies": {
"pipx": {
"package": "pipx==1.16.5",
"version": "1.16.5"
},
"pnpm": {
"package": "pnpm@10.24.0",
"version": "10.24.0"
}
},
"capabilities": [
{
"name": "jadx",
+87 -50
View File
@@ -24,6 +24,17 @@ $OutputEncoding = [System.Text.UTF8Encoding]::new($false)
. (Join-Path $PSScriptRoot 'lib\ToolDiscovery.ps1')
function Get-BootstrapDependency {
param([Parameter(Mandatory = $true)][string]$Name)
$manifest = Get-Content -LiteralPath (Get-ReverseBootstrapManifestPath) -Raw -Encoding UTF8 | ConvertFrom-Json
$dependency = $manifest.bootstrapDependencies.PSObject.Properties[$Name].Value
if ($null -eq $dependency -or [string]::IsNullOrWhiteSpace([string]$dependency.package) -or [string]::IsNullOrWhiteSpace([string]$dependency.version)) {
throw "bootstrapDependencies.$Name must define package and version."
}
return $dependency
}
$Capability = @(
foreach ($item in @($Capability)) {
if ([string]::IsNullOrWhiteSpace($item)) {
@@ -155,14 +166,23 @@ function Ensure-JavaRuntime {
function Ensure-Pnpm {
Ensure-NodeRuntime
if (-not (Get-NodeCommandPath -Name 'pnpm')) {
$dependency = Get-BootstrapDependency -Name 'pnpm'
$pnpm = Get-NodeCommandPath -Name 'pnpm'
$currentVersion = ''
if ($pnpm) {
$versionLine = & $pnpm --version 2>$null | Select-Object -First 1
if ($LASTEXITCODE -eq 0 -and $null -ne $versionLine) {
$currentVersion = ([string]$versionLine).Trim()
}
}
if ($currentVersion -ne [string]$dependency.version) {
$npm = Get-NodeCommandPath -Name 'npm'
if ([string]::IsNullOrWhiteSpace($npm)) {
throw 'npm is not available after Node.js installation.'
}
& $npm install -g pnpm
& $npm install -g ([string]$dependency.package)
if ($LASTEXITCODE -ne 0) {
throw 'Failed to install pnpm globally.'
throw "Failed to install pinned pnpm dependency $($dependency.package)."
}
}
}
@@ -341,34 +361,11 @@ function Set-AnythingAnalyzerPnpmBuildApprovals {
function Approve-AnythingAnalyzerBuildScripts {
param(
[Parameter(Mandatory = $true)][string]$RepoDir,
[Parameter(Mandatory = $true)][string]$PnpmPath
[Parameter(Mandatory = $true)][string]$RepoDir
)
$buildPackages = @('electron', 'esbuild', 'better-sqlite3')
Push-Location $RepoDir
try {
$approveExitCode = 1
try {
$approveOutput = & $PnpmPath approve-builds --all 2>&1
$approveExitCode = $LASTEXITCODE
}
catch {
$approveOutput = $_.Exception.Message
$approveExitCode = 1
}
if ($approveExitCode -eq 0) {
return
}
Write-Warning 'pnpm approve-builds --all is unavailable or failed; writing pnpm-workspace.yaml build approvals directly.'
}
finally {
Pop-Location
}
Set-AnythingAnalyzerPnpmBuildApprovals -RepoDir $RepoDir -Packages $buildPackages
}
@@ -805,9 +802,13 @@ if (Test-ReverseIsWindows) {
throw 'pnpm is not available after installation.'
}
$workspacePath = Join-Path $repoDir 'pnpm-workspace.yaml'
$workspaceExisted = Test-Path -LiteralPath $workspacePath -PathType Leaf
$workspaceBytes = if ($workspaceExisted) { [IO.File]::ReadAllBytes($workspacePath) } else { $null }
Push-Location $repoDir
try {
Approve-AnythingAnalyzerBuildScripts -RepoDir $repoDir -PnpmPath $pnpm
Approve-AnythingAnalyzerBuildScripts -RepoDir $repoDir
if (-not (Test-AnythingAnalyzerElectronHealthy -RepoDir $repoDir -PnpmPath $pnpm)) {
$nodeModules = Join-Path $repoDir 'node_modules'
@@ -816,7 +817,7 @@ if (Test-ReverseIsWindows) {
}
}
& $pnpm install
& $pnpm install --frozen-lockfile
if ($LASTEXITCODE -ne 0) {
if (-not [string]::IsNullOrWhiteSpace($vsBuildToolsError)) {
throw "pnpm install failed for anything-analyzer. Visual Studio Build Tools auto-install also failed earlier: $vsBuildToolsError"
@@ -838,8 +839,17 @@ if (Test-ReverseIsWindows) {
}
finally {
Pop-Location
if ($workspaceExisted) {
[IO.File]::WriteAllBytes($workspacePath, $workspaceBytes)
}
elseif (Test-Path -LiteralPath $workspacePath) {
Remove-Item -LiteralPath $workspacePath -Force
}
}
$git = Get-FirstCommandPath -Names @('git')
Assert-GitCheckoutState -GitPath $git -CheckoutPath $repoDir -PinnedCommit ([string]$Definition.pinnedCommit)
$stdoutLog = Join-Path $repoDir 'anything-analyzer-dev.log'
$stderrLog = Join-Path $repoDir 'anything-analyzer-dev.err.log'
Remove-Item -LiteralPath $stdoutLog, $stderrLog -Force -ErrorAction SilentlyContinue
@@ -879,6 +889,27 @@ function Ensure-AndroidPlatformTools {
return (Resolve-ReverseToolSpec -Name 'adb')
}
function Assert-GitCheckoutState {
param(
[Parameter(Mandatory = $true)][string]$GitPath,
[Parameter(Mandatory = $true)][string]$CheckoutPath,
[Parameter(Mandatory = $true)][string]$PinnedCommit
)
$resolvedLine = & $GitPath -C $CheckoutPath rev-parse HEAD 2>$null | Select-Object -First 1
$resolvedCommit = if ($null -eq $resolvedLine) { '' } else { ([string]$resolvedLine).Trim() }
if ($LASTEXITCODE -ne 0 -or $resolvedCommit -ne $PinnedCommit) {
throw "Checkout verification failed: expected $PinnedCommit, got $resolvedCommit ($CheckoutPath)"
}
$status = @(& $GitPath -C $CheckoutPath status --porcelain --untracked-files=all 2>&1)
if ($LASTEXITCODE -ne 0) {
throw "Cannot inspect checkout state: $CheckoutPath"
}
if ($status.Count -gt 0) {
throw "Checkout has local changes; refusing to execute it: $CheckoutPath"
}
}
function Ensure-GitCloneInstall {
param(
[Parameter(Mandatory = $true)]$Definition,
@@ -892,36 +923,42 @@ function Ensure-GitCloneInstall {
}
if ((Test-Path -LiteralPath $TargetPath -PathType Container) -and (Test-Path -LiteralPath (Join-Path $TargetPath '.git'))) {
if (-not [string]::IsNullOrWhiteSpace($pinnedCommit)) {
$currentCommit = (& $git -C $TargetPath rev-parse HEAD).Trim()
if ($LASTEXITCODE -ne 0 -or $currentCommit -ne $pinnedCommit) {
throw "Existing checkout is not at pinned commit $pinnedCommit. Move it aside explicitly, then retry: $TargetPath"
}
if ([string]::IsNullOrWhiteSpace($pinnedCommit)) {
throw "Git capability $($Definition.repo) must define pinnedCommit before an existing checkout can be used."
}
Assert-GitCheckoutState -GitPath $git -CheckoutPath $TargetPath -PinnedCommit $pinnedCommit
return $true
}
if (Test-Path -LiteralPath $TargetPath) {
$backupPath = "$TargetPath.bak-$([DateTime]::UtcNow.ToString('yyyyMMddHHmmss'))"
Move-Item -LiteralPath $TargetPath -Destination $backupPath -Force
throw "Install path exists but is not a git checkout: $TargetPath"
}
if ([string]::IsNullOrWhiteSpace($pinnedCommit)) {
throw "Git capability $($Definition.repo) must define pinnedCommit."
}
Ensure-DownloadDirectory -Path (Split-Path -Path $TargetPath -Parent)
if ([string]::IsNullOrWhiteSpace($pinnedCommit)) {
& $git clone --depth 1 $Definition.repo $TargetPath
if ($LASTEXITCODE -ne 0) {
throw "git clone failed for $($Definition.repo)"
$parent = Split-Path -Path $TargetPath -Parent
Ensure-DownloadDirectory -Path $parent
$stagePath = Join-Path $parent ('.reverse-bootstrap-{0}' -f [Guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $stagePath | Out-Null
try {
& $git init --quiet $stagePath
if ($LASTEXITCODE -ne 0) { throw 'git init failed' }
& $git -C $stagePath remote add origin $Definition.repo
if ($LASTEXITCODE -ne 0) { throw 'git remote add failed' }
& $git -C $stagePath fetch --depth 1 origin $pinnedCommit
if ($LASTEXITCODE -ne 0) { throw 'git fetch failed' }
& $git -C $stagePath checkout --quiet --detach FETCH_HEAD
if ($LASTEXITCODE -ne 0) { throw 'git checkout failed' }
Assert-GitCheckoutState -GitPath $git -CheckoutPath $stagePath -PinnedCommit $pinnedCommit
Move-Item -LiteralPath $stagePath -Destination $TargetPath
if ((Test-Path -LiteralPath $stagePath) -or -not (Test-Path -LiteralPath (Join-Path $TargetPath '.git') -PathType Container)) {
throw "Failed to promote staged checkout to $TargetPath"
}
}
else {
& $git init --quiet $TargetPath
& $git -C $TargetPath remote add origin $Definition.repo
& $git -C $TargetPath fetch --depth 1 origin $pinnedCommit
& $git -C $TargetPath checkout --quiet --detach FETCH_HEAD
$resolvedCommit = (& $git -C $TargetPath rev-parse HEAD).Trim()
if ($LASTEXITCODE -ne 0 -or $resolvedCommit -ne $pinnedCommit) {
throw "Pinned checkout verification failed for $($Definition.repo): expected $pinnedCommit, got $resolvedCommit"
finally {
if (Test-Path -LiteralPath $stagePath) {
Remove-Item -LiteralPath $stagePath -Recurse -Force
}
}
+101 -32
View File
@@ -89,6 +89,19 @@ raise SystemExit(1)
PY
}
manifest_dependency() {
local name="$1"
local field="$2"
python3 - "$MANIFEST_PATH" "$name" "$field" <<'PY'
import json, pathlib, sys
manifest = json.loads(pathlib.Path(sys.argv[1]).read_text(encoding='utf-8'))
value = manifest.get('bootstrapDependencies', {}).get(sys.argv[2], {}).get(sys.argv[3])
if value is None or value == '':
raise SystemExit(1)
print(value)
PY
}
safe_remove_install_dir() {
local target="$1"
local tmp_target="${2:-}"
@@ -218,15 +231,15 @@ ensure_python_runtime() {
*) log_err "Install Python 3 manually. See $(platform_doc)"; return 1 ;;
esac
fi
if ! has_cmd pipx; then
case "$PLATFORM" in
macos)
python3 -m pip install --user pipx || install_brew pipx
;;
linux)
install_apt pipx || python3 -m pip install --user pipx
;;
esac
local pipx_package pipx_version current_version
pipx_package=$(manifest_dependency pipx package) || return 1
pipx_version=$(manifest_dependency pipx version) || return 1
current_version=""
if has_cmd pipx; then
current_version=$(pipx --version 2>/dev/null | head -n1 | tr -d '[:space:]')
fi
if [[ "$current_version" != "$pipx_version" ]]; then
python3 -m pip install --user --upgrade "$pipx_package" || return 1
fi
python3 -m pipx ensurepath >/dev/null 2>&1 || true
export PATH="$HOME/.local/bin:$PATH"
@@ -251,10 +264,17 @@ ensure_java_runtime() {
}
ensure_pnpm() {
ensure_node_runtime
if has_cmd pnpm; then return 0; fi
if has_cmd corepack; then corepack enable || true; fi
if ! has_cmd pnpm; then npm install -g pnpm; fi
ensure_node_runtime || return 1
local package version current_version
package=$(manifest_dependency pnpm package) || return 1
version=$(manifest_dependency pnpm version) || return 1
current_version=""
if has_cmd pnpm; then
current_version=$(pnpm --version 2>/dev/null | head -n1 | tr -d '[:space:]')
fi
if [[ "$current_version" != "$version" ]]; then
npm install -g "$package" || return 1
fi
}
# Args: repo regex [release_tag]
@@ -378,14 +398,40 @@ install_git_commit() {
local commit="$2"
local install_dir="$3"
git_checkout_is_clean() {
local checkout="$1"
local status
if ! status=$(git -C "$checkout" status --porcelain --untracked-files=all); then
log_err "Cannot inspect checkout state: $checkout"
return 1
fi
if [[ -n "$status" ]]; then
log_err "Existing checkout has local changes; refusing to execute it: $checkout"
return 1
fi
}
cleanup_git_stage() {
local stage="$1"
local parent="$2"
case "$stage" in
"$parent"/.reverse-bootstrap-*) rm -rf "$stage" ;;
*) log_err "Refusing to clean unexpected staging path: $stage" ;;
esac
}
if [[ -d "$install_dir/.git" ]]; then
local current
current=$(git -C "$install_dir" rev-parse HEAD 2>/dev/null || true)
if ! current=$(git -C "$install_dir" rev-parse HEAD 2>/dev/null); then
log_err "Cannot resolve existing checkout HEAD: $install_dir"
return 1
fi
if [[ "$current" != "$commit" ]]; then
log_err "Existing checkout is not at pinned commit $commit: $install_dir"
log_err "Move it aside explicitly, then retry; bootstrap will not overwrite local changes."
return 1
fi
git_checkout_is_clean "$install_dir" || return 1
return 0
fi
if [[ -e "$install_dir" ]]; then
@@ -393,15 +439,36 @@ install_git_commit() {
return 1
fi
ensure_dir "$(dirname "$install_dir")"
git init --quiet "$install_dir"
git -C "$install_dir" remote add origin "$repo"
git -C "$install_dir" fetch --depth 1 origin "$commit"
git -C "$install_dir" checkout --quiet --detach FETCH_HEAD
local resolved
resolved=$(git -C "$install_dir" rev-parse HEAD)
local parent stage resolved
parent=$(dirname "$install_dir")
ensure_dir "$parent"
stage=$(mktemp -d "$parent/.reverse-bootstrap-XXXXXX") || return 1
if ! git init --quiet "$stage" ||
! git -C "$stage" remote add origin "$repo" ||
! git -C "$stage" fetch --depth 1 origin "$commit" ||
! git -C "$stage" checkout --quiet --detach FETCH_HEAD; then
cleanup_git_stage "$stage" "$parent"
return 1
fi
if ! resolved=$(git -C "$stage" rev-parse HEAD); then
cleanup_git_stage "$stage" "$parent"
return 1
fi
if [[ "$resolved" != "$commit" ]]; then
log_err "Pinned checkout verification failed for $repo: expected $commit, got $resolved"
cleanup_git_stage "$stage" "$parent"
return 1
fi
if ! git_checkout_is_clean "$stage"; then
cleanup_git_stage "$stage" "$parent"
return 1
fi
if ! python3 - "$stage" "$install_dir" <<'PY'
import os, sys
os.rename(sys.argv[1], sys.argv[2])
PY
then
cleanup_git_stage "$stage" "$parent"
return 1
fi
}
@@ -539,7 +606,7 @@ ensure_apktool() {
}
ensure_frida_tools() {
ensure_python_runtime
ensure_python_runtime || return 1
if has_cmd frida && has_cmd frida-ps; then log_ok "frida-tools ready"; return 0; fi
local package
package=$(manifest_field frida pipPackage)
@@ -548,7 +615,7 @@ ensure_frida_tools() {
}
ensure_idalib_mcp() {
ensure_python_runtime
ensure_python_runtime || return 1
if has_cmd ida-pro-mcp; then log_ok "ida-pro-mcp ready: $(cmd_path ida-pro-mcp)"; return 0; fi
local source
source=$(manifest_field idalib-mcp pipSource)
@@ -558,7 +625,7 @@ ensure_idalib_mcp() {
}
ensure_jshookmcp() {
ensure_node_runtime
ensure_node_runtime || return 1
local package
package=$(manifest_field jshookmcp npmPackage)
write_mcp_server "jshook" "$(python3 - "$package" <<'PY'
@@ -569,7 +636,7 @@ PY
}
ensure_reqable_mcp() {
ensure_node_runtime
ensure_node_runtime || return 1
local package
package=$(manifest_field reqable-mcp npmPackage)
write_mcp_server "reqable-mcp" "$(python3 - "$package" <<'PY'
@@ -589,11 +656,13 @@ ensure_anything_analyzer() {
case "$PLATFORM" in macos) install_brew git ;; linux) install_apt git ;; esac
fi
install_git_commit "$repo" "$commit" "$dir" || return 1
ensure_node_runtime
ensure_pnpm
ensure_node_runtime || return 1
ensure_pnpm || return 1
write_mcp_server "anything-analyzer" '{"url":"http://localhost:23816/mcp"}'
if $START_SERVICES; then
(cd "$dir" && pnpm install && nohup pnpm dev >/tmp/anything-analyzer.log 2>&1 &)
(cd "$dir" && pnpm install --frozen-lockfile) || return 1
install_git_commit "$repo" "$commit" "$dir" || return 1
(cd "$dir" && nohup pnpm dev >/tmp/anything-analyzer.log 2>&1 &)
if wait_for_port 23816 120; then
if test_mcp_http 23816; then
log_ok "anything-analyzer MCP server ready on port 23816 (HTTP verified)"
@@ -647,7 +716,7 @@ ensure_adb() {
}
ensure_agent_browser() {
ensure_node_runtime
ensure_node_runtime || return 1
if has_cmd agent-browser; then log_ok "agent-browser ready"; return 0; fi
local package
package=$(manifest_field agent-browser npmPackage)
@@ -658,7 +727,7 @@ ensure_agent_browser() {
}
ensure_ghidra_mcp() {
ensure_java_runtime
ensure_java_runtime || return 1
local repo regex
repo=$(manifest_field ghidra-mcp repo)
regex=$(manifest_field ghidra-mcp assetRegex)
@@ -689,7 +758,7 @@ ensure_seclists() {
}
ensure_proxycat() {
ensure_python_runtime
ensure_python_runtime || return 1
if has_cmd proxycat; then log_ok "proxycat ready"; return 0; fi
local repo commit
repo=$(manifest_field proxycat repo)
@@ -785,7 +854,7 @@ ensure_yara() {
}
ensure_pwntools() {
ensure_python_runtime
ensure_python_runtime || return 1
if python3 -c "import pwn" 2>/dev/null; then log_ok "pwntools ready"; return 0; fi
local package
package=$(manifest_field pwntools pipPackage)
+125 -197
View File
@@ -3,12 +3,11 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BOOTSTRAP="$SCRIPT_DIR/bootstrap-reverse.sh"
MANIFEST="$SCRIPT_DIR/bootstrap-manifest.json"
KALI_BOOTSTRAP="$SCRIPT_DIR/../../kali/scripts/bootstrap-reverse.sh"
MANIFEST="$SCRIPT_DIR/bootstrap-manifest.json"
REAL_PYTHON="$(command -v python3)"
SCRATCH="$(mktemp -d /tmp/reverse-bootstrap-test-XXXXXX)"
trap 'rm -rf "$SCRATCH"' EXIT
STUB_BIN="$SCRATCH/bin"
CALL_LOG="$SCRATCH/calls.log"
mkdir -p "$STUB_BIN" "$SCRATCH/home" "$SCRATCH/tools"
@@ -16,223 +15,152 @@ mkdir -p "$STUB_BIN" "$SCRATCH/home" "$SCRATCH/tools"
cat > "$STUB_BIN/command-stub" <<'STUB'
#!/usr/bin/env bash
name="$(basename "$0")"
{
printf '%s' "$name"
for arg in "$@"; do printf '|%s' "$arg"; done
printf '\n'
} >> "$CALL_LOG"
if [[ "${STUB_FAIL_COMMAND:-}" == "$name" ]]; then
exit 1
fi
if [[ "$name" == "git" ]]; then
if [[ "${1:-}" == "init" ]]; then
target="${!#}"
mkdir -p "$target/.git"
printf '%s\n' 'unpinned-head' > "$target/.stub-head"
elif [[ "${1:-}" == "-C" && "${3:-}" == "fetch" ]]; then
printf '%s\n' "${7:-}" > "$2/.stub-fetch"
elif [[ "${1:-}" == "-C" && "${3:-}" == "checkout" ]]; then
cat "$2/.stub-fetch" > "$2/.stub-head"
elif [[ "${1:-}" == "-C" && "${3:-}" == "rev-parse" ]]; then
cat "$2/.stub-head"
fi
fi
exit 0
{ printf '%s' "$name"; for arg in "$@"; do printf '|%s' "$arg"; done; printf '\n'; } >> "$CALL_LOG"
case "$name:${1:-}" in
pipx:--version) printf '%s\n' "${STUB_PIPX_VERSION:-0}" ;;
pnpm:--version) printf '%s\n' "${STUB_PNPM_VERSION:-0}" ;;
git:init)
target="${!#}"; mkdir -p "$target/.git"; printf '%s\n' unpinned-head > "$target/.stub-head"
;;
git:-C)
case "${3:-}" in
fetch)
[[ "${STUB_FAIL_FETCH:-0}" != 1 ]] || exit 1
printf '%s\n' "${7:-}" > "$2/.stub-fetch"
;;
checkout) cp "$2/.stub-fetch" "$2/.stub-head" ;;
rev-parse) cat "$2/.stub-head" ;;
status) [[ ! -e "$2/.stub-dirty" ]] || printf '%s\n' '?? .npmrc' ;;
esac
;;
nc:-z)
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
;;
esac
[[ "${STUB_FAIL_COMMAND:-}" != "$name" ]]
STUB
chmod +x "$STUB_BIN/command-stub"
for command_name in git node npm npx pipx pnpm sleep; do
ln -s command-stub "$STUB_BIN/$command_name"
done
for name in git node npm npx pipx pnpm sleep nc; do ln -s command-stub "$STUB_BIN/$name"; done
cat > "$STUB_BIN/python3" <<STUB
#!/usr/bin/env bash
if [[ "\${1:-}" == "-" && "\${2:-}" == "23816" ]]; then
exit 0
fi
if [[ "\${1:-}" == "-c" && "\${2:-}" == "import pwn" ]]; then
exit 1
fi
{ printf 'python3'; for arg in "\$@"; do printf '|%s' "\$arg"; done; printf '\n'; } >> "\$CALL_LOG"
if [[ "\${1:-}" == '-m' && "\${2:-}" == pip ]]; then [[ "\${STUB_FAIL_PIP_INSTALL:-0}" != 1 ]]; exit; fi
if [[ "\${1:-}" == '-m' && "\${2:-}" == pipx ]]; then exit 0; fi
if [[ "\${1:-}" == '-c' && "\${2:-}" == 'import pwn' ]]; then exit 1; fi
if [[ "\${1:-}" == '-' && "\${2:-}" == 23816 ]]; then exit 0; fi
exec "$REAL_PYTHON" "\$@"
STUB
chmod +x "$STUB_BIN/python3"
manifest_value() {
json_value() {
"$REAL_PYTHON" - "$MANIFEST" "$1" "$2" <<'PY'
import json, pathlib, sys
manifest = json.loads(pathlib.Path(sys.argv[1]).read_text(encoding='utf-8'))
capability = next(item for item in manifest['capabilities'] if item['name'] == sys.argv[2])
value = capability.get(sys.argv[3], '')
print(value if isinstance(value, str) else json.dumps(value, separators=(',', ':')))
d=json.loads(pathlib.Path(sys.argv[1]).read_text())
if sys.argv[2] == 'dependency': v=d['bootstrapDependencies'][sys.argv[3]]['package']
else: v=next(x for x in d['capabilities'] if x['name']==sys.argv[2])[sys.argv[3]]
print(v)
PY
}
run_bootstrap() {
env \
PATH="$STUB_BIN:/usr/bin:/bin" \
HOME="$SCRATCH/home" \
CALL_LOG="$CALL_LOG" \
REVERSE_SKILL_TOOLS_DIR="$SCRATCH/tools" \
CLAUDE_MCP_CONFIG="$SCRATCH/home/mcp.json" \
bash "$BOOTSTRAP" "$@"
run_generic() {
env PATH="$STUB_BIN:/usr/bin:/bin" HOME="$SCRATCH/home" CALL_LOG="$CALL_LOG" \
STUB_PIPX_VERSION="${STUB_PIPX_VERSION:-}" STUB_PNPM_VERSION="${STUB_PNPM_VERSION:-}" \
STUB_FAIL_PIP_INSTALL="${STUB_FAIL_PIP_INSTALL:-0}" STUB_FAIL_FETCH="${STUB_FAIL_FETCH:-0}" \
REVERSE_SKILL_TOOLS_DIR="${TEST_TOOLS_ROOT:-$SCRATCH/tools}" \
CLAUDE_MCP_CONFIG="$SCRATCH/home/mcp.json" bash "$BOOTSTRAP" "$@"
}
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" "$@"
}
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; }; }
rejects_without_pnpm() {
local runner="$1"; shift
: > "$CALL_LOG"; set +e; "$runner" "$@" >/dev/null 2>&1; local rc=$?; set -e
[[ $rc -ne 0 ]] && ! grep -Eq '^pnpm\|(install|dev)' "$CALL_LOG"
}
run_bootstrap_with_failing_pipx() {
env \
PATH="$STUB_BIN:/usr/bin:/bin" \
HOME="$SCRATCH/home" \
CALL_LOG="$CALL_LOG" \
STUB_FAIL_COMMAND=pipx \
REVERSE_SKILL_TOOLS_DIR="$SCRATCH/tools" \
CLAUDE_MCP_CONFIG="$SCRATCH/home/mcp.json" \
bash "$BOOTSTRAP" "$@"
}
pipx_package=$(json_value dependency pipx)
pnpm_package=$(json_value dependency pnpm)
anything_repo=$(json_value anything-analyzer repoUrl)
anything_pin=$(json_value anything-analyzer pinnedCommit)
run_kali_bootstrap() {
env \
PATH="$STUB_BIN:/opt/homebrew/bin:/usr/bin:/bin" \
HOME="$SCRATCH/home" \
CALL_LOG="$CALL_LOG" \
bash "$KALI_BOOTSTRAP" "$@"
}
failures=0
check_log_line() {
if ! grep -Fqx "$1" "$CALL_LOG"; then
printf 'missing argv: %s\n' "$1" >&2
failures=$((failures + 1))
fi
}
: > "$CALL_LOG"
run_bootstrap frida --skip-refresh >/dev/null
frida_package="$(manifest_value frida pipPackage)"
check_log_line "pipx|install|--force|$frida_package"
: > "$CALL_LOG"
run_bootstrap idalib-mcp --skip-refresh >/dev/null
idalib_source="$(manifest_value idalib-mcp pipSource)"
check_log_line "pipx|install|--force|$idalib_source"
: > "$CALL_LOG"
set +e
run_bootstrap_with_failing_pipx idalib-mcp --skip-refresh >/dev/null 2>&1
idalib_fail_exit=$?
set -e
if [[ "$idalib_fail_exit" -eq 0 ]]; then
printf 'idalib-mcp reported success after its pinned install failed\n' >&2
failures=$((failures + 1))
fi
check_log_line "pipx|install|--force|$idalib_source"
if [[ "$(wc -l < "$CALL_LOG" | tr -d ' ')" -ne 1 ]]; then
printf 'idalib-mcp attempted an unpinned fallback after pinned install failure\n' >&2
failures=$((failures + 1))
fi
: > "$CALL_LOG"
run_bootstrap agent-browser --skip-refresh >/dev/null
agent_package="$(manifest_value agent-browser npmPackage)"
check_log_line "npm|install|-g|$agent_package"
: > "$CALL_LOG"
run_bootstrap seclists --skip-refresh >/dev/null
seclists_repo="$(manifest_value seclists repo)"
seclists_pin="$(manifest_value seclists pinnedCommit)"
seclists_dir="$SCRATCH/tools/SecLists"
check_log_line "git|-C|$seclists_dir|remote|add|origin|$seclists_repo"
check_log_line "git|-C|$seclists_dir|fetch|--depth|1|origin|$seclists_pin"
: > "$CALL_LOG"
run_bootstrap proxycat --skip-refresh >/dev/null
proxycat_repo="$(manifest_value proxycat repo)"
proxycat_pin="$(manifest_value proxycat pinnedCommit)"
check_log_line "pipx|install|git+${proxycat_repo}@${proxycat_pin}"
: > "$CALL_LOG"
run_bootstrap pwntools --skip-refresh >/dev/null
pwntools_package="$(manifest_value pwntools pipPackage)"
check_log_line "pipx|install|$pwntools_package"
: > "$CALL_LOG"
run_bootstrap anything-analyzer --start-services --skip-refresh >/dev/null
anything_repo="$(manifest_value anything-analyzer repoUrl)"
anything_pin="$(manifest_value anything-analyzer pinnedCommit)"
anything_dir="$SCRATCH/tools/anything-analyzer"
if [[ -z "$anything_pin" ]]; then
printf 'anything-analyzer is missing pinnedCommit in bootstrap-manifest.json\n' >&2
failures=$((failures + 1))
else
check_log_line "git|init|--quiet|$anything_dir"
check_log_line "git|-C|$anything_dir|remote|add|origin|$anything_repo"
check_log_line "git|-C|$anything_dir|fetch|--depth|1|origin|$anything_pin"
check_log_line "git|-C|$anything_dir|checkout|--quiet|--detach|FETCH_HEAD"
check_log_line "git|-C|$anything_dir|rev-parse|HEAD"
fi
check_log_line 'pnpm|install'
check_log_line 'pnpm|dev'
if [[ -n "$anything_pin" ]]; then
checkout_line="$(grep -nF "git|-C|$anything_dir|checkout|--quiet|--detach|FETCH_HEAD" "$CALL_LOG" | cut -d: -f1 | head -n1)"
install_line="$(grep -nF 'pnpm|install' "$CALL_LOG" | cut -d: -f1 | head -n1)"
if [[ -z "$checkout_line" || -z "$install_line" || "$checkout_line" -ge "$install_line" ]]; then
printf 'anything-analyzer dependencies ran before the pinned checkout\n' >&2
failures=$((failures + 1))
fi
fi
: > "$CALL_LOG"
mkdir -p "$anything_dir/.git"
printf '%s\n' 'different-commit' > "$anything_dir/.stub-head"
set +e
run_bootstrap anything-analyzer --start-services --skip-refresh >/dev/null 2>&1
mismatch_exit=$?
set -e
if [[ "$mismatch_exit" -eq 0 ]]; then
printf 'anything-analyzer accepted an existing checkout at a different commit\n' >&2
failures=$((failures + 1))
fi
if grep -Eq '^pnpm\|(install|dev)$' "$CALL_LOG"; then
printf 'anything-analyzer ran dependencies from an unpinned existing checkout\n' >&2
failures=$((failures + 1))
fi
if (( BASH_VERSINFO[0] >= 4 )); then
# Table: each generic package-manager sink receives its canonical manifest value.
while IFS='|' read -r capability field expected; do
: > "$CALL_LOG"
STUB_PIPX_VERSION=1.16.5 run_generic "$capability" --skip-refresh >/dev/null
expect_line "$expected"
done <<EOF
frida|pipPackage|pipx|install|--force|$(json_value frida pipPackage)
idalib-mcp|pipSource|pipx|install|--force|$(json_value idalib-mcp pipSource)
agent-browser|npmPackage|npm|install|-g|$(json_value agent-browser npmPackage)
proxycat|repo|pipx|install|git+$(json_value proxycat repo)@$(json_value proxycat pinnedCommit)
pwntools|pipPackage|pipx|install|$(json_value pwntools pipPackage)
EOF
# pipx itself is pinned; a failed pinned install has no mutable fallback.
: > "$CALL_LOG"
STUB_FAIL_PIP_INSTALL=1 run_generic frida --skip-refresh >/dev/null 2>&1 && exit 1 || true
expect_line "python3|-m|pip|install|--user|--upgrade|$pipx_package"
[[ $(grep -c '|pip|install|' "$CALL_LOG") -eq 1 ]]
! grep -Eq '^pipx\|(install|upgrade)' "$CALL_LOG"
# Generic Anything Analyzer: staged checkout, pinned pnpm, frozen install, clean recheck, then dev.
: > "$CALL_LOG"
STUB_PIPX_VERSION=1.16.5 STUB_PNPM_VERSION=0 run_generic anything-analyzer --start-services --skip-refresh >/dev/null
anything_dir="$SCRATCH/tools/anything-analyzer"
expect_line "npm|install|-g|$pnpm_package"
expect_line 'pnpm|install|--frozen-lockfile'
expect_line 'pnpm|dev'
expect_fragment "remote|add|origin|$anything_repo"
expect_fragment "fetch|--depth|1|origin|$anything_pin"
[[ -d "$anything_dir/.git" ]]
[[ $(grep -c '|status|--porcelain|--untracked-files=all' "$CALL_LOG") -ge 2 ]]
# Dirty sources never reach install/dev.
touch "$anything_dir/.stub-dirty"
rejects_without_pnpm run_generic anything-analyzer --start-services --skip-refresh
rm "$anything_dir/.stub-dirty"
# Failed fetch leaves no final checkout or staging poison; a retry can succeed.
retry_root="$SCRATCH/retry-tools"
TEST_TOOLS_ROOT="$retry_root" STUB_FAIL_FETCH=1 rejects_without_pnpm run_generic anything-analyzer --start-services --skip-refresh
[[ ! -e "$retry_root/anything-analyzer" ]]
[[ -z "$(find "$retry_root" -maxdepth 1 -name '.reverse-bootstrap-*' -print -quit)" ]]
: > "$CALL_LOG"
TEST_TOOLS_ROOT="$retry_root" STUB_PNPM_VERSION=10.24.0 run_generic anything-analyzer --start-services --skip-refresh >/dev/null
[[ -d "$retry_root/anything-analyzer/.git" ]]
# Kali exercises the same source-before-execution boundary where associative arrays are supported.
if (( BASH_VERSINFO[0] >= 4 )); then
kali_dir="$SCRATCH/home/tools/anything-analyzer"
rm -rf "$kali_dir"
set +e
run_kali_bootstrap anything-analyzer --start-services --skip-refresh >"$SCRATCH/kali-bootstrap.out" 2>&1
set -e
check_log_line "git|init|-q|$kali_dir"
check_log_line "git|-C|$kali_dir|remote|add|origin|$anything_repo"
check_log_line "git|-C|$kali_dir|fetch|--depth|1|origin|$anything_pin"
check_log_line "git|-C|$kali_dir|checkout|-q|--detach|FETCH_HEAD"
check_log_line 'pnpm|install'
check_log_line 'pnpm|dev'
: > "$CALL_LOG"
mkdir -p "$kali_dir/.git"
printf '%s\n' 'different-commit' > "$kali_dir/.stub-head"
set +e
run_kali_bootstrap anything-analyzer --start-services --skip-refresh >/dev/null 2>&1
kali_mismatch_exit=$?
STUB_PNPM_VERSION=0 run_kali anything-analyzer --start-services --skip-refresh >/dev/null 2>&1
set -e
if [[ "$kali_mismatch_exit" -eq 0 ]]; then
printf 'Kali anything-analyzer accepted an existing checkout at a different commit\n' >&2
failures=$((failures + 1))
fi
if grep -Eq '^pnpm\|(install|dev)$' "$CALL_LOG"; then
printf 'Kali anything-analyzer ran dependencies from an unpinned existing checkout\n' >&2
failures=$((failures + 1))
fi
expect_line "npm|install|-g|$pnpm_package"
expect_line 'pnpm|install|--frozen-lockfile'
[[ $(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
rm -rf "$kali_dir"
: > "$CALL_LOG"
STUB_FAIL_FETCH=1 rejects_without_pnpm run_kali anything-analyzer --start-services --skip-refresh
[[ ! -e "$kali_dir" ]]
[[ -z "$(find "${kali_dir%/*}" -maxdepth 1 -name '.reverse-bootstrap-*' -print -quit)" ]]
set +e
STUB_PNPM_VERSION=10.24.0 run_kali anything-analyzer --start-services --skip-refresh >/dev/null 2>&1
set -e
[[ -d "$kali_dir/.git" ]]
expect_line 'pnpm|install|--frozen-lockfile'
fi
if [[ "$failures" -ne 0 ]]; then
if [[ -f "$SCRATCH/kali-bootstrap.out" ]]; then cat "$SCRATCH/kali-bootstrap.out" >&2; fi
printf '%s\n' 'captured argv:' >&2
cat "$CALL_LOG" >&2
exit 1
fi
printf '%s\n' 'bootstrap manifest source regression passed'
echo 'bootstrap manifest source regression passed'
@@ -395,6 +395,17 @@ foreach ($mf in @($skillsManifest, $kaliManifest)) {
if (-not (Test-Path -LiteralPath $mf)) { continue }
$mn = Split-Path $mf -Leaf
$mc = Get-Content -LiteralPath $mf -Raw -Encoding UTF8 | ConvertFrom-Json
foreach ($dependencyProperty in @($mc.bootstrapDependencies.PSObject.Properties)) {
$dependency = $dependencyProperty.Value
$expectedSuffix = '(?:==|@)' + [regex]::Escape([string]$dependency.version) + '$'
if ([string]::IsNullOrWhiteSpace([string]$dependency.package) -or
[string]::IsNullOrWhiteSpace([string]$dependency.version) -or
[string]$dependency.package -notmatch $expectedSuffix) {
Bad "unpinned bootstrap dependency: $($dependencyProperty.Name) in $mn"
} else {
Ok "pinned bootstrap dependency $($dependencyProperty.Name) in $mn"
}
}
foreach ($cap in $mc.capabilities) {
if (-not $cap.canAutoInstall) { continue }
$hasPin = ($cap.pinnedVersion -or $cap.pinnedCommit -or $cap.pinPolicy)