@fuzdev/fuz_app 0.126.0 → 0.128.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 (77) hide show
  1. package/dist/actions/CLAUDE.md +37 -21
  2. package/dist/actions/connection_closer.d.ts +16 -4
  3. package/dist/actions/connection_closer.d.ts.map +1 -1
  4. package/dist/actions/connection_closer.js +20 -4
  5. package/dist/actions/register_action_ws.d.ts +10 -2
  6. package/dist/actions/register_action_ws.d.ts.map +1 -1
  7. package/dist/actions/register_action_ws.js +6 -3
  8. package/dist/actions/register_ws_endpoint.d.ts +3 -1
  9. package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
  10. package/dist/actions/register_ws_endpoint.js +3 -1
  11. package/dist/auth/CLAUDE.md +13 -9
  12. package/dist/auth/audit_emitter.d.ts +59 -12
  13. package/dist/auth/audit_emitter.d.ts.map +1 -1
  14. package/dist/auth/audit_emitter.js +53 -15
  15. package/dist/auth/middleware.d.ts +30 -0
  16. package/dist/auth/middleware.d.ts.map +1 -1
  17. package/dist/auth/middleware.js +59 -0
  18. package/dist/http/CLAUDE.md +3 -3
  19. package/dist/http/surface.d.ts +12 -11
  20. package/dist/http/surface.d.ts.map +1 -1
  21. package/dist/http/surface.js +1 -15
  22. package/dist/rate_limiter.d.ts +19 -1
  23. package/dist/rate_limiter.d.ts.map +1 -1
  24. package/dist/rate_limiter.js +23 -0
  25. package/dist/realtime/sse_auth_guard.d.ts +3 -1
  26. package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
  27. package/dist/server/app_server.d.ts +41 -13
  28. package/dist/server/app_server.d.ts.map +1 -1
  29. package/dist/server/app_server.js +105 -50
  30. package/dist/testing/CLAUDE.md +51 -38
  31. package/dist/testing/app_server.d.ts +1 -1
  32. package/dist/testing/app_server.d.ts.map +1 -1
  33. package/dist/testing/app_server.js +15 -14
  34. package/dist/testing/attack_surface.d.ts +1 -1
  35. package/dist/testing/attack_surface.d.ts.map +1 -1
  36. package/dist/testing/audit_drift_guard.d.ts +4 -2
  37. package/dist/testing/audit_drift_guard.d.ts.map +1 -1
  38. package/dist/testing/audit_drift_guard.js +14 -4
  39. package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
  40. package/dist/testing/cross_backend/account_lifecycle.js +1 -2
  41. package/dist/testing/cross_backend/capabilities.d.ts +3 -1
  42. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
  43. package/dist/testing/cross_backend/default_backend_configs.d.ts +3 -34
  44. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  45. package/dist/testing/cross_backend/default_backend_configs.js +1 -31
  46. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +1 -1
  47. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
  48. package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +3 -3
  49. package/dist/testing/cross_backend/spine_surface_constants.d.ts +43 -3
  50. package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
  51. package/dist/testing/cross_backend/spine_surface_constants.js +43 -3
  52. package/dist/testing/cross_backend/testing_backdoor.d.ts +15 -1
  53. package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
  54. package/dist/testing/cross_backend/testing_backdoor.js +49 -5
  55. package/dist/testing/cross_backend/testing_reset_actions.d.ts +27 -18
  56. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  57. package/dist/testing/cross_backend/testing_reset_actions.js +30 -19
  58. package/dist/testing/cross_backend/testing_server_core.d.ts +11 -11
  59. package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -1
  60. package/dist/testing/cross_backend/testing_server_core.js +2 -2
  61. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +0 -2
  62. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
  63. package/dist/testing/cross_backend/ts_spine_backend_config.js +2 -4
  64. package/dist/testing/cross_backend/ws_action_rate_limit.d.ts +1 -1
  65. package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -1
  66. package/dist/testing/cross_backend/ws_round_trip.d.ts +2 -1
  67. package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
  68. package/dist/testing/cross_backend/ws_round_trip.js +40 -4
  69. package/dist/testing/middleware.d.ts.map +1 -1
  70. package/dist/testing/middleware.js +4 -3
  71. package/dist/testing/stubs.d.ts +26 -6
  72. package/dist/testing/stubs.d.ts.map +1 -1
  73. package/dist/testing/stubs.js +56 -16
  74. package/dist/testing/ws_round_trip.d.ts +7 -31
  75. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  76. package/dist/testing/ws_round_trip.js +0 -38
  77. package/package.json +1 -1
@@ -44,8 +44,10 @@ export const install_audit_drift_guard = () => {
44
44
  * forward from the input envelope. Tests asserting on role-grant-shape
45
45
  * emissions read out of the same homogeneous `calls` array.
46
46
  * `notify` is a no-op; `add_listener` records into a local array that
47
- * `listener_count` reports (registered listeners never fire — this emitter
48
- * captures `emit` shapes, not fan-out).
47
+ * `listener_count` reports, and returns a remover with the production
48
+ * semantics (per registration, idempotent) — registered listeners never fire,
49
+ * since this emitter captures `emit` shapes, not fan-out. `drain_inflight` resolves at once:
50
+ * a recorded call writes nothing, so nothing is ever in flight.
49
51
  *
50
52
  * `emit` AND `emit_pool` both append to `calls`, so a test reads either
51
53
  * entry point's writes off the same array.
@@ -65,6 +67,7 @@ export const install_audit_drift_guard = () => {
65
67
  */
66
68
  export const create_recording_audit_emitter = (calls_ref) => {
67
69
  const calls = calls_ref ?? [];
70
+ // one entry per registration, as `create_audit_emitter` keeps them
68
71
  const listeners = [];
69
72
  const emitter = {
70
73
  emit: (_ctx, input) => {
@@ -88,9 +91,16 @@ export const create_recording_audit_emitter = (calls_ref) => {
88
91
  },
89
92
  notify: () => undefined,
90
93
  add_listener: (listener) => {
91
- listeners.push(listener);
94
+ const entry = { listener };
95
+ listeners.push(entry);
96
+ return () => {
97
+ const index = listeners.indexOf(entry);
98
+ if (index !== -1)
99
+ listeners.splice(index, 1);
100
+ };
92
101
  },
93
- listener_count: () => listeners.length
102
+ listener_count: () => listeners.length,
103
+ drain_inflight: () => Promise.resolve()
94
104
  };
95
105
  return { emitter, calls };
96
106
  };
@@ -1 +1 @@
1
- {"version":3,"file":"account_lifecycle.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/account_lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAsC9B,OAAO,KAAK,EAAE,uCAAuC,EAAE,MAAM,YAAY,CAAC;AAG1E;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG,uCAAuC,CAAC;AAEvF,eAAO,MAAM,sCAAsC,GAClD,SAAS,gCAAgC,KACvC,IAqUF,CAAC"}
1
+ {"version":3,"file":"account_lifecycle.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/account_lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAsC9B,OAAO,KAAK,EAAE,uCAAuC,EAAE,MAAM,YAAY,CAAC;AAG1E;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG,uCAAuC,CAAC;AAEvF,eAAO,MAAM,sCAAsC,GAClD,SAAS,gCAAgC,KACvC,IAoUF,CAAC"}
@@ -88,8 +88,7 @@ export const describe_account_lifecycle_cross_tests = (options) => {
88
88
  const del = await cross_rpc_call(t, rpc_path, 'account_delete', { account_id: fixture.account.id }, fixture.create_session_headers());
89
89
  assert.strictEqual(error_reason(del), ERROR_CANNOT_DELETE_KEEPER);
90
90
  // Deterministic barrier before reading: await in-flight
91
- // fire-and-forget audit writes (the real await on the Rust spine;
92
- // satisfied-by-construction on the TS spine via await_pending_effects).
91
+ // fire-and-forget audit writes on either spine.
93
92
  const td = fixture.fresh_transport({ origin: null });
94
93
  const drained = await cross_rpc_call(td, rpc_path, '_testing_drain_effects', undefined, fixture.create_daemon_token_headers());
95
94
  assert.ok(drained.ok, `_testing_drain_effects failed: ${JSON.stringify(drained.error)}`);
@@ -183,7 +183,9 @@ export interface BackendCapabilities {
183
183
  * (`account_session_revoke_all` among them), so a socket can revoke the
184
184
  * session it is running on. Gates the self-revocation case in
185
185
  * `describe_cross_process_ws_tests`: the socket reads the reply to its
186
- * request, then is closed with `WS_CLOSE_SESSION_REVOKED`.
186
+ * request, then is closed with `WS_CLOSE_SESSION_REVOKED`. Also gates that
187
+ * suite's WS-mutation audit case (with `rpc_path`; it calls
188
+ * `_testing_drain_effects`).
187
189
  *
188
190
  * `true` on fuz_app's own spine presets — the TS spine binary mounts its
189
191
  * full action set on `/api/ws`, and the Rust `testing_spine_stub` serves
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA4C9B;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,kCAAkC,EAAE,OAAO,CAAC;IACrD;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAC1C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,wBAAwB,EAAE,OAAO,CAAC;IAC3C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;CACpC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAsBpC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,iBAInC,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAG,IAMrF,CAAC"}
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA4C9B;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,kCAAkC,EAAE,OAAO,CAAC;IACrD;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAC1C;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,wBAAwB,EAAE,OAAO,CAAC;IAC3C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;CACpC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAsBpC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,iBAInC,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAG,IAMrF,CAAC"}
@@ -2,8 +2,8 @@ import '../assert_dev_env.js';
2
2
  /**
3
3
  * Family-shared `BackendConfig` builders for cross-process test backends.
4
4
  *
5
- * Two consumer-facing factories — {@link make_default_ts_backend_config}
6
- * and {@link make_default_rust_backend_config} — own the common shape
5
+ * Two consumer-facing factories — `make_default_ts_backend_config`
6
+ * and `make_default_rust_backend_config` — own the common shape
7
7
  * for the JS-runtime (Deno/Node on V8) and Rust families respectively.
8
8
  * Per-backend factories in consumer projects compose a small
9
9
  * declaration against one of these and add consumer-specific env vars
@@ -35,38 +35,7 @@ import '../assert_dev_env.js';
35
35
  import type { BackendBootstrapConfig, BackendConfig } from './backend_config.js';
36
36
  import type { BackendCapabilities, BackendShapeNotes } from './capabilities.js';
37
37
  import { type TestBackendPaths } from './build_test_backend_paths.js';
38
- /**
39
- * Env var both spine binaries read to enable their login rate limiters
40
- * (`'true'` on / unset off). The cross-language contract for the login-security
41
- * cross project: the TS binary reads it via `runtime.env_get` (a test-only flag,
42
- * not in `BaseServerEnv`); the Rust `testing_spine_stub` reads it via
43
- * `std::env::var` — so one backend-config option drives both impls. Shared home
44
- * here because both `ts_spine_backend_config` and `rust_spine_stub_backend_config`
45
- * already import this module. (The spawned TS binary re-declares the literal
46
- * locally — it can't import this module, which transitively pulls `vitest` —
47
- * mirroring how `testing_spine_server_node.ts` re-declares `TS_SPINE_DIR_ENV`.)
48
- */
49
- export declare const LOGIN_RATE_LIMIT_ENABLED_ENV = "FUZ_LOGIN_RATE_LIMIT_ENABLED";
50
- /**
51
- * Env var both spine binaries read to enable their action rate limiters
52
- * (`'true'` on / unset off) — one per-IP and one per-account limiter, shared by
53
- * the RPC and WS endpoints (and, on the Rust stub, the auth-family handlers
54
- * that charge in-handler). The cross-language contract for the action
55
- * rate-limit cross suite (`ws_action_rate_limit.ts`); same delivery as
56
- * `LOGIN_RATE_LIMIT_ENABLED_ENV`. Off, the TS spine builds no action limiter
57
- * and the Rust stub keeps its default posture (only its auth families charge,
58
- * against an always-on per-account limiter at the production cap).
59
- */
60
- export declare const ACTION_RATE_LIMIT_ENABLED_ENV = "FUZ_ACTION_RATE_LIMIT_ENABLED";
61
- /**
62
- * Env var replacing both action limiters' `max_attempts` (a positive integer;
63
- * the windows stay `default_action_ip_rate_limit`'s /
64
- * `default_action_account_rate_limit`'s). Both spine binaries refuse to boot
65
- * when it is set without `ACTION_RATE_LIMIT_ENABLED_ENV` or is not a positive
66
- * integer, so a suite never asserts a throttle the backend didn't build.
67
- */
68
- export declare const ACTION_RATE_LIMIT_MAX_ATTEMPTS_ENV = "FUZ_ACTION_RATE_LIMIT_MAX_ATTEMPTS";
69
- /** Options for {@link action_rate_limit_env}. */
38
+ /** Options for `action_rate_limit_env`. */
70
39
  export interface ActionRateLimitEnvOptions {
71
40
  readonly enable_action_rate_limit?: boolean;
72
41
  readonly action_rate_limit_max_attempts?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"default_backend_configs.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/default_backend_configs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"default_backend_configs.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/default_backend_configs.ts"],"names":[],"mappings":"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"}
@@ -1,37 +1,7 @@
1
1
  import '../assert_dev_env.js';
2
2
  import { build_test_backend_paths } from './build_test_backend_paths.js';
3
3
  import { default_test_bootstrap_token, default_test_cookie_keys, default_test_keeper_password, default_test_keeper_username } from './default_secrets.js';
4
- /**
5
- * Env var both spine binaries read to enable their login rate limiters
6
- * (`'true'` on / unset off). The cross-language contract for the login-security
7
- * cross project: the TS binary reads it via `runtime.env_get` (a test-only flag,
8
- * not in `BaseServerEnv`); the Rust `testing_spine_stub` reads it via
9
- * `std::env::var` — so one backend-config option drives both impls. Shared home
10
- * here because both `ts_spine_backend_config` and `rust_spine_stub_backend_config`
11
- * already import this module. (The spawned TS binary re-declares the literal
12
- * locally — it can't import this module, which transitively pulls `vitest` —
13
- * mirroring how `testing_spine_server_node.ts` re-declares `TS_SPINE_DIR_ENV`.)
14
- */
15
- export const LOGIN_RATE_LIMIT_ENABLED_ENV = 'FUZ_LOGIN_RATE_LIMIT_ENABLED';
16
- /**
17
- * Env var both spine binaries read to enable their action rate limiters
18
- * (`'true'` on / unset off) — one per-IP and one per-account limiter, shared by
19
- * the RPC and WS endpoints (and, on the Rust stub, the auth-family handlers
20
- * that charge in-handler). The cross-language contract for the action
21
- * rate-limit cross suite (`ws_action_rate_limit.ts`); same delivery as
22
- * `LOGIN_RATE_LIMIT_ENABLED_ENV`. Off, the TS spine builds no action limiter
23
- * and the Rust stub keeps its default posture (only its auth families charge,
24
- * against an always-on per-account limiter at the production cap).
25
- */
26
- export const ACTION_RATE_LIMIT_ENABLED_ENV = 'FUZ_ACTION_RATE_LIMIT_ENABLED';
27
- /**
28
- * Env var replacing both action limiters' `max_attempts` (a positive integer;
29
- * the windows stay `default_action_ip_rate_limit`'s /
30
- * `default_action_account_rate_limit`'s). Both spine binaries refuse to boot
31
- * when it is set without `ACTION_RATE_LIMIT_ENABLED_ENV` or is not a positive
32
- * integer, so a suite never asserts a throttle the backend didn't build.
33
- */
34
- export const ACTION_RATE_LIMIT_MAX_ATTEMPTS_ENV = 'FUZ_ACTION_RATE_LIMIT_MAX_ATTEMPTS';
4
+ import { ACTION_RATE_LIMIT_ENABLED_ENV, ACTION_RATE_LIMIT_MAX_ATTEMPTS_ENV } from './spine_surface_constants.js';
35
5
  /**
36
6
  * The `extra_env` entries carrying the action rate-limit toggles, shared by the
37
7
  * TS and Rust backend configs so one option pair drives both impls.
@@ -13,7 +13,7 @@ export declare const RUST_SPINE_STUB_DATABASE_URL_ENV = "FUZ_TESTING_RUST_SPINE_
13
13
  /**
14
14
  * Env var the stub reads for the absolute path of the committed
15
15
  * `expected_schema.json` its `/ready` gate introspects against. Pointed at the
16
- * **same** fixture the TS spine reads ({@link SPINE_EXPECTED_SCHEMA_URL}) —
16
+ * **same** fixture the TS spine reads (`SPINE_EXPECTED_SCHEMA_URL`) —
17
17
  * column-presence is engine-portable, so one file is the cross-impl contract.
18
18
  */
19
19
  export declare const RUST_SPINE_STUB_EXPECTED_SCHEMA_PATH_ENV = "FUZ_RUST_SPINE_STUB_EXPECTED_SCHEMA_PATH";
@@ -1 +1 @@
1
- {"version":3,"file":"rust_spine_stub_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/rust_spine_stub_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA0C9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAUzD,uGAAuG;AACvG,eAAO,MAAM,uBAAuB,oCAAoC,CAAC;AAEzE;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,6CAA6C,CAAC;AAE3F;;;;;GAKG;AACH,eAAO,MAAM,wCAAwC,6CAA6C,CAAC;AAqBnG,kGAAkG;AAClG,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,sDACG,CAAC;AAErD,MAAM,WAAW,6BAA6B;IAC7C,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C;;;;;OAKG;IACH,QAAQ,CAAC,8BAA8B,CAAC,EAAE,MAAM,CAAC;CACjD;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,GAC1C,UAAS,6BAAkC,KACzC,aAmDF,CAAC"}
1
+ {"version":3,"file":"rust_spine_stub_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/rust_spine_stub_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA0C9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAYzD,uGAAuG;AACvG,eAAO,MAAM,uBAAuB,oCAAoC,CAAC;AAEzE;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,6CAA6C,CAAC;AAE3F;;;;;GAKG;AACH,eAAO,MAAM,wCAAwC,6CAA6C,CAAC;AAqBnG,kGAAkG;AAClG,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,sDACG,CAAC;AAErD,MAAM,WAAW,6BAA6B;IAC7C,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C;;;;;OAKG;IACH,QAAQ,CAAC,8BAA8B,CAAC,EAAE,MAAM,CAAC;CACjD;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,GAC1C,UAAS,6BAAkC,KACzC,aAmDF,CAAC"}
@@ -38,8 +38,8 @@ import '../assert_dev_env.js';
38
38
  */
39
39
  import { fileURLToPath } from 'node:url';
40
40
  import { build_test_backend_paths } from './build_test_backend_paths.js';
41
- import { SPINE_EXPECTED_SCHEMA_URL } from './spine_surface_constants.js';
42
- import { LOGIN_RATE_LIMIT_ENABLED_ENV, action_rate_limit_env, make_default_rust_backend_config, rust_default_capabilities } from './default_backend_configs.js';
41
+ import { LOGIN_RATE_LIMIT_ENABLED_ENV, SPINE_EXPECTED_SCHEMA_URL } from './spine_surface_constants.js';
42
+ import { action_rate_limit_env, make_default_rust_backend_config, rust_default_capabilities } from './default_backend_configs.js';
43
43
  /** Env var naming the prebuilt `testing_spine_stub` binary. Required when `binary_path` is omitted. */
44
44
  export const RUST_SPINE_STUB_BIN_ENV = 'FUZ_TESTING_RUST_SPINE_STUB_BIN';
45
45
  /**
@@ -53,7 +53,7 @@ export const RUST_SPINE_STUB_DATABASE_URL_ENV = 'FUZ_TESTING_RUST_SPINE_STUB_DAT
53
53
  /**
54
54
  * Env var the stub reads for the absolute path of the committed
55
55
  * `expected_schema.json` its `/ready` gate introspects against. Pointed at the
56
- * **same** fixture the TS spine reads ({@link SPINE_EXPECTED_SCHEMA_URL}) —
56
+ * **same** fixture the TS spine reads (`SPINE_EXPECTED_SCHEMA_URL`) —
57
57
  * column-presence is engine-portable, so one file is the cross-impl contract.
58
58
  */
59
59
  export const RUST_SPINE_STUB_EXPECTED_SCHEMA_PATH_ENV = 'FUZ_RUST_SPINE_STUB_EXPECTED_SCHEMA_PATH';
@@ -1,7 +1,8 @@
1
1
  import '../assert_dev_env.js';
2
2
  /**
3
- * Pure spine-surface path + role constants — the hono-free leaf split out of
4
- * `default_spine_surface.ts`.
3
+ * Pure spine-surface constants — wire paths, roles, the fixture URL, and the
4
+ * env-var names the backend configs set for the spawned spine binaries. A
5
+ * hono-free leaf split out of `default_spine_surface.ts`.
5
6
  *
6
7
  * Cross-process suite modules (which drive a separately-spawned backend binary
7
8
  * over HTTP) need only the wire path / role / fixture-URL, not the in-process
@@ -10,7 +11,13 @@ import '../assert_dev_env.js';
10
11
  * `session_middleware` → `hono/cookie` — onto a backend-spawning consumer with
11
12
  * no `hono` peer installed (a Rust-only spine consumer). Keeping these constants
12
13
  * on this handler-free leaf lets such a consumer import the path without the
13
- * peer. `default_spine_surface.ts` re-exports them for in-process callers.
14
+ * peer. `default_spine_surface.ts` imports the ones it uses from here.
15
+ *
16
+ * The env-var names live here so both sides of each contract share one
17
+ * constant: the backend configs that set them (`default_backend_configs.ts`,
18
+ * `ts_spine_backend_config.ts`, `rust_spine_stub_backend_config.ts`) and the
19
+ * spawned TS spine binary that reads them, which imports this leaf rather than
20
+ * the config builders.
14
21
  *
15
22
  * @module
16
23
  */
@@ -56,4 +63,37 @@ export declare const SPINE_PARTICIPANT_ROLE = "participant";
56
63
  * engine-portable, so one fixture is the cross-impl contract.
57
64
  */
58
65
  export declare const SPINE_EXPECTED_SCHEMA_URL: URL;
66
+ /**
67
+ * Env var both spine binaries read to enable their login rate limiters
68
+ * (`'true'` on / unset off). The cross-language contract for the login-security
69
+ * cross project: the TS binary reads it via `runtime.env_get` (a test-only flag,
70
+ * not in `BaseServerEnv`); the Rust `testing_spine_stub` reads it via
71
+ * `std::env::var` — so one backend-config option drives both impls
72
+ * (`ts_spine_backend_config` and `rust_spine_stub_backend_config` set it).
73
+ */
74
+ export declare const LOGIN_RATE_LIMIT_ENABLED_ENV = "FUZ_LOGIN_RATE_LIMIT_ENABLED";
75
+ /**
76
+ * Env var both spine binaries read to enable their action rate limiters
77
+ * (`'true'` on / unset off) — one per-IP and one per-account limiter, shared by
78
+ * the RPC and WS endpoints (and, on the Rust stub, the auth-family handlers
79
+ * that charge in-handler). The cross-language contract for the action
80
+ * rate-limit cross suite (`ws_action_rate_limit.ts`); same delivery as
81
+ * `LOGIN_RATE_LIMIT_ENABLED_ENV`. Off, neither spine builds an action
82
+ * limiter.
83
+ */
84
+ export declare const ACTION_RATE_LIMIT_ENABLED_ENV = "FUZ_ACTION_RATE_LIMIT_ENABLED";
85
+ /**
86
+ * Env var replacing both action limiters' `max_attempts` (a positive integer;
87
+ * the windows stay `default_action_ip_rate_limit`'s /
88
+ * `default_action_account_rate_limit`'s). Both spine binaries refuse to boot
89
+ * when it is set without `ACTION_RATE_LIMIT_ENABLED_ENV` or is not a positive
90
+ * integer, so a suite never asserts a throttle the backend didn't build.
91
+ */
92
+ export declare const ACTION_RATE_LIMIT_MAX_ATTEMPTS_ENV = "FUZ_ACTION_RATE_LIMIT_MAX_ATTEMPTS";
93
+ /**
94
+ * Env var naming the TS spine backend's root dir, set by
95
+ * `ts_spine_backend_config`; the spawned binary writes its daemon token to
96
+ * `{dir}/run/daemon_token`, which must match `bootstrap.daemon_token_path`.
97
+ */
98
+ export declare const TS_SPINE_DIR_ENV = "FUZ_TESTING_TS_SPINE_DIR";
59
99
  //# sourceMappingURL=spine_surface_constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spine_surface_constants.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/spine_surface_constants.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;GAcG;AAEH,iEAAiE;AACjE,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,4BAA4B,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,EAAE,GAAwD,CAAC"}
1
+ {"version":3,"file":"spine_surface_constants.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/spine_surface_constants.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,iEAAiE;AACjE,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,4BAA4B,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,EAAE,GAAwD,CAAC;AAEjG;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAE3E;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,kCAAkC,CAAC;AAE7E;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC,uCAAuC,CAAC;AAEvF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6BAA6B,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import '../assert_dev_env.js';
2
2
  /**
3
- * Pure spine-surface path + role constants — the hono-free leaf split out of
4
- * `default_spine_surface.ts`.
3
+ * Pure spine-surface constants — wire paths, roles, the fixture URL, and the
4
+ * env-var names the backend configs set for the spawned spine binaries. A
5
+ * hono-free leaf split out of `default_spine_surface.ts`.
5
6
  *
6
7
  * Cross-process suite modules (which drive a separately-spawned backend binary
7
8
  * over HTTP) need only the wire path / role / fixture-URL, not the in-process
@@ -10,7 +11,13 @@ import '../assert_dev_env.js';
10
11
  * `session_middleware` → `hono/cookie` — onto a backend-spawning consumer with
11
12
  * no `hono` peer installed (a Rust-only spine consumer). Keeping these constants
12
13
  * on this handler-free leaf lets such a consumer import the path without the
13
- * peer. `default_spine_surface.ts` re-exports them for in-process callers.
14
+ * peer. `default_spine_surface.ts` imports the ones it uses from here.
15
+ *
16
+ * The env-var names live here so both sides of each contract share one
17
+ * constant: the backend configs that set them (`default_backend_configs.ts`,
18
+ * `ts_spine_backend_config.ts`, `rust_spine_stub_backend_config.ts`) and the
19
+ * spawned TS spine binary that reads them, which imports this leaf rather than
20
+ * the config builders.
14
21
  *
15
22
  * @module
16
23
  */
@@ -56,3 +63,36 @@ export const SPINE_PARTICIPANT_ROLE = 'participant';
56
63
  * engine-portable, so one fixture is the cross-impl contract.
57
64
  */
58
65
  export const SPINE_EXPECTED_SCHEMA_URL = new URL('./expected_schema.json', import.meta.url);
66
+ /**
67
+ * Env var both spine binaries read to enable their login rate limiters
68
+ * (`'true'` on / unset off). The cross-language contract for the login-security
69
+ * cross project: the TS binary reads it via `runtime.env_get` (a test-only flag,
70
+ * not in `BaseServerEnv`); the Rust `testing_spine_stub` reads it via
71
+ * `std::env::var` — so one backend-config option drives both impls
72
+ * (`ts_spine_backend_config` and `rust_spine_stub_backend_config` set it).
73
+ */
74
+ export const LOGIN_RATE_LIMIT_ENABLED_ENV = 'FUZ_LOGIN_RATE_LIMIT_ENABLED';
75
+ /**
76
+ * Env var both spine binaries read to enable their action rate limiters
77
+ * (`'true'` on / unset off) — one per-IP and one per-account limiter, shared by
78
+ * the RPC and WS endpoints (and, on the Rust stub, the auth-family handlers
79
+ * that charge in-handler). The cross-language contract for the action
80
+ * rate-limit cross suite (`ws_action_rate_limit.ts`); same delivery as
81
+ * `LOGIN_RATE_LIMIT_ENABLED_ENV`. Off, neither spine builds an action
82
+ * limiter.
83
+ */
84
+ export const ACTION_RATE_LIMIT_ENABLED_ENV = 'FUZ_ACTION_RATE_LIMIT_ENABLED';
85
+ /**
86
+ * Env var replacing both action limiters' `max_attempts` (a positive integer;
87
+ * the windows stay `default_action_ip_rate_limit`'s /
88
+ * `default_action_account_rate_limit`'s). Both spine binaries refuse to boot
89
+ * when it is set without `ACTION_RATE_LIMIT_ENABLED_ENV` or is not a positive
90
+ * integer, so a suite never asserts a throttle the backend didn't build.
91
+ */
92
+ export const ACTION_RATE_LIMIT_MAX_ATTEMPTS_ENV = 'FUZ_ACTION_RATE_LIMIT_MAX_ATTEMPTS';
93
+ /**
94
+ * Env var naming the TS spine backend's root dir, set by
95
+ * `ts_spine_backend_config`; the spawned binary writes its daemon token to
96
+ * `{dir}/run/daemon_token`, which must match `bootstrap.daemon_token_path`.
97
+ */
98
+ export const TS_SPINE_DIR_ENV = 'FUZ_TESTING_TS_SPINE_DIR';
@@ -1,6 +1,20 @@
1
1
  import '../assert_dev_env.js';
2
2
  import type { RpcPathCrossSuiteOptions } from './setup.js';
3
3
  /** Options for the testing-backdoor negative-credential suite. */
4
- export type TestingBackdoorCrossTestOptions = RpcPathCrossSuiteOptions;
4
+ export interface TestingBackdoorCrossTestOptions extends RpcPathCrossSuiteOptions {
5
+ /**
6
+ * Where the backend's WebSocket endpoint is, for the session-socket cases.
7
+ * Pass it when the backend serves the `_testing_*` actions on its WS
8
+ * endpoint too; omitted, those cases are skipped.
9
+ */
10
+ readonly ws?: {
11
+ /** Base URL the backend is reachable at (e.g. `http://localhost:1178`). */
12
+ readonly base_url: string;
13
+ /** WebSocket endpoint path on the backend (e.g. `/api/ws`). */
14
+ readonly ws_path: string;
15
+ /** Origin for the upgrade. Defaults to `base_url`. */
16
+ readonly origin?: string;
17
+ };
18
+ }
5
19
  export declare const describe_testing_backdoor_cross_tests: (options: TestingBackdoorCrossTestOptions) => void;
6
20
  //# sourceMappingURL=testing_backdoor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing_backdoor.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_backdoor.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA6D9B,OAAO,KAAK,EAAE,wBAAwB,EAAe,MAAM,YAAY,CAAC;AAqExE,kEAAkE;AAClE,MAAM,MAAM,+BAA+B,GAAG,wBAAwB,CAAC;AAEvE,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAiCF,CAAC"}
1
+ {"version":3,"file":"testing_backdoor.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_backdoor.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2E9B,OAAO,KAAK,EAAE,wBAAwB,EAAe,MAAM,YAAY,CAAC;AA0ExE,kEAAkE;AAClE,MAAM,WAAW,+BAAgC,SAAQ,wBAAwB;IAChF;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE;QACb,2EAA2E;QAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,+DAA+D;QAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,sDAAsD;QACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACF;AAED,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAyEF,CAAC"}
@@ -29,6 +29,14 @@ import '../assert_dev_env.js';
29
29
  * `credential_type_required` — same ceiling; an api token cannot reach
30
30
  * keeper operations.
31
31
  *
32
+ * Over WebSocket (when `ws` is supplied), the same methods sent on a socket
33
+ * opened with the keeper's **session** cookie answer the same `forbidden`
34
+ * error with `credential_type_required`: the upgrade admits a session, but
35
+ * each message runs the same per-action gates as HTTP RPC, so a socket is no
36
+ * way around the daemon-token channel. Anonymous and bearer have no WS case —
37
+ * an anonymous upgrade is refused before any message, and the upgrade client
38
+ * threads cookies.
39
+ *
32
40
  * Each method is sent with **valid** params so each case varies only the
33
41
  * credential. (Validation runs after the gates — the order is 401 → authz →
34
42
  * 403 → 429 → 400 — so the shapes are belt-and-suspenders here rather than load-
@@ -45,7 +53,9 @@ import '../assert_dev_env.js';
45
53
  * binary, not the in-process app — like the ws/sse suites. Wire from a
46
54
  * `*.cross.test.ts`. Requires the standard `_testing_*` actions mounted (the
47
55
  * same precondition `default_cross_process_setup` already imposes for its
48
- * per-test `_testing_reset`); ungated, since every cross backend mounts them.
56
+ * per-test `_testing_reset`); the HTTP cases are ungated, since every cross
57
+ * backend mounts them, and the WS cases run when `ws` is passed — for a
58
+ * backend that also serves them on its WS endpoint.
49
59
  *
50
60
  * `$lib`-free by contract (relative specifiers only), like the sibling
51
61
  * cross-backend suites.
@@ -54,7 +64,11 @@ import '../assert_dev_env.js';
54
64
  */
55
65
  import { describe, test, assert } from 'vitest';
56
66
  import { ERROR_CREDENTIAL_TYPE_REQUIRED } from '../../http/error_schemas.js';
67
+ import { JSONRPC_ERROR_CODES } from '../../http/jsonrpc_errors.js';
57
68
  import { rpc_call } from '../rpc_helpers.js';
69
+ import { create_admitted_ws_transport } from '../transports/ws_transport.js';
70
+ import { is_response_for } from '../transports/ws_client.js';
71
+ import { test_if } from './capabilities.js';
58
72
  import { SPINE_RPC_PATH } from './spine_surface_constants.js';
59
73
  /** A well-formed UUID that never names a real row. */
60
74
  const NIL_UUID = '00000000-0000-0000-0000-000000000000';
@@ -81,18 +95,21 @@ const principals = [
81
95
  {
82
96
  name: 'anonymous',
83
97
  status: 401,
98
+ code: JSONRPC_ERROR_CODES.unauthenticated,
84
99
  // Fresh jar so the keeper cookie (cross-process) can't leak in.
85
100
  resolve: (f) => ({ transport: f.fresh_transport(), headers: {} })
86
101
  },
87
102
  {
88
103
  name: 'session',
89
104
  status: 403,
105
+ code: JSONRPC_ERROR_CODES.forbidden,
90
106
  reason: ERROR_CREDENTIAL_TYPE_REQUIRED,
91
107
  resolve: (f) => ({ transport: f.transport, headers: f.create_session_headers() })
92
108
  },
93
109
  {
94
110
  name: 'bearer',
95
111
  status: 403,
112
+ code: JSONRPC_ERROR_CODES.forbidden,
96
113
  reason: ERROR_CREDENTIAL_TYPE_REQUIRED,
97
114
  // Bearer is discarded in a browser context, so suppress Origin (empty
98
115
  // jar + no Origin) — the credential must actually resolve so the refusal
@@ -105,7 +122,7 @@ const principals = [
105
122
  }
106
123
  ];
107
124
  export const describe_testing_backdoor_cross_tests = (options) => {
108
- const { setup_test } = options;
125
+ const { setup_test, ws } = options;
109
126
  const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
110
127
  describe('testing backdoor credential gate parity', () => {
111
128
  for (const { method, params } of backdoor_methods) {
@@ -125,12 +142,39 @@ export const describe_testing_backdoor_cross_tests = (options) => {
125
142
  assert.ok(!res.ok, `${label}: expected denial (${principal.status}) but the call succeeded`);
126
143
  assert.strictEqual(res.status, principal.status, `${label}: status`);
127
144
  // `!res.ok` narrows `res` to the error variant for `res.error`.
128
- if (principal.reason !== undefined && !res.ok) {
129
- const reason = res.error.data?.reason;
130
- assert.strictEqual(reason, principal.reason, `${label}: error.data.reason`);
145
+ if (!res.ok) {
146
+ assert.strictEqual(res.error.code, principal.code, `${label}: error.code`);
147
+ if (principal.reason !== undefined) {
148
+ const reason = res.error.data?.reason;
149
+ assert.strictEqual(reason, principal.reason, `${label}: error.data.reason`);
150
+ }
131
151
  }
132
152
  });
133
153
  }
134
154
  }
155
+ for (const { method, params } of backdoor_methods) {
156
+ test_if(ws !== undefined, `${method} over a session socket → forbidden ${ERROR_CREDENTIAL_TYPE_REQUIRED}`, async () => {
157
+ const fixture = await setup_test();
158
+ const client = await create_admitted_ws_transport({
159
+ base_url: ws.base_url,
160
+ ws_path: ws.ws_path,
161
+ cookies: fixture.transport.cookies(),
162
+ origin: ws.origin
163
+ });
164
+ try {
165
+ const id = `backdoor_${method}`;
166
+ await client.send({ jsonrpc: '2.0', id, method, params });
167
+ const frame = await client.wait_for(is_response_for(id));
168
+ const label = `${method} session socket`;
169
+ assert.ok(frame.error, `${label}: expected a credential_type_required error but the call succeeded`);
170
+ assert.strictEqual(frame.error.code, JSONRPC_ERROR_CODES.forbidden, `${label}: code`);
171
+ const reason = frame.error.data?.reason;
172
+ assert.strictEqual(reason, ERROR_CREDENTIAL_TYPE_REQUIRED, `${label}: error.data.reason`);
173
+ }
174
+ finally {
175
+ await client.close();
176
+ }
177
+ });
178
+ }
135
179
  });
136
180
  };
@@ -71,6 +71,7 @@ import '../assert_dev_env.js';
71
71
  import { z } from 'zod';
72
72
  import { type RpcAction } from '../../actions/action_rpc.js';
73
73
  import type { AppDeps } from '../../auth/deps.js';
74
+ import type { AuditEmitter } from '../../auth/audit_emitter.js';
74
75
  import type { SessionOptions } from '../../auth/session_cookie.js';
75
76
  import type { DaemonTokenState } from '../../auth/daemon_token.js';
76
77
  import type { Db } from '../../db/db.js';
@@ -162,16 +163,21 @@ export declare const testing_reset_action_spec: {
162
163
  * the cross-backend conformance suite uses in place of a poll/sleep before
163
164
  * asserting on audit rows.
164
165
  *
165
- * On the TS spine the barrier is **satisfied by construction**: the test
166
- * binary runs `await_pending_effects: true`, so every **HTTP** mutation's
167
- * fire-and-forget audit emits are awaited before its response returns — by
168
- * the time a later drain call runs, prior emits are already durable. A
169
- * WS-dispatched mutation replies before its effects flush, so on TS this
170
- * action is not a barrier for WS-originated emits; issue audit-asserting
171
- * mutations over HTTP. The action still
172
- * exists so the cross-backend test body calls the same method on every
173
- * backend; the Rust spine (whose audit writes are detached tokio tasks)
174
- * does the real await in `AuditEmitter::drain_inflight`.
166
+ * The handler awaits `AuditEmitter.drain_inflight`, which waits until no
167
+ * tracked `emit` write is outstanding — so the binary's emitter must be built
168
+ * with `track_inflight: true`, or the drain resolves at once and is no barrier.
169
+ * Tracking is what makes it a barrier whatever the transport: an **HTTP**
170
+ * mutation on a binary running `await_pending_effects: true` has its writes
171
+ * settled by the time it responds, but a **WS** mutation is answered before
172
+ * its effects flush (reply-then-close for a self-revocation), so its audit
173
+ * write can still be in flight when the caller reads the reply. The Rust
174
+ * spine does the same await in `AuditEmitter::drain_inflight`, over an
175
+ * emitter built with `new_with_inflight_tracking`.
176
+ *
177
+ * Covered: every `emit` that ran before the drain was dispatched, and any
178
+ * started while it waits. A write that starts after the drain resolves is
179
+ * not — nor are eager writes outside `emit` (session touch, token usage),
180
+ * which only the dispatching transport's own flush awaits.
175
181
  *
176
182
  * `auth` gates on the daemon-token credential, matching `_testing_reset`.
177
183
  */
@@ -243,13 +249,15 @@ export declare const testing_mint_session_action_spec: {
243
249
  readonly description: string;
244
250
  };
245
251
  /**
246
- * Build the standalone `_testing_drain_effects` action. No deps — on TS the
247
- * barrier is satisfied by `await_pending_effects` (see the spec doc), so the
248
- * handler just returns `{ok: true}`. Mount it on any test endpoint whose
249
- * suite asserts on audit rows (the spine binary bundles it via
252
+ * Build the standalone `_testing_drain_effects` action over `audit` — the
253
+ * emitter the backend's handlers emit through (`deps.audit`), built with
254
+ * `track_inflight: true` (see the spec doc). Mount it on any test endpoint
255
+ * whose suite asserts on audit rows (the spine binary bundles it via
250
256
  * `create_testing_actions`; in-process suites mount it directly).
257
+ *
258
+ * @param audit - the backend's emitter, whose in-flight writes the action awaits
251
259
  */
252
- export declare const create_testing_drain_effects_action: () => RpcAction;
260
+ export declare const create_testing_drain_effects_action: (audit: AuditEmitter) => RpcAction;
253
261
  /**
254
262
  * `_testing_put_fact` — seed an **embedded** fact (`fact.bytes`) for the
255
263
  * cross-process fact-serving suite, which drives over real HTTP and has no
@@ -475,9 +483,10 @@ export interface CreateTestingActionsOptions {
475
483
  /**
476
484
  * Build the testing RPC actions for a test binary's registry.
477
485
  *
478
- * Returns `_testing_reset` — the single privileged action test binaries
479
- * register. The test binary calls this at server-assembly time and
480
- * registers the result on its dispatcher.
486
+ * Returns the bundled `_testing_*` actions (module doc). The test binary
487
+ * calls this at server-assembly time and registers the result on its
488
+ * dispatcher. `_testing_drain_effects` drains `deps.audit`, so the binary's
489
+ * `audit_factory` builds the emitter with `track_inflight: true`.
481
490
  *
482
491
  * The reset action's table-wipe list mirrors
483
492
  * `auth_integration_truncate_tables` from `testing/db.ts` — the
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAKzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAqCzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;QAiBpC;;;;;;;;WAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWyC,CAAC;AAE/C;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAwBC,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAO,SACmB,CAAC;AAE3E;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;CAeK,CAAC;AAE/C;;;;;;;;;GASG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWF,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,QAAO,SAGvD,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;CAYJ,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,uCAAuC,QAAO,SAGzD,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAaF,CAAC;AAyB/C,eAAO,MAAM,qCAAqC,GACjD,SAAS,aAAa,CAAC,SAAS,CAAC,KAC/B,SAMF,CAAC;AAEF,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;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CAsIjB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAKzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAqCzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;QAiBpC;;;;;;;;WAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWyC,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAwBC,CAAC;AAE/C;;;;;;;;GAQG;AACH,eAAO,MAAM,mCAAmC,GAAI,OAAO,YAAY,KAAG,SAIvE,CAAC;AAEJ;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;CAeK,CAAC;AAE/C;;;;;;;;;GASG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWF,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,QAAO,SAGvD,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;CAYJ,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,uCAAuC,QAAO,SAGzD,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAaF,CAAC;AAyB/C,eAAO,MAAM,qCAAqC,GACjD,SAAS,aAAa,CAAC,SAAS,CAAC,KAC/B,SAMF,CAAC;AAEF,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;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CAsIjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,UAAmC,CAAC"}