0010. Temporary GHCR CD: local dev, main publishes only
- Status: accepted (temporary; prod-off clause superseded by 0012)
- Date: 2026-10-08
- Issue: #10
Context
Issue 10 and the architecture doc said merges to main publish ghcr.io/pixelbar/pixel:<sha> and deploy to dev, with prod later behind a GitHub Environment approval. CI already built the image with push: false.
dev apply (#9) is blocked: Azure Container Apps cannot pull ghcr.io/pixelbar/pixel:main (GHCR 401 / DENIED). The image holds no secrets (Dockerfile copies content/ only; .env and access lists are dockerignored).
A first pass had pull requests deploy to Azure dev. That fights local testing: one replica, and CI’s merge SHA is not the working tree you are iterating on. Thomas asked for local builds on dev and prod = latest main. Prod is not ready (#12, prod secrets), so auto-deploying main to prod was gated off: the workflow must not log in to Azure or touch pixel-prod.
Decision
- Azure
dev:just deploy-devon a laptop (the Mini). It builds this tree, pushesghcr.io/pixelbar/pixel:<sha>(or adev-dirty-*tag if the tree is dirty) plus moving:dev, and runsaz containerapp updateonpixel-devonly. Max replicas stay 1. It never deploys prod and does not start Pixel locally. After the app rolls, it runsjust register devagainst the Pixel Dev guild from.env.dev(or.env), then a Sentry release (local recipe still skips if org/token are unset; a Sentry failure still fails the recipe). CI does not roll PRs ontodev. - Merges to
main:.github/workflows/cd.ymlpushes the SHA and moving tagmain, then creates a Sentry release with source maps when org/token are set. Prod CD is off until #12: the workflow does not use GitHub Environmentprod, does not Azure-login, and has no path topixel-prod. Fail closed — do not copypixel-dev-kvor the Mini local/Pixel Dev Discord token into prod. - GHCR auth (CI):
docker/login-actionwithGITHUB_TOKEN. Only the publish job haspackages: write. Local:just docker-login-ghcrusesgh auth token(needswrite:packages). The package is public so Container Apps can pull without a PAT in Terraform. The running app pins an explicit SHA (or dirty tag), notlatest. - Azure auth: local
azfordev. Prod OIDC (ARM_*on GitHub Environmentprod) stays unused until prod CD is turned back on with #12. - No Terraform apply from CD or
just deploy-dev. First create ofpixel-devstays #9. After that, Terraform ignores the dev Pixel container image sojust tf-apply devcannot silently replace the SHAjust deploy-devpinned (#73).container_imageis the first-create value on dev only. Prod (#12) apply will setcontainer_image(noignore_changeson that resource). Stop-then-start overlap is still #11. - Sentry: release name is
PIXEL_VERSION(the image SHA). Source maps upload fromdist/with URL prefix/app/dist. The CD job fails closed ifSENTRY_AUTH_TOKEN,SENTRY_ORG, orSENTRY_PROJECTis missing. just register dev: part ofjust deploy-dev(Pixel Dev.env.dev/.env). Production isjust register prodwith.env.prod. Not frommainCD (that would need the prod Discord token, which must not be the Mini/dev token).
This overrides main → dev and the short-lived main → prod deploy until we revert this ADR.
Consequences
- You can put a local (even dirty) tree on
devwithout waiting for another CI head. Do not also runjust devon the same Pixel Dev token whilepixel-devis up. - Merging to
mainpublishes an image and does not start Discord on prod. Prod stays dark until #12. - Two replicas still answer every command twice. Both paths pin min=max=1.
just tf-apply devafter a local roll leaves the running SHA alone. Bumpingcontainer_imagein gitignored tfvars does not change the live dev app.- Revert path: point
mainatdevagain, or restore prod deploy behind Environmentprodapproval once #12 exists. Prod Terraform/CD should setcontainer_image; do not copy the devignore_changesonto that app.