SCOPE: everything in progressdocs/compliance/this-week.md · build 40bb41bdb460

This week: Step 0, MFA, scanning, branch protection

Every step here is a dashboard click or an account move. Each says who can do it; nobody should do one without saying so first.

Where it stands (28 Oct)

Read from GitHub, Vercel and the Supabase dashboard on 28 Oct. Kyle had already started Step 0 on the evening of 27 Oct: a Lucent Axis Vercel team, a project in it built from lucent-axis/scope, and a Lucent Axis Supabase organization connected to it through Vercel's Supabase integration.

Dan's roles today: Member on the Vercel team, Developer in the Supabase organization, member with repo admin on GitHub. So requiring MFA on the Supabase organization, enforcing SSL, network restrictions and the password rules are Kyle's (Owner), or Dan's once Kyle makes him Owner or Administrator.

Item Outcome Waiting on
ORG-06 MFA Vercel team: done, MFA enforced by Kyle on 27 Oct (team setting mfa.enforced, read 28 Oct). Supabase org: read 28 Oct, both members have MFA on; "Require MFA to access organization" is off and only the Owner can switch it on (ID-1). GitHub org: Dan cannot see the setting (owner only). Google Workspace: not checked Kyle (GitHub org, Supabase org switch, Google)
OW-6 two owners GitHub org: Kyle is still the only owner. Vercel team: Kyle Owner, Dan Member. Supabase org: Kyle Owner, Dan Developer. No vault yet: Bitwarden's free organization is the choice under Free first, and Dan can create it now and invite Kyle Kyle: a second owner on each. Dan: the vault
OW-2 Vercel team Done. Lucent Axis (lucent-axis), created by Kyle 27 Oct, Pro plan (trial), MFA enforced, Vercel Authentication on every deployment except custom domains. Project scope-web, root apps/web, from lucent-axis/scope main, functions in iad1, live with Production env vars and the demo on the company database since 28 Oct Kyle: billing before the trial ends
OW-3 Supabase org Done, read 28 Oct. Project scope-dev (ref zvxabodonzynkxmcpbji) is the only one in the Lucent Axis organization, Pro plan, Nano compute, us-east-1, linked to lucent-axis/scope; members Kyle (Owner) and Dan (Developer). It was created with PITR off: daily backups only, so RPO is up to 24 hours today (AV-2). Dan brought the database current on 28 Oct and every verify_*.sql passes against it Kyle: the Owner switches (ID-1, DB-7, ID-7); AV-2 decides PITR
ORG-26 Dependabot alerts Done 28 Oct: switched on for lucent-axis/scope (Claude ran gh api -X PUT repos/lucent-axis/scope/vulnerability-alerts, approved by Dan); 0 open alerts at first read. dependabot.yml is on main from the CI session Nothing. The 7-day patch rule is in the policy set
DB-7 database door Read 28 Oct: SSL is not enforced and the database accepts connections from any address. Dan's Developer role cannot change either Kyle (Owner), or Dan once made Owner or Administrator; and the vault
ORG-32 / VN-4 plans and regions Vercel: all three SCOPE projects run functions in iad1 (Washington, D.C., US); Lucent Axis team on Pro (trial). Supabase: Pro, us-east-1, daily backups, PITR off. Log retention and SAML read from the vendors' pricing pages, to confirm on each billing page (system-inventory.md) Dan: confirm those three facts on the billing pages
ORG-07 branch ruleset Done 28 Oct: ruleset main (id 26059181) from .github/rulesets/main.json, pull request required with 0 approvals (Dan, 28 Oct), the five required checks, no bypass Kyle: the monthly review of merged PRs
ORG-33 Novvia's projects Decided (Dan, 28 Oct): Novvia gets its own Supabase and Vercel projects, cloned from lucent-axis/scope. lucent-axis/novvia is set aside Nothing
ORG-35 COFI in the boundary Default: out, until a COFI client asks Dan and Kyle's decision

