From c61169fba193fa37af291cf76c2f16a949b1d818 Mon Sep 17 00:00:00 2001 From: verlyn13 Date: Mon, 14 Sep 2026 11:16:32 -0800 Subject: [PATCH] docs: record GitHub governance --- docs/roadmap.md | 9 ++++----- docs/status.md | 10 +++++----- project.yaml | 4 ++-- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index 361e982..2806685 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -6,12 +6,11 @@ Ordered next work. State, decisions and deadlines live in [status.md](status.md) The backup, profile-role hardening/audit, two-script Worker URL restrictions and credential containment are recorded as complete in [status](status.md#latest-live-readbacks). Status action numbers are stable references; this is the execution order. Preserve durable facts (Supabase data, migrations, backups), not obsolete runtime topology: fix forward, delete classified legacy surfaces, and make the next production release the architecture we keep. Each production step retains its operator authority and stop points. -Action 5 discovery is complete. Action 8 retains a deletion-time zone DNS/Worker-route check because the scoped Cloudflare token cannot read those surfaces; that gap does not block GitHub governance. +Action 5 discovery and action 10 GitHub governance are complete. Action 8 retains a deletion-time zone DNS/Worker-route check because the scoped Cloudflare token cannot read those surfaces; that gap does not block the first release. -1. Establish the `main` ruleset, Production deployment protections and Dependabot controls (action 10) before the release. Require the exact check `Full repository validation`; inspect bypass behavior and the existing Wrangler/Miniflare ignore policy — authenticated control readbacks. -2. First release (action 3) from a clean checkout of the exact successful CI commit, at a quiet time, with operator commands rather than a CI dispatch: read back the completed `games` count, `player_stats` rows and summed `games_played` (the one-time rebuild resets stats that no completed game backs), apply `20260914000001` and `20260914000002` alone, deploy `dicee-web`, detach `dicee.games` from Pages and attach it to `dicee-web` (short outage), then deploy `dicee` (its protocol gate closes the old Pages client's sockets), run the smoke checks including one completed game, delete the deployed `aggregate-game-stats` Edge Function and rebuild all `player_stats` once, then delete the Pages project and the classified scripts (action 8) — sign-in, room/lobby, a persisted game with stats, headers, transcription, non-admin refusal and deletion readbacks. -3. Implement the profile visibility opt-in control, initially off for private profiles, writing `profiles.is_public`; explain that visibility is voluntary and cover it with tests. Merge through the new ruleset — successful full validation on the PR. -4. Deploy the opt-in code, verify the control and a test bug report, then take a fresh complete encrypted backup. Recheck the production link and history (`000001` remote, `000002` local-only), apply only `000002`, and verify the schema and two-account privacy behavior (action 4). Invite opt-ins only after verification; the migration clears earlier opt-ins. Fix forward — fresh backup evidence, migration readback and privacy tests. +1. First release (action 3) from a clean checkout of the exact successful CI commit, at a quiet time, with operator commands rather than a CI dispatch: read back the completed `games` count, `player_stats` rows and summed `games_played` (the one-time rebuild resets stats that no completed game backs), apply `20260914000001` and `20260914000002` alone, deploy `dicee-web`, detach `dicee.games` from Pages and attach it to `dicee-web` (short outage), then deploy `dicee` (its protocol gate closes the old Pages client's sockets), run the smoke checks including one completed game, delete the deployed `aggregate-game-stats` Edge Function and rebuild all `player_stats` once, then delete the Pages project and the classified scripts (action 8) — sign-in, room/lobby, a persisted game with stats, headers, transcription, non-admin refusal and deletion readbacks. +2. Implement the profile visibility opt-in control, initially off for private profiles, writing `profiles.is_public`; explain that visibility is voluntary and cover it with tests. Merge through the new ruleset — successful full validation on the PR. +3. Deploy the opt-in code, verify the control and a test bug report, then take a fresh complete encrypted backup. Recheck the production link and history (`000001` remote, `000002` local-only), apply only `000002`, and verify the schema and two-account privacy behavior (action 4). Invite opt-ins only after verification; the migration clears earlier opt-ins. Fix forward — fresh backup evidence, migration readback and privacy tests. Do not reapply or reverse `000001`, run a broad database push, or treat a successful dry run as namespace proof. Hosted multiplayer testing waits for an isolated backend (section 8). diff --git a/docs/status.md b/docs/status.md index 3f65627..08550ba 100644 --- a/docs/status.md +++ b/docs/status.md @@ -1,8 +1,8 @@ # Dicee status -**As of:** 2026-09-14T18:58:21Z +**As of:** 2026-09-14T19:16:31Z -**Current phase:** 2026-09 operator safety rollout; GitHub transfer complete, action 10 governance next, then the first release that ships stats correctness and the dicee-web cutover (no deployment yet) +**Current phase:** 2026-09 operator safety rollout; GitHub governance complete, first production release next (no deployment yet) Next work: [roadmap.md](roadmap.md). Cloudflare: [cloudflare.md](cloudflare.md). ## Current state @@ -12,7 +12,7 @@ Next work: [roadmap.md](roadmap.md). Cloudflare: [cloudflare.md](cloudflare.md). - The profile-role audit (action 2) is complete: 7 profiles comprise 5 users and 2 super admins, with no moderators or admins. The operator confirmed both elevated assignments as intentional after private record review; no role changes were needed. Audit-log absence cannot establish that the old privilege was never exploited. - The database backup is encrypted and verified on off-machine storage; Storage contained 0 objects. The plaintext exports were removed after verification. - `workers.dev` and Preview URLs are disabled on `dicee` and `dicee-production`; `gamelobby-production` still exposes both. Namespace and binding discovery is complete; zone-level DNS and Worker-route reads remain unavailable to the scoped Cloudflare token and must be rechecked before deletion. -- The GitHub repository is now `jefahnierocks/dicee` and the checkout is `~/Organizations/jefahnierocks/dicee`; the existing shared Cloudflare account and steward remain unchanged. Infrastructure adoption and any provider-account relocation remain separate future work. +- The GitHub repository is `jefahnierocks/dicee`; `main` is protected by an active ruleset requiring `Full repository validation`, Production is reviewer-gated and main-only, and Dependabot alerts/security updates are enabled. The existing shared Cloudflare account and steward remain unchanged; provider/infrastructure ownership is separate future work. - Credential containment (action 9) is complete: both exposed tokens (Cloudflare and Supabase) return HTTP 401 and their replacements authenticate (see readbacks). The Supabase CLI credential is a project-scoped token with only Database read-write access that expires 7 days after its 2026-09-14 creation; renew it before later operator steps need it. - No application deployment has run during this operator rollout. CI deploys only on a manual `workflow_dispatch` from `main` with `deploy=true`. - Legacy client layers are retired and the docs are consolidated into this file, the roadmap, `docs/cloudflare.md`, `docs/architecture/` and `docs/development/`. Git history is the archive. @@ -43,7 +43,7 @@ These are stable action identifiers, not execution order. [Roadmap section 1](ro 7. [ ] **Stats aggregation.** Fixed in source: `20260914000001` makes `player_stats` a rebuildable projection and stores AI seats, and the Worker now sends JSON arrays (its old array literals were rejected, so the deployed Worker has likely never persisted a game). Complete with action 3: delete the deployed `aggregate-game-stats` Edge Function, then rebuild all stats once. 8. [ ] **Delete obsolete surfaces.** `dicee-production`, `gamelobby` and `gamelobby-production` are legacy cleanup candidates; no deployed Worker service binding consumes them. `gamelobby-production` still exposes `workers.dev` and Preview URLs, and zone-level Worker routes/DNS remain unverified because the scoped token receives HTTP 403. Recheck those surfaces immediately before deletion. Delete Pages `dicee` only after the `dicee-web` cutover; live Durable Object state on legacy scripts is not preserved. 9. [x] **Credential containment.** Both exposed tokens are replaced, revoked and verified dead by direct HTTP 401 readbacks. Cloudflare: the replacement is canonical in 1Password and GitHub Production, and the repository duplicate is removed. Supabase: a project-scoped token with only Database read-write access is the sole CLI credential; temporary copies, the environment override, the fallback token file and plaintext copies are absent. -10. [ ] **GitHub governance.** A `main` ruleset requiring the check **Full repository validation** (the job display name, not `validate`); a `Production` environment with required reviewers and a main-only deployment branch policy; Dependabot alerts and security updates. +10. [x] **GitHub governance.** Active `main` ruleset with no bypass entries requires the exact check **Full repository validation** with strict status checks and blocks deletion/non-fast-forward updates. `Production` requires one reviewer, permits self-review, and accepts deployments only from `main`. Dependabot alerts and security updates are enabled. 11. [ ] **Supabase default grants change on 2026-10-30** for newly created tables; existing tables keep their grants. Apply the explicit-grants migration from the roadmap first ([change notice](https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically)). 12. [ ] Migrate off the legacy `anon` and `service_role` API keys before the announced end-of-2026 deprecation. Verify the final schedule before cutover ([migration guide](https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys)). 13. [ ] Revoke unused Infisical machine identities and any leftover Vercel or PartyKit credentials. @@ -74,7 +74,7 @@ Recorded results; do not rerun the database checks. The operator confirmed that |---|---|---|---| | Worker inventory | 2026-09-14T18:58:21Z | API: scripts, Durable Object namespaces, Worker metadata and Pages bindings | 11 scripts; Pages production binds `GAME_WORKER` to `dicee`; `dicee`, `dicee-production` and `gamelobby-production` hold SQLite `GameRoom`/`GlobalLobby` namespace pairs at v2; source `dicee` matches v1/v2, so no lifecycle deploy or cutover is required | | Worker subdomain URLs | 2026-09-14T18:58:21Z | API: subdomains, custom domains, cron and service-binding consumers | `dicee`, `dicee-production` and `gamelobby` have direct Worker URLs disabled; `gamelobby-production` has workers.dev and Preview URLs enabled; no custom domains, cron or Worker service-binding consumers were found; zone DNS/routes remain unresolved under the scoped token | -| GitHub governance | 2026-09-14T18:58:21Z | Transfer plus REST readback after move | Repository is `jefahnierocks/dicee`; local origin/home updated; Actions secrets and Production environment survived; 0 repository/organization/effective-main rules, Production still unprotected; action 10 remains next | +| GitHub governance | 2026-09-14T19:16:31Z | REST: repository/effective rules, Production environment and Dependabot controls | Active `main` ruleset: no bypass entries; deletion and non-fast-forward blocked; strict `Full repository validation` required. Production: 1 required reviewer, self-review permitted, custom deployment branch policy `main` only. Dependabot alerts and security updates enabled | | Credential containment | 2026-09-14T06:25:02Z | Cloudflare (04:41:28Z): private token verification, wrapper auth, GitHub secret-name readback. Supabase: dashboard last-used match, Management API call with the preserved old token, CLI `SELECT 1` with the replacement, local-copy inventory | Cloudflare: replacement canonical in 1Password; Production `CLOUDFLARE_API_TOKEN` present; repository duplicate absent; old token HTTP 401. Supabase: old token HTTP 401, other account tokens unchanged; project-scoped Database read-write replacement authenticates; environment override, fallback file, temporary Keychain copies and plaintext copies absent. No deployment or database mutation | | Cloudflare Pages and build triggers | 2026-09-13T04:35Z | API: Pages project `dicee`, Workers Builds triggers | Pages has no Git source, production branch `main`; trigger reads returned 403, so triggers are unverified | | GitHub Apps | 2026-09-13T04:49Z | Repository installed GitHub Apps page | No Cloudflare Workers and Pages app; with no Pages Git source, the native Git build integration is not in use | diff --git a/project.yaml b/project.yaml index 21e6d28..512b2fb 100644 --- a/project.yaml +++ b/project.yaml @@ -10,8 +10,8 @@ role: canonical peers: [] status: posture: deployed-system - local_phase: "2026-09 operator safety rollout; GitHub transfer complete, action 10 governance next, then the first release that ships stats correctness and the dicee-web cutover (no deployment yet)" - as_of: "2026-09-14T18:58:21Z" + local_phase: "2026-09 operator safety rollout; GitHub governance complete, first production release next (no deployment yet)" + as_of: "2026-09-14T19:16:31Z" authority: status_of_record: docs/status.md presentation: