Skip to content

ci(repo): add the cli-artifacts S3 bucket and publisher role stack - #6690

Merged
avallete merged 5 commits into
developfrom
avallete/vigilant-fermi-d4khh7
Sep 22, 2026
Merged

avallete merged 5 commits into
developfrom
avallete/vigilant-fermi-d4khh7

Conversation

@avallete

@avallete avallete commented Sep 21, 2026 •

Copy link
Copy Markdown
Member

Summary

Infrastructure for the public-read S3 mirror of slim native artifacts, in the dedicated cli-artifacts-prod AWS account (created in supabase/aws-org-root). The CLI will fall back to this host where registry blob CDNs and GitHub release assets are blocked, for example in agent sandboxes that allow *.amazonaws.com. This PR is infrastructure only; the upload job in the mirror workflow and the CLI-side candidate follow in separate PRs.

infra/cli-artifacts/template.yaml (CloudFormation):

  • Bucket supabase-cli-artifacts: anonymous GetObject through the bucket policy, TLS required, no ListBucket, ACL-based public access blocked, SSE-S3, versioning with 30-day noncurrent expiry and abort of stale multipart uploads. Retained on stack delete or replace.
  • Role slim-artifacts-publisher: trusts the account's GitHub OIDC provider for exactly repo:supabase/cli:ref:refs/heads/develop and can do nothing but s3:PutObject and s3:AbortMultipartUpload on the bucket's objects.

.github/workflows/cli-artifacts-infra.yml: runs cfn-lint on pull requests that touch this directory or the workflow, and deploys the stack on pushes to develop with the account's github-deploy role, passing the bucket name and trusted subject explicitly. Pull requests never touch AWS, because only develop can assume that role. The deploy job is skipped until the CLI_ARTIFACTS_AWS_ACCOUNT_ID repository variable exists, clears a stack left in ROLLBACK_COMPLETE by a failed first create, and prints failed stack events on error. The workflow file is placed under CLI maintainer ownership in CODEOWNERS.

Object layout, kept identical to the GitHub release asset names so checksum files match without rewriting:

https://supabase-cli-artifacts.s3.us-east-1.amazonaws.com/<service>/<version>/<service>-<version>-<target>.tar.zst
https://supabase-cli-artifacts.s3.us-east-1.amazonaws.com/<service>/<version>/<service>-<version>-<target>.manifest.json
https://supabase-cli-artifacts.s3.us-east-1.amazonaws.com/<service>/<version>/<service>-<version>-<target>.SHA256SUMS

Linked issue

