Fork pull_request runs get no secrets and no OIDC token, so every job that
assumes the CI test role fails at "Configure AWS credentials". copy-pr-bot
already pushes each vetted pull request to pull-request/<number>, and pushes
there get credentials.
Testing, Databricks, Snowflake, GCS and Kumo Installation now also run on
those pushes. A new _credentials-gate.yml job looks up the pull request: a
same-repo pull request already ran these jobs on pull_request, so its copy
skips them, and a fork's copy runs them. The gate also returns the pull
request's merge base, which each change filter diffs against, so the copy
tests the pull request's changes. Only pushes to main run the full suite.
Testing's jobs that need no credentials skip on these pushes, since they
already ran on pull_request.
Co-Authored-By: Claude <noreply@anthropic.com>
Summary
This PR gives pull requests from forks the CI jobs that need cloud credentials. It reuses copy-pr-bot's existing
pull-request/<number>branches: once a vetter approves a fork's commit, the Testing, Databricks, Snowflake, GCS and Kumo Installation workflows run on that copy with credentials, and the fork's ownpull_requestrun skips those jobs instead of failing.Problem. A fork pull request (#117, #122, #123) leaves reviewers unable to answer:
Today none of these can be answered. On #123, 52 jobs fail at "Configure AWS credentials" before any test starts, and 40 of them also fail at "Upload coverage artifact".
Cause. These jobs get AWS credentials through GitHub OIDC:
configure-aws-credentialswithrole-to-assume,id-token: writeand a jobenvironment:. Their tests then read test data from S3 and test-account credentials from Secrets Manager. For apull_requestrun from a fork, GitHub passes no repository, organization or environment secrets, makesGITHUB_TOKENread-only, and issues no OIDC token. The fork job's log showsSecret source: Noneand the action's "Did you mean to set theid-tokenpermission?" warning. A same-repo job showsSecret source: Actions. The settings that send secrets or write tokens to fork pull requests exist only for private repositories; this repository is public, so no setting changes this.copy-pr-bot already has the trusted path. A vetter comments
/ok to test <SHA>, the bot pushes that commit topull-request/<number>in this repository, and pushes there run with credentials. Their checks attach to the same commit, so they show on the pull request. Before this PR only Kumo Core GPU and Test backend images listened on those branches:Change.
_credentials-gate.yml(new, reusable). Each of the five workflows calls it as acredentialsjob. Its credentialed jobs need it and run only whenrunis'true':runbasepull_requestfrom this repositorytruepull_requestfrom a forkfalsepull-request/<number>, fork pull requesttruepull-request/<number>, same-repo pull requestfalse(it already ran onpull_request)main,merge_group,workflow_dispatch,workflow_calltrueOn
pull-request/<number>it reads the pull request the way Test backend images does (${GITHUB_REF_NAME#pull-request/}andgh api), plus the compare API for the merge base.Change filters diff against the merge base. Each credentialed job fetches
base(git fetch --depth=1) and passes it totj-actions/changed-filesasbase_sha. A push diff would otherwise compare against the previously synced commit, or the parent commit for a new branch. Withbaseempty on every other event, the filters behave exactly as before.Only pushes to
mainrun the full suite.RUN_FULL_TEST(Testing, Databricks) and Snowflake's minimal/full conditions checkedgithub.event_name == 'push'; they now also checkgithub.ref == 'refs/heads/main', so apull-request/<number>copy runs the minimal suite like itspull_requestrun would.Testing's jobs that need no credentials skip on
pull-request/<number>(diskgraph-rust,diskgraph-clippy,diskgraph-python,pyarrow-range,packages,pql-public): they already ran onpull_request.diskgraph-wheelruns there only whenpytestwill.Check OpenAPI Changes skips on fork pull requests. It is built around the
pull_requestevent (path filter, head checkout, PR comment), so it gets no push path here.Coverage upload runs only when its artifact name was set. After an earlier failure it used to fail a second time with "Input required and not supplied: path".
Back-compat and security
Same-repo pull requests, pushes to
main, merge queues and manual runs keep their jobs and suites; they wait for one short gate job first.pull_requestpull_requestpull-request/<number>, fork/ok to test. Each new commit needs a new approval.pull-request/<number>, same repomainmerge_group,workflow_dispatch, weekly durations (workflow_call)What a vetter now approves. A
pull-request/<number>run uses the workflow files and code at the approved commit, with the CI test role, its Secrets Manager test credentials and the repository secrets. This is the same trust model copy-pr-bot already uses for NVIDIA's GPU runners, now covering credentials too. Before commenting/ok to test, read the whole diff, including.github/,conftest.py, build scripts anduv.lock. Approval is pinned to a SHA, so a later push cannot ride on an earlier approval. No repository or IAM setting changes: the role trusts this repository's environments, whatever the branch.Known limitations
pull-request/<number>run uses the workflows at the pull request's head, so a fork pull request gets the new jobs only after it merges amainthat contains this change.mainaspull_requestdoes (same as Kumo Core GPU).paths-ignore, so a vetted update that only touchesui/**ortools/**gets no new run of these workflows. The earlier results still cover the unchanged code.pull-request/<number>run is not cancelled when a newer commit is approved (concurrency groups unchanged).store-durations-weekly.yml, which callstesting.yml) has failed at startup on every run since at least 10-11. Whoever fixes it must also grant the gate'spull-requests: readin that caller.Testing Done
actionlint1.7.12 with shellcheck on all 7 files: no new findings (the same 22 asmain, all on unchanged lines); the new gate workflow is clean.yamllint -c .yamllint.yml: 0 errors; 54 warnings, the same asmain.end-of-file-fixer,trailing-whitespace,check-yaml,yamllint,license-headers: passed..github/scripts/workflow-security.cjsand its tests: passed, 0 new findings.alan-kumo/kumo-engine(fork,run=true), Run eight candidate-wheel RTX task checks on code PRs #135 to this repository (run=false); both give merge basece6acc69.git fetch --depth=1 origin <base>followed bygit diff --name-only <base>..HEADlists exactly the 94 files the pull request's files API returns.pull_requestjobs, and apull-request/<number>copy that runs only the gate. Add index clocks from nanoseconds to days #123 will be the first fork case, once it mergesmainand a vetter approves it.Checklist
Change map: see the
kumo-pr-change-mapcomment.🤖 Generated with Claude Code