Source-candidate: poe d9a564e6d20f5f0fd75ce45b12cbbf8bb4c9d568\nSource-candidate: magica38ba5762b06716db1dee00d0afec162656488f5c\nValidated321whole-file phase plus whole bus1349/model-proxy100/webui490; final gate tooling checks pending, not landed.
77 lines
4.7 KiB
JavaScript
77 lines
4.7 KiB
JavaScript
// P2 RED: model is implicit, durable/private, and status never exposes current/retiring values.
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { tmpdir } from 'node:os';
|
|
import { randomBytes, createHash } from 'node:crypto';
|
|
import { Credentials } from '../src/credentials.mjs';
|
|
|
|
function fixture(t) {
|
|
const root = fs.mkdtempSync(join(tmpdir(), 'p2-store-'));
|
|
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
const storeRoot = join(root, 'config', 'secrets', 'agents');
|
|
fs.mkdirSync(storeRoot, { recursive: true, mode: 0o700 });
|
|
const open = () => new Credentials({ storeRoot, dataRoot: join(root, 'data'), modelAgents: ['demo/coder'] });
|
|
const file = join(storeRoot, 'demo', 'coder', 'model');
|
|
return { root, storeRoot, open, file };
|
|
}
|
|
const key = () => 'msk-fixture-' + randomBytes(32).toString('base64url');
|
|
const id = value => createHash('sha256').update(value).digest('hex').slice(0, 12);
|
|
const record = value => ({ key: value, keyId: id(value), issuedAt: '2026-10-24T00:00:00.000Z', rotateBy: '2026-11-23', state: 'valid', retiring: [] });
|
|
|
|
test('implicit model kind starts not-issued without a business or role reference', t => {
|
|
const f = fixture(t), c = f.open(); t.after(() => c.close());
|
|
const status = c.status().find(s => s.instance === 'demo/coder' && s.service === 'model');
|
|
assert.equal(status?.state, 'not-issued');
|
|
assert.equal(fs.existsSync(f.file), false);
|
|
});
|
|
test('model record persists at 0600 in 0700 dirs and reloads ids/issue time/state only in status', t => {
|
|
const f = fixture(t), c = f.open(), value = key(); t.after(() => c.close());
|
|
assert.equal(typeof c.writeModel, 'function');
|
|
c.writeModel('demo/coder', record(value));
|
|
assert.equal(fs.statSync(f.file).mode & 0o777, 0o600);
|
|
for (const dir of [f.storeRoot, join(f.storeRoot, 'demo'), join(f.storeRoot, 'demo', 'coder')]) assert.equal(fs.statSync(dir).mode & 0o777, 0o700);
|
|
c.close();
|
|
const again = f.open(); t.after(() => again.close());
|
|
const status = again.status().find(s => s.service === 'model');
|
|
assert.equal(status.keyId === id(value), true);
|
|
assert.equal(status.issuedAt, '2026-10-24T00:00:00.000Z');
|
|
assert.equal(status.state, 'valid');
|
|
assert.equal(JSON.stringify(again.status()).includes(value), false);
|
|
assert.equal(again.modelRecord('demo/coder').key === value, true);
|
|
});
|
|
test('revoking model metadata survives restart without losing the private record', t => {
|
|
const f = fixture(t), c = f.open(), value = key(); t.after(() => c.close());
|
|
assert.equal(typeof c.writeModel, 'function');
|
|
c.writeModel('demo/coder', { ...record(value), state: 'revoking', revokingAt: '2026-10-24T01:00:00.000Z' });
|
|
c.close(); const again = f.open(); t.after(() => again.close());
|
|
assert.equal(again.status().find(s => s.service === 'model').state, 'revoking');
|
|
assert.equal(again.modelRecord('demo/coder').key === value, true);
|
|
assert.equal(JSON.stringify(again.status()).includes(value), false);
|
|
});
|
|
test('model record wrong file mode refuses startup rather than inventing a replacement', t => {
|
|
const f = fixture(t), c = f.open(); t.after(() => c.close());
|
|
assert.equal(typeof c.writeModel, 'function'); c.writeModel('demo/coder', record(key())); c.close();
|
|
fs.chmodSync(f.file, 0o640);
|
|
assert.throws(() => f.open(), e => e.code === 'credential-file');
|
|
});
|
|
test('non-proxy Credentials has no implicit model kind', t => {
|
|
const f = fixture(t), c = new Credentials({ storeRoot: f.storeRoot, dataRoot: join(f.root, 'data') });
|
|
t.after(() => c.close()); assert.deepEqual(c.status(), []);
|
|
});
|
|
test('credential-revoke-failed: generic remove cannot bypass remote model confirmation', t => {
|
|
const f = fixture(t), c = f.open(); t.after(() => c.close());
|
|
c.writeModel('demo/coder', record(key()));
|
|
assert.throws(() => c.remove('demo/coder'), e => e.code === 'credential-revoke-failed');
|
|
assert.equal(c.modelRecord('demo/coder').state, 'valid'); assert.equal(fs.existsSync(f.file), true);
|
|
});
|
|
test('retiring keys reload privately and remain covered by the credential leak guard', t => {
|
|
const f = fixture(t), c = f.open(), value = key(), old = key(); t.after(() => c.close());
|
|
c.writeModel('demo/coder', { ...record(value), retiring: [{ key: old, keyId: id(old), issuedAt: '2026-10-23T00:00:00.000Z', retireAt: '2026-10-24T02:00:00.000Z' }] });
|
|
c.close(); const again = f.open(); t.after(() => again.close());
|
|
assert.equal(again.modelRecord('demo/coder').retiring[0].key === old, true);
|
|
const status = JSON.stringify(again.status()); assert.equal(status.includes(old), false); assert.equal(status.includes(value), false);
|
|
assert.throws(() => again.assertClean({ value: old }), e => e.code === 'credential-leak');
|
|
});
|