companion-shell-data-integrity.test.mjs
87 lines 2.8 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * Tier 5 — DATA-INTEGRITY: Phase 5 integrity and token-rotation invariants.
3 */
4
5 import { describe, it } from 'node:test';
6 import assert from 'node:assert/strict';
7 import crypto from 'node:crypto';
8 import { mkdtemp, readFile, rm } from 'node:fs/promises';
9 import os from 'node:os';
10 import path from 'node:path';
11
12 import { createCompanionInferenceListener } from '../lib/companion-inference-listener.mjs';
13 import {
14 createRuntimeGroup,
15 downloadVerifyAndStageModel,
16 } from '../lib/companion-shell.mjs';
17
18 function sha256(data) {
19 return crypto.createHash('sha256').update(data).digest('hex');
20 }
21
22 describe('downloaded model integrity', () => {
23 it('rejects one-bit corruption and leaves no verified model behind', async () => {
24 const expected = Buffer.from('expected model bytes');
25 const corrupted = Buffer.from(expected);
26 corrupted[0] ^= 0x01;
27 const tmp = await mkdtemp(path.join(os.tmpdir(), 'knowtation-phase5-integrity-'));
28 const verifiedPath = path.join(tmp, 'model.gguf');
29 try {
30 const runtimeGroup = createRuntimeGroup({
31 async download(_url, onChunk) {
32 onChunk(corrupted);
33 },
34 async spawn() {
35 throw new Error('spawn must not run');
36 },
37 async healthCheck() {
38 return false;
39 },
40 });
41
42 await assert.rejects(
43 () => downloadVerifyAndStageModel({
44 runtimeGroup,
45 tempPath: path.join(tmp, 'model.tmp'),
46 verifiedPath,
47 spec: {
48 modelUrl: 'https://cdn.knowtation-models.com/model.gguf',
49 expectedDigest: sha256(expected),
50 expectedSizeBytes: expected.length,
51 allowedSourceUrls: ['https://cdn.knowtation-models.com/'],
52 },
53 }),
54 /integrity_failed/,
55 );
56 await assert.rejects(() => readFile(verifiedPath), /ENOENT/);
57 } finally {
58 await rm(tmp, { recursive: true, force: true });
59 }
60 });
61 });
62
63 describe('loopback token rotation data boundary', () => {
64 it('makes the old loopback token inert after a new listener starts', async () => {
65 let hits = 0;
66 const listener = createCompanionInferenceListener({
67 expectedToken: 'new-loopback-token',
68 runtimeRequest(_req, res) {
69 hits += 1;
70 res.statusCode = 200;
71 res.end('ok');
72 },
73 });
74 const bound = await listener.start();
75 try {
76 const url = `http://127.0.0.1:${bound.port}/v1/models`;
77 const oldToken = await fetch(url, { headers: { Authorization: 'Bearer old-loopback-token' } });
78 assert.equal(oldToken.status, 401);
79 assert.equal(hits, 0);
80 const newToken = await fetch(url, { headers: { Authorization: 'Bearer new-loopback-token' } });
81 assert.equal(newToken.status, 200);
82 assert.equal(hits, 1);
83 } finally {
84 await listener.close();
85 }
86 });
87 });
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago