Org-level reusable workflows for the rrmadmin ecosystem.
Reusable workflow that builds an Astro site, runs the site-ssot prebuild
(if enabled), and deploys to Cloudflare Pages via wrangler.
Why it exists: CF Pages projects can be silently converted to "Direct
Upload" mode whenever wrangler pages deploy is run against them (one-way
conversion per CF docs / API error 8000069). Once converted, the native
GitHub App auto-deploy webhook stops firing and cannot be reconnected
without recreating the project (which destroys the *.pages.dev URL,
env vars, deploy history, and bindings).
This workflow replaces the broken native integration with a CI-driven
push-to-deploy pattern. Same UX (git push origin main → site updates),
runs on GitHub Actions instead of CF Pages' build infra.
Side benefit: ecosystem-wide consistency. Every Astro site in the ecosystem references the same workflow → updates to the build pipeline (new prebuild step, new validator, etc.) propagate to all sites automatically on next push. No need to update 50 workflow files when the build process changes.
In a consumer repo, add .github/workflows/deploy.yml:
name: Deploy
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
uses: rrmadmin/.github/.github/workflows/astro-cf-deploy.yml@main
with:
project-name: my-project-name # CF Pages project name (slug)
cloudflare-account-id: 88e9cb57... # CF account ID that owns the Pages project
secrets:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
RRM_ADMIN_APP_ID: ${{ secrets.RRM_ADMIN_APP_ID }}
RRM_ADMIN_APP_PRIVATE_KEY: ${{ secrets.RRM_ADMIN_APP_PRIVATE_KEY }}That's it. ~10 lines of YAML per site instead of ~80.
| Input | Required | Default | What |
|---|---|---|---|
project-name |
yes | — | CF Pages project slug (e.g., neofertility-ie) |
branch |
no | main |
Branch passed to wrangler pages deploy --branch |
ssot-enabled |
no | true |
Run the site-ssot prebuild + check out rrm-tools + ecosystem-identity. Set false for sites that don't use site-ssot. |
build-staging-block |
no | "1" |
ASTRO_STAGING_BLOCK env passed to build (1 = staging robots/headers, 0 = production). |
node-version |
no | "22" |
Node version for the runner. |
rrmadmin is a User account, so org-level secret inheritance is not available. Each consumer site sets these at the repo level:
Secrets:
CLOUDFLARE_API_TOKEN— CF API token with Pages: Edit scope on the ecosystem account(s).RRM_ADMIN_APP_ID/RRM_ADMIN_APP_PRIVATE_KEY: credentials for the RRM Admin Automation GitHub App. The workflow mints a short-lived installation token from these (scoped torrmadmin/rrm-tools+rrmadmin/ecosystem-identity) for the runtime cross-repo checkouts. Replaced the manually-rotatedGH_TOOLS_PATin the 2026-05-21 App migration. The App is installed org-wide, so the same two secrets work on every consumer site (or forward them withsecrets: inherit).
Vars:
CLOUDFLARE_ACCOUNT_ID— the CF account that owns the consumer's Pages project.
Onboarding a new site: ~30 seconds of gh secret set / gh variable set per consumer.
- Checkout caller repo (the Astro site).
- Checkout
rrmadmin/rrm-tools(only ifssot-enabled— containssite-ssot,standards-gate, etc.). - Checkout
rrmadmin/ecosystem-identity(only ifssot-enabled— containspeople.json,organizations.json,credentials.jsonregistry). - Stage ecosystem layout — symlink the two checkouts to the paths that local builds expect (
~/iCode/tools/...and~/iCode/config/ecosystem-identity/), so scripts that hardcode those paths Just Work in CI. - Install npm deps for the caller and for
site-ssot. npm run build(withASTRO_STAGING_BLOCKandSITE_SSOT_ENABLEDenv vars set per inputs).wrangler pages deploythe resultingdist/.
- Confirm the Astro site builds locally with
npm run build. - Confirm a CF Pages project exists for the site (project-name slug).
- Add
.github/workflows/deploy.yml(snippet above). - Push to
main. Watch Actions tab for the run.
- Sites that don't use
site-ssot(yet) should passssot-enabled: falseto skip the rrm-tools / ecosystem-identity checkouts. - The PAT auth pattern is a 2026 short-term choice; graduating to a GitHub App token (short-lived, no rotation) is on the roadmap once the surface area justifies it.
- Concurrency is grouped per
project-name + branch, so two simultaneous pushes to the same branch don't race; queued, not cancelled.