diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index f5b5bbc98..f4c6194b2 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -1,7 +1,7 @@ # Auto-merge — nobody is in the merge loop. # # Green, ready PRs merge themselves and deploy themselves. The policy lives in -# ONE place for the whole fleet — catomean/dotfiles, +# ONE place for the whole fleet — bitbaum/dotfiles, # scripts/ci/auto-merge-sweep.sh — and this file only says "run it, with these # settings". # @@ -42,7 +42,7 @@ permissions: jobs: sweep: - uses: catomean/dotfiles/.github/workflows/auto-merge-sweep.yml@master + uses: bitbaum/dotfiles/.github/workflows/auto-merge-sweep.yml@master with: base_branch: main ci_workflow: ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2b4c5369..b9a9bbf5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -273,26 +273,54 @@ jobs: fetch-depth: 0 - name: Secret scan (gitleaks) - # Free for public repos; no license needed. Fails the job on any finding. + # The gitleaks CLI, not gitleaks-action. The action is free only for + # PERSONAL accounts; under an organization it refuses to scan at all and + # exits with "missing gitleaks license". Moving this repo into the + # bitbaum org therefore switched secret scanning off while leaving the + # job, its name, and its place in the checks list exactly as they were. + # It happened to fail loudly here — but only because the licence check + # errors; a wrapper that had instead skipped would have reported green + # while scanning nothing. The CLI itself is MIT and unaffected. # - # Skipped on workflow_dispatch, and only there. On push and pull_request - # the action scans the incoming commits; a dispatched run has no such - # range, so it falls back to scanning all ~2.6k commits of history and - # fails on ~173 pre-existing findings (2025-era .env commits) that only - # a history rewrite can clear — see the security audit, not CI's job. + # Scope is the incoming commit range, which is what the action scanned. + # Scanning all of history instead would fail on ~173 pre-existing + # findings (2025-era .env commits) that only a history rewrite can clear + # — see the security audit, not CI's job. Coverage is unchanged: every + # commit is still scanned in its PR run before it can merge. # - # This costs nothing in coverage: every commit still gets scanned in its - # PR run before it can merge. The alternative — baselining those 173 - # findings in .gitleaksignore — would mean allowlisting real historical - # credentials, which that file explicitly forbids. - # - # Auto-merge dispatches CI on main after each merge (a GITHUB_TOKEN push - # triggers nothing), so without this every automated merge left main red - # and CD, which chains off green CI, never deployed. + # Skipped on workflow_dispatch, and only there: a dispatched run has no + # incoming range. Auto-merge dispatches CI on main after each merge (a + # GITHUB_TOKEN push triggers nothing), so without that skip every + # automated merge would leave main red and CD would never deploy. if: github.event_name != 'workflow_dispatch' - uses: gitleaks/gitleaks-action@v3 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITLEAKS_VERSION: '8.30.1' + BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} + HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + run: | + set -euo pipefail + curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ + | tar -xz gitleaks + base="$BASE_SHA" + # A branch's first push reports an all-zero "before", and a force-push + # can report a sha this clone no longer has. Both would otherwise make + # the range unresolvable. + if [ "$base" = "0000000000000000000000000000000000000000" ] \ + || ! git cat-file -e "${base}^{commit}" 2>/dev/null; then + base="${HEAD_SHA}~1" + fi + range="${base}..${HEAD_SHA}" + # gitleaks exits 0 on an empty range — it scans nothing and reports + # success, which is indistinguishable from a clean scan. Verified + # against 8.30.1 before writing this. Count the commits ourselves and + # refuse to call zero a pass. + n=$(git rev-list --count "$range") + echo "gitleaks: scanning $n commit(s) in $range" + if [ "$n" -eq 0 ]; then + echo "::error::empty scan range $range — refusing to report a pass" + exit 1 + fi + ./gitleaks git . --log-opts="$range" --redact --no-banner --exit-code 1 - name: Setup Node.js uses: actions/setup-node@v7