@fuzdev/fuz_app 0.86.0 → 0.87.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 (40) hide show
  1. package/dist/testing/CLAUDE.md +6 -3
  2. package/dist/testing/cross_backend/account_lifecycle.d.ts +5 -5
  3. package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
  4. package/dist/testing/cross_backend/account_lifecycle.js +1 -1
  5. package/dist/testing/cross_backend/actor_lookup.d.ts +5 -5
  6. package/dist/testing/cross_backend/actor_lookup.d.ts.map +1 -1
  7. package/dist/testing/cross_backend/actor_search.d.ts +3 -3
  8. package/dist/testing/cross_backend/actor_search.d.ts.map +1 -1
  9. package/dist/testing/cross_backend/app_settings.d.ts +3 -3
  10. package/dist/testing/cross_backend/app_settings.d.ts.map +1 -1
  11. package/dist/testing/cross_backend/body_size.d.ts +10 -0
  12. package/dist/testing/cross_backend/body_size.d.ts.map +1 -0
  13. package/dist/testing/cross_backend/body_size.js +137 -0
  14. package/dist/testing/cross_backend/body_size_smuggling.d.ts +10 -0
  15. package/dist/testing/cross_backend/body_size_smuggling.d.ts.map +1 -0
  16. package/dist/testing/cross_backend/body_size_smuggling.js +138 -0
  17. package/dist/testing/cross_backend/cell_cross_helpers.d.ts +0 -11
  18. package/dist/testing/cross_backend/cell_cross_helpers.d.ts.map +1 -1
  19. package/dist/testing/cross_backend/cell_crud.d.ts +2 -2
  20. package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
  21. package/dist/testing/cross_backend/cell_crud.js +1 -1
  22. package/dist/testing/cross_backend/cell_grant_role.d.ts +2 -2
  23. package/dist/testing/cross_backend/cell_grant_role.d.ts.map +1 -1
  24. package/dist/testing/cross_backend/cell_grant_role.js +1 -1
  25. package/dist/testing/cross_backend/cell_relations.d.ts +2 -2
  26. package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -1
  27. package/dist/testing/cross_backend/cell_relations.js +1 -1
  28. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
  29. package/dist/testing/cross_backend/conformance_table.js +8 -6
  30. package/dist/testing/cross_backend/fact_serving.d.ts +2 -3
  31. package/dist/testing/cross_backend/fact_serving.d.ts.map +1 -1
  32. package/dist/testing/cross_backend/origin.d.ts +5 -5
  33. package/dist/testing/cross_backend/origin.d.ts.map +1 -1
  34. package/dist/testing/cross_backend/ready.d.ts +2 -7
  35. package/dist/testing/cross_backend/ready.d.ts.map +1 -1
  36. package/dist/testing/cross_backend/setup.d.ts +28 -0
  37. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  38. package/dist/testing/cross_backend/testing_backdoor.d.ts +2 -2
  39. package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
  40. package/package.json +1 -1
@@ -1043,9 +1043,12 @@ stays **off** `create_spine_surface_spec`, and these dedicated suites are the
1043
1043
  cell validators (`describe_standard_cross_process_tests`' generic round-trip
1044
1044
  never sees them). Both parse every success response against the verb's Zod
1045
1045
  **output** schema, so a TS↔Rust envelope drift fails the suite — not just a
1046
- payload-field drift. Call-site primitives (`rpc_call` / `error_reason` /
1047
- `expect_output` + the shared `CellCrossTestOptions`) live in
1048
- `cross_backend/cell_cross_helpers.ts`.
1046
+ payload-field drift. Call-site primitives (`cross_rpc_call` / `error_reason` /
1047
+ `expect_output`) live in `cross_backend/cell_cross_helpers.ts`; the shared
1048
+ options shape is `RpcPathCrossSuiteOptions` from `cross_backend/setup.ts` (the
1049
+ neutral base every RPC-dispatched imperative cross suite aliases — origin,
1050
+ body-size, actor lookup/search, account lifecycle, app settings, testing
1051
+ backdoor, cell).
1049
1052
 
1050
1053
  - **`describe_cell_crud_cross_tests`** (gates on `capabilities.cell_crud`) —
1051
1054
  the create → get → update → delete → list lifecycle threading the id, plus
@@ -1,10 +1,10 @@
1
1
  import '../assert_dev_env.js';
2
- import { type CellCrossTestOptions } from './cell_cross_helpers.js';
2
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
3
3
  /**
4
- * Options for the account-lifecycle parity suite. Shares the shape of the
5
- * cell suites (`setup_test` / `capabilities` / `rpc_path`); reuses
6
- * `CellCrossTestOptions` rather than minting a structural duplicate.
4
+ * Options for the account-lifecycle parity suite. The standard
5
+ * RPC-dispatched cross-suite shape (`setup_test` / `capabilities` /
6
+ * `rpc_path`); aliases `RpcPathCrossSuiteOptions` rather than duplicating.
7
7
  */
8
- export type AccountLifecycleCrossTestOptions = CellCrossTestOptions;
8
+ export type AccountLifecycleCrossTestOptions = RpcPathCrossSuiteOptions;
9
9
  export declare const describe_account_lifecycle_cross_tests: (options: AccountLifecycleCrossTestOptions) => void;
10
10
  //# sourceMappingURL=account_lifecycle.d.ts.map
@@ -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;AAiC9B,OAAO,EAIN,KAAK,oBAAoB,EACzB,MAAM,yBAAyB,CAAC;AAGjC;;;;GAIG;AACH,MAAM,MAAM,gCAAgC,GAAG,oBAAoB,CAAC;AAEpE,eAAO,MAAM,sCAAsC,GAClD,SAAS,gCAAgC,KACvC,IA+TF,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;AAkC9B,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAGzD;;;;GAIG;AACH,MAAM,MAAM,gCAAgC,GAAG,wBAAwB,CAAC;AAExE,eAAO,MAAM,sCAAsC,GAClD,SAAS,gCAAgC,KACvC,IA+TF,CAAC"}
@@ -21,7 +21,7 @@ import { describe, assert } from 'vitest';
21
21
  import { AccountDeleteOutput, AccountUndeleteOutput, AccountPurgeOutput, AdminAccountListOutput, AuditLogListOutput, ERROR_CANNOT_DELETE_KEEPER, } from '../../auth/admin_action_specs.js';
