Skip to content

ci: run build-linux on Dependabot PRs without secrets; drop the workflow_run rerun - #482

Draft
leggetter wants to merge 1 commit into
mainfrom
ci/dependabot-build-linux
Draft

leggetter wants to merge 1 commit into
mainfrom
ci/dependabot-build-linux

Conversation

@leggetter

Copy link
Copy Markdown
Collaborator

What

Run build-linux on every pull request, including Dependabot and fork PRs, without needing secrets. Remove the workflow_run rerun of test and the "Dependabot PR Check" workflow that only existed to trigger it.

Why

  • build-linux was skipped on Dependabot PRs. Its job-level if skipped it for dependabot[bot] on pull_request, because it logs in to Docker Hub with secrets that Dependabot runs do not get. build-linux is a required check, and a skipped check counts as passing. Example: run 38388625127 (chore(deps): Bump golang.org/x/sys from 0.48.0 to 0.49.0): unit-test, build-mac and build-windows ran, build-linux was skipped.
  • The rerun built the wrong commit. The workflow_run run that was meant to cover it used actions/checkout@v4 with no ref, so it checked out the default branch's head. Every workflow_run run of test is on main (c117a4d, earlier db4958c). See gh run list --workflow=test --event workflow_run. The Linux build and the GoReleaser Docker snapshot never ran against a dependency bump before it merged.
  • Every PR triggered an extra test run against main. "Dependabot PR Check" runs on every pull_request and completes even when its job is skipped, so workflow_run fired for every PR. The result attaches to main's commit, not the PR. Example: run 39615377466, triggered by the Go 1.26.10 PR, showed main red.

Change

  • build-linux no longer has a job-level if. It runs on every pull_request, push to main and workflow_dispatch, like the other three build jobs.
  • docker login is conditional. A step checks whether DOCKER_USERNAME is set and writes a step output. Docker Login runs only when it is. A step-level if cannot read secrets directly, hence the extra step. When credentials are absent the job logs a ::notice:: and continues.
  • Removed the workflow_run trigger from test.yml.
  • Deleted .github/workflows/dependabot_pr.yml. Nothing else referenced it, and check-dependabot is not a required check in branch protection or the Main ruleset.

Why login is not needed for this build: goreleaser release --snapshot --skip=publish never pushes images. The current build-linux log (run 40877482324) says snapshot build: will not push any images. The only Docker Hub traffic is pulling the public alpine base image in Dockerfile, which anonymous pulls can do.

The required check names (unit-test, build-linux, build-mac, build-windows) are unchanged. release.yml, acceptance.yml and test-acceptance.yml are untouched. release.yml still logs in, because it pushes.

Security considerations

  • Design choice: no privileged run builds PR code. The obvious alternative was to keep workflow_run and check out github.event.workflow_run.head_sha. workflow_run runs in the base repository's context, with its secrets and its default GITHUB_TOKEN permissions. Building PR code there is the classic "pwn request": goreleaser runs go generate ./... and go mod download as before hooks, so a malicious go.mod, generator or dependency would run with DOCKER_PASSWORD and GORELEASER_GITHUB_TOKEN in reach. This PR avoids that rather than gating it.
  • Fork PRs. Fork PRs also trigger "Dependabot PR Check", and so the workflow_run run of test with secrets. Open examples: fix(listen): join the forwarding URL path and the event path with a single slash #478 (fix(listen): join the forwarding URL path and the event path with a single slash) and fix(cmd): reject unsupported --output values #481 (fix(cmd): reject unsupported --output values). Before this PR that run checked out main, so it wasted a run but did not build fork code. Any head_sha checkout would have needed two gates: the triggering actor is dependabot[bot] and github.event.workflow_run.head_repository.full_name == github.repository. After this PR there is no workflow_run path at all. Fork code runs only in pull_request runs, which GitHub gives no secrets and a read-only token.
  • Dependabot PRs now build in their pull_request run: no Actions secrets, read-only GITHUB_TOKEN. GORELEASER_GITHUB_TOKEN resolves to empty there. A snapshot build does not need it: build-mac and build-windows already pass under that condition (run 38388625127).
  • Unchanged: same-repository PRs and pushes to main still log in to Docker Hub before running GoReleaser, as they did before. Those authors already have write access.
  • Residual risk: Docker Hub pull limits for anonymous runs. GitHub's docs say Docker Hub's pull limit does not apply to public images pulled by GitHub-hosted runners. There is an unconfirmed community report from October 2026 of hosted runners hitting it. If anonymous build-linux runs start failing with toomanyrequests, the fix is a pull-through mirror or a read-only Docker Hub token in Dependabot secrets, not reintroducing workflow_run.

Testing

  • actionlint .github/workflows/test.yml: clean. A full-repository actionlint reports only pre-existing findings in files this PR does not touch (acceptance.yml, outpost-live.yml, release.yml, test-npm-install.yml).
  • This PR's own checks: see the PR's checks. build-linux runs here with credentials (same-repository branch), so it exercises the login branch, not the anonymous one.
  • No Go code changed, so no unit or acceptance tests were added. The acceptance suite runs because .github/workflows/** is in its path filter.

Unverified

  • The no-credentials branch of build-linux has not run in CI. It will first run on the next Dependabot PR, or on an approved fork PR. Expected behaviour: test runs once on pull_request, and build-linux runs instead of being skipped. Check for Docker Hub credentials logs the notice, Docker Login is skipped, the base image is pulled anonymously, and the snapshot builds against the PR's merge commit. No workflow_run run of test follows.
  • A local reproduction without login was not run, because the local Docker daemon was not available.
  • Anonymous pulls of alpine succeeding on hosted runners is based on the GoReleaser log, which shows images are only built, and on GitHub's documented exemption. It has not been observed for this job.

🤖 Generated with Claude Code

…run rerun

build-linux was skipped on Dependabot pull_request runs because it logs in
to Docker Hub with secrets those runs do not get. A skipped required check
counts as passing. The workflow_run rerun meant to cover it checked out the
default branch, not the PR, so the Linux build and Docker snapshot never ran
against a dependency bump before merge. It also ran test against main for
every PR, because "Dependabot PR Check" completes even when its job skips.

A --snapshot build never pushes images, so the Docker Hub login only
authenticates the pull of the public alpine base image. Log in when the
credentials exist and pull anonymously when they do not, and run build-linux
on every pull_request. Remove the workflow_run trigger and the "Dependabot
PR Check" workflow, which existed only to drive it.

No run now checks out PR code in a privileged context, so neither a
Dependabot PR nor a fork PR is built with secrets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant