@fuzdev/fuz_app 0.142.0 → 0.143.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/http/CLAUDE.md +1 -1
- package/dist/http/ip_canonical.d.ts +26 -2
- package/dist/http/ip_canonical.d.ts.map +1 -1
- package/dist/http/ip_canonical.js +107 -42
- package/dist/testing/CLAUDE.md +6 -4
- package/dist/testing/cross_backend/full_spine_mount.js +2 -1
- package/dist/testing/cross_backend/origin_conformance.d.ts +1 -1
- package/dist/testing/cross_backend/origin_conformance.d.ts.map +1 -1
- package/dist/testing/cross_backend/origin_conformance.js +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +12 -20
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +12 -20
- package/dist/testing/cross_backend/testing_origin_check.d.ts +128 -0
- package/dist/testing/cross_backend/testing_origin_check.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_origin_check.js +87 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +7 -119
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +8 -92
- package/package.json +1 -1
package/dist/http/CLAUDE.md
CHANGED
|
@@ -24,7 +24,7 @@ effects, see ../../../docs/architecture.md.
|
|
|
24
24
|
- `http/surface_query.ts` — pure filters/groupings over `AppSurface`.
|
|
25
25
|
- `http/proxy.ts` — trusted-proxy middleware, CIDR parsing, rightmost-first XFF resolution. Pulls `hono/utils/ipaddr` for CIDR matching.
|
|
26
26
|
- `http/client_ip.ts` — `get_client_ip(c)` — reads the resolved IP off the context (set by `proxy.ts`'s middleware). Split out of `proxy.ts` so it's hono-free: dispatch + route modules that only _read_ the IP don't pull `hono/utils/ipaddr`, keeping cross-process test surfaces free of the optional `hono` peer.
|
|
27
|
-
- `http/ip_canonical.ts` — RFC 5952 IPv6 canonicalization + IPv4-mapped collapse; `IP_LITERAL_CHARS` regex.
|
|
27
|
+
- `http/ip_canonical.ts` — RFC 5952 IPv6 canonicalization + IPv4-mapped collapse, `rate_limit_ip_key` (an IPv6 client's `/64`), and its own `parse_ipv4_bits` / `parse_ipv6_bits` (the grammar of Rust's `IpAddr::from_str`); `IP_LITERAL_CHARS` regex. Imports nothing — the dispatcher keys its IP limiter through it, so it must stay hono-free (`src/test/hono_free_modules.test.ts` walks every `src/lib` module's graph).
|
|
28
28
|
- `http/origin.ts` — origin allowlist: the strict pattern grammar shared with the Rust spine, typed refusals, and the Origin-only middleware.
|
|
29
29
|
- `http/jsonrpc.ts` — JSON-RPC 2.0 envelope schemas (MCP superset), `JsonrpcErrorCode`, `_meta`.
|
|
30
30
|
- `http/jsonrpc_errors.ts` — `ThrownJsonrpcError`, `jsonrpc_errors` throwers, HTTP-status mappings.
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
* strings (`'unknown'`, `'attacker:controlled'`, `'::1\n'`) pass
|
|
19
19
|
* through unchanged so downstream strict validators can still
|
|
20
20
|
* reject them.
|
|
21
|
-
* 2. Parses
|
|
21
|
+
* 2. Parses with `parse_ipv4_bits` / `parse_ipv6_bits` — the grammar of
|
|
22
|
+
* Rust's `IpAddr::from_str`, which the spine parses with.
|
|
22
23
|
* 3. Re-emits the canonical RFC 5952 string (lowercase hex,
|
|
23
24
|
* longest-zero-run compressed, IPv4-mapped emitted in the dotted
|
|
24
25
|
* form mandated by RFC 5952 §5).
|
|
@@ -37,8 +38,31 @@
|
|
|
37
38
|
* the limiter call sites apply it — the client IP stays the full address
|
|
38
39
|
* everywhere else (audit rows, token `last_used_ip`, `REMOTE_ADDR`).
|
|
39
40
|
*
|
|
41
|
+
* The module imports nothing: the action dispatcher keys its IP limiter
|
|
42
|
+
* through it, so it must not pull the optional `hono` peer.
|
|
43
|
+
*
|
|
40
44
|
* @module
|
|
41
45
|
*/
|
|
46
|
+
/**
|
|
47
|
+
* Parse a dotted-quad IPv4 address to its 32-bit value.
|
|
48
|
+
*
|
|
49
|
+
* Four decimal octets, each 0–255 with no leading zeros (`01.2.3.4` is
|
|
50
|
+
* refused, as Rust's `Ipv4Addr::from_str` refuses it).
|
|
51
|
+
*
|
|
52
|
+
* @returns the address as an unsigned 32-bit number, or `null` when `ip` isn't one
|
|
53
|
+
*/
|
|
54
|
+
export declare const parse_ipv4_bits: (ip: string) => number | null;
|
|
55
|
+
/**
|
|
56
|
+
* Parse an IPv6 address to its 128-bit value.
|
|
57
|
+
*
|
|
58
|
+
* The grammar of Rust's `Ipv6Addr::from_str`: eight groups of one to four
|
|
59
|
+
* hex digits (either case), or fewer around a single `::` standing for one or
|
|
60
|
+
* more zero groups, the last two groups optionally written as a dotted-quad
|
|
61
|
+
* IPv4 address. No zone (`%eth0`) — callers strip it first.
|
|
62
|
+
*
|
|
63
|
+
* @returns the address as a `bigint` in `[0, 2^128)`, or `null` when `ip` isn't one
|
|
64
|
+
*/
|
|
65
|
+
export declare const parse_ipv6_bits: (ip: string) => bigint | null;
|
|
42
66
|
/**
|
|
43
67
|
* Allowed character set for a bare IP literal.
|
|
44
68
|
*
|
|
@@ -95,7 +119,7 @@ export declare const canonicalize_ip: (ip: string) => string;
|
|
|
95
119
|
*
|
|
96
120
|
* Pure helper exported for the test suite to exercise the
|
|
97
121
|
* canonicalization invariants directly without a full
|
|
98
|
-
* `
|
|
122
|
+
* `parse_ipv6_bits` round-trip.
|
|
99
123
|
*
|
|
100
124
|
* @param bits - the 128-bit IPv6 value as `bigint`. Must satisfy `0n <= bits < 2n ** 128n`;
|
|
101
125
|
* throws `RangeError` otherwise. Silent truncation would mask caller bugs since the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ip_canonical.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/ip_canonical.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ip_canonical.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/ip_canonical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AASH;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAAI,IAAI,MAAM,KAAG,MAAM,GAAG,IAKrD,CAAC;AA0BF;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,GAAI,IAAI,MAAM,KAAG,MAAM,GAAG,IAkBrD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,QAAqB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,eAAe,GAAI,IAAI,MAAM,KAAG,MAsB5C,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,wBAAwB,GAAI,MAAM,MAAM,KAAG,MAgEvD,CAAC;AAKF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,iBAAiB,GAAI,IAAI,MAAM,KAAG,MAQ9C,CAAC"}
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
* strings (`'unknown'`, `'attacker:controlled'`, `'::1\n'`) pass
|
|
19
19
|
* through unchanged so downstream strict validators can still
|
|
20
20
|
* reject them.
|
|
21
|
-
* 2. Parses
|
|
21
|
+
* 2. Parses with `parse_ipv4_bits` / `parse_ipv6_bits` — the grammar of
|
|
22
|
+
* Rust's `IpAddr::from_str`, which the spine parses with.
|
|
22
23
|
* 3. Re-emits the canonical RFC 5952 string (lowercase hex,
|
|
23
24
|
* longest-zero-run compressed, IPv4-mapped emitted in the dotted
|
|
24
25
|
* form mandated by RFC 5952 §5).
|
|
@@ -37,9 +38,92 @@
|
|
|
37
38
|
* the limiter call sites apply it — the client IP stays the full address
|
|
38
39
|
* everywhere else (audit rows, token `last_used_ip`, `REMOTE_ADDR`).
|
|
39
40
|
*
|
|
41
|
+
* The module imports nothing: the action dispatcher keys its IP limiter
|
|
42
|
+
* through it, so it must not pull the optional `hono` peer.
|
|
43
|
+
*
|
|
40
44
|
* @module
|
|
41
45
|
*/
|
|
42
|
-
|
|
46
|
+
/** A dotted-quad IPv4 address: four decimal octets, 0–255, no leading zeros. */
|
|
47
|
+
const IPV4_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$/;
|
|
48
|
+
/** One IPv6 group: one to four hex digits. */
|
|
49
|
+
const IPV6_GROUP_REGEX = /^[0-9a-fA-F]{1,4}$/;
|
|
50
|
+
/**
|
|
51
|
+
* Parse a dotted-quad IPv4 address to its 32-bit value.
|
|
52
|
+
*
|
|
53
|
+
* Four decimal octets, each 0–255 with no leading zeros (`01.2.3.4` is
|
|
54
|
+
* refused, as Rust's `Ipv4Addr::from_str` refuses it).
|
|
55
|
+
*
|
|
56
|
+
* @returns the address as an unsigned 32-bit number, or `null` when `ip` isn't one
|
|
57
|
+
*/
|
|
58
|
+
export const parse_ipv4_bits = (ip) => {
|
|
59
|
+
if (!IPV4_REGEX.test(ip))
|
|
60
|
+
return null;
|
|
61
|
+
let bits = 0;
|
|
62
|
+
for (const octet of ip.split('.'))
|
|
63
|
+
bits = bits * 256 + Number(octet);
|
|
64
|
+
return bits;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Parse the colon-separated groups on one side of a `::` (or the whole
|
|
68
|
+
* address when there is none), `null` on a malformed one. Only the last group
|
|
69
|
+
* of the address may be a dotted-quad IPv4 tail, which fills two groups.
|
|
70
|
+
*/
|
|
71
|
+
const parse_ipv6_groups = (part, allow_ipv4_tail) => {
|
|
72
|
+
if (part === '')
|
|
73
|
+
return [];
|
|
74
|
+
const pieces = part.split(':');
|
|
75
|
+
const groups = [];
|
|
76
|
+
for (let i = 0; i < pieces.length; i++) {
|
|
77
|
+
const piece = pieces[i];
|
|
78
|
+
if (allow_ipv4_tail && i === pieces.length - 1 && piece.includes('.')) {
|
|
79
|
+
const ipv4 = parse_ipv4_bits(piece);
|
|
80
|
+
if (ipv4 === null)
|
|
81
|
+
return null;
|
|
82
|
+
groups.push(Math.floor(ipv4 / 0x10000), ipv4 % 0x10000);
|
|
83
|
+
}
|
|
84
|
+
else if (IPV6_GROUP_REGEX.test(piece)) {
|
|
85
|
+
groups.push(parseInt(piece, 16));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return groups;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Parse an IPv6 address to its 128-bit value.
|
|
95
|
+
*
|
|
96
|
+
* The grammar of Rust's `Ipv6Addr::from_str`: eight groups of one to four
|
|
97
|
+
* hex digits (either case), or fewer around a single `::` standing for one or
|
|
98
|
+
* more zero groups, the last two groups optionally written as a dotted-quad
|
|
99
|
+
* IPv4 address. No zone (`%eth0`) — callers strip it first.
|
|
100
|
+
*
|
|
101
|
+
* @returns the address as a `bigint` in `[0, 2^128)`, or `null` when `ip` isn't one
|
|
102
|
+
*/
|
|
103
|
+
export const parse_ipv6_bits = (ip) => {
|
|
104
|
+
const halves = ip.split('::');
|
|
105
|
+
let groups;
|
|
106
|
+
if (halves.length === 1) {
|
|
107
|
+
const all = parse_ipv6_groups(ip, true);
|
|
108
|
+
if (all === null || all.length !== 8)
|
|
109
|
+
return null;
|
|
110
|
+
groups = all;
|
|
111
|
+
}
|
|
112
|
+
else if (halves.length === 2) {
|
|
113
|
+
const head = parse_ipv6_groups(halves[0], false);
|
|
114
|
+
const tail = parse_ipv6_groups(halves[1], true);
|
|
115
|
+
if (head === null || tail === null || head.length + tail.length > 7)
|
|
116
|
+
return null;
|
|
117
|
+
groups = [...head, ...new Array(8 - head.length - tail.length).fill(0), ...tail];
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
let bits = 0n;
|
|
123
|
+
for (const group of groups)
|
|
124
|
+
bits = (bits << 16n) | BigInt(group);
|
|
125
|
+
return bits;
|
|
126
|
+
};
|
|
43
127
|
/**
|
|
44
128
|
* Allowed character set for a bare IP literal.
|
|
45
129
|
*
|
|
@@ -86,39 +170,27 @@ export const IP_LITERAL_CHARS = /^[0-9a-fA-F.:]+$/;
|
|
|
86
170
|
export const canonicalize_ip = (ip) => {
|
|
87
171
|
const lowered = ip.toLowerCase();
|
|
88
172
|
// Strict char-set filter — reject brackets, whitespace, control bytes,
|
|
89
|
-
// letters g-z before invoking the parser
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
// longer reject it. Pass-through preserves the original string.
|
|
173
|
+
// letters g-z, and `%` (so a zone) before invoking the parser, so a
|
|
174
|
+
// malformed form passes through for downstream `validate_ip_strict` to
|
|
175
|
+
// reject
|
|
93
176
|
if (!IP_LITERAL_CHARS.test(lowered))
|
|
94
177
|
return lowered;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// needed. Malformed forms (`999.999.999.999`) still pass through
|
|
99
|
-
// here; downstream `validate_ip_strict` rejects them via its own
|
|
100
|
-
// round-trip parse.
|
|
178
|
+
// IPv4's dotted-decimal form is already canonical — no transform needed.
|
|
179
|
+
// Malformed forms (`999.999.999.999`) fail both parsers and pass through.
|
|
180
|
+
if (parse_ipv4_bits(lowered) !== null)
|
|
101
181
|
return lowered;
|
|
182
|
+
const bits = parse_ipv6_bits(lowered);
|
|
183
|
+
if (bits === null)
|
|
184
|
+
return lowered;
|
|
185
|
+
const canonical = ipv6_bigint_to_canonical(bits);
|
|
186
|
+
// Strip `::ffff:` only when the canonical form is dotted IPv4-mapped
|
|
187
|
+
// (`::ffff:X.X.X.X`). Pure IPv6 values that happen to start with
|
|
188
|
+
// `::ffff:` (e.g. `::ffff:1` → `0:0:0:0:0:0:ffff:1`, where group[5] is 0
|
|
189
|
+
// not 0xffff) emit without the dot and are preserved.
|
|
190
|
+
if (canonical.startsWith('::ffff:') && canonical.substring(7).includes('.')) {
|
|
191
|
+
return canonical.substring(7);
|
|
102
192
|
}
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
const bits = convertIPv6ToBinary(lowered);
|
|
106
|
-
const canonical = ipv6_bigint_to_canonical(bits);
|
|
107
|
-
// Strip `::ffff:` only when the canonical form is dotted
|
|
108
|
-
// IPv4-mapped (`::ffff:X.X.X.X`). Pure IPv6 values that happen
|
|
109
|
-
// to start with `::ffff:` (e.g. `::ffff:1` → `0:0:0:0:0:0:ffff:1`,
|
|
110
|
-
// where group[5] is 0 not 0xffff) emit without the dot and
|
|
111
|
-
// are preserved.
|
|
112
|
-
if (canonical.startsWith('::ffff:') && canonical.substring(7).includes('.')) {
|
|
113
|
-
return canonical.substring(7);
|
|
114
|
-
}
|
|
115
|
-
return canonical;
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
return lowered;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return lowered;
|
|
193
|
+
return canonical;
|
|
122
194
|
};
|
|
123
195
|
/**
|
|
124
196
|
* Convert a 128-bit IPv6 binary value into its RFC 5952 canonical string form.
|
|
@@ -132,7 +204,7 @@ export const canonicalize_ip = (ip) => {
|
|
|
132
204
|
*
|
|
133
205
|
* Pure helper exported for the test suite to exercise the
|
|
134
206
|
* canonicalization invariants directly without a full
|
|
135
|
-
* `
|
|
207
|
+
* `parse_ipv6_bits` round-trip.
|
|
136
208
|
*
|
|
137
209
|
* @param bits - the 128-bit IPv6 value as `bigint`. Must satisfy `0n <= bits < 2n ** 128n`;
|
|
138
210
|
* throws `RangeError` otherwise. Silent truncation would mask caller bugs since the
|
|
@@ -226,17 +298,10 @@ export const rate_limit_ip_key = (ip) => {
|
|
|
226
298
|
const canonical = canonicalize_ip(zone_at === -1 ? ip : ip.slice(0, zone_at));
|
|
227
299
|
if (!IP_LITERAL_CHARS.test(canonical))
|
|
228
300
|
return ip;
|
|
229
|
-
|
|
230
|
-
if (family === 'IPv4')
|
|
301
|
+
if (parse_ipv4_bits(canonical) !== null)
|
|
231
302
|
return canonical;
|
|
232
|
-
|
|
303
|
+
const bits = parse_ipv6_bits(canonical);
|
|
304
|
+
if (bits === null)
|
|
233
305
|
return ip;
|
|
234
|
-
let bits;
|
|
235
|
-
try {
|
|
236
|
-
bits = convertIPv6ToBinary(canonical);
|
|
237
|
-
}
|
|
238
|
-
catch {
|
|
239
|
-
return ip;
|
|
240
|
-
}
|
|
241
306
|
return `${ipv6_bigint_to_canonical(bits & IPV6_PREFIX_64_MASK)}/64`;
|
|
242
307
|
};
|
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -1607,7 +1607,8 @@ are `src/test/auth/cell_crud_parity.db.test.ts`
|
|
|
1607
1607
|
payload-expiry tests never reached. Daemon-token-gated like its siblings; the
|
|
1608
1608
|
Rust mirror is `fuz_testing::create_testing_mint_session_action_spec`.
|
|
1609
1609
|
|
|
1610
|
-
|
|
1610
|
+
In the hono-free sibling `testing/cross_backend/testing_origin_check.ts`,
|
|
1611
|
+
**not** bundled: `_testing_origin_check`
|
|
1611
1612
|
(`create_testing_origin_check_action()`, `run_testing_origin_check(input)`,
|
|
1612
1613
|
`TestingOriginCheckInput` / `TestingOriginCheckOutput`) — answers the origin
|
|
1613
1614
|
allowlist's parse and request check for one `{patterns, origin}` pair:
|
|
@@ -1617,7 +1618,8 @@ are `src/test/auth/cell_crud_parity.db.test.ts`
|
|
|
1617
1618
|
keeps an exact action-manifest gate; the spine binary appends it in
|
|
1618
1619
|
`build_full_spine_rpc_actions`.
|
|
1619
1620
|
|
|
1620
|
-
|
|
1621
|
+
Back in `testing_reset_actions.ts`, also **not** bundled:
|
|
1622
|
+
`_testing_shorten_credential_expiry`
|
|
1621
1623
|
(`create_testing_shorten_credential_expiry_action()`) — pulls an account's
|
|
1622
1624
|
`auth_session` and `api_token` expiries in to `seconds` (1–60) from now,
|
|
1623
1625
|
shorten-only (`LEAST`, an eternal token gaining one), answering
|
|
@@ -1628,8 +1630,8 @@ are `src/test/auth/cell_crud_parity.db.test.ts`
|
|
|
1628
1630
|
`_testing_origin_check`. The Rust mirror is
|
|
1629
1631
|
`fuz_testing::create_testing_shorten_credential_expiry_action_spec`.
|
|
1630
1632
|
|
|
1631
|
-
Also in
|
|
1632
|
-
`_testing_action_manifest` (+ `create_testing_action_manifest_action(mounted)`):
|
|
1633
|
+
Also in `testing_reset_actions.ts` — but **not** bundled by
|
|
1634
|
+
`create_testing_actions` — `_testing_action_manifest` (+ `create_testing_action_manifest_action(mounted)`):
|
|
1633
1635
|
dumps the live RPC registry as a normalized `ActionManifest` for the
|
|
1634
1636
|
cross-impl manifest-parity gate (see §Cross-impl RPC-manifest parity). It must
|
|
1635
1637
|
enumerate _every_ mounted method, which `create_testing_actions` (one
|
|
@@ -5,7 +5,8 @@ import { create_standard_rpc_actions } from '../../auth/standard_rpc_actions.js'
|
|
|
5
5
|
import { create_all_cell_actions } from '../../auth/all_cell_actions.js';
|
|
6
6
|
import { create_actor_lookup_actions } from '../../auth/actor_lookup_actions.js';
|
|
7
7
|
import { create_actor_search_actions } from '../../auth/actor_search_actions.js';
|
|
8
|
-
import { create_testing_action_manifest_action, create_testing_actions,
|
|
8
|
+
import { create_testing_action_manifest_action, create_testing_actions, create_testing_shorten_credential_expiry_action } from './testing_reset_actions.js';
|
|
9
|
+
import { create_testing_origin_check_action } from './testing_origin_check.js';
|
|
9
10
|
import { test_cell_gated_create_authorize } from './test_cell_gated_create_authorize.js';
|
|
10
11
|
import { spine_roles, spine_session_options } from './default_spine_surface.js';
|
|
11
12
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import '../assert_dev_env.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { RpcPathCrossSuiteOptions } from './setup.js';
|
|
4
|
-
import { TestingOriginCheckOutput, type TestingOriginCheckInput } from './
|
|
4
|
+
import { TestingOriginCheckOutput, type TestingOriginCheckInput } from './testing_origin_check.js';
|
|
5
5
|
/** One expected refusal of a parse row. */
|
|
6
6
|
export declare const OriginConformanceError: z.ZodObject<{
|
|
7
7
|
index: z.ZodOptional<z.ZodNumber>;
|
|
@@ -1 +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,
|
|
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,2BAA2B,CAAC;AAEnC,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"}
|
|
@@ -26,7 +26,7 @@ import { z } from 'zod';
|
|
|
26
26
|
import { AllowedOriginsErrorKind } from '../../http/origin.js';
|
|
27
27
|
import { cross_rpc_call } from './cell_cross_helpers.js';
|
|
28
28
|
import { SPINE_RPC_PATH } from './spine_surface_constants.js';
|
|
29
|
-
import { TestingOriginCheckOutput, testing_origin_check_action_spec } from './
|
|
29
|
+
import { TestingOriginCheckOutput, testing_origin_check_action_spec } from './testing_origin_check.js';
|
|
30
30
|
/** One expected refusal of a parse row. */
|
|
31
31
|
export const OriginConformanceError = z.strictObject({
|
|
32
32
|
index: z.number().int().min(1).optional(),
|
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
import '../assert_dev_env.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* its eager `account_routes.ts` / `signup_routes.ts` imports — and through them
|
|
11
|
-
* `session_middleware` → `hono/cookie` — onto a backend-spawning consumer with
|
|
12
|
-
* no `hono` peer installed (a Rust-only spine consumer). Keeping these constants
|
|
13
|
-
* on this handler-free leaf lets such a consumer import the path without the
|
|
14
|
-
* peer. `default_spine_surface.ts` imports the ones it uses from here.
|
|
15
|
-
*
|
|
16
|
-
* The env-var names live here so both sides of each contract share one
|
|
17
|
-
* constant: the backend configs that set them (`default_backend_configs.ts`,
|
|
18
|
-
* `ts_spine_backend_config.ts`, `rust_spine_stub_backend_config.ts`) and the
|
|
19
|
-
* spawned TS spine binary that reads them, which imports this leaf rather than
|
|
20
|
-
* the config builders.
|
|
21
|
-
*
|
|
22
|
-
* @module
|
|
3
|
+
* Shared `auth` axis for every `_testing_*` action: keeper-only via the
|
|
4
|
+
* daemon-token credential, no acting actor. This is the entire structural
|
|
5
|
+
* fence on the backdoor surface (these actions run direct DB writes the
|
|
6
|
+
* production wire never exposes), so every `_testing_*` spec references this
|
|
7
|
+
* one const rather than re-declaring it — a single source of truth the gate test
|
|
8
|
+
* (`testing_actions_auth.test.ts`) pins. Mirrors the Rust `DAEMON_TOKEN_ONLY`
|
|
9
|
+
* / shared `AuthSpec` in `fuz_testing`.
|
|
23
10
|
*/
|
|
11
|
+
export declare const TESTING_ACTION_AUTH: {
|
|
12
|
+
readonly account: "required";
|
|
13
|
+
readonly actor: "none";
|
|
14
|
+
readonly credential_types: readonly ["daemon_token"];
|
|
15
|
+
};
|
|
24
16
|
/** RPC endpoint mount path — matches the binary's `/api/rpc`. */
|
|
25
17
|
export declare const SPINE_RPC_PATH = "/api/rpc";
|
|
26
18
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spine_surface_constants.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/spine_surface_constants.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"spine_surface_constants.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/spine_surface_constants.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA4B9B;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB;;;;CAIF,CAAC;AAE/B,iEAAiE;AACjE,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,4BAA4B,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,kBAAkB,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,MAAM,CAG1D,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,EAAE,GAAwD,CAAC;AAEjG;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAE3E;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,kCAAkC,CAAC;AAE7E;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC,uCAAuC,CAAC;AAEvF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6BAA6B,CAAC"}
|
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
import '../assert_dev_env.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* its eager `account_routes.ts` / `signup_routes.ts` imports — and through them
|
|
11
|
-
* `session_middleware` → `hono/cookie` — onto a backend-spawning consumer with
|
|
12
|
-
* no `hono` peer installed (a Rust-only spine consumer). Keeping these constants
|
|
13
|
-
* on this handler-free leaf lets such a consumer import the path without the
|
|
14
|
-
* peer. `default_spine_surface.ts` imports the ones it uses from here.
|
|
15
|
-
*
|
|
16
|
-
* The env-var names live here so both sides of each contract share one
|
|
17
|
-
* constant: the backend configs that set them (`default_backend_configs.ts`,
|
|
18
|
-
* `ts_spine_backend_config.ts`, `rust_spine_stub_backend_config.ts`) and the
|
|
19
|
-
* spawned TS spine binary that reads them, which imports this leaf rather than
|
|
20
|
-
* the config builders.
|
|
21
|
-
*
|
|
22
|
-
* @module
|
|
3
|
+
* Shared `auth` axis for every `_testing_*` action: keeper-only via the
|
|
4
|
+
* daemon-token credential, no acting actor. This is the entire structural
|
|
5
|
+
* fence on the backdoor surface (these actions run direct DB writes the
|
|
6
|
+
* production wire never exposes), so every `_testing_*` spec references this
|
|
7
|
+
* one const rather than re-declaring it — a single source of truth the gate test
|
|
8
|
+
* (`testing_actions_auth.test.ts`) pins. Mirrors the Rust `DAEMON_TOKEN_ONLY`
|
|
9
|
+
* / shared `AuthSpec` in `fuz_testing`.
|
|
23
10
|
*/
|
|
11
|
+
export const TESTING_ACTION_AUTH = {
|
|
12
|
+
account: 'required',
|
|
13
|
+
actor: 'none',
|
|
14
|
+
credential_types: ['daemon_token']
|
|
15
|
+
};
|
|
24
16
|
/** RPC endpoint mount path — matches the binary's `/api/rpc`. */
|
|
25
17
|
export const SPINE_RPC_PATH = '/api/rpc';
|
|
26
18
|
/**
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* `_testing_origin_check` — the testing seam behind the cross-impl origin
|
|
4
|
+
* conformance table (`origin_conformance.json`): its input and output schemas,
|
|
5
|
+
* the pure check it answers with, its spec, and the action builder.
|
|
6
|
+
*
|
|
7
|
+
* Split from `testing_reset_actions.ts`, whose other seams reach the
|
|
8
|
+
* in-process app server and through it the optional `hono` peer. This leaf is
|
|
9
|
+
* hono-free, so a consumer whose backend is a spawned Rust binary can run the
|
|
10
|
+
* conformance table without installing `hono`.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { type RpcAction } from '../../actions/action_rpc.js';
|
|
16
|
+
/** Input of `_testing_origin_check`. */
|
|
17
|
+
export declare const TestingOriginCheckInput: z.ZodObject<{
|
|
18
|
+
patterns: z.ZodString;
|
|
19
|
+
origin: z.ZodNullable<z.ZodString>;
|
|
20
|
+
}, z.core.$strict>;
|
|
21
|
+
export type TestingOriginCheckInput = z.infer<typeof TestingOriginCheckInput>;
|
|
22
|
+
/**
|
|
23
|
+
* Output of `_testing_origin_check`: the request-level answer when the list
|
|
24
|
+
* parses, else every refusal — `index` the 1-based entry position, absent for
|
|
25
|
+
* a list-level refusal.
|
|
26
|
+
*/
|
|
27
|
+
export declare const TestingOriginCheckOutput: z.ZodUnion<readonly [z.ZodObject<{
|
|
28
|
+
ok: z.ZodLiteral<true>;
|
|
29
|
+
allowed: z.ZodBoolean;
|
|
30
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
31
|
+
ok: z.ZodLiteral<false>;
|
|
32
|
+
errors: z.ZodArray<z.ZodObject<{
|
|
33
|
+
index: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
kind: z.ZodEnum<{
|
|
35
|
+
empty_entry: "empty_entry";
|
|
36
|
+
not_printable_ascii: "not_printable_ascii";
|
|
37
|
+
missing_scheme: "missing_scheme";
|
|
38
|
+
unsupported_scheme: "unsupported_scheme";
|
|
39
|
+
has_path: "has_path";
|
|
40
|
+
has_userinfo: "has_userinfo";
|
|
41
|
+
missing_host: "missing_host";
|
|
42
|
+
invalid_host_char: "invalid_host_char";
|
|
43
|
+
unbracketed_ipv6: "unbracketed_ipv6";
|
|
44
|
+
partial_wildcard: "partial_wildcard";
|
|
45
|
+
non_canonical_ipv4: "non_canonical_ipv4";
|
|
46
|
+
unclosed_ipv6: "unclosed_ipv6";
|
|
47
|
+
invalid_ipv6: "invalid_ipv6";
|
|
48
|
+
invalid_after_ipv6: "invalid_after_ipv6";
|
|
49
|
+
invalid_port: "invalid_port";
|
|
50
|
+
default_port: "default_port";
|
|
51
|
+
no_origins: "no_origins";
|
|
52
|
+
}>;
|
|
53
|
+
}, z.core.$strict>>;
|
|
54
|
+
}, z.core.$strict>]>;
|
|
55
|
+
export type TestingOriginCheckOutput = z.infer<typeof TestingOriginCheckOutput>;
|
|
56
|
+
/**
|
|
57
|
+
* Answer one `_testing_origin_check` input: parse `patterns` with
|
|
58
|
+
* `parse_allowed_origins`, then run the request-level check for one `Origin`
|
|
59
|
+
* carrying `origin` (`null` — no `Origin` — passes). The action handler and
|
|
60
|
+
* the conformance table's unit test both call this, so the table checks the
|
|
61
|
+
* same function the wire serves.
|
|
62
|
+
*
|
|
63
|
+
* @param input - the allowlist value and the `Origin` value
|
|
64
|
+
* @returns the answer the Rust twin returns for the same input
|
|
65
|
+
*/
|
|
66
|
+
export declare const run_testing_origin_check: (input: TestingOriginCheckInput) => TestingOriginCheckOutput;
|
|
67
|
+
/**
|
|
68
|
+
* `_testing_origin_check` — run the origin allowlist's parse and request
|
|
69
|
+
* check for one `{patterns, origin}` pair, so the shared conformance table
|
|
70
|
+
* (`origin_conformance.json`) checks each backend's grammar and matcher over
|
|
71
|
+
* the wire, row by row. Pure: no database, no state. The Rust mirror is
|
|
72
|
+
* `fuz_testing::create_testing_origin_check_action_spec`.
|
|
73
|
+
*
|
|
74
|
+
* Like `_testing_action_manifest`, it is **not** bundled by
|
|
75
|
+
* `create_testing_actions`: a consumer whose Rust binary doesn't mount the
|
|
76
|
+
* mirror would fail its action-manifest parity gate. The spine test binary
|
|
77
|
+
* appends it at the full-mount layer (`build_full_spine_rpc_actions`).
|
|
78
|
+
*
|
|
79
|
+
* `auth` gates on the daemon-token credential, matching `_testing_reset`.
|
|
80
|
+
*/
|
|
81
|
+
export declare const testing_origin_check_action_spec: {
|
|
82
|
+
readonly method: "_testing_origin_check";
|
|
83
|
+
readonly kind: "request_response";
|
|
84
|
+
readonly initiator: "frontend";
|
|
85
|
+
readonly auth: {
|
|
86
|
+
readonly account: "required";
|
|
87
|
+
readonly actor: "none";
|
|
88
|
+
readonly credential_types: readonly ["daemon_token"];
|
|
89
|
+
};
|
|
90
|
+
readonly side_effects: false;
|
|
91
|
+
readonly input: z.ZodObject<{
|
|
92
|
+
patterns: z.ZodString;
|
|
93
|
+
origin: z.ZodNullable<z.ZodString>;
|
|
94
|
+
}, z.core.$strict>;
|
|
95
|
+
readonly output: z.ZodUnion<readonly [z.ZodObject<{
|
|
96
|
+
ok: z.ZodLiteral<true>;
|
|
97
|
+
allowed: z.ZodBoolean;
|
|
98
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
99
|
+
ok: z.ZodLiteral<false>;
|
|
100
|
+
errors: z.ZodArray<z.ZodObject<{
|
|
101
|
+
index: z.ZodOptional<z.ZodNumber>;
|
|
102
|
+
kind: z.ZodEnum<{
|
|
103
|
+
empty_entry: "empty_entry";
|
|
104
|
+
not_printable_ascii: "not_printable_ascii";
|
|
105
|
+
missing_scheme: "missing_scheme";
|
|
106
|
+
unsupported_scheme: "unsupported_scheme";
|
|
107
|
+
has_path: "has_path";
|
|
108
|
+
has_userinfo: "has_userinfo";
|
|
109
|
+
missing_host: "missing_host";
|
|
110
|
+
invalid_host_char: "invalid_host_char";
|
|
111
|
+
unbracketed_ipv6: "unbracketed_ipv6";
|
|
112
|
+
partial_wildcard: "partial_wildcard";
|
|
113
|
+
non_canonical_ipv4: "non_canonical_ipv4";
|
|
114
|
+
unclosed_ipv6: "unclosed_ipv6";
|
|
115
|
+
invalid_ipv6: "invalid_ipv6";
|
|
116
|
+
invalid_after_ipv6: "invalid_after_ipv6";
|
|
117
|
+
invalid_port: "invalid_port";
|
|
118
|
+
default_port: "default_port";
|
|
119
|
+
no_origins: "no_origins";
|
|
120
|
+
}>;
|
|
121
|
+
}, z.core.$strict>>;
|
|
122
|
+
}, z.core.$strict>]>;
|
|
123
|
+
readonly async: true;
|
|
124
|
+
readonly description: string;
|
|
125
|
+
};
|
|
126
|
+
/** Build the standalone `_testing_origin_check` action (see the spec doc). */
|
|
127
|
+
export declare const create_testing_origin_check_action: () => RpcAction;
|
|
128
|
+
//# sourceMappingURL=testing_origin_check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing_origin_check.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_origin_check.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,6BAA6B,CAAC;AASzE,wCAAwC;AACxC,eAAO,MAAM,uBAAuB;;;kBAKlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAQnC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,GACpC,OAAO,uBAAuB,KAC5B,wBAcF,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYC,CAAC;AAE/C,8EAA8E;AAC9E,eAAO,MAAM,kCAAkC,QAAO,SACyC,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* `_testing_origin_check` — the testing seam behind the cross-impl origin
|
|
4
|
+
* conformance table (`origin_conformance.json`): its input and output schemas,
|
|
5
|
+
* the pure check it answers with, its spec, and the action builder.
|
|
6
|
+
*
|
|
7
|
+
* Split from `testing_reset_actions.ts`, whose other seams reach the
|
|
8
|
+
* in-process app server and through it the optional `hono` peer. This leaf is
|
|
9
|
+
* hono-free, so a consumer whose backend is a spawned Rust binary can run the
|
|
10
|
+
* conformance table without installing `hono`.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { rpc_action } from '../../actions/action_rpc.js';
|
|
16
|
+
import { AllowedOriginsErrorKind, parse_allowed_origins, should_allow_origin } from '../../http/origin.js';
|
|
17
|
+
import { TESTING_ACTION_AUTH } from './spine_surface_constants.js';
|
|
18
|
+
/** Input of `_testing_origin_check`. */
|
|
19
|
+
export const TestingOriginCheckInput = z.strictObject({
|
|
20
|
+
/** An allowlist value, as `FUZ_ALLOWED_ORIGINS` would carry it. */
|
|
21
|
+
patterns: z.string(),
|
|
22
|
+
/** One `Origin` header's value, or `null` for a request without one. */
|
|
23
|
+
origin: z.string().nullable()
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* Output of `_testing_origin_check`: the request-level answer when the list
|
|
27
|
+
* parses, else every refusal — `index` the 1-based entry position, absent for
|
|
28
|
+
* a list-level refusal.
|
|
29
|
+
*/
|
|
30
|
+
export const TestingOriginCheckOutput = z.union([
|
|
31
|
+
z.strictObject({ ok: z.literal(true), allowed: z.boolean() }),
|
|
32
|
+
z.strictObject({
|
|
33
|
+
ok: z.literal(false),
|
|
34
|
+
errors: z.array(z.strictObject({ index: z.number().int().min(1).optional(), kind: AllowedOriginsErrorKind }))
|
|
35
|
+
})
|
|
36
|
+
]);
|
|
37
|
+
/**
|
|
38
|
+
* Answer one `_testing_origin_check` input: parse `patterns` with
|
|
39
|
+
* `parse_allowed_origins`, then run the request-level check for one `Origin`
|
|
40
|
+
* carrying `origin` (`null` — no `Origin` — passes). The action handler and
|
|
41
|
+
* the conformance table's unit test both call this, so the table checks the
|
|
42
|
+
* same function the wire serves.
|
|
43
|
+
*
|
|
44
|
+
* @param input - the allowlist value and the `Origin` value
|
|
45
|
+
* @returns the answer the Rust twin returns for the same input
|
|
46
|
+
*/
|
|
47
|
+
export const run_testing_origin_check = (input) => {
|
|
48
|
+
const parsed = parse_allowed_origins(input.patterns);
|
|
49
|
+
if (!parsed.ok) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
errors: parsed.errors.map(({ index, kind }) => index === undefined ? { kind } : { index, kind })
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
ok: true,
|
|
57
|
+
allowed: input.origin === null || should_allow_origin(input.origin, parsed.origins)
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* `_testing_origin_check` — run the origin allowlist's parse and request
|
|
62
|
+
* check for one `{patterns, origin}` pair, so the shared conformance table
|
|
63
|
+
* (`origin_conformance.json`) checks each backend's grammar and matcher over
|
|
64
|
+
* the wire, row by row. Pure: no database, no state. The Rust mirror is
|
|
65
|
+
* `fuz_testing::create_testing_origin_check_action_spec`.
|
|
66
|
+
*
|
|
67
|
+
* Like `_testing_action_manifest`, it is **not** bundled by
|
|
68
|
+
* `create_testing_actions`: a consumer whose Rust binary doesn't mount the
|
|
69
|
+
* mirror would fail its action-manifest parity gate. The spine test binary
|
|
70
|
+
* appends it at the full-mount layer (`build_full_spine_rpc_actions`).
|
|
71
|
+
*
|
|
72
|
+
* `auth` gates on the daemon-token credential, matching `_testing_reset`.
|
|
73
|
+
*/
|
|
74
|
+
export const testing_origin_check_action_spec = {
|
|
75
|
+
method: '_testing_origin_check',
|
|
76
|
+
kind: 'request_response',
|
|
77
|
+
initiator: 'frontend',
|
|
78
|
+
auth: TESTING_ACTION_AUTH,
|
|
79
|
+
side_effects: false,
|
|
80
|
+
input: TestingOriginCheckInput,
|
|
81
|
+
output: TestingOriginCheckOutput,
|
|
82
|
+
async: true,
|
|
83
|
+
description: "Test-binary only — answer the origin allowlist's parse and request check for one " +
|
|
84
|
+
'{patterns, origin} pair, for the cross-impl origin conformance table.'
|
|
85
|
+
};
|
|
86
|
+
/** Build the standalone `_testing_origin_check` action (see the spec doc). */
|
|
87
|
+
export const create_testing_origin_check_action = () => rpc_action(testing_origin_check_action_spec, async (input) => run_testing_origin_check(input));
|
|
@@ -15,17 +15,17 @@ import '../assert_dev_env.js';
|
|
|
15
15
|
* of notifications onto the caller's own WebSocket connection, to push its
|
|
16
16
|
* outbound queue past its byte budget).
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* Two further daemon-token actions live here but are **not** bundled by
|
|
19
19
|
* `create_testing_actions`, and are appended at the full-mount layer
|
|
20
20
|
* (`build_full_spine_rpc_actions`) instead: **`_testing_action_manifest`**
|
|
21
21
|
* (dump the live RPC registry for cross-impl method-set + auth-shape parity —
|
|
22
22
|
* it must enumerate *every* mounted method, so it goes where the complete list
|
|
23
|
-
* exists)
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
23
|
+
* exists) and **`_testing_shorten_credential_expiry`** (pull an account's
|
|
24
|
+
* credential expiries in to seconds from now, shorten-only, for the
|
|
25
|
+
* credential-deadline cases) — the latter kept out of the bundle so a consumer
|
|
26
|
+
* whose Rust binary doesn't mount its mirror keeps a green manifest gate.
|
|
27
|
+
* `_testing_origin_check`, mounted the same way, lives in the hono-free
|
|
28
|
+
* `testing_origin_check.ts`.
|
|
29
29
|
*
|
|
30
30
|
* `_testing_reset` — full DB wipe + keeper re-seed + optional
|
|
31
31
|
* secondary-account seeding. The
|
|
@@ -472,118 +472,6 @@ export declare const testing_migration_tracker_action_spec: {
|
|
|
472
472
|
* `create_testing_actions`; mount directly for in-process use.
|
|
473
473
|
*/
|
|
474
474
|
export declare const create_testing_migration_tracker_action: () => RpcAction;
|
|
475
|
-
/** Input of `_testing_origin_check`. */
|
|
476
|
-
export declare const TestingOriginCheckInput: z.ZodObject<{
|
|
477
|
-
patterns: z.ZodString;
|
|
478
|
-
origin: z.ZodNullable<z.ZodString>;
|
|
479
|
-
}, z.core.$strict>;
|
|
480
|
-
export type TestingOriginCheckInput = z.infer<typeof TestingOriginCheckInput>;
|
|
481
|
-
/**
|
|
482
|
-
* Output of `_testing_origin_check`: the request-level answer when the list
|
|
483
|
-
* parses, else every refusal — `index` the 1-based entry position, absent for
|
|
484
|
-
* a list-level refusal.
|
|
485
|
-
*/
|
|
486
|
-
export declare const TestingOriginCheckOutput: z.ZodUnion<readonly [z.ZodObject<{
|
|
487
|
-
ok: z.ZodLiteral<true>;
|
|
488
|
-
allowed: z.ZodBoolean;
|
|
489
|
-
}, z.core.$strict>, z.ZodObject<{
|
|
490
|
-
ok: z.ZodLiteral<false>;
|
|
491
|
-
errors: z.ZodArray<z.ZodObject<{
|
|
492
|
-
index: z.ZodOptional<z.ZodNumber>;
|
|
493
|
-
kind: z.ZodEnum<{
|
|
494
|
-
empty_entry: "empty_entry";
|
|
495
|
-
not_printable_ascii: "not_printable_ascii";
|
|
496
|
-
missing_scheme: "missing_scheme";
|
|
497
|
-
unsupported_scheme: "unsupported_scheme";
|
|
498
|
-
has_path: "has_path";
|
|
499
|
-
has_userinfo: "has_userinfo";
|
|
500
|
-
missing_host: "missing_host";
|
|
501
|
-
invalid_host_char: "invalid_host_char";
|
|
502
|
-
unbracketed_ipv6: "unbracketed_ipv6";
|
|
503
|
-
partial_wildcard: "partial_wildcard";
|
|
504
|
-
non_canonical_ipv4: "non_canonical_ipv4";
|
|
505
|
-
unclosed_ipv6: "unclosed_ipv6";
|
|
506
|
-
invalid_ipv6: "invalid_ipv6";
|
|
507
|
-
invalid_after_ipv6: "invalid_after_ipv6";
|
|
508
|
-
invalid_port: "invalid_port";
|
|
509
|
-
default_port: "default_port";
|
|
510
|
-
no_origins: "no_origins";
|
|
511
|
-
}>;
|
|
512
|
-
}, z.core.$strict>>;
|
|
513
|
-
}, z.core.$strict>]>;
|
|
514
|
-
export type TestingOriginCheckOutput = z.infer<typeof TestingOriginCheckOutput>;
|
|
515
|
-
/**
|
|
516
|
-
* Answer one `_testing_origin_check` input: parse `patterns` with
|
|
517
|
-
* `parse_allowed_origins`, then run the request-level check for one `Origin`
|
|
518
|
-
* carrying `origin` (`null` — no `Origin` — passes). The action handler and
|
|
519
|
-
* the conformance table's unit test both call this, so the table checks the
|
|
520
|
-
* same function the wire serves.
|
|
521
|
-
*
|
|
522
|
-
* @param input - the allowlist value and the `Origin` value
|
|
523
|
-
* @returns the answer the Rust twin returns for the same input
|
|
524
|
-
*/
|
|
525
|
-
export declare const run_testing_origin_check: (input: TestingOriginCheckInput) => TestingOriginCheckOutput;
|
|
526
|
-
/**
|
|
527
|
-
* `_testing_origin_check` — run the origin allowlist's parse and request
|
|
528
|
-
* check for one `{patterns, origin}` pair, so the shared conformance table
|
|
529
|
-
* (`origin_conformance.json`) checks each backend's grammar and matcher over
|
|
530
|
-
* the wire, row by row. Pure: no database, no state. The Rust mirror is
|
|
531
|
-
* `fuz_testing::create_testing_origin_check_action_spec`.
|
|
532
|
-
*
|
|
533
|
-
* Like `_testing_action_manifest`, it is **not** bundled by
|
|
534
|
-
* `create_testing_actions`: a consumer whose Rust binary doesn't mount the
|
|
535
|
-
* mirror would fail its action-manifest parity gate. The spine test binary
|
|
536
|
-
* appends it at the full-mount layer (`build_full_spine_rpc_actions`).
|
|
537
|
-
*
|
|
538
|
-
* `auth` gates on the daemon-token credential, matching `_testing_reset`.
|
|
539
|
-
*/
|
|
540
|
-
export declare const testing_origin_check_action_spec: {
|
|
541
|
-
readonly method: "_testing_origin_check";
|
|
542
|
-
readonly kind: "request_response";
|
|
543
|
-
readonly initiator: "frontend";
|
|
544
|
-
readonly auth: {
|
|
545
|
-
readonly account: "required";
|
|
546
|
-
readonly actor: "none";
|
|
547
|
-
readonly credential_types: readonly ["daemon_token"];
|
|
548
|
-
};
|
|
549
|
-
readonly side_effects: false;
|
|
550
|
-
readonly input: z.ZodObject<{
|
|
551
|
-
patterns: z.ZodString;
|
|
552
|
-
origin: z.ZodNullable<z.ZodString>;
|
|
553
|
-
}, z.core.$strict>;
|
|
554
|
-
readonly output: z.ZodUnion<readonly [z.ZodObject<{
|
|
555
|
-
ok: z.ZodLiteral<true>;
|
|
556
|
-
allowed: z.ZodBoolean;
|
|
557
|
-
}, z.core.$strict>, z.ZodObject<{
|
|
558
|
-
ok: z.ZodLiteral<false>;
|
|
559
|
-
errors: z.ZodArray<z.ZodObject<{
|
|
560
|
-
index: z.ZodOptional<z.ZodNumber>;
|
|
561
|
-
kind: z.ZodEnum<{
|
|
562
|
-
empty_entry: "empty_entry";
|
|
563
|
-
not_printable_ascii: "not_printable_ascii";
|
|
564
|
-
missing_scheme: "missing_scheme";
|
|
565
|
-
unsupported_scheme: "unsupported_scheme";
|
|
566
|
-
has_path: "has_path";
|
|
567
|
-
has_userinfo: "has_userinfo";
|
|
568
|
-
missing_host: "missing_host";
|
|
569
|
-
invalid_host_char: "invalid_host_char";
|
|
570
|
-
unbracketed_ipv6: "unbracketed_ipv6";
|
|
571
|
-
partial_wildcard: "partial_wildcard";
|
|
572
|
-
non_canonical_ipv4: "non_canonical_ipv4";
|
|
573
|
-
unclosed_ipv6: "unclosed_ipv6";
|
|
574
|
-
invalid_ipv6: "invalid_ipv6";
|
|
575
|
-
invalid_after_ipv6: "invalid_after_ipv6";
|
|
576
|
-
invalid_port: "invalid_port";
|
|
577
|
-
default_port: "default_port";
|
|
578
|
-
no_origins: "no_origins";
|
|
579
|
-
}>;
|
|
580
|
-
}, z.core.$strict>>;
|
|
581
|
-
}, z.core.$strict>]>;
|
|
582
|
-
readonly async: true;
|
|
583
|
-
readonly description: string;
|
|
584
|
-
};
|
|
585
|
-
/** Build the standalone `_testing_origin_check` action (see the spec doc). */
|
|
586
|
-
export declare const create_testing_origin_check_action: () => RpcAction;
|
|
587
475
|
/** The shortest expiry `_testing_shorten_credential_expiry` sets, in seconds from now. */
|
|
588
476
|
export declare const TESTING_SHORTEN_CREDENTIAL_EXPIRY_MIN_SECONDS = 1;
|
|
589
477
|
/**
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2EG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,17 +15,17 @@ import '../assert_dev_env.js';
|
|
|
15
15
|
* of notifications onto the caller's own WebSocket connection, to push its
|
|
16
16
|
* outbound queue past its byte budget).
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* Two further daemon-token actions live here but are **not** bundled by
|
|
19
19
|
* `create_testing_actions`, and are appended at the full-mount layer
|
|
20
20
|
* (`build_full_spine_rpc_actions`) instead: **`_testing_action_manifest`**
|
|
21
21
|
* (dump the live RPC registry for cross-impl method-set + auth-shape parity —
|
|
22
22
|
* it must enumerate *every* mounted method, so it goes where the complete list
|
|
23
|
-
* exists)
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
23
|
+
* exists) and **`_testing_shorten_credential_expiry`** (pull an account's
|
|
24
|
+
* credential expiries in to seconds from now, shorten-only, for the
|
|
25
|
+
* credential-deadline cases) — the latter kept out of the bundle so a consumer
|
|
26
|
+
* whose Rust binary doesn't mount its mirror keeps a green manifest gate.
|
|
27
|
+
* `_testing_origin_check`, mounted the same way, lives in the hono-free
|
|
28
|
+
* `testing_origin_check.ts`.
|
|
29
29
|
*
|
|
30
30
|
* `_testing_reset` — full DB wipe + keeper re-seed + optional
|
|
31
31
|
* secondary-account seeding. The
|
|
@@ -89,21 +89,7 @@ import { ActionManifest, build_action_manifest } from './action_manifest.js';
|
|
|
89
89
|
import { query_create_actor } from '../../auth/account_queries.js';
|
|
90
90
|
import { create_test_account_with_credentials, mint_test_session } from '../app_server.js';
|
|
91
91
|
import { DEFAULT_TEST_PASSWORD } from '../test_credentials.js';
|
|
92
|
-
import {
|
|
93
|
-
/**
|
|
94
|
-
* Shared `auth` axis for every `_testing_*` action: keeper-only via the
|
|
95
|
-
* daemon-token credential, no acting actor. This is the entire structural
|
|
96
|
-
* fence on the backdoor surface (these actions run direct DB writes the
|
|
97
|
-
* production wire never exposes), so every `_testing_*` spec references this
|
|
98
|
-
* one const rather than re-declaring it — a single source of truth the gate test
|
|
99
|
-
* (`testing_actions_auth.test.ts`) pins. Mirrors the Rust `DAEMON_TOKEN_ONLY`
|
|
100
|
-
* / shared `AuthSpec` in `fuz_testing`.
|
|
101
|
-
*/
|
|
102
|
-
const TESTING_ACTION_AUTH = {
|
|
103
|
-
account: 'required',
|
|
104
|
-
actor: 'none',
|
|
105
|
-
credential_types: ['daemon_token']
|
|
106
|
-
};
|
|
92
|
+
import { TESTING_ACTION_AUTH } from './spine_surface_constants.js';
|
|
107
93
|
/** Output shape for an individual seeded account (keeper or extra). */
|
|
108
94
|
const SeededAccountShape = z.strictObject({
|
|
109
95
|
account: z.strictObject({ id: Uuid, username: z.string() }),
|
|
@@ -459,76 +445,6 @@ export const testing_migration_tracker_action_spec = {
|
|
|
459
445
|
* `create_testing_actions`; mount directly for in-process use.
|
|
460
446
|
*/
|
|
461
447
|
export const create_testing_migration_tracker_action = () => rpc_action(testing_migration_tracker_action_spec, async (_input, ctx) => query_migration_tracker(ctx.db));
|
|
462
|
-
/** Input of `_testing_origin_check`. */
|
|
463
|
-
export const TestingOriginCheckInput = z.strictObject({
|
|
464
|
-
/** An allowlist value, as `FUZ_ALLOWED_ORIGINS` would carry it. */
|
|
465
|
-
patterns: z.string(),
|
|
466
|
-
/** One `Origin` header's value, or `null` for a request without one. */
|
|
467
|
-
origin: z.string().nullable()
|
|
468
|
-
});
|
|
469
|
-
/**
|
|
470
|
-
* Output of `_testing_origin_check`: the request-level answer when the list
|
|
471
|
-
* parses, else every refusal — `index` the 1-based entry position, absent for
|
|
472
|
-
* a list-level refusal.
|
|
473
|
-
*/
|
|
474
|
-
export const TestingOriginCheckOutput = z.union([
|
|
475
|
-
z.strictObject({ ok: z.literal(true), allowed: z.boolean() }),
|
|
476
|
-
z.strictObject({
|
|
477
|
-
ok: z.literal(false),
|
|
478
|
-
errors: z.array(z.strictObject({ index: z.number().int().min(1).optional(), kind: AllowedOriginsErrorKind }))
|
|
479
|
-
})
|
|
480
|
-
]);
|
|
481
|
-
/**
|
|
482
|
-
* Answer one `_testing_origin_check` input: parse `patterns` with
|
|
483
|
-
* `parse_allowed_origins`, then run the request-level check for one `Origin`
|
|
484
|
-
* carrying `origin` (`null` — no `Origin` — passes). The action handler and
|
|
485
|
-
* the conformance table's unit test both call this, so the table checks the
|
|
486
|
-
* same function the wire serves.
|
|
487
|
-
*
|
|
488
|
-
* @param input - the allowlist value and the `Origin` value
|
|
489
|
-
* @returns the answer the Rust twin returns for the same input
|
|
490
|
-
*/
|
|
491
|
-
export const run_testing_origin_check = (input) => {
|
|
492
|
-
const parsed = parse_allowed_origins(input.patterns);
|
|
493
|
-
if (!parsed.ok) {
|
|
494
|
-
return {
|
|
495
|
-
ok: false,
|
|
496
|
-
errors: parsed.errors.map(({ index, kind }) => index === undefined ? { kind } : { index, kind })
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
return {
|
|
500
|
-
ok: true,
|
|
501
|
-
allowed: input.origin === null || should_allow_origin(input.origin, parsed.origins)
|
|
502
|
-
};
|
|
503
|
-
};
|
|
504
|
-
/**
|
|
505
|
-
* `_testing_origin_check` — run the origin allowlist's parse and request
|
|
506
|
-
* check for one `{patterns, origin}` pair, so the shared conformance table
|
|
507
|
-
* (`origin_conformance.json`) checks each backend's grammar and matcher over
|
|
508
|
-
* the wire, row by row. Pure: no database, no state. The Rust mirror is
|
|
509
|
-
* `fuz_testing::create_testing_origin_check_action_spec`.
|
|
510
|
-
*
|
|
511
|
-
* Like `_testing_action_manifest`, it is **not** bundled by
|
|
512
|
-
* `create_testing_actions`: a consumer whose Rust binary doesn't mount the
|
|
513
|
-
* mirror would fail its action-manifest parity gate. The spine test binary
|
|
514
|
-
* appends it at the full-mount layer (`build_full_spine_rpc_actions`).
|
|
515
|
-
*
|
|
516
|
-
* `auth` gates on the daemon-token credential, matching `_testing_reset`.
|
|
517
|
-
*/
|
|
518
|
-
export const testing_origin_check_action_spec = {
|
|
519
|
-
method: '_testing_origin_check',
|
|
520
|
-
kind: 'request_response',
|
|
521
|
-
initiator: 'frontend',
|
|
522
|
-
auth: TESTING_ACTION_AUTH,
|
|
523
|
-
side_effects: false,
|
|
524
|
-
input: TestingOriginCheckInput,
|
|
525
|
-
output: TestingOriginCheckOutput,
|
|
526
|
-
async: true,
|
|
527
|
-
description: "Test-binary only — answer the origin allowlist's parse and request check for one " +
|
|
528
|
-
'{patterns, origin} pair, for the cross-impl origin conformance table.'
|
|
529
|
-
};
|
|
530
|
-
/** Build the standalone `_testing_origin_check` action (see the spec doc). */
|
|
531
|
-
export const create_testing_origin_check_action = () => rpc_action(testing_origin_check_action_spec, async (input) => run_testing_origin_check(input));
|
|
532
448
|
/** The shortest expiry `_testing_shorten_credential_expiry` sets, in seconds from now. */
|
|
533
449
|
export const TESTING_SHORTEN_CREDENTIAL_EXPIRY_MIN_SECONDS = 1;
|
|
534
450
|
/**
|