@byollm/conformance 0.1.0-alpha.84 → 0.1.0-alpha.86
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 +1 -1
- package/dist/audit-cli.js +1 -1
- package/dist/{chunk-2EJHYOQS.js → chunk-2JXKI5TH.js} +16 -9
- package/dist/chunk-2JXKI5TH.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-2EJHYOQS.js.map +0 -1
package/README.md
CHANGED
package/dist/audit-cli.js
CHANGED
|
@@ -41,6 +41,11 @@ var outcome = (passed, detail) => ({
|
|
|
41
41
|
passed,
|
|
42
42
|
detail
|
|
43
43
|
});
|
|
44
|
+
var unmeasured = (detail) => ({
|
|
45
|
+
passed: false,
|
|
46
|
+
measured: false,
|
|
47
|
+
detail
|
|
48
|
+
});
|
|
44
49
|
async function servedCertificate(address, host) {
|
|
45
50
|
return new Promise((resolve) => {
|
|
46
51
|
const socket = tlsConnect(
|
|
@@ -310,8 +315,7 @@ var POSTURE_CHECKS = Object.freeze([
|
|
|
310
315
|
cites: [],
|
|
311
316
|
async run({ origin, originAddress }) {
|
|
312
317
|
if (originAddress === void 0) {
|
|
313
|
-
return
|
|
314
|
-
false,
|
|
318
|
+
return unmeasured(
|
|
315
319
|
"no origin address given \u2014 this posture was not measured (pass the origin's address as the third argument)"
|
|
316
320
|
);
|
|
317
321
|
}
|
|
@@ -357,8 +361,7 @@ var POSTURE_CHECKS = Object.freeze([
|
|
|
357
361
|
async run({ origin, originAddress }) {
|
|
358
362
|
const host = new URL(origin).host;
|
|
359
363
|
if (originAddress === void 0) {
|
|
360
|
-
return
|
|
361
|
-
false,
|
|
364
|
+
return unmeasured(
|
|
362
365
|
"no origin address given \u2014 this posture was not measured. Asking the hostname reads the edge's certificate, which names it by construction and proves nothing about the origin"
|
|
363
366
|
);
|
|
364
367
|
}
|
|
@@ -386,8 +389,7 @@ var POSTURE_CHECKS = Object.freeze([
|
|
|
386
389
|
async run({ origin, originAddress }) {
|
|
387
390
|
const host = new URL(origin).host;
|
|
388
391
|
if (originAddress === void 0) {
|
|
389
|
-
return
|
|
390
|
-
false,
|
|
392
|
+
return unmeasured(
|
|
391
393
|
"no origin address given \u2014 this posture was not measured (the edge's certificate is Cloudflare's to renew, not ours)"
|
|
392
394
|
);
|
|
393
395
|
}
|
|
@@ -445,7 +447,8 @@ var describe = (check) => ({
|
|
|
445
447
|
function formatPostureReport(report) {
|
|
446
448
|
const lines = [`deployment posture \u2014 ${report.origin}`, ""];
|
|
447
449
|
for (const result of report.results) {
|
|
448
|
-
|
|
450
|
+
const mark = result.passed ? "ok " : result.measured === false ? "? " : "FAIL";
|
|
451
|
+
lines.push(` ${mark} ${result.id}`);
|
|
449
452
|
lines.push(` ${result.title}`);
|
|
450
453
|
lines.push(` ${result.detail}`);
|
|
451
454
|
if (result.cites.length > 0) {
|
|
@@ -453,9 +456,13 @@ function formatPostureReport(report) {
|
|
|
453
456
|
}
|
|
454
457
|
}
|
|
455
458
|
const passed = report.results.filter((result) => result.passed).length;
|
|
459
|
+
const unasked = report.results.filter(
|
|
460
|
+
(result) => result.measured === false
|
|
461
|
+
).length;
|
|
462
|
+
const breached = report.results.length - passed - unasked;
|
|
456
463
|
lines.push(
|
|
457
464
|
"",
|
|
458
|
-
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.`,
|
|
465
|
+
report.passed ? `${String(passed)}/${String(report.results.length)} \u2014 a stranger got nowhere.` : breached > 0 ? `${String(passed)}/${String(report.results.length)} \u2014 a stranger got somewhere. See FAIL above.` + (unasked > 0 ? ` (${String(unasked)} not measured \u2014 see ? above.)` : "") : `${String(passed)}/${String(report.results.length)} \u2014 nothing was breached, and ${String(unasked)} posture(s) could not be measured. See ? above.`,
|
|
459
466
|
""
|
|
460
467
|
);
|
|
461
468
|
return lines.join("\n");
|
|
@@ -466,4 +473,4 @@ export {
|
|
|
466
473
|
auditDeployment,
|
|
467
474
|
formatPostureReport
|
|
468
475
|
};
|
|
469
|
-
//# sourceMappingURL=chunk-
|
|
476
|
+
//# sourceMappingURL=chunk-2JXKI5TH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/deployment.ts"],"sourcesContent":["import { connect as tlsConnect } from \"node:tls\";\nimport { request as httpsRequest } from \"node:https\";\nimport {\n PROTOCOL_VERSION,\n generateKeys,\n signRequest,\n signSiteRequest,\n} 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 * The origin's own address, behind whatever edge fronts it — `D008`.\n *\n * Optional because most deployments have no separate origin, and a check\n * that guessed one would report a posture it never tested.\n */\n readonly originAddress?: string;\n}\n\nexport interface PostureOutcome {\n readonly passed: boolean;\n /**\n * Did this check actually put its question? Absent means yes.\n *\n * A posture that could not be measured does not pass — a gate that waves\n * through what it could not look at passes hardest when it is blindest —\n * and it is not a breach either. Unproven is a third state.\n */\n readonly measured?: 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: \"private\",\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\n/**\n * A posture this run could not measure — B065.\n *\n * **Not a pass, and not a breach.** It does not pass, because a gate that\n * waves through what it could not look at is a gate that passes hardest when\n * it is blindest. It is not a FAIL either: \"the origin refused a stranger\"\n * and \"nobody asked the origin\" are different facts, and printing them in one\n * word tells an operator a stranger got somewhere when nobody did.\n *\n * Unproven is a third state — the rule this project already applies to a poll\n * that cannot read an answer and to a release check that cannot read a\n * version. It arrives here because three of these checks need the origin's\n * address, and without it they were reporting \"a stranger got somewhere\"\n * about a question they had not put.\n */\n/*\n * Exported for the one assertion that matters about it — that it does not\n * pass. A test that builds its own result objects can prove the FORMATTER\n * distinguishes the three states and prove nothing about the constructor,\n * which is exactly what the first draft of that test did.\n */\nexport const unmeasured = (detail: string): PostureOutcome => ({\n passed: false,\n measured: false,\n detail,\n});\n\n/**\n * The certificate the **origin** serves, read off the connection.\n *\n * Connects to the origin's own address with the pinned hostname in SNI, which\n * is what an edge does when it validates. Certificate verification is off for\n * `D008`'s reason: the question is what this address presents, not whether to\n * trust it.\n *\n * **It must be the origin, not the hostname.** Written first as a plain\n * connection to `hub.byollm.cloud`, which goes *through* Cloudflare and\n * returns Cloudflare's own edge certificate — one that names the host by\n * construction and auto-renews on a ninety-day cycle. `D009` passed on it\n * while the origin's certificate named nothing relevant, which is the exact\n * condition finding 45 describes; `D010` then failed with \"84 days\" and\n * revealed that both were measuring the edge.\n *\n * Two certificates, two purposes: the edge one protects visitors and\n * Cloudflare renews it, and the origin one is what the edge validates and\n * nobody renews automatically. Only the second is this audit's business.\n */\nasync function servedCertificate(\n address: string,\n host: string,\n): Promise<{ names: readonly string[]; validTo: string } | undefined> {\n return new Promise((resolve) => {\n const socket = tlsConnect(\n {\n host: address,\n servername: host,\n port: 443,\n timeout: 15_000,\n rejectUnauthorized: false,\n },\n () => {\n const peer = socket.getPeerCertificate();\n const alt = (peer.subjectaltname ?? \"\")\n .split(\",\")\n .map((entry) => entry.trim().replace(/^DNS:/, \"\"))\n .filter((entry) => entry.length > 0);\n const cn: unknown = peer.subject.CN;\n socket.end();\n resolve({\n names: alt.length > 0 ? alt : [typeof cn === \"string\" ? cn : \"\"],\n validTo: peer.valid_to,\n });\n },\n );\n socket.on(\"error\", () => {\n resolve(undefined);\n });\n socket.on(\"timeout\", () => {\n socket.destroy();\n resolve(undefined);\n });\n });\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 // The version, because the auditor is a site-plane client like any\n // other (§B.4). Without it the relay refuses on the handshake and\n // this check would report \"refused\" for a reason that has nothing to\n // do with signatures — success for an unrelated reason, which is the\n // failure this whole file was written against.\n body: JSON.stringify({\n protocolVersion: PROTOCOL_VERSION,\n siteId: \"any-site\",\n stub: STUB,\n }),\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&protocolVersion=${PROTOCOL_VERSION}`,\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: PROTOCOL_VERSION,\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({\n protocolVersion: PROTOCOL_VERSION,\n siteId: \"any-site\",\n stub: STUB,\n });\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: PROTOCOL_VERSION,\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: \"D011_VERSION_NAMED_ON_BOTH_PLANES\",\n title: \"an unknown protocol version is refused by name, not by accident\",\n cites: [\"VERSION_HANDSHAKE_REQUIRED\"],\n async run({ origin, fetch: f }) {\n // byollm_009 §B.4. A mismatch that arrives as a generic `bad-request`\n // leaves a daemon and a server to discover they disagree by failing,\n // with nothing in the answer naming the disagreement or the fix — which\n // is what this relay did on every endpoint until the handshake landed.\n //\n // **Both planes, because the gap was a whole plane.** The daemon plane\n // had version literals in its schemas and the site plane had none, so a\n // check that probed one would have reported a handshake the other did\n // not have.\n const probes: { where: string; response: Response }[] = [\n {\n where: \"daemon\",\n response: await f(`${origin}/byollm/claim`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ protocolVersion: \"99\", max: 1 }),\n }),\n },\n {\n where: \"site\",\n response: await f(`${origin}/relay/site/enqueue`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n protocolVersion: \"99\",\n siteId: \"any-site\",\n stub: STUB,\n }),\n }),\n },\n ];\n\n const wrong: string[] = [];\n for (const probe of probes) {\n let body: { error?: string; supported?: unknown } = {};\n try {\n body = (await probe.response.json()) as typeof body;\n } catch {\n wrong.push(\n `${probe.where}: answered ${String(probe.response.status)} and not as byollm`,\n );\n continue;\n }\n if (body.error !== \"unsupported-protocol-version\") {\n wrong.push(\n `${probe.where}: answered ${String(probe.response.status)} ${String(body.error)}`,\n );\n continue;\n }\n // Named, not merely refused: the field a client acts on.\n if (!Array.isArray(body.supported)) {\n wrong.push(`${probe.where}: refused without naming what it speaks`);\n }\n }\n\n return outcome(\n wrong.length === 0,\n wrong.length === 0\n ? \"both planes name the version they speak\"\n : wrong.join(\"; \"),\n );\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 // **Not merely \"not 200\"** — cloud_009 §3 made the page per-site, so\n // an enabled one answers a probe with no site id `400` rather than\n // rendering. A check that accepted anything but 200 would pass\n // against a deployment whose debug page is one query parameter away,\n // which is finding eleven with a shorter walk.\n //\n // `404` is the only answer that means the route does not exist. The\n // reference relay says exactly that when its debug page is off, and\n // says `400` when it is on and the caller named no site.\n statuses.every((status) => status === 404),\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: PROTOCOL_VERSION, 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 id: \"D008_ORIGIN_NOT_PUBLIC\",\n title: \"the origin answers the edge, and nobody else\",\n cites: [],\n async run({ origin, originAddress }) {\n // cloud_008 findings 44/45. A load balancer has a public address, and\n // an edge in front of it is a convention rather than a boundary until\n // the origin refuses everything else: anyone who resolves the address\n // reaches the hub past every WAF rule, rate limit and bot check the\n // zone applies, and appears in no edge log doing it.\n //\n // Bounded, and not nothing. Requests are signed and payloads sealed, so\n // a stranger cannot forge a claim or read a job — but they can reach\n // `/byollm/pair` and every plane endpoint at whatever rate the origin\n // serves, which is exactly the surface the edge exists to absorb.\n //\n // Skipped rather than failed when no address is supplied: an auditor\n // who does not know where the origin lives cannot ask this, and\n // guessing would be a check that passes for not looking.\n if (originAddress === undefined) {\n // **Fails, not skips.** This file's own rule, and the suite already\n // had a test for it: an audit that drops a check it could not run\n // reports a posture nobody measured, which reads identically to one\n // measured and found good.\n //\n // Written as a pass first, on the reasoning that most deployments\n // have no separate origin — and that test failed it immediately. The\n // reasoning was wrong in the way this whole audit exists to catch:\n // \"probably fine\" and \"verified\" must not print the same.\n return unmeasured(\n \"no origin address given — this posture was not measured \" +\n \"(pass the origin's address as the third argument)\",\n );\n }\n\n // Asked the way an attacker would, which `fetch` cannot.\n //\n // The first version of this check used `fetch` and passed for the wrong\n // reason: TLS fails against a bare IP because the certificate does not\n // name it, the request never reaches the load balancer's backend, and a\n // connection error read as \"refused\". It would have reported a green\n // origin with no policy attached at all.\n //\n // Plain HTTP does not work either — the frontend answers `301` before\n // any backend is chosen, so the policy is never consulted.\n //\n // So: HTTPS to the address, with the real host in SNI, and certificate\n // verification **off**. That is not a lapse. The property under test is\n // whether an address answers a stranger, not who the answer comes from,\n // and refusing to look because the certificate does not match the IP is\n // how the first version passed while proving nothing. Nothing else in\n // this kit may copy it.\n const host = new URL(origin).host;\n const status = await new Promise<number | \"refused\">((resolve) => {\n const request = httpsRequest(\n {\n host: originAddress,\n servername: host,\n headers: { host },\n path: \"/readyz\",\n method: \"GET\",\n rejectUnauthorized: false,\n timeout: 15_000,\n },\n (response) => {\n response.resume();\n resolve(response.statusCode ?? 0);\n },\n );\n request.on(\"error\", () => {\n resolve(\"refused\");\n });\n request.on(\"timeout\", () => {\n request.destroy();\n resolve(\"refused\");\n });\n request.end();\n });\n\n if (status === \"refused\") {\n // Nothing answered at all, which is the strongest form of this.\n return outcome(true, \"the origin address refused the connection\");\n }\n return outcome(\n status === 403,\n `the origin answered ${String(status)} to a direct request`,\n );\n },\n },\n\n {\n id: \"D009_CERT_NAMES_THE_PINNED_HOST\",\n title: \"the certificate names the hostname daemons pin\",\n cites: [],\n async run({ origin, originAddress }) {\n // cloud_008 finding 45. The load balancer held one certificate, for the\n // *origin* hostname, and `hub.byollm.cloud` — the name every daemon\n // pins and the edge validates — was not on it. Cloudflare cannot verify\n // a certificate that does not name what it asked for, so the zone sat\n // on plain Full: encrypted to the origin, not checking who the origin\n // is, while every daemon's pinned site keys arrive through it.\n //\n // Nothing said so. \"There is a certificate\" and \"there is a certificate\n // for the name being validated\" printed identically, which is why this\n // check exists rather than a note in a runbook.\n //\n // Asked over TLS with the real SNI and read from the peer, so it is the\n // certificate actually served rather than one somebody configured.\n const host = new URL(origin).host;\n if (originAddress === undefined) {\n return unmeasured(\n \"no origin address given — this posture was not measured. \" +\n \"Asking the hostname reads the edge's certificate, which names it \" +\n \"by construction and proves nothing about the origin\",\n );\n }\n const served = await servedCertificate(originAddress, host);\n const names = served?.names;\n\n if (names === undefined) {\n return outcome(\n false,\n `could not read a certificate from ${originAddress}`,\n );\n }\n const covered = names.some(\n (name) =>\n name === host ||\n (name.startsWith(\"*.\") && host.endsWith(name.slice(1))),\n );\n return outcome(\n covered,\n covered\n ? `served a certificate naming ${host}`\n : `the certificate names ${names.join(\", \")} — not ${host}`,\n );\n },\n },\n\n {\n id: \"D010_CERT_HAS_LIFE_LEFT\",\n title: \"the certificate is not about to expire\",\n cites: [],\n async run({ origin, originAddress }) {\n // A long-lived certificate is the kind whose expiry gets written in a\n // note and never looked at again. The one this deployment now depends\n // on runs to 2041, which makes it *more* likely to be forgotten, not\n // less — and it is load-bearing: it is what the edge validates before\n // it will carry a daemon's traffic at all.\n //\n // Measured from the artefact rather than from the note. A date somebody\n // owns has to mean a date something checks.\n //\n // Ninety days: long enough that a renewal is scheduled rather than\n // scrambled, short enough that the warning is still about something\n // real.\n const host = new URL(origin).host;\n if (originAddress === undefined) {\n return unmeasured(\n \"no origin address given — this posture was not measured \" +\n \"(the edge's certificate is Cloudflare's to renew, not ours)\",\n );\n }\n const served = await servedCertificate(originAddress, host);\n if (served === undefined) {\n return outcome(\n false,\n `could not read a certificate from ${originAddress}`,\n );\n }\n const days = Math.round(\n (Date.parse(served.validTo) - Date.now()) / 86_400_000,\n );\n return outcome(\n days > 90,\n `the certificate expires ${served.validTo} (${String(days)} days)`,\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 /** The origin behind the edge, for `D008`. */\n originAddress?: 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 ...(options.originAddress === undefined\n ? {}\n : { originAddress: options.originAddress }),\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 const mark = result.passed\n ? \"ok \"\n : result.measured === false\n ? \"? \"\n : \"FAIL\";\n lines.push(` ${mark} ${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 const unasked = report.results.filter(\n (result) => result.measured === false,\n ).length;\n const breached = report.results.length - passed - unasked;\n /**\n * Three numbers, because there are three outcomes — B065.\n *\n * This said \"a stranger got somewhere\" whenever anything did not pass, and\n * three of these checks do not pass when they are given no origin address:\n * they had not asked. An operator reading that sentence would go looking\n * for a breach that nobody had reported.\n */\n lines.push(\n \"\",\n report.passed\n ? `${String(passed)}/${String(report.results.length)} — a stranger got nowhere.`\n : breached > 0\n ? `${String(passed)}/${String(report.results.length)} — a stranger got somewhere. ` +\n `See FAIL above.` +\n (unasked > 0\n ? ` (${String(unasked)} not measured — see ? above.)`\n : \"\")\n : `${String(passed)}/${String(report.results.length)} — nothing was breached, and ` +\n `${String(unasked)} posture(s) could not be measured. See ? above.`,\n \"\",\n );\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -351,6 +351,14 @@ interface PostureContext {
|
|
|
351
351
|
}
|
|
352
352
|
interface PostureOutcome {
|
|
353
353
|
readonly passed: boolean;
|
|
354
|
+
/**
|
|
355
|
+
* Did this check actually put its question? Absent means yes.
|
|
356
|
+
*
|
|
357
|
+
* A posture that could not be measured does not pass — a gate that waves
|
|
358
|
+
* through what it could not look at passes hardest when it is blindest —
|
|
359
|
+
* and it is not a breach either. Unproven is a third state.
|
|
360
|
+
*/
|
|
361
|
+
readonly measured?: boolean;
|
|
354
362
|
/** What actually happened, in a sentence someone can act on. */
|
|
355
363
|
readonly detail: string;
|
|
356
364
|
}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byollm/conformance",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.86",
|
|
4
4
|
"description": "The BYOLLM compatibility contract — drive a real daemon against any server and assert every protocol MUST.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
"node": ">=22.14"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"
|
|
29
|
-
"byollm": "0.1.0-alpha.
|
|
28
|
+
"byollm": "0.1.0-alpha.86",
|
|
29
|
+
"@byollm/protocol": "0.1.0-alpha.86"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@supabase/supabase-js": "^2.112.2",
|
|
33
|
-
"@byollm/server": "0.1.0-alpha.
|
|
33
|
+
"@byollm/server": "0.1.0-alpha.86"
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/deployment.ts"],"sourcesContent":["import { connect as tlsConnect } from \"node:tls\";\nimport { request as httpsRequest } from \"node:https\";\nimport {\n PROTOCOL_VERSION,\n generateKeys,\n signRequest,\n signSiteRequest,\n} 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 * The origin's own address, behind whatever edge fronts it — `D008`.\n *\n * Optional because most deployments have no separate origin, and a check\n * that guessed one would report a posture it never tested.\n */\n readonly originAddress?: string;\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: \"private\",\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\n/**\n * The certificate the **origin** serves, read off the connection.\n *\n * Connects to the origin's own address with the pinned hostname in SNI, which\n * is what an edge does when it validates. Certificate verification is off for\n * `D008`'s reason: the question is what this address presents, not whether to\n * trust it.\n *\n * **It must be the origin, not the hostname.** Written first as a plain\n * connection to `hub.byollm.cloud`, which goes *through* Cloudflare and\n * returns Cloudflare's own edge certificate — one that names the host by\n * construction and auto-renews on a ninety-day cycle. `D009` passed on it\n * while the origin's certificate named nothing relevant, which is the exact\n * condition finding 45 describes; `D010` then failed with \"84 days\" and\n * revealed that both were measuring the edge.\n *\n * Two certificates, two purposes: the edge one protects visitors and\n * Cloudflare renews it, and the origin one is what the edge validates and\n * nobody renews automatically. Only the second is this audit's business.\n */\nasync function servedCertificate(\n address: string,\n host: string,\n): Promise<{ names: readonly string[]; validTo: string } | undefined> {\n return new Promise((resolve) => {\n const socket = tlsConnect(\n {\n host: address,\n servername: host,\n port: 443,\n timeout: 15_000,\n rejectUnauthorized: false,\n },\n () => {\n const peer = socket.getPeerCertificate();\n const alt = (peer.subjectaltname ?? \"\")\n .split(\",\")\n .map((entry) => entry.trim().replace(/^DNS:/, \"\"))\n .filter((entry) => entry.length > 0);\n const cn: unknown = peer.subject.CN;\n socket.end();\n resolve({\n names: alt.length > 0 ? alt : [typeof cn === \"string\" ? cn : \"\"],\n validTo: peer.valid_to,\n });\n },\n );\n socket.on(\"error\", () => {\n resolve(undefined);\n });\n socket.on(\"timeout\", () => {\n socket.destroy();\n resolve(undefined);\n });\n });\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 // The version, because the auditor is a site-plane client like any\n // other (§B.4). Without it the relay refuses on the handshake and\n // this check would report \"refused\" for a reason that has nothing to\n // do with signatures — success for an unrelated reason, which is the\n // failure this whole file was written against.\n body: JSON.stringify({\n protocolVersion: PROTOCOL_VERSION,\n siteId: \"any-site\",\n stub: STUB,\n }),\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&protocolVersion=${PROTOCOL_VERSION}`,\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: PROTOCOL_VERSION,\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({\n protocolVersion: PROTOCOL_VERSION,\n siteId: \"any-site\",\n stub: STUB,\n });\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: PROTOCOL_VERSION,\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: \"D011_VERSION_NAMED_ON_BOTH_PLANES\",\n title: \"an unknown protocol version is refused by name, not by accident\",\n cites: [\"VERSION_HANDSHAKE_REQUIRED\"],\n async run({ origin, fetch: f }) {\n // byollm_009 §B.4. A mismatch that arrives as a generic `bad-request`\n // leaves a daemon and a server to discover they disagree by failing,\n // with nothing in the answer naming the disagreement or the fix — which\n // is what this relay did on every endpoint until the handshake landed.\n //\n // **Both planes, because the gap was a whole plane.** The daemon plane\n // had version literals in its schemas and the site plane had none, so a\n // check that probed one would have reported a handshake the other did\n // not have.\n const probes: { where: string; response: Response }[] = [\n {\n where: \"daemon\",\n response: await f(`${origin}/byollm/claim`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ protocolVersion: \"99\", max: 1 }),\n }),\n },\n {\n where: \"site\",\n response: await f(`${origin}/relay/site/enqueue`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n protocolVersion: \"99\",\n siteId: \"any-site\",\n stub: STUB,\n }),\n }),\n },\n ];\n\n const wrong: string[] = [];\n for (const probe of probes) {\n let body: { error?: string; supported?: unknown } = {};\n try {\n body = (await probe.response.json()) as typeof body;\n } catch {\n wrong.push(\n `${probe.where}: answered ${String(probe.response.status)} and not as byollm`,\n );\n continue;\n }\n if (body.error !== \"unsupported-protocol-version\") {\n wrong.push(\n `${probe.where}: answered ${String(probe.response.status)} ${String(body.error)}`,\n );\n continue;\n }\n // Named, not merely refused: the field a client acts on.\n if (!Array.isArray(body.supported)) {\n wrong.push(`${probe.where}: refused without naming what it speaks`);\n }\n }\n\n return outcome(\n wrong.length === 0,\n wrong.length === 0\n ? \"both planes name the version they speak\"\n : wrong.join(\"; \"),\n );\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 // **Not merely \"not 200\"** — cloud_009 §3 made the page per-site, so\n // an enabled one answers a probe with no site id `400` rather than\n // rendering. A check that accepted anything but 200 would pass\n // against a deployment whose debug page is one query parameter away,\n // which is finding eleven with a shorter walk.\n //\n // `404` is the only answer that means the route does not exist. The\n // reference relay says exactly that when its debug page is off, and\n // says `400` when it is on and the caller named no site.\n statuses.every((status) => status === 404),\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: PROTOCOL_VERSION, 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 id: \"D008_ORIGIN_NOT_PUBLIC\",\n title: \"the origin answers the edge, and nobody else\",\n cites: [],\n async run({ origin, originAddress }) {\n // cloud_008 findings 44/45. A load balancer has a public address, and\n // an edge in front of it is a convention rather than a boundary until\n // the origin refuses everything else: anyone who resolves the address\n // reaches the hub past every WAF rule, rate limit and bot check the\n // zone applies, and appears in no edge log doing it.\n //\n // Bounded, and not nothing. Requests are signed and payloads sealed, so\n // a stranger cannot forge a claim or read a job — but they can reach\n // `/byollm/pair` and every plane endpoint at whatever rate the origin\n // serves, which is exactly the surface the edge exists to absorb.\n //\n // Skipped rather than failed when no address is supplied: an auditor\n // who does not know where the origin lives cannot ask this, and\n // guessing would be a check that passes for not looking.\n if (originAddress === undefined) {\n // **Fails, not skips.** This file's own rule, and the suite already\n // had a test for it: an audit that drops a check it could not run\n // reports a posture nobody measured, which reads identically to one\n // measured and found good.\n //\n // Written as a pass first, on the reasoning that most deployments\n // have no separate origin — and that test failed it immediately. The\n // reasoning was wrong in the way this whole audit exists to catch:\n // \"probably fine\" and \"verified\" must not print the same.\n return outcome(\n false,\n \"no origin address given — this posture was not measured \" +\n \"(pass the origin's address as the third argument)\",\n );\n }\n\n // Asked the way an attacker would, which `fetch` cannot.\n //\n // The first version of this check used `fetch` and passed for the wrong\n // reason: TLS fails against a bare IP because the certificate does not\n // name it, the request never reaches the load balancer's backend, and a\n // connection error read as \"refused\". It would have reported a green\n // origin with no policy attached at all.\n //\n // Plain HTTP does not work either — the frontend answers `301` before\n // any backend is chosen, so the policy is never consulted.\n //\n // So: HTTPS to the address, with the real host in SNI, and certificate\n // verification **off**. That is not a lapse. The property under test is\n // whether an address answers a stranger, not who the answer comes from,\n // and refusing to look because the certificate does not match the IP is\n // how the first version passed while proving nothing. Nothing else in\n // this kit may copy it.\n const host = new URL(origin).host;\n const status = await new Promise<number | \"refused\">((resolve) => {\n const request = httpsRequest(\n {\n host: originAddress,\n servername: host,\n headers: { host },\n path: \"/readyz\",\n method: \"GET\",\n rejectUnauthorized: false,\n timeout: 15_000,\n },\n (response) => {\n response.resume();\n resolve(response.statusCode ?? 0);\n },\n );\n request.on(\"error\", () => {\n resolve(\"refused\");\n });\n request.on(\"timeout\", () => {\n request.destroy();\n resolve(\"refused\");\n });\n request.end();\n });\n\n if (status === \"refused\") {\n // Nothing answered at all, which is the strongest form of this.\n return outcome(true, \"the origin address refused the connection\");\n }\n return outcome(\n status === 403,\n `the origin answered ${String(status)} to a direct request`,\n );\n },\n },\n\n {\n id: \"D009_CERT_NAMES_THE_PINNED_HOST\",\n title: \"the certificate names the hostname daemons pin\",\n cites: [],\n async run({ origin, originAddress }) {\n // cloud_008 finding 45. The load balancer held one certificate, for the\n // *origin* hostname, and `hub.byollm.cloud` — the name every daemon\n // pins and the edge validates — was not on it. Cloudflare cannot verify\n // a certificate that does not name what it asked for, so the zone sat\n // on plain Full: encrypted to the origin, not checking who the origin\n // is, while every daemon's pinned site keys arrive through it.\n //\n // Nothing said so. \"There is a certificate\" and \"there is a certificate\n // for the name being validated\" printed identically, which is why this\n // check exists rather than a note in a runbook.\n //\n // Asked over TLS with the real SNI and read from the peer, so it is the\n // certificate actually served rather than one somebody configured.\n const host = new URL(origin).host;\n if (originAddress === undefined) {\n return outcome(\n false,\n \"no origin address given — this posture was not measured. \" +\n \"Asking the hostname reads the edge's certificate, which names it \" +\n \"by construction and proves nothing about the origin\",\n );\n }\n const served = await servedCertificate(originAddress, host);\n const names = served?.names;\n\n if (names === undefined) {\n return outcome(\n false,\n `could not read a certificate from ${originAddress}`,\n );\n }\n const covered = names.some(\n (name) =>\n name === host ||\n (name.startsWith(\"*.\") && host.endsWith(name.slice(1))),\n );\n return outcome(\n covered,\n covered\n ? `served a certificate naming ${host}`\n : `the certificate names ${names.join(\", \")} — not ${host}`,\n );\n },\n },\n\n {\n id: \"D010_CERT_HAS_LIFE_LEFT\",\n title: \"the certificate is not about to expire\",\n cites: [],\n async run({ origin, originAddress }) {\n // A long-lived certificate is the kind whose expiry gets written in a\n // note and never looked at again. The one this deployment now depends\n // on runs to 2041, which makes it *more* likely to be forgotten, not\n // less — and it is load-bearing: it is what the edge validates before\n // it will carry a daemon's traffic at all.\n //\n // Measured from the artefact rather than from the note. A date somebody\n // owns has to mean a date something checks.\n //\n // Ninety days: long enough that a renewal is scheduled rather than\n // scrambled, short enough that the warning is still about something\n // real.\n const host = new URL(origin).host;\n if (originAddress === undefined) {\n return outcome(\n false,\n \"no origin address given — this posture was not measured \" +\n \"(the edge's certificate is Cloudflare's to renew, not ours)\",\n );\n }\n const served = await servedCertificate(originAddress, host);\n if (served === undefined) {\n return outcome(\n false,\n `could not read a certificate from ${originAddress}`,\n );\n }\n const days = Math.round(\n (Date.parse(served.validTo) - Date.now()) / 86_400_000,\n );\n return outcome(\n days > 90,\n `the certificate expires ${served.validTo} (${String(days)} days)`,\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 /** The origin behind the edge, for `D008`. */\n originAddress?: 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 ...(options.originAddress === undefined\n ? {}\n : { originAddress: options.originAddress }),\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":[]}
|