@fuzdev/fuz_app 0.140.0 → 0.141.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/CLAUDE.md +62 -17
- package/dist/actions/action_rpc.d.ts +5 -1
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +9 -1
- package/dist/actions/connection_closer.d.ts +25 -2
- package/dist/actions/connection_closer.d.ts.map +1 -1
- package/dist/actions/connection_closer.js +8 -1
- package/dist/actions/register_action_ws.d.ts +42 -6
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +87 -19
- package/dist/actions/register_ws_endpoint.d.ts +15 -6
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +5 -2
- package/dist/actions/socket.svelte.d.ts +19 -4
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +31 -4
- package/dist/actions/transports.d.ts +30 -1
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +30 -1
- package/dist/actions/transports_ws_auth_guard.d.ts +13 -6
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_auth_guard.js +24 -10
- package/dist/actions/transports_ws_backend.d.ts +51 -5
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +62 -9
- package/dist/actions/ws_endpoint_spec.d.ts +11 -10
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/auth/CLAUDE.md +11 -9
- package/dist/auth/account_route_schema.d.ts +1 -0
- package/dist/auth/account_route_schema.d.ts.map +1 -1
- package/dist/auth/account_route_schema.js +4 -0
- package/dist/auth/api_token.d.ts +20 -0
- package/dist/auth/api_token.d.ts.map +1 -1
- package/dist/auth/api_token.js +21 -1
- package/dist/auth/api_token_queries.d.ts +22 -4
- package/dist/auth/api_token_queries.d.ts.map +1 -1
- package/dist/auth/api_token_queries.js +11 -6
- package/dist/auth/audit_log_routes.d.ts +10 -0
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +20 -0
- package/dist/auth/audit_log_schema.d.ts +30 -5
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +30 -0
- package/dist/auth/bearer_auth.d.ts +4 -2
- package/dist/auth/bearer_auth.d.ts.map +1 -1
- package/dist/auth/bearer_auth.js +19 -8
- package/dist/auth/bootstrap_route_schema.d.ts +1 -0
- package/dist/auth/bootstrap_route_schema.d.ts.map +1 -1
- package/dist/auth/bootstrap_route_schema.js +1 -0
- package/dist/auth/cleanup.d.ts +9 -9
- package/dist/auth/cleanup.js +9 -9
- package/dist/auth/credential_deadline.d.ts +95 -0
- package/dist/auth/credential_deadline.d.ts.map +1 -0
- package/dist/auth/credential_deadline.js +139 -0
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
- package/dist/auth/daemon_token_middleware.js +4 -1
- package/dist/auth/middleware.d.ts +90 -12
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +115 -16
- package/dist/auth/request_context.d.ts +4 -2
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +14 -3
- package/dist/auth/resolved_auth.d.ts +13 -2
- package/dist/auth/resolved_auth.d.ts.map +1 -1
- package/dist/auth/resolved_auth.js +5 -4
- package/dist/auth/session_cookie.d.ts +4 -0
- package/dist/auth/session_cookie.d.ts.map +1 -1
- package/dist/auth/session_cookie.js +3 -2
- package/dist/auth/session_middleware.d.ts +1 -1
- package/dist/auth/session_middleware.d.ts.map +1 -1
- package/dist/auth/session_middleware.js +4 -1
- package/dist/auth/session_queries.d.ts +19 -2
- package/dist/auth/session_queries.d.ts.map +1 -1
- package/dist/auth/session_queries.js +8 -2
- package/dist/auth/signup_route_schema.d.ts.map +1 -1
- package/dist/auth/signup_route_schema.js +1 -0
- package/dist/hono_context.d.ts +23 -0
- package/dist/hono_context.d.ts.map +1 -1
- package/dist/hono_context.js +19 -0
- package/dist/http/CLAUDE.md +41 -15
- package/dist/http/middleware_spec.d.ts +16 -0
- package/dist/http/middleware_spec.d.ts.map +1 -1
- package/dist/http/origin.d.ts +113 -18
- package/dist/http/origin.d.ts.map +1 -1
- package/dist/http/origin.js +247 -127
- package/dist/http/route_spec.d.ts +21 -0
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/schema_helpers.d.ts +22 -0
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +24 -0
- package/dist/http/surface.d.ts +6 -1
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +12 -5
- package/dist/realtime/sse_auth_guard.d.ts +22 -6
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +31 -12
- package/dist/realtime/subscriber_registry.d.ts +10 -1
- package/dist/realtime/subscriber_registry.d.ts.map +1 -1
- package/dist/realtime/subscriber_registry.js +10 -1
- package/dist/server/app_server.d.ts +20 -7
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +8 -3
- package/dist/server/env.d.ts +2 -1
- package/dist/server/env.d.ts.map +1 -1
- package/dist/server/env.js +7 -17
- package/dist/server/serve_fact_route.d.ts.map +1 -1
- package/dist/server/serve_fact_route.js +1 -0
- package/dist/testing/CLAUDE.md +154 -22
- package/dist/testing/adversarial_headers.d.ts.map +1 -1
- package/dist/testing/adversarial_headers.js +13 -6
- package/dist/testing/connection_closer_helpers.d.ts +6 -1
- package/dist/testing/connection_closer_helpers.d.ts.map +1 -1
- package/dist/testing/connection_closer_helpers.js +4 -0
- package/dist/testing/cross_backend/body_size.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size.js +14 -65
- package/dist/testing/cross_backend/capabilities.d.ts +26 -2
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +9 -3
- package/dist/testing/cross_backend/conformance_case.d.ts +11 -3
- package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_case.js +6 -0
- package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_table.js +20 -19
- package/dist/testing/cross_backend/credential_deadline.d.ts +25 -0
- package/dist/testing/cross_backend/credential_deadline.d.ts.map +1 -0
- package/dist/testing/cross_backend/credential_deadline.js +185 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +13 -2
- package/dist/testing/cross_backend/full_spine_mount.d.ts +3 -0
- package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
- package/dist/testing/cross_backend/full_spine_mount.js +7 -1
- package/dist/testing/cross_backend/narrowed_api_token.d.ts +23 -0
- package/dist/testing/cross_backend/narrowed_api_token.d.ts.map +1 -0
- package/dist/testing/cross_backend/narrowed_api_token.js +40 -0
- package/dist/testing/cross_backend/origin.d.ts.map +1 -1
- package/dist/testing/cross_backend/origin.js +6 -26
- package/dist/testing/cross_backend/origin_conformance.d.ts +152 -0
- package/dist/testing/cross_backend/origin_conformance.d.ts.map +1 -0
- package/dist/testing/cross_backend/origin_conformance.js +136 -0
- package/dist/testing/cross_backend/origin_conformance.json +1679 -0
- package/dist/testing/cross_backend/origin_scope.d.ts +16 -0
- package/dist/testing/cross_backend/origin_scope.d.ts.map +1 -0
- package/dist/testing/cross_backend/origin_scope.js +140 -0
- package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts +35 -0
- package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts.map +1 -0
- package/dist/testing/cross_backend/role_grant_cross_helpers.js +64 -0
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts +8 -0
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.js +44 -33
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +6 -4
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +19 -0
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +22 -0
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +20 -7
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +180 -5
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +154 -5
- package/dist/testing/cross_backend/token_scope_surface.d.ts.map +1 -1
- package/dist/testing/cross_backend/token_scope_surface.js +25 -21
- package/dist/testing/cross_backend/transport_composition.d.ts +60 -0
- package/dist/testing/cross_backend/transport_composition.d.ts.map +1 -0
- package/dist/testing/cross_backend/transport_composition.js +364 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +21 -6
- package/dist/testing/cross_backend/ws_role_gated.d.ts +38 -0
- package/dist/testing/cross_backend/ws_role_gated.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_role_gated.js +142 -0
- package/dist/testing/entities.d.ts +23 -0
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +37 -0
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +3 -1
- package/dist/testing/middleware.d.ts +10 -0
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +31 -7
- package/dist/testing/stubs.d.ts +16 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +20 -7
- package/dist/testing/surface_invariants.js +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { RpcPathCrossSuiteOptions } from './setup.js';
|
|
4
|
+
import { TestingOriginCheckOutput, type TestingOriginCheckInput } from './testing_reset_actions.js';
|
|
5
|
+
/** One expected refusal of a parse row. */
|
|
6
|
+
export declare const OriginConformanceError: z.ZodObject<{
|
|
7
|
+
index: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
kind: z.ZodEnum<{
|
|
9
|
+
empty_entry: "empty_entry";
|
|
10
|
+
not_printable_ascii: "not_printable_ascii";
|
|
11
|
+
missing_scheme: "missing_scheme";
|
|
12
|
+
unsupported_scheme: "unsupported_scheme";
|
|
13
|
+
has_path: "has_path";
|
|
14
|
+
has_userinfo: "has_userinfo";
|
|
15
|
+
missing_host: "missing_host";
|
|
16
|
+
invalid_host_char: "invalid_host_char";
|
|
17
|
+
unbracketed_ipv6: "unbracketed_ipv6";
|
|
18
|
+
partial_wildcard: "partial_wildcard";
|
|
19
|
+
non_canonical_ipv4: "non_canonical_ipv4";
|
|
20
|
+
unclosed_ipv6: "unclosed_ipv6";
|
|
21
|
+
invalid_ipv6: "invalid_ipv6";
|
|
22
|
+
invalid_after_ipv6: "invalid_after_ipv6";
|
|
23
|
+
invalid_port: "invalid_port";
|
|
24
|
+
default_port: "default_port";
|
|
25
|
+
no_origins: "no_origins";
|
|
26
|
+
}>;
|
|
27
|
+
}, z.core.$strict>;
|
|
28
|
+
export type OriginConformanceError = z.infer<typeof OriginConformanceError>;
|
|
29
|
+
/** A parse row: the value parses (`ok: true`), or is refused with `errors`. */
|
|
30
|
+
export declare const OriginConformanceParseRow: z.ZodUnion<readonly [z.ZodObject<{
|
|
31
|
+
raw: z.ZodString;
|
|
32
|
+
ok: z.ZodLiteral<true>;
|
|
33
|
+
note: z.ZodOptional<z.ZodString>;
|
|
34
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
35
|
+
raw: z.ZodString;
|
|
36
|
+
errors: z.ZodArray<z.ZodObject<{
|
|
37
|
+
index: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
kind: z.ZodEnum<{
|
|
39
|
+
empty_entry: "empty_entry";
|
|
40
|
+
not_printable_ascii: "not_printable_ascii";
|
|
41
|
+
missing_scheme: "missing_scheme";
|
|
42
|
+
unsupported_scheme: "unsupported_scheme";
|
|
43
|
+
has_path: "has_path";
|
|
44
|
+
has_userinfo: "has_userinfo";
|
|
45
|
+
missing_host: "missing_host";
|
|
46
|
+
invalid_host_char: "invalid_host_char";
|
|
47
|
+
unbracketed_ipv6: "unbracketed_ipv6";
|
|
48
|
+
partial_wildcard: "partial_wildcard";
|
|
49
|
+
non_canonical_ipv4: "non_canonical_ipv4";
|
|
50
|
+
unclosed_ipv6: "unclosed_ipv6";
|
|
51
|
+
invalid_ipv6: "invalid_ipv6";
|
|
52
|
+
invalid_after_ipv6: "invalid_after_ipv6";
|
|
53
|
+
invalid_port: "invalid_port";
|
|
54
|
+
default_port: "default_port";
|
|
55
|
+
no_origins: "no_origins";
|
|
56
|
+
}>;
|
|
57
|
+
}, z.core.$strict>>;
|
|
58
|
+
note: z.ZodOptional<z.ZodString>;
|
|
59
|
+
}, z.core.$strict>]>;
|
|
60
|
+
export type OriginConformanceParseRow = z.infer<typeof OriginConformanceParseRow>;
|
|
61
|
+
/** A match row: a valid allowlist, one `Origin` value or `null`, and the answer. */
|
|
62
|
+
export declare const OriginConformanceMatchRow: z.ZodObject<{
|
|
63
|
+
patterns: z.ZodString;
|
|
64
|
+
origin: z.ZodNullable<z.ZodString>;
|
|
65
|
+
allowed: z.ZodBoolean;
|
|
66
|
+
note: z.ZodOptional<z.ZodString>;
|
|
67
|
+
}, z.core.$strict>;
|
|
68
|
+
export type OriginConformanceMatchRow = z.infer<typeof OriginConformanceMatchRow>;
|
|
69
|
+
/** The conformance table. */
|
|
70
|
+
export declare const OriginConformance: z.ZodObject<{
|
|
71
|
+
parse: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
72
|
+
raw: z.ZodString;
|
|
73
|
+
ok: z.ZodLiteral<true>;
|
|
74
|
+
note: z.ZodOptional<z.ZodString>;
|
|
75
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
76
|
+
raw: z.ZodString;
|
|
77
|
+
errors: z.ZodArray<z.ZodObject<{
|
|
78
|
+
index: z.ZodOptional<z.ZodNumber>;
|
|
79
|
+
kind: z.ZodEnum<{
|
|
80
|
+
empty_entry: "empty_entry";
|
|
81
|
+
not_printable_ascii: "not_printable_ascii";
|
|
82
|
+
missing_scheme: "missing_scheme";
|
|
83
|
+
unsupported_scheme: "unsupported_scheme";
|
|
84
|
+
has_path: "has_path";
|
|
85
|
+
has_userinfo: "has_userinfo";
|
|
86
|
+
missing_host: "missing_host";
|
|
87
|
+
invalid_host_char: "invalid_host_char";
|
|
88
|
+
unbracketed_ipv6: "unbracketed_ipv6";
|
|
89
|
+
partial_wildcard: "partial_wildcard";
|
|
90
|
+
non_canonical_ipv4: "non_canonical_ipv4";
|
|
91
|
+
unclosed_ipv6: "unclosed_ipv6";
|
|
92
|
+
invalid_ipv6: "invalid_ipv6";
|
|
93
|
+
invalid_after_ipv6: "invalid_after_ipv6";
|
|
94
|
+
invalid_port: "invalid_port";
|
|
95
|
+
default_port: "default_port";
|
|
96
|
+
no_origins: "no_origins";
|
|
97
|
+
}>;
|
|
98
|
+
}, z.core.$strict>>;
|
|
99
|
+
note: z.ZodOptional<z.ZodString>;
|
|
100
|
+
}, z.core.$strict>]>>;
|
|
101
|
+
match: z.ZodArray<z.ZodObject<{
|
|
102
|
+
patterns: z.ZodString;
|
|
103
|
+
origin: z.ZodNullable<z.ZodString>;
|
|
104
|
+
allowed: z.ZodBoolean;
|
|
105
|
+
note: z.ZodOptional<z.ZodString>;
|
|
106
|
+
}, z.core.$strict>>;
|
|
107
|
+
}, z.core.$strict>;
|
|
108
|
+
export type OriginConformance = z.infer<typeof OriginConformance>;
|
|
109
|
+
/** The committed table, resolved relative to this module. */
|
|
110
|
+
export declare const ORIGIN_CONFORMANCE_URL: URL;
|
|
111
|
+
/**
|
|
112
|
+
* Read and validate the committed conformance table.
|
|
113
|
+
*
|
|
114
|
+
* @returns the parsed table
|
|
115
|
+
* @throws Error when the file doesn't match `OriginConformance`
|
|
116
|
+
*/
|
|
117
|
+
export declare const load_origin_conformance: () => OriginConformance;
|
|
118
|
+
/** One table row as the action input that checks it. */
|
|
119
|
+
export interface OriginConformanceCheck {
|
|
120
|
+
/** A short label naming the row, for a failure message. */
|
|
121
|
+
readonly label: string;
|
|
122
|
+
readonly input: TestingOriginCheckInput;
|
|
123
|
+
readonly expected: TestingOriginCheckOutput;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Flatten the table into action inputs and the answers they must get. A parse
|
|
127
|
+
* row sends a `null` origin, so a value that parses answers
|
|
128
|
+
* `{ok: true, allowed: true}`.
|
|
129
|
+
*
|
|
130
|
+
* @param table - the conformance table
|
|
131
|
+
* @returns one check per row, parse rows first
|
|
132
|
+
*/
|
|
133
|
+
export declare const to_origin_conformance_checks: (table: OriginConformance) => Array<OriginConformanceCheck>;
|
|
134
|
+
/**
|
|
135
|
+
* Compare each check's answer with its expectation and fail once, listing
|
|
136
|
+
* every row that disagrees.
|
|
137
|
+
*
|
|
138
|
+
* @param checks - the table's checks
|
|
139
|
+
* @param answer - the answer each check got, in order
|
|
140
|
+
* @param backend - the name the failure message gives the answerer
|
|
141
|
+
*/
|
|
142
|
+
export declare const assert_origin_conformance: (checks: ReadonlyArray<OriginConformanceCheck>, answer: ReadonlyArray<unknown>, backend: string) => void;
|
|
143
|
+
/** Options for `describe_origin_conformance_cross_tests`. */
|
|
144
|
+
export type OriginConformanceCrossTestOptions = RpcPathCrossSuiteOptions;
|
|
145
|
+
/**
|
|
146
|
+
* Register the origin conformance suite: every row of the committed table,
|
|
147
|
+
* sent to the backend's `_testing_origin_check` action over the keeper's
|
|
148
|
+
* daemon-token channel, must get the answer the table names. The action is on
|
|
149
|
+
* every spine test binary, so the suite is ungated.
|
|
150
|
+
*/
|
|
151
|
+
export declare const describe_origin_conformance_cross_tests: (options: OriginConformanceCrossTestOptions) => void;
|
|
152
|
+
//# sourceMappingURL=origin_conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"origin_conformance.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/origin_conformance.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA0B9B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EACN,wBAAwB,EAExB,KAAK,uBAAuB,EAC5B,MAAM,4BAA4B,CAAC;AAEpC,2CAA2C;AAC3C,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;kBAGjC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE5E,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAOpC,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAElF,oFAAoF;AACpF,eAAO,MAAM,yBAAyB;;;;;kBAKpC,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAElF,6BAA6B;AAC7B,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAG5B,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,6DAA6D;AAC7D,eAAO,MAAM,sBAAsB,EAAE,GAA2D,CAAC;AAEjG;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,QAAO,iBACuC,CAAC;AAEnF,wDAAwD;AACxD,MAAM,WAAW,sBAAsB;IACtC,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC;CAC5C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,GACxC,OAAO,iBAAiB,KACtB,KAAK,CAAC,sBAAsB,CAc9B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,GACrC,QAAQ,aAAa,CAAC,sBAAsB,CAAC,EAC7C,QAAQ,aAAa,CAAC,OAAO,CAAC,EAC9B,SAAS,MAAM,KACb,IAiBF,CAAC;AAEF,6DAA6D;AAC7D,MAAM,MAAM,iCAAiC,GAAG,wBAAwB,CAAC;AAEzE;;;;;GAKG;AACH,eAAO,MAAM,uCAAuC,GACnD,SAAS,iCAAiC,KACxC,IA4BF,CAAC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* The origin allowlist conformance table, and the cross-backend suite that
|
|
4
|
+
* runs it against each backend over the wire.
|
|
5
|
+
*
|
|
6
|
+
* `origin_conformance.json` (beside this module) is the one statement of the
|
|
7
|
+
* allowlist grammar and matcher both spines implement. It holds two tables:
|
|
8
|
+
*
|
|
9
|
+
* - **parse** rows — `{raw, ok: true}` or `{raw, errors: [{index?, kind}]}`:
|
|
10
|
+
* an allowlist value (as `FUZ_ALLOWED_ORIGINS` would carry it) and whether
|
|
11
|
+
* it parses, or every refusal with its 1-based entry position (absent for a
|
|
12
|
+
* list-level refusal) and its `AllowedOriginsErrorKind`.
|
|
13
|
+
* - **match** rows — `{patterns, origin, allowed}`: a valid allowlist, one
|
|
14
|
+
* `Origin` value (`null` for none), and the request-level answer.
|
|
15
|
+
*
|
|
16
|
+
* A row may carry a `note` for the reader. The TS unit test reads the table
|
|
17
|
+
* directly; `describe_origin_conformance_cross_tests` sends every row to a
|
|
18
|
+
* backend's `_testing_origin_check` action and compares the answer, so the
|
|
19
|
+
* Rust spine is held to the same rows without reading this file.
|
|
20
|
+
*
|
|
21
|
+
* @module
|
|
22
|
+
*/
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
import { assert, describe, test } from 'vitest';
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
import { AllowedOriginsErrorKind } from '../../http/origin.js';
|
|
27
|
+
import { cross_rpc_call } from './cell_cross_helpers.js';
|
|
28
|
+
import { SPINE_RPC_PATH } from './spine_surface_constants.js';
|
|
29
|
+
import { TestingOriginCheckOutput, testing_origin_check_action_spec } from './testing_reset_actions.js';
|
|
30
|
+
/** One expected refusal of a parse row. */
|
|
31
|
+
export const OriginConformanceError = z.strictObject({
|
|
32
|
+
index: z.number().int().min(1).optional(),
|
|
33
|
+
kind: AllowedOriginsErrorKind
|
|
34
|
+
});
|
|
35
|
+
/** A parse row: the value parses (`ok: true`), or is refused with `errors`. */
|
|
36
|
+
export const OriginConformanceParseRow = z.union([
|
|
37
|
+
z.strictObject({ raw: z.string(), ok: z.literal(true), note: z.string().optional() }),
|
|
38
|
+
z.strictObject({
|
|
39
|
+
raw: z.string(),
|
|
40
|
+
errors: z.array(OriginConformanceError).min(1),
|
|
41
|
+
note: z.string().optional()
|
|
42
|
+
})
|
|
43
|
+
]);
|
|
44
|
+
/** A match row: a valid allowlist, one `Origin` value or `null`, and the answer. */
|
|
45
|
+
export const OriginConformanceMatchRow = z.strictObject({
|
|
46
|
+
patterns: z.string(),
|
|
47
|
+
origin: z.string().nullable(),
|
|
48
|
+
allowed: z.boolean(),
|
|
49
|
+
note: z.string().optional()
|
|
50
|
+
});
|
|
51
|
+
/** The conformance table. */
|
|
52
|
+
export const OriginConformance = z.strictObject({
|
|
53
|
+
parse: z.array(OriginConformanceParseRow).min(1),
|
|
54
|
+
match: z.array(OriginConformanceMatchRow).min(1)
|
|
55
|
+
});
|
|
56
|
+
/** The committed table, resolved relative to this module. */
|
|
57
|
+
export const ORIGIN_CONFORMANCE_URL = new URL('./origin_conformance.json', import.meta.url);
|
|
58
|
+
/**
|
|
59
|
+
* Read and validate the committed conformance table.
|
|
60
|
+
*
|
|
61
|
+
* @returns the parsed table
|
|
62
|
+
* @throws Error when the file doesn't match `OriginConformance`
|
|
63
|
+
*/
|
|
64
|
+
export const load_origin_conformance = () => OriginConformance.parse(JSON.parse(readFileSync(ORIGIN_CONFORMANCE_URL, 'utf8')));
|
|
65
|
+
/**
|
|
66
|
+
* Flatten the table into action inputs and the answers they must get. A parse
|
|
67
|
+
* row sends a `null` origin, so a value that parses answers
|
|
68
|
+
* `{ok: true, allowed: true}`.
|
|
69
|
+
*
|
|
70
|
+
* @param table - the conformance table
|
|
71
|
+
* @returns one check per row, parse rows first
|
|
72
|
+
*/
|
|
73
|
+
export const to_origin_conformance_checks = (table) => [
|
|
74
|
+
...table.parse.map((row) => ({
|
|
75
|
+
label: `parse ${JSON.stringify(row.raw)}`,
|
|
76
|
+
input: { patterns: row.raw, origin: null },
|
|
77
|
+
expected: 'errors' in row
|
|
78
|
+
? { ok: false, errors: row.errors.map((e) => ({ ...e })) }
|
|
79
|
+
: { ok: true, allowed: true }
|
|
80
|
+
})),
|
|
81
|
+
...table.match.map((row) => ({
|
|
82
|
+
label: `match ${JSON.stringify(row.patterns)} × ${JSON.stringify(row.origin)}`,
|
|
83
|
+
input: { patterns: row.patterns, origin: row.origin },
|
|
84
|
+
expected: { ok: true, allowed: row.allowed }
|
|
85
|
+
}))
|
|
86
|
+
];
|
|
87
|
+
/**
|
|
88
|
+
* Compare each check's answer with its expectation and fail once, listing
|
|
89
|
+
* every row that disagrees.
|
|
90
|
+
*
|
|
91
|
+
* @param checks - the table's checks
|
|
92
|
+
* @param answer - the answer each check got, in order
|
|
93
|
+
* @param backend - the name the failure message gives the answerer
|
|
94
|
+
*/
|
|
95
|
+
export const assert_origin_conformance = (checks, answer, backend) => {
|
|
96
|
+
const failures = [];
|
|
97
|
+
checks.forEach((check, i) => {
|
|
98
|
+
const got = answer[i];
|
|
99
|
+
try {
|
|
100
|
+
assert.deepStrictEqual(got, check.expected);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
failures.push(`${check.label}: expected ${JSON.stringify(check.expected)}, got ${JSON.stringify(got)}`);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
assert.ok(failures.length === 0, `${backend}: ${failures.length} of ${checks.length} origin conformance rows disagree:\n` +
|
|
107
|
+
failures.join('\n'));
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Register the origin conformance suite: every row of the committed table,
|
|
111
|
+
* sent to the backend's `_testing_origin_check` action over the keeper's
|
|
112
|
+
* daemon-token channel, must get the answer the table names. The action is on
|
|
113
|
+
* every spine test binary, so the suite is ungated.
|
|
114
|
+
*/
|
|
115
|
+
export const describe_origin_conformance_cross_tests = (options) => {
|
|
116
|
+
const { setup_test } = options;
|
|
117
|
+
const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
|
|
118
|
+
const checks = to_origin_conformance_checks(load_origin_conformance());
|
|
119
|
+
describe('origin allowlist conformance', () => {
|
|
120
|
+
test('every table row gets the answer it names', async () => {
|
|
121
|
+
const fixture = await setup_test();
|
|
122
|
+
// Origin-free: the daemon-token middleware discards the credential in a
|
|
123
|
+
// browser context, and the cross-process transport adds an `Origin`
|
|
124
|
+
const transport = fixture.fresh_transport({ origin: null });
|
|
125
|
+
const headers = fixture.create_daemon_token_headers();
|
|
126
|
+
const answers = [];
|
|
127
|
+
for (const check of checks) {
|
|
128
|
+
const res = await cross_rpc_call(transport, rpc_path, testing_origin_check_action_spec.method, check.input, headers);
|
|
129
|
+
assert.ok(res.ok, `${check.label}: RPC failed: ${JSON.stringify(res.error)}`);
|
|
130
|
+
const parsed = TestingOriginCheckOutput.safeParse(res.result);
|
|
131
|
+
answers.push(parsed.success ? parsed.data : res.result);
|
|
132
|
+
}
|
|
133
|
+
assert_origin_conformance(checks, answers, 'backend');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
};
|