Dan's clicks, in order

Dependabot alerts (ORG-26): done 28 Oct, kept for the record. github.com/lucent-axis/scope > Settings > Advanced Security (called Code security on older layouts; left sidebar, "Security" section) > Dependabot alerts > Enable. Leave Dependabot security updates and version updates off (the dependabot.yml is code, SC-7). Or, in a terminal: gh api -X PUT repos/lucent-axis/scope/vulnerability-alerts. Done when the Security tab lists Dependabot alerts.

Supabase read (OW-3, ORG-32, VN-4, ID-1): done 28 Oct, kept for the record. 5 minutes, changes nothing.

  1. supabase.com/dashboard, sign in. Top-left organization switcher: note every organization listed and which one holds the project connected to scope-web (its project ref is the subdomain in Vercel > scope-web > Settings > Environment Variables > SUPABASE_URL, which shows the host without revealing a key).
  2. In that organization: Settings > General: the plan. Settings > Team: every member and role. Settings > Security (or Team, depending on the plan): whether MFA is required.
  3. In the project: Project Settings > General: the region (must be a us- region). Database > Backups: daily backups and whether Point in Time Recovery is on. Project Settings > Log drains (or Logs): the retention.
  4. Write each answer into the table in system-inventory.md, or paste it to Claude to write in. No keys or passwords: none of these screens need one copied.

MFA on the Supabase org (ORG-06, ID-1). Kyle's switch (Owner), or Dan's once made Owner or Administrator. In the organization, Settings > Security > Require MFA. Both members already have MFA on (read 28 Oct), so the setting can be switched on now.

Password rules on the NEW project (ID-7). Kyle's (Owner), or Dan's once made Owner or Administrator. Authentication > Providers > Email (or Authentication > Policies, depending on the dashboard version): minimum password length 12, requirement "letters and digits", and leaked password protection on (Pro plan). The same rules are in supabase/config.toml for local databases. The demo personas' passwords are set by gen_demo_auth.sql and are not checked by it; give the company copy's personas a password of 12 or more anyway.

The database door (DB-7), once the vault exists. Section 5 below; the switches are Kyle's (Owner), or Dan's once made Owner or Administrator. One addition from 28 Oct: the Vercel integration has already copied the new project's database password, JWT secret and service-role key into scope-web's Preview and Development variables. The app uses none of them (it runs on the publishable key and RLS, VE-2), so after rotating the password, delete POSTGRES_*, SUPABASE_JWT_SECRET, SUPABASE_SERVICE_ROLE_KEY and SUPABASE_SECRET_KEY from the project, or the vault is not the only place the password lives.

Waiting on others

  • Kyle, in the Lucent Axis Supabase organization (Owner only; or make Dan an Administrator so he can): require MFA (ID-1), enforce SSL and set network restrictions (DB-7), and on the project's Email sign-in settings set 12 characters, letters and digits, and leaked-password protection (ID-7). Dan's Developer role can read these and change none of them (tried 28 Oct).
  • Kyle: second owner on the GitHub org and the Vercel team (OW-6); GitHub org "require two-factor" (ORG-06); the compliance platform and its auditor (ORG-04); whether Novvia accepts Type I plus a bridge letter (ORG-34); Vercel billing before the Pro trial ends.
  • Counsel or the Business lead: naming counsel (ORG-36), contractor agreements (ORG-08), cyber insurance (ORG-31), a company domain or not (OW-4).
  • Dan and Kyle: COFI in or out of the boundary (ORG-35). ORG-33 is decided (Dan, 28 Oct): Novvia gets its own projects, cloned from lucent-axis/scope.
  • Dan: the vault, Bitwarden's free organization (OW-6, DB-7, OW-8), created now and Kyle invited.

The rule: the personal demo does not change (Dan, 27 Oct)

