@fuzdev/fuz_app 0.67.1 → 0.69.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.
Files changed (235) hide show
  1. package/dist/actions/perform_action.d.ts.map +1 -1
  2. package/dist/actions/perform_action.js +10 -3
  3. package/dist/auth/CLAUDE.md +99 -5
  4. package/dist/auth/account_queries.d.ts +87 -4
  5. package/dist/auth/account_queries.d.ts.map +1 -1
  6. package/dist/auth/account_queries.js +107 -17
  7. package/dist/auth/account_schema.d.ts +19 -0
  8. package/dist/auth/account_schema.d.ts.map +1 -1
  9. package/dist/auth/account_schema.js +8 -0
  10. package/dist/auth/admin_action_specs.d.ts +170 -3
  11. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  12. package/dist/auth/admin_action_specs.js +148 -4
  13. package/dist/auth/admin_actions.d.ts +4 -14
  14. package/dist/auth/admin_actions.d.ts.map +1 -1
  15. package/dist/auth/admin_actions.js +246 -40
  16. package/dist/auth/audit_log_ddl.d.ts +10 -1
  17. package/dist/auth/audit_log_ddl.d.ts.map +1 -1
  18. package/dist/auth/audit_log_ddl.js +13 -4
  19. package/dist/auth/audit_log_schema.d.ts +34 -1
  20. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  21. package/dist/auth/audit_log_schema.js +73 -0
  22. package/dist/auth/auth_ddl.d.ts +2 -2
  23. package/dist/auth/auth_ddl.d.ts.map +1 -1
  24. package/dist/auth/auth_ddl.js +10 -2
  25. package/dist/auth/cell_action_specs.d.ts +1295 -0
  26. package/dist/auth/cell_action_specs.d.ts.map +1 -0
  27. package/dist/auth/cell_action_specs.js +397 -0
  28. package/dist/auth/cell_actions.d.ts +63 -0
  29. package/dist/auth/cell_actions.d.ts.map +1 -0
  30. package/dist/auth/cell_actions.js +546 -0
  31. package/dist/auth/cell_audit_action_specs.d.ts +131 -0
  32. package/dist/auth/cell_audit_action_specs.d.ts.map +1 -0
  33. package/dist/auth/cell_audit_action_specs.js +70 -0
  34. package/dist/auth/cell_audit_actions.d.ts +18 -0
  35. package/dist/auth/cell_audit_actions.d.ts.map +1 -0
  36. package/dist/auth/cell_audit_actions.js +59 -0
  37. package/dist/auth/cell_audit_events.d.ts +28 -0
  38. package/dist/auth/cell_audit_events.d.ts.map +1 -0
  39. package/dist/auth/cell_audit_events.js +42 -0
  40. package/dist/auth/cell_audit_metadata.d.ts +48 -0
  41. package/dist/auth/cell_audit_metadata.d.ts.map +1 -0
  42. package/dist/auth/cell_audit_metadata.js +46 -0
  43. package/dist/auth/cell_authorize.d.ts +88 -0
  44. package/dist/auth/cell_authorize.d.ts.map +1 -0
  45. package/dist/auth/cell_authorize.js +172 -0
  46. package/dist/auth/cell_data_schema.d.ts +44 -0
  47. package/dist/auth/cell_data_schema.d.ts.map +1 -0
  48. package/dist/auth/cell_data_schema.js +42 -0
  49. package/dist/auth/cell_field_action_specs.d.ts +244 -0
  50. package/dist/auth/cell_field_action_specs.d.ts.map +1 -0
  51. package/dist/auth/cell_field_action_specs.js +136 -0
  52. package/dist/auth/cell_field_actions.d.ts +34 -0
  53. package/dist/auth/cell_field_actions.d.ts.map +1 -0
  54. package/dist/auth/cell_field_actions.js +153 -0
  55. package/dist/auth/cell_field_audit_metadata.d.ts +30 -0
  56. package/dist/auth/cell_field_audit_metadata.d.ts.map +1 -0
  57. package/dist/auth/cell_field_audit_metadata.js +28 -0
  58. package/dist/auth/cell_grant_action_specs.d.ts +333 -0
  59. package/dist/auth/cell_grant_action_specs.d.ts.map +1 -0
  60. package/dist/auth/cell_grant_action_specs.js +148 -0
  61. package/dist/auth/cell_grant_actions.d.ts +50 -0
  62. package/dist/auth/cell_grant_actions.d.ts.map +1 -0
  63. package/dist/auth/cell_grant_actions.js +208 -0
  64. package/dist/auth/cell_grant_audit_metadata.d.ts +75 -0
  65. package/dist/auth/cell_grant_audit_metadata.d.ts.map +1 -0
  66. package/dist/auth/cell_grant_audit_metadata.js +54 -0
  67. package/dist/auth/cell_item_action_specs.d.ts +331 -0
  68. package/dist/auth/cell_item_action_specs.d.ts.map +1 -0
  69. package/dist/auth/cell_item_action_specs.js +182 -0
  70. package/dist/auth/cell_item_actions.d.ts +37 -0
  71. package/dist/auth/cell_item_actions.d.ts.map +1 -0
  72. package/dist/auth/cell_item_actions.js +204 -0
  73. package/dist/auth/cell_item_audit_metadata.d.ts +35 -0
  74. package/dist/auth/cell_item_audit_metadata.d.ts.map +1 -0
  75. package/dist/auth/cell_item_audit_metadata.js +32 -0
  76. package/dist/auth/cell_relation_visibility.d.ts +32 -0
  77. package/dist/auth/cell_relation_visibility.d.ts.map +1 -0
  78. package/dist/auth/cell_relation_visibility.js +57 -0
  79. package/dist/auth/deps.d.ts +9 -0
  80. package/dist/auth/deps.d.ts.map +1 -1
  81. package/dist/auth/role_grant_queries.d.ts +30 -0
  82. package/dist/auth/role_grant_queries.d.ts.map +1 -1
  83. package/dist/auth/role_grant_queries.js +54 -0
  84. package/dist/auth/signup_routes.d.ts +0 -3
  85. package/dist/auth/signup_routes.d.ts.map +1 -1
  86. package/dist/auth/signup_routes.js +9 -3
  87. package/dist/auth/standard_rpc_actions.d.ts +5 -5
  88. package/dist/auth/standard_rpc_actions.js +4 -4
  89. package/dist/db/CLAUDE.md +118 -0
  90. package/dist/db/cell_audit_queries.d.ts +26 -0
  91. package/dist/db/cell_audit_queries.d.ts.map +1 -0
  92. package/dist/db/cell_audit_queries.js +53 -0
  93. package/dist/db/cell_ddl.d.ts +151 -0
  94. package/dist/db/cell_ddl.d.ts.map +1 -0
  95. package/dist/db/cell_ddl.js +247 -0
  96. package/dist/db/cell_field_queries.d.ts +105 -0
  97. package/dist/db/cell_field_queries.d.ts.map +1 -0
  98. package/dist/db/cell_field_queries.js +113 -0
  99. package/dist/db/cell_grant_queries.d.ts +132 -0
  100. package/dist/db/cell_grant_queries.d.ts.map +1 -0
  101. package/dist/db/cell_grant_queries.js +145 -0
  102. package/dist/db/cell_history_ddl.d.ts +38 -0
  103. package/dist/db/cell_history_ddl.d.ts.map +1 -0
  104. package/dist/db/cell_history_ddl.js +61 -0
  105. package/dist/db/cell_item_queries.d.ts +107 -0
  106. package/dist/db/cell_item_queries.d.ts.map +1 -0
  107. package/dist/db/cell_item_queries.js +119 -0
  108. package/dist/db/cell_queries.d.ts +327 -0
  109. package/dist/db/cell_queries.d.ts.map +1 -0
  110. package/dist/db/cell_queries.js +431 -0
  111. package/dist/db/fact_ddl.d.ts +38 -0
  112. package/dist/db/fact_ddl.d.ts.map +1 -0
  113. package/dist/db/fact_ddl.js +71 -0
  114. package/dist/db/fact_queries.d.ts +140 -0
  115. package/dist/db/fact_queries.d.ts.map +1 -0
  116. package/dist/db/fact_queries.js +161 -0
  117. package/dist/db/fact_store.d.ts +112 -0
  118. package/dist/db/fact_store.d.ts.map +1 -0
  119. package/dist/db/fact_store.js +225 -0
  120. package/dist/server/app_server.d.ts +1 -7
  121. package/dist/server/app_server.d.ts.map +1 -1
  122. package/dist/server/app_server.js +1 -5
  123. package/dist/server/env.d.ts +2 -0
  124. package/dist/server/env.d.ts.map +1 -1
  125. package/dist/server/env.js +6 -0
  126. package/dist/server/fact_write.d.ts +32 -0
  127. package/dist/server/fact_write.d.ts.map +1 -0
  128. package/dist/server/fact_write.js +56 -0
  129. package/dist/server/file_fact_fetcher.d.ts +42 -0
  130. package/dist/server/file_fact_fetcher.d.ts.map +1 -0
  131. package/dist/server/file_fact_fetcher.js +60 -0
  132. package/dist/server/file_fact_url.d.ts +53 -0
  133. package/dist/server/file_fact_url.d.ts.map +1 -0
  134. package/dist/server/file_fact_url.js +52 -0
  135. package/dist/server/serve_fact_route.d.ts +78 -0
  136. package/dist/server/serve_fact_route.d.ts.map +1 -0
  137. package/dist/server/serve_fact_route.js +205 -0
  138. package/dist/testing/CLAUDE.md +142 -6
  139. package/dist/testing/app_server.d.ts +46 -0
  140. package/dist/testing/app_server.d.ts.map +1 -1
  141. package/dist/testing/app_server.js +67 -8
  142. package/dist/testing/audit_completeness.d.ts.map +1 -1
  143. package/dist/testing/audit_completeness.js +67 -1
  144. package/dist/testing/cross_backend/account_lifecycle.d.ts +10 -0
  145. package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -0
  146. package/dist/testing/cross_backend/account_lifecycle.js +144 -0
  147. package/dist/testing/cross_backend/actor_lookup.d.ts +10 -0
  148. package/dist/testing/cross_backend/actor_lookup.d.ts.map +1 -0
  149. package/dist/testing/cross_backend/actor_lookup.js +83 -0
  150. package/dist/testing/cross_backend/actor_search.d.ts +6 -0
  151. package/dist/testing/cross_backend/actor_search.d.ts.map +1 -0
  152. package/dist/testing/cross_backend/actor_search.js +92 -0
  153. package/dist/testing/cross_backend/app_settings.d.ts +6 -0
  154. package/dist/testing/cross_backend/app_settings.d.ts.map +1 -0
  155. package/dist/testing/cross_backend/app_settings.js +95 -0
  156. package/dist/testing/cross_backend/backend_config.d.ts +1 -1
  157. package/dist/testing/cross_backend/capabilities.d.ts +29 -7
  158. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
  159. package/dist/testing/cross_backend/capabilities.js +3 -1
  160. package/dist/testing/cross_backend/cell_cross_helpers.d.ts +39 -0
  161. package/dist/testing/cross_backend/cell_cross_helpers.d.ts.map +1 -0
  162. package/dist/testing/cross_backend/cell_cross_helpers.js +45 -0
  163. package/dist/testing/cross_backend/cell_crud.d.ts +4 -0
  164. package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -0
  165. package/dist/testing/cross_backend/cell_crud.js +168 -0
  166. package/dist/testing/cross_backend/cell_grant_role.d.ts +8 -0
  167. package/dist/testing/cross_backend/cell_grant_role.d.ts.map +1 -0
  168. package/dist/testing/cross_backend/cell_grant_role.js +102 -0
  169. package/dist/testing/cross_backend/cell_relations.d.ts +4 -0
  170. package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -0
  171. package/dist/testing/cross_backend/cell_relations.js +229 -0
  172. package/dist/testing/cross_backend/conformance_case.d.ts +144 -0
  173. package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -0
  174. package/dist/testing/cross_backend/conformance_case.js +132 -0
  175. package/dist/testing/cross_backend/conformance_table.d.ts +46 -0
  176. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -0
  177. package/dist/testing/cross_backend/conformance_table.js +199 -0
  178. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  179. package/dist/testing/cross_backend/default_backend_configs.js +6 -2
  180. package/dist/testing/cross_backend/default_spine_surface.d.ts +17 -9
  181. package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
  182. package/dist/testing/cross_backend/default_spine_surface.js +20 -12
  183. package/dist/testing/cross_backend/origin.d.ts +10 -0
  184. package/dist/testing/cross_backend/origin.d.ts.map +1 -0
  185. package/dist/testing/cross_backend/origin.js +73 -0
  186. package/dist/testing/cross_backend/setup.d.ts +22 -40
  187. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  188. package/dist/testing/cross_backend/setup.js +39 -5
  189. package/dist/testing/cross_backend/testing_reset_actions.d.ts +90 -2
  190. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  191. package/dist/testing/cross_backend/testing_reset_actions.js +91 -3
  192. package/dist/testing/cross_backend/xfail.d.ts +15 -0
  193. package/dist/testing/cross_backend/xfail.d.ts.map +1 -0
  194. package/dist/testing/cross_backend/xfail.js +37 -0
  195. package/dist/testing/entities.d.ts.map +1 -1
  196. package/dist/testing/entities.js +4 -0
  197. package/dist/testing/integration.d.ts +2 -3
  198. package/dist/testing/integration.d.ts.map +1 -1
  199. package/dist/testing/integration.js +20 -85
  200. package/dist/testing/rate_limiting.d.ts +1 -1
  201. package/dist/testing/rpc_helpers.d.ts +3 -3
  202. package/dist/testing/sse_round_trip.d.ts +1 -1
  203. package/dist/testing/stubs.d.ts.map +1 -1
  204. package/dist/testing/stubs.js +0 -1
  205. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  206. package/dist/testing/ws_round_trip.js +4 -0
  207. package/dist/ui/AdminAccounts.svelte +84 -35
  208. package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
  209. package/dist/ui/AdminSessions.svelte +21 -23
  210. package/dist/ui/AdminSessions.svelte.d.ts.map +1 -1
  211. package/dist/ui/CLAUDE.md +17 -26
  212. package/dist/ui/OpenSignupToggle.svelte +2 -5
  213. package/dist/ui/OpenSignupToggle.svelte.d.ts.map +1 -1
  214. package/dist/ui/account_sessions_state.svelte.d.ts +9 -10
  215. package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
  216. package/dist/ui/account_sessions_state.svelte.js +7 -17
  217. package/dist/ui/admin_accounts_state.svelte.d.ts +41 -20
  218. package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
  219. package/dist/ui/admin_accounts_state.svelte.js +52 -22
  220. package/dist/ui/admin_invites_state.svelte.d.ts +8 -11
  221. package/dist/ui/admin_invites_state.svelte.d.ts.map +1 -1
  222. package/dist/ui/admin_invites_state.svelte.js +7 -16
  223. package/dist/ui/admin_rpc_adapters.d.ts +6 -2
  224. package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
  225. package/dist/ui/admin_rpc_adapters.js +5 -1
  226. package/dist/ui/admin_sessions_state.svelte.d.ts +6 -10
  227. package/dist/ui/admin_sessions_state.svelte.d.ts.map +1 -1
  228. package/dist/ui/admin_sessions_state.svelte.js +4 -14
  229. package/dist/ui/app_settings_state.svelte.d.ts +8 -12
  230. package/dist/ui/app_settings_state.svelte.d.ts.map +1 -1
  231. package/dist/ui/app_settings_state.svelte.js +6 -16
  232. package/dist/ui/audit_log_state.svelte.d.ts +9 -8
  233. package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
  234. package/dist/ui/audit_log_state.svelte.js +8 -20
  235. package/package.json +2 -2