Tracked in Linear (CLI-2451); no GitHub issue.

  • The linked issue is open and carries the open-for-contribution label (or I'm a Supabase maintainer).

Checklist

  • The PR title follows Conventional Commits (e.g. fix(cli): …).
  • Tests added or updated for the change. Not applicable: CloudFormation template and workflow only; the template is linted by cfn-lint in the new workflow.
  • From the repository root, pnpm check:all passes; relevant package tests pass for every touched workspace, and pnpm types:check passes for each touched TypeScript workspace (or workspace declaring it). No TypeScript workspace is touched.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PeXSyQtKtGuwrdNW7uVKom

CloudFormation stack for the cli-artifacts-prod account: a public-read
bucket for slim native artifacts (anonymous GetObject only, TLS required,
no listing, versioning with 30-day noncurrent expiry) and a
slim-artifacts-publisher role trusted for develop with s3:PutObject on
that bucket's objects and nothing else.

The workflow lints the template on pull requests and deploys it from
develop with the account's github-deploy role; the deploy job is skipped
until CLI_ARTIFACTS_AWS_ACCOUNT_ID is set.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PeXSyQtKtGuwrdNW7uVKom
@avallete
avallete requested a review from a team as a code owner September 21, 2026 15:58
@avallete avallete changed the title ci: add CloudFormation stack for CLI artifacts S3 mirror ci(repo): add the cli-artifacts S3 bucket and publisher role stack Sep 21, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 AI Review

Both independent reviews completed. Their 11 reports merge into 10 unique findings, all confirmed after reading the cited code; the dotted-bucket finding was raised by both reviewers. No critical or major issues were found.

Findings

Severity Location Category Sources Claim
🟡 MINOR .github/workflows/cli-artifacts-infra.yml:69 infrastructure claude The deployment automation cannot apply a changed TrustedSubject value to an existing stack because it supplies no parameter overrides.
🟡 MINOR infra/cli-artifacts/template.yaml:86 security claude TrustedSubject is unrestricted and evaluated with wildcard-aware StringLike even though the documented value is intended to identify one exact branch.
🟡 MINOR infra/cli-artifacts/template.yaml:18 infrastructure claude The artifact bucket lacks retention policies, so stack deletion or bucket replacement can fail when published objects remain.
🟡 MINOR infra/cli-artifacts/template.yaml:88 infrastructure claude The publisher cannot abort failed multipart uploads because its object policy grants only s3:PutObject.
🟡 MINOR .github/workflows/cli-artifacts-infra.yml:23 ci claude All pull-request lint runs and deployments share one concurrency group, allowing a newly queued run to cancel another pull request's pending check.
🟡 MINOR infra/cli-artifacts/template.yaml:54 cost claude The stack exposes every object directly for anonymous S3 downloads without adding monitoring or mitigation for attacker-driven request and egress costs.
🟡 MINOR infra/cli-artifacts/template.yaml:11 input-validation claude+codex BucketName accepts dotted names that are incompatible with the template's virtual-hosted HTTPS URL and also accepts some S3-invalid dot/hyphen combinations.
🟡 MINOR .github/CODEOWNERS:6 security claude The new account-admin deployment workflow remains ownerless under CODEOWNERS and therefore is not specifically gated on CLI-team review.
⚪ NIT .github/workflows/cli-artifacts-infra.yml:75 ci claude The Show stack outputs multiline shell block omits the explicit strict-mode declaration used by the workflow's other multiline shell blocks.
⚪ NIT infra/cli-artifacts/README.md:31 documentation claude The README incorrectly says linting runs on every pull request even though the workflow is path-filtered.

Findings outside the diff

  • 🟡 MINOR .github/CODEOWNERS:6 — The new account-admin deployment workflow remains ownerless under CODEOWNERS and therefore is not specifically gated on CLI-team review.

Stats

Claude findings: 10 · Codex findings: 1 · Confirmed: 10 · Refuted: 0 · Uncertain: 0


Models: claude-opus-5 + gpt-5.6-sol · Trigger: auto · Workflow run

This review runs once per PR. A maintainer can request another with a /ai-review comment.

Comment thread .github/workflows/cli-artifacts-infra.yml Outdated
Comment thread infra/cli-artifacts/template.yaml Outdated
Comment thread infra/cli-artifacts/template.yaml
Comment thread infra/cli-artifacts/template.yaml
Comment thread .github/workflows/cli-artifacts-infra.yml Outdated
Comment thread infra/cli-artifacts/template.yaml
Comment thread infra/cli-artifacts/template.yaml Outdated
Comment thread .github/workflows/cli-artifacts-infra.yml
Comment thread infra/cli-artifacts/README.md Outdated
avallete and others added 2 commits September 21, 2026 16:09
Use the partition pseudo-parameter in the publisher role trust principal,
delete a stack left in ROLLBACK_COMPLETE by a failed initial create before
deploying (that state cannot be updated and holds no resources), and print
the failed stack events when a deploy fails.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PeXSyQtKtGuwrdNW7uVKom
Match the publisher trust subject exactly and constrain both template
parameters, retain the bucket on stack delete or replace, let the
publisher abort its own failed multipart uploads, pass the parameters
explicitly on every deploy so a change actually reaches the live stack,
scope the workflow concurrency per pull request with a separate serial
group for deploys, and put the deploy workflow under CLI maintainer
ownership.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PeXSyQtKtGuwrdNW7uVKom
Comment thread infra/cli-artifacts/template.yaml
Comment thread infra/cli-artifacts/template.yaml
Comment thread infra/cli-artifacts/template.yaml Outdated
RetainExceptOnCreate keeps the bucket on later stack deletion or
replacement but removes it when the initial create fails, so the retry
after clearing the ROLLBACK_COMPLETE stack does not collide with the
fixed bucket name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PeXSyQtKtGuwrdNW7uVKom
@avallete
avallete added this pull request to the merge queue Sep 22, 2026
Merged via the queue into develop with commit eb90caa Sep 22, 2026
39 checks passed
@avallete
avallete deleted the avallete/vigilant-fermi-d4khh7 branch September 22, 2026 08:31
pull Bot pushed a commit to chizee/cli that referenced this pull request Sep 22, 2026
## Summary

Second step of the public S3 mirror for slim native artifacts (the
bucket and publisher role landed in supabase#6690). This adds an
`upload-natives-s3` job to `mirror-slim-image.yml` so every
slim-services dispatch also copies the native triplets to the bucket,
for sandboxes that allow `*.amazonaws.com` but block registry blob CDNs
and unattached GitHub release assets.

How the job works:

- Runs only on `repository_dispatch`, only while
`CLI_ARTIFACTS_AWS_ACCOUNT_ID` is set, and only after the `mirror` job
succeeded (`success()`), so nothing reaches the public bucket from a
dispatch whose image digest check failed. It is `continue-on-error:
true`, so like the native ECR copy it never affects the image digest the
sender polls; a release whose mirror failed for ECR-side reasons is
covered by the sender's backfill re-dispatch.
- Re-validates the payload, then `fetch-natives` resolves each native
tag on GHCR and requires it to match the dispatched digest (the same
check the ECR copy makes), pulls the triplet by that digest (`regctl
manifest get` + `regctl blob get`), writes the files under their release
asset names, checks the archive against its own `SHA256SUMS`, and checks
the manifest's `service` / `version` / `target` against the dispatch
fields. A target that fails any check, repeats an earlier target, or
ships malformed manifest JSON is dropped with a warning.
- Assumes `slim-artifacts-publisher` (PutObject and AbortMultipartUpload
on the bucket only) with a session name that carries the workflow run
ID, then `upload-natives-s3` copies archive, manifest, and sums in that
order with plain `aws s3 cp` to
`s3://supabase-cli-artifacts/<service>/<version>/`. No `sync`, since the
role cannot list.
- Verifies every uploaded object is anonymously readable and that the
bucket root still returns 403.

Both commands live in `.github/scripts/mirror-slim-image.ts` next to the
existing mirror commands, with the triplet parsing and naming helpers in
`slim-mirror-payload.ts`, so the flow is replayable locally and covered
by the `bun:test` suite.

## Linked issue

Tracked in Linear (CLI-2451); no GitHub issue.

- [x] The linked issue is **open** and carries the
`open-for-contribution` label (or I'm a Supabase maintainer).

## Checklist

- [x] The PR title follows [Conventional
Commits](https://www.conventionalcommits.org/) (e.g. `fix(cli): …`).
- [x] Tests added or updated for the change.
- [x] From the repository root, `pnpm check:all` passes; relevant
package tests pass for every touched workspace, and `pnpm types:check`
passes for each touched TypeScript workspace (or workspace declaring
it).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01PeXSyQtKtGuwrdNW7uVKom

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants