@byollm/conformance 0.1.0-alpha.0 → 0.1.0-alpha.10

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/README.md CHANGED
@@ -1,15 +1,17 @@
1
1
  > [!WARNING]
2
- > **Alpha 0.1.0 — under active development. Don't use this yet.**
2
+ > **Alpha (`0.1.0-alpha.10`) — under active development. Don't use this yet.**
3
+ >
4
+ > Install it deliberately: `npm install @byollm/conformance@alpha`.
3
5
  >
4
- > > Install it deliberately: `npm install @byollm/conformance@alpha`.
5
6
  > The protocol is v0 and **will** change without a deprecation path, this has
6
7
  > never run outside its own test suite, and nothing here has production miles.
7
8
  > Read it, take the ideas, tell us what's wrong — but don't put it in front of
8
9
  > your users.
9
10
  >
10
- > npm assigns `latest` on a first publish and won't let it be removed, so the
11
- > alpha is also `latest`; the version is marked deprecated so every install
12
- > says so out loud.
11
+ > npm assigns `latest` on a first publish and won't let it be removed, so a
12
+ > bare install resolves here too. This notice is the only guard deliberately
13
+ > not an npm deprecation, which would read as *abandoned* rather than *early*.
14
+ > Ask for `@alpha` explicitly so your lockfile records that you meant to.
13
15
 
14
16
  # `@byollm/conformance`
15
17
 
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ auditDeployment,
4
+ formatPostureReport
5
+ } from "./chunk-C4OR4KM5.js";
6
+
7
+ // src/audit-cli.ts
8
+ var [url, basePath] = process.argv.slice(2);
9
+ if (url === void 0) {
10
+ process.stderr.write(
11
+ "usage: byollm-audit-deployment <url> [base-path]\n e.g. byollm-audit-deployment https://hub.byollm.cloud\n"
12
+ );
13
+ process.exit(2);
14
+ }
15
+ var report = await auditDeployment({
16
+ url,
17
+ ...basePath === void 0 ? {} : { basePath }
18
+ });
19
+ process.stdout.write(`
20
+ ${formatPostureReport(report)}`);
21
+ process.exit(report.passed ? 0 : 1);
22
+ //# sourceMappingURL=audit-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/audit-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { auditDeployment, formatPostureReport } from \"./deployment.js\";\n\n/**\n * `byollm-audit-deployment <url>` — what a stranger can do to a running relay.\n *\n * Distinct from `byollm-certify`, which drives a real daemon against a target\n * that may be an in-process handler. This one has a URL and nothing else,\n * which is exactly what an attacker has, and it exists because eight\n * freeze-gate findings came from a suite in which nothing was ever a stranger.\n *\n * ```bash\n * npx byollm-audit-deployment https://hub.byollm.cloud\n * ```\n *\n * Safe to run against production: nothing writes, nothing floods, and every\n * request is one an ordinary scanner would make.\n */\nconst [url, basePath] = process.argv.slice(2);\n\nif (url === undefined) {\n process.stderr.write(\n \"usage: byollm-audit-deployment <url> [base-path]\\n\" +\n \" e.g. byollm-audit-deployment https://hub.byollm.cloud\\n\",\n );\n process.exit(2);\n}\n\nconst report = await auditDeployment({\n url,\n ...(basePath === undefined ? {} : { basePath }),\n});\nprocess.stdout.write(`\\n${formatPostureReport(report)}`);\nprocess.exit(report.passed ? 0 : 1);\n"],"mappings":";;;;;;;AAkBA,IAAM,CAAC,KAAK,QAAQ,IAAI,QAAQ,KAAK,MAAM,CAAC;AAE5C,IAAI,QAAQ,QAAW;AACrB,UAAQ,OAAO;AAAA,IACb;AAAA,EAEF;AACA,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,SAAS,MAAM,gBAAgB;AAAA,EACnC;AAAA,EACA,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;AAC/C,CAAC;AACD,QAAQ,OAAO,MAAM;AAAA,EAAK,oBAAoB,MAAM,CAAC,EAAE;AACvD,QAAQ,KAAK,OAAO,SAAS,IAAI,CAAC;","names":[]}
@@ -0,0 +1,252 @@
1
+ // src/deployment.ts
2
+ import { generateKeys, signRequest, signSiteRequest } from "@byollm/protocol";
3
+ var STUB = {
4
+ id: "posture-probe",
5
+ kind: "llm.generate",
6
+ owner: "nobody",
7
+ audience: "self",
8
+ sizeClass: "small",
9
+ streaming: false,
10
+ // Far enough out that a deployment cannot pass by calling it expired.
11
+ deadlineAt: 41024448e5
12
+ };
13
+ var REFUSED = /* @__PURE__ */ new Set([401, 403, 404]);
14
+ async function refusedByByollm(response) {
15
+ if (!REFUSED.has(response.status)) {
16
+ return { ok: false, why: `answered ${String(response.status)}` };
17
+ }
18
+ let body;
19
+ try {
20
+ body = await response.json();
21
+ } catch {
22
+ return {
23
+ ok: false,
24
+ why: `answered ${String(response.status)} but not as byollm \u2014 something else is serving this path`
25
+ };
26
+ }
27
+ const shaped = typeof body === "object" && body !== null && typeof body.error === "string";
28
+ return shaped ? { ok: true, why: `answered ${String(response.status)}` } : {
29
+ ok: false,
30
+ why: `answered ${String(response.status)} with a body byollm would not send \u2014 something else is serving this path`
31
+ };
32
+ }
33
+ var outcome = (passed, detail) => ({
34
+ passed,
35
+ detail
36
+ });
37
+ var POSTURE_CHECKS = Object.freeze([
38
+ {
39
+ id: "D001_SITE_ENQUEUE_REFUSES_UNSIGNED",
40
+ title: "an anonymous caller cannot enqueue work in a site's name",
41
+ cites: ["REQUESTS_SIGNED_NOT_BEARER"],
42
+ async run({ origin, fetch: f }) {
43
+ const response = await f(`${origin}/relay/site/enqueue`, {
44
+ method: "POST",
45
+ headers: { "content-type": "application/json" },
46
+ body: JSON.stringify({ siteId: "any-site", stub: STUB })
47
+ });
48
+ const refusal = await refusedByByollm(response);
49
+ return outcome(refusal.ok, `POST /relay/site/enqueue ${refusal.why}`);
50
+ }
51
+ },
52
+ {
53
+ id: "D002_SITE_READS_REFUSE_UNSIGNED",
54
+ title: "an anonymous caller cannot read who is online",
55
+ cites: ["REQUESTS_SIGNED_NOT_BEARER"],
56
+ async run({ origin, fetch: f }) {
57
+ const why = [];
58
+ let ok = true;
59
+ for (const path of ["pending", "results"]) {
60
+ const response = await f(
61
+ `${origin}/relay/site/${path}?siteId=any-site`
62
+ );
63
+ const refusal = await refusedByByollm(response);
64
+ ok &&= refusal.ok;
65
+ why.push(`${path} ${refusal.why}`);
66
+ }
67
+ return outcome(ok, why.join("; "));
68
+ }
69
+ },
70
+ {
71
+ id: "D003_DAEMON_PLANE_REFUSES_UNSIGNED",
72
+ title: "an anonymous caller cannot claim work",
73
+ cites: ["REQUESTS_SIGNED_NOT_BEARER", "CLAIM_REQUIRES_CAPABILITY"],
74
+ async run({ origin, basePath, fetch: f }) {
75
+ const response = await f(`${origin}${basePath}/claim`, {
76
+ method: "POST",
77
+ headers: { "content-type": "application/json" },
78
+ body: JSON.stringify({
79
+ protocolVersion: "0",
80
+ runnerId: "nobody",
81
+ max: 1,
82
+ capabilities: [{ kind: "llm.generate", models: ["any"] }]
83
+ })
84
+ });
85
+ const refusal = await refusedByByollm(response);
86
+ return outcome(refusal.ok, `POST ${basePath}/claim ${refusal.why}`);
87
+ }
88
+ },
89
+ {
90
+ id: "D004_REFUSES_A_STRANGER_S_VALID_SIGNATURE",
91
+ title: "a well-formed signature from an unknown key is not enough",
92
+ cites: ["REQUESTS_SIGNED_NOT_BEARER", "KEYS_EXCHANGED_AT_CONSENT"],
93
+ async run({ origin, basePath, fetch: f }) {
94
+ const stranger = generateKeys(Date.now());
95
+ const now = Date.now();
96
+ const siteBody = JSON.stringify({ siteId: "any-site", stub: STUB });
97
+ const siteSignature = signSiteRequest(stranger, {
98
+ endpoint: "enqueue",
99
+ siteId: "any-site",
100
+ issuedAt: now,
101
+ body: siteBody
102
+ });
103
+ const site = await f(`${origin}/relay/site/enqueue`, {
104
+ method: "POST",
105
+ headers: {
106
+ "content-type": "application/json",
107
+ "x-byollm-site": "any-site",
108
+ "x-byollm-issued-at": String(siteSignature.issuedAt),
109
+ "x-byollm-signature": siteSignature.signature
110
+ },
111
+ body: siteBody
112
+ });
113
+ const daemonBody = JSON.stringify({
114
+ protocolVersion: "0",
115
+ runnerId: "nobody",
116
+ max: 1,
117
+ capabilities: [{ kind: "llm.generate", models: ["any"] }]
118
+ });
119
+ const daemonSignature = signRequest(stranger, {
120
+ endpoint: "claim",
121
+ runnerId: "nobody",
122
+ issuedAt: now,
123
+ body: daemonBody
124
+ });
125
+ const daemon = await f(`${origin}${basePath}/claim`, {
126
+ method: "POST",
127
+ headers: {
128
+ "content-type": "application/json",
129
+ "x-byollm-runner": "nobody",
130
+ "x-byollm-issued-at": String(daemonSignature.issuedAt),
131
+ "x-byollm-signature": daemonSignature.signature
132
+ },
133
+ body: daemonBody
134
+ });
135
+ const siteRefusal = await refusedByByollm(site);
136
+ const daemonRefusal = await refusedByByollm(daemon);
137
+ return outcome(
138
+ siteRefusal.ok && daemonRefusal.ok,
139
+ `signed by a stranger: site ${siteRefusal.why}, daemon ${daemonRefusal.why}`
140
+ );
141
+ }
142
+ },
143
+ {
144
+ id: "D005_NO_DEBUG_SURFACE",
145
+ title: "the debug page is not on the internet",
146
+ cites: [],
147
+ async run({ origin, basePath, fetch: f }) {
148
+ const paths = ["/debug", `${basePath}/debug`];
149
+ const statuses = [];
150
+ for (const path of paths) {
151
+ const response = await f(`${origin}${path}`);
152
+ statuses.push(response.status);
153
+ }
154
+ return outcome(
155
+ statuses.every((status) => status !== 200),
156
+ `debug paths answered ${statuses.map(String).join("/")}`
157
+ );
158
+ }
159
+ },
160
+ {
161
+ id: "D006_NO_PATH_DISPATCH",
162
+ title: "a handler cannot be reached by dressing a path up to look like it",
163
+ cites: ["REQUESTS_SIGNED_NOT_BEARER"],
164
+ async run({ origin, fetch: f }) {
165
+ const response = await f(`${origin}/literally/anything/claim`, {
166
+ method: "POST",
167
+ headers: { "content-type": "application/json" },
168
+ body: JSON.stringify({ protocolVersion: "0", max: 1 })
169
+ });
170
+ const refusal = await refusedByByollm(response);
171
+ return outcome(
172
+ refusal.ok && response.status === 404,
173
+ `POST /literally/anything/claim ${refusal.why}`
174
+ );
175
+ }
176
+ },
177
+ {
178
+ id: "D007_TLS_ONLY",
179
+ title: "the deployment is reached over TLS, and plaintext is not served",
180
+ cites: [],
181
+ async run({ origin, fetch: f }) {
182
+ if (!origin.startsWith("https://")) {
183
+ return outcome(false, `origin is ${origin} \u2014 this audit saw no TLS`);
184
+ }
185
+ const plain = origin.replace("https://", "http://");
186
+ const response = await f(`${plain}/healthz`, { redirect: "manual" });
187
+ const redirected = response.status >= 300 && response.status < 400 && (response.headers.get("location") ?? "").startsWith("https://");
188
+ return outcome(
189
+ redirected || REFUSED.has(response.status),
190
+ `plaintext answered ${String(response.status)}${redirected ? " and redirects to https" : ""}`
191
+ );
192
+ }
193
+ }
194
+ ]);
195
+ async function auditDeployment(options) {
196
+ const origin = options.url.replace(/\/+$/, "");
197
+ const context = {
198
+ origin,
199
+ basePath: (options.basePath ?? "/byollm").replace(/\/+$/, ""),
200
+ fetch: options.fetch ?? globalThis.fetch
201
+ };
202
+ const results = [];
203
+ for (const check of POSTURE_CHECKS) {
204
+ let result;
205
+ try {
206
+ result = { ...await check.run(context), ...describe(check) };
207
+ } catch (error) {
208
+ result = {
209
+ ...describe(check),
210
+ passed: false,
211
+ detail: `the probe failed: ${error instanceof Error ? error.message : "unknown"}`
212
+ };
213
+ }
214
+ results.push(result);
215
+ options.onProgress?.(result);
216
+ }
217
+ return {
218
+ origin,
219
+ passed: results.every((result) => result.passed),
220
+ results
221
+ };
222
+ }
223
+ var describe = (check) => ({
224
+ id: check.id,
225
+ title: check.title,
226
+ cites: check.cites
227
+ });
228
+ function formatPostureReport(report) {
229
+ const lines = [`deployment posture \u2014 ${report.origin}`, ""];
230
+ for (const result of report.results) {
231
+ lines.push(` ${result.passed ? "ok " : "FAIL"} ${result.id}`);
232
+ lines.push(` ${result.title}`);
233
+ lines.push(` ${result.detail}`);
234
+ if (result.cites.length > 0) {
235
+ lines.push(` cites ${result.cites.join(", ")}`);
236
+ }
237
+ }
238
+ const passed = report.results.filter((result) => result.passed).length;
239
+ lines.push(
240
+ "",
241
+ report.passed ? `${String(passed)}/${String(report.results.length)} \u2014 a stranger got nowhere.` : `${String(passed)}/${String(report.results.length)} \u2014 a stranger got somewhere. See FAIL above.`,
242
+ ""
243
+ );
244
+ return lines.join("\n");
245
+ }
246
+
247
+ export {
248
+ POSTURE_CHECKS,
249
+ auditDeployment,
250
+ formatPostureReport
251
+ };
252
+ //# sourceMappingURL=chunk-C4OR4KM5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/deployment.ts"],"sourcesContent":["import { generateKeys, signRequest, signSiteRequest } from \"@byollm/protocol\";\n\n/**\n * The deployment posture audit — what an outsider can do to a running relay.\n *\n * ## Why this exists as a separate surface\n *\n * `certify` drives a real daemon against a {@link ConformanceTarget}, and a\n * target may be an in-process handler or an HTTP server: \"deliberately\n * transport-agnostic\", which is the right call for certifying a *protocol*.\n *\n * It is also a blind spot, and byollm_009's ninth finding lived in it. Eight\n * freeze-gate findings came from tests where the site reached the relay by\n * calling `handle()` on an object it held a reference to — and a harness that\n * invokes the system under test directly cannot see anything about how the\n * system is *reached*. The site plane had no authentication at all. Nothing\n * noticed, because nothing in the suite was ever a stranger.\n *\n * So this suite is a stranger. It holds no credential, no key the deployment\n * knows, and no reference to any object inside it. It has a URL, which is\n * exactly what an attacker has. Every check asks the question that form of\n * access makes available:\n *\n * - can I enqueue work into someone's machines?\n * - can I read who is online and what they are holding?\n * - can I make a signature that is *well-formed* and be believed?\n * - is anything served that should not be on the internet?\n * - can I reach a handler by dressing a path up to look like one?\n *\n * ## What this is not\n *\n * Not a penetration test, and not exhaustive — it cannot be, because the next\n * hole will be in whatever gets added next. It is the specific class that has\n * already bitten, turned into something that runs. That is the same move as\n * every other check in this kit: a finding becomes a check so its *shape*\n * cannot recur silently.\n *\n * It is also deliberately **safe to run against production**: nothing here\n * writes, nothing floods, and every request is one an ordinary scanner would\n * make. A posture audit you are nervous about running is one nobody runs.\n */\n\n/** One thing a stranger tried. */\nexport interface PostureCheck {\n /** Stable id, cited in output. */\n readonly id: string;\n /** What a person should understand from a failure. */\n readonly title: string;\n /** MUSTs this exercises, where one applies. Empty is honest, not a gap. */\n readonly cites: readonly string[];\n run(context: PostureContext): Promise<PostureOutcome>;\n}\n\nexport interface PostureContext {\n /** The origin, as an outsider would type it. */\n readonly origin: string;\n /** Where the daemon plane is mounted. */\n readonly basePath: string;\n /** Injectable, so a test can drive this without a network. */\n readonly fetch: typeof fetch;\n}\n\nexport interface PostureOutcome {\n readonly passed: boolean;\n /** What actually happened, in a sentence someone can act on. */\n readonly detail: string;\n}\n\nexport interface PostureResult extends PostureOutcome {\n readonly id: string;\n readonly title: string;\n readonly cites: readonly string[];\n}\n\nexport interface PostureReport {\n readonly origin: string;\n readonly passed: boolean;\n readonly results: readonly PostureResult[];\n}\n\nconst STUB = {\n id: \"posture-probe\",\n kind: \"llm.generate\",\n owner: \"nobody\",\n audience: \"self\",\n sizeClass: \"small\",\n streaming: false,\n // Far enough out that a deployment cannot pass by calling it expired.\n deadlineAt: 4_102_444_800_000,\n};\n\n/** Refused, for any reason a server is entitled to refuse a stranger. */\nconst REFUSED = new Set([401, 403, 404]);\n\n/**\n * Refused **by a byollm relay**, rather than by nothing being there.\n *\n * The distinction is the whole difference between a posture audit and a\n * connectivity check, and this suite shipped without it for an hour. Running\n * against `hub.byollm.cloud` before its Ingress had a matching host rule, the\n * load balancer answered 404 to everything from its own error page — and the\n * audit reported 6/7, because 404 is a refusal and every probe got one.\n *\n * A completely dead deployment scored better than a working one. That is the\n * assertion-that-cannot-fail wearing its most convincing disguise: not a check\n * that never fails, but one that passes for a reason unrelated to the property\n * it claims.\n *\n * So a refusal has to be *byollm's* refusal: the protocol answers errors as\n * JSON with an `error` field, and Google's `backend NotFound` page does not.\n */\nasync function refusedByByollm(\n response: Response,\n): Promise<{ ok: boolean; why: string }> {\n if (!REFUSED.has(response.status)) {\n return { ok: false, why: `answered ${String(response.status)}` };\n }\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n return {\n ok: false,\n why:\n `answered ${String(response.status)} but not as byollm — ` +\n `something else is serving this path`,\n };\n }\n const shaped =\n typeof body === \"object\" &&\n body !== null &&\n typeof (body as { error?: unknown }).error === \"string\";\n return shaped\n ? { ok: true, why: `answered ${String(response.status)}` }\n : {\n ok: false,\n why:\n `answered ${String(response.status)} with a body byollm would not ` +\n `send — something else is serving this path`,\n };\n}\n\nconst outcome = (passed: boolean, detail: string): PostureOutcome => ({\n passed,\n detail,\n});\n\nexport const POSTURE_CHECKS: readonly PostureCheck[] = Object.freeze([\n {\n id: \"D001_SITE_ENQUEUE_REFUSES_UNSIGNED\",\n title: \"an anonymous caller cannot enqueue work in a site's name\",\n cites: [\"REQUESTS_SIGNED_NOT_BEARER\"],\n async run({ origin, fetch: f }) {\n const response = await f(`${origin}/relay/site/enqueue`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ siteId: \"any-site\", stub: STUB }),\n });\n // The finding, exactly: a relay that accepts this routes unsolicited\n // work to consenting users' private hardware. The payload that follows\n // is sealed by the real site or not at all, so nothing forged *runs* —\n // and dispatch to someone's machine is a breach whatever the\n // ciphertext does.\n const refusal = await refusedByByollm(response);\n return outcome(refusal.ok, `POST /relay/site/enqueue ${refusal.why}`);\n },\n },\n {\n id: \"D002_SITE_READS_REFUSE_UNSIGNED\",\n title: \"an anonymous caller cannot read who is online\",\n cites: [\"REQUESTS_SIGNED_NOT_BEARER\"],\n async run({ origin, fetch: f }) {\n // Reads matter as much as writes here. A blind relay's whole claim is\n // that it holds routing metadata and nothing else — which makes that\n // metadata the entire prize, and \"who is online right now, on which\n // device, holding which lease\" is the shape of it.\n const why: string[] = [];\n let ok = true;\n for (const path of [\"pending\", \"results\"]) {\n const response = await f(\n `${origin}/relay/site/${path}?siteId=any-site`,\n );\n const refusal = await refusedByByollm(response);\n ok &&= refusal.ok;\n why.push(`${path} ${refusal.why}`);\n }\n return outcome(ok, why.join(\"; \"));\n },\n },\n {\n id: \"D003_DAEMON_PLANE_REFUSES_UNSIGNED\",\n title: \"an anonymous caller cannot claim work\",\n cites: [\"REQUESTS_SIGNED_NOT_BEARER\", \"CLAIM_REQUIRES_CAPABILITY\"],\n async run({ origin, basePath, fetch: f }) {\n const response = await f(`${origin}${basePath}/claim`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n protocolVersion: \"0\",\n runnerId: \"nobody\",\n max: 1,\n capabilities: [{ kind: \"llm.generate\", models: [\"any\"] }],\n }),\n });\n const refusal = await refusedByByollm(response);\n return outcome(refusal.ok, `POST ${basePath}/claim ${refusal.why}`);\n },\n },\n {\n id: \"D004_REFUSES_A_STRANGER_S_VALID_SIGNATURE\",\n title: \"a well-formed signature from an unknown key is not enough\",\n cites: [\"REQUESTS_SIGNED_NOT_BEARER\", \"KEYS_EXCHANGED_AT_CONSENT\"],\n async run({ origin, basePath, fetch: f }) {\n // The check `D001`–`D003` cannot make: everything about these requests\n // is correct except whose key signed them. A deployment that verified\n // signatures without checking *whose* would pass the three above and\n // fail here, and that is a real implementation mistake rather than a\n // hypothetical one — verifying a signature and identifying a signer are\n // two steps, and the second is the one that gets skipped.\n const stranger = generateKeys(Date.now());\n const now = Date.now();\n\n const siteBody = JSON.stringify({ siteId: \"any-site\", stub: STUB });\n const siteSignature = signSiteRequest(stranger, {\n endpoint: \"enqueue\",\n siteId: \"any-site\",\n issuedAt: now,\n body: siteBody,\n });\n const site = await f(`${origin}/relay/site/enqueue`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-byollm-site\": \"any-site\",\n \"x-byollm-issued-at\": String(siteSignature.issuedAt),\n \"x-byollm-signature\": siteSignature.signature,\n },\n body: siteBody,\n });\n\n const daemonBody = JSON.stringify({\n protocolVersion: \"0\",\n runnerId: \"nobody\",\n max: 1,\n capabilities: [{ kind: \"llm.generate\", models: [\"any\"] }],\n });\n const daemonSignature = signRequest(stranger, {\n endpoint: \"claim\",\n runnerId: \"nobody\",\n issuedAt: now,\n body: daemonBody,\n });\n const daemon = await f(`${origin}${basePath}/claim`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-byollm-runner\": \"nobody\",\n \"x-byollm-issued-at\": String(daemonSignature.issuedAt),\n \"x-byollm-signature\": daemonSignature.signature,\n },\n body: daemonBody,\n });\n\n const siteRefusal = await refusedByByollm(site);\n const daemonRefusal = await refusedByByollm(daemon);\n return outcome(\n siteRefusal.ok && daemonRefusal.ok,\n `signed by a stranger: site ${siteRefusal.why}, daemon ${daemonRefusal.why}`,\n );\n },\n },\n {\n id: \"D005_NO_DEBUG_SURFACE\",\n title: \"the debug page is not on the internet\",\n cites: [],\n async run({ origin, basePath, fetch: f }) {\n // Finding eleven. The relay's debug page shows no prompt or result text\n // — it does not have them — and it does show every routed job, who\n // claimed it, and every lease in flight. Closing the site plane while\n // leaving this open protects the data from one door and not the other.\n const paths = [\"/debug\", `${basePath}/debug`];\n const statuses: number[] = [];\n for (const path of paths) {\n const response = await f(`${origin}${path}`);\n statuses.push(response.status);\n }\n return outcome(\n statuses.every((status) => status !== 200),\n `debug paths answered ${statuses.map(String).join(\"/\")}`,\n );\n },\n },\n {\n id: \"D006_NO_PATH_DISPATCH\",\n title: \"a handler cannot be reached by dressing a path up to look like it\",\n cites: [\"REQUESTS_SIGNED_NOT_BEARER\"],\n async run({ origin, fetch: f }) {\n // A router that dispatched on the last path segment would serve\n // `/literally/anything/claim`. Worth checking from outside because it\n // is invisible from inside: an in-process harness calls the handler by\n // name and never constructs a URL that could be misread.\n const response = await f(`${origin}/literally/anything/claim`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ protocolVersion: \"0\", max: 1 }),\n });\n const refusal = await refusedByByollm(response);\n return outcome(\n refusal.ok && response.status === 404,\n `POST /literally/anything/claim ${refusal.why}`,\n );\n },\n },\n {\n id: \"D007_TLS_ONLY\",\n title: \"the deployment is reached over TLS, and plaintext is not served\",\n cites: [],\n async run({ origin, fetch: f }) {\n if (!origin.startsWith(\"https://\")) {\n // Not a failure when auditing a local hub on purpose, but never\n // silent: an audit that reports \"posture good\" against an http origin\n // has certified the one thing that matters least.\n return outcome(false, `origin is ${origin} — this audit saw no TLS`);\n }\n // Payloads are sealed end to end and would survive plaintext transport.\n // Request signatures would not: on the wire they are replayable by\n // anyone on the path for the length of the freshness window, and every\n // site-plane and daemon-plane call carries one.\n const plain = origin.replace(\"https://\", \"http://\");\n const response = await f(`${plain}/healthz`, { redirect: \"manual\" });\n const redirected =\n response.status >= 300 &&\n response.status < 400 &&\n (response.headers.get(\"location\") ?? \"\").startsWith(\"https://\");\n return outcome(\n redirected || REFUSED.has(response.status),\n `plaintext answered ${String(response.status)}${\n redirected ? \" and redirects to https\" : \"\"\n }`,\n );\n },\n },\n]);\n\n/**\n * Audit a running deployment. Holds nothing it was not given a URL for.\n *\n * Every check runs even after one fails, because a posture report's job is to\n * be a complete picture rather than the first thing that went wrong.\n */\nexport async function auditDeployment(options: {\n url: string;\n basePath?: string;\n fetch?: typeof fetch;\n onProgress?: (result: PostureResult) => void;\n}): Promise<PostureReport> {\n const origin = options.url.replace(/\\/+$/, \"\");\n const context: PostureContext = {\n origin,\n basePath: (options.basePath ?? \"/byollm\").replace(/\\/+$/, \"\"),\n fetch: options.fetch ?? globalThis.fetch,\n };\n\n const results: PostureResult[] = [];\n for (const check of POSTURE_CHECKS) {\n let result: PostureResult;\n try {\n result = { ...(await check.run(context)), ...describe(check) };\n } catch (error) {\n // A check that cannot complete is a failure, not a skip. An audit that\n // silently drops a probe it could not run reports a posture nobody\n // measured — which is worse than reporting none at all.\n result = {\n ...describe(check),\n passed: false,\n detail: `the probe failed: ${error instanceof Error ? error.message : \"unknown\"}`,\n };\n }\n results.push(result);\n options.onProgress?.(result);\n }\n\n return {\n origin,\n passed: results.every((result) => result.passed),\n results,\n };\n}\n\nconst describe = (check: PostureCheck) => ({\n id: check.id,\n title: check.title,\n cites: check.cites,\n});\n\nexport function formatPostureReport(report: PostureReport): string {\n const lines = [`deployment posture — ${report.origin}`, \"\"];\n for (const result of report.results) {\n lines.push(` ${result.passed ? \"ok \" : \"FAIL\"} ${result.id}`);\n lines.push(` ${result.title}`);\n lines.push(` ${result.detail}`);\n if (result.cites.length > 0) {\n lines.push(` cites ${result.cites.join(\", \")}`);\n }\n }\n const passed = report.results.filter((result) => result.passed).length;\n lines.push(\n \"\",\n report.passed\n ? `${String(passed)}/${String(report.results.length)} — a stranger got nowhere.`\n : `${String(passed)}/${String(report.results.length)} — a stranger got somewhere. See FAIL above.`,\n \"\",\n );\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}