Skip to content

fix(accounts): offer a whole workflow or the step alone as a trusted workflow's example - #616

Merged
alukach merged 3 commits into
mainfrom
fix/github-workflow-example
Oct 2, 2026
Merged

alukach merged 3 commits into
mainfrom
fix/github-workflow-example

Conversation

@alukach

@alukach alukach commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

"Example usage" on a trusted GitHub workflow handed out a fragment of a job: env: and steps: at column zero, with permissions: { id-token: write } left in a comment. It didn't drop into a workflow: at the top level steps is invalid, and pasted under jobs: the keys turn into jobs named env and steps, leaving the real job with nothing to run. That's what happened on the first hand-written workflow against staging. It also ignored which subject the trust names, so a trust pinned to an environment got an example whose token would carry the ref instead, and would be refused. Part of #491.

What

The dialog now has a switch between two forms, both naming the proxy once in AWS_ENDPOINT_URL_S3 and reading it back in the sign-in step's with: as ${{ env.AWS_ENDPOINT_URL_S3 }} (for audience, and with /.sts appended for sts-endpoint):

  • Full Workflow (shown first): githubWorkflow(proxyOrigin, accountId, subject) returns a complete workflow to save under .github/workflows/. AWS_ENDPOINT_URL_S3 is set in a workflow-level env:, so every step's S3 client reaches the proxy. One job, data, has runs-on, permissions (id-token: write, contents: read), the configure-aws-credentials@v6 sign-in step, and a first aws s3 ls s3://{owner}/ to show the credentials working.
  • Step: githubWorkflowStep(proxyOrigin, accountId, subject) returns the sign-in step alone, for a workflow that already exists, with AWS_ENDPOINT_URL_S3 set in the step's own env:. A step's env reaches only that step, so two comments above it say what the job around it needs: id-token: write (plus the environment, for a trust pinned to one), and AWS_ENDPOINT_URL_S3 on the job for later steps to reach the proxy.

Both forms are built from one shared signInStep. Either way:

  • A trust pinned to an environment puts environment: on the job (JSON-quoted, since an environment name may hold a space). Without it GitHub puts the ref in the token's subject, and the trust doesn't match.
  • A trust pinned to a ref says on the on: workflow_dispatch line which ref to run it from (full workflow only).

ExampleUsage takes code as before, or a map of labelled forms, in which case a SegmentedControl above the code chooses between them and the copy button takes whichever is showing. ServiceAccountDetail passes both forms for each trust, and the intro now reads "In the repository {subject} names, save the full workflow under .github/workflows/, or add the step to a job of your own:".

Stories

On this branch's deploy:

The Sign in from this workflow dialog on Full Workflow: a workflow-level env setting AWS_ENDPOINT_URL_S3 to https://data.source.coop, one data job with id-token write, and a sign-in step whose audience and sts-endpoint read ${{ env.AWS_ENDPOINT_URL_S3 }}

The same dialog on Step: two comments saying the job needs id-token write and AWS_ENDPOINT_URL_S3 for later steps, then the sign-in step with its own env setting AWS_ENDPOINT_URL_S3 and with: reading ${{ env.AWS_ENDPOINT_URL_S3 }}

Testing

  • service-account-usage.test.ts: the workflow sets AWS_ENDPOINT_URL_S3 in a top-level env and has one job holding runs-on, permissions with id-token: write and the sign-in step, nested where GitHub reads them (asserted on the exact indented lines, since nesting is the bug); with: reads ${{ env.AWS_ENDPOINT_URL_S3 }}; a ref trust adds no environment, while an environment trust puts it on the job. The step stands alone with env beside with, and names the environment in its comment when the trust is pinned to one. 6 pass.
  • Once, outside the suite: both forms for an environment named prod west parsed with js-yaml: the workflow's top-level env, the job's environment and the step's with, and the step's own env and with.
  • src/stories.smoke.test.tsx 195 pass; npm run type-check is clean.
  • Checked on the branch deploy: both forms render, and the switch changes the code shown (screenshots above).
  • Not run: either form in a real repository. On staging it still needs feat(sts): answer GetCallerIdentity with multistore 0.8.0 data.source.coop#248 deployed, since configure-aws-credentials checks the credentials with GetCallerIdentity. That with: can read a step's own env comes from GitHub's documented context availability (env is available in jobs.<job_id>.steps.with), not from a run.

