You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(auth): update capabilities source-of-truth references after @core/capabilities refactor
- docs/reference/capabilities.md: fix TL;DR (TypeBox union → const array, server/auth → src/core),
fix SITE_WRITE_CAPABILITIES location (now defined locally at point-of-use, not in capabilities.ts),
update "Adding a capability" steps to reflect single source of truth
- docs/features/auth-and-access.md: fix TL;DR and Capabilities section source path;
update "Where the code lives" tree to show src/core/capabilities.ts and correct
server/auth/capabilities.ts description; fix Roles table (Admin is force-resynced,
not "Editable"); fix "Add a new capability" cookbook (remove defunct CoreCapabilitySchema,
point to correct file, add picker-coverage step); update Related source-of-truth entries
- docs/server.md: fix one-liner pointing to old server/auth/capabilities.ts location
and wrong doc link (should be docs/reference/capabilities.md)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/features/auth-and-access.md
+27-23Lines changed: 27 additions & 23 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,7 +9,7 @@ Every state-changing CMS request goes through one auth funnel: parse the session
9
9
## TL;DR
10
10
11
11
-**Sessions** are token-cookie based. Cookie name: `SESSION_COOKIE_NAME` (`instatic_admin_session`). Tokens are hashed before storage; the cookie carries the raw token.
12
-
-**Capabilities** are the access model. 36 `CoreCapability` strings defined in `server/auth/capabilities.ts`. Roles are sets of capabilities. Handlers gate on capability, not role.
12
+
-**Capabilities** are the access model. 36 `CoreCapability` strings defined in `src/core/capabilities.ts` (`@core/capabilities`). Roles are sets of capabilities. Handlers gate on capability, not role.
13
13
-**`requireCapability(req, db, 'site.read')`** is the canonical handler entrypoint. Returns the `AuthUser` or a 401/403 `Response`.
14
14
-**MFA (TOTP)** is per-user opt-in. Sessions for MFA-enrolled users are `pending_mfa` until verified, then become `active`. Failed MFA codes go through `mfaRateLimit` AND increment the per-account lockout counter — the same counter the password step uses. A locked account is rejected at the MFA step before any code is checked.
15
15
-**Step-up auth** gates sensitive actions (delete user, revoke another device, sign out all) unless the user disables it on Account -> Security. The default window is 15 minutes; users can configure 5, 15, 30, or 60 minutes.
@@ -22,9 +22,11 @@ Every state-changing CMS request goes through one auth funnel: parse the session
22
22
## Where the code lives
23
23
24
24
```text
25
+
src/core/capabilities.ts — CORE_CAPABILITIES (the canonical list), CoreCapability type (@core/capabilities)
@@ -114,24 +116,25 @@ Users can list active sessions and revoke them individually. `revokeOtherSession
114
116
115
117
## Capabilities
116
118
117
-
36 core capabilities, defined as a closed TypeBox literal union in `server/auth/capabilities.ts`:
119
+
36 core capabilities. The canonical list is in `src/core/capabilities.ts` (`@core/capabilities`) as an `as const` array; `CoreCapability` is derived from it via `typeof CORE_CAPABILITIES[number]`:
1.Add the literal to `CoreCapabilitySchema` and `CORE_CAPABILITIES` in `server/auth/capabilities.ts`.
403
-
2. If it belongs to an existing role surface (admin / client), add it to the matching `*Capabilities` array.
405
+
1.Append the literal to `CORE_CAPABILITIES` in `src/core/capabilities.ts` (`@core/capabilities`). The `CoreCapability` type updates automatically; the server picks it up via import.
406
+
2. If it belongs to the Owner / Admin / Client default sets, add it to the matching entry in `SYSTEM_ROLES` inside `server/auth/capabilities.ts`. Owner + Admin force-sync on next boot.
404
407
3. Use `requireCapability(req, db, 'your.new.capability')` in the handler that needs it.
405
-
4.Owner and Admin roles auto-sync on next boot — no migration needed for existing Owner or Admin accounts.
408
+
4.Add a `CAPABILITY_META` entry + `CAPABILITY_GROUPS` section in `src/admin/pages/users/utils/capabilities.ts` so the role-edit dialog renders a checkbox. The `capability-picker-coverage.test.ts` gate fails until you do.
406
409
5. Existing custom roles will NOT have the new capability until users grant it through the Roles admin page.
Copy file name to clipboardExpand all lines: docs/reference/capabilities.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,10 +8,10 @@ For the broader auth flow (sessions, MFA, step-up), see [docs/features/auth-and-
8
8
9
9
## TL;DR
10
10
11
-
- Defined as a closed TypeBox literal union in `server/auth/capabilities.ts`. **36 capabilities.**
11
+
- Defined as a `const` array in `src/core/capabilities.ts` (`@core/capabilities`); `CoreCapability` is derived via `typeof CORE_CAPABILITIES[number]`. **36 capabilities.**
12
12
- Handlers gate on capability, not on role: `requireCapability(req, db, 'site.read')`.
13
13
- The **Owner AND Admin** roles get their capability lists force-resynced from `SYSTEM_ROLES` on every server boot. Hand-edits to either built-in role through the admin UI are restored at next boot — they are code-level decisions, not runtime ones.
14
-
- Adding a capability: append the literal in three places (server schema, server array, client array), then add it to the SYSTEM_ROLES entries it should belong to, wire `requireCapability(...)` at the gate point, and add picker meta + groups for the role-edit dialog. The two architecture tests (`capability-picker-coverage.test.ts`, `cms-handlers-capability-gated.test.ts`) catch missing pieces.
14
+
- Adding a capability: append the literal to `CORE_CAPABILITIES` in `src/core/capabilities.ts` (one place — server imports it), add it to the relevant `SYSTEM_ROLES` entries, wire `requireCapability(...)` at the gate point, and add picker meta + groups for the role-edit dialog. The two architecture tests (`capability-picker-coverage.test.ts`, `cms-handlers-capability-gated.test.ts`) catch missing pieces.
15
15
- Custom roles editable in the Roles admin page (Owner-only `roles.manage`).
16
16
17
17
---
@@ -33,7 +33,7 @@ For the broader auth flow (sessions, MFA, step-up), see [docs/features/auth-and-
33
33
|`site.content.edit`| Modify content props (text, image src/alt, link href) on existing nodes — no structure or style edits | Owner, Admin, Client |
`SITE_WRITE_CAPABILITIES`(in `capabilities.ts`) is the convenience set `['site.structure.edit', 'site.content.edit', 'site.style.edit']` — used by the site shell save handler. The `/pages` and `/components` reconcile endpoints additionally require `site.structure.edit` because their wholesale reconcile can soft-delete entries.
36
+
`SITE_WRITE_CAPABILITIES` is the convenience set `['site.structure.edit', 'site.content.edit', 'site.style.edit']` — defined locally in `server/handlers/cms/site.ts` and `src/admin/access.ts` at each point of use, not in a shared capabilities module. Used by the site shell save handler. The `/pages` and `/components` reconcile endpoints additionally require `site.structure.edit` because their wholesale reconcile can soft-delete entries.
Copy file name to clipboardExpand all lines: docs/server.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -260,7 +260,7 @@ if (user instanceof Response) return user // 401 or 403 already encoded
260
260
// ... user is now AuthUser
261
261
```
262
262
263
-
`requireCapability` and `requireAnyCapability` are the only auth surfaces a handler should call. Capabilities are strings like `site.read`, `site.structure.edit`, `media.write`, `plugins.install`, `users.manage`, etc. Owner accounts get all `CORE_CAPABILITIES` automatically. The full list is in `server/auth/capabilities.ts`; `docs/features/auth-and-access.md` catalogs every one.
263
+
`requireCapability` and `requireAnyCapability` are the only auth surfaces a handler should call. Capabilities are strings like `site.read`, `site.structure.edit`, `media.write`, `plugins.install`, `users.manage`, etc. Owner accounts get all `CORE_CAPABILITIES` automatically. The full list is in `src/core/capabilities.ts` (`@core/capabilities`); `docs/reference/capabilities.md` catalogs every one.
0 commit comments