Skip to content

fix(ci): add trusted self-mutation reusable workflow (1/2) - #866

Open
darccio wants to merge 1 commit into
mainfrom
dario.castane/infallible-tharp-ba69a7
Open

fix(ci): add trusted self-mutation reusable workflow (1/2)#866
darccio wants to merge 1 commit into
mainfrom
dario.castane/infallible-tharp-ba69a7

Conversation

@darccio

@darccio darccio commented Aug 3, 2026

Copy link
Copy Markdown
Member

Step 1 of 2 to fix the self-mutation token exchange, which has been failing on every PR since #846.

The bug

#846 constrained the trust policy to job_workflow_ref: ...validate.yml@refs/heads/main. That constraint is unsatisfiable. For pull_request events GitHub runs workflows from the PR merge ref, so the claim is always validate.yml@refs/pull/<N>/merge — as seen in a real failing run:

"job_workflow_ref": "DataDog/orchestrion/.github/workflows/validate.yml@refs/pull/865/merge",

So the policy has never matched, dd-octo-sts returns permission denied, and self-mutation has been silently dead for ~5 weeks.

Why not just relax the policy to accept merge refs

That was this PR's first attempt, and Codex correctly flagged it: matching any refs/pull/<N>/merge reintroduces exactly what #846 set out to prevent, since a PR can rewrite validate.yml's steps and mint the repo-wide contents: write token from its own code.

Corrections to that review

Codex's finding was right in substance, but two details in it don't hold up and are worth recording so they don't get relitigated later:

  1. "An approved fork PR" can't actually reach this. Fork PRs are capped at id-token: read on public repos, and the org setting that would send write tokens to PR workflows applies only to private repos — so a fork cannot mint this token under any circumstance. The real exposure is the same-repository PR path Codex also named (anyone with push access rewriting validate.yml on their own branch), which is what actually drove this fix.
  2. Its suggested remediation ("a reusable workflow pinned to main") has an unstated trap. A reusable workflow called by a relative path (./.github/workflows/self-mutation.yml) resolves against the caller's commit, not main — so if validate.yml referenced it that way, job_workflow_ref would still be the untrusted merge ref, silently defeating the fix. Only the fully-qualified DataDog/orchestrion/.github/workflows/self-mutation.yml@main form anchors it correctly. This is called out in the new file's comments so it doesn't get "simplified" away in a future edit.

The fix

Move the token minting into this reusable workflow, which validate.yml will call pinned at @main. Because job_workflow_ref resolves to the called reusable workflow, the claim becomes self-mutation.yml@refs/heads/main — a ref no PR can influence. That satisfies #846's intent and makes the feature work again.

  • The call must use the full DataDog/orchestrion/...@main form (see correction Wrap http handler and handler func #2 above).
  • The workflow takes no inputs — the push target is derived from the pull_request event context so an untrusted caller can't redirect it. The same-repo/maintainer_can_modify guard also moved in here, so it now lives in trusted code.

Why this is split into two PRs

GitHub resolves uses: ...@main when it creates a run, not when the job executes. Adding the reference in the same PR that adds the file makes the entire workflow fail to load — verified empirically on this branch (run 30830039834: zero jobs, instant failure, run named by file path because name: Tests couldn't even be parsed). So this file must reach main first.

This PR is inert: on: workflow_call with no callers, so it changes no behaviour and can't break anything. The validate.yml wiring + policy update are stacked on top in 2/2 and will merge once this lands on main.

Test plan

  • actionlint clean
  • YAML parses (same check as fix: narrow validate STS policy #846)
  • After 2/2 lands, confirm a PR with a generator diff mints the token and pushes (no permission denied)

@darccio
darccio requested a review from a team as a code owner August 3, 2026 15:28
@darccio

darccio commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dcd25e4bc6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/chainguard/self.github.validate.self-mutation.sts.yaml Outdated
darccio added a commit that referenced this pull request Aug 3, 2026
Addresses the Codex review on #866: matching the PR merge ref would let a
pull request rewrite the token-minting steps, which is exactly what #846
set out to prevent.

Instead of broadening the trust policy to untrusted merge refs, move the
token minting and push into a new .github/workflows/self-mutation.yml
reusable workflow, called from validate.yml pinned at @main. Because the
OIDC job_workflow_ref claim resolves to the *called* reusable workflow,
it now reads self-mutation.yml@refs/heads/main -- a ref no pull request
can influence -- so the policy can assert it while the feature actually
works again.

Notes:
- The call MUST use the full DataDog/orchestrion/... @main form. A
  relative ./.github/workflows/self-mutation.yml reference resolves to
  the caller's commit (the untrusted merge ref) and would defeat this.
- The reusable workflow takes no inputs; the push target is derived from
  the pull_request event context so an untrusted caller cannot redirect
  it. The same-repo/maintainer_can_modify guard also moved into it, so
  it lives in trusted code.
- ratchet:exclude and an allowlist entry are needed because this one
  reference is intentionally a branch ref rather than a SHA.
@darccio
darccio force-pushed the dario.castane/infallible-tharp-ba69a7 branch from 86829b2 to ae88a7d Compare August 3, 2026 16:01
@darccio darccio changed the title fix(ci): correct job_workflow_ref pattern in self-mutation STS policy ci: add trusted self-mutation reusable workflow (1/2) Aug 3, 2026
@darccio darccio changed the title ci: add trusted self-mutation reusable workflow (1/2) fix(ci): add trusted self-mutation reusable workflow (1/2) Aug 3, 2026
Groundwork for fixing the self-mutation token exchange, which has been
failing since #846.

#846 constrained the dd-octo-sts policy to
validate.yml@refs/heads/main. That constraint is unsatisfiable: for
pull_request events GitHub runs workflows from the PR merge ref, so the
job_workflow_ref claim is always validate.yml@refs/pull/<N>/merge. The
policy has therefore never matched and self-mutation has been dead.

Simply relaxing the policy to accept merge refs would reintroduce what
#846 set out to prevent, since a pull request can rewrite validate.yml
and mint the contents: write token from its own code. Instead, the token
minting moves here, into a workflow that validate.yml will call pinned at
@main. job_workflow_ref resolves to the *called* reusable workflow, so
the claim becomes self-mutation.yml@refs/heads/main -- a ref no pull
request can influence.

This commit only adds the workflow; nothing calls it yet. GitHub resolves
uses: ...@main when it creates a run, so this file must be on main before
validate.yml can reference it (otherwise the whole run fails to load).
The wiring and policy update follow once this has landed.
@darccio
darccio force-pushed the dario.castane/infallible-tharp-ba69a7 branch from ae88a7d to fb37000 Compare August 3, 2026 16:03
@darccio darccio added the AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos label Aug 3, 2026
@datadog-datadog-prod-us1-2

Copy link
Copy Markdown

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 74.81%

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: fb37000 | Docs | Datadog PR Page | Give us feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos conventional-commit/fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant