@fuzdev/fuz_app 0.106.0 → 0.107.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 +42 -23
- package/dist/actions/action_bridge.d.ts +34 -3
- package/dist/actions/action_bridge.d.ts.map +1 -1
- package/dist/actions/action_bridge.js +32 -1
- package/dist/actions/action_rpc.d.ts +5 -4
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +4 -3
- package/dist/actions/action_spec.d.ts +8 -2
- package/dist/actions/action_spec.d.ts.map +1 -1
- package/dist/actions/action_spec.js +5 -2
- package/dist/actions/compile_action_registry.d.ts +26 -14
- package/dist/actions/compile_action_registry.d.ts.map +1 -1
- package/dist/actions/compile_action_registry.js +29 -14
- package/dist/actions/perform_action.d.ts +26 -16
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +69 -44
- package/dist/actions/register_action_ws.d.ts +4 -4
- package/dist/actions/register_action_ws.js +5 -5
- package/dist/actions/register_ws_endpoint.d.ts +13 -5
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +15 -6
- package/dist/auth/CLAUDE.md +16 -9
- package/dist/auth/audit_log_route_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_route_schema.js +11 -1
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +4 -9
- package/dist/auth/auth_guard_resolver.d.ts +48 -21
- package/dist/auth/auth_guard_resolver.d.ts.map +1 -1
- package/dist/auth/auth_guard_resolver.js +60 -26
- package/dist/auth/bearer_auth.d.ts +1 -1
- package/dist/auth/bearer_auth.js +1 -1
- package/dist/auth/middleware.js +1 -1
- package/dist/auth/request_context.d.ts +54 -24
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +117 -39
- package/dist/auth/token_scope.d.ts +109 -21
- package/dist/auth/token_scope.d.ts.map +1 -1
- package/dist/auth/token_scope.js +106 -21
- package/dist/http/CLAUDE.md +23 -11
- package/dist/http/auth_shape.d.ts +58 -3
- package/dist/http/auth_shape.d.ts.map +1 -1
- package/dist/http/auth_shape.js +63 -5
- package/dist/http/error_schemas.d.ts +24 -1
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +36 -14
- package/dist/http/route_spec.d.ts +29 -26
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/route_spec.js +12 -16
- package/dist/http/surface_query.d.ts +2 -2
- package/dist/http/surface_query.js +2 -2
- package/dist/server/serve_fact_route.d.ts.map +1 -1
- package/dist/server/serve_fact_route.js +12 -10
- package/dist/testing/CLAUDE.md +39 -3
- package/dist/testing/cross_backend/conformance_case.js +1 -1
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +6 -5
- package/dist/testing/cross_backend/token_scope_surface.d.ts +9 -0
- package/dist/testing/cross_backend/token_scope_surface.d.ts.map +1 -0
- package/dist/testing/cross_backend/token_scope_surface.js +170 -0
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +3 -2
- package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
- package/dist/testing/rpc_attack_surface.js +4 -2
- package/dist/ui/account_sessions_state.svelte.d.ts +3 -3
- package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -189,6 +189,25 @@ export declare const CredentialTypeRequiredError: z.ZodObject<{
|
|
|
189
189
|
required_credential_types: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
190
190
|
}, z.core.$loose>;
|
|
191
191
|
export type CredentialTypeRequiredError = z.infer<typeof CredentialTypeRequiredError>;
|
|
192
|
+
/**
|
|
193
|
+
* Token-scope error — returned by the `require_token_scope` guard (and its
|
|
194
|
+
* direct-call twin `token_scope_surface_denial`) when a **narrowed** api token
|
|
195
|
+
* reaches a capability its scope does not admit. See
|
|
196
|
+
* `docs/security.md` §Token scoping.
|
|
197
|
+
*
|
|
198
|
+
* `required_scope` carries the capability string the route demands, verbatim
|
|
199
|
+
* from its `auth.required_scope` — `surface:audit_stream` for a non-RPC
|
|
200
|
+
* surface, `rpc:<method>` for a bridged action — matching the Rust
|
|
201
|
+
* `token_scope_surface_denied_response` and the dispatcher's own per-method
|
|
202
|
+
* denial. Third in the family with `PermissionError` and
|
|
203
|
+
* `CredentialTypeRequiredError` — each names what the route demanded rather
|
|
204
|
+
* than what the caller holds.
|
|
205
|
+
*/
|
|
206
|
+
export declare const TokenScopeRequiredError: z.ZodObject<{
|
|
207
|
+
error: z.ZodLiteral<"token_scope_required">;
|
|
208
|
+
required_scope: z.ZodString;
|
|
209
|
+
}, z.core.$loose>;
|
|
210
|
+
export type TokenScopeRequiredError = z.infer<typeof TokenScopeRequiredError>;
|
|
192
211
|
/** Rate limit error — returned when a rate limiter rejects the request. */
|
|
193
212
|
export declare const RateLimitError: z.ZodObject<{
|
|
194
213
|
error: z.ZodLiteral<"rate_limit_exceeded">;
|
|
@@ -275,12 +294,16 @@ export type RateLimitKey = z.infer<typeof RateLimitKey>;
|
|
|
275
294
|
* Derivation rules under the new flat-record auth shape:
|
|
276
295
|
* - **Has input / params / query schema**: 400 (`ValidationError`).
|
|
277
296
|
* - **`auth.account === 'required'`** or **`auth.actor === 'required'`**: 401
|
|
278
|
-
* (`ApiError`) — pre-
|
|
297
|
+
* (`ApiError`) — pre-authorization 401 fires when the credential isn't there.
|
|
279
298
|
* `'optional'` does not derive 401.
|
|
280
299
|
* - **`auth.roles?.length`**: 403 (`PermissionError` carrying `required_roles`).
|
|
281
300
|
* - **`auth.credential_types?.length`**: 403 (`CredentialTypeRequiredError`
|
|
282
301
|
* carrying `required_credential_types` — symmetric with `PermissionError`).
|
|
283
302
|
* Today the only credential gate is keeper; future gates reuse the literal.
|
|
303
|
+
* - **`auth.required_scope`**: 403 (`TokenScopeRequiredError` carrying
|
|
304
|
+
* `required_scope`) — the refusal `require_token_scope` emits.
|
|
305
|
+
* A route declaring more than one of these three gates derives the union
|
|
306
|
+
* of their shapes, since any of them can be the one that answers.
|
|
284
307
|
* - **`auth.actor !== 'none'`** (`'optional'` or `'required'`): extends 400
|
|
285
308
|
* with `ActorRequiredError` / `ActorNotOnAccountError` and adds 500 union
|
|
286
309
|
* of `NoActorsOnAccountError` / `AccountVanishedError`. The dispatcher's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/error_schemas.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"error_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/error_schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -195,6 +195,24 @@ export const CredentialTypeRequiredError = z.looseObject({
|
|
|
195
195
|
error: z.literal(ERROR_CREDENTIAL_TYPE_REQUIRED),
|
|
196
196
|
required_credential_types: z.array(z.string()).readonly()
|
|
197
197
|
});
|
|
198
|
+
/**
|
|
199
|
+
* Token-scope error — returned by the `require_token_scope` guard (and its
|
|
200
|
+
* direct-call twin `token_scope_surface_denial`) when a **narrowed** api token
|
|
201
|
+
* reaches a capability its scope does not admit. See
|
|
202
|
+
* `docs/security.md` §Token scoping.
|
|
203
|
+
*
|
|
204
|
+
* `required_scope` carries the capability string the route demands, verbatim
|
|
205
|
+
* from its `auth.required_scope` — `surface:audit_stream` for a non-RPC
|
|
206
|
+
* surface, `rpc:<method>` for a bridged action — matching the Rust
|
|
207
|
+
* `token_scope_surface_denied_response` and the dispatcher's own per-method
|
|
208
|
+
* denial. Third in the family with `PermissionError` and
|
|
209
|
+
* `CredentialTypeRequiredError` — each names what the route demanded rather
|
|
210
|
+
* than what the caller holds.
|
|
211
|
+
*/
|
|
212
|
+
export const TokenScopeRequiredError = z.looseObject({
|
|
213
|
+
error: z.literal(ERROR_TOKEN_SCOPE_REQUIRED),
|
|
214
|
+
required_scope: z.string()
|
|
215
|
+
});
|
|
198
216
|
/** Rate limit error — returned when a rate limiter rejects the request. */
|
|
199
217
|
export const RateLimitError = z.looseObject({
|
|
200
218
|
error: z.literal(ERROR_RATE_LIMIT_EXCEEDED),
|
|
@@ -262,27 +280,31 @@ export const derive_error_schemas = ({ auth, has_input = false, has_params = fal
|
|
|
262
280
|
else if (has_validation) {
|
|
263
281
|
errors[400] = ValidationError;
|
|
264
282
|
}
|
|
265
|
-
// 401 fires when the dispatcher's pre-
|
|
283
|
+
// 401 fires when the dispatcher's pre-authorization gate rejects an
|
|
266
284
|
// unauthenticated caller — `account === 'required'` (no credential) or
|
|
267
285
|
// `actor === 'required'` (no credential to resolve an actor against,
|
|
268
286
|
// per registry-time invariant 3 forbidding accountless actors in v1).
|
|
269
287
|
if (auth.account === 'required' || auth.actor === 'required') {
|
|
270
288
|
errors[401] = ApiError;
|
|
271
289
|
}
|
|
272
|
-
// 403 fires
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
//
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
290
|
+
// 403 fires from any of three gates: the token-scope refusal
|
|
291
|
+
// (`auth.required_scope`, pre-authorization), the credential-type gate, and
|
|
292
|
+
// the role gate (both post-authorization). A route can declare any
|
|
293
|
+
// combination, so collect the shapes its gates can emit — in the order they
|
|
294
|
+
// fire — and union them when there's more than one, so DEV-mode
|
|
295
|
+
// error-schema validation accepts whichever the pipeline produced.
|
|
296
|
+
const forbidden_shapes = [];
|
|
297
|
+
if (auth.required_scope !== undefined)
|
|
298
|
+
forbidden_shapes.push(TokenScopeRequiredError);
|
|
299
|
+
if (auth.credential_types?.length)
|
|
300
|
+
forbidden_shapes.push(CredentialTypeRequiredError);
|
|
301
|
+
if (auth.roles?.length)
|
|
302
|
+
forbidden_shapes.push(PermissionError);
|
|
303
|
+
if (forbidden_shapes.length === 1) {
|
|
304
|
+
errors[403] = forbidden_shapes[0];
|
|
283
305
|
}
|
|
284
|
-
else if (
|
|
285
|
-
errors[403] =
|
|
306
|
+
else if (forbidden_shapes.length > 1) {
|
|
307
|
+
errors[403] = z.union(forbidden_shapes);
|
|
286
308
|
}
|
|
287
309
|
if (rate_limit) {
|
|
288
310
|
errors[429] = RateLimitError;
|
|
@@ -22,14 +22,20 @@ import { type RouteAuth } from './auth_shape.js';
|
|
|
22
22
|
/**
|
|
23
23
|
* Two-phase auth guard set returned by `AuthGuardResolver`.
|
|
24
24
|
*
|
|
25
|
-
* `
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* authorization phase has populated
|
|
29
|
-
* checks live here because they read
|
|
25
|
+
* `pre_authorization` runs before the authorization phase — the 401 check
|
|
26
|
+
* and the rule-3 token-scope refusal live here, so a caller either one turns
|
|
27
|
+
* away never reaches the actor resolution or the route's body.
|
|
28
|
+
* `post_authorization` runs after the authorization phase has populated
|
|
29
|
+
* `RequestContext` — credential / role checks live here because they read
|
|
30
|
+
* `c.var.request_context.role_grants`.
|
|
31
|
+
*
|
|
32
|
+
* Both phases run ahead of body validation, which is why neither is named
|
|
33
|
+
* for it: route-shape information stays behind every authority gate. The
|
|
34
|
+
* names say which side of the authorization phase a guard sits on, the only
|
|
35
|
+
* axis that still distinguishes them.
|
|
30
36
|
*/
|
|
31
37
|
export interface AuthGuards {
|
|
32
|
-
|
|
38
|
+
pre_authorization: Array<MiddlewareHandler>;
|
|
33
39
|
post_authorization: Array<MiddlewareHandler>;
|
|
34
40
|
}
|
|
35
41
|
/**
|
|
@@ -41,12 +47,13 @@ export interface AuthGuards {
|
|
|
41
47
|
*/
|
|
42
48
|
export type AuthGuardResolver = (auth: RouteAuth) => AuthGuards;
|
|
43
49
|
/**
|
|
44
|
-
* Per-route authorization phase. Runs after pre-
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* the
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
+
* Per-route authorization phase. Runs after the pre-authorization auth guards
|
|
51
|
+
* and before input validation; resolves the acting actor (when `auth.actor !==
|
|
52
|
+
* 'none'`) from the `acting` selector — `c.var.validated_query.acting` on GETs,
|
|
53
|
+
* read off the raw body on mutations — and sets the request context on the Hono
|
|
54
|
+
* context. Per-route order in `apply_route_specs`: params → query →
|
|
55
|
+
* pre-authorization auth (401 + rule-3 scope) → authorization phase →
|
|
56
|
+
* post-authorization auth (403) → input validation (400) → handler.
|
|
50
57
|
*
|
|
51
58
|
* Returns a `Response` to short-circuit (resolution failure → 400 / 500),
|
|
52
59
|
* or `void` to continue. The http framework stays auth-agnostic — fuz_app
|
|
@@ -221,19 +228,15 @@ export declare const apply_middleware_specs: (app: Hono, specs: Array<Middleware
|
|
|
221
228
|
* validation, wraps with error catch layer (catches `ThrownJsonrpcError`
|
|
222
229
|
* and generic errors), and registers the route.
|
|
223
230
|
*
|
|
224
|
-
* Per-route middleware order: params → query → pre-
|
|
225
|
-
* guards (401
|
|
226
|
-
* post-authorization auth guards (403) →
|
|
227
|
-
*
|
|
228
|
-
* route-shape information from parse
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* authenticated-but-unauthorized callers can distinguish 400
|
|
234
|
-
* (validation) from 403 (authorization), a defense-in-depth concession
|
|
235
|
-
* deemed acceptable because the route surface is public via
|
|
236
|
-
* spec/codegen JSON.
|
|
231
|
+
* Per-route middleware order: params → query → pre-authorization auth
|
|
232
|
+
* guards (401 + rule-3 scope) → authorization phase →
|
|
233
|
+
* post-authorization auth guards (403) → input validation (400) →
|
|
234
|
+
* handler. Body validation runs behind every authority gate, so a caller
|
|
235
|
+
* any of them refuse never sees route-shape information from a parse
|
|
236
|
+
* failure — a 400 there would confirm the route exists and describe how
|
|
237
|
+
* to call it. Params and query still validate first (they address the
|
|
238
|
+
* route rather than carry its payload, and the authorization phase reads
|
|
239
|
+
* `acting` off the query on GETs).
|
|
237
240
|
*
|
|
238
241
|
* Each handler receives a `RouteContext` with:
|
|
239
242
|
* - `db`: transaction-scoped when `RouteSpec.transaction` is true; pool-level otherwise
|
|
@@ -248,7 +251,7 @@ export declare const apply_middleware_specs: (app: Hono, specs: Array<Middleware
|
|
|
248
251
|
* `input` only — `ActionSpec` has no `query` shape.
|
|
249
252
|
*
|
|
250
253
|
* @param resolve_auth_guards - maps `RouteAuth` to middleware — use `fuz_auth_guard_resolver` from `auth/auth_guard_resolver.ts`
|
|
251
|
-
* @param authorize - optional authorization phase; runs after
|
|
254
|
+
* @param authorize - optional authorization phase; runs after the pre-authorization guards and before the post-authorization guards
|
|
252
255
|
* @param db - used for transaction wrapping and `RouteContext`
|
|
253
256
|
* @mutates `app`
|
|
254
257
|
* @throws Error if two specs share the same `method` + `path` (each combination must be unique), or if any spec violates the actor-acting biconditional
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/route_spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAW,IAAI,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACtE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EACN,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAKjB,MAAM,oBAAoB,CAAC;AAS5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAA0C,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEzF
|
|
1
|
+
{"version":3,"file":"route_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/route_spec.ts"],"names":[],"mappings":"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"}
|
package/dist/http/route_spec.js
CHANGED
|
@@ -266,19 +266,15 @@ const build_rest_error_body = (err) => {
|
|
|
266
266
|
* validation, wraps with error catch layer (catches `ThrownJsonrpcError`
|
|
267
267
|
* and generic errors), and registers the route.
|
|
268
268
|
*
|
|
269
|
-
* Per-route middleware order: params → query → pre-
|
|
270
|
-
* guards (401
|
|
271
|
-
* post-authorization auth guards (403) →
|
|
272
|
-
*
|
|
273
|
-
* route-shape information from parse
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
* authenticated-but-unauthorized callers can distinguish 400
|
|
279
|
-
* (validation) from 403 (authorization), a defense-in-depth concession
|
|
280
|
-
* deemed acceptable because the route surface is public via
|
|
281
|
-
* spec/codegen JSON.
|
|
269
|
+
* Per-route middleware order: params → query → pre-authorization auth
|
|
270
|
+
* guards (401 + rule-3 scope) → authorization phase →
|
|
271
|
+
* post-authorization auth guards (403) → input validation (400) →
|
|
272
|
+
* handler. Body validation runs behind every authority gate, so a caller
|
|
273
|
+
* any of them refuse never sees route-shape information from a parse
|
|
274
|
+
* failure — a 400 there would confirm the route exists and describe how
|
|
275
|
+
* to call it. Params and query still validate first (they address the
|
|
276
|
+
* route rather than carry its payload, and the authorization phase reads
|
|
277
|
+
* `acting` off the query on GETs).
|
|
282
278
|
*
|
|
283
279
|
* Each handler receives a `RouteContext` with:
|
|
284
280
|
* - `db`: transaction-scoped when `RouteSpec.transaction` is true; pool-level otherwise
|
|
@@ -293,7 +289,7 @@ const build_rest_error_body = (err) => {
|
|
|
293
289
|
* `input` only — `ActionSpec` has no `query` shape.
|
|
294
290
|
*
|
|
295
291
|
* @param resolve_auth_guards - maps `RouteAuth` to middleware — use `fuz_auth_guard_resolver` from `auth/auth_guard_resolver.ts`
|
|
296
|
-
* @param authorize - optional authorization phase; runs after
|
|
292
|
+
* @param authorize - optional authorization phase; runs after the pre-authorization guards and before the post-authorization guards
|
|
297
293
|
* @param db - used for transaction wrapping and `RouteContext`
|
|
298
294
|
* @mutates `app`
|
|
299
295
|
* @throws Error if two specs share the same `method` + `path` (each combination must be unique), or if any spec violates the actor-acting biconditional
|
|
@@ -307,7 +303,7 @@ export const apply_route_specs = (app, specs, resolve_auth_guards, log, db, auth
|
|
|
307
303
|
}
|
|
308
304
|
registered.add(route_key);
|
|
309
305
|
assert_route_auth_acting_biconditional(spec.auth, { input: spec.input, query: spec.query }, `Route "${route_key}"`);
|
|
310
|
-
const {
|
|
306
|
+
const { pre_authorization: pre_authorization_guards, post_authorization: post_authorization_guards } = resolve_auth_guards(spec.auth);
|
|
311
307
|
const params_validation = create_params_validation(spec.params);
|
|
312
308
|
const query_validation = create_query_validation(spec.query);
|
|
313
309
|
const input_validation = create_input_validation(spec.input, spec.method);
|
|
@@ -344,7 +340,7 @@ export const apply_route_specs = (app, specs, resolve_auth_guards, log, db, auth
|
|
|
344
340
|
handler = wrap_output_validation(handler, spec.output, merged_errors, log);
|
|
345
341
|
// Step 3: error catch layer
|
|
346
342
|
handler = wrap_error_catch(handler, log);
|
|
347
|
-
app.on(spec.method, [spec.path], ...params_validation, ...query_validation, ...
|
|
343
|
+
app.on(spec.method, [spec.path], ...params_validation, ...query_validation, ...pre_authorization_guards, ...authorization, ...post_authorization_guards, ...input_validation, handler);
|
|
348
344
|
}
|
|
349
345
|
};
|
|
350
346
|
/**
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* `filter_keeper_routes`) group the new flat-record `RouteAuth` shape into
|
|
9
9
|
* the legacy categorical buckets (`'authenticated'`, `'role'`, `'keeper'`)
|
|
10
10
|
* for adversarial test runners and the surface explorer. The buckets are
|
|
11
|
-
* derived views over the
|
|
11
|
+
* derived views over the authority axes (`account`, `actor`, `roles`,
|
|
12
12
|
* `credential_types`) — see `http/auth_shape.ts` for the canonical shape.
|
|
13
13
|
*
|
|
14
14
|
* @module
|
|
@@ -65,7 +65,7 @@ export declare const format_route_key: (route: AppSurfaceRoute) => string;
|
|
|
65
65
|
/**
|
|
66
66
|
* Summarize route auth distribution across the surface.
|
|
67
67
|
*
|
|
68
|
-
* Categorical view over the
|
|
68
|
+
* Categorical view over the flat auth record. Multi-role specs
|
|
69
69
|
* contribute one count per role they admit.
|
|
70
70
|
*
|
|
71
71
|
* @returns counts by auth category, with role counts broken out by role name
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* `filter_keeper_routes`) group the new flat-record `RouteAuth` shape into
|
|
9
9
|
* the legacy categorical buckets (`'authenticated'`, `'role'`, `'keeper'`)
|
|
10
10
|
* for adversarial test runners and the surface explorer. The buckets are
|
|
11
|
-
* derived views over the
|
|
11
|
+
* derived views over the authority axes (`account`, `actor`, `roles`,
|
|
12
12
|
* `credential_types`) — see `http/auth_shape.ts` for the canonical shape.
|
|
13
13
|
*
|
|
14
14
|
* @module
|
|
@@ -87,7 +87,7 @@ export const format_route_key = (route) => `${route.method} ${route.path}`;
|
|
|
87
87
|
/**
|
|
88
88
|
* Summarize route auth distribution across the surface.
|
|
89
89
|
*
|
|
90
|
-
* Categorical view over the
|
|
90
|
+
* Categorical view over the flat auth record. Multi-role specs
|
|
91
91
|
* contribute one count per role they admit.
|
|
92
92
|
*
|
|
93
93
|
* @returns counts by auth category, with role counts broken out by role name
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve_fact_route.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/serve_fact_route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"serve_fact_route.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/serve_fact_route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAetD,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAE5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAM/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AA6DjD,MAAM,WAAW,+BAA+B;IAC/C;;;;;;OAMG;IACH,IAAI,EAAE,OAAO,CAAC;IACd,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACZ;AAgHD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iCAAiC,GAC7C,SAAS,+BAA+B,KACtC,SAgDF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,4BAA4B,GACxC,SAAS,+BAA+B,KACtC,SA0CF,CAAC"}
|
|
@@ -93,7 +93,7 @@ import { join } from 'node:path';
|
|
|
93
93
|
import { FactHashSchema } from '@fuzdev/fuz_util/hash_schemas.ts';
|
|
94
94
|
import { Uuid } from '@fuzdev/fuz_util/id.ts';
|
|
95
95
|
import { z } from 'zod';
|
|
96
|
-
import { build_request_context, get_request_context, has_role
|
|
96
|
+
import { build_request_context, get_request_context, has_role } from '../auth/request_context.js';
|
|
97
97
|
import { ROLE_ADMIN } from '../auth/role_schema.js';
|
|
98
98
|
import { ActingActor } from '../http/auth_shape.js';
|
|
99
99
|
import { ACCOUNT_ID_KEY } from '../hono_context.js';
|
|
@@ -320,7 +320,17 @@ export const create_serve_fact_route_spec = (options) => {
|
|
|
320
320
|
return {
|
|
321
321
|
method: 'GET',
|
|
322
322
|
path: '/api/facts/:hash',
|
|
323
|
-
auth: {
|
|
323
|
+
auth: {
|
|
324
|
+
account: 'required',
|
|
325
|
+
actor: 'required',
|
|
326
|
+
roles: [ROLE_ADMIN],
|
|
327
|
+
// Rule 3 — a narrowed token gets no bare-hash read. This route
|
|
328
|
+
// serves *any* stored fact by hash with no per-reference cell check
|
|
329
|
+
// (that is the per-cell route's job), so it is the broad capability
|
|
330
|
+
// of the pair; gating it keeps a narrowed token to the cell-scoped
|
|
331
|
+
// route its RPC methods can justify.
|
|
332
|
+
required_scope: 'surface:fact_bare'
|
|
333
|
+
},
|
|
324
334
|
description: 'Serve content-addressed fact bytes by bare hash — admin only. Non-admin reads go through GET /api/cells/:cell_id/facts/:hash (per-reference).',
|
|
325
335
|
params: bare_hash_params_schema,
|
|
326
336
|
// `actor: 'required'` (implied by the admin role gate) needs the
|
|
@@ -334,14 +344,6 @@ export const create_serve_fact_route_spec = (options) => {
|
|
|
334
344
|
errors: params_400_error,
|
|
335
345
|
handler: async (c, route) => {
|
|
336
346
|
const { hash } = get_route_params(c);
|
|
337
|
-
// Rule 3 — a narrowed token gets no bare-hash read. This route serves
|
|
338
|
-
// *any* stored fact by hash with no per-reference cell check (that is
|
|
339
|
-
// the per-cell route's job), so it is the broad capability of the
|
|
340
|
-
// pair; gating it keeps a narrowed token to the cell-scoped route its
|
|
341
|
-
// RPC methods can justify.
|
|
342
|
-
const denied = token_scope_surface_denial(c, 'fact_bare');
|
|
343
|
-
if (denied)
|
|
344
|
-
return denied;
|
|
345
347
|
// Defense-in-depth: the auth phase already gated this on the admin
|
|
346
348
|
// role, but re-check the resolved context so a mounting/auth-shape
|
|
347
349
|
// regression fails closed instead of serving by bare hash.
|
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -1346,6 +1346,42 @@ are `src/test/auth/cell_crud_parity.db.test.ts`
|
|
|
1346
1346
|
complete action list plus its own spec. Daemon-token-gated like its siblings;
|
|
1347
1347
|
the Rust mirror is `fuz_testing::create_testing_action_manifest_action_spec`.
|
|
1348
1348
|
|
|
1349
|
+
### Token-scope surface parity — `cross_backend/token_scope_surface.ts`
|
|
1350
|
+
|
|
1351
|
+
`describe_token_scope_surface_cross_tests({setup_test, capabilities, rpc_path?,
|
|
1352
|
+
sse_path?})` — the `surface:<name>` twin of the conformance slate's
|
|
1353
|
+
`token_scope_cases`, which cover only the `rpc:<method>` arm. Token scoping's
|
|
1354
|
+
RPC-only rule (_a narrowed api token reaches no non-RPC surface_) is the
|
|
1355
|
+
load-bearing half of the design and had **no** cross-impl gate: the schema gate
|
|
1356
|
+
can't see it (no column), the action-manifest gate can't see it (no method), and
|
|
1357
|
+
the spec-derived suites can't see it (REST routes, off the declared RPC surface).
|
|
1358
|
+
|
|
1359
|
+
Mints a narrowed bearer through the production `account_token_create` path and
|
|
1360
|
+
fires it at the two surfaces whose denial **body** is observable over plain
|
|
1361
|
+
HTTP — the audit SSE stream (`capabilities.sse`) and the admin-only bare-hash
|
|
1362
|
+
fact read (`capabilities.fact_serving`) — asserting the exact flat
|
|
1363
|
+
`{error: 'token_scope_required', required_scope: 'surface:<name>'}` both spines
|
|
1364
|
+
contract on (`token_scope_denied_body` ↔
|
|
1365
|
+
`fuz_auth::token_scope_surface_denied_response`).
|
|
1366
|
+
|
|
1367
|
+
The fifth case is the one with no prior pin anywhere: **scope outranks role**. A
|
|
1368
|
+
narrowed token on an account that _also_ lacks the gating role must hear
|
|
1369
|
+
`token_scope_required`, not `insufficient_permissions` — the observable the
|
|
1370
|
+
TS↔Rust ordering divergence produced before both spines converged on running the
|
|
1371
|
+
surface gate ahead of the role gate. Every other scoped-token probe uses the
|
|
1372
|
+
keeper's token, whose account holds the role, so both orderings look identical
|
|
1373
|
+
there; that is why the divergence survived as long as it did. Verified to
|
|
1374
|
+
discriminate: dropping the route's `required_scope` turns it into a 403
|
|
1375
|
+
`insufficient_permissions` + `required_roles`, exactly the pre-convergence shape.
|
|
1376
|
+
|
|
1377
|
+
Two non-vacuity controls: the narrowed token must still reach the RPC method it
|
|
1378
|
+
_does_ name, and a full bearer must get past the scope gate on the same route.
|
|
1379
|
+
The WS upgrade is deliberately omitted — `create_ws_transport` threads cookies,
|
|
1380
|
+
not bearer headers, and a refused upgrade's body isn't readable, so it can't
|
|
1381
|
+
serve a body-parity gate (its per-spine coverage stays in the two surface
|
|
1382
|
+
censuses). Cross-process only; fuz_app's own wiring is
|
|
1383
|
+
`src/test/cross_backend/token_scope_surface.cross.test.ts`.
|
|
1384
|
+
|
|
1349
1385
|
### Origin verification parity — `cross_backend/origin.ts`
|
|
1350
1386
|
|
|
1351
1387
|
`describe_origin_cross_tests({setup_test, capabilities, rpc_path?})` — the
|
|
@@ -1396,9 +1432,9 @@ read) it fires three principals over real HTTP: **anonymous** → 401, **session
|
|
|
1396
1432
|
proving the daemon-token gate that fences each backdoor action holds end-to-end
|
|
1397
1433
|
on the real dispatcher (the spec-derived `describe_rpc_attack_surface_tests`
|
|
1398
1434
|
never enumerates them because they're off the declared surface). Each method is
|
|
1399
|
-
sent with **valid** params so
|
|
1400
|
-
|
|
1401
|
-
|
|
1435
|
+
sent with **valid** params so each case varies only the credential (validation
|
|
1436
|
+
runs after the gates — order is 401 → authz → 403 → 400); the handler never
|
|
1437
|
+
runs. Cited property: `docs/security.md`
|
|
1402
1438
|
§Test Backdoor Actions. Cross-process only (the `_testing_*` actions are
|
|
1403
1439
|
mounted on the spawned binary, not the in-process app — like the ws/sse
|
|
1404
1440
|
suites); ungated, since every cross backend that uses
|
|
@@ -141,7 +141,7 @@ export const ConformanceCaseExpectation = z.strictObject({
|
|
|
141
141
|
description: 'Expected error reason — pass the IMPORTED `ERROR_*` constant from ' +
|
|
142
142
|
'`http/error_schemas.ts`, never a string literal. Asserted against the RPC ' +
|
|
143
143
|
'`error.data.reason` (when the denial carries one) or the REST flat-body ' +
|
|
144
|
-
'`error` field. The pre-
|
|
144
|
+
'`error` field. The pre-authorization 401 carries `data.reason` too; a denial ' +
|
|
145
145
|
'that genuinely omits it falls back to the `status` assertion to pin the class.'
|
|
146
146
|
}),
|
|
147
147
|
fields: z
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing_backdoor.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_backdoor.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"testing_backdoor.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_backdoor.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA4D9B,OAAO,KAAK,EAAE,wBAAwB,EAAe,MAAM,YAAY,CAAC;AAqExE,kEAAkE;AAClE,MAAM,MAAM,+BAA+B,GAAG,wBAAwB,CAAC;AAEvE,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAiCF,CAAC"}
|
|
@@ -19,7 +19,7 @@ import '../assert_dev_env.js';
|
|
|
19
19
|
*
|
|
20
20
|
* For every backdoor method, three principals:
|
|
21
21
|
*
|
|
22
|
-
* - **anonymous** (no credential) → `401` (pre-
|
|
22
|
+
* - **anonymous** (no credential) → `401` (pre-authorization auth refuses an
|
|
23
23
|
* account-less caller before anything else).
|
|
24
24
|
* - **session** (the keeper's browser-context cookie) → `403`
|
|
25
25
|
* `credential_type_required` — a session cookie, even one carrying the
|
|
@@ -28,10 +28,11 @@ import '../assert_dev_env.js';
|
|
|
28
28
|
* `credential_type_required` — same ceiling; an api token cannot reach
|
|
29
29
|
* keeper operations.
|
|
30
30
|
*
|
|
31
|
-
* Each method is sent with **valid** params so
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* handler never runs (the gate refuses first), so the writes
|
|
31
|
+
* Each method is sent with **valid** params so each case varies only the
|
|
32
|
+
* credential. (Validation runs after the gates — the order is 401 → authz →
|
|
33
|
+
* 403 → 400 — so the shapes are belt-and-suspenders here rather than load-
|
|
34
|
+
* bearing.) The handler never runs (the gate refuses first), so the writes
|
|
35
|
+
* never execute.
|
|
35
36
|
*
|
|
36
37
|
* Complements the spec-level gate check (which pins that each spec *declares*
|
|
37
38
|
* `credential_types: ['daemon_token']`) and the surface-absence invariant
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
import type { RpcPathCrossSuiteOptions } from './setup.js';
|
|
3
|
+
/** Options for the token-scope surface parity suite. */
|
|
4
|
+
export interface TokenScopeSurfaceCrossTestOptions extends RpcPathCrossSuiteOptions {
|
|
5
|
+
/** Audit-log SSE path. Default `/api/admin/audit/stream`. */
|
|
6
|
+
readonly sse_path?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const describe_token_scope_surface_cross_tests: (options: TokenScopeSurfaceCrossTestOptions) => void;
|
|
9
|
+
//# sourceMappingURL=token_scope_surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token_scope_surface.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/token_scope_surface.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAiE9B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAkB3D,wDAAwD;AACxD,MAAM,WAAW,iCAAkC,SAAQ,wBAAwB;IAClF,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AA2DD,eAAO,MAAM,wCAAwC,GACpD,SAAS,iCAAiC,KACxC,IAwHF,CAAC"}
|