Skip to content

ci: make schema and build jobs work without repository secrets (#214) - #227

Merged
dkijania merged 2 commits into
mainfrom
ci/secretless-pr-jobs
Sep 2, 2026
Merged

ci: make schema and build jobs work without repository secrets (#214)#227
dkijania merged 2 commits into
mainfrom
ci/secretless-pr-jobs

Conversation

@dkijania

@dkijania dkijania commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

What & why

A pull request from a fork, and one opened by Dependabot, runs with a read-only GITHUB_TOKEN and no repository secrets. Two jobs assume otherwise and fail on every such pull request. This is currently red on #225 (fork, community contribution) and #226 (Dependabot).

1. Check Schema — could not report

##[error]Resource not accessible by integration - .../checks/runs#create-a-check-run

kamilkisiela/graphql-inspector@master reports by creating a check run, which needs checks: write. Adding a permissions: block does not help: GitHub caps the token at read-only for these events whatever the workflow asks for.

The gate is now npx @graphql-inspector/cli@7.0.0 diff 'git:origin/main:schema.graphql' schema.graphql, whose exit code is the job result — no API write, so it works from a fork. Behaviour kept: the expected-breaking-change label still approves a deliberate breaking change. Side benefit: actions/checkout@master and graphql-inspector@master were unpinned; both are now pinned.

2. build-and-deploy — could not authenticate, and could not check out a fork

##[error]google-github-actions/auth failed with: … By default, secrets are not passed
to workflows triggered from forks, including Dependabot.

and, on forks only, one step earlier:

fatal: couldn't find remote ref feat/verification-key-updates

This job authenticates to Google Cloud, writes a registry token, publishes a dev npm package and pushes an image. None of that can or should run for an untrusted pull request — the failure is GitHub's protection working, not a bug to fix by handing over secrets. So the job is now skipped for fork and Dependabot pull requests instead of failing at the auth step, and the checkout resolves the head SHA through actions/checkout rather than git fetch origin <head ref>, which cannot resolve a branch living in a fork.

Coverage for those pull requests is unchanged otherwise: Run-Tests, Linting, unit-tests, smoke-load, npm audit, SBOM and Check Schema all still run. Both required checks (Run-Tests, Linting) are unaffected.

3. Registry credential in the Docker build context — closes #214

.npmrc holds a live GCP access token, and the step that deleted it only ran when needs_version_update == 'true'. docker/build-push-action runs later in the same job with context: ., so on any other build the token was uploaded into the build context. Nothing copies it into a layer today; the hazard is one COPY . . away.

  • rm -f .npmrc split into its own step and made unconditional.
  • .npmrc added to .dockerignore.

The package.json version restore keeps its original condition.

Testing

  • actionlint — clean on both changed workflows.
  • Schema gate, run locally against this repo: unchanged schema → [success] No changes detected, exit 0. With parentHash deleted from BlockInfo✖ Field parentHash was removed from object type BlockInfo / [error] Detected 1 breaking change, exit 1. So the gate still fails the build on a breaking change.
  • .dockerignore, verified with a throwaway image that does COPY . /ctx over a workspace containing a fake .npmrc: with the new line the file is absent from the context (build passes); with the line removed the same build fails — a negative control proving the test is meaningful.

Follow-up, not in this PR

Once this lands, Check Schema can pass from a fork, which unblocks making it a required status check — tracked in #213.

Note on ordering: for pull_request events GitHub runs the workflow files from the merge ref, so #225 and #226 need their runs re-triggered after this merges (both are behind main anyway).

🤖 Generated with Claude Code

https://claude.ai/code/session_012LtdRKTkaKRAuTkEEpgPcc

A pull request from a fork, and one opened by Dependabot, runs with a
read-only GITHUB_TOKEN and no repository secrets. Two jobs assumed
otherwise and failed on every such pull request, most recently on #225
(fork) and #226 (Dependabot).

Check Schema reported through a check run, which needs `checks: write`,
so it ended in "Resource not accessible by integration". A `permissions:`
block cannot fix that — GitHub caps the token for these events whatever
the workflow asks for. The gate is now `@graphql-inspector/cli diff`,
whose exit code is the job result, so it needs no write access. The
expected-breaking-change label keeps working as the approval escape
hatch, and the unpinned `@master` action references are gone.

build-and-deploy authenticates to Google Cloud, publishes a dev npm
package and pushes an image, none of which can work without secrets. It
is now skipped for fork and Dependabot pull requests rather than left to
fail at the auth step. Its checkout no longer runs
`git fetch origin <head ref>`, which could not resolve a branch that
lives in a fork; actions/checkout resolves the head SHA directly.

Also removes the registry credential from the workspace unconditionally
(#214). `docker/build-push-action` runs later in the same job with
`context: .`, so a live token must not survive on disk because the
version-bump branch was not taken, and `.npmrc` is added to
`.dockerignore` so a future `COPY . .` cannot bake it into a layer.

Closes #214.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012LtdRKTkaKRAuTkEEpgPcc

@SanabriaRusso SanabriaRusso left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. This closes two of the repo-level findings from the round-4 review (§4.1 Check Schema blind to fork/Dependabot PRs, and #214 registry token in the Docker build context) with no change to the API surface, so nothing for mina-explorer / mina-explorer-api to adapt to.

What I verified

Schema gate (graphql-inspector.yaml)

  • The new gate ran on this PR's own merge ref (job 100292004125) and reported [success] No changes detected — so the npx path, the git fetch of origin/main, and the git: loader all work under the read-only token. The PR itself doesn't touch schema.graphql, so that only exercises the passing path.
  • Ran @graphql-inspector/cli@7.0.0 diff 'git:origin/main:schema.graphql' <file> locally against three variants of the current schema:
    • unchanged → [success] No changes detected, exit 0
    • parentHash removed from Block and BlockInfo[error] Detected 2 breaking changes, exit 1
    • new optional field added → ✔ Field … was added, [success] No breaking changes detected, exit 0
      The gate fails only on breaking changes, which matches the previous action's fail-on-breaking default; additive changes (the shape #225 uses) still pass.
  • permissions: contents: read is explicit; no ${{ }} interpolation of PR-controlled data into run: (the label check goes through env), and the expected-breaking-change label can only be applied by someone with triage rights, so a fork author cannot self-approve a breaking change.

Build job (build.yaml)

  • Triggers are pull_request and push: tags: v*. The new if: leaves tag builds untouched, keeps same-repo PR builds (this PR's build-and-deploy ran and passed, 5m42s), and skips only fork/Dependabot PRs where the job could never have succeeded.
  • ref: head.sha for PRs builds the same commit the old git fetch origin <ref> && git checkout <sha> step did; for tag pushes it resolves to github.sha, identical to before.
  • rm -f .npmrc is now its own if: always() step, so the GAR token is removed before docker/build-push-action on every path — including release builds, where needs_version_update == 'false' previously left it in the context. .dockerignore now excludes it as defence in depth. The Dockerfile never copies .npmrc and npm ci uses the public registry, so this cannot break the image build. No .npmrc is committed.

Non-blocking

  • npx @graphql-inspector/cli@7.0.0 pins the CLI but resolves its ^ transitive deps fresh each run. Same class of exposure as the old @master action (strictly better, since the top-level is pinned now); a follow-up could vendor it into devDependencies so the lockfile covers it.
  • Branch is behind main (no conflicts). After merge, #225 and #226 need their runs re-triggered as the description says, and #213 (make Check Schema required) is now actually achievable.

@dkijania
dkijania merged commit a81a9ec into main Sep 2, 2026
7 checks passed
@dkijania
dkijania deleted the ci/secretless-pr-jobs branch September 2, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CI leaves a live GCP registry token in .npmrc inside the Docker build context on non-version-bump builds

2 participants