diff --git a/hooks/disk-reclaim.sh b/hooks/disk-reclaim.sh index 6bb6e29..4161184 100755 --- a/hooks/disk-reclaim.sh +++ b/hooks/disk-reclaim.sh @@ -85,11 +85,18 @@ for proj_git in "$PROJECTS_ROOT"/*/.claude/worktrees "$PROJECTS_ROOT"/*/*/.claud continue fi - # Guard 3: unpushed - unpushed=$(cd "$wt" && git log @{u}.. 2>/dev/null | wc -l | tr -d ' ') - if [ -n "$unpushed" ] && [ "$unpushed" != "0" ]; then + # Guard 3: unpushed (fail-safe — skip on missing upstream) + if cd "$wt" 2>/dev/null && git rev-parse --abbrev-ref @{u} >/dev/null 2>&1; then + unpushed=$(git log @{u}.. 2>/dev/null | wc -l | tr -d ' ') + if [ -n "$unpushed" ] && [ "$unpushed" != "0" ]; then + worktrees_skip_unpushed=$((worktrees_skip_unpushed + 1)) + log " SKIP[unpushed=$unpushed] $wt" + continue + fi + else + # No upstream tracking — treat as "may have unpushed work", skip conservatively worktrees_skip_unpushed=$((worktrees_skip_unpushed + 1)) - log " SKIP[unpushed=$unpushed] $wt" + log " SKIP[no-upstream] $wt" continue fi diff --git a/hooks/secrets-pre-guard.sh b/hooks/secrets-pre-guard.sh index bd834ac..7a7b1fc 100755 --- a/hooks/secrets-pre-guard.sh +++ b/hooks/secrets-pre-guard.sh @@ -40,64 +40,65 @@ CONTENT=$(printf '%s' "$INPUT" | jq -r \ [ -z "$CONTENT" ] && exit 0 -# --- Allowlist: placeholder or documentation patterns ---------------------- -# If the content indicates example/placeholder values, skip. -if printf '%s' "$CONTENT" | grep -qiE \ - 'YOUR_TOKEN_HERE||\[VERIFY:|placeholder|xxx+|_TOKEN_NAME_HERE|_KEY_HERE|_SECRET_HERE|example[_-]?(key|token|secret)'; then - exit 0 -fi +# --- Per-line allowlist + secret detection --------------------------------- +# Evaluate placeholder allowlist PER LINE (not globally) so a "placeholder" +# marker elsewhere in the file does not disable secret scanning on lines +# that contain real tokens. +# +# A line is allowed iff it contains BOTH a secret-shaped pattern AND a +# placeholder marker on the SAME LINE. Otherwise, the secret pattern on +# that line is treated as a real hit. -# --- Secret detection patterns ------------------------------------------- -# Each pattern is checked individually so we can name the type in the error. +ALLOWLIST_RE='YOUR_TOKEN_HERE||\[VERIFY:|placeholder|xxx+|_TOKEN_NAME_HERE|_KEY_HERE|_SECRET_HERE|example[_-]?(key|token|secret)|dummy[_-]?(key|token|secret)' DETECTED="" +# Helper: scan content line-by-line for a given regex; for each match, +# allow only if the SAME LINE matches ALLOWLIST_RE. Sets DETECTED to label +# on first non-allowlisted hit. +scan_pattern() { + pattern="$1" + label="$2" + [ -n "$DETECTED" ] && return 0 + hit=$(printf '%s' "$CONTENT" | awk -v pat="$pattern" -v allow="$ALLOWLIST_RE" ' + { + if (match($0, pat)) { + if (match($0, allow)) { + next + } + print "HIT" + exit + } + } + ') + if [ "$hit" = "HIT" ]; then + DETECTED="$label" + fi +} + # Anthropic/OpenAI legacy key -if printf '%s' "$CONTENT" | grep -qE 'sk-[A-Za-z0-9]{20,}'; then - DETECTED="Anthropic/OpenAI legacy key (sk-...)" -fi +scan_pattern 'sk-[A-Za-z0-9]{20,}' "Anthropic/OpenAI legacy key (sk-...)" # Anthropic current key -if [ -z "$DETECTED" ] && \ - printf '%s' "$CONTENT" | grep -qE 'sk-ant-[A-Za-z0-9_-]{40,}'; then - DETECTED="Anthropic current key (sk-ant-...)" -fi +scan_pattern 'sk-ant-[A-Za-z0-9_-]{40,}' "Anthropic current key (sk-ant-...)" # GitHub classic PAT -if [ -z "$DETECTED" ] && \ - printf '%s' "$CONTENT" | grep -qE 'ghp_[A-Za-z0-9]{36}'; then - DETECTED="GitHub classic PAT (ghp_...)" -fi +scan_pattern 'ghp_[A-Za-z0-9]{36}' "GitHub classic PAT (ghp_...)" # GitHub fine-grained PAT -if [ -z "$DETECTED" ] && \ - printf '%s' "$CONTENT" | grep -qE 'github_pat_[A-Za-z0-9_]{82}'; then - DETECTED="GitHub fine-grained PAT (github_pat_...)" -fi +scan_pattern 'github_pat_[A-Za-z0-9_]{82}' "GitHub fine-grained PAT (github_pat_...)" # Slack bot token -if [ -z "$DETECTED" ] && \ - printf '%s' "$CONTENT" | grep -qE 'xoxb-[0-9]+-[0-9]+-[A-Za-z0-9]+'; then - DETECTED="Slack bot token (xoxb-...)" -fi +scan_pattern 'xoxb-[0-9]+-[0-9]+-[A-Za-z0-9]+' "Slack bot token (xoxb-...)" # Telegram bot token -if [ -z "$DETECTED" ] && \ - printf '%s' "$CONTENT" | grep -qE '[0-9]{8,10}:[A-Za-z0-9_-]{35}'; then - DETECTED="Telegram bot token (NNNNNNNNN:...)" -fi +scan_pattern '[0-9]{8,10}:[A-Za-z0-9_-]{35}' "Telegram bot token (NNNNNNNNN:...)" # AWS access key -if [ -z "$DETECTED" ] && \ - printf '%s' "$CONTENT" | grep -qE 'AKIA[A-Z0-9]{16}'; then - DETECTED="AWS access key (AKIA...)" -fi +scan_pattern 'AKIA[A-Z0-9]{16}' "AWS access key (AKIA...)" # PEM private key block -if [ -z "$DETECTED" ] && \ - printf '%s' "$CONTENT" | grep -qE '-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----'; then - DETECTED="PEM private key (-----BEGIN ... PRIVATE KEY-----)" -fi +scan_pattern '-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----' "PEM private key (-----BEGIN ... PRIVATE KEY-----)" [ -z "$DETECTED" ] && exit 0 diff --git a/install/lib-rust-prebuild.sh b/install/lib-rust-prebuild.sh index 045876f..ebab772 100644 --- a/install/lib-rust-prebuild.sh +++ b/install/lib-rust-prebuild.sh @@ -76,7 +76,15 @@ download_release_tarball() { (cd "$tmp" && shasum -a 256 -c "${tarball}.sha256" >/dev/null 2>&1) \ || { say " sha256 mismatch on ${tarball} — refusing to install"; rm -rf "$tmp"; return 1; } else - say " WARNING: no sha256 available for ${tarball}, proceeding without verification" + say " ERROR: no sha256 sidecar found at ${url}.sha256" + say " Refusing to install unverified tarball (RULE 0.1 supply-chain hardening)." + say " Override with KEI_ALLOW_UNVERIFIED_TARBALL=1 (visible per-call)." + if [ "${KEI_ALLOW_UNVERIFIED_TARBALL:-0}" = "1" ]; then + say " KEI_ALLOW_UNVERIFIED_TARBALL=1 set — proceeding without verification (DANGEROUS)." + else + rm -rf "$tmp" + return 1 + fi fi local dst="$KIT_DIR/_primitives/_rust/target/release" mkdir -p "$dst" || { rm -rf "$tmp"; return 1; }