Add an S3 publish action - #2
Merged
Merged
Conversation
Uploads built assets to an S3 bucket and invalidates the matching CloudFront paths, authenticating with OIDC so no long-lived AWS keys exist anywhere. Replaces the per-repository publish_to_s3.bash and invalidate_cdn.bash scripts, which needed an uncommitted media.env to exist on someone's machine. The invalidation stays in this action rather than becoming a separate one. It is cleanup after an upload, not a step anyone would run on its own. Two guards, both covering ways the old scripts could do damage quietly: - It refuses to publish an empty or missing source directory. A build that "succeeds" into nothing would otherwise leave the CDN serving stale objects with no signal that anything went wrong. - The invalidation is scoped to the project's own prefix. The previous script invalidated /*, which charged for and discarded every other project's cached objects in the same distribution. Content types are set explicitly per extension rather than left to the AWS CLI's guess, which omits the charset and has changed between CLI versions. publish_to_s3.bash set text/javascript and text/css with charset=utf-8, and the live objects carry those values; replacing it should not quietly change them. It uses `cp`, not `sync --delete`. The CL-web-components prefix holds a fonts/ directory that exists in no repository -- three woff files that page.tmpl and the footer component load. A delete-enabled sync would remove them and nothing would put them back. --acl public-read is kept and the reason recorded: the media bucket is in legacy ObjectWriter mode with no bucket policy, so public read comes entirely from per-object ACLs. Removing the need for it means adding a bucket policy first, verifying the CDN still serves, then setting BucketOwnerEnforced -- in that order, or every project on the distribution goes down. The calling job must declare `permissions: id-token: write`; a composite action cannot. The role's trust policy must name the calling repository's subject claim, which is repo-specific. Both are documented, because both cost time to diagnose from the error message alone. CI tests the argument handling and the guards but holds no AWS credentials. This repository should not have any. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uploads built assets to S3 and invalidates the matching CloudFront paths, authenticating with OIDC so no long-lived AWS keys exist anywhere.
Replaces the per-repository
publish_to_s3.bashandinvalidate_cdn.bashscripts, which needed an uncommittedmedia.envto exist on someone's machine.What it does differently from the scripts it replaces
/*, which charged for and discarded every other project's cached objects in the same distribution.publish_to_s3.bashsettext/javascriptandtext/csswithcharset=utf-8, and the live objects carry those. Replacing it should not quietly change them./returns 404 rather than an index — so there is no parent URL to link. Setpublic-base-urlto turn the file list into links.Things worth knowing before merging
cp, notsync --delete. The CL-web-components prefix holds afonts/directory that exists in no repository — three woff files thatpage.tmpland the footer component load. A delete-enabled sync would remove them and nothing would put them back.--acl public-readis kept, and the reason is in the script: the media bucket is in legacyObjectWritermode with no bucket policy, so public read comes entirely from per-object ACLs. Removing the need for it means adding a bucket policy first, verifying the CDN still serves, then settingBucketOwnerEnforced— in that order, or every project on the distribution goes down.permissions: id-token: write. A composite action cannot.Testing
CI covers the argument handling and both guards. It holds no AWS credentials, and should not — the end-to-end path was exercised from a fork against separate test resources, with
dry_runreporting the same destinations the old script wrote to:Those paths match
publish_to_s3.bashexactly: root bundles to the prefix root, CSS undercss/.Once this merges and
v1moves, I'll re-run that dry run against the released action before the CL-web-components caller is opened.🤖 Generated with Claude Code