From 7e2c2333b88b8a6f67e54f4cbbf34fd0f405c92e Mon Sep 17 00:00:00 2001 From: Lukas Wuttke Date: Tue, 14 Jul 2026 20:59:34 +0200 Subject: [PATCH] fix(ci): PAT-reachability fallback + pin-ref shape guard for the data-ingestors jobs Two Cursor Bugbot findings surfaced on the #323 promotion re-review of the data-ingestors drift jobs: 1. Invalid PAT breaks canary checkout (Medium). head-drift-canary.yml passed `secrets.CROSS_REPO_READ_TOKEN || github.token` straight to actions/checkout. `||` only falls back when the secret is EMPTY, so a set-but-expired / mis-scoped PAT reds the weekly canary even though data-ingestors is public and github.token would work. Ported goldens-drift.yml's reachability probe: a `git ls-remote` check picks the PAT only when it actually works and falls back to the default token otherwise (use_pat output, kept in lockstep with the checkout). goldens-drift.yml already had this probe. 2. Pin ref lacks shape guard (Low). goldens-drift.yml and head-drift-canary.yml read scripts/.data-ingestors-ref and (for goldens-drift) pass it straight to actions/checkout after only an emptiness check, unlike chart-drift.yml which validates ref shape. Added the same guard to both: SHA / branch / tag characters only and no "..", so a malformed pin fails with a clear error instead of an opaque checkout failure. Verified: the shape guard accepts the real pin, branch/tag/SHA refs, and rejects "..", shell metacharacters, and empty; the probe's no-token path selects github.token; actionlint + shellcheck clean; YAML valid. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/goldens-drift.yml | 7 +++++ .github/workflows/head-drift-canary.yml | 34 ++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/.github/workflows/goldens-drift.yml b/.github/workflows/goldens-drift.yml index 53837b0a..06791c98 100644 --- a/.github/workflows/goldens-drift.yml +++ b/.github/workflows/goldens-drift.yml @@ -65,6 +65,13 @@ jobs: echo "::error::scripts/.data-ingestors-ref contains no ref" exit 1 fi + # Shape guard (mirrors chart-drift.yml): SHA / branch / tag characters + # only and no "..", so a malformed pin fails here with a clear error + # instead of an opaque failure deep in git / actions-checkout. + if ! printf '%s' "$ref" | grep -qE '^[A-Za-z0-9][A-Za-z0-9._/-]*$' || printf '%s' "$ref" | grep -q '\.\.'; then + echo "::error file=scripts/.data-ingestors-ref::invalid ref shape: $ref" + exit 1 + fi echo "ref=$ref" >> "$GITHUB_OUTPUT" - name: Probe data-ingestors readability diff --git a/.github/workflows/head-drift-canary.yml b/.github/workflows/head-drift-canary.yml index 4d174af2..8d308733 100644 --- a/.github/workflows/head-drift-canary.yml +++ b/.github/workflows/head-drift-canary.yml @@ -58,8 +58,36 @@ jobs: echo "::error::scripts/.data-ingestors-ref contains no ref" exit 1 fi + # Shape guard (mirrors chart-drift.yml): SHA / branch / tag characters + # only and no "..", so a malformed pin fails here with a clear error + # instead of an opaque failure deep in git / actions-checkout. + if ! printf '%s' "$ref" | grep -qE '^[A-Za-z0-9][A-Za-z0-9._/-]*$' || printf '%s' "$ref" | grep -q '\.\.'; then + echo "::error file=scripts/.data-ingestors-ref::invalid ref shape: $ref" + exit 1 + fi echo "ref=$ref" >> "$GITHUB_OUTPUT" + - name: Select the data-ingestors read token + id: access + # data-ingestors is public today, so github.token suffices. Prefer the + # least-privilege CROSS_REPO_READ_TOKEN when it is set AND actually + # works, but a set-but-invalid PAT (expired / wrong scope) must fall back + # to the default token rather than red this advisory canary for an infra + # misconfig — the same reachability probe goldens-drift.yml uses, kept in + # lockstep with the checkout below via the use_pat output. + env: + CROSS_REPO_READ_TOKEN: ${{ secrets.CROSS_REPO_READ_TOKEN }} + run: | + use_pat=false + if [ -n "$CROSS_REPO_READ_TOKEN" ]; then + if git ls-remote "https://x-access-token:${CROSS_REPO_READ_TOKEN}@github.com/tracebloc/data-ingestors.git" HEAD >/dev/null 2>&1; then + use_pat=true + else + echo "::warning::CROSS_REPO_READ_TOKEN is set but tracebloc/data-ingestors is not readable with it (expired or wrong scope) — falling back to the default workflow token." + fi + fi + echo "use_pat=$use_pat" >> "$GITHUB_OUTPUT" + - name: Checkout tracebloc/data-ingestors @ develop HEAD uses: actions/checkout@v4 with: @@ -68,7 +96,11 @@ jobs: path: data-ingestors # Full history so the pin SHA is present for the pin-vs-HEAD diff. fetch-depth: 0 - token: ${{ secrets.CROSS_REPO_READ_TOKEN || github.token }} + # Exactly the token the probe validated: the PAT only when use_pat + # confirmed it works, else the default token — so a set-but-invalid + # PAT falls back instead of hard-failing a checkout the public repo + # would otherwise allow. + token: ${{ steps.access.outputs.use_pat == 'true' && secrets.CROSS_REPO_READ_TOKEN || github.token }} - name: Diff the mirrored validator surface, pin vs HEAD id: srcdiff