@@ -37,12 +37,23 @@ import { create_test_app_surface_spec } from '../stubs.js';
37
37
  */
38
38
  export const spine_session_options = create_session_config('fuz_session');
39
39
  /**
40
- * Built-in roles only — the standard spine registers no app-defined role
41
- * specs. When the spine grows additional grantable roles, thread their
42
- * registry through `create_role_schema` here so the admin suite picks up
43
- * grant-path coverage.
40
+ * App role the role-shaped-`cell_grant` cross suite exercises. Registered
41
+ * with no grant path (`grant_paths: []`) so it stays a valid registry member
42
+ * without entering the admin / self-service grant flows holders are seeded
43
+ * directly via `extra_accounts`. Must match the `cell_editor` entry in the
44
+ * Rust `testing_spine_stub`'s `known_roles` (cross-language test contract).
44
45
  */
45
- export const spine_roles = create_role_schema([]);
46
+ export const SPINE_CELL_EDITOR_ROLE = 'cell_editor';
47
+ /**
48
+ * The spine's closed role registry: built-ins plus `SPINE_CELL_EDITOR_ROLE`.
49
+ * Threaded into the cell spec set's role-validity gate; the Rust stub mirrors
50
+ * the same membership. When the spine grows additional grantable roles,
51
+ * thread their registry through `create_role_schema` here so the admin suite
52
+ * picks up grant-path coverage.
53
+ */
54
+ export const spine_roles = create_role_schema([
55
+ { name: SPINE_CELL_EDITOR_ROLE, grant_paths: [] },
56
+ ]);
46
57
  /** RPC endpoint mount path — matches the binary's `/api/rpc`. */
