Skip to content

feat: publish UI stylesheet to CDN on release (YPE-1733) - #331

Open
bdhyv wants to merge 7 commits into
mainfrom
ype-1733/cdn-css-upload
Open

feat: publish UI stylesheet to CDN on release (YPE-1733)#331
bdhyv wants to merge 7 commits into
mainfrom
ype-1733/cdn-css-upload

Conversation

@bdhyv

@bdhyv bdhyv commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements YPE-1733: when the Release workflow publishes a new @youversion/platform-react-ui version to npm, it now also uploads the package's compiled stylesheet (packages/ui/dist/tailwind.css) to the cdn.youversion.com origin bucket, served at:

https://cdn.youversion.com/platform/1/bible.css

How it works

  • The upload steps in release.yml run only when @youversion/platform-react-ui is among the packages published by changesets (npm publish happens first, per the ticket).
  • The /1 path segment is defined in one obvious placepackages/ui/CDN_CSS_MAJOR_VERSION — and is bumped only for breaking CSS changes. Documented in PUBLISHING.md (new "CDN Stylesheet" section).
  • Uploaded with Cache-Control: public, max-age=300, must-revalidate since this is a mutable object at a stable URL (unlike the hashed immutable CSS the transformers build ships).
  • Feature-flag gated (ship dark): before uploading, the workflow reads feature.platform.sdkCssCdn from the prod Firebase Remote Config server template (parameter feature_platform_sdkCssCdn) and skips the upload unless it is true. The flag is defined in the transformers manifest per Platform conventions — see transformers !599 — with prod: false, so merging this PR does not start CDN publishing by itself; launching (or killing) it is a value flip in the prod Firebase console, no deploy needed.
  • Manual recovery path: if the CDN step fails after npm publish, re-running the job can't retry it (changesets reports nothing newly published on a re-run). Instead, trigger the workflow manually on main: manual runs skip versioning/publishing, check out the tag of the latest published UI release (so the CSS always matches npm even if main advanced), and upload. Dispatches from non-main refs are no-ops (job-level guard).

Authorization (the "delicate part")

No static API keys. This uses Workload Identity Federation, the same pattern as youversion-platform-accounts and youversion-platform-developer-hub:

  • GitHub's OIDC token is exchanged via the existing github-actions-pool in the yvplatform-prod GCP project.
  • Only this repository can impersonate the new dedicated service account platform-sdk-cdn-publisher@yvplatform-prod.iam.gserviceaccount.com (per-repo workloadIdentityUser binding).
  • That service account holds exactly two grants: roles/storage.objectUser on gs://cdn-yv-platform-prod restricted by IAM condition to the platform/ prefix, and roles/cloudconfig.viewer on yvplatform-prod for the feature-flag read. It cannot touch css/, fonts/, spotlights/, or anything else in GCP.

The WIF_PROVIDER / WIF_SERVICE_ACCOUNT repo secrets are already set, and the GCP-side resources are already provisioned, so this works as soon as it merges (dark until the flag flips).

Test plan

  • release.yml passes YAML validation
  • GCP side verified: SA exists, WIF binding scoped to youversion/platform-sdk-react, conditional bucket grant in place (platform/ write 200, css/ write 403), Remote Config server template read 200
  • Merge transformers !599 (flag manifest definition)
  • After merge: release a UI version with the flag off — confirm the CDN step logs the skip notice
  • Flip feature_platform_sdkCssCdn to true in the prod Firebase console (server template), run the workflow manually on main, and confirm https://cdn.youversion.com/platform/1/bible.css serves the latest released build (check last-modified / byte size)

Greptile Summary

The PR adds feature-flagged publication of the UI package’s compiled stylesheet to a stable CDN URL, including a manual recovery path pinned to the npm latest release tag.

  • Uploads tailwind.css after a UI package release using workload identity federation.
  • Adds guarded manual recovery without rerunning package publication.
  • Documents versioning, caching, authorization, feature-flag behavior, and recovery procedures.
  • Adds the required intentional empty changeset and CSS major-version constant.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
