Repository navigation
feat: accept pull request uploads for opted-in namespaces, starting with void - #17
Merged
Merged
Conversation
…ith void A namespace can now opt in to GitHub Actions OIDC tokens from same-repository `pull_request` runs whose PR targets its default branch. The opt-in is off by default and enabled in production only for `void`, whose PR CI wants to show remote cache reuse before merging. An opted-in namespace keeps the audience, repository/owner ID, and public visibility checks, and requires `ref` `refs/pull/<number>/merge`, `ref_type` `branch`, and `base_ref` equal to the registered default branch. `pull_request_target`, `workflow_run`, tags, other base branches, and fork repositories stay denied. The opt-in is a `pull_requests` column on `scopes` (migration 0002), part of the `changed_policy` trigger so withdrawing it stops admitted uploads. It is set by `pnpm operator setup/policy --pull-requests`, by production deployments from the object form of `.github/production-repositories.jsonc`, and kept off in staging so PR runs still check that PR tokens are rejected. This is interim: same-repository PR code, including Renovate branches, can publish entries that default-branch builds restore. #16 tracks scoping PR uploads to the PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remote cache stagingCommit: Cloudflare deployment is disabled. Configure the repository secrets and variables described in the e2e plan, then set |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
voidzero-dev/void#492 caches every task
build:allruns, and its PR CI should show remote cache reuse before it merges. void#492 already makes same-repository PR runs read-write, but the production cache only accepts uploads from default-branchpushjobs, so those PR uploads get403 write_policy. The decision is to let void's same-repository PR CI upload to its namespace (https://voidzero-remote-cache.voidzero-docs.workers.dev/projects/void) for now. Every other namespace keeps the main-branch-push-only policy.Design
Opt-in per namespace, off by default. Migration
0002_pull_requests.sqladdsscopes.pull_requests(0/1, default 0) and recreates thechanged_policytrigger with that column, so turning the opt-in on or off bumpspolicy_versionand stops uploads admitted under the old policy.Write policy (
src/auth.ts).pushtokens work as before. For an opted-in namespace, apull_requesttoken passes the same audience,repository_id,repository_owner_id, andrepository_visibility: publicchecks, and also needs:refmatchingrefs/pull/<number>/mergeref_typebranchbase_refequal to the registered default branch's short name (main, notrefs/heads/main)These are the values GitHub signs for a PR's merge-branch run: see the
refdescription ("for pull request events exceptpull_request_targetthat were not merged, it isrefs/pull/<pr_number>/merge"),GITHUB_BASE_REF("for example,main"), the OIDC claim reference, and the decodedpull_requesttoken in github/actions-oidc-debugger ("ref": "refs/pull/27/merge","ref_type": "branch","base_ref": "main").pull_request_target,workflow_run, tags, PRs to other branches, theclosedrun of a merged PR (whoserefis the base branch), and workflows in fork repositories are still denied.Configuration. A
.github/production-repositories.jsoncentry can now be{ "repository": "owner/repo", "pullRequests": true }as well as"owner/repo", which meanspullRequests: false. Onlyvoiduses the object form.pnpm ci:deploy productionsets every namespace's opt-in from the list on each run, the same way it already handlesenabled/writes_enabled. Self-hosters usepnpm operator policy --pull-requests on|off, orsetup --pull-requests onwhen creating a namespace.statusalready prints the full row.Staging keeps
pull_requests = 0, so PR staging runs still check that PR tokens are rejected.Logging. Verified writes now also log
event_nameandhead_ref.base_refalways equals the default branch, and the PR number is already inworkflow_ref.Risk
PR entries share the namespace with default-branch entries. Code from any same-repository PR, including Renovate dependency branches, runs before review and can publish an entry that a later default-branch build restores. That's why the opt-in is off by default and only on for void. The README, self-hosting guide, e2e plan, and RFC describe it as interim and link the long-term fix, #16 (scope pull request uploads to the pull request).
The server can't tell fork PRs from same-repository PRs: fork PR runs carry the base repository's IDs. It relies on GitHub not granting
id-token: writeto fork PR workflows. GitHub only does that when "Send write tokens to workflows from pull requests" is enabled, a setting it offers for private repositories only. The docs state this dependency.After merge
Production changes only after a maintainer runs Actions → Remote cache production on
main. That run applies migration 0002 and enables PR uploads forvoid. Its log should printEnabled pull request uploads for namespace void.🤖 Generated with Claude Code