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