diff --git a/scripts/ci-health/README.adoc b/scripts/ci-health/README.adoc index 16027554..3ee21a85 100644 --- a/scripts/ci-health/README.adoc +++ b/scripts/ci-health/README.adoc @@ -47,6 +47,10 @@ matches its ref. This is an exact diagnosis within that bounded run horizon. | **Report only** — in a checkout, run `gh actions-lock --verify`, repair the reported dependency with the authoritative tool, and commit `actions.lock`. +| `B-TRACKER-TOKEN` +| HIGH. The pin updater explicitly reports a missing write credential. +| **Report only** — compare pins read-only. If an update is needed, provision the repository-scoped updater credential. + | `B-STARTUPFAIL` | One or more `startup_failure` conclusions among the latest API page of at most 30 workflow runs. The report includes both numerator and denominator and diff --git a/scripts/ci-health/detect.sh b/scripts/ci-health/detect.sh index 883aad84..6c6d4fc2 100755 --- a/scripts/ci-health/detect.sh +++ b/scripts/ci-health/detect.sh @@ -47,6 +47,7 @@ fi # mechanism and supports a precise recommendation. billing_seen=false lockfile_seen=false +tracker_token_seen=false mapfile -t fail_ids < <(api "repos/$O/$R/actions/runs?status=failure&per_page=5" --jq '.workflow_runs[].id' || true) for fail_id in "${fail_ids[@]}"; do [ -n "${fail_id:-}" ] || continue @@ -54,6 +55,10 @@ for fail_id in "${fail_ids[@]}"; do for job_id in "${job_ids[@]}"; do [ -n "${job_id:-}" ] || continue msg=$(api "repos/$O/$R/check-runs/$job_id/annotations?per_page=100" --jq '.[].message // empty' || true) + if [ "$tracker_token_seen" = false ] && [[ "$msg" == *"Stale cicd-suite pins detected. AUTOMATION_TOKEN is required"* || "$msg" == *"AUTOMATION_TOKEN is not set. This job edits files under .github/workflows/"* ]]; then + emit B-TRACKER-TOKEN HIGH "Pin updater reports missing write credential (run $fail_id) → compare pins read-only before provisioning repository-scoped write access" + tracker_token_seen=true + fi if [ "$billing_seen" = false ] && printf '%s' "$msg" | grep -qiE 'payments have failed|spending limit'; then emit A-BILLING CRITICAL "Actions billing/spending-limit wall blocks all billable jobs → OWNER: GitHub Settings -> Billing & plans" billing_seen=true diff --git a/scripts/ci-health/sweep.sh b/scripts/ci-health/sweep.sh index 35ec7727..b4c227d0 100755 --- a/scripts/ci-health/sweep.sh +++ b/scripts/ci-health/sweep.sh @@ -49,14 +49,14 @@ rep=$(mktemp) grep -qP '\tA-BILLING\t' "$findings" || echo "- _none_" echo "" echo "### 🟠 B — allow-list / lockfile / bounded startup_failure observations" - grep -P '\tB-(ALLOWLIST|LOCKFILE|STARTUPFAIL)\t' "$findings" | awk -F'\t' '{print "- "$1" ("$2"): "$4}' || true + grep -P '\tB-(ALLOWLIST|LOCKFILE|STARTUPFAIL|TRACKER-TOKEN)\t' "$findings" | awk -F'\t' '{print "- "$1" ("$2"): "$4}' || true grep -qP '\tB-' "$findings" || echo "- _none_" echo "" echo "### 🟡 D-BURN — push/PR double-trigger" grep -P '\tD-BURN\t' "$findings" | awk -F'\t' '{print "- "$1": "$4}' || true grep -qP '\tD-BURN\t' "$findings" || echo "- _none_" echo "" - echo "> Auto-remediation: B-ALLOWLIST is applied in place and verified; D-BURN opens PRs (cap $MAXPR/run). B-LOCKFILE and B-STARTUPFAIL are report-only; A-BILLING is owner-only. See \`scripts/ci-health/README.adoc\`." + echo "> Auto-remediation: B-ALLOWLIST is applied in place and verified; D-BURN opens PRs (cap $MAXPR/run). B-LOCKFILE, B-TRACKER-TOKEN and B-STARTUPFAIL are report-only; A-BILLING is owner-only. See \`scripts/ci-health/README.adoc\`." } >"$rep" [ -n "${GITHUB_STEP_SUMMARY:-}" ] && cat "$rep" >>"$GITHUB_STEP_SUMMARY"