@fuzdev/fuz_app 0.113.0 → 0.115.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/CLAUDE.md +46 -20
- package/dist/actions/action_dispatcher.d.ts +1 -1
- package/dist/actions/action_dispatcher.d.ts.map +1 -1
- package/dist/actions/action_dispatcher.js +22 -16
- package/dist/actions/action_event.d.ts +18 -2
- package/dist/actions/action_event.d.ts.map +1 -1
- package/dist/actions/action_event.js +63 -19
- package/dist/actions/action_event_types.d.ts +22 -0
- package/dist/actions/action_event_types.d.ts.map +1 -1
- package/dist/actions/action_event_types.js +19 -0
- package/dist/actions/compile_action_registry.d.ts +4 -2
- package/dist/actions/compile_action_registry.d.ts.map +1 -1
- package/dist/actions/compile_action_registry.js +8 -3
- package/dist/actions/frontend_rpc_client.d.ts +6 -0
- package/dist/actions/frontend_rpc_client.d.ts.map +1 -1
- package/dist/actions/frontend_rpc_client.js +2 -1
- package/dist/actions/heartbeat.d.ts +8 -4
- package/dist/actions/heartbeat.d.ts.map +1 -1
- package/dist/actions/heartbeat.js +8 -4
- package/dist/actions/peer_ping.d.ts.map +1 -1
- package/dist/actions/peer_ping.js +3 -1
- package/dist/actions/perform_action.d.ts +1 -1
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +6 -4
- package/dist/actions/register_action_ws.d.ts +13 -0
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +23 -2
- package/dist/actions/rpc_client.d.ts +1 -1
- package/dist/actions/rpc_client.d.ts.map +1 -1
- package/dist/actions/rpc_client.js +2 -1
- package/dist/actions/socket.svelte.d.ts +53 -10
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +84 -23
- package/dist/actions/transports.d.ts +24 -0
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +30 -0
- package/dist/actions/transports_http.d.ts +11 -4
- package/dist/actions/transports_http.d.ts.map +1 -1
- package/dist/actions/transports_http.js +63 -18
- package/dist/actions/transports_ws.d.ts +28 -3
- package/dist/actions/transports_ws.d.ts.map +1 -1
- package/dist/actions/transports_ws.js +33 -4
- package/dist/actions/ws_endpoint_spec.d.ts +7 -0
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/auth/CLAUDE.md +52 -8
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +4 -3
- package/dist/auth/audit_log_schema.d.ts +3 -1
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +13 -3
- package/dist/auth/cell_action_specs.js +1 -1
- package/dist/auth/cell_actions.d.ts.map +1 -1
- package/dist/auth/cell_actions.js +33 -4
- package/dist/auth/cell_authorize.d.ts +3 -0
- package/dist/auth/cell_authorize.d.ts.map +1 -1
- package/dist/auth/cell_authorize.js +7 -4
- package/dist/auth/request_context.d.ts +12 -3
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +12 -3
- package/dist/auth/role_grant_offer_action_specs.d.ts +30 -5
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +53 -17
- package/dist/auth/role_grant_offer_actions.d.ts +23 -12
- package/dist/auth/role_grant_offer_actions.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_actions.js +132 -38
- package/dist/auth/role_grant_offer_queries.d.ts +36 -0
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_queries.js +76 -0
- package/dist/auth/role_schema.d.ts +12 -0
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +12 -0
- package/dist/auth/self_service_role_actions.d.ts +14 -0
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +25 -1
- package/dist/http/CLAUDE.md +7 -3
- package/dist/http/jsonrpc_helpers.d.ts +0 -5
- package/dist/http/jsonrpc_helpers.d.ts.map +1 -1
- package/dist/http/jsonrpc_helpers.js +0 -13
- package/dist/http/schema_helpers.d.ts +56 -0
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +91 -0
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +1 -0
- package/dist/server/serve_fact_route.d.ts +3 -1
- package/dist/server/serve_fact_route.d.ts.map +1 -1
- package/dist/server/serve_fact_route.js +7 -4
- package/dist/testing/CLAUDE.md +29 -16
- package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_gated_create.js +23 -1
- package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/peer_ping_ws.js +18 -0
- package/dist/testing/cross_backend/role_grant_participation.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_participation.js +34 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +12 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +13 -1
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts.map +1 -1
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.js +9 -7
- package/dist/testing/cross_backend/ws_round_trip.d.ts +11 -3
- package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_round_trip.js +74 -12
- package/dist/testing/entities.d.ts +6 -3
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +4 -1
- package/dist/testing/transports/ws_client.d.ts +6 -0
- package/dist/testing/transports/ws_client.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.js +6 -1
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +5 -0
- package/dist/ui/BootstrapForm.svelte +14 -10
- package/dist/ui/BootstrapForm.svelte.d.ts.map +1 -1
- package/dist/ui/CLAUDE.md +19 -7
- package/dist/ui/LoginForm.svelte +8 -4
- package/dist/ui/LoginForm.svelte.d.ts.map +1 -1
- package/dist/ui/RoleGrantOfferForm.svelte +29 -14
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts +2 -3
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts.map +1 -1
- package/dist/ui/SignupForm.svelte +14 -13
- package/dist/ui/form_state.svelte.d.ts +24 -11
- package/dist/ui/form_state.svelte.d.ts.map +1 -1
- package/dist/ui/form_state.svelte.js +38 -10
- package/dist/ui/role_grant_offers_state.svelte.d.ts +25 -15
- package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -1
- package/dist/ui/role_grant_offers_state.svelte.js +7 -1
- package/package.json +2 -22
- package/dist/actions/request_tracker.svelte.d.ts +0 -77
- package/dist/actions/request_tracker.svelte.d.ts.map +0 -1
- package/dist/actions/request_tracker.svelte.js +0 -169
package/dist/auth/CLAUDE.md
CHANGED
|
@@ -57,7 +57,7 @@ Cross-cutting notes that don't live on any single symbol:
|
|
|
57
57
|
Convention — `*_schema.ts` is Zod-only; `*_ddl.ts` holds DDL strings.
|
|
58
58
|
|
|
59
59
|
- `auth/account_schema.ts` — `Account`, `Actor`, `RoleGrant`, `AuthSession`, `ApiToken` + client-safe JSON shapes.
|
|
60
|
-
- `auth/role_schema.ts` — `RoleName`, `RoleSpec`, `ROLE_KEEPER`, `ROLE_ADMIN`, `create_role_schema`, `builtin_role_specs_by_name`, `role_has_grant_path`, `list_roles_with_grant_path`.
|
|
60
|
+
- `auth/role_schema.ts` — `RoleName`, `RoleSpec`, `ROLE_KEEPER`, `ROLE_ADMIN`, `is_builtin_role`, `create_role_schema`, `builtin_role_specs_by_name`, `role_has_grant_path`, `list_roles_with_grant_path`.
|
|
61
61
|
- `auth/scope_kind_schema.ts` — `ScopeKindName`, `create_scope_kind_schema` (open registry, no builtins).
|
|
62
62
|
- `auth/credential_type_schema.ts` — `CredentialTypeName`, `CREDENTIAL_TYPE_SESSION` / `_API_TOKEN` / `_DAEMON_TOKEN`, `create_credential_type_schema`.
|
|
63
63
|
- `auth/grant_path_schema.ts` — `GrantPathName`, `GRANT_PATH_ADMIN` / `_SELF_SERVICE` / `_SYSTEM` / `_BOOTSTRAP`, `create_grant_path_schema`.
|
|
@@ -183,7 +183,7 @@ Everything else listed under §RPC action surfaces.
|
|
|
183
183
|
### Middleware
|
|
184
184
|
|
|
185
185
|
- `auth/middleware.ts` — `create_auth_middleware_specs(deps, options)` assembles `[origin, session, request_context, bearer_auth]` + optional `daemon_token`.
|
|
186
|
-
- `auth/request_context.ts` — `RequestContext`, `resolve_acting_actor`, `build_request_context`, predicates (`has_role`, `has_scoped_role`, `has_any_scoped_role`), guards (`require_auth`, `require_role`, `require_credential_types`, `require_token_scope`), `token_scope_surface_denial` (the direct-call form, for surfaces that aren't route specs), `refresh_role_grants`.
|
|
186
|
+
- `auth/request_context.ts` — `RequestContext`, `resolve_acting_actor`, `build_request_context`, predicates (`has_role`, `has_scoped_role`, `has_any_scoped_role` — the dispatcher's role gate and every builtin-role check read the **global** grant via `has_scoped_role(_, role, null)` / `has_any_scoped_role(_, roles, null)`; scope-blind `has_role` is never the gate for a builtin role), guards (`require_auth`, `require_role`, `require_credential_types`, `require_token_scope`), `token_scope_surface_denial` (the direct-call form, for surfaces that aren't route specs), `refresh_role_grants`.
|
|
187
187
|
- `auth/session_middleware.ts` — `process_session_cookie` integration, `create_session_and_set_cookie` (shared by login / signup / bootstrap).
|
|
188
188
|
- `auth/bearer_auth.ts` — soft-fail bearer middleware; rejects when `Origin` or `Referer` present (browser context).
|
|
189
189
|
- `auth/daemon_token_middleware.ts` — `create_daemon_token_middleware(state, deps, log)` — the credential **consumer** only (soft-fail validation, keeper account resolution). The producer (`write_daemon_token` / `start_daemon_token_rotation`) lives in `testing/daemon_token_rotation.ts` behind the dev-env guard — no production assembly mints daemon tokens, mirroring the Rust spine's `fuz_testing`-confined producer. Soft-fails — discards the credential (pass-through, no own 401/503) on **every** non-success path: browser context (`Origin`/`Referer` present), malformed/invalid token, and valid-token-but-no-keeper all `next()` through to the dispatcher's `credential_type_required` (403) gate, mirroring the bearer guard and the Rust spine's `resolve.rs`. Daemon tokens are loopback-only, so browser context never arises in practice — the discard is defense-in-depth.
|
|
@@ -227,7 +227,8 @@ delete / list / clone / moderate`), error reasons, and `all_cell_action_specs`
|
|
|
227
227
|
delegable. Editor-grant holders edit content + relations but cannot
|
|
228
228
|
manage grants or read the audit timeline. NULL
|
|
229
229
|
`created_by` (system origin) is admin-only for edit/manage (explicit
|
|
230
|
-
defense-in-depth).
|
|
230
|
+
defense-in-depth). "Admin" on every tier is the **global** grant — a
|
|
231
|
+
scoped `admin` row bypasses nothing.
|
|
231
232
|
- `auth/cell_relation_visibility.ts` — `filter_visible_target_ids(deps,
|
|
232
233
|
auth, ids)`: batched strict relation-read filter. Every relation read —
|
|
233
234
|
the `cell_get` bundle, **forward and reverse** `cell_field_list` /
|
|
@@ -247,7 +248,10 @@ auth, ids)`: batched strict relation-read filter. Every relation read —
|
|
|
247
248
|
write-once-at-birth or control-gated, never on the update patch).
|
|
248
249
|
`cell_get` bundles visibility-filtered `fields` + `items` (one over the cap
|
|
249
250
|
for truncation detection). `cell_clone` deep-walks viewable children only
|
|
250
|
-
(each clone inherits its source's `kind`; clones are unparented)
|
|
251
|
+
(each clone inherits its source's `kind`; clones are unparented), and runs
|
|
252
|
+
the mounted `authorize_create` for **every** cell it writes as a parentless
|
|
253
|
+
create — a denial is the same 403 `cell_create_forbidden`, so clone is no
|
|
254
|
+
side door past the creation policy. The optional
|
|
251
255
|
parent-aware `authorize_create` dep (`CellCreateAuthorize` — wider input
|
|
252
256
|
`{kind, data, parent_id, root_id, root_data, scope_id}` than `validate_data`,
|
|
253
257
|
returning a `CellCreateVerdict` `{allow:false} | {allow:true, moderation_required}`)
|
|
@@ -611,14 +615,31 @@ event additionally records `credential_type` in metadata (defense in depth).
|
|
|
611
615
|
> suite assume auto-accept and have to redesign their tests when they
|
|
612
616
|
> discover otherwise.
|
|
613
617
|
|
|
614
|
-
- `role_grant_offer_create_action_spec` — input `{to_account_id, to_actor_id?, role, scope_id?, message?}
|
|
615
|
-
- `role_grant_offer_accept_action_spec` — input `{offer_id}`; output `{role_grant_id, offer, superseded_offer_ids}`.
|
|
618
|
+
- `role_grant_offer_create_action_spec` — input `{to_account_id, to_actor_id?, role, scope_kind?, scope_id?, message?}` (`scope_kind` + `scope_id` paired — both or neither, else `invalid_params`); output `{offer}`.
|
|
619
|
+
- `role_grant_offer_accept_action_spec` — input `{offer_id}`; output `{role_grant_id, offer, superseded_offer_ids}`. Refuses a builtin-role offer that must not mint (see below), leaving it pending.
|
|
616
620
|
- `role_grant_offer_decline_action_spec` — input `{offer_id, reason?}`; output `{ok}`.
|
|
617
621
|
- `role_grant_offer_retract_action_spec` — input `{offer_id}`; output `{ok}`.
|
|
618
622
|
- `role_grant_offer_list_action_spec` — input `{account_id?}`; output `{offers}`.
|
|
619
623
|
- `role_grant_offer_history_action_spec` — input `{account_id?, limit?, offset?}`; output `{offers}`.
|
|
620
624
|
- `role_grant_revoke_action_spec` — input `{actor_id, role_grant_id, reason?}`; output `{ok, revoked}`.
|
|
621
|
-
- `role_grant_assign_action_spec` — admin-only immediate conferral (no
|
|
625
|
+
- `role_grant_assign_action_spec` — global-admin-only immediate conferral (no
|
|
626
|
+
consent step); input `{to_account_id, to_actor_id?, role, scope_kind?, scope_id?}`
|
|
627
|
+
(the pair as on offer-create); output `{ok, role_grant_id}`. The handler:
|
|
628
|
+
- re-checks the global admin grant behind the dispatcher gate;
|
|
629
|
+
- runs the same admin-grant-path gate as offer-create, and refuses a scoped
|
|
630
|
+
`admin` (`invalid_params` + `ERROR_ROLE_GRANT_BUILTIN_SCOPED`; a scoped
|
|
631
|
+
`keeper` stays 403 `ERROR_ROLE_NOT_WEB_GRANTABLE`, since `keeper` is never
|
|
632
|
+
web-grantable);
|
|
633
|
+
- resolves the target actor (named `to_actor_id` ∈ the account's active
|
|
634
|
+
actors, else its sole active actor — multi-actor → `invalid_params`,
|
|
635
|
+
actorless → 404);
|
|
636
|
+
- writes the `(scope_kind, scope_id)` pair via the idempotent
|
|
637
|
+
`query_create_role_grant`, and emits a `role_grant_create` audit row
|
|
638
|
+
(metadata carries `scope_kind`, success and failure).
|
|
639
|
+
|
|
640
|
+
No WS notification in v1. Reasons: `ERROR_INSUFFICIENT_PERMISSIONS`,
|
|
641
|
+
`ERROR_ROLE_NOT_WEB_GRANTABLE`, `ERROR_ROLE_GRANT_BUILTIN_SCOPED`,
|
|
642
|
+
`ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH`.
|
|
622
643
|
|
|
623
644
|
Every input carries `acting?: ActingActor` (registry-time invariant 2).
|
|
624
645
|
`role_grant_revoke` keys on **`actor_id`**, not `account_id` — role_grants
|
|
@@ -635,6 +656,25 @@ escalating into global authority over the offer surface. A consumer needing
|
|
|
635
656
|
scope-aware delegation (e.g. a classroom teacher offering within their own
|
|
636
657
|
scope) supplies a custom `authorize` callback.
|
|
637
658
|
|
|
659
|
+
**Builtin roles (`admin` / `keeper`) are global-only**, decided by the spine
|
|
660
|
+
ahead of any callback. Offer-create refuses a scoped `admin`
|
|
661
|
+
(`invalid_params` + `ERROR_ROLE_GRANT_BUILTIN_SCOPED`; `keeper`, scoped or not,
|
|
662
|
+
stays 403 `ERROR_ROLE_GRANT_OFFER_ROLE_NOT_GRANTABLE` at the grant-path gate)
|
|
663
|
+
and a builtin offered by
|
|
664
|
+
a caller without a global `admin` (`ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED`), so
|
|
665
|
+
a consumer callback only ever sees app roles or a global admin's unscoped
|
|
666
|
+
builtin offer. Accept (`query_accept_offer`, the chokepoint where an offer
|
|
667
|
+
becomes a grant) refuses a `keeper` offer (`ERROR_ROLE_GRANT_OFFER_ROLE_NOT_GRANTABLE`),
|
|
668
|
+
a scoped `admin` offer (`invalid_request` + `ERROR_ROLE_GRANT_BUILTIN_SCOPED`), and a
|
|
669
|
+
builtin offer whose grantor no longer holds an active global `admin` on an
|
|
670
|
+
active actor of an active account (`ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED`,
|
|
671
|
+
re-checked under `FOR SHARE` so a racing revoke is ordered against it) — via
|
|
672
|
+
`RoleGrantOfferBuiltinRefusedError` (`refusal: BuiltinOfferRefusal`). Each
|
|
673
|
+
refusal leaves the offer pending and is audited as a failed
|
|
674
|
+
`role_grant_offer_accept` with `{offer_id, role, scope_id, reason}`. The
|
|
675
|
+
grantor re-check is builtin-only: an app-role offer's authority was the
|
|
676
|
+
callback's call at create time.
|
|
677
|
+
|
|
638
678
|
Error reasons (`as const` literals):
|
|
639
679
|
|
|
640
680
|
- `ERROR_ROLE_GRANT_OFFER_SELF_TARGET`
|
|
@@ -645,6 +685,7 @@ Error reasons (`as const` literals):
|
|
|
645
685
|
- `ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED`
|
|
646
686
|
- `ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH` (supplied `to_actor_id` doesn't belong to `to_account_id`)
|
|
647
687
|
- `ERROR_ROLE_GRANT_OFFER_ACTOR_MISMATCH` (actor-targeted offer accepted by wrong actor)
|
|
688
|
+
- `ERROR_ROLE_GRANT_BUILTIN_SCOPED` (a grant path asked to bind `admin` / `keeper` to a scope)
|
|
648
689
|
|
|
649
690
|
Plus re-uses from `http/error_schemas.ts`: `ERROR_ROLE_GRANT_NOT_FOUND`,
|
|
650
691
|
`ERROR_ROLE_NOT_WEB_GRANTABLE`, `ERROR_INSUFFICIENT_PERMISSIONS`,
|
|
@@ -755,7 +796,10 @@ Audit metadata carries `self_service: true` so admin reviewers can
|
|
|
755
796
|
distinguish self-toggled role_grants. Eligibility derives from
|
|
756
797
|
`roles.role_specs` by selecting roles with `'self_service' ∈ grant_paths`;
|
|
757
798
|
override via `eligible_roles`. Roles outside the eligible set are rejected
|
|
758
|
-
with `ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE`.
|
|
799
|
+
with `ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE`. The eligible set is validated at
|
|
800
|
+
construction (`validate_self_service_eligible_roles`): a builtin role or a name
|
|
801
|
+
outside the `RoleName` grammar throws — self-toggling a builtin would hand any
|
|
802
|
+
account instance-wide authority.
|
|
759
803
|
|
|
760
804
|
Method name is static (`role` lives in input, not method) — per-role
|
|
761
805
|
parameterized methods would break the `satisfies RequestResponseActionSpec`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC;AAyC1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AA0DnD,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IAClC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC5C;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,iBAAiB,EACvB,UAAS,kBAAuB,KAC9B,KAAK,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"admin_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC;AAyC1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AA0DnD,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IAClC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC5C;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,iBAAiB,EACvB,UAAS,kBAAuB,KAC9B,KAAK,CAAC,SAAS,CAyfjB,CAAC"}
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
import { rpc_action } from '../actions/action_rpc.js';
|
|
32
32
|
import { jsonrpc_errors } from '../http/jsonrpc_errors.js';
|
|
33
33
|
import { builtin_role_specs_by_name, list_roles_with_grant_path, ROLE_ADMIN, ROLE_KEEPER } from './role_schema.js';
|
|
34
|
-
import {
|
|
34
|
+
import { has_scoped_role } from './request_context.js';
|
|
35
35
|
import { query_account_has_global_role, query_account_has_active_global_role, query_count_active_accounts_with_global_role } from './role_grant_queries.js';
|
|
36
36
|
import { GRANT_PATH_ADMIN } from './grant_path_schema.js';
|
|
37
37
|
import { query_account_by_email, query_account_by_id, query_account_by_username, query_account_soft_delete, query_account_undelete, query_actor_soft_delete, query_actor_undelete, query_actors_by_account, query_admin_account_list, query_purge_account } from './account_queries.js';
|
|
@@ -282,8 +282,9 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
282
282
|
const account_delete_handler = async (input, ctx) => {
|
|
283
283
|
const auth = ctx.auth;
|
|
284
284
|
const target_account_id = input.account_id ?? auth.account.id;
|
|
285
|
-
// Self-or-admin elevation: deleting someone else needs
|
|
286
|
-
|
|
285
|
+
// Self-or-admin elevation: deleting someone else needs the **global**
|
|
286
|
+
// admin grant — a scoped `admin` row confers no cross-account authority.
|
|
287
|
+
if (target_account_id !== auth.account.id && !has_scoped_role(auth, ROLE_ADMIN, null)) {
|
|
287
288
|
throw jsonrpc_errors.forbidden('cannot delete another account', {
|
|
288
289
|
reason: ERROR_INSUFFICIENT_PERMISSIONS
|
|
289
290
|
});
|
|
@@ -141,6 +141,7 @@ export declare const audit_metadata_schemas: Readonly<{
|
|
|
141
141
|
role_grant_create: z.ZodObject<{
|
|
142
142
|
role: z.ZodString;
|
|
143
143
|
role_grant_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
144
|
+
scope_kind: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
144
145
|
scope_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
|
|
145
146
|
source_offer_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
146
147
|
self_service: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -160,9 +161,10 @@ export declare const audit_metadata_schemas: Readonly<{
|
|
|
160
161
|
}, z.core.$loose>;
|
|
161
162
|
role_grant_offer_accept: z.ZodObject<{
|
|
162
163
|
offer_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
163
|
-
role_grant_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out"
|
|
164
|
+
role_grant_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
164
165
|
role: z.ZodString;
|
|
165
166
|
scope_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
|
|
167
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
166
168
|
}, z.core.$loose>;
|
|
167
169
|
role_grant_offer_decline: z.ZodObject<{
|
|
168
170
|
offer_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit_log_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAmB9C;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,6iBA6BnB,CAAC;AAEZ,wCAAwC;AACxC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAA4B,CAAC;AACxD,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,QAA+B,CAAC;AAExE,0DAA0D;AAC1D,eAAO,MAAM,kBAAkB,aAE7B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,2CAA2C;AAC3C,eAAO,MAAM,YAAY;;;EAAiC,CAAC;AAC3D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB
|
|
1
|
+
{"version":3,"file":"audit_log_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -178,6 +178,9 @@ export const audit_metadata_schemas = Object.freeze({
|
|
|
178
178
|
role_grant_id: Uuid.optional().meta({
|
|
179
179
|
description: 'Id of the resulting role_grant row. Omitted when the grant failed (e.g. admin-grant-path denial).'
|
|
180
180
|
}),
|
|
181
|
+
scope_kind: z.string().nullish().meta({
|
|
182
|
+
description: 'Kind tag paired with `scope_id` on a `role_grant_assign` row; null for a global grant.'
|
|
183
|
+
}),
|
|
181
184
|
scope_id: Uuid.nullish().meta({
|
|
182
185
|
description: 'Scope of the granted role_grant; null for global role_grants.'
|
|
183
186
|
}),
|
|
@@ -215,13 +218,20 @@ export const audit_metadata_schemas = Object.freeze({
|
|
|
215
218
|
to_account_id: Uuid.meta({ description: 'Account the offer is directed to.' })
|
|
216
219
|
}),
|
|
217
220
|
// `role_grant_create` is emitted alongside on accept — two events per accept by
|
|
218
|
-
// design: offer-lifecycle audit + role-grant-lifecycle audit.
|
|
221
|
+
// design: offer-lifecycle audit + role-grant-lifecycle audit. A refused
|
|
222
|
+
// accept (a builtin-role offer that must not mint) is an `outcome=failure`
|
|
223
|
+
// row with no `role_grant_id` (nothing was minted) and the wire `reason`.
|
|
219
224
|
role_grant_offer_accept: z.looseObject({
|
|
220
|
-
offer_id: Uuid.meta({ description: 'Id of the accepted offer.' }),
|
|
221
|
-
role_grant_id: Uuid.meta({
|
|
225
|
+
offer_id: Uuid.meta({ description: 'Id of the accepted (or refused) offer.' }),
|
|
226
|
+
role_grant_id: Uuid.optional().meta({
|
|
227
|
+
description: 'Id of the resulting role_grant row. Omitted on `outcome=failure` because no grant was minted.'
|
|
228
|
+
}),
|
|
222
229
|
role: z.string().meta({ description: 'Role granted by the offer.' }),
|
|
223
230
|
scope_id: Uuid.nullish().meta({
|
|
224
231
|
description: 'Scope of the resulting role_grant; null for global role_grants.'
|
|
232
|
+
}),
|
|
233
|
+
reason: z.string().optional().meta({
|
|
234
|
+
description: 'Wire error reason of a refused accept. Set only on `outcome=failure`.'
|
|
225
235
|
})
|
|
226
236
|
}),
|
|
227
237
|
role_grant_offer_decline: z.looseObject({
|
|
@@ -454,7 +454,7 @@ export const cell_clone_action_spec = {
|
|
|
454
454
|
output: CellCloneOutput,
|
|
455
455
|
async: true,
|
|
456
456
|
rate_limit: 'account',
|
|
457
|
-
description: 'Clone a cell (optionally deep). New owner is the caller; `path` is always nulled. Provenance recorded only in the `cell_clone` audit row. Per-account rate-limited — `deep: true` walks `cell_item` rows and fans out, so unbounded clone is a write-amplification vector.'
|
|
457
|
+
description: 'Clone a cell (optionally deep). New owner is the caller; `path` is always nulled. Provenance recorded only in the `cell_clone` audit row. Every cell a clone writes passes the mounted creation authorizer as a parentless create (a denial is 403 `cell_create_forbidden`). Per-account rate-limited — `deep: true` walks `cell_item` rows and fans out, so unbounded clone is a write-amplification vector.'
|
|
458
458
|
};
|
|
459
459
|
export const cell_moderate_action_spec = {
|
|
460
460
|
method: 'cell_moderate',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,0BAA0B,CAAC;AAGlC,OAAO,
|
|
1
|
+
{"version":3,"file":"cell_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAoCN,KAAK,QAAQ,EAEb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EASN,KAAK,OAAO,EACZ,MAAM,uBAAuB,CAAC;AAyB/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACxC,uFAAuF;IACvF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,6HAA6H;IAC7H,IAAI,EAAE,QAAQ,CAAC;IACf,wHAAwH;IACxH,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,wJAAwJ;IACxJ,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,6XAA6X;IAC7X,SAAS,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,8GAA8G;IAC9G,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,mBAAmB,EAAE,OAAO,CAAA;CAAE,CAAC;AAEjG;;;;;;;;;GASG;AACH,MAAM,MAAM,mBAAmB,GAAG,CACjC,IAAI,EAAE,mBAAmB,EACzB,KAAK,EAAE,wBAAwB,KAC3B,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEpD;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG;IAChD,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,QAAQ,CAAC;IAC7C,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;CACvC,CAAC;AA6BF,eAAO,MAAM,YAAY,GAAI,KAAK,OAAO,KAAG,QAgB1C,CAAC;AA2BH,+CAA+C;AAC/C,eAAO,MAAM,mBAAmB,GAAI,MAAM,cAAc,KAAG,KAAK,CAAC,SAAS,CAgpBzE,CAAC"}
|
|
@@ -42,7 +42,7 @@ import { z } from 'zod';
|
|
|
42
42
|
import { rpc_action } from '../actions/action_rpc.js';
|
|
43
43
|
import { jsonrpc_errors, dev_only } from '../http/jsonrpc_errors.js';
|
|
44
44
|
import { is_pg_unique_violation } from '../db/pg_error.js';
|
|
45
|
-
import {
|
|
45
|
+
import { has_scoped_role } from './request_context.js';
|
|
46
46
|
import { ROLE_ADMIN } from './role_schema.js';
|
|
47
47
|
import { cell_create_action_spec, cell_get_action_spec, cell_update_action_spec, cell_delete_action_spec, cell_list_action_spec, cell_clone_action_spec, cell_moderate_action_spec, ERROR_CELL_NOT_FOUND, ERROR_CELL_PATH_ADMIN_ONLY, ERROR_CELL_PATH_TAKEN, ERROR_CELL_VISIBILITY_MANAGE_ONLY, ERROR_CELL_GET_REQUIRES_ID_OR_PATH, ERROR_CELL_KIND_IN_DATA, ERROR_CELL_KIND_EMPTY, ERROR_CELL_CREATE_FORBIDDEN, ERROR_CELL_MODERATE_FORBIDDEN, ERROR_CELL_NOT_A_CONTRIBUTION, ERROR_CELL_LIST_CREATED_BY_REQUIRES_AUTH, ERROR_CELL_LIST_SHARED_WITH_REQUIRES_AUTH, CELL_LIST_LIMIT_DEFAULT, CELL_RELATIONS_BUNDLE_LIMIT } from './cell_action_specs.js';
|
|
48
48
|
import { query_cell_create, query_cell_get, query_cell_get_by_path, query_cell_update, query_cell_delete, query_cell_set_moderation, query_cell_list, query_cell_load_many } from '../db/cell_queries.js';
|
|
@@ -137,7 +137,9 @@ export const create_cell_actions = (deps) => {
|
|
|
137
137
|
const auth = ctx.auth;
|
|
138
138
|
// Path writes are admin-only. Reject before the insert so the audit
|
|
139
139
|
// + DB are clean.
|
|
140
|
-
if (input.path !== undefined &&
|
|
140
|
+
if (input.path !== undefined &&
|
|
141
|
+
input.path !== null &&
|
|
142
|
+
!has_scoped_role(auth, ROLE_ADMIN, null)) {
|
|
141
143
|
throw jsonrpc_errors.forbidden('cell.path is admin-only', {
|
|
142
144
|
reason: ERROR_CELL_PATH_ADMIN_ONLY
|
|
143
145
|
});
|
|
@@ -321,7 +323,7 @@ export const create_cell_actions = (deps) => {
|
|
|
321
323
|
const path_provided = Object.hasOwn(input, 'path');
|
|
322
324
|
// `path` writes are admin-only. Check before fetching so non-admins
|
|
323
325
|
// can't probe for cell existence by varying `path` shape.
|
|
324
|
-
if (path_provided && !
|
|
326
|
+
if (path_provided && !has_scoped_role(auth, ROLE_ADMIN, null)) {
|
|
325
327
|
throw jsonrpc_errors.forbidden('cell.path is admin-only', {
|
|
326
328
|
reason: ERROR_CELL_PATH_ADMIN_ONLY
|
|
327
329
|
});
|
|
@@ -455,6 +457,14 @@ export const create_cell_actions = (deps) => {
|
|
|
455
457
|
* semantics in `clone_handler`. Provenance lives only in the
|
|
456
458
|
* `cell_clone` audit row's `source_id`; `data` carries no
|
|
457
459
|
* server-stamped provenance fields.
|
|
460
|
+
*
|
|
461
|
+
* Each cloned row is a creation — a fresh, unparented cell of the
|
|
462
|
+
* source's kind — so a mounted `authorize_create` gates it exactly as it
|
|
463
|
+
* gates a parentless `cell_create`: `{allow: false}` is the same 403
|
|
464
|
+
* `cell_create_forbidden`, and an allow stamps no moderation (a root has
|
|
465
|
+
* no container to be moderated under). So clone is no side door past the
|
|
466
|
+
* creation policy: a caller denied a root `cell_create` of some kind can't
|
|
467
|
+
* clone a viewable cell of that kind into one they own.
|
|
458
468
|
*/
|
|
459
469
|
const clone_one_cell_row = async (ctx, source, auth, options) => {
|
|
460
470
|
// A patch is wire-supplied `data` — reject a stray `kind` (kind is the
|
|
@@ -468,6 +478,25 @@ export const create_cell_actions = (deps) => {
|
|
|
468
478
|
// Source rows are validated on their original create; the patch
|
|
469
479
|
// could violate the kind shape (e.g., remove a required field).
|
|
470
480
|
const validated_data = validate_data_or_throw(merged_data);
|
|
481
|
+
// Creation-capability gate, after the shape check (the `cell_create`
|
|
482
|
+
// order). The clone is parentless, so no `root_id` / `root_data`; the
|
|
483
|
+
// authorizer sees the merged (pre-normalization) data, as `cell_create`
|
|
484
|
+
// hands it the raw input.
|
|
485
|
+
if (authorize_create) {
|
|
486
|
+
const verdict = await authorize_create(auth, {
|
|
487
|
+
kind: source.kind,
|
|
488
|
+
data: merged_data,
|
|
489
|
+
parent_id: null,
|
|
490
|
+
root_id: null,
|
|
491
|
+
root_data: null,
|
|
492
|
+
scope_id: null
|
|
493
|
+
});
|
|
494
|
+
if (!verdict.allow) {
|
|
495
|
+
throw jsonrpc_errors.forbidden('cell creation is not permitted here', {
|
|
496
|
+
reason: ERROR_CELL_CREATE_FORBIDDEN
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
471
500
|
return query_cell_create(ctx, {
|
|
472
501
|
// Boundary cast (see `create_handler`).
|
|
473
502
|
data: validated_data,
|
|
@@ -651,7 +680,7 @@ export const create_cell_actions = (deps) => {
|
|
|
651
680
|
root_id: input.root_id,
|
|
652
681
|
moderation: input.moderation,
|
|
653
682
|
viewer_actor_id: caller_actor_id,
|
|
654
|
-
viewer_is_admin: auth ?
|
|
683
|
+
viewer_is_admin: auth ? has_scoped_role(auth, ROLE_ADMIN, null) : false,
|
|
655
684
|
caller_actor_id,
|
|
656
685
|
caller_role_grant_roles: role_grant_roles,
|
|
657
686
|
caller_role_grant_scope_ids: role_grant_scope_ids,
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
* role_grant). The grant's `level` (`viewer` / `editor`) gates which
|
|
27
27
|
* predicate it satisfies.
|
|
28
28
|
*
|
|
29
|
+
* The admin bypass on every tier is the **global** `admin` grant
|
|
30
|
+
* (`has_scoped_role(auth, ROLE_ADMIN, null)`), never a scoped one.
|
|
31
|
+
*
|
|
29
32
|
* @module
|
|
30
33
|
*/
|
|
31
34
|
import { type RequestContext } from './request_context.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell_authorize.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_authorize.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cell_authorize.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_authorize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAI5E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AA+DhE;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,aAAa,GACzB,MAAM,cAAc,GAAG,IAAI,EAC3B,MAAM,OAAO,EACb,QAAQ,aAAa,CAAC,YAAY,CAAC,GAAG,IAAI,KACxC,OAMF,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,aAAa,GACzB,MAAM,cAAc,GAAG,IAAI,EAC3B,MAAM,OAAO,EACb,QAAQ,aAAa,CAAC,YAAY,CAAC,GAAG,IAAI,KACxC,OAUF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,cAAc,GAAG,IAAI,EAAE,MAAM,OAAO,KAAG,OAI5E,CAAC"}
|
|
@@ -26,9 +26,12 @@
|
|
|
26
26
|
* role_grant). The grant's `level` (`viewer` / `editor`) gates which
|
|
27
27
|
* predicate it satisfies.
|
|
28
28
|
*
|
|
29
|
+
* The admin bypass on every tier is the **global** `admin` grant
|
|
30
|
+
* (`has_scoped_role(auth, ROLE_ADMIN, null)`), never a scoped one.
|
|
31
|
+
*
|
|
29
32
|
* @module
|
|
30
33
|
*/
|
|
31
|
-
import {
|
|
34
|
+
import { has_scoped_role } from './request_context.js';
|
|
32
35
|
import { is_role_grant_active } from './account_schema.js';
|
|
33
36
|
import { ROLE_ADMIN } from './role_schema.js';
|
|
34
37
|
const cell_is_public = (cell) => cell.visibility === 'public';
|
|
@@ -103,7 +106,7 @@ const is_owner = (auth, cell) => auth.actor !== null && cell.created_by !== null
|
|
|
103
106
|
* @returns whether the caller may view the cell
|
|
104
107
|
*/
|
|
105
108
|
export const can_view_cell = (auth, cell, grants) => {
|
|
106
|
-
if (auth &&
|
|
109
|
+
if (auth && has_scoped_role(auth, ROLE_ADMIN, null))
|
|
107
110
|
return true;
|
|
108
111
|
if (cell_is_public(cell))
|
|
109
112
|
return true;
|
|
@@ -135,7 +138,7 @@ export const can_view_cell = (auth, cell, grants) => {
|
|
|
135
138
|
export const can_edit_cell = (auth, cell, grants) => {
|
|
136
139
|
if (!auth)
|
|
137
140
|
return false;
|
|
138
|
-
if (
|
|
141
|
+
if (has_scoped_role(auth, ROLE_ADMIN, null))
|
|
139
142
|
return true;
|
|
140
143
|
if (cell.created_by === null)
|
|
141
144
|
return false; // explicit: NULL = admin-only
|
|
@@ -166,7 +169,7 @@ export const can_edit_cell = (auth, cell, grants) => {
|
|
|
166
169
|
export const can_manage_cell = (auth, cell) => {
|
|
167
170
|
if (!auth)
|
|
168
171
|
return false;
|
|
169
|
-
if (
|
|
172
|
+
if (has_scoped_role(auth, ROLE_ADMIN, null))
|
|
170
173
|
return true;
|
|
171
174
|
return is_owner(auth, cell);
|
|
172
175
|
};
|
|
@@ -105,13 +105,19 @@ export interface RequestActorContext extends RequestContext {
|
|
|
105
105
|
actor: Actor;
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
|
-
* Check if a request context has an active role_grant for a given role
|
|
108
|
+
* Check if a request context has an active role_grant for a given role at
|
|
109
|
+
* **any** scope.
|
|
109
110
|
*
|
|
110
111
|
* Checks the role_grants already loaded in the context (no DB query).
|
|
111
112
|
* Null-tolerant — `null` ctx (unauthenticated) returns `false`. Symmetric
|
|
112
113
|
* with `has_scoped_role` / `has_any_scoped_role` so the three helpers
|
|
113
|
-
* compose freely in the same predicate
|
|
114
|
-
*
|
|
114
|
+
* compose freely in the same predicate.
|
|
115
|
+
*
|
|
116
|
+
* Scope-blind, so never the gate for a builtin role (`admin` / `keeper`) or
|
|
117
|
+
* for any capability that isn't itself scoped: a grant bound to one resource
|
|
118
|
+
* would pass it. Those gates read the global grant through
|
|
119
|
+
* `has_scoped_role(ctx, role, null)` (e.g.
|
|
120
|
+
* `has_scoped_role(auth, ROLE_ADMIN, null) || has_scoped_role(auth, role, scope)`).
|
|
115
121
|
*
|
|
116
122
|
* @param ctx - the request context, or `null` for unauthenticated callers
|
|
117
123
|
* @param role - the role to check
|
|
@@ -138,6 +144,9 @@ export declare const has_role: (ctx: RequestContext | null, role: string, now?:
|
|
|
138
144
|
* (`{account: 'required', actor: 'none'}`) handlers without a manual
|
|
139
145
|
* narrow. See `cell_authorize` for the resource-side analog.
|
|
140
146
|
*
|
|
147
|
+
* `has_scoped_role(ctx, ROLE_ADMIN, null)` is the admin check everywhere admin
|
|
148
|
+
* confers authority (builtin roles are global-only, see `is_builtin_role`).
|
|
149
|
+
*
|
|
141
150
|
* `scope_id` semantics: in-memory `role_grant.scope_id` is `string | null`, so
|
|
142
151
|
* JS `===` matches the SQL `IS NOT DISTINCT FROM` semantics exactly:
|
|
143
152
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request_context.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/request_context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAEvD,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,KAAK,EAEV,KAAK,SAAS,EACd,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAgBrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElG,OAAO,EAIN,oBAAoB,EACpB,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,EACtB,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,4BAA4B,CAAC;AAErE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,GAAG,OAAO,KAAG,cAAc,GAAG,IAEjE,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB,GAAI,GAAG,OAAO,KAAG,cAQpD,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IAC1D,KAAK,EAAE,KAAK,CAAC;CACb;AAED
|
|
1
|
+
{"version":3,"file":"request_context.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/request_context.ts"],"names":[],"mappings":"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"}
|
|
@@ -84,13 +84,19 @@ export const require_request_context = (c) => {
|
|
|
84
84
|
return ctx;
|
|
85
85
|
};
|
|
86
86
|
/**
|
|
87
|
-
* Check if a request context has an active role_grant for a given role
|
|
87
|
+
* Check if a request context has an active role_grant for a given role at
|
|
88
|
+
* **any** scope.
|
|
88
89
|
*
|
|
89
90
|
* Checks the role_grants already loaded in the context (no DB query).
|
|
90
91
|
* Null-tolerant — `null` ctx (unauthenticated) returns `false`. Symmetric
|
|
91
92
|
* with `has_scoped_role` / `has_any_scoped_role` so the three helpers
|
|
92
|
-
* compose freely in the same predicate
|
|
93
|
-
*
|
|
93
|
+
* compose freely in the same predicate.
|
|
94
|
+
*
|
|
95
|
+
* Scope-blind, so never the gate for a builtin role (`admin` / `keeper`) or
|
|
96
|
+
* for any capability that isn't itself scoped: a grant bound to one resource
|
|
97
|
+
* would pass it. Those gates read the global grant through
|
|
98
|
+
* `has_scoped_role(ctx, role, null)` (e.g.
|
|
99
|
+
* `has_scoped_role(auth, ROLE_ADMIN, null) || has_scoped_role(auth, role, scope)`).
|
|
94
100
|
*
|
|
95
101
|
* @param ctx - the request context, or `null` for unauthenticated callers
|
|
96
102
|
* @param role - the role to check
|
|
@@ -117,6 +123,9 @@ export const has_role = (ctx, role, now = new Date()) => ctx?.role_grants.some((
|
|
|
117
123
|
* (`{account: 'required', actor: 'none'}`) handlers without a manual
|
|
118
124
|
* narrow. See `cell_authorize` for the resource-side analog.
|
|
119
125
|
*
|
|
126
|
+
* `has_scoped_role(ctx, ROLE_ADMIN, null)` is the admin check everywhere admin
|
|
127
|
+
* confers authority (builtin roles are global-only, see `is_builtin_role`).
|
|
128
|
+
*
|
|
120
129
|
* `scope_id` semantics: in-memory `role_grant.scope_id` is `string | null`, so
|
|
121
130
|
* JS `===` matches the SQL `IS NOT DISTINCT FROM` semantics exactly:
|
|
122
131
|
*
|
|
@@ -38,6 +38,28 @@ export declare const ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED: "role_grant_offer_no
|
|
|
38
38
|
export declare const ERROR_ROLE_GRANT_OFFER_ACTOR_MISMATCH: "role_grant_offer_actor_mismatch";
|
|
39
39
|
/** Error reason — `role_grant_offer_create` was called with a `to_actor_id` that does not belong to `to_account_id`. */
|
|
40
40
|
export declare const ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH: "role_grant_offer_actor_account_mismatch";
|
|
41
|
+
/**
|
|
42
|
+
* Error reason — a grant path was asked to bind a builtin role to a scope
|
|
43
|
+
* (builtin roles are global-only, see `is_builtin_role`). Refused by
|
|
44
|
+
* `role_grant_assign`, `role_grant_offer_create`, and `role_grant_offer_accept`.
|
|
45
|
+
*/
|
|
46
|
+
export declare const ERROR_ROLE_GRANT_BUILTIN_SCOPED: "role_grant_builtin_scoped";
|
|
47
|
+
/**
|
|
48
|
+
* Whether a grant input's `scope_kind` + `scope_id` are paired — both absent
|
|
49
|
+
* (a global grant) or both present (a scoped one), the
|
|
50
|
+
* `role_grant_scope_kind_paired` / `role_grant_offer_scope_kind_paired`
|
|
51
|
+
* CHECKs. The grant inputs refine on it so a half-scoped call is a `-32602`
|
|
52
|
+
* rather than a constraint-violation 500.
|
|
53
|
+
*
|
|
54
|
+
* @param input - the grant input's scope pair
|
|
55
|
+
* @returns `true` when both are set or both are absent
|
|
56
|
+
*/
|
|
57
|
+
export declare const is_grant_scope_paired: (input: {
|
|
58
|
+
scope_kind?: string | null;
|
|
59
|
+
scope_id?: string | null;
|
|
60
|
+
}) => boolean;
|
|
61
|
+
/** The message a half-scoped grant input fails with — the grant inputs' refine, and the UI's pre-RPC guard. */
|
|
62
|
+
export declare const GRANT_SCOPE_PAIRED_MESSAGE = "'scope_kind' and 'scope_id' must be given together (both for a scoped grant, neither for a global one)";
|
|
41
63
|
/**
|
|
42
64
|
* Input for `role_grant_offer_create`.
|
|
43
65
|
*
|
|
@@ -215,13 +237,15 @@ export type RoleGrantRevokeOutput = z.infer<typeof RoleGrantRevokeOutput>;
|
|
|
215
237
|
* Input for `role_grant_assign` — the immediate admin-only conferral path, the
|
|
216
238
|
* consent-free sibling of `role_grant_offer_create`. An admin assigns a
|
|
217
239
|
* role_grant straight onto the target actor; there is no offer for a grantee to
|
|
218
|
-
* accept. No `message` (no offer to carry it on)
|
|
219
|
-
*
|
|
240
|
+
* accept. No `message` (no offer to carry it on). `scope_kind` pairs with
|
|
241
|
+
* `scope_id` exactly as on `role_grant_offer_create` — both or neither — and
|
|
242
|
+
* the grant row carries the pair.
|
|
220
243
|
*/
|
|
221
244
|
export declare const RoleGrantAssignInput: z.ZodObject<{
|
|
222
245
|
to_account_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
223
246
|
to_actor_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
|
|
224
247
|
role: z.ZodString;
|
|
248
|
+
scope_kind: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
225
249
|
scope_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
|
|
226
250
|
acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
227
251
|
}, z.core.$strict>;
|
|
@@ -282,7 +306,7 @@ export declare const role_grant_offer_create_action_spec: {
|
|
|
282
306
|
}, z.core.$strict>;
|
|
283
307
|
async: true;
|
|
284
308
|
description: string;
|
|
285
|
-
error_reasons: ("role_grant_offer_self_target" | "role_grant_offer_role_not_grantable" | "role_grant_offer_not_authorized" | "role_grant_offer_actor_account_mismatch")[];
|
|
309
|
+
error_reasons: ("role_grant_offer_self_target" | "role_grant_offer_role_not_grantable" | "role_grant_offer_not_authorized" | "role_grant_offer_actor_account_mismatch" | "role_grant_builtin_scoped")[];
|
|
286
310
|
rate_limit: "account";
|
|
287
311
|
};
|
|
288
312
|
/**
|
|
@@ -334,7 +358,7 @@ export declare const role_grant_offer_accept_action_spec: {
|
|
|
334
358
|
}, z.core.$strict>;
|
|
335
359
|
async: true;
|
|
336
360
|
description: string;
|
|
337
|
-
error_reasons: ("role_grant_offer_terminal" | "role_grant_offer_expired" | "role_grant_offer_not_found" | "role_grant_offer_actor_mismatch")[];
|
|
361
|
+
error_reasons: ("role_grant_offer_terminal" | "role_grant_offer_expired" | "role_grant_offer_not_found" | "role_grant_offer_role_not_grantable" | "role_grant_offer_not_authorized" | "role_grant_offer_actor_mismatch" | "role_grant_builtin_scoped")[];
|
|
338
362
|
};
|
|
339
363
|
export declare const role_grant_offer_decline_action_spec: {
|
|
340
364
|
method: string;
|
|
@@ -501,6 +525,7 @@ export declare const role_grant_assign_action_spec: {
|
|
|
501
525
|
to_account_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
502
526
|
to_actor_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
|
|
503
527
|
role: z.ZodString;
|
|
528
|
+
scope_kind: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
504
529
|
scope_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
|
|
505
530
|
acting: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
506
531
|
}, z.core.$strict>;
|
|
@@ -510,7 +535,7 @@ export declare const role_grant_assign_action_spec: {
|
|
|
510
535
|
}, z.core.$strict>;
|
|
511
536
|
async: true;
|
|
512
537
|
description: string;
|
|
513
|
-
error_reasons: ("role_not_web_grantable" | "role_grant_offer_actor_account_mismatch")[];
|
|
538
|
+
error_reasons: ("insufficient_permissions" | "role_not_web_grantable" | "role_grant_offer_actor_account_mismatch" | "role_grant_builtin_scoped")[];
|
|
514
539
|
rate_limit: "account";
|
|
515
540
|
};
|
|
516
541
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role_grant_offer_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"role_grant_offer_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_action_specs.ts"],"names":[],"mappings":"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"}
|