Every outside contributor's PR fails OSS-31

Open2 versionsCI/CD · Hard · Investigate · about 35 min ·Linux

Lab machine

A private Linux machine with the problem already set up. Sessions last up to 60 minutes.
Sasha Lind opened OSS-31 at 16:20task

Kim sent a pull request from a fork; CI fails with 401 from deployctl. Someone suggests pull_request_target "so forks get the token".

Pull requests from forks run untrusted code. If that code runs with the release token, anyone who can open a PR can deploy to production or steal the token.

"pull_request_target runs with secrets and checks out whatever the PR says. That is the token in a stranger's hands." (Priya)

Right now a pull request cannot get green without something in it asking for the deploy token.

Your task

Split the workflow so pull requests, including from forks, run the tests without any secret, and only a push to main can deploy and see RELEASE_TOKEN. Try both events.

On the machine

  • repo/.github/workflows/release.yml
  • bin/ci runs, bin/ci log N
  • bin/ci run pull_request --pr contrib/depot-names --fork, bin/ci run push

Timeline

SpringWaybill's client libraries are opened to partner carriers.
MonKim (a partner carrier) opens a PR from a fork. CI: deployctl 401.
16:20OSS-31: "Can we just use pull_request_target?"

Done when

  1. Pull requests, forks included, run the tests without any secret and cannot read it.
  2. Only a push to main can deploy.

Hints

Hint 1

Check where in the workflow the token is available, and which events reach that place.

Hint 2

Pull requests from forks do not receive secrets. The question is why a pull request needs one at all.

Hint 3

Tests should not need deployment credentials, and deploying should be its own job.

Hint 4

Give the token only to a deploy job that runs for pushes to main.

Show the solution

Keep `on: pull_request` for tests and never switch to `pull_request_target`, which runs fork code with secrets. Read where `RELEASE_TOKEN` is set and which jobs run on pull requests: either the deploy job runs for every event, or tests and deploy share one job and the token is set for the whole workflow. Split it so tests run everywhere without the token, and a separate `deploy` job with `if: github.event_name == 'push' && github.ref == 'refs/heads/main'` gets it in its own `env:`. Set `permissions: contents: read`. Commit to main, then run `bin/ci run pull_request --pr contrib/depot-names --fork` and `bin/ci run push`.