22
22
  import { ERROR_ACCOUNT_NOT_FOUND, ERROR_AUTHENTICATION_REQUIRED } from '../../http/error_schemas.js';
23
23
  import { test_if } from './capabilities.js';
24
- import { cross_rpc_call, error_reason, expect_output, } from './cell_cross_helpers.js';
24
+ import { cross_rpc_call, error_reason, expect_output } from './cell_cross_helpers.js';
25
25
  import { SPINE_RPC_PATH } from './default_spine_surface.js';
26
26
  export const describe_account_lifecycle_cross_tests = (options) => {
27
27
  const { setup_test, capabilities } = options;
@@ -1,10 +1,10 @@
1
1
  import '../assert_dev_env.js';
2
- import type { CellCrossTestOptions } from './cell_cross_helpers.js';
2
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
3
3
  /**
4
- * Options for the actor-lookup parity suite. Shares the shape of the cell /
5
- * origin suites (`setup_test` / `capabilities` / `rpc_path`); reuses
6
- * `CellCrossTestOptions` rather than minting a structural duplicate.
4
+ * Options for the actor-lookup parity suite. The standard RPC-dispatched
5
+ * cross-suite shape (`setup_test` / `capabilities` / `rpc_path`); aliases
6
+ * the shared `RpcPathCrossSuiteOptions` rather than minting a duplicate.
7
7
  */
8
- export type ActorLookupCrossTestOptions = CellCrossTestOptions;
8
+ export type ActorLookupCrossTestOptions = RpcPathCrossSuiteOptions;
9
9
  export declare const describe_actor_lookup_cross_tests: (options: ActorLookupCrossTestOptions) => void;
10
10
  //# sourceMappingURL=actor_lookup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"actor_lookup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/actor_lookup.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAqC9B,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAGlE;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG,oBAAoB,CAAC;AAS/D,eAAO,MAAM,iCAAiC,GAAI,SAAS,2BAA2B,KAAG,IAkDxF,CAAC"}
1
+ {"version":3,"file":"actor_lookup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/actor_lookup.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAqC9B,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAGzD;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG,wBAAwB,CAAC;AASnE,eAAO,MAAM,iCAAiC,GAAI,SAAS,2BAA2B,KAAG,IAkDxF,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import '../assert_dev_env.js';
2
- import type { CellCrossTestOptions } from './cell_cross_helpers.js';
3
- /** Options for the actor-search parity suite (shares the cell/origin shape). */
4
- export type ActorSearchCrossTestOptions = CellCrossTestOptions;
2
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
3
+ /** Options for the actor-search parity suite (the standard RPC-dispatched shape). */
4
+ export type ActorSearchCrossTestOptions = RpcPathCrossSuiteOptions;
5
5
  export declare const describe_actor_search_cross_tests: (options: ActorSearchCrossTestOptions) => void;
6
6
  //# sourceMappingURL=actor_search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"actor_search.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/actor_search.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2C9B,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAGlE,gFAAgF;AAChF,MAAM,MAAM,2BAA2B,GAAG,oBAAoB,CAAC;AAS/D,eAAO,MAAM,iCAAiC,GAAI,SAAS,2BAA2B,KAAG,IAyDxF,CAAC"}
1
+ {"version":3,"file":"actor_search.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/actor_search.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2C9B,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAGzD,qFAAqF;AACrF,MAAM,MAAM,2BAA2B,GAAG,wBAAwB,CAAC;AASnE,eAAO,MAAM,iCAAiC,GAAI,SAAS,2BAA2B,KAAG,IAyDxF,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import '../assert_dev_env.js';
2
- import type { CellCrossTestOptions } from './cell_cross_helpers.js';
3
- /** Options for the app-settings effect suite (shares the cell/origin shape). */
4
- export type AppSettingsCrossTestOptions = CellCrossTestOptions;
2
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
3
+ /** Options for the app-settings effect suite (the standard RPC-dispatched shape). */
4
+ export type AppSettingsCrossTestOptions = RpcPathCrossSuiteOptions;
5
5
  export declare const describe_app_settings_cross_tests: (options: AppSettingsCrossTestOptions) => void;
6
6
  //# sourceMappingURL=app_settings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app_settings.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/app_settings.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAsC9B,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAGlE,gFAAgF;AAChF,MAAM,MAAM,2BAA2B,GAAG,oBAAoB,CAAC;AAiB/D,eAAO,MAAM,iCAAiC,GAAI,SAAS,2BAA2B,KAAG,IA8DxF,CAAC"}
1
+ {"version":3,"file":"app_settings.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/app_settings.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAsC9B,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAGzD,qFAAqF;AACrF,MAAM,MAAM,2BAA2B,GAAG,wBAAwB,CAAC;AAiBnE,eAAO,MAAM,iCAAiC,GAAI,SAAS,2BAA2B,KAAG,IA8DxF,CAAC"}
@@ -0,0 +1,10 @@
1
+ import '../assert_dev_env.js';
2
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
3
+ /**
4
+ * Options for the body-size parity suite — the standard RPC-dispatched
5
+ * cross-suite shape (`setup_test` / `capabilities` / `rpc_path`); aliases the
6
+ * shared `RpcPathCrossSuiteOptions` rather than minting a duplicate.
7
+ */
8
+ export type BodySizeCrossTestOptions = RpcPathCrossSuiteOptions;
9
+ export declare const describe_body_size_cross_tests: (options: BodySizeCrossTestOptions) => void;
10
+ //# sourceMappingURL=body_size.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body_size.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/body_size.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA6D9B,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAGzD;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG,wBAAwB,CAAC;AAmDhE,eAAO,MAAM,8BAA8B,GAAI,SAAS,wBAAwB,KAAG,IA0ClF,CAAC"}
@@ -0,0 +1,137 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Cross-backend parity suite for the request body-size limit.
4
+ *
5
+ * `create_app_server` (TS) and the Rust spine both cap the request body at a
6
+ * 1 MiB default (`DEFAULT_MAX_BODY_SIZE` / `fuz_http`'s
7
+ * `DEFAULT_BODY_LIMIT_BYTES`) and reject oversized payloads with `413` and the
8
+ * canonical flat REST body `{error: 'payload_too_large'}` — *before* auth,
9
+ * origin, or dispatch run (middleware step 4). Each impl unit-tests this in
10
+ * isolation, but nothing fires an oversized POST over the wire, so the
11
+ * cross-impl agreement on the status + body shape (and on the exact `>` cap
12
+ * boundary, not an off-by-one divergence) was unpinned. Three cases:
13
+ *
14
+ * - **over-limit POST (cap + 1 byte) → 413** `payload_too_large`, refused
15
+ * before any handler runs (the limit fires ahead of origin verification + the
16
+ * dispatcher, so an over-cap body is rejected regardless of how well-formed it
17
+ * is). Exactly one byte over — both impls reject on a strict `>`, so this is
18
+ * the tight upper boundary, and staying just over keeps it clear of any
19
+ * larger framework-default limit that would answer with a different body.
20
+ * - **at-limit POST (exactly the cap) → not 413** — one byte under the
21
+ * rejection threshold passes the size gate and reaches the dispatcher (the
22
+ * downstream status is irrelevant; only "not size-rejected" is asserted). The
23
+ * boundary sibling of the case above.
24
+ * - **under-limit POST (small) → 200** — a small, well-formed authenticated
25
+ * `account_verify` envelope sails through to a successful handler response,
26
+ * the positive control that the route works for normal traffic.
27
+ *
28
+ * **Real-socket connection hazard (cross-process only).** When the server caps
29
+ * the body it answers 413 and closes the connection *before* the client
30
+ * finishes uploading — correct HTTP, since an unread request body can't share a
31
+ * keep-alive socket. The client's pool can then hand that now-dead socket to
32
+ * the very next request (observed as `other side closed`). So every request
33
+ * here goes through `fetch_retrying_once`: a request that inherits the poisoned
34
+ * socket retries onto a fresh connection, which both keeps the suite
35
+ * deterministic *and* evicts the dead socket so it can't strand a later cross
36
+ * suite in the same process. In-process (`app.request`) has no socket, so the
37
+ * hazard is cross-process-only and the retry never fires there.
38
+ *
39
+ * Like origin/payload rejection, this is middleware-level flat REST — not the
40
+ * JSON-RPC envelope the conformance-table runner expects — so it's an
41
+ * imperative suite, not a `conformance_table` row. Runs both legs via the
42
+ * shared `{setup_test, capabilities}` protocol: the in-process leg
43
+ * (`auth/body_size_parity.db.test.ts`, plain `gro test`) and the cross-process
44
+ * leg (`cross_backend/body_size.cross.test.ts`, the TS spine binaries + Rust
45
+ * `testing_spine_stub` over real HTTP). The body-size limit is on every spine,
46
+ * so the suite is ungated.
47
+ *
48
+ * Cited property: `docs/security.md` §"Body Size Limiting".
49
+ *
50
+ * `$lib`-free by contract (relative specifiers only), like the sibling
51
+ * cross-backend suites.
52
+ *
53
+ * @module
54
+ */
55
+ import { describe, test, assert } from 'vitest';
56
+ import { account_verify_action_spec } from '../../auth/account_action_specs.js';
57
+ import { ERROR_PAYLOAD_TOO_LARGE } from '../../http/error_schemas.js';
58
+ import { SPINE_RPC_PATH } from './default_spine_surface.js';
59
+ /**
60
+ * The shared 1 MiB default both impls ship (`DEFAULT_MAX_BODY_SIZE` in TS,
61
+ * `DEFAULT_BODY_LIMIT_BYTES` in `fuz_http`). Kept as a local cross-impl
62
+ * contract value rather than imported from either impl — the boundary it
63
+ * pins is the shared default, and a change to either is a deliberate
64
+ * cross-impl decision that would revisit this suite regardless.
65
+ */
66
+ const BODY_LIMIT_DEFAULT_BYTES = 1024 * 1024;
67
+ /**
68
+ * Build an `account_verify` JSON-RPC envelope whose serialized length is
69
+ * *exactly* `target_bytes`, by growing a `params.pad` string to fill. Every
70
+ * character is ASCII, so the string length equals the UTF-8 byte length equals
71
+ * the `Content-Length` the transport sends — which is what the body-size
72
+ * middleware measures. `account_verify` takes no params, but at/over the cap
73
+ * the size check fires before input validation, so the padded shape is never
74
+ * reached on the rejection path.
75
+ */
76
+ const sized_envelope = (id, target_bytes) => {
77
+ const method = account_verify_action_spec.method;
78
+ const base = JSON.stringify({ jsonrpc: '2.0', method, id, params: { pad: '' } });
79
+ const pad = 'x'.repeat(Math.max(0, target_bytes - base.length));
80
+ return JSON.stringify({ jsonrpc: '2.0', method, id, params: { pad } });
81
+ };
82
+ /** A small, well-formed nullary `account_verify` body — well under the cap. */
83
+ const small_envelope = (id) => JSON.stringify({ jsonrpc: '2.0', method: account_verify_action_spec.method, id });
84
+ /**
85
+ * Issue a request, retrying once if the call *throws* (vs. returning a
86
+ * response). A request handed the keep-alive socket the server closed on an
87
+ * oversized-body rejection fails at the transport layer before any response;
88
+ * one retry opens a fresh connection (and drops the dead socket from the
89
+ * pool). Keyed on "threw at all" rather than a specific error code so it holds
90
+ * across the node / deno / bun cross runtimes, which surface different errors.
91
+ */
92
+ const fetch_retrying_once = async (transport, path, init) => {
93
+ try {
94
+ return await transport(path, init);
95
+ }
96
+ catch {
97
+ return await transport(path, init);
98
+ }
99
+ };
100
+ export const describe_body_size_cross_tests = (options) => {
101
+ const { setup_test } = options;
102
+ const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
103
+ /** POST `body` to the RPC path as the keeper, retry-once on a dead socket. */
104
+ const post = (fixture, body) => fetch_retrying_once(fixture.transport, rpc_path, {
105
+ method: 'POST',
106
+ headers: { ...fixture.create_session_headers(), 'content-type': 'application/json' },
107
+ body,
108
+ });
109
+ describe('body-size limit parity', () => {
110
+ test('over-limit POST (cap + 1) → 413 payload_too_large (refused before dispatch)', async () => {
111
+ const fixture = await setup_test();
112
+ // Keeper session cookie + the transport's default allowed Origin, so
113
+ // neither auth nor origin is the cause — only the body size. One byte
114
+ // over the cap: both impls reject on a strict `>`.
115
+ const res = await post(fixture, sized_envelope('over-limit', BODY_LIMIT_DEFAULT_BYTES + 1));
116
+ assert.strictEqual(res.status, 413, 'a body one byte over the cap must be rejected with 413');
117
+ const body = (await res.json().catch(() => undefined));
118
+ assert.strictEqual(body?.error, ERROR_PAYLOAD_TOO_LARGE);
119
+ });
120
+ test('at-limit POST (exactly the cap) → not size-rejected', async () => {
121
+ const fixture = await setup_test();
122
+ // Exactly at the cap is one byte under the `>` threshold, so it clears
123
+ // the size gate and reaches the dispatcher. Whatever the dispatcher
124
+ // then returns, it must not be the 413 — that's the lower boundary.
125
+ const res = await post(fixture, sized_envelope('at-limit', BODY_LIMIT_DEFAULT_BYTES));
126
+ assert.notStrictEqual(res.status, 413, 'a body exactly at the cap must not be size-rejected');
127
+ });
128
+ test('under-limit POST (small) → 200', async () => {
129
+ const fixture = await setup_test();
130
+ // Small well-formed body: clears the cap and reaches the
131
+ // `account_verify` handler, the positive control that normal traffic
132
+ // passes (and the 413 above is size-gated, not a blanket rejection).
133
+ const res = await post(fixture, small_envelope('under-limit'));
134
+ assert.strictEqual(res.status, 200, 'an under-limit authenticated request must pass');
135
+ });
136
+ });
137
+ };
@@ -0,0 +1,10 @@
1
+ import '../assert_dev_env.js';
2
+ /** Options for the smuggling probe — needs the raw URL, not a transport. */
3
+ export interface BodySizeSmugglingCrossTestOptions {
4
+ /** Base URL the spawned backend is reachable at (e.g. `http://localhost:1178`). */
5
+ readonly base_url: string;
6
+ /** RPC endpoint path to target. Default `/api/rpc`. */
7
+ readonly rpc_path?: string;
8
+ }
9
+ export declare const describe_body_size_smuggling_cross_tests: (options: BodySizeSmugglingCrossTestOptions) => void;
10
+ //# sourceMappingURL=body_size_smuggling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body_size_smuggling.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/body_size_smuggling.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAkD9B,4EAA4E;AAC5E,MAAM,WAAW,iCAAiC;IACjD,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAqDD,eAAO,MAAM,wCAAwC,GACpD,SAAS,iCAAiC,KACxC,IA4DF,CAAC"}
@@ -0,0 +1,138 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Cross-backend request-smuggling probe for the body-size limit's connection
4
+ * handling — the security sibling of `body_size.ts`.
5
+ *
6
+ * When the server caps the request body it answers `413` on the
7
+ * `Content-Length` header and closes the connection *without reading the
8
+ * oversized body*. That close is load-bearing: HTTP/1.1 forbids reusing a
9
+ * keep-alive connection whose request body wasn't consumed, because the unread
10
+ * body bytes would otherwise be parsed as the start of the next request — a
11
+ * classic request-smuggling vector. This suite proves the mitigation holds end
12
+ * to end by **pipelining**: it opens a raw TCP socket and sends, in one write,
13
+ * an oversized `POST` immediately followed by a second `GET` request. A correct
14
+ * server rejects the POST with `413` and never processes the trailing GET (the
15
+ * connection closes with the GET bytes unconsumed); a vulnerable one would
16
+ * drain past the body and answer the smuggled GET too. The assertion is
17
+ * therefore "**at most one** HTTP response comes back" — a *second* response is
18
+ * the smuggle. It's `<= 1` rather than "exactly the 413" because the impls close
19
+ * differently at the TCP level (node-server graceful close delivers the 413
20
+ * first; hyper's RST can drop the in-flight 413 before the client reads it), so
21
+ * demanding a cleanly-read 413 would be flaky; the 413-ness itself is pinned
22
+ * reliably over `fetch` by `describe_body_size_cross_tests`. A **positive
23
+ * control** (two pipelined requests → >= 2 responses) proves a second response
24
+ * *would* be seen if the trailing request were processed — without it the
25
+ * `<= 1` assertion would be vacuous on a server that never reuses connections,
26
+ * and it also proves the response counter isn't undercounting.
27
+ *
28
+ * Raw-socket by necessity (the `FetchTransport` can't pipeline two requests on
29
+ * one connection), so — unlike `body_size.ts` — this is **cross-process only**
30
+ * (no in-process leg; there is no socket in-process) and ungated (the limit is
31
+ * on every spine). Robust by construction: it counts responses until the
32
+ * socket closes or a short read timeout, so a server that closes (the expected
33
+ * path) and one that merely holds the connection open without smuggling both
34
+ * read as one response; only an actual second response fails.
35
+ *
36
+ * Cited property: `docs/security.md` §"Body Size Limiting" (connection close on
37
+ * oversized reject).
38
+ *
39
+ * `$lib`-free by contract (relative + `node:` specifiers only).
40
+ *
41
+ * @module
42
+ */
43
+ import { connect } from 'node:net';
44
+ import { describe, test, assert } from 'vitest';
45
+ import { SPINE_RPC_PATH } from './default_spine_surface.js';
46
+ /** The shared 1 MiB cap (see `body_size.ts` for why it's a local constant). */
47
+ const BODY_LIMIT_DEFAULT_BYTES = 1024 * 1024;
48
+ /**
49
+ * Open a raw TCP socket to `base_url`, write `request_bytes` once, and collect
50
+ * everything the server sends back until it closes the connection or
51
+ * `read_timeout_ms` elapses. Write errors are swallowed: the server closing
52
+ * mid-upload (the correct response to an oversized body) surfaces as
53
+ * `EPIPE`/`ECONNRESET` on our unfinished write, which is exactly the behavior
54
+ * under test — what matters is what we *read back*.
55
+ */
56
+ const send_raw = (base_url, request_bytes, read_timeout_ms) => new Promise((resolve) => {
57
+ const url = new URL(base_url);
58
+ const port = Number(url.port) || (url.protocol === 'https:' ? 443 : 80);
59
+ const socket = connect({ host: url.hostname, port });
60
+ let received = '';
61
+ let settled = false;
62
+ const finish = () => {
63
+ if (settled)
64
+ return;
65
+ settled = true;
66
+ clearTimeout(timer);
67
+ socket.destroy();
68
+ resolve(received);
69
+ };
70
+ const timer = setTimeout(finish, read_timeout_ms);
71
+ socket.setEncoding('latin1');
72
+ socket.on('connect', () => socket.write(request_bytes));
73
+ socket.on('data', (chunk) => {
74
+ received += chunk;
75
+ });
76
+ socket.on('error', () => { }); // EPIPE/ECONNRESET on mid-write close is expected
77
+ socket.on('close', finish);
78
+ });
79
+ /**
80
+ * Count HTTP response status lines in a raw byte stream. Deliberately
81
+ * **unanchored** (no `^`/`m`): a second pipelined response is concatenated
82
+ * straight after the first response's body, which carries no trailing newline,
83
+ * so a line-anchored match would miss it — and missing a smuggled second
84
+ * response is a silent false negative. No response header or JSON error body
85
+ * contains the literal `HTTP/1.x NNN`, so an unanchored match counts exactly
86
+ * the status lines. The positive control below proves this counts 2 when the
87
+ * server genuinely returns 2.
88
+ */
89
+ const count_responses = (raw) => (raw.match(/HTTP\/1\.[01] \d{3}/g) ?? []).length;
90
+ export const describe_body_size_smuggling_cross_tests = (options) => {
91
+ const { base_url } = options;
92
+ const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
93
+ const host = new URL(base_url).host;
94
+ describe('body-size limit — request-smuggling resistance', () => {
95
+ // Positive control: prove the server returns >1 response on a single
96
+ // connection. Without this the smuggling assertion below would be
97
+ // vacuously green on a server that simply never reuses connections — and
98
+ // it also validates `count_responses` actually counts a second response.
99
+ test('control: two pipelined requests → ≥2 responses (connection reuse is real)', async () => {
100
+ const two_requests = `GET ${rpc_path} HTTP/1.1\r\nHost: ${host}\r\n\r\n` +
101
+ `GET ${rpc_path} HTTP/1.1\r\nHost: ${host}\r\nConnection: close\r\n\r\n`;
102
+ const response = await send_raw(base_url, two_requests, 2000);
103
+ const n = count_responses(response);
104
+ assert.ok(n >= 2, `expected ≥2 responses on one keep-alive connection (got ${n}); without ` +
105
+ `connection reuse — or with an undercounting matcher — the smuggling ` +
106
+ `assertion below is not a real signal. Raw head: ${response.slice(0, 120)}`);
107
+ });
108
+ test('oversized POST + pipelined GET → smuggled request not processed', async () => {
109
+ const oversized_len = BODY_LIMIT_DEFAULT_BYTES + 1024;
110
+ // One write: an over-cap POST (rejected on Content-Length, body never
111
+ // read) immediately followed by a GET. If the server wrongly drained
112
+ // the unread body it would reach + answer this GET — a smuggle.
113
+ const payload = `POST ${rpc_path} HTTP/1.1\r\n` +
114
+ `Host: ${host}\r\n` +
115
+ `Content-Type: application/json\r\n` +
116
+ `Content-Length: ${oversized_len}\r\n` +
117
+ `\r\n` +
118
+ 'x'.repeat(oversized_len) +
119
+ `GET ${rpc_path} HTTP/1.1\r\nHost: ${host}\r\n\r\n`;
120
+ const response = await send_raw(base_url, payload, 2000);
121
+ // The security property is "the pipelined GET is not processed", i.e.
122
+ // **at most one** response comes back (the 413, or none if the close
123
+ // raced the read). A *second* response is the smuggle. We assert `<= 1`
124
+ // rather than "exactly the 413" because the two impls close the
125
+ // connection differently at the TCP level — node-server closes
126
+ // gracefully (the 413 is delivered first), hyper sends an RST that can
127
+ // drop the in-flight 413 before the client reads it — and demanding a
128
+ // cleanly-read 413 here would be flaky. That the oversized body is
129
+ // rejected *with* a 413 is pinned reliably (over `fetch`) by
130
+ // `describe_body_size_cross_tests`; this test owns only the no-smuggle
131
+ // half. The control above proves a second response *would* be seen if
132
+ // the GET were processed, so `<= 1` is a real signal, not a vacuous one.
133
+ const n = count_responses(response);
134
+ assert.ok(n <= 1, `expected at most one response (the GET must not be smuggled in off the ` +
135
+ `unread body); a second response means it was. Saw ${n}. Raw head: ${response.slice(0, 120)}`);
136
+ });
137
+ });
138
+ };
@@ -1,17 +1,6 @@
1
1
  import '../assert_dev_env.js';
2
2
  import type { z } from 'zod';
3
3
  import type { FetchTransport } from '../transports/fetch_transport.js';
4
- import type { BackendCapabilities } from './capabilities.js';
5
- import type { SetupTest } from './setup.js';
6
- /** Shared options for the cell cross-backend parity suites. */
7
- export interface CellCrossTestOptions {
8
- /** Per-test fixture-producing function (fresh keeper + db per call). */
9
- readonly setup_test: SetupTest;
10
- /** Backend capability declarations — each suite gates on its own flag. */
11
- readonly capabilities: BackendCapabilities;
12
- /** RPC endpoint path the cell verbs are mounted on. Default `/api/rpc`. */
13
- readonly rpc_path?: string;
14
- }
15
4
  /** Minimal JSON-RPC envelope shape the suites read off responses. */
16
5
  export interface RpcResult {
17
6
  readonly ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"cell_cross_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_cross_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAmB9B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAG3B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AACrE,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C,+DAA+D;AAC/D,MAAM,WAAW,oBAAoB;IACpC,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CAC5F;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAC1B,WAAW,cAAc,EACzB,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,QAAQ,OAAO,EACf,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC7B,OAAO,CAAC,SAAS,CAMnB,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,YAAY,GAAI,GAAG,SAAS,KAAG,OAG/B,CAAC;AAEd;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,GAAG,SAAS,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAG,CAQrE,CAAC"}
1
+ {"version":3,"file":"cell_cross_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_cross_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAmB9B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAG3B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AAErE,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CAC5F;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAC1B,WAAW,cAAc,EACzB,MAAM,MAAM,EACZ,QAAQ,MAAM,EACd,QAAQ,OAAO,EACf,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC7B,OAAO,CAAC,SAAS,CAMnB,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,YAAY,GAAI,GAAG,SAAS,KAAG,OAG/B,CAAC;AAEd;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,GAAG,SAAS,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAG,CAQrE,CAAC"}
@@ -1,4 +1,4 @@
1
1
  import '../assert_dev_env.js';
2
- import { type CellCrossTestOptions } from './cell_cross_helpers.js';
3
- export declare const describe_cell_crud_cross_tests: (options: CellCrossTestOptions) => void;
2
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
3
+ export declare const describe_cell_crud_cross_tests: (options: RpcPathCrossSuiteOptions) => void;
4
4
  //# sourceMappingURL=cell_crud.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cell_crud.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_crud.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAqD9B,OAAO,EAIN,KAAK,oBAAoB,EACzB,MAAM,yBAAyB,CAAC;AAGjC,eAAO,MAAM,8BAA8B,GAAI,SAAS,oBAAoB,KAAG,IAwS9E,CAAC"}
1
+ {"version":3,"file":"cell_crud.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_crud.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAsD9B,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAGzD,eAAO,MAAM,8BAA8B,GAAI,SAAS,wBAAwB,KAAG,IAwSlF,CAAC"}
@@ -42,7 +42,7 @@ import '../assert_dev_env.js';
42
42
  import { describe, assert } from 'vitest';
43
43
  import { CellCreateOutput, CellDeleteOutput, CellGetOutput, CellListOutput, CellUpdateOutput, } from '../../auth/cell_action_specs.js';
44
44
  import { test_if } from './capabilities.js';
45
- import { cross_rpc_call, error_reason, expect_output, } from './cell_cross_helpers.js';
45
+ import { cross_rpc_call, error_reason, expect_output } from './cell_cross_helpers.js';
46
46
  import { SPINE_RPC_PATH } from './default_spine_surface.js';
47
47
  export const describe_cell_crud_cross_tests = (options) => {
48
48
  const { setup_test, capabilities } = options;
@@ -1,8 +1,8 @@
1
1
  import '../assert_dev_env.js';
2
- import { type CellCrossTestOptions } from './cell_cross_helpers.js';
2
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
3
3
  /** App role the holder is seeded with; matches the spine's registered role. */
4
4
  export declare const CELL_EDITOR_ROLE = "cell_editor";
5
5
  /** Username the fixture seeds (via `extra_accounts`) holding `CELL_EDITOR_ROLE`. */
6
6
  export declare const CELL_ROLE_HOLDER_USERNAME = "cell_role_holder";
7
- export declare const describe_cell_grant_role_cross_tests: (options: CellCrossTestOptions) => void;
7
+ export declare const describe_cell_grant_role_cross_tests: (options: RpcPathCrossSuiteOptions) => void;
8
8
  //# sourceMappingURL=cell_grant_role.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cell_grant_role.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_grant_role.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA6C9B,OAAO,EACN,KAAK,oBAAoB,EAIzB,MAAM,yBAAyB,CAAC;AAGjC,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,gBAAyB,CAAC;AAEvD,oFAAoF;AACpF,eAAO,MAAM,yBAAyB,qBAAqB,CAAC;AAK5D,eAAO,MAAM,oCAAoC,GAAI,SAAS,oBAAoB,KAAG,IAuIpF,CAAC"}
1
+ {"version":3,"file":"cell_grant_role.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_grant_role.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA8C9B,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAGzD,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,gBAAyB,CAAC;AAEvD,oFAAoF;AACpF,eAAO,MAAM,yBAAyB,qBAAqB,CAAC;AAK5D,eAAO,MAAM,oCAAoC,GAAI,SAAS,wBAAwB,KAAG,IAuIxF,CAAC"}
@@ -37,7 +37,7 @@ import { describe, assert } from 'vitest';
37
37
  import { CellCreateOutput, CellGetOutput, CellUpdateOutput } from '../../auth/cell_action_specs.js';
38
38
  import { CellGrantCreateOutput, ERROR_CELL_GRANT_UNKNOWN_ROLE, } from '../../auth/cell_grant_action_specs.js';
39
39
  import { test_if } from './capabilities.js';
40
- import { cross_rpc_call, error_reason, expect_output, } from './cell_cross_helpers.js';
40
+ import { cross_rpc_call, error_reason, expect_output } from './cell_cross_helpers.js';
41
41
  import { SPINE_CELL_EDITOR_ROLE, SPINE_RPC_PATH } from './default_spine_surface.js';
42
42
  /** App role the holder is seeded with; matches the spine's registered role. */
43
43
  export const CELL_EDITOR_ROLE = SPINE_CELL_EDITOR_ROLE;
@@ -1,4 +1,4 @@
1
1
  import '../assert_dev_env.js';
2
- import { type CellCrossTestOptions } from './cell_cross_helpers.js';
3
- export declare const describe_cell_relations_cross_tests: (options: CellCrossTestOptions) => void;
2
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
3
+ export declare const describe_cell_relations_cross_tests: (options: RpcPathCrossSuiteOptions) => void;
4
4
  //# sourceMappingURL=cell_relations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cell_relations.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_relations.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAoF9B,OAAO,EAIN,KAAK,oBAAoB,EACzB,MAAM,yBAAyB,CAAC;AAsFjC,eAAO,MAAM,mCAAmC,GAAI,SAAS,oBAAoB,KAAG,IAyvBnF,CAAC"}
1
+ {"version":3,"file":"cell_relations.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_relations.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAqF9B,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAsFzD,eAAO,MAAM,mCAAmC,GAAI,SAAS,wBAAwB,KAAG,IAyvBvF,CAAC"}
@@ -60,7 +60,7 @@ import { CellFieldDeleteOutput, CellFieldListOutput, CellFieldSetOutput, } from
60
60
  import { CellItemDeleteOutput, CellItemInsertOutput, CellItemListOutput, CellItemMoveOutput, } from '../../auth/cell_item_action_specs.js';
61
61
  import { CellAuditListOutput } from '../../auth/cell_audit_action_specs.js';
62
62
  import { test_if } from './capabilities.js';
63
- import { cross_rpc_call, error_reason, expect_output, } from './cell_cross_helpers.js';
63
+ import { cross_rpc_call, error_reason, expect_output } from './cell_cross_helpers.js';
64
64
  import { SPINE_RPC_PATH } from './default_spine_surface.js';
65
65
  /** Create a cell over the wire and return its id (the parity gate parses the output). */
66
66
  const create_cell = async (t, rpc_path, h, params) => expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', params, h), CellCreateOutput).cell
@@ -1 +1 @@
1
- {"version":3,"file":"conformance_table.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/conformance_table.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAwB9B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AAMjE,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAC,KAAK,eAAe,EAA4B,MAAM,uBAAuB,CAAC;AACtF,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,YAAY,CAAC;AAGvD;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IAC1C,iEAAiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,sDAAsD;AACtD,MAAM,WAAW,uBAAuB;IACvC,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC/C,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,kEAAkE;IAClE,QAAQ,CAAC,aAAa,EAAE,uBAAuB,CAAC;IAChD,4EAA4E;IAC5E,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,0BAA0B,CAAC;IACjD,iEAAiE;IACjE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAgOD;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAAI,SAAS,uBAAuB,KAAG,IAgBnF,CAAC"}
1
+ {"version":3,"file":"conformance_table.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/conformance_table.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAwB9B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AAMjE,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAC,KAAK,eAAe,EAA4B,MAAM,uBAAuB,CAAC;AACtF,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,YAAY,CAAC;AAGvD;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IAC1C,iEAAiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,sDAAsD;AACtD,MAAM,WAAW,uBAAuB;IACvC,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC/C,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,kEAAkE;IAClE,QAAQ,CAAC,aAAa,EAAE,uBAAuB,CAAC;IAChD,4EAA4E;IAC5E,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,0BAA0B,CAAC;IACjD,iEAAiE;IACjE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAkOD;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAAI,SAAS,uBAAuB,KAAG,IAgBnF,CAAC"}
@@ -133,13 +133,15 @@ const run_rpc_case = async (c, transport, headers, suppress_default_origin, reso
133
133
  assert.ok(!res.ok, `${c.name}: expected error status ${c.expect.status} but got success`);
134
134
  assert.strictEqual(res.status, c.expect.status, `${c.name}: error status`);
135
135
  if (c.expect.error_reason !== undefined) {
136
+ // A row that *declares* a reason must carry it — present AND equal —
137
+ // mirroring the REST branch's unconditional `body.error` assertion. The
138
+ // earlier skip-if-absent form let a backend that dropped the reason pass
139
+ // a row declaring one, blessing a reason/forensic-parity divergence (the
140
+ // IDOR-mask / privilege reason is exactly the distinguishing bit). Rows
141
+ // whose denial genuinely has no reason (the bare `unauthenticated()` 401)
142
+ // simply omit `error_reason` and are pinned by `status` above.
136
143
  const reason = res.error.data?.reason;
137
- // Most RPC denials carry `error.data.reason` (incl. the pre-validation
138
- // 401 now); a denial that genuinely omits it falls back to the status
139
- // assertion above to pin the denial class.
140
- if (reason !== undefined) {
141
- assert.strictEqual(reason, c.expect.error_reason, `${c.name}: error.data.reason`);
142
- }
144
+ assert.strictEqual(reason, c.expect.error_reason, `${c.name}: error.data.reason`);
143
145
  }
144
146
  if (c.expect.fields)
145
147
  assert_fields(res.error.data, c.expect.fields, c.name);
@@ -1,13 +1,12 @@
1
1
  import '../assert_dev_env.js';
2
- import { type CellCrossTestOptions } from './cell_cross_helpers.js';
3
- import type { SetupTest } from './setup.js';
2
+ import type { RpcPathCrossSuiteOptions, SetupTest } from './setup.js';
4
3
  /**
5
4
  * The fact suite adds one optional knob to the shared cell options: a setup
6
5
  * variant whose keeper carries a **second actor**. Only the multi-actor case
7
6
  * needs it; the rest of the suite runs single-actor, so wiring it is opt-in.
8
7
  * Omit it and the multi-actor case silently skips.
9
8
  */
10
- export interface FactServingCrossTestOptions extends CellCrossTestOptions {
9
+ export interface FactServingCrossTestOptions extends RpcPathCrossSuiteOptions {
11
10
  readonly setup_test_multi_actor?: SetupTest;
12
11
  }
13
12
  export declare const describe_fact_serving_cross_tests: (options: FactServingCrossTestOptions) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"fact_serving.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/fact_serving.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA+C9B,OAAO,EAAgC,KAAK,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAEjG,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,WAAW,2BAA4B,SAAQ,oBAAoB;IACxE,QAAQ,CAAC,sBAAsB,CAAC,EAAE,SAAS,CAAC;CAC5C;AA8BD,eAAO,MAAM,iCAAiC,GAAI,SAAS,2BAA2B,KAAG,IA8NxF,CAAC"}
1
+ {"version":3,"file":"fact_serving.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/fact_serving.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAiD9B,OAAO,KAAK,EAAC,wBAAwB,EAAE,SAAS,EAAC,MAAM,YAAY,CAAC;AAEpE;;;;;GAKG;AACH,MAAM,WAAW,2BAA4B,SAAQ,wBAAwB;IAC5E,QAAQ,CAAC,sBAAsB,CAAC,EAAE,SAAS,CAAC;CAC5C;AA8BD,eAAO,MAAM,iCAAiC,GAAI,SAAS,2BAA2B,KAAG,IA8NxF,CAAC"}
@@ -1,10 +1,10 @@
1
1
  import '../assert_dev_env.js';
2
- import type { CellCrossTestOptions } from './cell_cross_helpers.js';
2
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
3
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.
4
+ * Options for the origin parity suite. The standard RPC-dispatched
5
+ * cross-suite shape (`setup_test` / `capabilities` / `rpc_path`); aliases
6
+ * the shared `RpcPathCrossSuiteOptions` rather than minting a duplicate.
7
7
  */
8
- export type OriginCrossTestOptions = CellCrossTestOptions;
8
+ export type OriginCrossTestOptions = RpcPathCrossSuiteOptions;
9
9
  export declare const describe_origin_cross_tests: (options: OriginCrossTestOptions) => void;
10
10
  //# sourceMappingURL=origin.d.ts.map
@@ -1 +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"}
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,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAGzD;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAM9D,eAAO,MAAM,2BAA2B,GAAI,SAAS,sBAAsB,KAAG,IAwC7E,CAAC"}
@@ -1,12 +1,7 @@
1
1
  import '../assert_dev_env.js';
2
- import { type BackendCapabilities } from './capabilities.js';
3
- import type { SetupTest } from './setup.js';
2
+ import type { CrossSuiteOptions } from './setup.js';
4
3
  /** Options for the readiness-probe parity suite. */
5
- export interface ReadyCrossTestOptions {
6
- /** Per-test fixture-producing function (fresh keeper + db per call). */
7
- readonly setup_test: SetupTest;
8
- /** Backend capability declarations — the suite gates on `capabilities.ready`. */
9
- readonly capabilities: BackendCapabilities;
4
+ export interface ReadyCrossTestOptions extends CrossSuiteOptions {
10
5
  /** Readiness probe path. Default `/ready`. */
11
6
  readonly ready_path?: string;
12
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ready.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ready.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAiC9B,OAAO,EAAU,KAAK,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C,oDAAoD;AACpD,MAAM,WAAW,qBAAqB;IACrC,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,8CAA8C;IAC9C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,0BAA0B,GAAI,SAAS,qBAAqB,KAAG,IAuB3E,CAAC"}
1
+ {"version":3,"file":"ready.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ready.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAkC9B,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,YAAY,CAAC;AAElD,oDAAoD;AACpD,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC/D,8CAA8C;IAC9C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,0BAA0B,GAAI,SAAS,qBAAqB,KAAG,IAuB3E,CAAC"}
@@ -187,6 +187,34 @@ export type TestFixture = TestFixtureBase;
187
187
  * a fresh per-test bundle on each call.
188
188
  */
189
189
  export type SetupTest = () => Promise<TestFixture>;
190
+ /**
191
+ * Base options shared by every imperative cross-backend parity suite
192
+ * (`origin` / `ready` / `body_size` / `cell_*` / `actor_*` /
193
+ * `account_lifecycle` / `app_settings` / `testing_backdoor` / …). The
194
+ * `{setup_test, capabilities}` core is identical across them; each suite
195
+ * extends this with its own path field (`rpc_path` for RPC-dispatched
196
+ * suites via `RpcPathCrossSuiteOptions`, `ready_path` for the readiness
197
+ * probe, etc.). Lives here in the neutral fixture-types home rather than in
198
+ * any one domain helper, so a non-cell suite no longer reaches into the
199
+ * cell helpers for its option shape.
200
+ */
201
+ export interface CrossSuiteOptions {
202
+ /** Per-test fixture-producing function (fresh keeper + db per call). */
203
+ readonly setup_test: SetupTest;
204
+ /** Backend capability declarations — each suite gates on its own flag. */
205
+ readonly capabilities: BackendCapabilities;
206
+ }
207
+ /**
208
+ * `CrossSuiteOptions` plus the RPC endpoint path the suite dispatches
209
+ * against — the shape every JSON-RPC-driven imperative suite takes (cell
210
+ * verbs, origin, body-size, actor lookup/search, account lifecycle, app
211
+ * settings, testing backdoor). Suites alias this under a self-documenting
212
+ * per-suite name (e.g. `OriginCrossTestOptions = RpcPathCrossSuiteOptions`).
213
+ */
214
+ export interface RpcPathCrossSuiteOptions extends CrossSuiteOptions {
215
+ /** RPC endpoint path the methods are mounted on. Default `/api/rpc`. */
216
+ readonly rpc_path?: string;
217
+ }
190
218
  /**
191
219
  * Options for `default_in_process_setup`. Extends `CreateTestAppOptions`
192
220
  * with the same `extra_accounts` slot the cross-process variant accepts
@@ -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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"}
@@ -1,6 +1,6 @@
1
1
  import '../assert_dev_env.js';
2
- import type { CellCrossTestOptions } from './cell_cross_helpers.js';
2
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
3
3
  /** Options for the testing-backdoor negative-credential suite. */
4
- export type TestingBackdoorCrossTestOptions = CellCrossTestOptions;
4
+ export type TestingBackdoorCrossTestOptions = RpcPathCrossSuiteOptions;
5
5
  export declare const describe_testing_backdoor_cross_tests: (options: TestingBackdoorCrossTestOptions) => void;
6
6
  //# 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;AAyD9B,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,yBAAyB,CAAC;AAgElE,kEAAkE;AAClE,MAAM,MAAM,+BAA+B,GAAG,oBAAoB,CAAC;AAEnE,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;AAyD9B,OAAO,KAAK,EAAC,wBAAwB,EAAc,MAAM,YAAY,CAAC;AA+DtE,kEAAkE;AAClE,MAAM,MAAM,+BAA+B,GAAG,wBAAwB,CAAC;AAEvE,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAiCF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.86.0",
3
+ "version": "0.87.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",