47
58
  export const SPINE_RPC_PATH = '/api/rpc';
48
59
  /**
@@ -54,11 +65,10 @@ export const SPINE_RPC_PATH = '/api/rpc';
54
65
  */
55
66
  export const SPINE_SSE_PATH = '/api/admin/audit/stream';
56
67
  /**
57
- * Factory-form RPC endpoints so the `app_settings_update` handler closes
58
- * over the per-test `ctx.app_settings`. `create_app_server` (in the binary)
59
- * owns live dispatch; the surface builder invokes the factory once with a
60
- * stub ctx for setup-time path/method lookup, so the handler closures are
61
- * never called across the process boundary.
68
+ * Factory-form RPC endpoints over the per-test `ctx.deps`. `create_app_server`
69
+ * (in the binary) owns live dispatch; the surface builder invokes the factory
70
+ * once with a stub ctx for setup-time path/method lookup, so the handler
71
+ * closures are never called across the process boundary.
62
72
  *
63
73
  * Test binaries append their own `_testing_reset` action to this endpoint's
64
74
  * `actions` (see `testing_reset_actions.ts`); it is intentionally excluded
@@ -69,7 +79,6 @@ export const spine_rpc_endpoints = (ctx) => [
69
79
  {
70
80
  path: SPINE_RPC_PATH,
71
81
  actions: create_standard_rpc_actions(ctx.deps, {
72
- app_settings: ctx.app_settings,
73
82
  roles: spine_roles,
74
83
  }),
75
84
  },
@@ -97,7 +106,6 @@ export const create_spine_route_specs = (ctx) => [
97
106
  session_options: spine_session_options,
98
107
  ip_rate_limiter: null,
99
108
  signup_account_rate_limiter: null,
100
- app_settings: ctx.app_settings,
101
109
  }),
102
110
  ]),
103
111
  ...(ctx.audit_sse
@@ -0,0 +1,10 @@
1
+ import '../assert_dev_env.js';
2
+ import type { CellCrossTestOptions } from './cell_cross_helpers.js';
3
+ /**
4
+ * Options for the origin parity suite. Shares the shape of the cell /
5
+ * account-lifecycle suites (`setup_test` / `capabilities` / `rpc_path`);
6
+ * reuses `CellCrossTestOptions` rather than minting a structural duplicate.
7
+ */
8
+ export type OriginCrossTestOptions = CellCrossTestOptions;
9
+ export declare const describe_origin_cross_tests: (options: OriginCrossTestOptions) => void;
10
+ //# sourceMappingURL=origin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origin.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/origin.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAkC9B,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAGlE;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAM1D,eAAO,MAAM,2BAA2B,GAAI,SAAS,sBAAsB,KAAG,IAwC7E,CAAC"}
@@ -0,0 +1,73 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Cross-backend parity suite for Origin verification.
4
+ *
5
+ * Origin checking is middleware that runs *before* the RPC dispatcher and
6
+ * returns a flat REST `{error}` body — not a JSON-RPC envelope — so it
7
+ * doesn't fit the envelope-shaped conformance-table runner. This dedicated
8
+ * imperative suite drives raw transport calls instead, mirroring how the
9
+ * in-process origin tests were already hand-rolled. Two cases:
10
+ *
11
+ * - **disallowed `Origin` → 403** `forbidden_origin`, refused before any
12
+ * handler runs (the allowlist rejects the cross-origin request even with
13
+ * a valid session cookie attached).
14
+ * - **absent `Origin` → request passes** — non-browser / direct-access
15
+ * clients (curl, CLI, server-to-server) carry no `Origin` and must not be
16
+ * blocked; token auth is the control for those callers.
17
+ *
18
+ * Runs both legs via the shared `{setup_test, capabilities}` protocol: the
19
+ * in-process leg (`auth/origin_parity.db.test.ts`, plain `gro test`) and the
20
+ * cross-process leg (`cross_backend/origin.cross.test.ts`, the TS spine
21
+ * binaries + Rust `testing_spine_stub` over real HTTP). Origin middleware is
22
+ * on every spine, so the suite is ungated.
23
+ *
24
+ * `$lib`-free by contract (relative specifiers only), like the sibling
25
+ * cross-backend suites.
26
+ *
27
+ * @module
28
+ */
29
+ import { describe, test, assert } from 'vitest';
30
+ import { account_verify_action_spec } from '../../auth/account_action_specs.js';
31
+ import { ERROR_FORBIDDEN_ORIGIN } from '../../http/error_schemas.js';
32
+ import { SPINE_RPC_PATH } from './default_spine_surface.js';
33
+ /** Build the JSON-RPC envelope body for a nullary `account_verify` call. */
34
+ const verify_envelope = (id) => JSON.stringify({ jsonrpc: '2.0', method: account_verify_action_spec.method, id });
35
+ export const describe_origin_cross_tests = (options) => {
36
+ const { setup_test } = options;
37
+ const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
38
+ describe('origin verification parity', () => {
39
+ test('disallowed Origin → 403 forbidden_origin (refused before dispatch)', async () => {
40
+ const fixture = await setup_test();
41
+ // Keeper session cookie attached + a rogue Origin header (overrides
42
+ // the transport's default allowed Origin). The allowlist must reject
43
+ // before the dispatcher, returning a flat REST error body.
44
+ const res = await fixture.transport(rpc_path, {
45
+ method: 'POST',
46
+ headers: {
47
+ ...fixture.create_session_headers(),
48
+ origin: 'http://evil.com',
49
+ 'content-type': 'application/json',
50
+ },
51
+ body: verify_envelope('evil-origin'),
52
+ });
53
+ assert.strictEqual(res.status, 403, 'disallowed Origin must be rejected with 403');
54
+ const body = (await res.json().catch(() => undefined));
55
+ assert.strictEqual(body?.error, ERROR_FORBIDDEN_ORIGIN);
56
+ });
57
+ test('absent Origin → request passes (non-browser direct access)', async () => {
58
+ const fixture = await setup_test();
59
+ // `origin: null` so no Origin header is sent at all (a header omission
60
+ // alone wouldn't suffice cross-process — the jar auto-adds the default
61
+ // allowed Origin). The keeper cookie rides via an explicit header.
62
+ const res = await fixture.fresh_transport({ origin: null })(rpc_path, {
63
+ method: 'POST',
64
+ headers: {
65
+ ...fixture.create_session_headers(),
66
+ 'content-type': 'application/json',
67
+ },
68
+ body: verify_envelope('no-origin'),
69
+ });
70
+ assert.strictEqual(res.status, 200, 'absent Origin with a valid session must pass');
71
+ });
72
+ });
73
+ };
@@ -1,10 +1,9 @@
1
1
  import '../assert_dev_env.js';
