companion-shell-data-integrity.test.mjs
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