Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions .claude/TODO/2026-09-30-held-github-repo-security-settings.md

This file was deleted.

24 changes: 0 additions & 24 deletions .claude/TODO/2026-09-30-held-stored-procedure-allowlist.md

This file was deleted.

31 changes: 0 additions & 31 deletions .claude/TODO/2026-09-30-step7-write-audit-and-datetime-cleanup.md

This file was deleted.

24 changes: 0 additions & 24 deletions .claude/TODO/2026-09-30-step9-ci-setup-and-docs.md

This file was deleted.

96 changes: 0 additions & 96 deletions .claude/TODO/2026-10-10-owner-ops-checklist-before-release.md

This file was deleted.

48 changes: 15 additions & 33 deletions .claude/TODO/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,10 @@ Severity tiers:
- **medium**: doc drift, missing test, refactor with real cost
- **low**: nits, minor doc fixes, stylistic improvements

Total: **11 open TODOs**.
Total: **6 open TODOs**.

> **Start here for owner (non-code) work:** [`2026-10-10-owner-ops-checklist-before-release.md`](2026-10-10-owner-ops-checklist-before-release.md)
> collects every env-var, MP and GitHub setting to do before and right after the next `/release`.

> **`step6`…`step9`** are the remaining steps from the 2026-09-30 MPNext playbook
> audit (one PR each). `held-*` items wait on an owner decision.
> **`step6`** and **`step8`** are the remaining steps from the 2026-09-30 MPNext
> playbook audit (one PR each). `held-*` items wait on an owner decision.

---

Expand All @@ -33,25 +30,19 @@ Total: **11 open TODOs**.
### Critical (0)
_none open_

### High (1)
| Area | Tags | Title | File |
|---|---|---|---|
| auth | security, doc | Owner checklist — settings to do before/after the next /release | [→](2026-10-10-owner-ops-checklist-before-release.md) |
### High (0)
_none open_

### Medium (4)
### Medium (2)
| Area | Tags | Title | File |
|---|---|---|---|
| routing | security, drift | Step 6 — Headers, next.config, server-only, prerender + build in CI | [→](2026-09-30-step6-headers-csp-build-guards.md) |
| services | drift, missing-test | Step 7 — Write-audit gaps and datetime drift cleanup | [→](2026-09-30-step7-write-audit-and-datetime-cleanup.md) |
| routing | security, doc | Held — CSP notes for customer-deployed clones | [→](2026-09-30-held-csp-customer-deployments.md) |
| mp-provider | security | Held — Deny-all stored-procedure allowlist | [→](2026-09-30-held-stored-procedure-allowlist.md) |

### Low (6)
### Low (4)
| Area | Tags | Title | File |
|---|---|---|---|
| components | security, bug | Step 8 — Address-label caps, error boundaries, tool-params decode, codegen escaping | [→](2026-09-30-step8-fork-specific-low-risk-items.md) |
| commands | security, doc | Step 9 — CI supply chain, setup env writer, docs | [→](2026-09-30-step9-ci-setup-and-docs.md) |
| commands | security, doc | Held — GitHub repo security settings | [→](2026-09-30-held-github-repo-security-settings.md) |
| components | bug | Add/Edit Family search: "No contacts found" empty state never renders | [→](2026-09-13-search-empty-state-never-renders.md) |
| components | refactor, missing-test | Unreachable "empty STEP_FIELDS" branch in `GroupWizard.handleNext` | [→](2026-09-13-dead-empty-fields-branch-handlenext.md) |
| services | security | `ToolService.resolveContactIds` takes table/column names from its caller (dev panel) | [→](2026-10-10-dev-panel-resolvecontactids-caller-identifiers.md) |
Expand All @@ -60,36 +51,27 @@ _none open_

## By tag

### security (8)
- owner-ops-checklist-before-release — high
### security (4)
- step6-headers-csp-build-guards — medium
- held-csp-customer-deployments — medium
- held-stored-procedure-allowlist — medium
- step8-fork-specific-low-risk-items — low
- step9-ci-setup-and-docs — low
- held-github-repo-security-settings — low
- dev-panel-resolvecontactids-caller-identifiers — low

### bug (2)
- step8-fork-specific-low-risk-items — low
- search-empty-state-never-renders — low

### drift (2)
### drift (1)
- step6-headers-csp-build-guards — medium
- step7-write-audit-and-datetime-cleanup — medium

### missing-test (2)
- step7-write-audit-and-datetime-cleanup — medium
### missing-test (1)
- dead-empty-fields-branch-handlenext — low

### refactor (1)
- dead-empty-fields-branch-handlenext — low

### doc (4)
- owner-ops-checklist-before-release — high
### doc (1)
- held-csp-customer-deployments — medium
- step9-ci-setup-and-docs — low
- held-github-repo-security-settings — low

### perf (0)
_none open_
Expand All @@ -101,11 +83,11 @@ _none open_
| Area | Count |
|---|---|
| components | 3 |
| auth | 1 |
| routing | 2 |
| commands | 2 |
| services | 2 |
| mp-provider | 1 |
| services | 1 |
| auth | 0 |
| commands | 0 |
| mp-provider | 0 |
| testing | 0 |
| utils | 0 |
| mp-schema | 0 |
Expand Down
2 changes: 1 addition & 1 deletion .claude/references/mp-provider/services/procedure.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function isDevProcedure(procedure: string): boolean {

## How it works
- Both execute methods call `resolveHttpClient(procedure)` which branches on `isDevProcedure` and invokes the matching `ensureValid*Token` + `get*HttpClient` pair (`procedure.service.ts:87-95`).
- Procedure name is validated with `sanitizeIdentifier` (`^[A-Za-z_][A-Za-z0-9_]*$`, ≤128) and then URL-encoded, before any token work; a bad name throws `Invalid procedure name`. There is **no** allowlist of callable procedures (held; see `.claude/TODO/2026-09-30-held-stored-procedure-allowlist.md`).
- Procedure name is validated with `sanitizeIdentifier` (`^[A-Za-z_][A-Za-z0-9_]*$`, ≤128) and then URL-encoded, before any token work; a bad name throws `Invalid procedure name`. There is **no** allowlist of callable procedures — by design for this template; every caller is gated and passes a literal proc name. A downstream clone that wants defence in depth can add one here.
- Errors propagate after `logger.error('mp.procs.execute_failed', { procedure, error: errorName(e) })`.

## Stored procedures called by this codebase
Expand Down
26 changes: 0 additions & 26 deletions .claude/references/security/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,32 +505,6 @@ and no code-bearing URLs in logs.

### Still open — needs a human

- **The MP OAuth client's registered redirect URI must be updated.** Better Auth
1.7 changed the callback path, so the `redirect_uri` this app sends is now
`<BETTER_AUTH_URL>/api/auth/callback/ministryplatform` — previously
`/api/auth/oauth2/callback/ministry-platform`. Note BOTH halves changed: the
1.7 upgrade moved `/oauth2/callback/` to `/callback/`, and the provider id was
renamed from `ministry-platform` to `ministryplatform`. Register the new value in the
Ministry Platform OAuth client **before** deploying, or MP will reject the
authorization request outright.
- **The enforced-CSP browser walk has not been done.** Headers and nonce
coverage were verified against `next start`; a human still needs to click
through every Radix surface under enforcement.
- **`BETTER_AUTH_SECRET` rotated** (done 2026-10-10; owner decision 2026-09-30) in every
Vercel environment and `.env.local` — this deployment was exposed to
F-UPDATE-USER from 2026-07-09 to 2026-09-13. Patching does not revoke sessions
already forged, and with `refreshCache` on (fixed 2026-09-30) they could keep
re-signing themselves; with no database there is no session table to clear.
- **Repo settings**: GitHub private vulnerability reporting, secret scanning,
push protection and Dependabot security updates were all **disabled** on
2026-09-30 (public repo). `SECURITY.md` points reporters at private
vulnerability reporting, so it needs enabling.
- **Check the MP client's redirect URIs** in every environment:
`MINISTRY_PLATFORM_CLIENT_ID`'s MP record must list exactly
`<BETTER_AUTH_URL>/api/auth/callback/ministryplatform` and post-logout
`<BETTER_AUTH_URL>`. Remove `MP_OIDC_CLIENT_ID` / `_SECRET` from any
environment that set them (ignored now, but stale secrets).
- **Real-MP smoke test of Step 4 not yet done** (a real sign-in): sign in,
confirm `/api/auth/get-session` has a `userGuid`, no
`auth.oidc.discovery_failed` / `auth.userinfo.id_token_unverified` in the
log, and sign-out ends the MP session without a "log out?" prompt.
Loading