2
2
  import { Uuid } from '@fuzdev/fuz_util/id.js';
3
- import type { Keyring } from '../../auth/keyring.js';
4
3
  import type { RouteSpec } from '../../http/route_spec.js';
5
4
  import type { AppServerContext, BootstrapServerOptions } from '../../server/app_server.js';
6
5
  import type { SessionOptions } from '../../auth/session_cookie.js';
7
- import { type CreateTestAppOptions, type SuiteAppOptions, type TestAccount, type TestAppServer } from '../app_server.js';
6
+ import { type CreateTestAppOptions, type SuiteAppOptions, type TestAccount } from '../app_server.js';
8
7
  import { type RpcEndpointsSuiteOption } from '../rpc_helpers.js';
9
8
  import { type BackendCapabilities } from './capabilities.js';
10
9
  import type { AppSurfaceSpec } from '../../http/surface.js';
@@ -140,49 +139,32 @@ export interface TestFixtureBase {
140
139
  * for suites that don't declare any.
141
140
  */
142
141
  readonly extra_accounts: Readonly<Record<string, ExtraAccountFixture>>;
142
+ /**
143
+ * Forge an *expired server-side session* for the keeper account and
144
+ * return the ready-to-send `Cookie` header value (`name=value`). The
145
+ * minted `auth_session` row is backdated while the signed cookie payload
146
+ * stays valid — so resolution clears the cookie-payload gate
147
+ * (`parse_session`) and is refused at the authoritative DB-row gate
148
+ * (`query_session_get_valid` — `WHERE expires_at > NOW()`). Backs the
149
+ * `expired_session` conformance principal. In-process mints directly via
150
+ * `mint_test_session`; cross-process drives the `_testing_mint_session`
151
+ * RPC over the keeper's daemon-token channel (the driver has no keyring).
152
+ */
153
+ readonly mint_expired_session: () => Promise<string>;
143
154
  }
