diff --git a/product-source/guanghu-knowledge-base/server/domain-access.test.ts b/product-source/guanghu-knowledge-base/server/domain-access.test.ts index 6b978b2..4b2520e 100644 --- a/product-source/guanghu-knowledge-base/server/domain-access.test.ts +++ b/product-source/guanghu-knowledge-base/server/domain-access.test.ts @@ -5,12 +5,14 @@ import { domainManifestSigningBytes, evaluateDomainAccess, parseDomainAccessHandoff, + verifyDomainAccessHandoffFromSnapshot, } from './domain-access.js'; import { parseTrustedManifestSignerRegistry, resolveTrustedManifestSigner, type TrustedManifestSigner, } from './trusted-signer-registry.js'; +import { TrustedSignerSnapshotLoader } from './trusted-signer-snapshot.js'; const NOW = 1_786_291_200_000; const COMMIT = 'b'.repeat(40); @@ -84,6 +86,62 @@ const verifiedHandoff = parseDomainAccessHandoff( NOW, ); +const SNAPSHOT_COMMIT = 'a'.repeat(40); +const SNAPSHOT_ANCHOR_URL = 'https://guanghulab.com/api/ai/v1/anchor'; +const SNAPSHOT_REGISTRY_URL = `https://guanghulab.com/code/bingshuo/guanghu-ice-heart/raw/commit/${SNAPSHOT_COMMIT}/routing/trusted-domain-manifest-signers.json`; + +function snapshotAnchor() { + return { + schema: 'guanghu.public-navigation-anchor/v1', + anchor_id: 'GLW-PUBLIC-NAV-ANCHOR-001', + state: 'CURRENT_CANONICAL', + repository_id: 'REPO-012', + branch: 'main', + public_entry: SNAPSHOT_ANCHOR_URL, + code_entry: 'https://guanghulab.com/code/bingshuo/guanghu-ice-heart', + maps: { + trusted_domain_manifest_signers: { + path: 'routing/trusted-domain-manifest-signers.json', + id: 'GH-AIOS-TRUSTED-DOMAIN-MANIFEST-SIGNERS-001', + version: '1.0.0', + }, + }, + navigation_source: { + anchor_id: 'GLW-PUBLIC-NAV-ANCHOR-001', + source_commit: SNAPSHOT_COMMIT, + source_mode: 'REPO-012_MAIN_GIT_SNAPSHOT', + source_degraded: false, + }, + }; +} + +function snapshotRegistry(signers: unknown[] = [{ + algorithm: 'Ed25519', + domainIds: ['DOM-FIFTH-0001'], + publicKeyPem: publicKey.export({ format: 'pem', type: 'spki' }).toString(), + repositoryId: 'REPO-014', + signerId: 'GH-LIGHTHOUSE-001', + status: 'ACTIVE', +}]) { + return { + registryId: 'GH-AIOS-TRUSTED-DOMAIN-MANIFEST-SIGNERS-001', + schema: 'gh-aios.trusted-domain-manifest-signers/v1', + signers, + state: 'CURRENT', + version: '1.0.0', + }; +} + +function snapshotLoader(readRegistry: () => unknown) { + return new TrustedSignerSnapshotLoader({ + async fetchJson(url) { + if (url === SNAPSHOT_ANCHOR_URL) return snapshotAnchor(); + if (url === SNAPSHOT_REGISTRY_URL) return readRegistry(); + throw new Error('unexpected_url'); + }, + }); +} + test('a local workspace remains available without claiming domain runtime access', () => { const status = evaluateDomainAccess({ accountVerified: false, domainId: 'DOM-FIFTH-0001', nodeId: '' }, NOW); assert.equal(status.localWorkspaceAllowed, true); @@ -114,6 +172,77 @@ test('runtime access requires matching manifest, scoped capability and online re assert.deepEqual(status.blockers, []); }); +test('the runtime handoff entry resolves its signer only from a loaded snapshot', async () => { + const snapshot = await snapshotLoader(() => snapshotRegistry()).refresh(); + const verified = verifyDomainAccessHandoffFromSnapshot( + validHandoff, + 'DOM-FIFTH-0001', + 'LOCAL-001', + { repositoryId: 'REPO-014', signerId: 'GH-LIGHTHOUSE-001' }, + snapshot, + NOW, + ); + + assert.equal(verified.trustSource.status, 'CURRENT'); + assert.equal(verified.trustSource.sourceCommit, SNAPSHOT_COMMIT); + assert.equal(evaluateDomainAccess({ + accountVerified: true, + domainId: 'DOM-FIFTH-0001', + nodeId: 'LOCAL-001', + ...verified.handoff, + }, NOW).runtimeReady, true); +}); + +test('an empty, forged or mismatched snapshot cannot open the runtime handoff', async () => { + const empty = await snapshotLoader(() => snapshotRegistry([])).refresh(); + assert.throws(() => verifyDomainAccessHandoffFromSnapshot( + validHandoff, + 'DOM-FIFTH-0001', + 'LOCAL-001', + { repositoryId: 'REPO-014', signerId: 'GH-LIGHTHOUSE-001' }, + empty, + NOW, + ), /domain_access_handoff_invalid/); + + const loaded = await snapshotLoader(() => snapshotRegistry()).refresh(); + assert.throws(() => verifyDomainAccessHandoffFromSnapshot( + validHandoff, + 'DOM-FIFTH-0001', + 'LOCAL-001', + { repositoryId: 'REPO-014', signerId: 'GH-LIGHTHOUSE-001' }, + { ...loaded }, + NOW, + ), /domain_access_handoff_invalid/); + assert.throws(() => verifyDomainAccessHandoffFromSnapshot( + validHandoff, + 'DOM-FIFTH-0001', + 'LOCAL-001', + { repositoryId: 'REPO-OTHER', signerId: 'GH-LIGHTHOUSE-001' }, + loaded, + NOW, + ), /domain_access_handoff_invalid/); +}); + +test('a clearly degraded last-known-good snapshot remains usable without claiming freshness', async () => { + let registry: unknown = snapshotRegistry(); + const loader = snapshotLoader(() => registry); + await loader.refresh(); + registry = { ...snapshotRegistry(), version: 'invalid' }; + const degraded = await loader.refresh(); + + const verified = verifyDomainAccessHandoffFromSnapshot( + validHandoff, + 'DOM-FIFTH-0001', + 'LOCAL-001', + { repositoryId: 'REPO-014', signerId: 'GH-LIGHTHOUSE-001' }, + degraded, + NOW, + ); + assert.equal(verified.trustSource.status, 'DEGRADED_LAST_KNOWN_GOOD'); + assert.equal(verified.trustSource.reason, 'REGISTRY_INVALID'); + assert.equal(verified.trustSource.sourceCommit, SNAPSHOT_COMMIT); +}); + test('mismatched or expired evidence fails closed', () => { const status = evaluateDomainAccess({ accountVerified: true, diff --git a/product-source/guanghu-knowledge-base/server/domain-access.ts b/product-source/guanghu-knowledge-base/server/domain-access.ts index 1a5ee6d..fca432b 100644 --- a/product-source/guanghu-knowledge-base/server/domain-access.ts +++ b/product-source/guanghu-knowledge-base/server/domain-access.ts @@ -1,8 +1,15 @@ import { createHash, verify as verifySignature } from 'node:crypto'; import { assertRegisteredTrustedManifestSigner, + resolveTrustedManifestSigner, type TrustedManifestSigner, + type TrustedSignerLookup, } from './trusted-signer-registry.js'; +import { + assertLoadedTrustedSignerSnapshot, + type TrustedSignerSnapshotReceipt, + type TrustedSignerSnapshotResult, +} from './trusted-signer-snapshot.js'; const MANIFEST_SCHEMA = 'gh-aios.domain-manifest/v1' as const; const SHA256_PATTERN = /^[a-f0-9]{64}$/; @@ -57,6 +64,11 @@ export interface DomainAccessHandoff { sessionCapability: DomainSessionCapability; } +export interface DomainAccessHandoffVerification { + handoff: DomainAccessHandoff; + trustSource: Readonly; +} + export interface DomainAccessEvidence { accountVerified: boolean; connectionReceipt?: DomainConnectionReceipt; @@ -185,6 +197,38 @@ export function parseDomainAccessHandoff( return handoff; } +export function verifyDomainAccessHandoffFromSnapshot( + input: unknown, + expectedDomainId: string, + expectedNodeId: string, + signerLookup: Omit, + snapshot: TrustedSignerSnapshotResult, + now = Date.now(), +): DomainAccessHandoffVerification { + try { + const loaded = assertLoadedTrustedSignerSnapshot(snapshot); + const registry = loaded.registry; + const source = loaded.receipt; + if (!registry + || source.status === 'UNAVAILABLE' + || source.sourceCommit !== registry.source.sourceCommit + || source.registryVersion !== registry.version + || source.signerCount !== registry.signers.length) invalidHandoff(); + const trustedSigner = resolveTrustedManifestSigner(registry, { + domainId: expectedDomainId, + repositoryId: signerLookup.repositoryId, + signerId: signerLookup.signerId, + }); + if (!trustedSigner) invalidHandoff(); + return Object.freeze({ + handoff: parseDomainAccessHandoff(input, expectedDomainId, expectedNodeId, trustedSigner, now), + trustSource: source, + }); + } catch { + invalidHandoff(); + } +} + export function evaluateDomainAccess(evidence: DomainAccessEvidence, now = Date.now()): DomainAccessStatus { const blockers: string[] = []; if (!evidence.accountVerified || !evidence.nodeId) blockers.push('account_node_identity_missing'); diff --git a/product-source/guanghu-knowledge-base/server/trusted-signer-snapshot.test.ts b/product-source/guanghu-knowledge-base/server/trusted-signer-snapshot.test.ts index 2a9565e..abd1370 100644 --- a/product-source/guanghu-knowledge-base/server/trusted-signer-snapshot.test.ts +++ b/product-source/guanghu-knowledge-base/server/trusted-signer-snapshot.test.ts @@ -1,6 +1,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { + assertLoadedTrustedSignerSnapshot, TrustedSignerSnapshotLoader, type TrustedSignerSnapshotTransport, } from './trusted-signer-snapshot.js'; @@ -78,6 +79,8 @@ test('loads the anchor and signer registry from one exact REPO-012 commit', asyn assert.equal(result.receipt.signerCount, 0); assert.ok(result.registry); assert.equal(result.registry.source.sourceCommit, COMMIT); + assert.equal(assertLoadedTrustedSignerSnapshot(result), result); + assert.throws(() => assertLoadedTrustedSignerSnapshot({ ...result }), /trusted_signer_snapshot_unregistered/); assert.equal(resolveTrustedManifestSigner(result.registry, { domainId: 'DOM-FIFTH-0001', repositoryId: 'REPO-014', diff --git a/product-source/guanghu-knowledge-base/server/trusted-signer-snapshot.ts b/product-source/guanghu-knowledge-base/server/trusted-signer-snapshot.ts index 6572ac7..45e92de 100644 --- a/product-source/guanghu-knowledge-base/server/trusted-signer-snapshot.ts +++ b/product-source/guanghu-knowledge-base/server/trusted-signer-snapshot.ts @@ -9,6 +9,7 @@ const REGISTRY_ID = 'GH-AIOS-TRUSTED-DOMAIN-MANIFEST-SIGNERS-001'; const REGISTRY_PATH = 'routing/trusted-domain-manifest-signers.json'; const COMMIT_PATTERN = /^[a-f0-9]{40}(?:[a-f0-9]{24})?$/; const VERSION_PATTERN = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/; +const registeredLoadedSnapshots = new WeakSet(); export interface TrustedSignerSnapshotTransport { fetchJson(url: string): Promise; @@ -98,7 +99,16 @@ function result( registry: TrustedManifestSignerRegistry | null, snapshotReceipt: Readonly, ): TrustedSignerSnapshotResult { - return Object.freeze({ registry, receipt: snapshotReceipt }); + const loaded = Object.freeze({ registry, receipt: snapshotReceipt }); + registeredLoadedSnapshots.add(loaded); + return loaded; +} + +export function assertLoadedTrustedSignerSnapshot( + snapshot: TrustedSignerSnapshotResult, +): TrustedSignerSnapshotResult { + if (!registeredLoadedSnapshots.has(snapshot)) throw new Error('trusted_signer_snapshot_unregistered'); + return snapshot; } export class TrustedSignerSnapshotLoader {