Skip to content

feat(sts): answer GetCallerIdentity with multistore 0.8.0 - #248

Merged
alukach merged 1 commit into
mainfrom
chore/multistore-0.8
Oct 1, 2026
Merged

alukach merged 1 commit into
mainfrom
chore/multistore-0.8

Conversation

@alukach

@alukach alukach commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

What I'm changing

Bumps multistore from 0.7.2 to 0.8.0 (developmentseed/multistore#153), which answers GetCallerIdentity. aws-actions/configure-aws-credentials, the step source.coop's settings page hands out, makes that call after the exchange to check the credentials it exports, so until now the step failed after a successful exchange. The call needs no new routing here: it is answered by the STS handler this Worker already mounts with with_sts("/.sts", …), which in 0.8.0 serves /.sts/ too and verifies SigV4 over the path the client signed, so the existing /.sts/ → /.sts rewrite doesn't break the signature.

What 0.8.0 asked of this repo:

The README's paragraph saying the action fails now says it works.

Decisions to flag

Testing

  • cargo fmt --check, cargo clippy --target wasm32-unknown-unknown -- -D warnings, cargo check --target wasm32-unknown-unknown and cargo test pass locally (the pre-push hook).
  • Not run locally: the Python integration tests and a real configure-aws-credentials run. CI's integration job runs the former on this PR's preview; the latter is the functional test for Trust GitHub Actions alongside the Source issuer #223 once this deploys.

Docs and ADRs

ADR-014 says the proxy answers GetCallerIdentity "once developmentseed/multistore#126 lands"; this PR is that landing and implements the decision, so the ADR still holds. ADR-004 already lists configure-aws-credentials as a supported client. docs.source.coop: the GitHub Actions section of the automated-access guide (source-cooperative/docs.source.coop#37) is waiting on this.

Part of #223: it is done once a workflow in an unrelated repository writes with only its ambient token, against a deployment. Upstream: developmentseed/multistore#126, developmentseed/multistore#146, developmentseed/multistore#153. Epic: source-cooperative/source.coop#491.

🤖 Generated with Claude Code

multistore 0.8.0 answers GetCallerIdentity, which aws-actions/configure-aws-credentials calls after the exchange to check the credentials it exports, so the step source.coop hands out now works. The Role sets the two fields 0.8.0 adds or makes fail closed: subject_conditions ["*"], since an empty list now accepts no subject, and allow_missing_exp_from empty, so every issuer must set exp. mint_temporary_credentials now returns a Result and BucketConfig::backend_type is an enum, parsed from the provider's backend string.

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

claude Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

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


✅ No blocking issues — safe to merge.

I read the diff for Cargo.toml, src/keys.rs, src/source_api/registry.rs, src/sts.rs and the README. I did not build it or run the tests.

  • subject_conditions: ["*"] is needed under 0.8.0, where an empty list accepts no subject. The comment explains why it is safe: person tokens name the person, and platform tokens only act as an account that trusts their subject.
  • allow_missing_exp_from: [] makes exp required for every issuer. This matches the claim that Ory always sets exp and API keys never reach verify_token.
  • backend_type.parse()? in registry.rs:246 uses the string that backend_options() already produces, and the enclosing function returns ProxyError. A bad value now surfaces as an error instead of passing through as a string. registry.rs:258 still uses config.backend_type.as_str().
  • mint_temporary_credentials(...)? in keys.rs:104 propagates the new Result.
  • Leaving feat(sts): let platform IdP tokens act as accounts that trust them #237's redundant exp check in place is fine as a separate change.

Simplify (ponytail)

  • None. The diff is the minimum the upgrade requires.

💰 Estimated review cost: $0.11 · 0m13s · 5 turns

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

🚀 Latest commit deployed to https://source-data-proxy-pr-248.source-coop.workers.dev

  • Date: 2026-10-01T18:36:28Z
  • Commit: 38b6c1f

@alukach
alukach merged commit 0659a7b into main Oct 1, 2026
21 checks passed
@alukach
alukach deleted the chore/multistore-0.8 branch October 1, 2026 18:39
alukach added a commit to source-cooperative/source.coop that referenced this pull request Oct 2, 2026
…workflow's example (#616)

"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:

- `ExampleUsage` › **GithubWorkflow** (opens on Full Workflow):
https://source-coop-ui-git-fix-github-workflow-example-radiantearth.vercel.app/?path=/story/features-service-accounts-exampleusage--github-workflow
- `ExampleUsage` › **GithubWorkflowStep** (new, opens on Step):
https://source-coop-ui-git-fix-github-workflow-example-radiantearth.vercel.app/?path=/story/features-service-accounts-exampleusage--github-workflow-step
- `ExampleUsage` › **GithubWorkflowInAnEnvironment** (new):
https://source-coop-ui-git-fix-github-workflow-example-radiantearth.vercel.app/?path=/story/features-service-accounts-exampleusage--github-workflow-in-an-environment
- `ExampleUsage` › **Mobile**:
https://source-coop-ui-git-fix-github-workflow-example-radiantearth.vercel.app/?path=/story/features-service-accounts-exampleusage--mobile

![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
}}](https://raw.githubusercontent.com/source-cooperative/source.coop/assets/github-workflow-example/example-usage-full-workflow.jpg)

![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
}}](https://raw.githubusercontent.com/source-cooperative/source.coop/assets/github-workflow-example/example-usage-step.jpg)

## 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
source-cooperative/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](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
preview — 78c0090d Deployed Oct 1, 2026 by alukach via Deploy & Test / Deploy #409
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