144
155
  /**
145
156
  * The per-test bundle returned by `SetupTest`. Every Tier 1 suite body
146
- * reads exclusively from this shape — no `test_app.backend.*` reads
147
- * remain in the suite bodies.
157
+ * reads exclusively from this shape — no `test_app.backend.*` reads remain
158
+ * in the suite bodies.
148
159
  *
149
- * Discriminated by `in_process`: when `true`, `keyring` and
150
- * `backend_internals` are present (compile-time narrowed); when `false`,
151
- * they're absent and the suite body must either run via the public wire
152
- * (cross-process) or gate the test with
153
- * `test_if(capabilities.in_process_only, ...)`. The discriminant value
154
- * mirrors `BackendCapabilities.in_process_only` — both source from the
155
- * same producer (`default_in_process_setup` vs. cross-process variant).
156
- *
157
- * Suite bodies narrow with `assert(fixture.in_process)` after
158
- * `setup_test()`; sites that reach for `keyring` or `backend_internals`
159
- * are in-process-only by structure and the assertion surfaces a clear
160
- * failure if a future cross-process consumer reaches them without a
161
- * `test_if` gate.
160
+ * Transport-agnostic: in-process and cross-process producers return the
161
+ * same shape. Behaviors that once needed raw backend access (keyring for
162
+ * forging cookies) are reached through wire-shaped seams instead
163
+ * `mint_expired_session()` mints over the `_testing_mint_session` channel
164
+ * cross-process and directly in-process, so suite bodies never branch on
165
+ * the transport.
162
166
  */
163
- export type TestFixture = (TestFixtureBase & {
164
- readonly in_process: true;
165
- /**
166
- * Test-only keyring access — in-process only. Used for
167
- * expired-cookie generation in `describe_standard_integration_tests`.
168
- */
169
- readonly keyring: Keyring;
170
- /**
171
- * Raw backend access (`deps.db`, etc.) — in-process only. Used
172
- * by the origin-verification cookie-composition sites in
173
- * `describe_standard_integration_tests`. Tests that need a
174
- * direct DB role_grant seed at the in-process layer reach for
175
- * `create_test_role_grant_direct` from `db_entities.ts`; that
176
- * helper bypasses the consent flow on purpose for query-level
177
- * (`*.db.test.ts`) tests and has no cross-process analog.
178
- * Cross-process tests grant additional roles via
179
- * `fixture.create_account({roles})` (offer/accept) or
180
- * `extra_accounts` (bootstrap-time bypass).
181
- */
182
- readonly backend_internals: TestAppServer;
183
- }) | (TestFixtureBase & {
184
- readonly in_process: false;
185
- });
167
+ export type TestFixture = TestFixtureBase;
186
168
  /**
187
169
  * Per-test fixture-producing function. Invoked once inside every
188
170
  * `test()` body. The implementation captures factory inputs (in-process)
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/setup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/setup.ts"],"names":[],"mappings":"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"}
@@ -23,7 +23,7 @@ import { Uuid } from '@fuzdev/fuz_util/id.js';
23
23
  import { ROLE_KEEPER } from '../../auth/role_schema.js';
24
24
  import { DAEMON_TOKEN_HEADER } from '../../auth/daemon_token.js';
25
25
  import { USERNAME_LENGTH_MAX } from '../../primitive_schemas.js';
26
- import { create_test_app, create_test_account_with_credentials, DEFAULT_TEST_PASSWORD, } from '../app_server.js';
26
+ import { create_test_app, create_test_account_with_credentials, mint_test_session, DEFAULT_TEST_PASSWORD, } from '../app_server.js';
27
27
  import { create_test_app_surface_spec } from '../stubs.js';
28
28
  import { http_transport, } from '../rpc_helpers.js';
29
29
  import { in_process_capabilities } from './capabilities.js';
@@ -85,6 +85,11 @@ const in_process_fetch_transport = (app) => {
85
85
  * beyond what `create_test_app` already does.
86
86
  */
