feat(domain-access): load trusted signer registry

This commit is contained in:
冰朔 2026-08-10 02:34:05 +08:00
commit 6bd95c76e9
7 changed files with 318 additions and 17 deletions

View file

@ -12,6 +12,7 @@
"diff": "^7.0.0",
"express": "^5.1.0",
"gray-matter": "^4.0.3",
"lucide-react": "^0.468.0",
"marked": "^15.0.0",
"simple-git": "^3.27.0"
},
@ -2352,6 +2353,15 @@
"yallist": "^3.0.2"
}
},
"node_modules/lucide-react": {
"version": "0.468.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.468.0.tgz",
"integrity": "sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
}
},
"node_modules/marked": {
"version": "15.0.12",
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz",
@ -2638,7 +2648,6 @@
"version": "19.2.8",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
"integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"

View file

@ -16,6 +16,7 @@
"cors": "^2.8.5",
"simple-git": "^3.27.0",
"gray-matter": "^4.0.3",
"lucide-react": "^0.468.0",
"marked": "^15.0.0",
"diff": "^7.0.0"
},

View file

@ -6,16 +6,44 @@ import {
evaluateDomainAccess,
parseDomainAccessHandoff,
} from './domain-access.js';
import {
parseTrustedManifestSignerRegistry,
resolveTrustedManifestSigner,
type TrustedManifestSigner,
} from './trusted-signer-registry.js';
const NOW = 1_786_291_200_000;
const COMMIT = 'b'.repeat(40);
const { privateKey, publicKey } = generateKeyPairSync('ed25519');
const trustedSigner = {
algorithm: 'Ed25519',
publicKeyPem: publicKey.export({ format: 'pem', type: 'spki' }).toString(),
repositoryId: 'REPO-014',
signerId: 'GH-LIGHTHOUSE-001',
} as const;
function trustedSignerFromRegistry(overrides: Record<string, unknown> = {}): TrustedManifestSigner {
const parsed = parseTrustedManifestSignerRegistry({
registryId: 'GH-AIOS-TRUSTED-DOMAIN-MANIFEST-SIGNERS-001',
schema: 'gh-aios.trusted-domain-manifest-signers/v1',
signers: [{
algorithm: 'Ed25519',
domainIds: ['DOM-FIFTH-0001'],
publicKeyPem: publicKey.export({ format: 'pem', type: 'spki' }).toString(),
repositoryId: 'REPO-014',
signerId: 'GH-LIGHTHOUSE-001',
status: 'ACTIVE',
...overrides,
}],
state: 'CURRENT',
version: '1.0.0',
}, {
repositoryId: 'REPO-012',
sourceCommit: 'a'.repeat(40),
sourceUrl: 'https://guanghulab.com/code/bingshuo/guanghu-ice-heart',
});
const signer = resolveTrustedManifestSigner(parsed, {
domainId: 'DOM-FIFTH-0001',
repositoryId: String(overrides.repositoryId ?? 'REPO-014'),
signerId: 'GH-LIGHTHOUSE-001',
});
if (!signer) throw new Error('test_trusted_signer_missing');
return signer;
}
const trustedSigner = trustedSignerFromRegistry();
const manifestPayload = {
domainId: 'DOM-FIFTH-0001',
repositoryId: 'REPO-014',
@ -147,7 +175,7 @@ test('trusted signer identity and repository are external inputs, not payload au
validHandoff,
'DOM-FIFTH-0001',
'LOCAL-001',
{ ...trustedSigner, repositoryId: 'REPO-OTHER' },
trustedSignerFromRegistry({ repositoryId: 'REPO-OTHER' }),
NOW,
), /domain_access_handoff_invalid/);
});

View file

@ -1,4 +1,8 @@
import { createHash, verify as verifySignature } from 'node:crypto';
import {
assertRegisteredTrustedManifestSigner,
type TrustedManifestSigner,
} from './trusted-signer-registry.js';
const MANIFEST_SCHEMA = 'gh-aios.domain-manifest/v1' as const;
const SHA256_PATTERN = /^[a-f0-9]{64}$/;
@ -30,13 +34,6 @@ export interface DomainManifestSignedPayload {
sourceCommit: string;
}
export interface TrustedManifestSigner {
algorithm: 'Ed25519';
publicKeyPem: string;
repositoryId: string;
signerId: string;
}
export interface DomainSessionCapability {
capabilityId: string;
domainId: string;
@ -117,6 +114,7 @@ export function parseDomainAccessHandoff(
trustedSigner: TrustedManifestSigner,
now = Date.now(),
): DomainAccessHandoff {
assertRegisteredTrustedManifestSigner(trustedSigner);
if (!isRecord(input) || !hasExactKeys(input, ['connectionReceipt', 'manifest', 'sessionCapability'])) invalidHandoff();
const manifest = input.manifest;
const capability = input.sessionCapability;

View file

@ -0,0 +1,104 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { generateKeyPairSync } from 'node:crypto';
import {
assertRegisteredTrustedManifestSigner,
parseTrustedManifestSignerRegistry,
resolveTrustedManifestSigner,
} from './trusted-signer-registry.js';
const COMMIT = 'd'.repeat(40);
const SOURCE = {
repositoryId: 'REPO-012',
sourceCommit: COMMIT,
sourceUrl: 'https://guanghulab.com/code/bingshuo/guanghu-ice-heart',
} as const;
const publicKeyPem = generateKeyPairSync('ed25519').publicKey
.export({ format: 'pem', type: 'spki' }).toString();
function registry(signers: unknown[] = []) {
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 signer(overrides: Record<string, unknown> = {}) {
return {
algorithm: 'Ed25519',
domainIds: ['DOM-FIFTH-0001'],
publicKeyPem,
repositoryId: 'REPO-014',
signerId: 'GH-LIGHTHOUSE-001',
status: 'ACTIVE',
...overrides,
};
}
test('an empty current registry is safe and trusts no signer', () => {
const parsed = parseTrustedManifestSignerRegistry(registry(), SOURCE);
assert.equal(parsed.signers.length, 0);
assert.equal(resolveTrustedManifestSigner(parsed, {
domainId: 'DOM-FIFTH-0001',
repositoryId: 'REPO-014',
signerId: 'GH-LIGHTHOUSE-001',
}), null);
});
test('an active Ed25519 SPKI signer resolves only for its exact domain and repository', () => {
const parsed = parseTrustedManifestSignerRegistry(registry([signer()]), SOURCE);
const trusted = resolveTrustedManifestSigner(parsed, {
domainId: 'DOM-FIFTH-0001',
repositoryId: 'REPO-014',
signerId: 'GH-LIGHTHOUSE-001',
});
assert.ok(trusted);
assert.equal(assertRegisteredTrustedManifestSigner(trusted), trusted);
assert.equal(resolveTrustedManifestSigner(parsed, {
domainId: 'DOMAIN-OTHER',
repositoryId: 'REPO-014',
signerId: 'GH-LIGHTHOUSE-001',
}), null);
});
test('copied signer fields do not cross the parsed-registry trust boundary', () => {
const parsed = parseTrustedManifestSignerRegistry(registry([signer()]), SOURCE);
const trusted = resolveTrustedManifestSigner(parsed, {
domainId: 'DOM-FIFTH-0001',
repositoryId: 'REPO-014',
signerId: 'GH-LIGHTHOUSE-001',
});
assert.ok(trusted);
assert.throws(() => assertRegisteredTrustedManifestSigner({ ...trusted }), /trusted_manifest_signer_unregistered/);
});
test('revoked signers stay parseable for history but never resolve', () => {
const parsed = parseTrustedManifestSignerRegistry(registry([signer({ status: 'REVOKED' })]), SOURCE);
assert.equal(resolveTrustedManifestSigner(parsed, {
domainId: 'DOM-FIFTH-0001',
repositoryId: 'REPO-014',
signerId: 'GH-LIGHTHOUSE-001',
}), null);
});
test('duplicates, unknown fields and unsupported algorithms fail closed', () => {
assert.throws(() => parseTrustedManifestSignerRegistry(registry([signer(), signer()]), SOURCE), /trusted_signer_registry_invalid/);
assert.throws(() => parseTrustedManifestSignerRegistry({ ...registry(), extra: true }, SOURCE), /trusted_signer_registry_invalid/);
assert.throws(() => parseTrustedManifestSignerRegistry(registry([signer({ algorithm: 'RSA' })]), SOURCE), /trusted_signer_registry_invalid/);
});
test('private keys and malformed public keys fail closed', () => {
const privateKeyPem = generateKeyPairSync('ed25519').privateKey
.export({ format: 'pem', type: 'pkcs8' }).toString();
assert.throws(() => parseTrustedManifestSignerRegistry(registry([signer({ publicKeyPem: privateKeyPem })]), SOURCE), /trusted_signer_registry_invalid/);
assert.throws(() => parseTrustedManifestSignerRegistry(registry([signer({ publicKeyPem: 'not-a-key' })]), SOURCE), /trusted_signer_registry_invalid/);
});
test('registry source provenance requires exact Guanghu HTTPS and a full commit', () => {
assert.throws(() => parseTrustedManifestSignerRegistry(registry(), { ...SOURCE, sourceCommit: 'short' }), /trusted_signer_registry_source_invalid/);
assert.throws(() => parseTrustedManifestSignerRegistry(registry(), { ...SOURCE, sourceUrl: 'https://example.com/registry.json' }), /trusted_signer_registry_source_invalid/);
assert.throws(() => parseTrustedManifestSignerRegistry(registry(), { ...SOURCE, sourceUrl: 'https://user:pass@guanghulab.com/registry.json' }), /trusted_signer_registry_source_invalid/);
});

View file

@ -0,0 +1,162 @@
import { createPublicKey } from 'node:crypto';
const REGISTRY_SCHEMA = 'gh-aios.trusted-domain-manifest-signers/v1' as const;
const COMMIT_PATTERN = /^[a-f0-9]{40}(?:[a-f0-9]{24})?$/;
const IDENTIFIER_PATTERN = /^[A-Z0-9][A-Z0-9._:-]{1,159}$/;
const VERSION_PATTERN = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
const registeredTrustedSigners = new WeakSet<object>();
export interface TrustedManifestSigner {
algorithm: 'Ed25519';
domainIds: readonly string[];
publicKeyPem: string;
repositoryId: string;
signerId: string;
status: 'ACTIVE' | 'REVOKED';
}
export interface TrustedSignerRegistrySource {
repositoryId: 'REPO-012';
sourceCommit: string;
sourceUrl: string;
}
export interface TrustedManifestSignerRegistry {
registryId: 'GH-AIOS-TRUSTED-DOMAIN-MANIFEST-SIGNERS-001';
schema: typeof REGISTRY_SCHEMA;
signers: readonly TrustedManifestSigner[];
source: Readonly<TrustedSignerRegistrySource>;
state: 'CURRENT';
version: string;
}
export interface TrustedSignerLookup {
domainId: string;
repositoryId: string;
signerId: string;
}
function invalidRegistry(): never {
throw new Error('trusted_signer_registry_invalid');
}
function invalidSource(): never {
throw new Error('trusted_signer_registry_source_invalid');
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function hasExactKeys(record: Record<string, unknown>, keys: string[]): boolean {
const expected = [...keys].sort();
const actual = Object.keys(record).sort();
return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
}
function isIdentifier(value: unknown): value is string {
return typeof value === 'string' && IDENTIFIER_PATTERN.test(value);
}
function parseSource(source: TrustedSignerRegistrySource): Readonly<TrustedSignerRegistrySource> {
if (!isRecord(source)
|| !hasExactKeys(source, ['repositoryId', 'sourceCommit', 'sourceUrl'])
|| source.repositoryId !== 'REPO-012'
|| typeof source.sourceCommit !== 'string'
|| !COMMIT_PATTERN.test(source.sourceCommit)
|| typeof source.sourceUrl !== 'string') invalidSource();
let url: URL;
try {
url = new URL(source.sourceUrl);
} catch {
invalidSource();
}
if (url.protocol !== 'https:'
|| url.hostname !== 'guanghulab.com'
|| url.port
|| url.username
|| url.password
|| url.search
|| url.hash) invalidSource();
return Object.freeze({ ...source });
}
function parsePublicKey(value: unknown): string {
if (typeof value !== 'string'
|| value.length > 4096
|| value.includes('PRIVATE KEY')
|| !value.startsWith('-----BEGIN PUBLIC KEY-----\n')
|| !value.endsWith('-----END PUBLIC KEY-----\n')) invalidRegistry();
try {
const key = createPublicKey({ format: 'pem', key: value });
if (key.asymmetricKeyType !== 'ed25519') invalidRegistry();
} catch {
invalidRegistry();
}
return value;
}
function parseSigner(input: unknown): TrustedManifestSigner {
if (!isRecord(input)
|| !hasExactKeys(input, ['algorithm', 'domainIds', 'publicKeyPem', 'repositoryId', 'signerId', 'status'])
|| input.algorithm !== 'Ed25519'
|| !isIdentifier(input.repositoryId)
|| !isIdentifier(input.signerId)
|| (input.status !== 'ACTIVE' && input.status !== 'REVOKED')
|| !Array.isArray(input.domainIds)
|| input.domainIds.length === 0
|| input.domainIds.some(domainId => !isIdentifier(domainId))
|| new Set(input.domainIds).size !== input.domainIds.length) invalidRegistry();
const signer: TrustedManifestSigner = Object.freeze({
algorithm: 'Ed25519',
domainIds: Object.freeze([...input.domainIds] as string[]),
publicKeyPem: parsePublicKey(input.publicKeyPem),
repositoryId: input.repositoryId,
signerId: input.signerId,
status: input.status,
});
registeredTrustedSigners.add(signer);
return signer;
}
export function parseTrustedManifestSignerRegistry(
input: unknown,
source: TrustedSignerRegistrySource,
): TrustedManifestSignerRegistry {
if (!isRecord(input)
|| !hasExactKeys(input, ['registryId', 'schema', 'signers', 'state', 'version'])
|| input.registryId !== 'GH-AIOS-TRUSTED-DOMAIN-MANIFEST-SIGNERS-001'
|| input.schema !== REGISTRY_SCHEMA
|| input.state !== 'CURRENT'
|| typeof input.version !== 'string'
|| !VERSION_PATTERN.test(input.version)
|| !Array.isArray(input.signers)) invalidRegistry();
const signers = input.signers.map(parseSigner);
if (new Set(signers.map(signer => signer.signerId)).size !== signers.length) invalidRegistry();
return Object.freeze({
registryId: input.registryId,
schema: input.schema,
signers: Object.freeze(signers),
source: parseSource(source),
state: input.state,
version: input.version,
});
}
export function assertRegisteredTrustedManifestSigner(
signer: TrustedManifestSigner,
): TrustedManifestSigner {
if (!registeredTrustedSigners.has(signer)) throw new Error('trusted_manifest_signer_unregistered');
return signer;
}
export function resolveTrustedManifestSigner(
registry: TrustedManifestSignerRegistry,
lookup: TrustedSignerLookup,
): TrustedManifestSigner | null {
const signer = registry.signers.find(candidate => candidate.status === 'ACTIVE'
&& candidate.signerId === lookup.signerId
&& candidate.repositoryId === lookup.repositoryId
&& candidate.domainIds.includes(lookup.domainId));
return signer ? assertRegisteredTrustedManifestSigner(signer) : null;
}

View file

@ -15,8 +15,7 @@
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@server/*": ["./server/*"],
"marked": ["../hololake-desktop/node_modules/marked/lib/marked.esm.js"]
"@server/*": ["./server/*"]
}
},
"include": ["src/**/*", "server/**/*"],