Bind domain access to registered node type

This commit is contained in:
冰朔 2026-08-10 06:28:47 +08:00
commit 8807b99d98
15 changed files with 168 additions and 63 deletions

View file

@ -8,6 +8,7 @@ import { TrustedSignerSnapshotLoader } from './trusted-signer-snapshot.js';
const NOW = 1_786_291_200_000;
const DOMAIN_ID = 'DOM-FIFTH-0001';
const NODE_ID = 'LOCAL-001';
const NODE_TYPE = 'local-terminal' as const;
const COMMIT = 'a'.repeat(40);
const ANCHOR_URL = 'https://guanghulab.com/api/ai/v1/anchor';
const REGISTRY_URL = `https://guanghulab.com/code/bingshuo/guanghu-ice-heart/raw/commit/${COMMIT}/routing/trusted-domain-manifest-signers.json`;
@ -85,6 +86,7 @@ function validHandoff() {
domainId: DOMAIN_ID,
manifestDigest: digest,
nodeId: NODE_ID,
nodeType: NODE_TYPE,
receiptId: 'RECEIPT-001',
state: 'online',
},
@ -98,6 +100,7 @@ function validHandoff() {
domainId: DOMAIN_ID,
expiresAt: NOW + 60_000,
nodeId: NODE_ID,
nodeType: NODE_TYPE,
scopes: ['domain:enter'],
},
};
@ -107,11 +110,11 @@ test('projects public trust health without asking for a handoff before login', a
let handoffReads = 0;
const orchestrator = new DomainAccessOrchestrator(
loader(),
{ async read() { return { accountVerified: false, nodeId: '' }; } },
{ async read() { return { accountVerified: false, nodeId: '', nodeRegistrationVerified: false }; } },
{ async read() { handoffReads += 1; return null; } },
);
const status = await orchestrator.domainAccess(DOMAIN_ID, NOW);
const status = await orchestrator.domainAccess(DOMAIN_ID, NODE_TYPE, NOW);
assert.equal(handoffReads, 0);
assert.equal(status.stage, 'login-required');
@ -128,21 +131,36 @@ test('projects public trust health without asking for a handoff before login', a
test('an authenticated node without a verified handoff remains identity-only', async () => {
const orchestrator = new DomainAccessOrchestrator(
loader(),
{ async read() { return { accountVerified: true, nodeId: NODE_ID }; } },
{ async read() { return { accountVerified: true, nodeId: NODE_ID, nodeRegistrationVerified: true }; } },
{ async read() { return null; } },
);
const status = await orchestrator.domainAccess(DOMAIN_ID, NOW);
const status = await orchestrator.domainAccess(DOMAIN_ID, NODE_TYPE, NOW);
assert.equal(status.stage, 'identity-verified');
assert.equal(status.runtimeReady, false);
assert.ok(status.blockers.includes('verified_domain_manifest_missing'));
});
test('a code-channel account without node registration never contacts a domain handoff route', async () => {
let handoffReads = 0;
const orchestrator = new DomainAccessOrchestrator(
loader(),
{ async read() { return { accountVerified: true, nodeId: NODE_ID, nodeRegistrationVerified: false }; } },
{ async read() { handoffReads += 1; return validHandoff() as never; } },
);
const status = await orchestrator.domainAccess(DOMAIN_ID, NODE_TYPE, NOW);
assert.equal(handoffReads, 0);
assert.equal(status.stage, 'login-required');
assert.ok(status.blockers.includes('verified_node_registration_missing'));
});
test('a loaded signer snapshot and verified handoff project runtime-ready', async () => {
const orchestrator = new DomainAccessOrchestrator(
loader(() => registry([activeSigner()])),
{ async read() { return { accountVerified: true, nodeId: NODE_ID }; } },
{ async read() { return { accountVerified: true, nodeId: NODE_ID, nodeRegistrationVerified: true }; } },
{ async read() {
return {
handoff: validHandoff(),
@ -151,7 +169,7 @@ test('a loaded signer snapshot and verified handoff project runtime-ready', asyn
} },
);
const status = await orchestrator.domainAccess(DOMAIN_ID, NOW);
const status = await orchestrator.domainAccess(DOMAIN_ID, NODE_TYPE, NOW);
assert.equal(status.stage, 'runtime-ready');
assert.equal(status.runtimeReady, true);
@ -162,11 +180,11 @@ test('a loaded signer snapshot and verified handoff project runtime-ready', asyn
test('source and handoff failures are reduced to safe status without raw details', async () => {
const orchestrator = new DomainAccessOrchestrator(
new TrustedSignerSnapshotLoader({ async fetchJson() { throw new Error('secret source detail'); } }),
{ async read() { return { accountVerified: true, nodeId: NODE_ID }; } },
{ async read() { return { accountVerified: true, nodeId: NODE_ID, nodeRegistrationVerified: true }; } },
{ async read() { throw new Error('secret handoff detail'); } },
);
const status = await orchestrator.domainAccess(DOMAIN_ID, NOW);
const status = await orchestrator.domainAccess(DOMAIN_ID, NODE_TYPE, NOW);
assert.equal(status.stage, 'identity-verified');
assert.equal(status.runtimeReady, false);
@ -182,7 +200,7 @@ test('a last-known-good signer can project access while preserving degraded heal
currentRegistry = { ...registry([activeSigner()]), version: 'invalid' };
const orchestrator = new DomainAccessOrchestrator(
signerLoader,
{ async read() { return { accountVerified: true, nodeId: NODE_ID }; } },
{ async read() { return { accountVerified: true, nodeId: NODE_ID, nodeRegistrationVerified: true }; } },
{ async read() {
return {
handoff: validHandoff(),
@ -191,7 +209,7 @@ test('a last-known-good signer can project access while preserving degraded heal
} },
);
const status = await orchestrator.domainAccess(DOMAIN_ID, NOW);
const status = await orchestrator.domainAccess(DOMAIN_ID, NODE_TYPE, NOW);
assert.equal(status.runtimeReady, true);
assert.equal(status.trustSource.status, 'DEGRADED_LAST_KNOWN_GOOD');