feat(knowledge): bind domain handoff to signer snapshot

This commit is contained in:
冰朔 2026-08-10 03:09:53 +08:00
commit 5054d4620f
4 changed files with 187 additions and 1 deletions

View file

@ -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<TrustedSignerSnapshotReceipt>;
}
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<TrustedSignerLookup, 'domainId'>,
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');