The audit boundary (Dan, 28 Oct): everything in a Lucent Axis account, and nothing else. Dan's personal GitHub repo, Vercel projects and Supabase project are Paul's demo on synthetic data and are not tested against the requirements. So nothing below is done to them for the audit's sake.

Paul is demoing to clients on the personal setup, so until Lucent Axis has its own Vercel and Supabase running, nothing that the personal demo depends on changes:

  • the Vercel project scope-safety-poc on Dan's personal account, its settings and env vars
  • its Supabase project, its keys, its database password and the demo persona passwords
  • the personal repo daniel-sgalia/scope-safety-poc and the routine that pushes main to it

Step 0 is therefore done by building a copy under Lucent Axis, never by moving or reconfiguring the original: new Vercel project, new Supabase project, new keys, built from lucent-axis/scope. The personal demo is retired only after the company copy has been proven and Paul has switched to it, and then it is paused, not rotated in place.

Each step below says whether it is safe now (it cannot reach the personal demo) or waits (for the company copy, or for Paul's switch).

Order: build the company copy (1), MFA on each account as it lands (2), fresh secrets come with the new projects (3). Branch protection (4) applies to lucent-axis/scope now and leaves the personal repo alone; the database door (5) applies to the new project.

1. Step 0: accounts

GitHub (OW-1, OW-6)

Step Who When Done when
Make a second owner of lucent-axis (Dan, or another Lucent Axis person) Kyle Safe now Org > People shows two Owners
Download the org owners' recovery codes into the company vault Kyle and the second owner Safe now, once there is a vault Each owner's codes stored in the vault, not on a laptop
Archive the personal repo and drop it as a remote (lucent-axis/scope, renamed from lucent-axis/demo, has been origin since 28 Oct) Dan Waits for Paul's switch git remote -v shows lucent-axis only. OW-1 then moves to Done

Vault. OW-6, DB-7 and OW-8 all need a company password vault with shared folders. Under Free first (README.md) it is Bitwarden's free organization, enough for the two owners; Dan can create it now and invite Kyle. Bitwarden Teams or 1Password Business once a third person needs shared secrets.

Vercel (OW-2)

Today: scope-safety-poc (Paul's demo) and scope-novvia are on Dan's personal Vercel account (danielsgalia-6070's projects), next to unrelated personal projects. Neither is transferred or changed.

28 Oct: the first two rows are done by Kyle except the second owner (team lucent-axis, Pro trial, Kyle Owner, Dan Member), and the third is done: project scope-web builds from lucent-axis/scope and has run with Production environment variables since 28 Oct. See "Where it stands" above.

Step Who When Done when
Create a Lucent Axis Vercel team on company billing (Pro; log drains and deployment protection on previews need it) Dan, with a company card Safe now Team exists, billed to Lucent Axis
Invite Kyle as Owner, so the team has two owners Dan Safe now Two owners
Create a NEW project in the team, built from lucent-axis/scope, with its own env vars pointing at the new Supabase project Dan After the Supabase copy It builds, and the demo runs on it end to end
Paul switches his demos to the new address Paul, Dan When the copy is proven Paul confirms
Pause scope-safety-poc on the personal account Dan After the switch Personal project paused
Novvia: its own new project in the team, cloned from lucent-axis/scope (ORG-33; lucent-axis/novvia is set aside) Dan Dan's call

Supabase (OW-3)

Step Who When Done when
Create a Lucent Axis Supabase organization on company billing Dan, with a company card Safe now Org exists
Invite Kyle as Owner Dan Safe now Two owners
Create a NEW project in it (US region; created by Kyle 27 Oct with PITR off, AV-2) and build it from the migrations, then copy the demo's data across with a dump and restore. The personal project is only read, never changed Dan Safe now: reading the personal database does not change it Every scripts/db/verify*.sql passes against the new project
Write down: plan, region, PITR, backup retention, log retention of the NEW project Dan With the step above The blanks in system-inventory.md filled (ORG-32, VN-4, AV-2)
Pause the personal Supabase project Dan After Paul's switch Paused

Client-one production and staging (ORG-11) are created in this org too, never moved in later.

Domain (OW-4)

scope-web answers at scope.lucent-axis.com since 4 Nov (DNS at Cloudflare, a DNS-only CNAME to Vercel), and that address opens on the hub. scope-web-mauve.vercel.app still works and still opens on the persona picker. staging.scope.lucent-axis.com is attached in Vercel, but its environment has no branch and no variables yet. SCOPE Training is still on *.vercel.app.

Everything else (OW-5)

The full list is system-inventory.md. The code uses no email or error-tracking service. The one other account with a key is Anthropic (Spotter in the demo): the company copy gets a key from a Lucent Axis Anthropic organization; the personal demo keeps its key until it is paused. AWS Bedrock (client builds) is created in a Lucent Axis AWS account from the start.

2. MFA everywhere (ORG-06, VE-4, ID-1)

Account Setting Who
GitHub org lucent-axis Settings > Authentication security > Require two-factor authentication. Members without 2FA are removed, so check first Kyle (org owner)
Vercel team Team Settings > Security: require MFA for members. Done 27 Oct Kyle
Supabase org Organization settings > Security: require MFA. Both members have it on (read 28 Oct) Kyle (Owner), or Dan once made Owner or Administrator
Google Workspace Admin console > Security > 2-Step Verification > Enforce Workspace admin
Registrar, Anthropic, AWS, the vault Each account's own security page Whoever owns it

Evidence for the auditor: one screenshot per account of the enforced setting, dated.

3. Fresh secrets (OW-8, ORG-02, closes SC-1's rotation)

The new projects come with new keys, so the company copy starts with nothing created under a personal account. The personal demo's keys and passwords are NOT rotated while Paul demos on it; at the switch it is paused, which retires them. The list below is what the company copy must have generated fresh, and stored only in the vault and the new Vercel project.

Secret Where it is used Regenerate in
Supabase publishable key (NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY) Every build, the browser Supabase > API keys, then each Vercel environment
Supabase secret / service-role key Not used by the app or the scripts (checked 27 Oct); may still exist in someone's .env.local Supabase > API keys
Supabase JWT signing key Every session New with the new project
Database password (SUPABASE_DB_URL in .env.local) Scripts run by hand Supabase > Database; store only in the vault
NEXT_PUBLIC_DEMO_PASSWORD The persona picker; shipped to the browser by design A new password for the company copy's personas (gen_demo_auth.sql against the NEW project), set in the new Vercel project. Purging it from the bundle is code (SC-1)
ANTHROPIC_API_KEY Spotter, demo only Anthropic console, in the Lucent Axis org
Vercel and Supabase personal access tokens on laptops CLI Revoke the old ones; new ones under the company accounts

gitleaks in CI finds nothing in the git history, so there is no history to purge today.

4. Protect main on lucent-axis/scope only (ORG-07, SC-5)

Decided (Dan, 28 Oct): the company repo follows the rules now; the personal repo does not change. Checked 28 Oct: Paul's demo (scope-safety-poc) is deployed from Dan's personal side, so a lock on lucent-axis/scope cannot reach the live demo. (Later on 28 Oct: lucent-axis/scope main does deploy, to scope-web in the Lucent Axis Vercel team, which Kyle created on 27 Oct. That is the company copy, not Paul's demo; its Vercel status on each commit is not a check to require until its builds pass.) Dan is admin on the repo and can set this.

Superseded 28 Oct by the pre-commit/CI session: the ruleset is now a file, .github/rulesets/main.json (no admin bypass; required checks check, secrets, pre-commit, build, data; emergency = an owner sets it to Disabled), applied by Dan, with scripts/git/ship.sh for the push routine. The steps below are the first draft, kept for the record.

Settings > Rules > Rulesets > New ruleset > New branch ruleset:

  • Name main, enforcement Active
  • Target branches: Include default branch
  • Bypass list: Organization admin, set to For pull requests only. An owner can merge a pull request whose checks fail in an emergency, but nobody can push to main directly, so every change still leaves a PR. Today only Kyle is an org owner; Dan gets the path once OW-6 makes him the second owner
  • Restrict deletions; block force pushes
  • Require a pull request before merging: 0 approvals (Dan, 28 Oct: mostly one developer, so nobody waits on a second person). The author merges their own PR once the checks pass
  • Require status checks to pass: check and secrets, source GitHub Actions (the two jobs in .github/workflows/ci.yml, which run on pull requests too). Leave "require branches to be up to date" off

Repo settings alongside it:

  • Merge commits only (squash and rebase off). The personal repo's commits arrive unchanged; a squash would rewrite them and the next sync would conflict
  • Dependabot alerts on (free on Team; alerts only, no automatic PRs)

Emergency rule, for the policy: a bypassed merge gets a comment on the PR within one working day saying why.

What an auditor will say about 0 approvals. SOC 2 change management (CC8.1) usually expects a second person to look at a change. With one developer, the usual answer is a compensating control instead of a gate: every change is a PR with green checks (enforced), and Kyle reviews the list of merged PRs once a month and records it (a short note or tick per month). That is written into the change-management policy; if the auditor wants pre-merge review later, the setting is one number.

The push routine once the ruleset is on

Until the ruleset is switched on, main is pushed to both remotes as today: git push personal main and git push origin main. Once it is on, the second of those is refused, so:

The personal repo is untouched: work is still committed to main and pushed with git push personal main exactly as today, and Paul's demo deploys as it always has. Only the second push changes:

  1. git push origin main:personal-main (origin is lucent-axis/scope; a branch, not main)
  2. One standing pull request, personal-main into main, picks the new commits up; CI runs on it
  3. When the checks are green, Dan merges it himself with a merge commit
  4. Repeat: each push adds to the same PR until it is merged, then the next push opens a new one

Kyle's own changes, when there are any, go the same way the other round: a branch and a PR on lucent-axis/scope, merged once green, and after the merge Dan pulls lucent-axis/scope main into the personal repo so the two do not drift.

When Paul has switched to the company copy (OW-1), the personal repo is archived and the standing PR becomes ordinary branch-per-change work.

lucent-axis/novvia is set aside (28 Oct); Novvia's clone of lucent-axis/scope carries the same ruleset file.

5. Lock the database door (DB-7)

OW-3 is done; this waits for the vault and for an Owner or Administrator.

Step Where Who
Enforce SSL on connections Supabase > Database > SSL configuration Kyle (Owner), or Dan once made Owner or Administrator
Network restrictions: allow only the addresses that need a direct connection (none of the app's traffic needs one: it goes through the API) Supabase > Database > Network restrictions Kyle (Owner), or Dan once made Owner or Administrator
Rotate the database password; keep it in the vault only, never in chat or a file outside .env.local Supabase > Database Kyle (Owner), or Dan once made Owner or Administrator

Secret scanning and push protection (ORG-03, SC-3)

Decided (Dan, 28 Oct): option 2, the free route, under the free-first rule in README.md. Option 1 is the upgrade, not the plan.

On GitHub Team, secret scanning and push protection for private repos come with the paid GitHub Secret Protection add-on, charged per active committer (two today). Options:

  1. Buy it for the org and switch both on for all repos (Kyle, Org > Code security > Configurations). This is what the roadmap asks for and what an auditor recognises.
  2. Do not buy it; rely on gitleaks in CI (already running over the whole history on every push) and add a gitleaks pre-commit hook. Cheaper, but it catches a secret after the push, not before.

Dependabot alerts are free on Team and can be switched on now (Repo > Settings > Code security).

Back to top