Add strict domain handoff response adapter
This commit is contained in:
parent
a9f244d781
commit
066f14d007
2 changed files with 132 additions and 0 deletions
|
|
@ -0,0 +1,72 @@
|
||||||
|
import test from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { StrictDomainRuntimeHandoffSource } from './domain-runtime-handoff-source.js';
|
||||||
|
|
||||||
|
const DOMAIN_ID = 'DOM-FIFTH-0001';
|
||||||
|
const NODE_ID = 'JD-FD-PRIMARY';
|
||||||
|
|
||||||
|
function response(overrides: Record<string, unknown> = {}) {
|
||||||
|
return {
|
||||||
|
schema: 'gh-aios.domain-runtime-handoff-response/v1',
|
||||||
|
handoff: { manifest: { digest: 'untrusted-until-orchestrator-verifies' } },
|
||||||
|
signer_lookup: {
|
||||||
|
repository_id: 'REPO-014',
|
||||||
|
signer_id: 'GH-LIGHTHOUSE-001',
|
||||||
|
},
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test('adapts one exact endpoint-neutral response without interpreting signed evidence', async () => {
|
||||||
|
const requests: unknown[] = [];
|
||||||
|
const source = new StrictDomainRuntimeHandoffSource({
|
||||||
|
async request(input) {
|
||||||
|
requests.push(input);
|
||||||
|
return response();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const candidate = await source.read(DOMAIN_ID, NODE_ID);
|
||||||
|
|
||||||
|
assert.deepEqual(requests, [{ domainId: DOMAIN_ID, nodeId: NODE_ID }]);
|
||||||
|
assert.deepEqual(candidate, {
|
||||||
|
handoff: { manifest: { digest: 'untrusted-until-orchestrator-verifies' } },
|
||||||
|
signerLookup: { repositoryId: 'REPO-014', signerId: 'GH-LIGHTHOUSE-001' },
|
||||||
|
});
|
||||||
|
assert.equal(Object.isFrozen(candidate), true);
|
||||||
|
assert.equal(Object.isFrozen(candidate?.signerLookup), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rejects malformed, extended and self-authorizing response envelopes', async () => {
|
||||||
|
const samples = [
|
||||||
|
null,
|
||||||
|
response({ extra: true }),
|
||||||
|
response({ schema: 'other/v1' }),
|
||||||
|
response({ signer_lookup: { repository_id: 'REPO-014', signer_id: 'bad signer' } }),
|
||||||
|
response({ signer_lookup: { repository_id: 'REPO-014', signer_id: 'GH-LIGHTHOUSE-001', public_key: 'forbidden' } }),
|
||||||
|
response({ handoff: null }),
|
||||||
|
];
|
||||||
|
let index = 0;
|
||||||
|
const source = new StrictDomainRuntimeHandoffSource({
|
||||||
|
async request() { return samples[index++]; },
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const _sample of samples) {
|
||||||
|
assert.equal(await source.read(DOMAIN_ID, NODE_ID), null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fails closed on invalid request identity and transport errors without leaking details', async () => {
|
||||||
|
let requests = 0;
|
||||||
|
const source = new StrictDomainRuntimeHandoffSource({
|
||||||
|
async request() {
|
||||||
|
requests += 1;
|
||||||
|
throw new Error('secret remote detail');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(await source.read('bad domain', NODE_ID), null);
|
||||||
|
assert.equal(requests, 0);
|
||||||
|
assert.equal(await source.read(DOMAIN_ID, NODE_ID), null);
|
||||||
|
assert.equal(requests, 1);
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
import type {
|
||||||
|
DomainRuntimeHandoffCandidate,
|
||||||
|
DomainRuntimeHandoffSource,
|
||||||
|
} from './domain-access-orchestrator.js';
|
||||||
|
|
||||||
|
const IDENTIFIER_PATTERN = /^[A-Z0-9][A-Z0-9._:-]{1,159}$/;
|
||||||
|
|
||||||
|
export interface DomainRuntimeHandoffRequest {
|
||||||
|
domainId: string;
|
||||||
|
nodeId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DomainRuntimeHandoffTransport {
|
||||||
|
request(input: Readonly<DomainRuntimeHandoffRequest>): Promise<unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||||
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasExactKeys(value: Record<string, unknown>, expected: readonly string[]): boolean {
|
||||||
|
const actual = Object.keys(value).sort();
|
||||||
|
const keys = [...expected].sort();
|
||||||
|
return actual.length === keys.length && actual.every((key, index) => key === keys[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseResponse(input: unknown): Readonly<DomainRuntimeHandoffCandidate> | null {
|
||||||
|
if (!isRecord(input)
|
||||||
|
|| !hasExactKeys(input, ['handoff', 'schema', 'signer_lookup'])
|
||||||
|
|| input.schema !== 'gh-aios.domain-runtime-handoff-response/v1'
|
||||||
|
|| !isRecord(input.handoff)
|
||||||
|
|| !isRecord(input.signer_lookup)
|
||||||
|
|| !hasExactKeys(input.signer_lookup, ['repository_id', 'signer_id'])
|
||||||
|
|| typeof input.signer_lookup.repository_id !== 'string'
|
||||||
|
|| !IDENTIFIER_PATTERN.test(input.signer_lookup.repository_id)
|
||||||
|
|| typeof input.signer_lookup.signer_id !== 'string'
|
||||||
|
|| !IDENTIFIER_PATTERN.test(input.signer_lookup.signer_id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Object.freeze({
|
||||||
|
handoff: input.handoff,
|
||||||
|
signerLookup: Object.freeze({
|
||||||
|
repositoryId: input.signer_lookup.repository_id,
|
||||||
|
signerId: input.signer_lookup.signer_id,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StrictDomainRuntimeHandoffSource implements DomainRuntimeHandoffSource {
|
||||||
|
constructor(private readonly transport: DomainRuntimeHandoffTransport) {}
|
||||||
|
|
||||||
|
async read(domainId: string, nodeId: string): Promise<Readonly<DomainRuntimeHandoffCandidate> | null> {
|
||||||
|
if (!IDENTIFIER_PATTERN.test(domainId) || !IDENTIFIER_PATTERN.test(nodeId)) return null;
|
||||||
|
try {
|
||||||
|
return parseResponse(await this.transport.request(Object.freeze({ domainId, nodeId })));
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue