@fuzdev/fuz_app 0.29.0 → 0.31.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 +630 -0
- package/dist/actions/action_rpc.d.ts +29 -0
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +42 -6
- package/dist/actions/action_types.d.ts +2 -2
- package/dist/actions/cancel.d.ts +12 -13
- package/dist/actions/cancel.d.ts.map +1 -1
- package/dist/actions/cancel.js +10 -13
- package/dist/actions/heartbeat.d.ts +8 -13
- package/dist/actions/heartbeat.d.ts.map +1 -1
- package/dist/actions/heartbeat.js +5 -8
- package/dist/actions/register_action_ws.d.ts +3 -3
- package/dist/actions/register_action_ws.js +2 -2
- package/dist/actions/register_ws_endpoint.d.ts +4 -4
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +3 -3
- package/dist/actions/socket.svelte.d.ts +16 -16
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +15 -15
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.d.ts +15 -0
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +17 -0
- package/dist/auth/CLAUDE.md +923 -0
- package/dist/auth/account_action_specs.d.ts +216 -0
- package/dist/auth/account_action_specs.d.ts.map +1 -0
- package/dist/auth/account_action_specs.js +159 -0
- package/dist/auth/account_actions.d.ts +51 -0
- package/dist/auth/account_actions.d.ts.map +1 -0
- package/dist/auth/account_actions.js +119 -0
- package/dist/auth/account_queries.d.ts +6 -2
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +40 -4
- package/dist/auth/account_routes.d.ts +94 -16
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +108 -180
- package/dist/auth/account_schema.d.ts +85 -30
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +40 -8
- package/dist/auth/admin_action_specs.d.ts +674 -0
- package/dist/auth/admin_action_specs.d.ts.map +1 -0
- package/dist/auth/admin_action_specs.js +287 -0
- package/dist/auth/admin_actions.d.ts +69 -0
- package/dist/auth/admin_actions.d.ts.map +1 -0
- package/dist/auth/admin_actions.js +256 -0
- package/dist/auth/api_token.d.ts +10 -0
- package/dist/auth/api_token.d.ts.map +1 -1
- package/dist/auth/api_token.js +9 -0
- package/dist/auth/api_token_queries.d.ts +3 -3
- package/dist/auth/api_token_queries.js +3 -3
- package/dist/auth/app_settings_schema.d.ts +4 -3
- package/dist/auth/app_settings_schema.d.ts.map +1 -1
- package/dist/auth/app_settings_schema.js +2 -1
- package/dist/auth/audit_log_routes.d.ts +14 -6
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +22 -79
- package/dist/auth/audit_log_schema.d.ts +100 -29
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +83 -11
- package/dist/auth/bootstrap_routes.d.ts +14 -0
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +10 -3
- package/dist/auth/cleanup.d.ts +63 -0
- package/dist/auth/cleanup.d.ts.map +1 -0
- package/dist/auth/cleanup.js +80 -0
- package/dist/auth/invite_schema.d.ts +11 -10
- package/dist/auth/invite_schema.d.ts.map +1 -1
- package/dist/auth/invite_schema.js +4 -3
- package/dist/auth/migrations.d.ts +6 -0
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +28 -0
- package/dist/auth/permit_offer_action_specs.d.ts +364 -0
- package/dist/auth/permit_offer_action_specs.d.ts.map +1 -0
- package/dist/auth/permit_offer_action_specs.js +216 -0
- package/dist/auth/permit_offer_actions.d.ts +96 -0
- package/dist/auth/permit_offer_actions.d.ts.map +1 -0
- package/dist/auth/permit_offer_actions.js +428 -0
- package/dist/auth/permit_offer_notifications.d.ts +361 -0
- package/dist/auth/permit_offer_notifications.d.ts.map +1 -0
- package/dist/auth/permit_offer_notifications.js +179 -0
- package/dist/auth/permit_offer_queries.d.ts +165 -0
- package/dist/auth/permit_offer_queries.d.ts.map +1 -0
- package/dist/auth/permit_offer_queries.js +390 -0
- package/dist/auth/permit_offer_schema.d.ts +103 -0
- package/dist/auth/permit_offer_schema.d.ts.map +1 -0
- package/dist/auth/permit_offer_schema.js +142 -0
- package/dist/auth/permit_queries.d.ts +77 -14
- package/dist/auth/permit_queries.d.ts.map +1 -1
- package/dist/auth/permit_queries.js +119 -24
- package/dist/auth/session_queries.d.ts +4 -2
- package/dist/auth/session_queries.d.ts.map +1 -1
- package/dist/auth/session_queries.js +4 -2
- package/dist/auth/signup_routes.d.ts +13 -0
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +14 -7
- package/dist/http/CLAUDE.md +584 -0
- package/dist/http/pending_effects.d.ts +29 -0
- package/dist/http/pending_effects.d.ts.map +1 -0
- package/dist/http/pending_effects.js +31 -0
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/route_spec.js +4 -3
- package/dist/rate_limiter.d.ts +30 -0
- package/dist/rate_limiter.d.ts.map +1 -1
- package/dist/rate_limiter.js +25 -2
- package/dist/realtime/sse_auth_guard.d.ts +2 -0
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +5 -3
- package/dist/testing/CLAUDE.md +668 -1
- package/dist/testing/admin_integration.d.ts +10 -7
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +382 -482
- package/dist/testing/app_server.d.ts +7 -6
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/attack_surface.d.ts +9 -3
- package/dist/testing/attack_surface.d.ts.map +1 -1
- package/dist/testing/attack_surface.js +4 -4
- package/dist/testing/audit_completeness.d.ts +6 -0
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +158 -134
- package/dist/testing/auth_apps.d.ts.map +1 -1
- package/dist/testing/auth_apps.js +4 -33
- package/dist/testing/db.d.ts +1 -1
- package/dist/testing/db.d.ts.map +1 -1
- package/dist/testing/db.js +2 -0
- package/dist/testing/entities.d.ts +35 -13
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +17 -0
- package/dist/testing/integration.d.ts +10 -0
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +352 -340
- package/dist/testing/integration_helpers.d.ts +16 -5
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +24 -4
- package/dist/testing/rate_limiting.d.ts +7 -0
- package/dist/testing/rate_limiting.d.ts.map +1 -1
- package/dist/testing/rate_limiting.js +41 -10
- package/dist/testing/rpc_helpers.d.ts +153 -1
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +184 -8
- package/dist/testing/sse_round_trip.d.ts +8 -0
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +10 -3
- package/dist/testing/standard.d.ts +9 -1
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/standard.js +6 -2
- package/dist/testing/surface_invariants.d.ts +7 -3
- package/dist/testing/surface_invariants.d.ts.map +1 -1
- package/dist/testing/surface_invariants.js +5 -4
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +9 -38
- package/dist/ui/AccountSessions.svelte +8 -4
- package/dist/ui/AccountSessions.svelte.d.ts.map +1 -1
- package/dist/ui/AdminAccounts.svelte +61 -33
- package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
- package/dist/ui/AdminAuditLog.svelte +3 -2
- package/dist/ui/AdminAuditLog.svelte.d.ts.map +1 -1
- package/dist/ui/AdminInvites.svelte +3 -2
- package/dist/ui/AdminInvites.svelte.d.ts.map +1 -1
- package/dist/ui/AdminOverview.svelte +14 -9
- package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
- package/dist/ui/AdminPermitHistory.svelte +3 -2
- package/dist/ui/AdminPermitHistory.svelte.d.ts.map +1 -1
- package/dist/ui/AdminSessions.svelte +29 -25
- package/dist/ui/AdminSessions.svelte.d.ts.map +1 -1
- package/dist/ui/CLAUDE.md +351 -0
- package/dist/ui/OpenSignupToggle.svelte +6 -3
- package/dist/ui/OpenSignupToggle.svelte.d.ts.map +1 -1
- package/dist/ui/PermitOfferForm.svelte +141 -0
- package/dist/ui/PermitOfferForm.svelte.d.ts +14 -0
- package/dist/ui/PermitOfferForm.svelte.d.ts.map +1 -0
- package/dist/ui/PermitOfferHistory.svelte +109 -0
- package/dist/ui/PermitOfferHistory.svelte.d.ts +11 -0
- package/dist/ui/PermitOfferHistory.svelte.d.ts.map +1 -0
- package/dist/ui/PermitOfferInbox.svelte +121 -0
- package/dist/ui/PermitOfferInbox.svelte.d.ts +12 -0
- package/dist/ui/PermitOfferInbox.svelte.d.ts.map +1 -0
- package/dist/ui/account_sessions_state.svelte.d.ts +53 -3
- package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
- package/dist/ui/account_sessions_state.svelte.js +39 -16
- package/dist/ui/admin_accounts_state.svelte.d.ts +118 -2
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +99 -23
- package/dist/ui/admin_invites_state.svelte.d.ts +47 -1
- package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_invites_state.svelte.js +38 -26
- package/dist/ui/admin_sessions_state.svelte.d.ts +26 -0
- package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_sessions_state.svelte.js +35 -21
- package/dist/ui/app_settings_state.svelte.d.ts +39 -0
- package/dist/ui/app_settings_state.svelte.d.ts.map +1 -1
- package/dist/ui/app_settings_state.svelte.js +34 -18
- package/dist/ui/audit_log_state.svelte.d.ts +40 -3
- package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
- package/dist/ui/audit_log_state.svelte.js +36 -42
- package/dist/ui/auth_state.svelte.d.ts +4 -3
- package/dist/ui/auth_state.svelte.d.ts.map +1 -1
- package/dist/ui/auth_state.svelte.js +4 -1
- package/dist/ui/permit_offers_state.svelte.d.ts +125 -0
- package/dist/ui/permit_offers_state.svelte.d.ts.map +1 -0
- package/dist/ui/permit_offers_state.svelte.js +197 -0
- package/package.json +3 -3
- package/dist/auth/admin_routes.d.ts +0 -29
- package/dist/auth/admin_routes.d.ts.map +0 -1
- package/dist/auth/admin_routes.js +0 -226
- package/dist/auth/app_settings_routes.d.ts +0 -27
- package/dist/auth/app_settings_routes.d.ts.map +0 -1
- package/dist/auth/app_settings_routes.js +0 -66
- package/dist/auth/invite_routes.d.ts +0 -18
- package/dist/auth/invite_routes.d.ts.map +0 -1
- package/dist/auth/invite_routes.js +0 -129
|
@@ -18,6 +18,7 @@ import type { Db, DbType } from '../db/db.js';
|
|
|
18
18
|
import type { PasswordHashDeps } from '../auth/password.js';
|
|
19
19
|
import { type SessionOptions } from '../auth/session_cookie.js';
|
|
20
20
|
import type { AuditLogEvent } from '../auth/audit_log_schema.js';
|
|
21
|
+
import type { Uuid } from '../uuid.js';
|
|
21
22
|
import type { AppBackend } from '../server/app_backend.js';
|
|
22
23
|
import { type AppServerOptions, type AppServerContext } from '../server/app_server.js';
|
|
23
24
|
import type { AppSurface, AppSurfaceSpec } from '../http/surface.js';
|
|
@@ -52,11 +53,11 @@ export interface BootstrapTestAccountOptions {
|
|
|
52
53
|
*/
|
|
53
54
|
export declare const bootstrap_test_account: (options: BootstrapTestAccountOptions) => Promise<{
|
|
54
55
|
account: {
|
|
55
|
-
id:
|
|
56
|
+
id: Uuid;
|
|
56
57
|
username: string;
|
|
57
58
|
};
|
|
58
59
|
actor: {
|
|
59
|
-
id:
|
|
60
|
+
id: Uuid;
|
|
60
61
|
};
|
|
61
62
|
api_token: string;
|
|
62
63
|
session_cookie: string;
|
|
@@ -67,12 +68,12 @@ export declare const bootstrap_test_account: (options: BootstrapTestAccountOptio
|
|
|
67
68
|
export interface TestAppServer extends AppBackend {
|
|
68
69
|
/** The bootstrapped account. */
|
|
69
70
|
account: {
|
|
70
|
-
id:
|
|
71
|
+
id: Uuid;
|
|
71
72
|
username: string;
|
|
72
73
|
};
|
|
73
74
|
/** The actor linked to the account. */
|
|
74
75
|
actor: {
|
|
75
|
-
id:
|
|
76
|
+
id: Uuid;
|
|
76
77
|
};
|
|
77
78
|
/** Raw API token for Bearer auth. */
|
|
78
79
|
api_token: string;
|
|
@@ -125,11 +126,11 @@ export interface CreateTestAppOptions extends TestAppServerOptions {
|
|
|
125
126
|
*/
|
|
126
127
|
export interface TestAccount {
|
|
127
128
|
account: {
|
|
128
|
-
id:
|
|
129
|
+
id: Uuid;
|
|
129
130
|
username: string;
|
|
130
131
|
};
|
|
131
132
|
actor: {
|
|
132
|
-
id:
|
|
133
|
+
id: Uuid;
|
|
133
134
|
};
|
|
134
135
|
/** Signed session cookie value. */
|
|
135
136
|
session_cookie: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAK/B,OAAO,EAA2B,KAAK,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAE1E,OAAO,KAAK,EAAC,EAAE,EAAE,MAAM,EAAC,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAC;AAU1D,OAAO,EAA8B,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAG3F,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAEN,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAC,UAAU,EAAE,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAUrD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBAIhC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,QAAiB,CAAC;AASjD;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC3C,EAAE,EAAE,EAAE,CAAC;IACP,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACtB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAClC,SAAS,2BAA2B,KAClC,OAAO,CAAC;IACV,OAAO,EAAE;QAAC,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,8 +36,14 @@ export interface StandardAttackSurfaceOptions {
|
|
|
36
36
|
api_path_prefix?: string;
|
|
37
37
|
/** Security policy configuration. Omit for sensible defaults. */
|
|
38
38
|
security_policy?: SurfaceSecurityPolicyOptions;
|
|
39
|
-
/**
|
|
40
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Error schema tightness assertion config. Defaults to
|
|
41
|
+
* `DEFAULT_ERROR_SCHEMA_TIGHTNESS` (ignores 401/403/429,
|
|
42
|
+
* `min_specificity: 'enum'`). Pass a narrower config to extend the
|
|
43
|
+
* allowlist or tighten the threshold; pass `null` to skip the assertion
|
|
44
|
+
* and keep the audit log informational-only.
|
|
45
|
+
*/
|
|
46
|
+
error_schema_tightness?: ErrorSchemaTightnessOptions | null;
|
|
41
47
|
}
|
|
42
48
|
/**
|
|
43
49
|
* Run the standard attack surface test suite.
|
|
@@ -49,7 +55,7 @@ export interface StandardAttackSurfaceOptions {
|
|
|
49
55
|
* 4. Middleware stack — every API route has the full middleware chain
|
|
50
56
|
* 5. Surface invariants — structural assertions (error schemas, descriptions, duplicates, consistency)
|
|
51
57
|
* 6. Security policy — rate limiting on sensitive routes, no unexpected public mutations, method conventions
|
|
52
|
-
* 7. Error schema tightness
|
|
58
|
+
* 7. Error schema tightness — informational log of generic vs specific error schemas, plus assertion against `DEFAULT_ERROR_SCHEMA_TIGHTNESS` by default (opt out with `error_schema_tightness: null`)
|
|
53
59
|
* 8. Adversarial auth — unauthenticated/wrong-role/correct-auth enforcement
|
|
54
60
|
* 9. Adversarial input — input body and params validation
|
|
55
61
|
* 10. Adversarial 404 — stub 404 handlers, validate response bodies against declared schemas
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attack_surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/attack_surface.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAoB7B,OAAO,
|
|
1
|
+
{"version":3,"file":"attack_surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/attack_surface.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAoB7B,OAAO,EAMN,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,MAAM,yBAAyB,CAAC;AAoBjC,OAAO,EAA4B,KAAK,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAsClF,oFAAoF;AACpF,MAAM,WAAW,sBAAsB;IACtC,+EAA+E;IAC/E,KAAK,EAAE,MAAM,cAAc,CAAC;IAC5B,yDAAyD;IACzD,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,GAAI,SAAS,sBAAsB,KAAG,IAkH3E,CAAC;AAIF,0DAA0D;AAC1D,MAAM,WAAW,4BAA4B;IAC5C,+EAA+E;IAC/E,KAAK,EAAE,MAAM,cAAc,CAAC;IAC5B,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,sBAAsB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACtC,gHAAgH;IAChH,uBAAuB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,yDAAyD;IACzD,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACrB,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,eAAe,CAAC,EAAE,4BAA4B,CAAC;IAC/C;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAC;CAC5D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,sCAAsC,GAClD,SAAS,4BAA4B,KACnC,IAoEF,CAAC"}
|
|
@@ -15,7 +15,7 @@ import './assert_dev_env.js';
|
|
|
15
15
|
* @module
|
|
16
16
|
*/
|
|
17
17
|
import { test, assert, describe } from 'vitest';
|
|
18
|
-
import { assert_surface_invariants, assert_surface_security_policy, audit_error_schema_tightness, assert_error_schema_tightness, } from './surface_invariants.js';
|
|
18
|
+
import { assert_surface_invariants, assert_surface_security_policy, audit_error_schema_tightness, assert_error_schema_tightness, DEFAULT_ERROR_SCHEMA_TIGHTNESS, } from './surface_invariants.js';
|
|
19
19
|
import { describe_adversarial_input } from './adversarial_input.js';
|
|
20
20
|
import { describe_adversarial_404 } from './adversarial_404.js';
|
|
21
21
|
import { create_test_app_from_specs, create_test_request_context, create_auth_test_apps, select_auth_app, resolve_test_path, } from './auth_apps.js';
|
|
@@ -167,7 +167,7 @@ export const describe_adversarial_auth = (options) => {
|
|
|
167
167
|
* 4. Middleware stack — every API route has the full middleware chain
|
|
168
168
|
* 5. Surface invariants — structural assertions (error schemas, descriptions, duplicates, consistency)
|
|
169
169
|
* 6. Security policy — rate limiting on sensitive routes, no unexpected public mutations, method conventions
|
|
170
|
-
* 7. Error schema tightness
|
|
170
|
+
* 7. Error schema tightness — informational log of generic vs specific error schemas, plus assertion against `DEFAULT_ERROR_SCHEMA_TIGHTNESS` by default (opt out with `error_schema_tightness: null`)
|
|
171
171
|
* 8. Adversarial auth — unauthenticated/wrong-role/correct-auth enforcement
|
|
172
172
|
* 9. Adversarial input — input body and params validation
|
|
173
173
|
* 10. Adversarial 404 — stub 404 handlers, validate response bodies against declared schemas
|
|
@@ -178,7 +178,7 @@ export const describe_adversarial_auth = (options) => {
|
|
|
178
178
|
* @param options - the test configuration
|
|
179
179
|
*/
|
|
180
180
|
export const describe_standard_attack_surface_tests = (options) => {
|
|
181
|
-
const { build, snapshot_path, expected_public_routes, expected_api_middleware, roles, api_path_prefix = '/api/', security_policy, error_schema_tightness, } = options;
|
|
181
|
+
const { build, snapshot_path, expected_public_routes, expected_api_middleware, roles, api_path_prefix = '/api/', security_policy, error_schema_tightness = DEFAULT_ERROR_SCHEMA_TIGHTNESS, } = options;
|
|
182
182
|
const built = build();
|
|
183
183
|
const { surface } = built;
|
|
184
184
|
describe('attack surface snapshot', () => {
|
|
@@ -202,7 +202,7 @@ export const describe_standard_attack_surface_tests = (options) => {
|
|
|
202
202
|
test('security policy', () => {
|
|
203
203
|
assert_surface_security_policy(surface, security_policy);
|
|
204
204
|
});
|
|
205
|
-
test('error schema tightness
|
|
205
|
+
test('error schema tightness', () => {
|
|
206
206
|
const entries = audit_error_schema_tightness(surface);
|
|
207
207
|
const generic = entries.filter((e) => e.specificity === 'generic');
|
|
208
208
|
const literal = entries.filter((e) => e.specificity === 'literal');
|
|
@@ -3,6 +3,7 @@ import type { SessionOptions } from '../auth/session_cookie.js';
|
|
|
3
3
|
import type { AppServerContext, AppServerOptions } from '../server/app_server.js';
|
|
4
4
|
import type { RouteSpec } from '../http/route_spec.js';
|
|
5
5
|
import { type DbFactory } from './db.js';
|
|
6
|
+
import type { RpcEndpointSpec } from '../http/surface.js';
|
|
6
7
|
/**
|
|
7
8
|
* Configuration for `describe_audit_completeness_tests`.
|
|
8
9
|
*/
|
|
@@ -11,6 +12,11 @@ export interface AuditCompletenessTestOptions {
|
|
|
11
12
|
session_options: SessionOptions<string>;
|
|
12
13
|
/** Route spec factory — same one used in production. */
|
|
13
14
|
create_route_specs: (ctx: AppServerContext) => Array<RouteSpec>;
|
|
15
|
+
/**
|
|
16
|
+
* RPC endpoint specs — the source `RpcAction` arrays. Required; the
|
|
17
|
+
* admin permit flow is RPC-only and the suite hard-fails without it.
|
|
18
|
+
*/
|
|
19
|
+
rpc_endpoints: Array<RpcEndpointSpec>;
|
|
14
20
|
/** Optional overrides for `AppServerOptions`. */
|
|
15
21
|
app_options?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
|
|
16
22
|
/** Database factories to run tests against. Default: pglite only. */
|
|
@@ -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,EAAE,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,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,EAAE,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAMrD,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AA0BjB,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAExD;;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;;;OAGG;IACH,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IACtC,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CACpB,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,iBAAiB,GAAG,oBAAoB,CAAC,CAC5E,CAAC;IACF,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAoDD;;;;;;;;GAQG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,4BAA4B,KAAG,IAgezF,CAAC"}
|
|
@@ -20,11 +20,12 @@ import { create_test_app } from './app_server.js';
|
|
|
20
20
|
import { create_pglite_factory, create_describe_db, AUTH_INTEGRATION_TRUNCATE_TABLES, } from './db.js';
|
|
21
21
|
import { find_auth_route } from './integration_helpers.js';
|
|
22
22
|
import { run_migrations } from '../db/migrate.js';
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
import { query_accept_offer } from '../auth/permit_offer_queries.js';
|
|
24
|
+
import { rpc_call, require_rpc_endpoint_path } from './rpc_helpers.js';
|
|
25
|
+
import { permit_offer_create_action_spec, permit_revoke_action_spec, } from '../auth/permit_offer_action_specs.js';
|
|
26
|
+
import { admin_session_revoke_all_action_spec, admin_token_revoke_all_action_spec, app_settings_update_action_spec, invite_create_action_spec, invite_delete_action_spec, } from '../auth/admin_action_specs.js';
|
|
27
|
+
import { account_session_list_action_spec, account_session_revoke_action_spec, account_session_revoke_all_action_spec, account_token_create_action_spec, account_token_list_action_spec, account_token_revoke_action_spec, } from '../auth/account_action_specs.js';
|
|
28
|
+
import { query_actor_by_account } from '../auth/account_queries.js';
|
|
28
29
|
/** Query audit log events from the database. */
|
|
29
30
|
const query_audit_events = async (db) => {
|
|
30
31
|
return db.query('SELECT event_type, seq FROM audit_log ORDER BY seq');
|
|
@@ -39,7 +40,10 @@ const build_options = (options, db) => ({
|
|
|
39
40
|
create_route_specs: options.create_route_specs,
|
|
40
41
|
db,
|
|
41
42
|
roles: [ROLE_KEEPER, ROLE_ADMIN],
|
|
42
|
-
app_options:
|
|
43
|
+
app_options: {
|
|
44
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
45
|
+
...options.app_options,
|
|
46
|
+
},
|
|
43
47
|
});
|
|
44
48
|
/** Headers for unauthenticated JSON requests (login, signup). */
|
|
45
49
|
const UNAUTHENTICATED_JSON_HEADERS = {
|
|
@@ -52,15 +56,6 @@ const json_session_headers = (test_app, extra) => test_app.create_session_header
|
|
|
52
56
|
'content-type': 'application/json',
|
|
53
57
|
...extra,
|
|
54
58
|
});
|
|
55
|
-
/**
|
|
56
|
-
* Find an account-scoped parameterized route (e.g. `/tokens/:id/revoke`).
|
|
57
|
-
*
|
|
58
|
-
* Matches routes with a `:id` or `:param` segment that are NOT admin role-gated.
|
|
59
|
-
*/
|
|
60
|
-
const find_account_parameterized_route = (specs, segment, suffix, method) => specs.find((s) => s.method === method &&
|
|
61
|
-
s.path.includes(`/${segment}/`) &&
|
|
62
|
-
s.path.endsWith(suffix) &&
|
|
63
|
-
s.auth.type !== 'role');
|
|
64
59
|
/**
|
|
65
60
|
* Composable audit log completeness test suite.
|
|
66
61
|
*
|
|
@@ -71,6 +66,9 @@ const find_account_parameterized_route = (specs, segment, suffix, method) => spe
|
|
|
71
66
|
* @param options - session config, route factory, and optional overrides
|
|
72
67
|
*/
|
|
73
68
|
export const describe_audit_completeness_tests = (options) => {
|
|
69
|
+
// Hard-fail early so consumers see a clear setup error instead of a
|
|
70
|
+
// confusing test failure when `rpc_endpoints` is missing.
|
|
71
|
+
const rpc_path = require_rpc_endpoint_path(options.rpc_endpoints);
|
|
74
72
|
const init_schema = async (db) => {
|
|
75
73
|
await run_migrations(db, [AUTH_MIGRATION_NS]);
|
|
76
74
|
};
|
|
@@ -125,37 +123,39 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
125
123
|
});
|
|
126
124
|
test('token create produces token_create event', async () => {
|
|
127
125
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
method:
|
|
132
|
-
|
|
133
|
-
|
|
126
|
+
const res = await rpc_call({
|
|
127
|
+
app: test_app.app,
|
|
128
|
+
path: rpc_path,
|
|
129
|
+
method: account_token_create_action_spec.method,
|
|
130
|
+
params: { name: 'audit-test' },
|
|
131
|
+
headers: test_app.create_session_headers(),
|
|
134
132
|
});
|
|
135
|
-
assert.
|
|
133
|
+
assert.ok(res.ok, `account_token_create failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
136
134
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
137
|
-
assert_has_event(events, 'token_create', '
|
|
135
|
+
assert_has_event(events, 'token_create', 'account_token_create RPC');
|
|
138
136
|
});
|
|
139
137
|
test('token revoke produces token_revoke event', async () => {
|
|
140
138
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
141
139
|
// get a token ID to revoke
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
const list_res = await rpc_call({
|
|
141
|
+
app: test_app.app,
|
|
142
|
+
path: rpc_path,
|
|
143
|
+
method: account_token_list_action_spec.method,
|
|
145
144
|
headers: test_app.create_session_headers(),
|
|
146
145
|
});
|
|
147
|
-
|
|
146
|
+
assert.ok(list_res.ok, 'account_token_list should succeed');
|
|
147
|
+
const { tokens } = list_res.result;
|
|
148
148
|
assert.ok(tokens.length > 0, 'Expected at least one token');
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
149
|
+
const res = await rpc_call({
|
|
150
|
+
app: test_app.app,
|
|
151
|
+
path: rpc_path,
|
|
152
|
+
method: account_token_revoke_action_spec.method,
|
|
153
|
+
params: { token_id: tokens[0].id },
|
|
154
154
|
headers: test_app.create_session_headers(),
|
|
155
155
|
});
|
|
156
|
-
assert.
|
|
156
|
+
assert.ok(res.ok, `account_token_revoke failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
157
157
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
158
|
-
assert_has_event(events, 'token_revoke', '
|
|
158
|
+
assert_has_event(events, 'token_revoke', 'account_token_revoke RPC');
|
|
159
159
|
});
|
|
160
160
|
test('session revoke produces session_revoke event', async () => {
|
|
161
161
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
@@ -171,36 +171,38 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
171
171
|
}),
|
|
172
172
|
});
|
|
173
173
|
// get session IDs (newest first)
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
174
|
+
const list_res = await rpc_call({
|
|
175
|
+
app: test_app.app,
|
|
176
|
+
path: rpc_path,
|
|
177
|
+
method: account_session_list_action_spec.method,
|
|
177
178
|
headers: test_app.create_session_headers(),
|
|
178
179
|
});
|
|
179
|
-
|
|
180
|
+
assert.ok(list_res.ok, 'account_session_list should succeed');
|
|
181
|
+
const { sessions } = list_res.result;
|
|
180
182
|
assert.ok(sessions.length >= 2, 'Expected at least 2 sessions');
|
|
181
|
-
const route = find_account_parameterized_route(test_app.route_specs, 'sessions', '/revoke', 'POST');
|
|
182
|
-
assert.ok(route, 'Expected POST /sessions/:id/revoke route');
|
|
183
183
|
// revoke the second session (not the one used for auth)
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
const res = await rpc_call({
|
|
185
|
+
app: test_app.app,
|
|
186
|
+
path: rpc_path,
|
|
187
|
+
method: account_session_revoke_action_spec.method,
|
|
188
|
+
params: { session_id: sessions[1].id },
|
|
187
189
|
headers: test_app.create_session_headers(),
|
|
188
190
|
});
|
|
189
|
-
assert.
|
|
191
|
+
assert.ok(res.ok, `account_session_revoke failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
190
192
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
191
|
-
assert_has_event(events, 'session_revoke', '
|
|
193
|
+
assert_has_event(events, 'session_revoke', 'account_session_revoke RPC');
|
|
192
194
|
});
|
|
193
195
|
test('session revoke-all produces session_revoke_all event', async () => {
|
|
194
196
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
method:
|
|
197
|
+
const res = await rpc_call({
|
|
198
|
+
app: test_app.app,
|
|
199
|
+
path: rpc_path,
|
|
200
|
+
method: account_session_revoke_all_action_spec.method,
|
|
199
201
|
headers: test_app.create_session_headers(),
|
|
200
202
|
});
|
|
201
|
-
assert.
|
|
203
|
+
assert.ok(res.ok, `account_session_revoke_all failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
202
204
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
203
|
-
assert_has_event(events, 'session_revoke_all', '
|
|
205
|
+
assert_has_event(events, 'session_revoke_all', 'account_session_revoke_all RPC');
|
|
204
206
|
});
|
|
205
207
|
test('password change produces password_change event', async () => {
|
|
206
208
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
@@ -221,137 +223,144 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
221
223
|
});
|
|
222
224
|
// --- Admin routes ---
|
|
223
225
|
describe('admin mutation audit events', () => {
|
|
224
|
-
test('
|
|
226
|
+
test('admin offer (RPC) + accept produces permit_offer_create and permit_grant events', async () => {
|
|
225
227
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
226
|
-
const route = find_admin_route(test_app.route_specs, '/permits/grant', 'POST');
|
|
227
|
-
assert.ok(route, 'Expected admin POST /permits/grant route');
|
|
228
228
|
const target = await test_app.create_account({ username: 'audit_target' });
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
229
|
+
const offer_res = await rpc_call({
|
|
230
|
+
app: test_app.app,
|
|
231
|
+
path: rpc_path,
|
|
232
|
+
method: permit_offer_create_action_spec.method,
|
|
233
|
+
params: { to_account_id: target.account.id, role: ROLE_ADMIN },
|
|
234
|
+
headers: test_app.create_session_headers(),
|
|
234
235
|
});
|
|
235
|
-
assert.
|
|
236
|
-
const
|
|
237
|
-
|
|
236
|
+
assert.ok(offer_res.ok, `permit_offer_create failed: ${offer_res.ok ? '' : JSON.stringify(offer_res.error)}`);
|
|
237
|
+
const { offer } = offer_res.result;
|
|
238
|
+
// Admin offer emits `permit_offer_create` only — the permit doesn't
|
|
239
|
+
// exist yet. Drive the accept to confirm `permit_grant` fires on the
|
|
240
|
+
// downstream consent transition.
|
|
241
|
+
const events_after_offer = await query_audit_events(test_app.backend.deps.db);
|
|
242
|
+
assert_has_event(events_after_offer, 'permit_offer_create', 'permit_offer_create RPC');
|
|
243
|
+
await get_db().transaction(async (tx) => {
|
|
244
|
+
await query_accept_offer({ db: tx }, { offer_id: offer.id, to_account_id: target.account.id, ip: null });
|
|
245
|
+
});
|
|
246
|
+
const events_after_accept = await query_audit_events(test_app.backend.deps.db);
|
|
247
|
+
assert_has_event(events_after_accept, 'permit_grant', 'offer accept');
|
|
238
248
|
});
|
|
239
|
-
test('permit revoke produces permit_revoke event', async () => {
|
|
249
|
+
test('permit revoke (RPC) produces permit_revoke event', async () => {
|
|
240
250
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
241
|
-
const grant_route = find_admin_route(test_app.route_specs, '/permits/grant', 'POST');
|
|
242
|
-
const revoke_route = test_app.route_specs.find((s) => s.method === 'POST' &&
|
|
243
|
-
s.path.includes('/permits/') &&
|
|
244
|
-
s.path.endsWith('/revoke') &&
|
|
245
|
-
s.auth.type === 'role');
|
|
246
|
-
assert.ok(grant_route, 'Expected admin POST /permits/grant route');
|
|
247
|
-
assert.ok(revoke_route, 'Expected admin POST /permits/:permit_id/revoke route');
|
|
248
251
|
const target = await test_app.create_account({ username: 'audit_revoke_target' });
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
252
|
+
const target_actor = await query_actor_by_account({ db: get_db() }, target.account.id);
|
|
253
|
+
assert.ok(target_actor);
|
|
254
|
+
// Offer + accept to materialize a permit we can revoke.
|
|
255
|
+
const offer_res = await rpc_call({
|
|
256
|
+
app: test_app.app,
|
|
257
|
+
path: rpc_path,
|
|
258
|
+
method: permit_offer_create_action_spec.method,
|
|
259
|
+
params: { to_account_id: target.account.id, role: ROLE_ADMIN },
|
|
260
|
+
headers: test_app.create_session_headers(),
|
|
255
261
|
});
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
262
|
+
assert.ok(offer_res.ok, `permit_offer_create failed: ${offer_res.ok ? '' : JSON.stringify(offer_res.error)}`);
|
|
263
|
+
const { offer } = offer_res.result;
|
|
264
|
+
const accept_result = await get_db().transaction(async (tx) => {
|
|
265
|
+
return query_accept_offer({ db: tx }, { offer_id: offer.id, to_account_id: target.account.id, ip: null });
|
|
266
|
+
});
|
|
267
|
+
// Revoke via RPC.
|
|
268
|
+
const revoke_res = await rpc_call({
|
|
269
|
+
app: test_app.app,
|
|
270
|
+
path: rpc_path,
|
|
271
|
+
method: permit_revoke_action_spec.method,
|
|
272
|
+
params: { actor_id: target_actor.id, permit_id: accept_result.permit.id },
|
|
263
273
|
headers: test_app.create_session_headers(),
|
|
264
274
|
});
|
|
265
|
-
assert.
|
|
275
|
+
assert.ok(revoke_res.ok, `permit_revoke failed: ${revoke_res.ok ? '' : JSON.stringify(revoke_res.error)}`);
|
|
266
276
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
267
|
-
assert_has_event(events, 'permit_revoke', '
|
|
277
|
+
assert_has_event(events, 'permit_revoke', 'permit_revoke RPC');
|
|
268
278
|
});
|
|
269
279
|
test('admin session revoke-all produces session_revoke_all event', async () => {
|
|
270
280
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
271
|
-
const route = find_admin_route(test_app.route_specs, '/sessions/revoke-all', 'POST');
|
|
272
|
-
assert.ok(route, 'Expected admin POST /sessions/revoke-all route');
|
|
273
281
|
const target = await test_app.create_account({ username: 'audit_sessions_target' });
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
282
|
+
const res = await rpc_call({
|
|
283
|
+
app: test_app.app,
|
|
284
|
+
path: rpc_path,
|
|
285
|
+
method: admin_session_revoke_all_action_spec.method,
|
|
286
|
+
params: { account_id: target.account.id },
|
|
277
287
|
headers: test_app.create_session_headers(),
|
|
278
288
|
});
|
|
279
|
-
assert.
|
|
289
|
+
assert.ok(res.ok, `admin_session_revoke_all failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
280
290
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
281
291
|
// admin session revoke-all also produces session_revoke_all
|
|
282
|
-
assert_has_event(events, 'session_revoke_all', '
|
|
292
|
+
assert_has_event(events, 'session_revoke_all', 'admin_session_revoke_all RPC');
|
|
283
293
|
});
|
|
284
294
|
test('admin token revoke-all produces token_revoke_all event', async () => {
|
|
285
295
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
286
|
-
const route = find_admin_route(test_app.route_specs, '/tokens/revoke-all', 'POST');
|
|
287
|
-
assert.ok(route, 'Expected admin POST /tokens/revoke-all route');
|
|
288
296
|
const target = await test_app.create_account({ username: 'audit_tokens_target' });
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
297
|
+
const res = await rpc_call({
|
|
298
|
+
app: test_app.app,
|
|
299
|
+
path: rpc_path,
|
|
300
|
+
method: admin_token_revoke_all_action_spec.method,
|
|
301
|
+
params: { account_id: target.account.id },
|
|
292
302
|
headers: test_app.create_session_headers(),
|
|
293
303
|
});
|
|
294
|
-
assert.
|
|
304
|
+
assert.ok(res.ok, `admin_token_revoke_all failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
295
305
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
296
|
-
assert_has_event(events, 'token_revoke_all', '
|
|
306
|
+
assert_has_event(events, 'token_revoke_all', 'admin_token_revoke_all RPC');
|
|
297
307
|
});
|
|
298
308
|
});
|
|
299
|
-
// --- Invite
|
|
309
|
+
// --- Invite RPC actions ---
|
|
300
310
|
describe('invite mutation audit events', () => {
|
|
301
311
|
test('invite create and delete produce audit events', async () => {
|
|
302
312
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
method: 'POST',
|
|
310
|
-
headers: json_session_headers(test_app),
|
|
311
|
-
body: JSON.stringify({ username: 'invited_user' }),
|
|
313
|
+
const create_res = await rpc_call({
|
|
314
|
+
app: test_app.app,
|
|
315
|
+
path: rpc_path,
|
|
316
|
+
method: invite_create_action_spec.method,
|
|
317
|
+
params: { username: 'invited_user' },
|
|
318
|
+
headers: test_app.create_session_headers(),
|
|
312
319
|
});
|
|
313
|
-
assert.
|
|
314
|
-
const { invite } =
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
method:
|
|
320
|
+
assert.ok(create_res.ok, `invite_create failed: ${create_res.ok ? '' : JSON.stringify(create_res.error)}`);
|
|
321
|
+
const { invite } = create_res.result;
|
|
322
|
+
const delete_res = await rpc_call({
|
|
323
|
+
app: test_app.app,
|
|
324
|
+
path: rpc_path,
|
|
325
|
+
method: invite_delete_action_spec.method,
|
|
326
|
+
params: { invite_id: invite.id },
|
|
319
327
|
headers: test_app.create_session_headers(),
|
|
320
328
|
});
|
|
321
|
-
assert.
|
|
329
|
+
assert.ok(delete_res.ok, `invite_delete failed: ${delete_res.ok ? '' : JSON.stringify(delete_res.error)}`);
|
|
322
330
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
323
|
-
assert_has_event(events, 'invite_create', '
|
|
324
|
-
assert_has_event(events, 'invite_delete', '
|
|
331
|
+
assert_has_event(events, 'invite_create', 'invite_create RPC');
|
|
332
|
+
assert_has_event(events, 'invite_delete', 'invite_delete RPC');
|
|
325
333
|
});
|
|
326
334
|
});
|
|
327
|
-
// --- App settings
|
|
335
|
+
// --- App settings RPC action ---
|
|
328
336
|
describe('app settings mutation audit events', () => {
|
|
329
337
|
test('settings update produces app_settings_update event', async () => {
|
|
330
338
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
method:
|
|
335
|
-
|
|
336
|
-
|
|
339
|
+
const res = await rpc_call({
|
|
340
|
+
app: test_app.app,
|
|
341
|
+
path: rpc_path,
|
|
342
|
+
method: app_settings_update_action_spec.method,
|
|
343
|
+
params: { open_signup: true },
|
|
344
|
+
headers: test_app.create_session_headers(),
|
|
337
345
|
});
|
|
338
|
-
assert.
|
|
346
|
+
assert.ok(res.ok, `app_settings_update failed: ${res.ok ? '' : JSON.stringify(res.error)}`);
|
|
339
347
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
340
|
-
assert_has_event(events, 'app_settings_update', '
|
|
348
|
+
assert_has_event(events, 'app_settings_update', 'app_settings_update RPC');
|
|
341
349
|
});
|
|
342
350
|
});
|
|
343
351
|
// --- Signup route ---
|
|
344
352
|
describe('signup audit events', () => {
|
|
345
353
|
test('signup produces signup event', async () => {
|
|
346
354
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
347
|
-
// enable open signup
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
method:
|
|
352
|
-
|
|
353
|
-
|
|
355
|
+
// enable open signup via RPC
|
|
356
|
+
const settings_res = await rpc_call({
|
|
357
|
+
app: test_app.app,
|
|
358
|
+
path: rpc_path,
|
|
359
|
+
method: app_settings_update_action_spec.method,
|
|
360
|
+
params: { open_signup: true },
|
|
361
|
+
headers: test_app.create_session_headers(),
|
|
354
362
|
});
|
|
363
|
+
assert.ok(settings_res.ok, `app_settings_update failed: ${settings_res.ok ? '' : JSON.stringify(settings_res.error)}`);
|
|
355
364
|
// signup
|
|
356
365
|
const signup_route = find_auth_route(test_app.route_specs, '/signup', 'POST');
|
|
357
366
|
assert.ok(signup_route, 'Expected POST /signup route');
|
|
@@ -384,6 +393,7 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
384
393
|
'token_create',
|
|
385
394
|
'token_revoke',
|
|
386
395
|
'token_revoke_all',
|
|
396
|
+
'permit_offer_create',
|
|
387
397
|
'permit_grant',
|
|
388
398
|
'permit_revoke',
|
|
389
399
|
'invite_create',
|
|
@@ -393,6 +403,20 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
393
403
|
/** Event types excluded with justification. */
|
|
394
404
|
const EXCLUDED_EVENT_TYPES = new Set([
|
|
395
405
|
'bootstrap', // requires filesystem token — tested in bootstrap_account.db.test.ts
|
|
406
|
+
// The remaining `permit_offer_*` events fire only via the RPC
|
|
407
|
+
// endpoint or via downstream effects of `permit_revoke`. Direct
|
|
408
|
+
// coverage lives in `permit_offer_queries.db.test.ts`,
|
|
409
|
+
// `permit_offer_actions.db.test.ts`,
|
|
410
|
+
// `permit_offer_actions.notifications.db.test.ts`, and
|
|
411
|
+
// `permit_offer_actions.notifications.revoke.db.test.ts`.
|
|
412
|
+
// `permit_offer_expire` fires from the cleanup sweep
|
|
413
|
+
// (`cleanup_expired_permit_offers` in `auth/cleanup.ts`) —
|
|
414
|
+
// covered in `cleanup.db.test.ts`.
|
|
415
|
+
'permit_offer_accept',
|
|
416
|
+
'permit_offer_decline',
|
|
417
|
+
'permit_offer_retract',
|
|
418
|
+
'permit_offer_expire',
|
|
419
|
+
'permit_offer_supersede',
|
|
396
420
|
]);
|
|
397
421
|
test('all audit event types are covered or explicitly excluded', () => {
|
|
398
422
|
const all_covered = new Set([...COVERED_EVENT_TYPES, ...EXCLUDED_EVENT_TYPES]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth_apps.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/auth_apps.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;GAOG;AAEH,OAAO,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAG1B,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExF,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AACpF,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth_apps.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/auth_apps.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;GAOG;AAEH,OAAO,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAG1B,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExF,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AACpF,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAI5E;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,GAAI,OAAO,MAAM,KAAG,cAI1D,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,GACtC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,WAAW,cAAc,EACzB,kBAAkB,cAAc,KAC9B,IAkBF,CAAC;AAEF,sFAAsF;AACtF,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GACjC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,OAAO,KAAK,CAAC,MAAM,CAAC,KAClB,YAeF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,YAAY,EAAE,MAAM,SAAS,KAAG,IAcrE,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,MAA4C,CAAC"}
|