.github/workflows/release.yml Adds guarded CDN publication and a manual recovery flow that skips npm publication and builds from the release tag matching npm latest.
PUBLISHING.md Documents the CDN URL contract, major-version policy, feature flag, authentication, caching, and recovery procedure.
.changeset/cdn-css-upload-ci.md Adds the required intentional empty changeset for CI and documentation-only release behavior.
packages/ui/CDN_CSS_MAJOR_VERSION Defines the stable CDN stylesheet major path segment as version 1.

Sequence Diagram

sequenceDiagram
  participant Trigger as Release trigger
  participant Workflow as Release workflow
  participant NPM as npm registry
  participant Git as Git tags
  participant RC as Firebase Remote Config
  participant CDN as GCS CDN origin
  alt Push to main
    Trigger->>Workflow: Run release
    Workflow->>NPM: Publish changed packages
    Workflow->>RC: Read CDN feature flag
    RC-->>Workflow: Enabled or disabled
    opt UI published and flag enabled
      Workflow->>CDN: Upload compiled bible.css
    end
  else Manual recovery on main
    Trigger->>Workflow: workflow_dispatch
    Workflow->>NPM: Resolve UI latest version
    Workflow->>Git: Check out matching release tag
    Workflow->>Workflow: Build stylesheet
    Workflow->>RC: Read CDN feature flag
    opt Flag enabled
      Workflow->>CDN: Upload compiled bible.css
    end
  end
Loading

Reviews (8): Last reviewed commit: "fix: resolve manual recovery tag from th..." | Re-trigger Greptile

@changeset-bot

changeset-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 168a60c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml
Comment thread .github/workflows/release.yml
Comment thread .github/workflows/release.yml
@cameronapak

Copy link
Copy Markdown
Collaborator

@bdhyv feel free to tag me for review when this is ready for review!

Comment thread .github/workflows/release.yml Outdated
bdhyv and others added 7 commits August 14, 2026 09:28
When a new @youversion/platform-react-ui version is published, upload
packages/ui/dist/tailwind.css to the cdn.youversion.com origin bucket so
it is served at https://cdn.youversion.com/platform/<major>/bible.css.

Auth uses Workload Identity Federation (no static keys): only this repo
can impersonate platform-sdk-cdn-publisher@yvplatform-prod, which can
only write under the bucket's platform/ prefix. The <major> path segment
lives in packages/ui/CDN_CSS_MAJOR_VERSION and is bumped only for
breaking CSS changes (documented in PUBLISHING.md).

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Re-running a failed Release job cannot retry the CDN upload because
changesets reports nothing newly published on the re-run. Add a
workflow_dispatch trigger that skips versioning/publishing and always
uploads the freshly built stylesheet (idempotent), and document it as
the recovery path. Addresses Greptile P1 review feedback.

Co-authored-by: Cursor <cursoragent@cursor.com>
workflow_dispatch can be triggered from any ref containing the workflow
file, which would let a branch build overwrite the production
stylesheet. Guard the job to refs/heads/main so non-main dispatches are
no-ops. Addresses Greptile security review feedback.

Co-authored-by: Cursor <cursoragent@cursor.com>
A manual recovery run previously rebuilt current HEAD, which could
contain merged-but-unreleased UI changes and push CSS ahead of the
published npm package. Manual runs now check out the newest
@youversion/platform-react-ui release tag before building, so the
uploaded stylesheet always matches npm. Addresses Greptile review.

Co-authored-by: Cursor <cursoragent@cursor.com>
Per the Platform feature-flag conventions (transformers
docs/feature_flags.md), the CDN upload now reads the
feature.platform.sdkCssCdn flag from the prod Firebase Remote Config
server template and skips the upload unless it is "true". The flag
ships dark (prod: false) and is launched/killed from the Firebase
console without a code change. Flag defined in transformers MR !599.

Co-authored-by: Cursor <cursoragent@cursor.com>
Tag creation dates can lie (recreated tags, prereleases), so manual
recovery runs now ask npm for the latest dist-tag version and check out
the exact matching release tag, failing loudly if it does not exist.
Addresses Greptile review feedback.

Co-authored-by: Cursor <cursoragent@cursor.com>
@bdhyv
bdhyv force-pushed the ype-1733/cdn-css-upload branch from aa9535d to 168a60c Compare August 14, 2026 14:28
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.

3 participants