Docs and ADRs

Checked ADR-014 (source-cooperative/data.source.coop): the step and the RoleArn it names are unchanged, so it still holds. docs.source.coop: the automated-access guide (source-cooperative/docs.source.coop#37) has its GitHub Actions section marked "coming soon", and should use this file when it's written.

🤖 Generated with Claude Code

… example

The example usage for a trusted GitHub workflow was a fragment of a job, `env:` and `steps:` at column zero with permissions in a comment, so pasting it into a workflow put the keys at the wrong level: at the top level `steps` is invalid, and under `jobs:` they become jobs of their own. It is now a complete workflow to save under .github/workflows/: one job with runs-on, `id-token: write`, the proxy's S3 endpoint, the sign-in step and a first `aws s3 ls`. The example is built from the trust's subject, so a trust pinned to an environment gets `environment:` on the job, without which GitHub puts the ref in the token's subject and the trust doesn't match; a trust pinned to a ref says which ref to run it on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
source-coop-ui Ready Ready Preview Oct 2, 2026 6:31pm UTC
source-cooperative Ready Ready Preview Oct 2, 2026 6:31pm UTC

Request Review

@claude

claude Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @alukach's task in 24s —— View job


✅ No blocking issues — safe to merge.

I read the diff for service-account-usage.ts, ExampleUsage.tsx and ServiceAccountDetail.tsx. I didn't run the tests, and I didn't read the story and test diffs.

  • The generated YAML nests correctly.
  • environment goes through JSON.stringify, so a name containing a space is quoted.
  • The ref and environment subject regexes only ever read the tail of the subject.
  • useState(labels[0]) is safe because each TrustRow owns its own dialog. If one ExampleUsage instance were ever reused with a different set of labels, chosen would go stale.

Simplify (ponytail)

  • service-account-usage.ts, githubWorkflow and githubWorkflowStep: both repeat subject.match(/:environment:(.+)$/)?.[1]. Move it into a one-line environmentOf(subject) helper.
  • ExampleUsage.tsx: the string | Record<string, string> union adds a branch (typeof forms === "string") that ServiceAccountDetail no longer exercises, and the API-key path is the only other caller. If that caller can pass { Key: code } or the single-string path stays, keep it. Otherwise the union is speculative flexibility.

Docs

The description names ADR-014 (still holds, since the step and RoleArn are unchanged) and points at docs.source.coop#37, which is still "coming soon". That satisfies the docs requirement.


💰 Estimated review cost: $0.13 · 0m23s · 5 turns

…workflow and the step

The example usage for a trusted GitHub workflow now offers both forms behind a segmented control. "Full Workflow" sets AWS_ENDPOINT_URL_S3 once for the whole workflow; "Step" is the configure-aws-credentials step alone, setting AWS_ENDPOINT_URL_S3 on itself, with comments saying what the surrounding job needs. In both, `audience` and `sts-endpoint` read the proxy's address from `${{ env.AWS_ENDPOINT_URL_S3 }}` instead of repeating it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alukach alukach changed the title fix(accounts): hand out a whole workflow file as a trusted workflow's example fix(accounts): offer a whole workflow or the step alone as a trusted workflow's example Oct 2, 2026
…itch

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alukach
alukach merged commit eef4fbd into main Oct 2, 2026
7 checks passed
@alukach
alukach deleted the fix/github-workflow-example branch October 2, 2026 18:40

This branch was successfully deployed

2 active deployments
Preview – source-cooperative — 11857a7a Deployed Oct 2, 2026 by vercel[bot]
Preview – source-coop-ui — 11857a7a Deployed Oct 2, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant