Skip to content

CI-001B2 — Make releases protected, backend-first, and fail-closed #135

Closed

Description

@daliu

Outcome

Replace the current automatic, frontend-first, fail-open release workflow with a release gate that cannot publish a dependent website before its compatible backend. Remove every server credential from the frontend build job and make missing authority/config an explicit failure.

This ticket changes release behavior and is blocked on an owner choice before source edits:

  1. Recommended: merges run CI only; staging/production releases are manual, protected, exact-commit actions.
  2. Alternative: main automatically deploys to isolated staging, while production remains a protected manual action.

Do not preserve today's “merge automatically publishes production Pages” behavior for backend-dependent changes; it cannot satisfy backend-first approval.

Officer impact: Officers will approve a merge separately from a protected release, and a missing backend credential will be shown as a stopped release rather than a green success.

Officer documentation: Update OFFICER_START_HERE.md, docs/officers/PUBLISH_AND_CHECK.md, docs/officers/ACCESS_CONTINUITY.md, and the exact root release-status docs after the owner selects the release model.

Deployment evidence: None at creation. This ticket changes the gate only; CI-001D performs and proves the staged/live release.

Current verified defect

.github/workflows/deploy.yml currently:

  • runs on every main push;
  • publishes GitHub Pages before the Firebase job;
  • passes FIREBASE_SERVICE_ACCOUNT into the frontend build environment;
  • installs firebase-tools@latest over the network during deployment instead of using the lockfile version;
  • deploys all Functions, Rules, and indexes rather than an approved target set;
  • reports success when FIREBASE_SERVICE_ACCOUNT is missing and Firebase is skipped.

That workflow cannot safely release PR #132/#118.

Atomic source outcome after owner decision

  1. Separate merge/CI from release authorization.
  2. Require an exact merged commit and its required checks before release.
  3. Validate environment, target project, approved deploy scope, and authority before any mutable install, build, or publication.
  4. Use the lockfile-pinned Firebase CLI; do not install latest during release.
  5. Give the frontend build only public browser configuration. Never pass a cloud service credential or write a key file in that job.
  6. Make the backend job complete and verify first; the website job must depend on its success.
  7. Use fixed reviewed deployment targets rather than caller-supplied shell text or a broad all-Functions default.
  8. Make missing/mismatched authority, skipped backend, wrong ref, or partial verification fail the workflow and prevent website publication.
  9. Give jobs minimum GitHub permissions; CI-001C supplies the approved short-lived cloud identity.
  10. Keep staging and production evidence distinct.

Acceptance criteria

  • Dave/board records the selected release model and names production approvers.
  • A normal merge cannot silently publish a backend-dependent production website.
  • No server credential exists in the frontend environment, build files, artifacts, or logs.
  • Backend verification is a hard prerequisite of website publication.
  • Missing authority/config fails before deployment and cannot end in an overall green “skipped” release.
  • Firebase CLI/version comes from the committed lockfile.
  • Deployment targets are fixed, reviewed, and shell-injection safe.
  • A temporary synthetic missing-authority probe fails and publishes nothing, then is removed.
  • Workflow YAML/static checks, CI, and affected officer procedures pass independent review.
  • CI-001C provider configuration and CI-001D actual deployment remain separate.

Stop conditions

Stop if the owner has not chosen the release model, if an implementation needs a cloud key in source/frontend, if it accepts arbitrary deployment targets, or if it can publish the website after a failed/skipped backend. Do not deploy from this ticket.

Claim protocol

Creation is not a claim. After the owner decision, publish the exact allowed files, assign one agent, and post CLAIMED by <canonical agent> at <UTC>; branch <branch> before editing. Coordinate root-document ownership with PR #132/#118; do not overwrite its profile-recovery sections.

Activity

  1. added
    priority:P0Launch blocker or urgent security risk
    type:securitySecurity or privacy boundary
    area:firebaseFirebase services and data
    area:webWeb application and hosting
    area:ciContinuous integration and deployment
    size:MMedium multi-file issue
    on Jul 13, 2026
  2. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    OWNER DECISION / CLAIM at 2026-07-13T08:54:57Z:

    Dave authorized agents to push, merge, and deploy and directed the queue to proceed one issue at a time. The selected release model is the recommended option: normal merges run CI only; staging and production releases are separate manual, exact-commit, protected actions. Production still requires the environment's named human approval and the short-lived authority owned by #133; this authorization does not invent credentials or provider configuration.

    CLAIMED by /root at 2026-07-13T08:54:57Z; branch codex/issue-135-protected-releases.

    Initial exclusive source scope:

    • .github/workflows/deploy.yml
    • OFFICER_START_HERE.md
    • OFFICER_HANDBOOK.md
    • docs/officers/README.md
    • docs/officers/PUBLISH_AND_CHECK.md
    • docs/officers/ACCESS_CONTINUITY.md

    PR #132/#118 retains SECURITY.md, OPERATIONS_RUNBOOK.md, profile/runtime/Rules tests, and its officer profile sections. #134 retains only its declared Sentry files. I will post a scope amendment before touching any additional path. This ticket changes and tests the gate; it will not perform a Firebase or website deployment.

  3. added
    status:in-progressClaimed and actively being implemented
    and removed on Jul 13, 2026
  4. self-assigned this
    on Jul 13, 2026
  5. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    SCOPE AMENDMENT at 2026-07-13T09:02:44Z after read-only release-boundary review:

    The live custom domain is served by Netlify, and its Git connection currently creates production deploys from main. Editing the GitHub workflow alone would therefore leave a second automatic publication path. #135 now also owns the smallest repository-controlled containment: a tested netlify.toml ignore command that stops Git-triggered production builds while leaving deploy previews available for public, read-only review. Netlify build hooks/provider settings and a protected Netlify publication path remain WEB-001/provider work; #135 will not claim that the GitHub release publishes runmprc.com.

    Additional exclusive source/test paths:

    • .github/workflows/ci.yml (one hosted release-gate test step only)
    • netlify.toml
    • scripts/netlify-ignore-build.js
    • tests/release-workflow.test.js

    Additional exact truth/diagram hunks:

    • README.md
    • AGENTS.md
    • IMPLEMENTATION_PLAN.md
    • OPERATIONS_RUNBOOK.md
    • SECURITY.md
    • GITHUB_ISSUES.md
    • GITHUB_ISSUE_SLICES.md
    • docs/officers/REQUEST_A_CHANGE.md
    • docs/officers/EVENTS_SHOP_MEMBERS.md
    • docs/officers/SYSTEM_MAPS.md

    The original six officer paths remain owned. These documentation edits are limited to the #135 release state; they do not claim profile, email, events, monitoring, payment, data, or hosting-cutover behavior.

    PR #132/#118 keeps all runtime/Rules/tests and profile/App Check content. #135 temporarily owns only the release-status paragraphs in SECURITY.md and OPERATIONS_RUNBOOK.md; #118 will refresh after #135 and preserve them. #134 remains limited to its declared Sentry files.

    Invariant: normal GitHub merges run checks only on the GitHub-controlled path, Netlify Git-triggered production builds stop, missing release authority fails red before installs/deploy/build/publication, Firebase is verified before any GitHub Pages publication, and runmprc.com remains separately NOT AVAILABLE for protected publication until WEB-001/provider work is proven.

  6. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    SECOND SCOPE AMENDMENT at 2026-07-13T09:10:36Z after independent workflow threat-model review:

    Additional owned paths:

    • .gitignore — ignore only gha-creds-*.json, as required by the pinned Google auth action
    • .github/scripts/verify-firebase-release.mjs — redacted provider readback for the exact Rules source and both Function revisions
    • tests/firebase-release-verification.test.js — pure fixture tests for positive and stale/mismatched provider state

    The workflow will also be tightened in its already-owned file: current-main only; exact successful ci.yml main-push run/jobs; frontend artifact built before backend mutation; install/source validation before cloud auth; one fixed backend deploy command; always-run post-attempt readback; staging unavailable until an exact approved project is added by reviewed source change; provider identifiers sourced from protected environment secrets rather than visible variables.

    No provider call runs in this issue. The verification script is tested with made-up fixtures only. #133/#136 still own configured authority and actual provider readback/deployment.

  7. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    EXTERNAL STATE at 2026-07-13T09:16:16Z: changed the repository default branch from legacy dev to canonical protected main. This is required for the manual workflow to be discoverable/runnable from its reviewed main definition. No commit, website, Firebase, Netlify, or provider deployment was triggered. The legacy dev branch still exists and was not deleted.

  8. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    DESIGN CLARIFICATION at 2026-07-13T09:24:39Z after the independent trust-boundary review:

    The earlier scope note said missing authority would stop before any build. The safer final order deliberately prepares the public, credential-free website artifact before backend mutation, so a later dependency/build failure cannot leave Firebase changed while the Pages artifact is unavailable. That preparation has read-only source access, no environment binding, no cloud identity, and no publication permission.

    Missing protected configuration still fails before backend dependency installation, cloud authentication, provider access, deployment, or website publication. The prebuilt artifact remains unpublished and expires. This clarifies “mutable build” in the issue as an externally mutable/provider-capable step; it does not weaken the hard acceptance rule that missing authority or failed/partial Firebase verification publishes nothing.

    PR #138 and the officer diagrams now state this exact boundary. No release or provider call was run.

  9. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    THIRD SCOPE AMENDMENT at 2026-07-13T09:38:16Z after exact provider/readback review:

    GitHub Pages currently reports runmprc.com as its custom domain, and the normal GitHub Pages URL redirects to that name, while public DNS serves Netlify. Calling it a separately reachable copy would be false and continuing to publish a CNAME would perpetuate competing ownership.

    Additional owned paths:

    • public/CNAME — remove the future artifact's stale Netlify-domain claim
    • SYSTEM_DESIGN.md — replace the obsolete automatic/green-skip system flow with the exact protected release and current CNAME conflict
    • docs/officers/GLOSSARY.md — correct the one-line Pages definition

    This is source containment only. Merging PR #138 does not publish Pages or change the current provider setting/DNS. #136 plus a protected Netlify child under WEB-001 must publish/read back the Pages branch without the CNAME and separately prove runmprc.com. The new tests statically forbid a Pages CNAME. No provider or website action was run by this amendment.

  10. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    COMPLETED — source gate and negative deployment proof (2026-07-13T09:55Z)

    • PR CI-001B2: protect backend-first releases #138 merged to main as 9eafab1217aff7058c42240aaba72d7b93f8ed24; exact source head 4da12d6f3dea8559a2d30a0453dd1c20c2c758ac had two independent approvals.
    • Exact main-push CI run 29240557552 passed Frontend/build, Functions, and Rules. The merge triggered CI only. It did not automatically start this release workflow.
    • Safe staging probe run 29240643286 failed at the deliberate unavailable-staging guard. Checkout, installs, cloud authentication, Firebase mutation/readback, artifact build, and Pages publication were skipped.
    • Strict synthetic missing-authority probe run 29240751944 used only two temporary non-secret public values. The unpublished website artifact built and passed its credential scan. Backend validation then failed red with Required protected cloud authority is missing.
    • In that strict probe, backend checkout/install, OIDC, provider reads, Firebase deployment/readback, and Pages publication were all skipped.
    • The two temporary repository variables, unpublished artifact 8275321076, and auto-created test environments were deleted. Readback shows zero retained run artifacts, zero repository variables/secrets, and only the pre-existing github-pages environment.
    • The latest GitHub Pages provider build remains the earlier 2026-07-13T08:00Z build at commit 68b823a5f2a42e0490859dc74e5188d89fd5181c; neither the merge nor either probe published Pages.
    • No Firebase, Pages, Netlify production, DNS, Stripe, email, or member-data mutation was performed. Protected provider configuration remains CI-001C — Configure protected short-lived Firebase deployment identity #133; an actual profile-recovery release remains CI-001D — Prove backend-first staging and deploy the profile repair #136; protected Netlify publication/readback remains WEB-001.

    Officer impact: a merge now changes source and runs checks only. A release is a separate exact-commit request, and missing configuration or authority is a visible red stop before backend or website publication.

    Officer documentation: merged in #138 across the root handbooks/system maps and the affected short officer guides.

    Deployment evidence: source gate live; negative fail-closed behavior proven. No production application deployment is claimed by this issue.

    CLAIM RELEASED at 9eafab1217aff7058c42240aaba72d7b93f8ed24.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:ciContinuous integration and deploymentarea:firebaseFirebase services and dataarea:webWeb application and hostingpriority:P0Launch blocker or urgent security risksize:MMedium multi-file issuetype:reliabilityReliability and recoverytype:securitySecurity or privacy boundary

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions