audit-labs/gh-attest
GitHub Audit Evidence Extractor
clone: git clone https://gitbay.org/audit-labs/gh-attest.git
0849131c0bd24eafbcf704c4fd15d33fdebb643e
verified · cmc
author: Christian Cleberg <hello@cleberg.net> · 2026-08-22T19:46:11Z
.github/workflows/ci.yml | 34 ++++++++++--------------- .github/workflows/migration-drift.yml | 47 ----------------------------------- package.json | 3 ++- 3 files changed, 15 insertions(+), 69 deletions(-) @@ -9,7 +9,14 @@ permissions: contents: read jobs: - check: + # Only the mapping check lives here. Cloudflare Workers Builds already runs + # `wrangler types && tsc --noEmit` as its build command, on every branch, so + # duplicating the typecheck bought a second copy of the same signal. + # + # What Workers Builds does not do is compare the control mappings against the + # docs — and that check needs no Cloudflare credentials, which is why it can + # live here and the migration guard cannot. + mappings: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 @@ -17,25 +24,10 @@ jobs: - uses: actions/setup-node@v7 with: node-version: '26' - cache: npm - # --ignore-scripts: no dependency here needs a lifecycle hook, and CI - # should not run arbitrary postinstall code from the tree. - - run: npm ci --ignore-scripts - - # worker-configuration.d.ts is generated, not committed, and tsconfig - # lists it under "types" — so tsc cannot run on a fresh checkout without - # this. Needs no Cloudflare credentials; it reads wrangler.jsonc. - - name: Generate Workers types - run: npm run types - - # The engine is TypeScript on Workers types; a type error is a deploy - # that fails in Cloudflare's build rather than here. - - name: Typecheck - run: npm run typecheck - - # Applies every migration to an in-memory SQLite database and diffs the - # resulting control_mappings against docs/framework-mapping.md. The doc - # is what an auditor reads, so drift there is a lie in every export. + # No install step: check-mappings.mjs has no dependencies. It applies the + # migrations to an in-memory SQLite database using Node's built-in module + # and diffs the resulting control_mappings against + # docs/framework-mapping.md, rationale text included. - name: Control mappings match the docs - run: npm run test:mappings + run: node scripts/check-mappings.mjs deleted file mode 100644 @@ -1,47 +0,0 @@ -name: Migration drift - -# Deploys and migrations are separate actions, so production can run code whose -# schema was never applied — which is exactly what happened with 0008: its code -# shipped, its migration did not, and evidence output was silently wrong until -# someone went looking. Nothing in CI can catch that, because CI has no view of -# the production database. This does. - -on: - schedule: - - cron: '0 9 * * *' - workflow_dispatch: - -permissions: - contents: read - -jobs: - drift: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - - uses: actions/setup-node@v7 - with: - node-version: '26' - cache: npm - - # --ignore-scripts: no dependency here needs a lifecycle hook, and CI - # should not run arbitrary postinstall code from the tree. - - run: npm ci --ignore-scripts - - - name: Every migration in migrations/ is applied to production - env: - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - run: | - if [ -z "$CLOUDFLARE_API_TOKEN" ]; then - echo "::error::CLOUDFLARE_API_TOKEN is not set — this check cannot see production." - exit 1 - fi - out=$(./node_modules/.bin/wrangler d1 migrations list DB --remote 2>&1) || true - echo "$out" - if echo "$out" | grep -q "No migrations to apply"; then - echo "Production schema matches migrations/." - else - echo "::error::Production is missing migrations listed above. Run 'npm run db:migrate:remote'." - exit 1 - fi @@ -10,7 +10,8 @@ "typecheck": "tsc --noEmit", "test:mappings": "node scripts/check-mappings.mjs", "db:migrate:local": "wrangler d1 migrations apply DB --local", - "db:migrate:remote": "wrangler d1 migrations apply DB --remote" + "db:migrate:remote": "wrangler d1 migrations apply DB --remote", + "check:migrations": "wrangler d1 migrations list DB --remote | grep -q 'No migrations to apply' || { echo 'Pending D1 migrations. Run: npm run db:migrate:remote' >&2; exit 1; }" }, "devDependencies": { "@types/node": "^26.2.0",