Skip to content

feat(platform-objects): secure-by-default posture for sensitive system objects (ADR-0066 ④)#2691

Merged
os-zhuang merged 2 commits into
mainfrom
claude/auth-lifecycle-gaps-248nvb
Jul 8, 2026
Merged

feat(platform-objects): secure-by-default posture for sensitive system objects (ADR-0066 ④)#2691
os-zhuang merged 2 commits into
mainfrom
claude/auth-lifecycle-gaps-248nvb

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

What & why

Lands the system-object slice of ADR-0066 ④ (secure-by-default rollout) from the authorization gap map (umbrella #2561). The D2 access: { default: 'private' } primitive has been enforced since #2690's predecessors — but no production object used it: the platform's raw secret/credential stores were still covered by member_default's wildcard '*': allowRead. This PR flips the clearly-sensitive, flip-safe ones.

Change

6 objects → access: { default: 'private' }

Object What its rows are
sys_secret encrypted settings/datasource secrets
sys_jwks JWT signing private keys
sys_verification live password-reset / verify tokens (reading one = account takeover)
sys_oauth_access_token live bearer tokens (reading one = session hijack)
sys_oauth_refresh_token live long-lived credentials
sys_device_code pending device-grant codes (reading one = CLI-login hijack)

An ordinary member's generic data-layer access now 403s; platform admins retain access via the posture-gated viewAllRecords/modifyAllRecords superuser bypass.

Flip-safety — every runtime consumer verified

  • better-auth reads/writes all identity tables via its adapter with isSystem: true → middleware short-circuits; auth flows unaffected.
  • engine.resolveSecret reads sys_secret at driver level (below the middleware).
  • SettingsService / datasource secret-binder read principal-less → middleware falls open for internal calls.
  • API-key auth (core/security/api-key.ts) reads with isSystem: true.

Deliberately excluded (member self-service)

sys_session, sys_api_key, sys_oauth_application, sys_two_factor keep the public posture: the Account app ("My Sessions" / "My API Keys" / "My Apps" / 2FA "My Enrollment") reads them through the generic data layer as the member — flipping them would break self-service. Row scoping (owner/tenant RLS + _self carve-outs) remains their guard. A test asserts the exclusion so it's a documented decision, not an oversight.

Also

  • sys_scim_provider (SCIM bearer-token config) gains requiredPermissions: ['manage_platform_settings'] — mirrors its sibling sys_sso_provider's D3 gate.
  • Setup nav nav_jwks is capability-gated like nav_api_keys (UX: non-admins no longer see a menu entry that can only 403).

Regression pinning

  • platform-objects.test.ts — "secure-by-default posture" suite asserts each flip and the self-service exclusions.
  • ADR-0056 D10 conformance matrix — new row secure-by-default-posture (dropping the flag from a secret store fails CI, not review).
  • ADR-0066 ④ + content/docs/permissions/authorization.mdx updated: system-object slice landed; still open = Studio posture surfacing (objectui) and the explicit-public reference-data convention (no such objects ship in framework today).

Tests / verification

  • platform-objects: 71 passed (incl. new posture suite)
  • plugin-auth: 230 passed (auth flows unaffected by the flips)
  • dogfood: conformance-matrix test ✓, showcase-anonymous-deny + two-doors-permission e2e (real kernel boot + login) 8 passed
  • service-settings 129 + service-datasource 93 passed (the sys_secret consumers)
  • Full workspace turbo build green

Refs #2561

🤖 Generated with Claude Code

https://claude.ai/code/session_0187GeNqezxV6g5jiLiggfbt


Generated by Claude Code

…m objects (ADR-0066 ④)

The platform's raw secret/credential stores no longer ride the wildcard `'*'`
permission grant. `sys_secret`, `sys_jwks`, `sys_verification`,
`sys_oauth_access_token`, `sys_oauth_refresh_token`, and `sys_device_code`
declare `access: { default: 'private' }` — an ordinary member's generic
data-layer access gets 403; platform admins retain access via the
posture-gated viewAllRecords/modifyAllRecords superuser bypass.

Every runtime consumer is unaffected (verified per reader): better-auth reads
via its adapter (system context), `engine.resolveSecret` reads at driver
level, SettingsService / the datasource secret-binder read principal-less
(middleware falls open for internal calls), API-key auth reads isSystem.

- `sys_scim_provider` gains `requiredPermissions: ['manage_platform_settings']`
  (D3 capability gate), mirroring its sibling `sys_sso_provider`.
- Setup nav `nav_jwks` is capability-gated like `nav_api_keys` so non-admins
  don't see a menu entry that can only 403.
- Member self-service objects (sys_session, sys_api_key,
  sys_oauth_application, sys_two_factor) deliberately keep the public
  posture — the Account app reads them as the member; row scoping is their
  guard. A test asserts this exclusion too.
- Pinned against regression: platform-objects.test.ts posture suite + the
  ADR-0056 D10 conformance-matrix row `secure-by-default-posture`.

Tests: platform-objects 71, plugin-auth 230, dogfood conformance +
anonymous-deny + two-doors e2e, service-settings 129, service-datasource 93 —
all green; full turbo build green.

Refs #2561

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0187GeNqezxV6g5jiLiggfbt
@vercel

vercel Bot commented Jul 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 8, 2026 3:49pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m and removed documentation Improvements or additions to documentation tests tooling labels Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/dogfood, @objectstack/platform-objects.

3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/permissions/authorization.mdx (via packages/dogfood)
  • content/docs/plugins/packages.mdx (via @objectstack/platform-objects)
  • content/docs/ui/setup-app.mdx (via @objectstack/platform-objects)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…ADR-0066 ④)

The Advanced table listed Verifications and Device Codes, but those nav
entries were deliberately removed (sensitive ephemeral secrets — not
browsable; see setup-nav.contributions.ts). Also document that nav_jwks is
capability-gated and sys_jwks is private-posture.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0187GeNqezxV6g5jiLiggfbt
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Jul 8, 2026
@os-zhuang os-zhuang marked this pull request as ready for review July 8, 2026 16:03
@os-zhuang os-zhuang merged commit 9fa84f9 into main Jul 8, 2026
17 checks passed
@os-zhuang os-zhuang deleted the claude/auth-lifecycle-gaps-248nvb branch July 8, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants