@fuzdev/fuz_app 0.143.0 → 0.145.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/auth/CLAUDE.md +8 -0
- package/dist/auth/cell_action_specs.d.ts +13 -0
- package/dist/auth/cell_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_action_specs.js +13 -0
- package/dist/auth/cell_actions.d.ts +7 -0
- package/dist/auth/cell_actions.d.ts.map +1 -1
- package/dist/auth/cell_actions.js +30 -0
- package/dist/auth/cell_ref_admission.d.ts +51 -0
- package/dist/auth/cell_ref_admission.d.ts.map +1 -0
- package/dist/auth/cell_ref_admission.js +69 -0
- package/dist/auth/deps.d.ts +6 -3
- package/dist/auth/deps.d.ts.map +1 -1
- package/dist/db/CLAUDE.md +40 -23
- package/dist/db/cell_ddl.d.ts +3 -2
- package/dist/db/cell_ddl.d.ts.map +1 -1
- package/dist/db/cell_ddl.js +3 -2
- package/dist/db/cell_queries.d.ts +31 -6
- package/dist/db/cell_queries.d.ts.map +1 -1
- package/dist/db/cell_queries.js +45 -18
- package/dist/db/fact_ddl.d.ts +30 -4
- package/dist/db/fact_ddl.d.ts.map +1 -1
- package/dist/db/fact_ddl.js +44 -4
- package/dist/db/fact_holder_queries.d.ts +70 -0
- package/dist/db/fact_holder_queries.d.ts.map +1 -0
- package/dist/db/fact_holder_queries.js +79 -0
- package/dist/db/fact_queries.d.ts +19 -14
- package/dist/db/fact_queries.d.ts.map +1 -1
- package/dist/db/fact_queries.js +31 -10
- package/dist/db/fact_store.d.ts +65 -9
- package/dist/db/fact_store.d.ts.map +1 -1
- package/dist/db/fact_store.js +49 -20
- package/dist/server/fact_security_headers.d.ts +54 -0
- package/dist/server/fact_security_headers.d.ts.map +1 -0
- package/dist/server/fact_security_headers.js +53 -0
- package/dist/server/serve_fact_route.d.ts +33 -7
- package/dist/server/serve_fact_route.d.ts.map +1 -1
- package/dist/server/serve_fact_route.js +36 -32
- package/dist/server/x_accel.d.ts +106 -30
- package/dist/server/x_accel.d.ts.map +1 -1
- package/dist/server/x_accel.js +533 -86
- package/dist/testing/CLAUDE.md +25 -1
- package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_crud.js +6 -3
- package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_gated_create.js +25 -16
- package/dist/testing/cross_backend/cell_ref_admission.d.ts +4 -0
- package/dist/testing/cross_backend/cell_ref_admission.d.ts.map +1 -0
- package/dist/testing/cross_backend/cell_ref_admission.js +268 -0
- package/dist/testing/cross_backend/expected_schema.json +66 -10
- package/dist/testing/cross_backend/fact_serving.d.ts +19 -1
- package/dist/testing/cross_backend/fact_serving.d.ts.map +1 -1
- package/dist/testing/cross_backend/fact_serving.js +31 -9
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +6 -2
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +13 -3
- package/package.json +3 -3
package/dist/server/x_accel.d.ts
CHANGED
|
@@ -5,37 +5,112 @@
|
|
|
5
5
|
* nginx location being `internal;` — only the authz'd handler's redirect (an
|
|
6
6
|
* internal subrequest) may reach it. A *public* facts location would serve any
|
|
7
7
|
* fact's bytes to anyone who guesses the `<shard>/<rest>` path, bypassing every
|
|
8
|
-
* cell-visibility check. `
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* cell-visibility check. A location with its own `add_header` also stops the
|
|
9
|
+
* server-level headers from applying, so the facts location must carry the fact
|
|
10
|
+
* hardening headers itself (`fact_security_header_directives` in
|
|
11
|
+
* `server/fact_security_headers.ts`).
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* `XAccelConfig` makes these assertions structural: a consumer can only obtain
|
|
14
|
+
* the redirect prefix by building an `XAccelConfig`, which runs
|
|
15
|
+
* `validate_facts_internal_location` and throws **loudly** on any violation — it
|
|
16
|
+
* cannot silently fall closed.
|
|
17
|
+
*
|
|
18
|
+
* ## Rules
|
|
19
|
+
*
|
|
20
|
+
* The config is tokenized as nginx reads it (`ngx_conf_read_token`): whitespace
|
|
21
|
+
* is exactly space, tab, CR and LF; an unquoted word ends only at those or at
|
|
22
|
+
* `;` / `{` (a `}` inside a word is part of it, and so is a `{` straight after
|
|
23
|
+
* `$`); `#` starts a comment only where a token would start; quoted strings are
|
|
24
|
+
* one word, with nginx's backslash escapes. It is then parsed into nested
|
|
25
|
+
* blocks, and every `location` at any depth, in every `server` block, is
|
|
26
|
+
* classified against the prefix (trailing slashes ignored). A location *serves
|
|
27
|
+
* the prefix* when it is a prefix-type location (no modifier, or `^~`) whose
|
|
28
|
+
* path is the prefix or below it. Each one must:
|
|
29
|
+
*
|
|
30
|
+
* - use `^~` — a plain prefix location is refused;
|
|
31
|
+
* - be a direct child of a `server` block — one nested in another location is
|
|
32
|
+
* refused;
|
|
33
|
+
* - carry, as top-level directives of its own body, an exact `internal;` and
|
|
34
|
+
* each `fact_security_header_directives` line (token-equal: whitespace and
|
|
35
|
+
* quoting are free, the words are not);
|
|
36
|
+
* - hold only simple directives — any nested block (`location`, `if`,
|
|
37
|
+
* `limit_except`, …) is refused, and so is `include`, since included files
|
|
38
|
+
* are not followed.
|
|
39
|
+
*
|
|
40
|
+
* The first two rules are what keep regex locations out: nginx never evaluates
|
|
41
|
+
* regex locations for a path whose longest prefix match is a `^~` location at
|
|
42
|
+
* server level, and because every prefix location at or below the prefix must
|
|
43
|
+
* be such a location, the longest match for any redirected path always is. (A
|
|
44
|
+
* longer plain location below the prefix can't exist — the `^~` rule refuses
|
|
45
|
+
* it.)
|
|
46
|
+
*
|
|
47
|
+
* The prefix may appear only in its own location lines and their bodies:
|
|
48
|
+
* `internal;` admits every internal redirect and subrequest, so any other
|
|
49
|
+
* directive with a word naming the prefix (trailing slash trimmed, so
|
|
50
|
+
* `/_facts$uri` counts) is refused, in any block at any depth — a `rewrite`,
|
|
51
|
+
* `try_files`, `error_page`, `index`, `add_before_body`, or a `set` / `map`
|
|
52
|
+
* value that a redirect later reads. The only exemptions are each `location`'s
|
|
53
|
+
* own modifier and path words and the bodies of the locations serving the
|
|
54
|
+
* prefix.
|
|
55
|
+
*
|
|
56
|
+
* Also refused: an `=` location on the prefix or below it (it can't serve the
|
|
57
|
+
* nested paths the redirect emits); a regex location (`~` / `~*`) whose pattern
|
|
58
|
+
* spells out the prefix (after unescaping `\/`, ASCII case-folded for `~*`) —
|
|
59
|
+
* dead under the rules above, refused for the clearer message; and a config
|
|
60
|
+
* with no location serving the prefix. `include` at server level is allowed,
|
|
61
|
+
* but its file is not read — keep facts-related locations out of included
|
|
62
|
+
* files.
|
|
63
|
+
*
|
|
64
|
+
* The threat model is operator mistakes, not an adversarial config author: the
|
|
65
|
+
* prefix check is textual, so a value assembled from pieces (`/_fac$1`) evades
|
|
66
|
+
* it. Beyond the config text:
|
|
67
|
+
*
|
|
68
|
+
* - The validator checks URL paths only — another `root` or `alias` that maps
|
|
69
|
+
* onto the facts directory would serve its files publicly, so keep the facts
|
|
70
|
+
* directory outside every other location's root.
|
|
71
|
+
* - nginx honours `X-Accel-Redirect` from any proxied upstream (`proxy_pass`,
|
|
72
|
+
* `fastcgi_pass`, `uwsgi_pass`, `scgi_pass`, `grpc_pass`), so every upstream in
|
|
73
|
+
* the server is trusted to point into the prefix; an untrusted one needs
|
|
74
|
+
* `proxy_ignore_headers X-Accel-Redirect;` (or the `fastcgi_` / `uwsgi_` /
|
|
75
|
+
* `scgi_` equivalent).
|
|
76
|
+
* - Module code can redirect internally too (ssi `include virtual`, njs
|
|
77
|
+
* `internalRedirect`, perl, echo), so run trusted modules and content only.
|
|
78
|
+
*
|
|
79
|
+
* The Rust twin is `fuz_fact_serving`'s `nginx.rs`, held to the same rules and
|
|
80
|
+
* the same fixture corpus.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* const x_accel = create_x_accel_config(
|
|
85
|
+
* '/_facts/',
|
|
86
|
+
* `server {
|
|
87
|
+
* location ^~ /_facts/ {
|
|
88
|
+
* internal;
|
|
89
|
+
* alias /srv/app/facts/;
|
|
90
|
+
* ${fact_security_header_directives().join('\n\t\t')}
|
|
91
|
+
* }
|
|
92
|
+
* }`
|
|
93
|
+
* );
|
|
94
|
+
* ```
|
|
17
95
|
*
|
|
18
96
|
* @module
|
|
19
97
|
*/
|
|
20
98
|
import { z } from 'zod';
|
|
21
99
|
/** Result of the facts-location check. */
|
|
22
100
|
export interface NginxFactsValidation {
|
|
23
|
-
/** `true` when
|
|
101
|
+
/** `true` when every rule passes. */
|
|
24
102
|
ok: boolean;
|
|
25
|
-
/** Fatal issues
|
|
103
|
+
/** Fatal issues, each naming the offending location. */
|
|
26
104
|
errors: Array<string>;
|
|
27
105
|
}
|
|
28
106
|
/**
|
|
29
|
-
* Assert the nginx
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* `/_facts/`). Returns a fatal error when no matching `location` block exists,
|
|
33
|
-
* or when the matching block is not marked `internal;` — either is a public
|
|
34
|
-
* facts location that bypasses cell visibility.
|
|
107
|
+
* Assert the nginx config serves the X-Accel facts prefix only from `internal;`
|
|
108
|
+
* locations carrying the fact hardening headers. See the module docs for the
|
|
109
|
+
* rules; every violation is collected, so one call reports them all.
|
|
35
110
|
*
|
|
36
|
-
* @param config - the nginx config
|
|
37
|
-
* @param facts_location - the facts location path the redirect prefix points at
|
|
38
|
-
* @returns `{ok, errors}` — `ok` is `true` only when
|
|
111
|
+
* @param config - the nginx config string to check
|
|
112
|
+
* @param facts_location - the facts location path the redirect prefix points at (e.g. `/_facts/`)
|
|
113
|
+
* @returns `{ok, errors}` — `ok` is `true` only when every rule passes
|
|
39
114
|
*/
|
|
40
115
|
export declare const validate_facts_internal_location: (config: string, facts_location: string) => NginxFactsValidation;
|
|
41
116
|
/**
|
|
@@ -44,10 +119,11 @@ export declare const validate_facts_internal_location: (config: string, facts_lo
|
|
|
44
119
|
*
|
|
45
120
|
* The redirect prefix can be obtained **only** by passing the nginx config
|
|
46
121
|
* through `validate_facts_internal_location` (via `create_x_accel_config`), so
|
|
47
|
-
* X-Accel serving is impossible to enable without proving
|
|
48
|
-
* `internal;`
|
|
49
|
-
* cell-visibility check. A
|
|
50
|
-
*
|
|
122
|
+
* X-Accel serving is impossible to enable without proving at boot that the
|
|
123
|
+
* facts location is `internal;` and carries the fact hardening headers — a
|
|
124
|
+
* public facts location would bypass every cell-visibility check. A
|
|
125
|
+
* Zod-branded type: the brand can't be forged without an explicit cast, so the
|
|
126
|
+
* factory is the only ordinary construction path.
|
|
51
127
|
*/
|
|
52
128
|
export declare const XAccelConfig: z.core.$ZodBranded<z.ZodObject<{
|
|
53
129
|
redirect_prefix: z.ZodString;
|
|
@@ -63,18 +139,18 @@ export declare class XAccelConfigError extends Error {
|
|
|
63
139
|
constructor(errors: Array<string>);
|
|
64
140
|
}
|
|
65
141
|
/**
|
|
66
|
-
* Build a validated `XAccelConfig`, asserting the nginx
|
|
67
|
-
* `redirect_prefix`
|
|
142
|
+
* Build a validated `XAccelConfig`, asserting the nginx config serves
|
|
143
|
+
* `redirect_prefix` only from safe locations (the module-level rules).
|
|
68
144
|
*
|
|
69
145
|
* The make-impossible-states gate: serving can only emit `X-Accel-Redirect`
|
|
70
|
-
* into a location proven `internal;` at boot.
|
|
146
|
+
* into a location proven `internal;` and header-carrying at boot.
|
|
71
147
|
*
|
|
72
148
|
* @param redirect_prefix - the X-Accel redirect prefix (e.g. `/_facts/`)
|
|
73
|
-
* @param nginx_config - the nginx config
|
|
149
|
+
* @param nginx_config - the nginx config string to validate against
|
|
74
150
|
* @returns the validated `XAccelConfig` carrying `redirect_prefix`
|
|
75
|
-
* @throws `XAccelConfigError`
|
|
76
|
-
* `
|
|
77
|
-
*
|
|
151
|
+
* @throws `XAccelConfigError` carrying every violation
|
|
152
|
+
* `validate_facts_internal_location` finds — a missing, public, header-less,
|
|
153
|
+
* exact-match, or regex-shadowed facts location.
|
|
78
154
|
*/
|
|
79
155
|
export declare const create_x_accel_config: (redirect_prefix: string, nginx_config: string) => XAccelConfig;
|
|
80
156
|
//# sourceMappingURL=x_accel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x_accel.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/x_accel.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"x_accel.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/x_accel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,0CAA0C;AAC1C,MAAM,WAAW,oBAAoB;IACpC,qCAAqC;IACrC,EAAE,EAAE,OAAO,CAAC;IACZ,wDAAwD;IACxD,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,gCAAgC,GAC5C,QAAQ,MAAM,EACd,gBAAgB,MAAM,KACpB,oBAYF,CAAC;AAsHF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY;;0CAKF,CAAC;AACxB,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC3C,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;gBACnB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;CAKjC;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,GACjC,iBAAiB,MAAM,EACvB,cAAc,MAAM,KAClB,YAMF,CAAC"}
|