87
87
  export const default_in_process_setup = (options) => async () => {
88
+ // Per-test fresh db. When `options.migration_namespaces` is set,
89
+ // `create_test_app` provisions an auth+extras PGlite (e.g. the cell
90
+ // layer); otherwise the auth-only default. Either way the factory
91
+ // resets + re-migrates on each `create`, so the per-test keeper
92
+ // bootstrap below lands on a clean DB.
88
93
  const test_app = await create_test_app(options);
89
94
  // Seed bootstrap-time secondaries against the same DB the keeper
90
95
  // just landed on. Direct-insert is the only path for roles whose
@@ -105,7 +110,6 @@ export const default_in_process_setup = (options) => async () => {
105
110
  extra_accounts[spec.username] = build_extra_account_fixture(seeded, cookie_name);
106
111
  }
107
112
  return {
108
- in_process: true,
109
113
  transport: in_process_fetch_transport(test_app.app),
110
114
  // In-process the wrapper is stateless and never auto-adds Origin —
111
115
  // `options` is accepted for API symmetry with cross-process but
@@ -118,8 +122,18 @@ export const default_in_process_setup = (options) => async () => {
118
122
  create_daemon_token_headers: test_app.create_daemon_token_headers,
119
123
  create_account: test_app.create_account,
120
124
  extra_accounts,
121
- keyring: test_app.backend.keyring,
122
- backend_internals: test_app.backend,
125
+ // Forge directly against the live backend's DB + keyring — no wire
126
+ // hop needed in-process.
127
+ mint_expired_session: async () => {
128
+ const { session_cookie } = await mint_test_session({
129
+ db: test_app.backend.deps.db,
130
+ keyring: test_app.backend.keyring,
131
+ session_options: options.session_options,
132
+ account_id: test_app.backend.account.id,
133
+ expires_in_seconds: EXPIRED_SESSION_OFFSET_SECONDS,
134
+ });
135
+ return `${cookie_name}=${session_cookie}`;
136
+ },
123
137
  };
124
138
  };
125
139
  /**
@@ -219,6 +233,15 @@ const rpc_via_transport = async (transport, rpc_path, method, params, backend_na
219
233
  }
220
234
  return raw.result;
221
235
  };
236
+ /**
237
+ * Backdating offset (seconds) the `mint_expired_session` seam passes to
238
+ * `mint_test_session` / `_testing_mint_session`. A minute in the past is
239
+ * comfortably past `NOW()` for the DB-row expiry gate without depending on
240
+ * clock precision.
241
+ */
242
+ const EXPIRED_SESSION_OFFSET_SECONDS = -60;
243
+ /** Structural subset of `_testing_mint_session`'s output. */
244
+ const MintSessionResponseShape = z.object({ session_cookie: z.string() });
222
245
  /** Structural subset of `_testing_reset`'s output. */
223
246
  const TestingResetResponseShape = z.object({
224
247
  account: z.object({ id: Uuid, username: z.string() }),
@@ -499,7 +522,6 @@ export const default_cross_process_setup = (handle, options) => {
499
522
  initial_cookies: [`${cookie_name}=${keeper.session_cookie}`],
500
523
  });
501
524
  return {
502
- in_process: false,
503
525
  transport,
504
526
  fresh_transport: (fresh_options) => create_fetch_transport({
505
527
  base_url: handle.config.base_url,
@@ -512,6 +534,18 @@ export const default_cross_process_setup = (handle, options) => {
512
534
  create_daemon_token_headers,
513
535
  create_account,
514
536
  extra_accounts,
537
+ // Forge over the wire — the cross-process driver has no keyring,
538
+ // so `_testing_mint_session` mints the backdated row + signs the
539
+ // cookie server-side over the keeper's daemon-token channel.
540
+ mint_expired_session: async () => {
541
+ const raw = await rpc_via_transport(refreshed_handle.keeper_transport, handle.config.rpc_path, '_testing_mint_session', { account_id: keeper.account.id, expires_in_seconds: EXPIRED_SESSION_OFFSET_SECONDS }, handle.config.name, { [DAEMON_TOKEN_HEADER]: handle.daemon_token });
542
+ const parsed = MintSessionResponseShape.safeParse(raw);
543
+ if (!parsed.success) {
544
+ throw new Error(`_testing_mint_session(${handle.config.name}) returned unexpected result: ` +
545
+ `${JSON.stringify(raw)} (${parsed.error.message})`);
546
+ }
547
+ return `${cookie_name}=${parsed.data.session_cookie}`;
548
+ },
515
549
  };
516
550
  };
517
551
  };
@@ -2,8 +2,14 @@ import '../assert_dev_env.js';
2
2
  /**
3
3
  * Test-binary RPC actions for cross-process integration tests.
4
4
  *
5
- * Single daemon-token-authed action: **`_testing_reset`** full DB
6
- * wipe + keeper re-seed + optional secondary-account seeding. The
5
+ * Three daemon-token-authed actions, bundled by `create_testing_actions`:
6
+ * **`_testing_reset`** (DB wipe + keeper re-seed), **`_testing_drain_effects`**
7
+ * (audit barrier), and **`_testing_mint_session`** (forge an
8
+ * expired-by-construction server-side session for the expiry conformance
9
+ * cases).
10
+ *
11
+ * `_testing_reset` — full DB wipe + keeper re-seed + optional
12
+ * secondary-account seeding. The
7
13
  * handler wipes every auth-namespace row (no keeper-preserve filter),
8
14
  * flips `bootstrap_lock` back to its post-bootstrap shape, seeds a
9
15
  * fresh keeper account inline (reusing `create_test_account_with_credentials`
@@ -124,6 +130,88 @@ export declare const testing_reset_action_spec: {
124
130
  readonly async: true;
125
131
  readonly description: "Test-binary only — wipe auth tables, re-bootstrap a fresh keeper (+ optional extras), fire the domain-state reset.";
126
132
  };
133
+ /**
134
+ * `_testing_drain_effects` — await in-flight fire-and-forget audit writes so
135
+ * a following `audit_log_list` is authoritative. The deterministic barrier
136
+ * the cross-backend conformance suite uses in place of a poll/sleep before
137
+ * asserting on audit rows.
138
+ *
139
+ * On the TS spine the barrier is **satisfied by construction**: the test
140
+ * binary runs `await_pending_effects: true`, so every mutation's fire-and-
141
+ * forget audit emits are awaited before its response returns — by the time
142
+ * a later drain call runs, prior emits are already durable. The action still
143
+ * exists so the cross-backend test body calls the same method on every
144
+ * backend; the Rust spine (whose audit writes are detached tokio tasks)
145
+ * does the real await in `AuditEmitter::drain_inflight`.
146
+ *
147
+ * `auth` gates on the daemon-token credential, matching `_testing_reset`.
148
+ */
149
+ export declare const testing_drain_effects_action_spec: {
150
+ readonly method: "_testing_drain_effects";
151
+ readonly kind: "request_response";
152
+ readonly initiator: "frontend";
153
+ readonly auth: {
154
+ readonly account: "required";
155
+ readonly actor: "none";
156
+ readonly credential_types: readonly ["daemon_token"];
157
+ };
158
+ readonly side_effects: false;
159
+ readonly input: z.ZodVoid;
160
+ readonly output: z.ZodObject<{
161
+ ok: z.ZodBoolean;
162
+ }, z.core.$strict>;
163
+ readonly async: true;
164
+ readonly description: "Test-binary only — await in-flight fire-and-forget audit writes so a following audit_log_list read is authoritative.";
165
+ };
166
+ /**
167
+ * `_testing_mint_session` — mint an expired-by-construction server-side
168
+ * session for an existing account and return its signed cookie value.
169
+ *
170
+ * The minted `auth_session` row's `expires_at` is backdated (negative
171
+ * `expires_in_seconds`) while the returned cookie's own signed payload
172
+ * stays valid (future). Cross-process auth resolution therefore passes the
173
+ * cookie-payload gate (`parse_session`) and is refused by the authoritative
174
+ * DB-row gate (`query_session_get_valid` — `WHERE expires_at > NOW()`) —
175
+ * the gate the in-process payload-expiry tests never reach and the one that
176
+ * structurally needs a server-side mint (the cross-process driver has no
177
+ * keyring / DB access). The `expired_session` conformance principal drives
178
+ * this.
179
+ *
180
+ * `auth` gates on the daemon-token credential, matching `_testing_reset` —
181
+ * effectively keeper-only. Like its siblings the action is internally
182
+ * privileged (a direct `auth_session` insert the production wire never
183
+ * exposes); daemon-token auth is the structural fence and the module's
184
+ * `assert_dev_env` import (TS) plus the Rust `cargo xtask check-release`
185
+ * dep-graph audit keep the `_testing_` surface out of every shipped build.
186
+ */
187
+ export declare const testing_mint_session_action_spec: {
188
+ readonly method: "_testing_mint_session";
189
+ readonly kind: "request_response";
190
+ readonly initiator: "frontend";
191
+ readonly auth: {
192
+ readonly account: "required";
193
+ readonly actor: "none";
194
+ readonly credential_types: readonly ["daemon_token"];
195
+ };
196
+ readonly side_effects: true;
197
+ readonly input: z.ZodObject<{
198
+ account_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
199
+ expires_in_seconds: z.ZodNumber;
200
+ }, z.core.$strict>;
201
+ readonly output: z.ZodObject<{
202
+ session_cookie: z.ZodString;
203
+ }, z.core.$strict>;
204
+ readonly async: true;
205
+ readonly description: string;
206
+ };
207
+ /**
208
+ * Build the standalone `_testing_drain_effects` action. No deps — on TS the
209
+ * barrier is satisfied by `await_pending_effects` (see the spec doc), so the
210
+ * handler just returns `{ok: true}`. Mount it on any test endpoint whose
211
+ * suite asserts on audit rows (the spine binary bundles it via
212
+ * `create_testing_actions`; in-process suites mount it directly).
213
+ */
214
+ export declare const create_testing_drain_effects_action: () => RpcAction;
127
215
  /** Options for `create_testing_actions`. */
128
216
  export interface CreateTestingActionsOptions {
129
217
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAEvE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AAajE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwBQ,CAAC;AAE/C,4CAA4C;AAC5C,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;IAC9C;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAClD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CA4FjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,UAAmC,CAAC"}
1
+ {"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAEvE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AAiBjE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwBQ,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAeC,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAO,SACiB,CAAC;AAEzE,4CAA4C;AAC5C,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;IAC9C;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAClD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CAuGjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,UAAmC,CAAC"}
@@ -2,8 +2,14 @@ import '../assert_dev_env.js';
2
2
  /**
3
3
  * Test-binary RPC actions for cross-process integration tests.
4
4
  *
5
- * Single daemon-token-authed action: **`_testing_reset`** full DB
6
- * wipe + keeper re-seed + optional secondary-account seeding. The
5
+ * Three daemon-token-authed actions, bundled by `create_testing_actions`:
6
+ * **`_testing_reset`** (DB wipe + keeper re-seed), **`_testing_drain_effects`**
7
+ * (audit barrier), and **`_testing_mint_session`** (forge an
8
+ * expired-by-construction server-side session for the expiry conformance
9
+ * cases).
10
+ *
11
+ * `_testing_reset` — full DB wipe + keeper re-seed + optional
12
+ * secondary-account seeding. The
7
13
  * handler wipes every auth-namespace row (no keeper-preserve filter),
8
14
  * flips `bootstrap_lock` back to its post-bootstrap shape, seeds a
9
15
  * fresh keeper account inline (reusing `create_test_account_with_credentials`
@@ -56,7 +62,7 @@ import { Uuid } from '@fuzdev/fuz_util/id.js';
56
62
  import { rpc_action } from '../../actions/action_rpc.js';
57
63
  import { ROLE_ADMIN, ROLE_KEEPER } from '../../auth/role_schema.js';
58
64
  import { auth_integration_truncate_tables } from '../db.js';
59
- import { create_test_account_with_credentials, DEFAULT_TEST_PASSWORD } from '../app_server.js';
65
+ import { create_test_account_with_credentials, mint_test_session, DEFAULT_TEST_PASSWORD, } from '../app_server.js';
60
66
  /** Output shape for an individual seeded account (keeper or extra). */
61
67
  const SeededAccountShape = z.strictObject({
62
68
  account: z.strictObject({ id: Uuid, username: z.string() }),
@@ -111,6 +117,77 @@ export const testing_reset_action_spec = {
111
117
  async: true,
112
118
  description: 'Test-binary only — wipe auth tables, re-bootstrap a fresh keeper (+ optional extras), fire the domain-state reset.',
113
119
  };
120
+ /**
121
+ * `_testing_drain_effects` — await in-flight fire-and-forget audit writes so
122
+ * a following `audit_log_list` is authoritative. The deterministic barrier
123
+ * the cross-backend conformance suite uses in place of a poll/sleep before
124
+ * asserting on audit rows.
125
+ *
126
+ * On the TS spine the barrier is **satisfied by construction**: the test
127
+ * binary runs `await_pending_effects: true`, so every mutation's fire-and-
128
+ * forget audit emits are awaited before its response returns — by the time
129
+ * a later drain call runs, prior emits are already durable. The action still
130
+ * exists so the cross-backend test body calls the same method on every
131
+ * backend; the Rust spine (whose audit writes are detached tokio tasks)
132
+ * does the real await in `AuditEmitter::drain_inflight`.
133
+ *
134
+ * `auth` gates on the daemon-token credential, matching `_testing_reset`.
135
+ */
136
+ export const testing_drain_effects_action_spec = {
137
+ method: '_testing_drain_effects',
138
+ kind: 'request_response',
139
+ initiator: 'frontend',
140
+ auth: { account: 'required', actor: 'none', credential_types: ['daemon_token'] },
141
+ side_effects: false,
142
+ input: z.void(),
143
+ output: z.strictObject({ ok: z.boolean() }),
144
+ async: true,
145
+ description: 'Test-binary only — await in-flight fire-and-forget audit writes so a following audit_log_list read is authoritative.',
146
+ };
147
+ /**
148
+ * `_testing_mint_session` — mint an expired-by-construction server-side
149
+ * session for an existing account and return its signed cookie value.
150
+ *
151
+ * The minted `auth_session` row's `expires_at` is backdated (negative
152
+ * `expires_in_seconds`) while the returned cookie's own signed payload
153
+ * stays valid (future). Cross-process auth resolution therefore passes the
154
+ * cookie-payload gate (`parse_session`) and is refused by the authoritative
155
+ * DB-row gate (`query_session_get_valid` — `WHERE expires_at > NOW()`) —
156
+ * the gate the in-process payload-expiry tests never reach and the one that
157
+ * structurally needs a server-side mint (the cross-process driver has no
158
+ * keyring / DB access). The `expired_session` conformance principal drives
159
+ * this.
160
+ *
161
+ * `auth` gates on the daemon-token credential, matching `_testing_reset` —
162
+ * effectively keeper-only. Like its siblings the action is internally
163
+ * privileged (a direct `auth_session` insert the production wire never
164
+ * exposes); daemon-token auth is the structural fence and the module's
165
+ * `assert_dev_env` import (TS) plus the Rust `cargo xtask check-release`
166
+ * dep-graph audit keep the `_testing_` surface out of every shipped build.
167
+ */
168
+ export const testing_mint_session_action_spec = {
169
+ method: '_testing_mint_session',
170
+ kind: 'request_response',
171
+ initiator: 'frontend',
172
+ auth: { account: 'required', actor: 'none', credential_types: ['daemon_token'] },
173
+ side_effects: true,
174
+ input: z.strictObject({
175
+ account_id: Uuid,
176
+ expires_in_seconds: z.number().int(),
177
+ }),
178
+ output: z.strictObject({ session_cookie: z.string() }),
179
+ async: true,
180
+ description: 'Test-binary only — mint a backdated-expiry auth_session row for an account and return its ' +
181
+ 'signed cookie value (exercises the authoritative server-side DB-row expiry gate).',
182
+ };
183
+ /**
184
+ * Build the standalone `_testing_drain_effects` action. No deps — on TS the
185
+ * barrier is satisfied by `await_pending_effects` (see the spec doc), so the
186
+ * handler just returns `{ok: true}`. Mount it on any test endpoint whose
187
+ * suite asserts on audit rows (the spine binary bundles it via
188
+ * `create_testing_actions`; in-process suites mount it directly).
189
+ */
190
+ export const create_testing_drain_effects_action = () => rpc_action(testing_drain_effects_action_spec, async () => ({ ok: true }));
114
191
  /**
115
192
  * Build the testing RPC actions for a test binary's registry.
116
193
  *
@@ -207,6 +284,17 @@ export const create_testing_actions = (deps, options) => {
207
284
  await reset_state();
208
285
  return { ...keeper, extra_accounts: extras };
209
286
  }),
287
+ rpc_action(testing_mint_session_action_spec, async (input, ctx) => {
288
+ const { session_cookie } = await mint_test_session({
289
+ db: ctx.db,
290
+ keyring: deps.keyring,
291
+ session_options,
292
+ account_id: input.account_id,
293
+ expires_in_seconds: input.expires_in_seconds,
294
+ });
295
+ return { session_cookie };
296
+ }),
297
+ create_testing_drain_effects_action(),
210
298
  ];
211
299
  };
212
300
  /** Set of auth-namespace tables `_testing_reset` wipes. Mirrored by the coverage test. */
@@ -0,0 +1,15 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Register `fn` as an expected-failure test. Passes while `fn` throws /
4
+ * rejects; **fails** once `fn` succeeds (signalling the gap closed and the
5
+ * marker should be removed).
6
+ *
7
+ * @param tracking_id - descriptive id of the tracked gap (e.g.
8
+ * `'audit-log-sse-rust-spine'`) — a feature/behavior name, not a
9
+ * process/milestone label.
10
+ * @param reason - why the case is deferred-by-design.
11
+ * @param name - the assertion / test label.
12
+ * @param fn - the test body (expected to throw/reject until the gap closes).
13
+ */
14
+ export declare const xfail_until: (tracking_id: string, reason: string, name: string, fn: () => void | Promise<void>) => void;
15
+ //# sourceMappingURL=xfail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xfail.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/xfail.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAyB9B;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,GACvB,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAC5B,IAEF,CAAC"}
@@ -0,0 +1,37 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * `xfail_until` — mark a deferred-by-design gap as an expected failure.
4
+ *
5
+ * A thin wrapper over vitest's `test.fails` that bakes a tracking id +
6
+ * reason into the test label. Two properties make it the right tool for
7
+ * declared gaps (distinct from in-scope gaps, which fail loud as a normal
8
+ * red `test`):
9
+ *
10
+ * - **Visible** — the case shows in the report as a distinct expected
11
+ * failure, not a silent `.skip`, so a deferred gap never disappears from
12
+ * view.
13
+ * - **Self-cleaning** — `test.fails` turns **red** the moment the body
14
+ * stops throwing (i.e. the impl starts passing), forcing whoever closed
15
+ * the gap to delete the marker. A `.skip` would rot silently; this can't.
16
+ *
17
+ * Sibling to `test_if` in `capabilities.ts`. No taxonomy — a one-line
18
+ * marker with a tracking id and a reason, nothing more.
19
+ *
20
+ * @module
21
+ */
22
+ import { test } from 'vitest';
23
+ /**
24
+ * Register `fn` as an expected-failure test. Passes while `fn` throws /
25
+ * rejects; **fails** once `fn` succeeds (signalling the gap closed and the
26
+ * marker should be removed).
27
+ *
28
+ * @param tracking_id - descriptive id of the tracked gap (e.g.
29
+ * `'audit-log-sse-rust-spine'`) — a feature/behavior name, not a
30
+ * process/milestone label.
31
+ * @param reason - why the case is deferred-by-design.
32
+ * @param name - the assertion / test label.
33
+ * @param fn - the test body (expected to throw/reject until the gap closes).
34
+ */
35
+ export const xfail_until = (tracking_id, reason, name, fn) => {
36
+ test.fails(`${name} [xfail_until ${tracking_id}: ${reason}]`, fn);
37
+ };