@fuzdev/fuz_app 0.53.0 → 0.55.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 +68 -13
- package/dist/actions/action_codegen.d.ts +13 -0
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +15 -1
- package/dist/actions/action_rpc.d.ts +60 -7
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +158 -44
- package/dist/actions/register_action_ws.d.ts +4 -4
- package/dist/actions/register_action_ws.js +6 -6
- package/dist/actions/register_ws_endpoint.d.ts +20 -7
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +30 -5
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +0 -4
- package/dist/auth/CLAUDE.md +230 -63
- package/dist/auth/account_actions.d.ts +6 -6
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +8 -11
- package/dist/auth/account_queries.d.ts +6 -3
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +14 -5
- package/dist/auth/account_routes.d.ts +7 -10
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +70 -23
- package/dist/auth/account_schema.d.ts +19 -0
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +20 -0
- package/dist/auth/admin_action_specs.d.ts +45 -11
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +23 -8
- package/dist/auth/admin_actions.d.ts +8 -7
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +11 -18
- package/dist/auth/audit_log_queries.d.ts +53 -14
- package/dist/auth/audit_log_queries.d.ts.map +1 -1
- package/dist/auth/audit_log_queries.js +45 -2
- package/dist/auth/audit_log_schema.d.ts +55 -1
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +19 -3
- package/dist/auth/bearer_auth.d.ts +9 -7
- package/dist/auth/bearer_auth.d.ts.map +1 -1
- package/dist/auth/bearer_auth.js +13 -21
- package/dist/auth/cleanup.d.ts.map +1 -1
- package/dist/auth/cleanup.js +5 -0
- package/dist/auth/daemon_token_middleware.d.ts +23 -11
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
- package/dist/auth/daemon_token_middleware.js +26 -20
- package/dist/auth/deps.d.ts +14 -0
- package/dist/auth/deps.d.ts.map +1 -1
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +4 -2
- package/dist/auth/migrations.d.ts +15 -7
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +15 -7
- package/dist/auth/permit_offer_action_specs.d.ts +45 -6
- package/dist/auth/permit_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/permit_offer_action_specs.js +38 -7
- package/dist/auth/permit_offer_actions.d.ts +2 -2
- package/dist/auth/permit_offer_actions.d.ts.map +1 -1
- package/dist/auth/permit_offer_actions.js +106 -95
- package/dist/auth/permit_offer_notifications.d.ts +10 -0
- package/dist/auth/permit_offer_notifications.d.ts.map +1 -1
- package/dist/auth/permit_offer_queries.d.ts +68 -9
- package/dist/auth/permit_offer_queries.d.ts.map +1 -1
- package/dist/auth/permit_offer_queries.js +147 -35
- package/dist/auth/permit_offer_schema.d.ts +23 -1
- package/dist/auth/permit_offer_schema.d.ts.map +1 -1
- package/dist/auth/permit_offer_schema.js +5 -0
- package/dist/auth/permit_queries.d.ts +17 -5
- package/dist/auth/permit_queries.d.ts.map +1 -1
- package/dist/auth/permit_queries.js +19 -8
- package/dist/auth/request_context.d.ts +360 -32
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +442 -60
- package/dist/auth/route_guards.d.ts +10 -4
- package/dist/auth/route_guards.d.ts.map +1 -1
- package/dist/auth/route_guards.js +14 -8
- package/dist/auth/self_service_role_action_specs.d.ts +2 -0
- package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
- package/dist/auth/self_service_role_action_specs.js +2 -0
- package/dist/auth/self_service_role_actions.d.ts +6 -5
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +32 -19
- package/dist/db/migrate.d.ts +11 -7
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +9 -6
- package/dist/dev/setup.d.ts.map +1 -1
- package/dist/dev/setup.js +5 -3
- package/dist/hono_context.d.ts +77 -0
- package/dist/hono_context.d.ts.map +1 -1
- package/dist/hono_context.js +50 -0
- package/dist/http/CLAUDE.md +80 -17
- package/dist/http/error_schemas.d.ts +92 -1
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +73 -16
- package/dist/http/jsonrpc_errors.d.ts +27 -2
- package/dist/http/jsonrpc_errors.d.ts.map +1 -1
- package/dist/http/jsonrpc_errors.js +26 -2
- package/dist/http/route_spec.d.ts +62 -4
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/route_spec.js +117 -21
- package/dist/http/schema_helpers.d.ts +13 -1
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +21 -2
- package/dist/http/surface.d.ts +10 -1
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +2 -2
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +11 -1
- package/dist/testing/CLAUDE.md +23 -17
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +15 -13
- package/dist/testing/adversarial_headers.js +1 -1
- package/dist/testing/app_server.js +2 -2
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +21 -7
- package/dist/testing/auth_apps.d.ts.map +1 -1
- package/dist/testing/auth_apps.js +6 -3
- package/dist/testing/entities.d.ts +2 -1
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +1 -0
- package/dist/testing/integration_helpers.d.ts +4 -2
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +9 -5
- package/dist/testing/middleware.d.ts +12 -8
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +67 -25
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +3 -1
- package/dist/testing/schema_generators.d.ts.map +1 -1
- package/dist/testing/schema_generators.js +12 -0
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +5 -1
- package/dist/ui/CLAUDE.md +16 -10
- package/dist/ui/PermitOfferForm.svelte +14 -0
- package/dist/ui/PermitOfferForm.svelte.d.ts +6 -0
- package/dist/ui/PermitOfferForm.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.d.ts +8 -1
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +14 -3
- package/dist/ui/permit_offers_state.svelte.d.ts +9 -1
- package/dist/ui/permit_offers_state.svelte.d.ts.map +1 -1
- package/dist/ui/permit_offers_state.svelte.js +7 -1
- package/package.json +1 -1
package/dist/http/route_spec.js
CHANGED
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { DEV } from 'esm-env';
|
|
16
16
|
import { ERROR_INVALID_JSON_BODY, ERROR_INVALID_REQUEST_BODY, ERROR_INVALID_ROUTE_PARAMS, ERROR_INVALID_QUERY_PARAMS, } from './error_schemas.js';
|
|
17
|
-
import { ThrownJsonrpcError,
|
|
17
|
+
import { ThrownJsonrpcError, jsonrpc_error_code_to_http_status, jsonrpc_error_code_to_name, } from './jsonrpc_errors.js';
|
|
18
|
+
import { CACHED_REQUEST_BODY_KEY } from '../hono_context.js';
|
|
18
19
|
import { is_null_schema, merge_error_schemas } from './schema_helpers.js';
|
|
19
20
|
/**
|
|
20
21
|
* Get validated input from the Hono context.
|
|
@@ -63,12 +64,30 @@ const create_input_validation = (input_schema, method) => {
|
|
|
63
64
|
if (is_null_schema(input_schema))
|
|
64
65
|
return [];
|
|
65
66
|
const validate = async (c, next) => {
|
|
67
|
+
// Prefer the cached parse result written by `read_raw_acting`
|
|
68
|
+
// (the dispatcher's `acting` extractor). The cache decouples
|
|
69
|
+
// us from Hono's internal `bodyCache` — Hono keeps the body
|
|
70
|
+
// text alive across multiple `c.req.json()` calls but still
|
|
71
|
+
// re-runs `JSON.parse` each time, so caching the parsed value
|
|
72
|
+
// saves work and pins behavior to fuz_app code rather than to
|
|
73
|
+
// undocumented Hono internals.
|
|
74
|
+
// Hono's `c.get()` types this as the variable-map entry, but at
|
|
75
|
+
// runtime it returns `undefined` when no setter has run for this
|
|
76
|
+
// request. Narrow defensively.
|
|
77
|
+
const cached = c.get(CACHED_REQUEST_BODY_KEY);
|
|
66
78
|
let body;
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
if (cached !== undefined) {
|
|
80
|
+
if (!cached.ok)
|
|
81
|
+
return c.json({ error: ERROR_INVALID_JSON_BODY }, 400);
|
|
82
|
+
body = cached.body;
|
|
69
83
|
}
|
|
70
|
-
|
|
71
|
-
|
|
84
|
+
else {
|
|
85
|
+
try {
|
|
86
|
+
body = await c.req.json();
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return c.json({ error: ERROR_INVALID_JSON_BODY }, 400);
|
|
90
|
+
}
|
|
72
91
|
}
|
|
73
92
|
if (typeof body !== 'object' || body === null || Array.isArray(body)) {
|
|
74
93
|
return c.json({ error: ERROR_INVALID_JSON_BODY }, 400);
|
|
@@ -192,10 +211,29 @@ export const apply_middleware_specs = (app, specs) => {
|
|
|
192
211
|
/**
|
|
193
212
|
* Wrap a handler with error catch logic.
|
|
194
213
|
*
|
|
195
|
-
* Catches `ThrownJsonrpcError` and maps to
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
214
|
+
* Catches `ThrownJsonrpcError` and maps it to a flat REST `ApiError` body
|
|
215
|
+
* (`{error: <reason>, message?, ...rest_data}`) at the matching HTTP status.
|
|
216
|
+
* Catches generic `Error` and maps to `{error: 'internal_error', message?}`
|
|
217
|
+
* at 500 (`message` populated only in DEV). Existing handlers that return
|
|
218
|
+
* `c.json()` directly are unaffected — the catch layer only activates when
|
|
219
|
+
* something is thrown.
|
|
220
|
+
*
|
|
221
|
+
* The flat shape matches what middleware and direct handler emissions
|
|
222
|
+
* produce (e.g. `c.json({error: ERROR_FOO}, status)`,
|
|
223
|
+
* `c.json(failure.body, status)` from the dispatcher's authorization phase),
|
|
224
|
+
* so REST callers see one error envelope across every emit site. The
|
|
225
|
+
* `<reason>` string comes from `err.data.reason` when set (consumer-supplied
|
|
226
|
+
* canonical reason code) or from `jsonrpc_error_code_to_name(err.code)`
|
|
227
|
+
* (the JSON-RPC error name — `'not_found'`, `'forbidden'`, etc.). Other
|
|
228
|
+
* `data` fields flatten alongside `error` so diagnostic data is visible
|
|
229
|
+
* to clients without descending an envelope.
|
|
230
|
+
*
|
|
231
|
+
* The JSON-RPC code is intentionally **not** carried on the REST body —
|
|
232
|
+
* REST callers key on HTTP status + `error` reason, and the JSON-RPC code
|
|
233
|
+
* is recoverable via `http_status_to_jsonrpc_error_code(status)` on the
|
|
234
|
+
* rare consumer that wants it. Keeping the shape transport-shaped (REST
|
|
235
|
+
* emits ApiError; JSON-RPC dispatcher emits the JSON-RPC envelope) avoids
|
|
236
|
+
* a hybrid envelope that has to be normalized on the way out.
|
|
199
237
|
*/
|
|
200
238
|
const wrap_error_catch = (handler, log) => {
|
|
201
239
|
return async (c, next) => {
|
|
@@ -205,25 +243,72 @@ const wrap_error_catch = (handler, log) => {
|
|
|
205
243
|
catch (err) {
|
|
206
244
|
if (err instanceof ThrownJsonrpcError) {
|
|
207
245
|
const status = jsonrpc_error_code_to_http_status(err.code);
|
|
208
|
-
|
|
209
|
-
if (err.data !== undefined)
|
|
210
|
-
error.data = err.data;
|
|
211
|
-
return c.json({ error }, status);
|
|
246
|
+
return c.json(build_rest_error_body(err), status);
|
|
212
247
|
}
|
|
213
248
|
// generic error — internal_error
|
|
214
249
|
log.error('Unhandled handler error', err);
|
|
215
|
-
const
|
|
216
|
-
|
|
250
|
+
const body = { error: 'internal_error' };
|
|
251
|
+
if (DEV && err instanceof Error)
|
|
252
|
+
body.message = err.message;
|
|
253
|
+
return c.json(body, 500);
|
|
217
254
|
}
|
|
218
255
|
};
|
|
219
256
|
};
|
|
257
|
+
/**
|
|
258
|
+
* Build the REST body for a thrown `ThrownJsonrpcError`. Splits out
|
|
259
|
+
* for unit-test directness and keeps the catch handler readable.
|
|
260
|
+
*
|
|
261
|
+
* Reason resolution order:
|
|
262
|
+
* 1. `err.data.reason` (consumer-supplied canonical reason — overrides code-derived name)
|
|
263
|
+
* 2. `jsonrpc_error_code_to_name(err.code)` (e.g. -32003 → `'not_found'`)
|
|
264
|
+
*
|
|
265
|
+
* Remaining `err.data` fields (everything except `reason`) flatten under
|
|
266
|
+
* the body. Non-object `data` is dropped — we don't want a primitive
|
|
267
|
+
* `data` to overwrite the structured shape.
|
|
268
|
+
*/
|
|
269
|
+
const build_rest_error_body = (err) => {
|
|
270
|
+
let reason;
|
|
271
|
+
const rest = {};
|
|
272
|
+
if (err.data !== null &&
|
|
273
|
+
typeof err.data === 'object' &&
|
|
274
|
+
!Array.isArray(err.data) &&
|
|
275
|
+
typeof err.data.reason === 'string') {
|
|
276
|
+
const { reason: data_reason, ...other } = err.data;
|
|
277
|
+
reason = data_reason;
|
|
278
|
+
Object.assign(rest, other);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
reason = jsonrpc_error_code_to_name(err.code);
|
|
282
|
+
if (err.data !== null && typeof err.data === 'object' && !Array.isArray(err.data)) {
|
|
283
|
+
Object.assign(rest, err.data);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const body = { error: reason, ...rest };
|
|
287
|
+
if (err.message && err.message !== reason)
|
|
288
|
+
body.message = err.message;
|
|
289
|
+
return body;
|
|
290
|
+
};
|
|
220
291
|
/**
|
|
221
292
|
* Apply route specs to a Hono app.
|
|
222
293
|
*
|
|
223
294
|
* For each spec: resolves auth to guards via the provided resolver,
|
|
224
295
|
* adds input validation middleware (for routes with non-null input schemas),
|
|
225
|
-
*
|
|
226
|
-
*
|
|
296
|
+
* runs the optional authorization phase to resolve the acting actor + build
|
|
297
|
+
* the request context, wraps handler with DEV-only output and error
|
|
298
|
+
* validation, wraps with error catch layer (catches `ThrownJsonrpcError`
|
|
299
|
+
* and generic errors), and registers the route.
|
|
300
|
+
*
|
|
301
|
+
* Per-route middleware order: params → query → pre-validation auth
|
|
302
|
+
* guards (401) → authorization phase → post-authorization auth guards
|
|
303
|
+
* (403) → input validation → handler. The 401 check runs before any
|
|
304
|
+
* body parsing so unauthenticated callers never see route-shape
|
|
305
|
+
* information from parse failures. The authorization phase runs before
|
|
306
|
+
* input validation (matches the RPC dispatcher's order) so role /
|
|
307
|
+
* keeper denials surface 403 before 400 invalid_params; it extracts
|
|
308
|
+
* `acting` from raw query (GET) or pre-parsed JSON body (POST/PUT/...)
|
|
309
|
+
* — Hono caches the parsed body internally so the subsequent input-
|
|
310
|
+
* validation step does not re-parse. The role / keeper guards consume
|
|
311
|
+
* the `RequestContext` populated by the authorization phase.
|
|
227
312
|
*
|
|
228
313
|
* Each handler receives a `RouteContext` with:
|
|
229
314
|
* - `db`: transaction-scoped (for non-GET) or pool-level (for GET)
|
|
@@ -231,11 +316,12 @@ const wrap_error_catch = (handler, log) => {
|
|
|
231
316
|
* - `pending_effects`: fire-and-forget effect queue
|
|
232
317
|
*
|
|
233
318
|
* @param resolve_auth_guards - maps `RouteAuth` to middleware — use `fuz_auth_guard_resolver` from `auth/route_guards.ts`
|
|
319
|
+
* @param authorize - optional authorization phase; runs between guards and input validation
|
|
234
320
|
* @param db - used for transaction wrapping and `RouteContext`
|
|
235
321
|
* @mutates `app`
|
|
236
322
|
* @throws Error if two specs share the same `method` + `path` (each combination must be unique)
|
|
237
323
|
*/
|
|
238
|
-
export const apply_route_specs = (app, specs, resolve_auth_guards, log, db) => {
|
|
324
|
+
export const apply_route_specs = (app, specs, resolve_auth_guards, log, db, authorize, is_acting_aware) => {
|
|
239
325
|
const registered = new Set();
|
|
240
326
|
for (const spec of specs) {
|
|
241
327
|
const route_key = `${spec.method} ${spec.path}`;
|
|
@@ -243,11 +329,21 @@ export const apply_route_specs = (app, specs, resolve_auth_guards, log, db) => {
|
|
|
243
329
|
throw new Error(`Duplicate route: ${route_key} — each method+path combination must be unique`);
|
|
244
330
|
}
|
|
245
331
|
registered.add(route_key);
|
|
246
|
-
const
|
|
332
|
+
const { pre_validation: pre_validation_guards, post_authorization: post_authorization_guards } = resolve_auth_guards(spec.auth);
|
|
247
333
|
const params_validation = create_params_validation(spec.params);
|
|
248
334
|
const query_validation = create_query_validation(spec.query);
|
|
249
335
|
const input_validation = create_input_validation(spec.input, spec.method);
|
|
250
|
-
const merged_errors = merge_error_schemas(spec);
|
|
336
|
+
const merged_errors = merge_error_schemas(spec, null, is_acting_aware?.(spec) ?? false);
|
|
337
|
+
const authorization = authorize
|
|
338
|
+
? [
|
|
339
|
+
async (c, next) => {
|
|
340
|
+
const response = await authorize(c, spec);
|
|
341
|
+
if (response)
|
|
342
|
+
return response;
|
|
343
|
+
await next();
|
|
344
|
+
},
|
|
345
|
+
]
|
|
346
|
+
: [];
|
|
251
347
|
// Step 1: adapt RouteHandler → Handler (construct RouteContext, call spec.handler)
|
|
252
348
|
const use_transaction = spec.transaction ?? spec.method !== 'GET';
|
|
253
349
|
const inner = spec.handler;
|
|
@@ -258,7 +354,7 @@ export const apply_route_specs = (app, specs, resolve_auth_guards, log, db) => {
|
|
|
258
354
|
handler = wrap_output_validation(handler, spec.output, merged_errors, log);
|
|
259
355
|
// Step 3: error catch layer
|
|
260
356
|
handler = wrap_error_catch(handler, log);
|
|
261
|
-
app.on(spec.method, [spec.path], ...
|
|
357
|
+
app.on(spec.method, [spec.path], ...params_validation, ...query_validation, ...pre_validation_guards, ...authorization, ...post_authorization_guards, ...input_validation, handler);
|
|
262
358
|
}
|
|
263
359
|
};
|
|
264
360
|
/**
|
|
@@ -55,7 +55,19 @@ export declare const middleware_applies: (mw_path: string, route_path: string) =
|
|
|
55
55
|
* Merge order: derived -> middleware -> explicit route errors.
|
|
56
56
|
* Later layers override earlier ones for the same status code.
|
|
57
57
|
*
|
|
58
|
+
* `acting_aware` flows through to `derive_error_schemas` so routes whose
|
|
59
|
+
* input declares `acting?: ActingActor` (or whose auth requires permits)
|
|
60
|
+
* pick up the actor-failure error shapes the dispatcher's authorization
|
|
61
|
+
* phase may emit. The flag is computed at the call site rather than here
|
|
62
|
+
* because the `acting`-detection helper lives in `auth/` (it depends on
|
|
63
|
+
* the canonical `ActingActor` schema for reference equality, and `http/`
|
|
64
|
+
* stays auth-agnostic). See `http/CLAUDE.md` § Three-layer error-schema
|
|
65
|
+
* merge.
|
|
66
|
+
*
|
|
58
67
|
* @param spec - the route spec (needs `auth`, `input`, `params`, `rate_limit`, `errors`)
|
|
68
|
+
* @param middleware_errors - errors contributed by middleware whose path matches the route
|
|
69
|
+
* @param acting_aware - whether the dispatcher's authorization phase may emit
|
|
70
|
+
* actor-failure errors on this route
|
|
59
71
|
* @returns merged error schemas, or `null` if empty
|
|
60
72
|
*/
|
|
61
73
|
export declare const merge_error_schemas: (spec: {
|
|
@@ -65,5 +77,5 @@ export declare const merge_error_schemas: (spec: {
|
|
|
65
77
|
query?: z.ZodObject;
|
|
66
78
|
rate_limit?: RateLimitKey;
|
|
67
79
|
errors?: RouteErrorSchemas;
|
|
68
|
-
}, middleware_errors?: RouteErrorSchemas | null) => RouteErrorSchemas | null;
|
|
80
|
+
}, middleware_errors?: RouteErrorSchemas | null, acting_aware?: boolean) => RouteErrorSchemas | null;
|
|
69
81
|
//# sourceMappingURL=schema_helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/schema_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAuB,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAEnG;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACe,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAQrD,CAAC;AAoBF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAQxE,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"schema_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/schema_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAuB,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAEnG;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAAsC,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OACe,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAQrD,CAAC;AAoBF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,OAQxE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM;IACL,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC3B,EACD,oBAAoB,iBAAiB,GAAG,IAAI,EAC5C,sBAAoB,KAClB,iBAAiB,GAAG,IAWtB,CAAC"}
|
|
@@ -94,11 +94,30 @@ export const middleware_applies = (mw_path, route_path) => {
|
|
|
94
94
|
* Merge order: derived -> middleware -> explicit route errors.
|
|
95
95
|
* Later layers override earlier ones for the same status code.
|
|
96
96
|
*
|
|
97
|
+
* `acting_aware` flows through to `derive_error_schemas` so routes whose
|
|
98
|
+
* input declares `acting?: ActingActor` (or whose auth requires permits)
|
|
99
|
+
* pick up the actor-failure error shapes the dispatcher's authorization
|
|
100
|
+
* phase may emit. The flag is computed at the call site rather than here
|
|
101
|
+
* because the `acting`-detection helper lives in `auth/` (it depends on
|
|
102
|
+
* the canonical `ActingActor` schema for reference equality, and `http/`
|
|
103
|
+
* stays auth-agnostic). See `http/CLAUDE.md` § Three-layer error-schema
|
|
104
|
+
* merge.
|
|
105
|
+
*
|
|
97
106
|
* @param spec - the route spec (needs `auth`, `input`, `params`, `rate_limit`, `errors`)
|
|
107
|
+
* @param middleware_errors - errors contributed by middleware whose path matches the route
|
|
108
|
+
* @param acting_aware - whether the dispatcher's authorization phase may emit
|
|
109
|
+
* actor-failure errors on this route
|
|
98
110
|
* @returns merged error schemas, or `null` if empty
|
|
99
111
|
*/
|
|
100
|
-
export const merge_error_schemas = (spec, middleware_errors) => {
|
|
101
|
-
const derived = derive_error_schemas(
|
|
112
|
+
export const merge_error_schemas = (spec, middleware_errors, acting_aware = false) => {
|
|
113
|
+
const derived = derive_error_schemas({
|
|
114
|
+
auth: spec.auth,
|
|
115
|
+
has_input: !is_null_schema(spec.input),
|
|
116
|
+
has_params: !!spec.params,
|
|
117
|
+
has_query: !!spec.query,
|
|
118
|
+
rate_limit: spec.rate_limit,
|
|
119
|
+
acting_aware,
|
|
120
|
+
});
|
|
102
121
|
const merged = { ...derived, ...middleware_errors, ...spec.errors };
|
|
103
122
|
return Object.keys(merged).length > 0 ? merged : null;
|
|
104
123
|
};
|
package/dist/http/surface.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { z } from 'zod';
|
|
10
10
|
import type { EventSpec } from '../realtime/sse.js';
|
|
11
11
|
import type { MiddlewareSpec } from './middleware_spec.js';
|
|
12
|
-
import type { RouteAuth, RouteSpec } from './route_spec.js';
|
|
12
|
+
import type { IsActingAware, RouteAuth, RouteSpec } from './route_spec.js';
|
|
13
13
|
import type { RateLimitKey, RouteErrorSchemas } from './error_schemas.js';
|
|
14
14
|
import type { RpcAction } from '../actions/action_rpc.js';
|
|
15
15
|
import type { Sensitivity } from '../sensitivity.js';
|
|
@@ -118,6 +118,15 @@ export interface GenerateAppSurfaceOptions {
|
|
|
118
118
|
env_schema?: z.ZodObject;
|
|
119
119
|
event_specs?: Array<EventSpec>;
|
|
120
120
|
rpc_endpoints?: Array<RpcEndpointSpec>;
|
|
121
|
+
/**
|
|
122
|
+
* Per-route predicate that decides whether the dispatcher's authorization
|
|
123
|
+
* phase may emit `actor_required` / `actor_not_on_account` (400) or
|
|
124
|
+
* `no_actors_on_account` / `account_vanished` (500) on this spec. Mirrors
|
|
125
|
+
* the parameter on `apply_route_specs` so the surface exposes the same
|
|
126
|
+
* error shapes the live framework would emit. See `http/CLAUDE.md` §
|
|
127
|
+
* Three-layer error-schema merge.
|
|
128
|
+
*/
|
|
129
|
+
is_acting_aware?: IsActingAware;
|
|
121
130
|
}
|
|
122
131
|
/**
|
|
123
132
|
* Collect error schemas from all middleware that applies to a route path.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/surface.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAC,SAAS,EAAE,SAAS,EAAC,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/surface.ts"],"names":[],"mappings":"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"}
|
package/dist/http/surface.js
CHANGED
|
@@ -61,7 +61,7 @@ export const events_to_surface = (event_specs) => {
|
|
|
61
61
|
* and optional env/event metadata.
|
|
62
62
|
*/
|
|
63
63
|
export const generate_app_surface = (options) => {
|
|
64
|
-
const { route_specs, middleware_specs, env_schema, event_specs, rpc_endpoints } = options;
|
|
64
|
+
const { route_specs, middleware_specs, env_schema, event_specs, rpc_endpoints, is_acting_aware } = options;
|
|
65
65
|
const diagnostics = [];
|
|
66
66
|
// Spec-level diagnostics: check for non-strict input schemas
|
|
67
67
|
for (const r of route_specs) {
|
|
@@ -98,7 +98,7 @@ export const generate_app_surface = (options) => {
|
|
|
98
98
|
.map((m) => m.name);
|
|
99
99
|
// Merge auto-derived + middleware + explicit error schemas
|
|
100
100
|
const mw_errors = collect_middleware_errors(middleware_specs, r.path);
|
|
101
|
-
const merged_errors = merge_error_schemas(r, mw_errors);
|
|
101
|
+
const merged_errors = merge_error_schemas(r, mw_errors, is_acting_aware?.(r) ?? false);
|
|
102
102
|
let error_schemas = null;
|
|
103
103
|
if (merged_errors) {
|
|
104
104
|
const schemas = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,IAAI,EAAE,KAAK,OAAO,EAAC,MAAM,MAAM,CAAC;AAGxC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,EAEN,KAAK,cAAc,EAEnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAGN,KAAK,WAAW,EAChB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAEhE,OAAO,EAKN,KAAK,WAAW,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EAA2B,KAAK,kBAAkB,EAAC,MAAM,aAAa,CAAC;AAE9E,OAAO,EAEN,KAAK,cAAc,EAEnB,KAAK,eAAe,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,
|
|
1
|
+
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,7 @@ import { check_bootstrap_status, create_bootstrap_route_specs, } from '../auth/b
|
|
|
27
27
|
import { create_surface_route_spec } from '../http/common_routes.js';
|
|
28
28
|
import { create_auth_middleware_specs } from '../auth/middleware.js';
|
|
29
29
|
import { fuz_auth_guard_resolver } from '../auth/route_guards.js';
|
|
30
|
+
import { create_fuz_authorization_handler, input_schema_declares_acting, is_actor_implying_auth, } from '../auth/request_context.js';
|
|
30
31
|
import { ERROR_PAYLOAD_TOO_LARGE } from '../http/error_schemas.js';
|
|
31
32
|
import { create_rpc_endpoint } from '../actions/action_rpc.js';
|
|
32
33
|
/** Default maximum request body size: 1 MiB. */
|
|
@@ -160,12 +161,20 @@ export const create_app_server = async (options) => {
|
|
|
160
161
|
...(options.event_specs ?? []),
|
|
161
162
|
...(audit_sse ? AUDIT_LOG_EVENT_SPECS : []),
|
|
162
163
|
];
|
|
164
|
+
// Per-route flag for the dispatcher's authorization-phase error shapes.
|
|
165
|
+
// Mirrors the runtime check in `apply_authorization_phase`: a route emits
|
|
166
|
+
// actor-failure errors when its input declares `acting?: ActingActor` or
|
|
167
|
+
// its auth requires permits. Routes that fail this check stay on the
|
|
168
|
+
// narrow derived schema (validation + auth shapes) so non-fuz_app HTTP
|
|
169
|
+
// frameworks aren't forced to surface fuz_app-specific error codes.
|
|
170
|
+
const fuz_is_acting_aware = (spec) => is_actor_implying_auth(spec.auth) || input_schema_declares_acting(spec.input);
|
|
163
171
|
const surface_spec = create_app_surface_spec({
|
|
164
172
|
middleware_specs: surface_middleware,
|
|
165
173
|
route_specs,
|
|
166
174
|
env_schema: options.env_schema,
|
|
167
175
|
event_specs: all_event_specs,
|
|
168
176
|
rpc_endpoints: resolved_rpc_endpoints,
|
|
177
|
+
is_acting_aware: fuz_is_acting_aware,
|
|
169
178
|
});
|
|
170
179
|
// Config-level diagnostics (concatenated after spec-level from generate_app_surface)
|
|
171
180
|
const config_diagnostics = [];
|
|
@@ -257,7 +266,8 @@ export const create_app_server = async (options) => {
|
|
|
257
266
|
}));
|
|
258
267
|
}
|
|
259
268
|
apply_middleware_specs(app, middleware_specs);
|
|
260
|
-
|
|
269
|
+
const authorize = create_fuz_authorization_handler({ db: deps.db });
|
|
270
|
+
apply_route_specs(app, route_specs, fuz_auth_guard_resolver, log, deps.db, authorize, fuz_is_acting_aware);
|
|
261
271
|
// Post-route middleware (before static serving)
|
|
262
272
|
if (options.post_route_middleware) {
|
|
263
273
|
apply_middleware_specs(app, options.post_route_middleware);
|
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -157,9 +157,13 @@ bind to the server's deps (db, keyring). Hono assembly is cheap
|
|
|
157
157
|
|
|
158
158
|
Pre-built Hono apps at each auth level (public / authed / keeper / per-role)
|
|
159
159
|
for attack-surface testing. No middleware stack — a single `/*` middleware
|
|
160
|
-
injects
|
|
161
|
-
`'session'`)
|
|
162
|
-
|
|
160
|
+
injects `ACCOUNT_ID_KEY` + `REQUEST_CONTEXT_KEY` + `CREDENTIAL_TYPE_KEY`
|
|
161
|
+
(default `'session'`) plus the `TEST_CONTEXT_PRESET_KEY` flag (so the
|
|
162
|
+
dispatcher's authorization phase trusts the pre-baked context and skips
|
|
163
|
+
its DB-backed actor resolution), then hands off to `apply_route_specs`
|
|
164
|
+
with `fuz_auth_guard_resolver` + `create_fuz_authorization_handler`.
|
|
165
|
+
Production middleware never sets `TEST_CONTEXT_PRESET_KEY`, so the escape
|
|
166
|
+
hatch is test-only by construction.
|
|
163
167
|
|
|
164
168
|
| Helper | Role |
|
|
165
169
|
| ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -389,22 +393,24 @@ test file that imports from `middleware.ts` gets these mocks globally.
|
|
|
389
393
|
Pair with `vi.restoreAllMocks()` in `afterEach` when mixing into
|
|
390
394
|
`.db.test.ts` files (see DB test caveat below).
|
|
391
395
|
|
|
392
|
-
| Helper | Role
|
|
393
|
-
| ----------------------------------------------------------------- |
|
|
394
|
-
| `BearerAuthTestOptions`, `BearerAuthTestCase` | Test-case table shape for the bearer auth runner.
|
|
395
|
-
| `create_bearer_auth_mocks(tc)` | Configures the module-level mocks per test case; returns spy references.
|
|
396
|
-
| `TEST_CLIENT_IP = '127.0.0.1'` | IP set by the proxy stub in `create_bearer_auth_test_app`.
|
|
397
|
-
| `create_bearer_auth_test_app(tc, ip_rate_limiter?)` | Hono app with bearer middleware + echo route at `/api/test` returning `{ok,
|
|
398
|
-
| `describe_bearer_auth_cases(suite_name, cases, ip_rate_limiter?)` | Table-driven runner — one `test()` per case; asserts status, error, body fields, `api_token_id`, context preservation.
|
|
399
|
-
| `TEST_MIDDLEWARE_PATH = '/api/test'` | Path used by the echo route in the stack factory.
|
|
400
|
-
| `create_test_middleware_stack_app(options?)` | Real proxy + origin + bearer middleware for integration-shape testing. Echo route returns `{ok, client_ip, has_context}`.
|
|
396
|
+
| Helper | Role |
|
|
397
|
+
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
398
|
+
| `BearerAuthTestOptions`, `BearerAuthTestCase` | Test-case table shape for the bearer auth runner. |
|
|
399
|
+
| `create_bearer_auth_mocks(tc)` | Configures the module-level mocks per test case; returns spy references. |
|
|
400
|
+
| `TEST_CLIENT_IP = '127.0.0.1'` | IP set by the proxy stub in `create_bearer_auth_test_app`. |
|
|
401
|
+
| `create_bearer_auth_test_app(tc, ip_rate_limiter?)` | Hono app with bearer middleware + echo route at `/api/test` returning `{ok, account_id, credential_type, api_token_id, request_context_set}` — the account-grain identity bearer auth writes, plus a flag for tests that pre-populate `REQUEST_CONTEXT_KEY` via `pre_context`. |
|
|
402
|
+
| `describe_bearer_auth_cases(suite_name, cases, ip_rate_limiter?)` | Table-driven runner — one `test()` per case; asserts status, error, body fields, `api_token_id`, context preservation. |
|
|
403
|
+
| `TEST_MIDDLEWARE_PATH = '/api/test'` | Path used by the echo route in the stack factory. |
|
|
404
|
+
| `create_test_middleware_stack_app(options?)` | Real proxy + origin + bearer middleware for integration-shape testing. Echo route returns `{ok, client_ip, has_context}`. |
|
|
401
405
|
|
|
402
406
|
The echo route under `create_bearer_auth_test_app` deliberately surfaces
|
|
403
|
-
every middleware-written context variable (`
|
|
404
|
-
`CREDENTIAL_TYPE_KEY`, `AUTH_API_TOKEN_ID_KEY`)
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
407
|
+
every middleware-written context variable (`ACCOUNT_ID_KEY`,
|
|
408
|
+
`CREDENTIAL_TYPE_KEY`, `AUTH_API_TOKEN_ID_KEY`) — bearer middleware
|
|
409
|
+
writes account-grain identity only; the dispatcher's authorization phase
|
|
410
|
+
owns `REQUEST_CONTEXT_KEY`. The `request_context_set` flag covers the
|
|
411
|
+
test-only `pre_context` injection path. When public auth surface gains a
|
|
412
|
+
new context variable, header, or field, update this echo alongside the
|
|
413
|
+
assertions in `src/test/auth/*.test.ts` — the two move together.
|
|
408
414
|
|
|
409
415
|
## Round-trip suites
|
|
410
416
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAgC7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAA0B,KAAK,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAEtF,OAAO,EAA6C,KAAK,eAAe,EAAC,MAAM,iBAAiB,CAAC;AACjG,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AASjB,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAgC7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAA0B,KAAK,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAEtF,OAAO,EAA6C,KAAK,eAAe,EAAC,MAAM,iBAAiB,CAAC;AACjG,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AASjB,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAoB1B;;GAEG;AACH,MAAM,WAAW,mCAAmC;IACnD,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,wDAAwD;IACxD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,4GAA4G;IAC5G,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAgCD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,mCAAmC,KAC1C,IA21BF,CAAC"}
|
|
@@ -38,7 +38,6 @@ import { permit_offer_create_action_spec, permit_revoke_action_spec, } from '../
|
|
|
38
38
|
import { admin_account_list_action_spec, admin_session_list_action_spec, admin_session_revoke_all_action_spec, admin_token_revoke_all_action_spec, audit_log_list_action_spec, audit_log_permit_history_action_spec, } from '../auth/admin_action_specs.js';
|
|
39
39
|
import { account_token_create_action_spec, account_verify_action_spec, } from '../auth/account_action_specs.js';
|
|
40
40
|
import { query_grant_permit } from '../auth/permit_queries.js';
|
|
41
|
-
import { query_actor_by_account } from '../auth/account_queries.js';
|
|
42
41
|
import { query_accept_offer } from '../auth/permit_offer_queries.js';
|
|
43
42
|
/**
|
|
44
43
|
* Pick a web-grantable role for testing, preferring a non-admin app-defined role.
|
|
@@ -153,7 +152,12 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
153
152
|
});
|
|
154
153
|
assert.ok(res.ok, `permit_offer_create failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
155
154
|
const { offer } = res.result;
|
|
156
|
-
const accept_result = await get_db().transaction(async (tx) => query_accept_offer({ db: tx }, {
|
|
155
|
+
const accept_result = await get_db().transaction(async (tx) => query_accept_offer({ db: tx }, {
|
|
156
|
+
offer_id: offer.id,
|
|
157
|
+
to_account_id: args.to_account_id,
|
|
158
|
+
actor_id: args.to_actor_id,
|
|
159
|
+
ip: null,
|
|
160
|
+
}));
|
|
157
161
|
return { offer_id: offer.id, permit_id: accept_result.permit.id };
|
|
158
162
|
};
|
|
159
163
|
// --- 1. Admin account listing (RPC) ---
|
|
@@ -165,7 +169,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
165
169
|
app: test_app.app,
|
|
166
170
|
path: rpc_path,
|
|
167
171
|
spec: admin_account_list_action_spec,
|
|
168
|
-
params:
|
|
172
|
+
params: {},
|
|
169
173
|
headers: test_app.create_session_headers(),
|
|
170
174
|
});
|
|
171
175
|
assert.ok(res.ok, `admin_account_list failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
@@ -183,7 +187,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
183
187
|
app: test_app.app,
|
|
184
188
|
path: rpc_path,
|
|
185
189
|
spec: admin_account_list_action_spec,
|
|
186
|
-
params:
|
|
190
|
+
params: {},
|
|
187
191
|
headers: test_app.create_session_headers(),
|
|
188
192
|
});
|
|
189
193
|
assert.ok(!res.ok, 'Expected admin_account_list to fail for non-admin');
|
|
@@ -207,7 +211,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
207
211
|
app: test_app.app,
|
|
208
212
|
path: rpc_path,
|
|
209
213
|
spec: admin_session_list_action_spec,
|
|
210
|
-
params:
|
|
214
|
+
params: {},
|
|
211
215
|
headers: test_app.create_session_headers(),
|
|
212
216
|
});
|
|
213
217
|
assert.ok(res.ok, `admin_session_list failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
@@ -358,6 +362,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
358
362
|
app: test_app.app,
|
|
359
363
|
admin_headers: test_app.create_session_headers(),
|
|
360
364
|
to_account_id: user_two.account.id,
|
|
365
|
+
to_actor_id: user_two.actor.id,
|
|
361
366
|
role: grantable_role,
|
|
362
367
|
});
|
|
363
368
|
const res = await rpc_call_for_spec({
|
|
@@ -376,10 +381,8 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
376
381
|
test('permit revoke creates audit event', async () => {
|
|
377
382
|
const test_app = await create_test_app(build_admin_test_app_options(options, get_db()));
|
|
378
383
|
const user_two = await test_app.create_account({ username: 'user_two' });
|
|
379
|
-
const target_actor = await query_actor_by_account({ db: get_db() }, user_two.account.id);
|
|
380
|
-
assert.ok(target_actor);
|
|
381
384
|
const permit = await query_grant_permit({ db: get_db() }, {
|
|
382
|
-
actor_id:
|
|
385
|
+
actor_id: user_two.actor.id,
|
|
383
386
|
role: grantable_role,
|
|
384
387
|
granted_by: test_app.backend.actor.id,
|
|
385
388
|
});
|
|
@@ -388,7 +391,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
388
391
|
app: test_app.app,
|
|
389
392
|
path: rpc_path,
|
|
390
393
|
spec: permit_revoke_action_spec,
|
|
391
|
-
params: { actor_id:
|
|
394
|
+
params: { actor_id: user_two.actor.id, permit_id: permit.id },
|
|
392
395
|
headers: test_app.create_session_headers(),
|
|
393
396
|
});
|
|
394
397
|
assert.ok(revoke_res.ok, `permit_revoke failed: ${revoke_res.ok ? '' : JSON.stringify(revoke_res.error)}`);
|
|
@@ -560,16 +563,15 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
560
563
|
app: test_app.app,
|
|
561
564
|
admin_headers: test_app.create_session_headers(),
|
|
562
565
|
to_account_id: user_two.account.id,
|
|
566
|
+
to_actor_id: user_two.actor.id,
|
|
563
567
|
role: grantable_role,
|
|
564
568
|
});
|
|
565
569
|
// 4. revoke permit (RPC)
|
|
566
|
-
const target_actor = await query_actor_by_account({ db: get_db() }, user_two.account.id);
|
|
567
|
-
assert.ok(target_actor);
|
|
568
570
|
const revoke_res = await rpc_call_for_spec({
|
|
569
571
|
app: test_app.app,
|
|
570
572
|
path: rpc_path,
|
|
571
573
|
spec: permit_revoke_action_spec,
|
|
572
|
-
params: { actor_id:
|
|
574
|
+
params: { actor_id: user_two.actor.id, permit_id },
|
|
573
575
|
headers: test_app.create_session_headers(),
|
|
574
576
|
});
|
|
575
577
|
assert.ok(revoke_res.ok, `permit_revoke failed: ${revoke_res.ok ? '' : JSON.stringify(revoke_res.error)}`);
|
|
@@ -727,7 +729,7 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
727
729
|
app: test_app.app,
|
|
728
730
|
path: rpc_path,
|
|
729
731
|
spec: admin_account_list_action_spec,
|
|
730
|
-
params:
|
|
732
|
+
params: {},
|
|
731
733
|
headers: create_headers(regular_user.session_cookie),
|
|
732
734
|
});
|
|
733
735
|
assert.ok(!res.ok, 'Expected admin_account_list to fail for non-admin');
|
|
@@ -112,7 +112,7 @@ export const describe_standard_adversarial_headers = (suite_name, options, allow
|
|
|
112
112
|
}
|
|
113
113
|
if (tc.expected_status === 200) {
|
|
114
114
|
assert.strictEqual(body.ok, true, 'expected ok to be true for 200 response');
|
|
115
|
-
assert.strictEqual(body.
|
|
115
|
+
assert.strictEqual(body.account_id, null, 'expected account_id to be null (no auth)');
|
|
116
116
|
}
|
|
117
117
|
if (tc.validate_expectation === 'not_called') {
|
|
118
118
|
assert.strictEqual(mock_validate.mock.calls.length, 0, 'validate should not have been called — middleware should short-circuit');
|
|
@@ -56,10 +56,10 @@ export const bootstrap_test_account = async (options) => {
|
|
|
56
56
|
for (const role of roles) {
|
|
57
57
|
await query_grant_permit(deps, { actor_id: actor.id, role, granted_by: null });
|
|
58
58
|
}
|
|
59
|
-
// Create API token
|
|
59
|
+
// Create API token (account-scoped — acting actor is per-request)
|
|
60
60
|
const { token: api_token, id: token_id, token_hash } = generate_api_token();
|
|
61
61
|
await query_create_api_token(deps, token_id, account.id, 'test-cli', token_hash);
|
|
62
|
-
// Create session
|
|
62
|
+
// Create session (account-scoped — acting actor is per-request)
|
|
63
63
|
const session_token = generate_session_token();
|
|
64
64
|
const session_hash = hash_session_token(session_token);
|
|
65
65
|
const expires_at = new Date(Date.now() + AUTH_SESSION_LIFETIME_MS);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit_completeness.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/audit_completeness.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAkB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAIrD,OAAO,EAGN,KAAK,eAAe,EAEpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAKjB,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"audit_completeness.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/audit_completeness.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAkB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAIrD,OAAO,EAGN,KAAK,eAAe,EAEpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAKjB,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAqB1B;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,wDAAwD;IACxD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE;;;;;;;;;;;OAWG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAoDD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,4BAA4B,KAAG,IA8fzF,CAAC"}
|