feat: anchor domain runtime handoff transport
This commit is contained in:
parent
7cb5de1a0e
commit
9994d81fd2
9 changed files with 759 additions and 19 deletions
|
|
@ -0,0 +1,66 @@
|
|||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
assertRegisteredDomainRuntimeHandoffEndpoint,
|
||||
parseDomainRuntimeHandoffEndpointRegistry,
|
||||
resolveDomainRuntimeHandoffEndpoint,
|
||||
} from './domain-runtime-handoff-registry.js';
|
||||
|
||||
const COMMIT = 'a'.repeat(40);
|
||||
const SOURCE = {
|
||||
repositoryId: 'REPO-012' as const,
|
||||
sourceCommit: COMMIT,
|
||||
sourceUrl: `https://guanghulab.com/code/bingshuo/guanghu-ice-heart/raw/commit/${COMMIT}/routing/domain-runtime-handoff-endpoints.json`,
|
||||
};
|
||||
|
||||
function endpoint(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
domainIds: ['DOM-FIFTH-0001'], endpointId: 'GH-DOMAIN-HANDOFF-001',
|
||||
nodeTypes: ['cloud-resident'], status: 'ACTIVE',
|
||||
url: 'https://guanghulab.com/api/ai/v1/domain-runtime/handoff', ...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function registry(endpoints: unknown[] = [endpoint()]) {
|
||||
return {
|
||||
endpoints, registryId: 'GH-AIOS-DOMAIN-RUNTIME-HANDOFF-ENDPOINTS-001',
|
||||
schema: 'gh-aios.domain-runtime-handoff-endpoints/v1', state: 'CURRENT', version: '1.0.0',
|
||||
};
|
||||
}
|
||||
|
||||
test('parses and resolves one anchored endpoint for the exact scope', () => {
|
||||
const parsed = parseDomainRuntimeHandoffEndpointRegistry(registry(), SOURCE);
|
||||
const resolved = resolveDomainRuntimeHandoffEndpoint(parsed, {
|
||||
domainId: 'DOM-FIFTH-0001', nodeType: 'cloud-resident',
|
||||
});
|
||||
assert.ok(resolved);
|
||||
assert.equal(resolved.url, 'https://guanghulab.com/api/ai/v1/domain-runtime/handoff');
|
||||
assert.equal(resolveDomainRuntimeHandoffEndpoint(parsed, {
|
||||
domainId: 'DOM-FIFTH-0001', nodeType: 'local-terminal',
|
||||
}), null);
|
||||
});
|
||||
|
||||
test('rejects unsafe URLs, unknown fields and duplicate active scopes', () => {
|
||||
for (const unsafe of [
|
||||
'http://guanghulab.com/api/ai/v1/handoff',
|
||||
'https://example.com/api/ai/v1/handoff',
|
||||
'https://user@guanghulab.com/api/ai/v1/handoff',
|
||||
'https://guanghulab.com:8443/api/ai/v1/handoff',
|
||||
'https://guanghulab.com/api/ai/v1/handoff?target=other',
|
||||
]) {
|
||||
assert.throws(() => parseDomainRuntimeHandoffEndpointRegistry(registry([endpoint({ url: unsafe })]), SOURCE));
|
||||
}
|
||||
assert.throws(() => parseDomainRuntimeHandoffEndpointRegistry(registry([endpoint({ extra: true })]), SOURCE));
|
||||
assert.throws(() => parseDomainRuntimeHandoffEndpointRegistry(registry([
|
||||
endpoint(), endpoint({ endpointId: 'GH-DOMAIN-HANDOFF-002' }),
|
||||
]), SOURCE));
|
||||
});
|
||||
|
||||
test('rejects caller-created and copied endpoint objects', () => {
|
||||
const parsed = parseDomainRuntimeHandoffEndpointRegistry(registry(), SOURCE);
|
||||
const resolved = resolveDomainRuntimeHandoffEndpoint(parsed, {
|
||||
domainId: 'DOM-FIFTH-0001', nodeType: 'cloud-resident',
|
||||
});
|
||||
assert.ok(resolved);
|
||||
assert.throws(() => assertRegisteredDomainRuntimeHandoffEndpoint({ ...resolved }), /endpoint_unregistered/);
|
||||
});
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
import type { DomainNodeType } from './domain-access.js';
|
||||
|
||||
const REGISTRY_SCHEMA = 'gh-aios.domain-runtime-handoff-endpoints/v1' as const;
|
||||
const IDENTIFIER_PATTERN = /^[A-Z0-9][A-Z0-9._:-]{1,159}$/;
|
||||
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 registeredEndpoints = new WeakSet<object>();
|
||||
|
||||
export interface DomainRuntimeHandoffEndpoint {
|
||||
domainIds: readonly string[];
|
||||
endpointId: string;
|
||||
nodeTypes: readonly DomainNodeType[];
|
||||
status: 'ACTIVE' | 'REVOKED';
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface DomainRuntimeHandoffEndpointRegistrySource {
|
||||
repositoryId: 'REPO-012';
|
||||
sourceCommit: string;
|
||||
sourceUrl: string;
|
||||
}
|
||||
|
||||
export interface DomainRuntimeHandoffEndpointRegistry {
|
||||
endpoints: readonly DomainRuntimeHandoffEndpoint[];
|
||||
registryId: 'GH-AIOS-DOMAIN-RUNTIME-HANDOFF-ENDPOINTS-001';
|
||||
schema: typeof REGISTRY_SCHEMA;
|
||||
source: Readonly<DomainRuntimeHandoffEndpointRegistrySource>;
|
||||
state: 'CURRENT';
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface DomainRuntimeHandoffEndpointLookup {
|
||||
domainId: string;
|
||||
nodeType: DomainNodeType;
|
||||
}
|
||||
|
||||
function invalidRegistry(): never {
|
||||
throw new Error('domain_runtime_handoff_endpoint_registry_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 parseEndpointUrl(value: unknown): string {
|
||||
if (typeof value !== 'string') invalidRegistry();
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(value);
|
||||
} catch {
|
||||
invalidRegistry();
|
||||
}
|
||||
if (url.protocol !== 'https:'
|
||||
|| url.hostname !== 'guanghulab.com'
|
||||
|| url.port
|
||||
|| url.username
|
||||
|| url.password
|
||||
|| url.search
|
||||
|| url.hash
|
||||
|| !url.pathname.startsWith('/api/ai/v1/')) invalidRegistry();
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
function parseEndpoint(input: unknown): DomainRuntimeHandoffEndpoint {
|
||||
if (!isRecord(input)
|
||||
|| !hasExactKeys(input, ['domainIds', 'endpointId', 'nodeTypes', 'status', 'url'])
|
||||
|| !isIdentifier(input.endpointId)
|
||||
|| (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
|
||||
|| !Array.isArray(input.nodeTypes)
|
||||
|| input.nodeTypes.length === 0
|
||||
|| input.nodeTypes.some(nodeType => nodeType !== 'local-terminal' && nodeType !== 'cloud-resident')
|
||||
|| new Set(input.nodeTypes).size !== input.nodeTypes.length) invalidRegistry();
|
||||
const endpoint = Object.freeze({
|
||||
domainIds: Object.freeze([...input.domainIds] as string[]),
|
||||
endpointId: input.endpointId,
|
||||
nodeTypes: Object.freeze([...input.nodeTypes] as DomainNodeType[]),
|
||||
status: input.status,
|
||||
url: parseEndpointUrl(input.url),
|
||||
});
|
||||
registeredEndpoints.add(endpoint);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
function parseSource(
|
||||
source: DomainRuntimeHandoffEndpointRegistrySource,
|
||||
): Readonly<DomainRuntimeHandoffEndpointRegistrySource> {
|
||||
if (!isRecord(source)
|
||||
|| !hasExactKeys(source, ['repositoryId', 'sourceCommit', 'sourceUrl'])
|
||||
|| source.repositoryId !== 'REPO-012'
|
||||
|| typeof source.sourceCommit !== 'string'
|
||||
|| !COMMIT_PATTERN.test(source.sourceCommit)) invalidRegistry();
|
||||
const expected = `https://guanghulab.com/code/bingshuo/guanghu-ice-heart/raw/commit/${source.sourceCommit}/routing/domain-runtime-handoff-endpoints.json`;
|
||||
if (source.sourceUrl !== expected) invalidRegistry();
|
||||
return Object.freeze({ ...source });
|
||||
}
|
||||
|
||||
export function parseDomainRuntimeHandoffEndpointRegistry(
|
||||
input: unknown,
|
||||
source: DomainRuntimeHandoffEndpointRegistrySource,
|
||||
): DomainRuntimeHandoffEndpointRegistry {
|
||||
if (!isRecord(input)
|
||||
|| !hasExactKeys(input, ['endpoints', 'registryId', 'schema', 'state', 'version'])
|
||||
|| input.registryId !== 'GH-AIOS-DOMAIN-RUNTIME-HANDOFF-ENDPOINTS-001'
|
||||
|| input.schema !== REGISTRY_SCHEMA
|
||||
|| input.state !== 'CURRENT'
|
||||
|| typeof input.version !== 'string'
|
||||
|| !VERSION_PATTERN.test(input.version)
|
||||
|| !Array.isArray(input.endpoints)) invalidRegistry();
|
||||
const endpoints = input.endpoints.map(parseEndpoint);
|
||||
if (new Set(endpoints.map(endpoint => endpoint.endpointId)).size !== endpoints.length) invalidRegistry();
|
||||
const activeScopes = new Set<string>();
|
||||
for (const endpoint of endpoints.filter(candidate => candidate.status === 'ACTIVE')) {
|
||||
for (const domainId of endpoint.domainIds) {
|
||||
for (const nodeType of endpoint.nodeTypes) {
|
||||
const scope = `${domainId}\0${nodeType}`;
|
||||
if (activeScopes.has(scope)) invalidRegistry();
|
||||
activeScopes.add(scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Object.freeze({
|
||||
endpoints: Object.freeze(endpoints),
|
||||
registryId: input.registryId,
|
||||
schema: input.schema,
|
||||
source: parseSource(source),
|
||||
state: input.state,
|
||||
version: input.version,
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveDomainRuntimeHandoffEndpoint(
|
||||
registry: DomainRuntimeHandoffEndpointRegistry,
|
||||
lookup: DomainRuntimeHandoffEndpointLookup,
|
||||
): DomainRuntimeHandoffEndpoint | null {
|
||||
const endpoint = registry.endpoints.find(candidate => candidate.status === 'ACTIVE'
|
||||
&& candidate.domainIds.includes(lookup.domainId)
|
||||
&& candidate.nodeTypes.includes(lookup.nodeType));
|
||||
if (!endpoint) return null;
|
||||
return assertRegisteredDomainRuntimeHandoffEndpoint(endpoint);
|
||||
}
|
||||
|
||||
export function assertRegisteredDomainRuntimeHandoffEndpoint(
|
||||
endpoint: DomainRuntimeHandoffEndpoint,
|
||||
): DomainRuntimeHandoffEndpoint {
|
||||
if (!registeredEndpoints.has(endpoint)) throw new Error('domain_runtime_handoff_endpoint_unregistered');
|
||||
return endpoint;
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
assertLoadedDomainRuntimeHandoffSnapshot,
|
||||
DomainRuntimeHandoffSnapshotLoader,
|
||||
} from './domain-runtime-handoff-snapshot.js';
|
||||
|
||||
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/domain-runtime-handoff-endpoints.json`;
|
||||
|
||||
function anchor(includeMap = true) {
|
||||
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: ANCHOR_URL,
|
||||
code_entry: 'https://guanghulab.com/code/bingshuo/guanghu-ice-heart',
|
||||
maps: includeMap ? { domain_runtime_handoff_endpoints: {
|
||||
path: 'routing/domain-runtime-handoff-endpoints.json',
|
||||
id: 'GH-AIOS-DOMAIN-RUNTIME-HANDOFF-ENDPOINTS-001', version: '1.0.0',
|
||||
} } : {},
|
||||
navigation_source: { anchor_id: 'GLW-PUBLIC-NAV-ANCHOR-001', source_commit: COMMIT,
|
||||
source_mode: 'REPO-012_MAIN_GIT_SNAPSHOT', source_degraded: false },
|
||||
};
|
||||
}
|
||||
|
||||
function registry(version = '1.0.0') {
|
||||
return {
|
||||
endpoints: [{ domainIds: ['DOM-FIFTH-0001'], endpointId: 'GH-DOMAIN-HANDOFF-001',
|
||||
nodeTypes: ['cloud-resident'], status: 'ACTIVE',
|
||||
url: 'https://guanghulab.com/api/ai/v1/domain-runtime/handoff' }],
|
||||
registryId: 'GH-AIOS-DOMAIN-RUNTIME-HANDOFF-ENDPOINTS-001',
|
||||
schema: 'gh-aios.domain-runtime-handoff-endpoints/v1', state: 'CURRENT', version,
|
||||
};
|
||||
}
|
||||
|
||||
function loader(readAnchor: () => unknown, readRegistry: () => unknown) {
|
||||
return new DomainRuntimeHandoffSnapshotLoader({
|
||||
async fetchJson(url) {
|
||||
if (url === ANCHOR_URL) return readAnchor();
|
||||
if (url === REGISTRY_URL) return readRegistry();
|
||||
throw new Error('unexpected_url');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
test('loads only the registry at the exact anchor source commit', async () => {
|
||||
const snapshot = await loader(() => anchor(), () => registry()).refresh();
|
||||
assert.equal(snapshot.receipt.status, 'CURRENT');
|
||||
assert.equal(snapshot.receipt.sourceCommit, COMMIT);
|
||||
assert.equal(snapshot.receipt.endpointCount, 1);
|
||||
assert.equal(assertLoadedDomainRuntimeHandoffSnapshot(snapshot), snapshot);
|
||||
});
|
||||
|
||||
test('current anchor without the handoff map is explicitly unavailable', async () => {
|
||||
const snapshot = await loader(() => anchor(false), () => registry()).refresh();
|
||||
assert.deepEqual(snapshot.receipt, { endpointCount: 0, reason: 'REGISTRY_UNREGISTERED',
|
||||
registryVersion: null, sourceCommit: null, status: 'UNAVAILABLE' });
|
||||
assert.equal(snapshot.registry, null);
|
||||
});
|
||||
|
||||
test('invalid and degraded sources remain unusable as current authority', async () => {
|
||||
const invalid = await loader(() => anchor(), () => registry('2.0.0')).refresh();
|
||||
assert.equal(invalid.receipt.reason, 'REGISTRY_INVALID');
|
||||
let currentAnchor: unknown = anchor();
|
||||
const snapshots = loader(() => currentAnchor, () => registry());
|
||||
await snapshots.refresh();
|
||||
currentAnchor = anchor(false);
|
||||
const degraded = await snapshots.refresh();
|
||||
assert.equal(degraded.receipt.status, 'DEGRADED_LAST_KNOWN_GOOD');
|
||||
assert.equal(degraded.receipt.reason, 'REGISTRY_UNREGISTERED');
|
||||
});
|
||||
|
||||
test('caller-created snapshots are rejected', () => {
|
||||
assert.throws(() => assertLoadedDomainRuntimeHandoffSnapshot({
|
||||
receipt: { endpointCount: 0, registryVersion: null, sourceCommit: null, status: 'UNAVAILABLE' },
|
||||
registry: null,
|
||||
}), /snapshot_unregistered/);
|
||||
});
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
import {
|
||||
parseDomainRuntimeHandoffEndpointRegistry,
|
||||
type DomainRuntimeHandoffEndpointRegistry,
|
||||
} from './domain-runtime-handoff-registry.js';
|
||||
|
||||
const ANCHOR_URL = 'https://guanghulab.com/api/ai/v1/anchor';
|
||||
const CODE_URL = 'https://guanghulab.com/code/bingshuo/guanghu-ice-heart';
|
||||
const REGISTRY_ID = 'GH-AIOS-DOMAIN-RUNTIME-HANDOFF-ENDPOINTS-001';
|
||||
const REGISTRY_PATH = 'routing/domain-runtime-handoff-endpoints.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 registeredSnapshots = new WeakSet<object>();
|
||||
|
||||
export interface DomainRuntimeHandoffSnapshotTransport {
|
||||
fetchJson(url: string): Promise<unknown>;
|
||||
}
|
||||
|
||||
export type DomainRuntimeHandoffSnapshotReason =
|
||||
| 'ANCHOR_INVALID'
|
||||
| 'REGISTRY_INVALID'
|
||||
| 'REGISTRY_UNREGISTERED'
|
||||
| 'SOURCE_UNAVAILABLE';
|
||||
|
||||
export interface DomainRuntimeHandoffSnapshotReceipt {
|
||||
endpointCount: number;
|
||||
reason?: DomainRuntimeHandoffSnapshotReason;
|
||||
registryVersion: string | null;
|
||||
sourceCommit: string | null;
|
||||
status: 'CURRENT' | 'DEGRADED_LAST_KNOWN_GOOD' | 'UNAVAILABLE';
|
||||
}
|
||||
|
||||
export interface DomainRuntimeHandoffSnapshotResult {
|
||||
receipt: Readonly<DomainRuntimeHandoffSnapshotReceipt>;
|
||||
registry: DomainRuntimeHandoffEndpointRegistry | null;
|
||||
}
|
||||
|
||||
interface ParsedAnchor { registryVersion: string; sourceCommit: string }
|
||||
|
||||
class SnapshotLoadError extends Error {
|
||||
constructor(readonly reason: DomainRuntimeHandoffSnapshotReason) { super(reason); }
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function parseAnchor(input: unknown): ParsedAnchor {
|
||||
if (!isRecord(input)
|
||||
|| input.schema !== 'guanghu.public-navigation-anchor/v1'
|
||||
|| input.anchor_id !== 'GLW-PUBLIC-NAV-ANCHOR-001'
|
||||
|| input.state !== 'CURRENT_CANONICAL'
|
||||
|| input.repository_id !== 'REPO-012'
|
||||
|| input.branch !== 'main'
|
||||
|| input.public_entry !== ANCHOR_URL
|
||||
|| input.code_entry !== CODE_URL
|
||||
|| !isRecord(input.maps)
|
||||
|| !isRecord(input.navigation_source)
|
||||
|| input.navigation_source.anchor_id !== 'GLW-PUBLIC-NAV-ANCHOR-001'
|
||||
|| input.navigation_source.source_mode !== 'REPO-012_MAIN_GIT_SNAPSHOT'
|
||||
|| input.navigation_source.source_degraded !== false
|
||||
|| typeof input.navigation_source.source_commit !== 'string'
|
||||
|| !COMMIT_PATTERN.test(input.navigation_source.source_commit)) {
|
||||
throw new SnapshotLoadError('ANCHOR_INVALID');
|
||||
}
|
||||
if (!isRecord(input.maps.domain_runtime_handoff_endpoints)) {
|
||||
throw new SnapshotLoadError('REGISTRY_UNREGISTERED');
|
||||
}
|
||||
const map = input.maps.domain_runtime_handoff_endpoints;
|
||||
if (map.path !== REGISTRY_PATH
|
||||
|| map.id !== REGISTRY_ID
|
||||
|| typeof map.version !== 'string'
|
||||
|| !VERSION_PATTERN.test(map.version)) throw new SnapshotLoadError('ANCHOR_INVALID');
|
||||
return Object.freeze({
|
||||
registryVersion: map.version,
|
||||
sourceCommit: input.navigation_source.source_commit,
|
||||
});
|
||||
}
|
||||
|
||||
function registryUrl(sourceCommit: string): string {
|
||||
return `${CODE_URL}/raw/commit/${sourceCommit}/${REGISTRY_PATH}`;
|
||||
}
|
||||
|
||||
function receipt(
|
||||
status: DomainRuntimeHandoffSnapshotReceipt['status'],
|
||||
registry: DomainRuntimeHandoffEndpointRegistry | null,
|
||||
reason?: DomainRuntimeHandoffSnapshotReason,
|
||||
): Readonly<DomainRuntimeHandoffSnapshotReceipt> {
|
||||
return Object.freeze({
|
||||
endpointCount: registry?.endpoints.length ?? 0,
|
||||
...(reason ? { reason } : {}),
|
||||
registryVersion: registry?.version ?? null,
|
||||
sourceCommit: registry?.source.sourceCommit ?? null,
|
||||
status,
|
||||
});
|
||||
}
|
||||
|
||||
function result(
|
||||
registry: DomainRuntimeHandoffEndpointRegistry | null,
|
||||
snapshotReceipt: Readonly<DomainRuntimeHandoffSnapshotReceipt>,
|
||||
): DomainRuntimeHandoffSnapshotResult {
|
||||
const loaded = Object.freeze({ receipt: snapshotReceipt, registry });
|
||||
registeredSnapshots.add(loaded);
|
||||
return loaded;
|
||||
}
|
||||
|
||||
export function assertLoadedDomainRuntimeHandoffSnapshot(
|
||||
snapshot: DomainRuntimeHandoffSnapshotResult,
|
||||
): DomainRuntimeHandoffSnapshotResult {
|
||||
if (!registeredSnapshots.has(snapshot)) throw new Error('domain_runtime_handoff_snapshot_unregistered');
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
export class DomainRuntimeHandoffSnapshotLoader {
|
||||
#inFlight: Promise<DomainRuntimeHandoffSnapshotResult> | null = null;
|
||||
#lastKnownGood: DomainRuntimeHandoffEndpointRegistry | null = null;
|
||||
|
||||
constructor(private readonly transport: DomainRuntimeHandoffSnapshotTransport) {}
|
||||
|
||||
refresh(): Promise<DomainRuntimeHandoffSnapshotResult> {
|
||||
if (this.#inFlight) return this.#inFlight;
|
||||
this.#inFlight = this.#load().finally(() => { this.#inFlight = null; });
|
||||
return this.#inFlight;
|
||||
}
|
||||
|
||||
async #load(): Promise<DomainRuntimeHandoffSnapshotResult> {
|
||||
try {
|
||||
let rawAnchor: unknown;
|
||||
try { rawAnchor = await this.transport.fetchJson(ANCHOR_URL); }
|
||||
catch { throw new SnapshotLoadError('SOURCE_UNAVAILABLE'); }
|
||||
const anchor = parseAnchor(rawAnchor);
|
||||
let rawRegistry: unknown;
|
||||
try { rawRegistry = await this.transport.fetchJson(registryUrl(anchor.sourceCommit)); }
|
||||
catch { throw new SnapshotLoadError('SOURCE_UNAVAILABLE'); }
|
||||
let registry: DomainRuntimeHandoffEndpointRegistry;
|
||||
try {
|
||||
registry = parseDomainRuntimeHandoffEndpointRegistry(rawRegistry, {
|
||||
repositoryId: 'REPO-012',
|
||||
sourceCommit: anchor.sourceCommit,
|
||||
sourceUrl: registryUrl(anchor.sourceCommit),
|
||||
});
|
||||
} catch { throw new SnapshotLoadError('REGISTRY_INVALID'); }
|
||||
if (registry.version !== anchor.registryVersion) throw new SnapshotLoadError('REGISTRY_INVALID');
|
||||
this.#lastKnownGood = registry;
|
||||
return result(registry, receipt('CURRENT', registry));
|
||||
} catch (error) {
|
||||
const reason = error instanceof SnapshotLoadError ? error.reason : 'SOURCE_UNAVAILABLE';
|
||||
return this.#lastKnownGood
|
||||
? result(this.#lastKnownGood, receipt('DEGRADED_LAST_KNOWN_GOOD', this.#lastKnownGood, reason))
|
||||
: result(null, receipt('UNAVAILABLE', null, reason));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,16 @@
|
|||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createHash, generateKeyPairSync, sign } from 'node:crypto';
|
||||
import { StrictDomainRuntimeHandoffSource } from './domain-runtime-handoff-source.js';
|
||||
import {
|
||||
AnchoredDomainRuntimeHandoffSource,
|
||||
HttpDomainRuntimeHandoffTransport,
|
||||
StrictDomainRuntimeHandoffSource,
|
||||
} from './domain-runtime-handoff-source.js';
|
||||
import { DomainRuntimeHandoffSnapshotLoader } from './domain-runtime-handoff-snapshot.js';
|
||||
import {
|
||||
parseDomainRuntimeHandoffEndpointRegistry,
|
||||
resolveDomainRuntimeHandoffEndpoint,
|
||||
} from './domain-runtime-handoff-registry.js';
|
||||
import {
|
||||
createNodePossessionChallenge,
|
||||
nodePossessionChallengeSigningBytes,
|
||||
|
|
@ -25,6 +34,29 @@ const fingerprint = createHash('sha256')
|
|||
.update(nodeKeys.publicKey.export({ format: 'der', type: 'spki' }))
|
||||
.digest('hex');
|
||||
|
||||
function handoffEndpoint() {
|
||||
const registry = parseDomainRuntimeHandoffEndpointRegistry({
|
||||
endpoints: [{
|
||||
domainIds: [DOMAIN_ID],
|
||||
endpointId: 'GH-DOMAIN-HANDOFF-001',
|
||||
nodeTypes: [NODE_TYPE],
|
||||
status: 'ACTIVE',
|
||||
url: 'https://guanghulab.com/api/ai/v1/domain-runtime/handoff',
|
||||
}],
|
||||
registryId: 'GH-AIOS-DOMAIN-RUNTIME-HANDOFF-ENDPOINTS-001',
|
||||
schema: 'gh-aios.domain-runtime-handoff-endpoints/v1',
|
||||
state: 'CURRENT',
|
||||
version: '1.0.0',
|
||||
}, {
|
||||
repositoryId: 'REPO-012',
|
||||
sourceCommit: 'b'.repeat(40),
|
||||
sourceUrl: `https://guanghulab.com/code/bingshuo/guanghu-ice-heart/raw/commit/${'b'.repeat(40)}/routing/domain-runtime-handoff-endpoints.json`,
|
||||
});
|
||||
const endpoint = resolveDomainRuntimeHandoffEndpoint(registry, { domainId: DOMAIN_ID, nodeType: NODE_TYPE });
|
||||
assert.ok(endpoint);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
function verifiedPossession() {
|
||||
const registry = parseNodeRegistrationEndpointRegistry({
|
||||
endpoints: [{
|
||||
|
|
@ -101,8 +133,8 @@ function response(requestId: string, overrides: Record<string, unknown> = {}) {
|
|||
|
||||
test('forwards one exact cryptographic authorization bundle without private material', async () => {
|
||||
const requests: unknown[] = [];
|
||||
const source = new StrictDomainRuntimeHandoffSource({
|
||||
async request(input) {
|
||||
const source = new StrictDomainRuntimeHandoffSource(handoffEndpoint(), {
|
||||
async request(_endpoint, input) {
|
||||
requests.push(input);
|
||||
return response(input.requestId);
|
||||
},
|
||||
|
|
@ -112,7 +144,7 @@ test('forwards one exact cryptographic authorization bundle without private mate
|
|||
|
||||
assert.equal(requests.length, 1);
|
||||
assert.deepEqual(Object.keys(requests[0] as object).sort(), [
|
||||
'accountId', 'challenge', 'domainId', 'issuedAt', 'nodeId', 'nodeType',
|
||||
'accountId', 'challenge', 'domainId', 'endpointId', 'issuedAt', 'nodeId', 'nodeType',
|
||||
'registration', 'requestId', 'response', 'schema',
|
||||
]);
|
||||
assert.equal(JSON.stringify(requests[0]).includes('PRIVATE KEY'), false);
|
||||
|
|
@ -134,7 +166,7 @@ test('binds the response to the generated request and rejects malformed envelope
|
|||
response('HANDOFF-REQ-001', { handoff: null, signer_lookup: null, status: 'NOT_AUTHORIZED' }),
|
||||
];
|
||||
for (const sample of samples) {
|
||||
const source = new StrictDomainRuntimeHandoffSource({ async request() { return sample; } }, () => NOW + 2, () => 'HANDOFF-REQ-001');
|
||||
const source = new StrictDomainRuntimeHandoffSource(handoffEndpoint(), { async request() { return sample; } }, () => NOW + 2, () => 'HANDOFF-REQ-001');
|
||||
assert.equal(await source.read(verifiedPossession()), null);
|
||||
}
|
||||
});
|
||||
|
|
@ -142,22 +174,139 @@ test('binds the response to the generated request and rejects malformed envelope
|
|||
test('rejects copied, expired and replayed possession authorizations before transport', async () => {
|
||||
let requests = 0;
|
||||
const possession = verifiedPossession();
|
||||
const source = new StrictDomainRuntimeHandoffSource({
|
||||
async request(input) { requests += 1; return response(input.requestId); },
|
||||
const source = new StrictDomainRuntimeHandoffSource(handoffEndpoint(), {
|
||||
async request(_endpoint, input) { requests += 1; return response(input.requestId); },
|
||||
}, () => NOW + 2, () => 'HANDOFF-REQ-001');
|
||||
assert.ok(await source.read(possession));
|
||||
assert.equal(await source.read(possession), null);
|
||||
assert.equal(await source.read({ ...verifiedPossession() }), null);
|
||||
const expired = new StrictDomainRuntimeHandoffSource({
|
||||
async request(input) { requests += 1; return response(input.requestId); },
|
||||
const expired = new StrictDomainRuntimeHandoffSource(handoffEndpoint(), {
|
||||
async request(_endpoint, input) { requests += 1; return response(input.requestId); },
|
||||
}, () => NOW + 60_000, () => 'HANDOFF-REQ-002');
|
||||
assert.equal(await expired.read(verifiedPossession()), null);
|
||||
assert.equal(requests, 1);
|
||||
});
|
||||
|
||||
test('fails closed on transport errors without exposing remote details', async () => {
|
||||
const source = new StrictDomainRuntimeHandoffSource({
|
||||
const source = new StrictDomainRuntimeHandoffSource(handoffEndpoint(), {
|
||||
async request() { throw new Error('secret remote detail'); },
|
||||
}, () => NOW + 2, () => 'HANDOFF-REQ-001');
|
||||
assert.equal(await source.read(verifiedPossession()), null);
|
||||
});
|
||||
|
||||
function handoffAnchor(includeMap = true) {
|
||||
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: 'https://guanghulab.com/api/ai/v1/anchor',
|
||||
code_entry: 'https://guanghulab.com/code/bingshuo/guanghu-ice-heart',
|
||||
maps: includeMap ? {
|
||||
domain_runtime_handoff_endpoints: {
|
||||
path: 'routing/domain-runtime-handoff-endpoints.json',
|
||||
id: 'GH-AIOS-DOMAIN-RUNTIME-HANDOFF-ENDPOINTS-001',
|
||||
version: '1.0.0',
|
||||
},
|
||||
} : {},
|
||||
navigation_source: {
|
||||
anchor_id: 'GLW-PUBLIC-NAV-ANCHOR-001',
|
||||
source_commit: 'b'.repeat(40),
|
||||
source_mode: 'REPO-012_MAIN_GIT_SNAPSHOT',
|
||||
source_degraded: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function handoffRegistry() {
|
||||
return {
|
||||
endpoints: [{
|
||||
domainIds: [DOMAIN_ID], endpointId: 'GH-DOMAIN-HANDOFF-001', nodeTypes: [NODE_TYPE],
|
||||
status: 'ACTIVE', url: 'https://guanghulab.com/api/ai/v1/domain-runtime/handoff',
|
||||
}],
|
||||
registryId: 'GH-AIOS-DOMAIN-RUNTIME-HANDOFF-ENDPOINTS-001',
|
||||
schema: 'gh-aios.domain-runtime-handoff-endpoints/v1',
|
||||
state: 'CURRENT', version: '1.0.0',
|
||||
};
|
||||
}
|
||||
|
||||
function anchoredLoader(includeMap = true) {
|
||||
return new DomainRuntimeHandoffSnapshotLoader({
|
||||
async fetchJson(url) {
|
||||
if (url.endsWith('/api/ai/v1/anchor')) return handoffAnchor(includeMap);
|
||||
if (url.includes('/raw/commit/')) return handoffRegistry();
|
||||
throw new Error('unexpected_url');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
test('anchored source resolves the exact endpoint before consuming possession', async () => {
|
||||
const requests: Array<{ endpoint: string; endpointId: string }> = [];
|
||||
const source = new AnchoredDomainRuntimeHandoffSource(anchoredLoader(), {
|
||||
async request(endpoint, input) {
|
||||
requests.push({ endpoint: endpoint.url, endpointId: input.endpointId });
|
||||
return response(input.requestId);
|
||||
},
|
||||
}, () => NOW + 2, () => 'HANDOFF-REQ-001');
|
||||
assert.ok(await source.read(verifiedPossession()));
|
||||
assert.deepEqual(requests, [{
|
||||
endpoint: 'https://guanghulab.com/api/ai/v1/domain-runtime/handoff',
|
||||
endpointId: 'GH-DOMAIN-HANDOFF-001',
|
||||
}]);
|
||||
});
|
||||
|
||||
test('missing anchored registry fails before network and does not consume possession', async () => {
|
||||
let requests = 0;
|
||||
const possession = verifiedPossession();
|
||||
const unavailable = new AnchoredDomainRuntimeHandoffSource(anchoredLoader(false), {
|
||||
async request() { requests += 1; return null; },
|
||||
}, () => NOW + 2, () => 'HANDOFF-REQ-001');
|
||||
assert.equal(await unavailable.read(possession), null);
|
||||
assert.equal(requests, 0);
|
||||
const current = new AnchoredDomainRuntimeHandoffSource(anchoredLoader(), {
|
||||
async request(_endpoint, input) { requests += 1; return response(input.requestId); },
|
||||
}, () => NOW + 2, () => 'HANDOFF-REQ-002');
|
||||
assert.ok(await current.read(possession));
|
||||
assert.equal(requests, 1);
|
||||
});
|
||||
|
||||
test('HTTP transport posts only to the registered endpoint without credentials', async () => {
|
||||
const endpoint = handoffEndpoint();
|
||||
let observedUrl = '';
|
||||
let observedInit: RequestInit | undefined;
|
||||
const transport = new HttpDomainRuntimeHandoffTransport(async (url, init) => {
|
||||
observedUrl = String(url);
|
||||
observedInit = init;
|
||||
return new Response(JSON.stringify(response('HANDOFF-REQ-001')), {
|
||||
headers: { 'Content-Type': 'application/json' }, status: 200,
|
||||
});
|
||||
});
|
||||
const source = new StrictDomainRuntimeHandoffSource(endpoint, transport, () => NOW + 2, () => 'HANDOFF-REQ-001');
|
||||
assert.ok(await source.read(verifiedPossession()));
|
||||
assert.equal(observedUrl, endpoint.url);
|
||||
assert.equal(observedInit?.method, 'POST');
|
||||
assert.equal(observedInit?.credentials, 'omit');
|
||||
assert.equal(observedInit?.redirect, 'manual');
|
||||
assert.equal(observedInit?.cache, 'no-store');
|
||||
assert.equal(observedInit?.referrerPolicy, 'no-referrer');
|
||||
assert.equal(JSON.stringify(observedInit?.headers).includes('Authorization'), false);
|
||||
});
|
||||
|
||||
test('HTTP transport rejects redirects, non-JSON and oversized responses', async () => {
|
||||
const endpoint = handoffEndpoint();
|
||||
const request = Object.freeze({
|
||||
accountId: 'bingshuo', challenge: {} as never, domainId: DOMAIN_ID,
|
||||
endpointId: endpoint.endpointId, issuedAt: NOW, nodeId: NODE_ID, nodeType: NODE_TYPE,
|
||||
registration: {} as never, requestId: 'HANDOFF-REQ-001', response: {} as never,
|
||||
schema: 'gh-aios.domain-runtime-handoff-request/v1' as const,
|
||||
});
|
||||
for (const reply of [
|
||||
new Response('', { status: 302, headers: { Location: 'https://example.com/' } }),
|
||||
new Response('plain', { status: 200, headers: { 'Content-Type': 'text/plain' } }),
|
||||
new Response('{}', { status: 200, headers: { 'Content-Type': 'application/json', 'Content-Length': '262145' } }),
|
||||
]) {
|
||||
const transport = new HttpDomainRuntimeHandoffTransport(async () => reply);
|
||||
await assert.rejects(() => transport.request(endpoint, request));
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,16 +10,27 @@ import {
|
|||
} from './node-possession-proof.js';
|
||||
import type { VerifiedNodeRegistration } from './node-registration.js';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import {
|
||||
assertRegisteredDomainRuntimeHandoffEndpoint,
|
||||
resolveDomainRuntimeHandoffEndpoint,
|
||||
type DomainRuntimeHandoffEndpoint,
|
||||
} from './domain-runtime-handoff-registry.js';
|
||||
import {
|
||||
assertLoadedDomainRuntimeHandoffSnapshot,
|
||||
type DomainRuntimeHandoffSnapshotLoader,
|
||||
} from './domain-runtime-handoff-snapshot.js';
|
||||
|
||||
const IDENTIFIER_PATTERN = /^[A-Z0-9][A-Z0-9._:-]{1,159}$/;
|
||||
const REQUEST_SCHEMA = 'gh-aios.domain-runtime-handoff-request/v1' as const;
|
||||
const RESPONSE_SCHEMA = 'gh-aios.domain-runtime-handoff-response/v1' as const;
|
||||
const consumedPossessions = new WeakSet<object>();
|
||||
const MAX_RESPONSE_BYTES = 256 * 1024;
|
||||
|
||||
export interface DomainRuntimeHandoffRequest {
|
||||
accountId: string;
|
||||
challenge: Readonly<NodePossessionChallenge>;
|
||||
domainId: string;
|
||||
endpointId: string;
|
||||
issuedAt: number;
|
||||
nodeId: string;
|
||||
nodeType: VerifiedNodeRegistration['nodeType'];
|
||||
|
|
@ -30,7 +41,10 @@ export interface DomainRuntimeHandoffRequest {
|
|||
}
|
||||
|
||||
export interface DomainRuntimeHandoffTransport {
|
||||
request(input: Readonly<DomainRuntimeHandoffRequest>): Promise<unknown>;
|
||||
request(
|
||||
endpoint: Readonly<DomainRuntimeHandoffEndpoint>,
|
||||
input: Readonly<DomainRuntimeHandoffRequest>,
|
||||
): Promise<unknown>;
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
|
|
@ -76,6 +90,7 @@ function parseResponse(
|
|||
|
||||
export class StrictDomainRuntimeHandoffSource implements DomainRuntimeHandoffSource {
|
||||
constructor(
|
||||
private readonly endpoint: DomainRuntimeHandoffEndpoint,
|
||||
private readonly transport: DomainRuntimeHandoffTransport,
|
||||
private readonly clock: () => number = Date.now,
|
||||
private readonly requestId: () => string = () => `HANDOFF-REQ-${randomUUID().toUpperCase()}`,
|
||||
|
|
@ -85,6 +100,10 @@ export class StrictDomainRuntimeHandoffSource implements DomainRuntimeHandoffSou
|
|||
try {
|
||||
const verified = assertVerifiedNodePossession(possession);
|
||||
if (consumedPossessions.has(verified)) return null;
|
||||
const endpoint = assertRegisteredDomainRuntimeHandoffEndpoint(this.endpoint);
|
||||
if (endpoint.status !== 'ACTIVE'
|
||||
|| !endpoint.domainIds.includes(verified.registration.domainId)
|
||||
|| !endpoint.nodeTypes.includes(verified.registration.nodeType)) return null;
|
||||
const issuedAt = this.clock();
|
||||
const requestId = this.requestId();
|
||||
if (!Number.isSafeInteger(issuedAt)
|
||||
|
|
@ -96,6 +115,7 @@ export class StrictDomainRuntimeHandoffSource implements DomainRuntimeHandoffSou
|
|||
accountId: verified.registration.accountId,
|
||||
challenge: verified.challenge,
|
||||
domainId: verified.registration.domainId,
|
||||
endpointId: endpoint.endpointId,
|
||||
issuedAt,
|
||||
nodeId: verified.registration.nodeId,
|
||||
nodeType: verified.registration.nodeType,
|
||||
|
|
@ -105,9 +125,82 @@ export class StrictDomainRuntimeHandoffSource implements DomainRuntimeHandoffSou
|
|||
schema: REQUEST_SCHEMA,
|
||||
});
|
||||
consumedPossessions.add(verified);
|
||||
return parseResponse(await this.transport.request(request), request);
|
||||
return parseResponse(await this.transport.request(endpoint, request), request);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class AnchoredDomainRuntimeHandoffSource implements DomainRuntimeHandoffSource {
|
||||
constructor(
|
||||
private readonly snapshots: DomainRuntimeHandoffSnapshotLoader,
|
||||
private readonly transport: DomainRuntimeHandoffTransport,
|
||||
private readonly clock: () => number = Date.now,
|
||||
private readonly requestId: () => string = () => `HANDOFF-REQ-${randomUUID().toUpperCase()}`,
|
||||
) {}
|
||||
|
||||
async read(possession: VerifiedNodePossession): Promise<Readonly<DomainRuntimeHandoffCandidate> | null> {
|
||||
try {
|
||||
const verified = assertVerifiedNodePossession(possession);
|
||||
const snapshot = assertLoadedDomainRuntimeHandoffSnapshot(await this.snapshots.refresh());
|
||||
if (snapshot.receipt.status !== 'CURRENT' || !snapshot.registry) return null;
|
||||
const endpoint = resolveDomainRuntimeHandoffEndpoint(snapshot.registry, {
|
||||
domainId: verified.registration.domainId,
|
||||
nodeType: verified.registration.nodeType,
|
||||
});
|
||||
if (!endpoint) return null;
|
||||
return new StrictDomainRuntimeHandoffSource(
|
||||
endpoint,
|
||||
this.transport,
|
||||
this.clock,
|
||||
this.requestId,
|
||||
).read(verified);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class HttpDomainRuntimeHandoffTransport implements DomainRuntimeHandoffTransport {
|
||||
constructor(private readonly fetcher: typeof fetch = fetch) {}
|
||||
|
||||
async request(
|
||||
inputEndpoint: Readonly<DomainRuntimeHandoffEndpoint>,
|
||||
input: Readonly<DomainRuntimeHandoffRequest>,
|
||||
): Promise<unknown> {
|
||||
const endpoint = assertRegisteredDomainRuntimeHandoffEndpoint(inputEndpoint);
|
||||
if (endpoint.status !== 'ACTIVE'
|
||||
|| input.endpointId !== endpoint.endpointId
|
||||
|| !endpoint.domainIds.includes(input.domainId)
|
||||
|| !endpoint.nodeTypes.includes(input.nodeType)) {
|
||||
throw new Error('domain_runtime_handoff_endpoint_scope_invalid');
|
||||
}
|
||||
const response = await this.fetcher(endpoint.url, {
|
||||
body: JSON.stringify(input),
|
||||
cache: 'no-store',
|
||||
credentials: 'omit',
|
||||
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
|
||||
method: 'POST',
|
||||
redirect: 'manual',
|
||||
referrerPolicy: 'no-referrer',
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
if (!response.ok || response.status < 200 || response.status >= 300
|
||||
|| response.type === 'opaqueredirect') throw new Error('domain_runtime_handoff_http_rejected');
|
||||
const contentType = response.headers.get('content-type')?.split(';', 1)[0].trim().toLowerCase();
|
||||
if (contentType !== 'application/json') throw new Error('domain_runtime_handoff_content_type_invalid');
|
||||
const declaredLength = response.headers.get('content-length');
|
||||
if (declaredLength !== null
|
||||
&& (!/^\d+$/.test(declaredLength) || Number(declaredLength) > MAX_RESPONSE_BYTES)) {
|
||||
throw new Error('domain_runtime_handoff_response_too_large');
|
||||
}
|
||||
const bytes = new Uint8Array(await response.arrayBuffer());
|
||||
if (bytes.byteLength > MAX_RESPONSE_BYTES) throw new Error('domain_runtime_handoff_response_too_large');
|
||||
let text: string;
|
||||
try { text = new TextDecoder('utf-8', { fatal: true }).decode(bytes); }
|
||||
catch { throw new Error('domain_runtime_handoff_response_encoding_invalid'); }
|
||||
try { return JSON.parse(text); }
|
||||
catch { throw new Error('domain_runtime_handoff_response_json_invalid'); }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,11 @@ import { DomainAccessOrchestrator } from '../../guanghu-knowledge-base/server/do
|
|||
import { TrustedSignerSnapshotLoader } from '../../guanghu-knowledge-base/server/trusted-signer-snapshot.js';
|
||||
import { NodeRegistrationSnapshotLoader } from '../../guanghu-knowledge-base/server/node-registration-snapshot.js';
|
||||
import { HttpNodeRegistrationClaimSource } from '../../guanghu-knowledge-base/server/node-registration-client.js';
|
||||
import { DomainRuntimeHandoffSnapshotLoader } from '../../guanghu-knowledge-base/server/domain-runtime-handoff-snapshot.js';
|
||||
import {
|
||||
AnchoredDomainRuntimeHandoffSource,
|
||||
HttpDomainRuntimeHandoffTransport,
|
||||
} from '../../guanghu-knowledge-base/server/domain-runtime-handoff-source.js';
|
||||
|
||||
// ─── 配置 ───
|
||||
|
||||
|
|
@ -339,6 +344,28 @@ const nodeRegistrationSnapshots = new NodeRegistrationSnapshotLoader({
|
|||
|
||||
const nodeRegistrationClaims = new HttpNodeRegistrationClaimSource();
|
||||
|
||||
const domainRuntimeHandoffSnapshots = new DomainRuntimeHandoffSnapshotLoader({
|
||||
async fetchJson(url: string): Promise<unknown> {
|
||||
const response = await fetch(url, {
|
||||
cache: 'no-store',
|
||||
credentials: 'omit',
|
||||
headers: { Accept: 'application/json' },
|
||||
redirect: 'manual',
|
||||
referrerPolicy: 'no-referrer',
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
if (!response.ok || response.type === 'opaqueredirect') {
|
||||
throw new Error(`domain_runtime_handoff_source_http_${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
},
|
||||
});
|
||||
|
||||
const domainRuntimeHandoffs = new AnchoredDomainRuntimeHandoffSource(
|
||||
domainRuntimeHandoffSnapshots,
|
||||
new HttpDomainRuntimeHandoffTransport(),
|
||||
);
|
||||
|
||||
const domainAccessOrchestrator = new DomainAccessOrchestrator(
|
||||
trustedSignerSnapshots,
|
||||
nodeRegistrationSnapshots,
|
||||
|
|
@ -366,12 +393,7 @@ const domainAccessOrchestrator = new DomainAccessOrchestrator(
|
|||
// proof keeps the domain gate closed even if a future signed claim appears.
|
||||
async prove() { return null; },
|
||||
},
|
||||
{
|
||||
async read() {
|
||||
// 当前灯塔尚未发布签名运行体交接端点。保持关闭,不从账号身份推导运行体权限。
|
||||
return null;
|
||||
},
|
||||
},
|
||||
domainRuntimeHandoffs,
|
||||
);
|
||||
|
||||
function startServer(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -99,3 +99,22 @@ REPO-012 信任快照独立验证 handoff 中的域清单签名、短期会话
|
|||
本阶段闭合的是“证明能够被带到交接边界”的客户端证据结构,不是生产 HTTP 端点。当前公共
|
||||
锚点没有域交接端点注册表,桌面运行源仍返回空结果,因此生产会话签发、域运行体连接与在线
|
||||
回执继续为 `NOT_EXISTS_0`。
|
||||
|
||||
## 域运行体交接端点锚定与严格传输 · 阶段 005
|
||||
|
||||
本阶段先固定以下验收标准,再进入实现:
|
||||
|
||||
1. 域交接 URL 只能来自 REPO-012 当前公共锚点同一提交声明的
|
||||
`GH-AIOS-DOMAIN-RUNTIME-HANDOFF-ENDPOINTS-001`,账号响应、调用方参数、本地配置和复制对象
|
||||
都不能指定或替换 URL。
|
||||
2. 注册表只允许无凭据的 `https://guanghulab.com/api/ai/v1/...` 端点;禁止端口、用户名、密码、
|
||||
查询串、片段和重定向。同一域与节点类型最多一个活跃端点。
|
||||
3. 只有来源状态为 `CURRENT` 的已登记快照和已登记端点才能发起请求;注册表缺失、来源降级、
|
||||
范围不匹配、端点撤销或调用方伪造对象时必须在网络请求前失败关闭。
|
||||
4. 交接传输固定为无凭据 `POST application/json`,5 秒超时、`redirect=manual`、
|
||||
`credentials=omit`、`cache=no-store`、`referrerPolicy=no-referrer`;响应必须是 JSON 且不超过
|
||||
256 KiB。HTTP 错误、重定向、非 JSON、超限和响应绑定错误均返回空结果。
|
||||
5. 请求包必须增加并绑定 `endpointId`,已验证节点证明只有在解析到当前活跃端点后才被消耗,
|
||||
且一次证明仍最多发起一次网络请求。
|
||||
6. 当前公共锚点尚未登记域交接端点映射,生产桌面必须不发送交接请求并继续返回
|
||||
`NOT_EXISTS_0`;代码完成不得冒充生产端点、会话签发、域运行体连接或在线健康已经存在。
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
- [`HOLOLAKE-INTENT-REASONING-MAP-20260809.md`](HOLOLAKE-INTENT-REASONING-MAP-20260809.md):当前产品意图、纠正、思维推理与因果链。
|
||||
- [`HOLOLAKE-SYSTEM-ARCHITECTURE-20260809.md`](HOLOLAKE-SYSTEM-ARCHITECTURE-20260809.md):`HLP-CURRENT-ARCH-001` 当前完整系统蓝图,覆盖 GH-AIOS 灯塔、五域独立入口、光湖本源域、节点登录与光湖桥。
|
||||
- [`HOLOLAKE-DESKTOP-0.8.0-CURRENT-CAPABILITY-GAP-20260809.md`](HOLOLAKE-DESKTOP-0.8.0-CURRENT-CAPABILITY-GAP-20260809.md):桌面 0.8.0 已观察能力与最终规划的逐项差距;同时登记线上产品源码仍为 0.4.6 的分叉事实。
|
||||
- [`HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md`](HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md):账号、签名节点登记与当前节点私钥持有证明分离后的端点注册表、无凭据声明读取、60 秒一次性 Ed25519 挑战、不可伪造交接证据包、失败关闭和当前生产缺口验收基线。
|
||||
- [`HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md`](HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md):账号、签名节点登记与当前节点私钥持有证明分离后的端点注册表、无凭据声明读取、60 秒一次性 Ed25519 挑战、不可伪造交接证据包,以及只能由 REPO-012 当前公共锚点登记 URL 的严格域交接传输;当前锚点未登记映射,生产继续失败关闭。
|
||||
- [`HOLOLAKE-LANGUAGE-PERSONA-OS.md`](HOLOLAKE-LANGUAGE-PERSONA-OS.md):HoloLake 作为 AI 语言人格驱动操作系统的当前正式产品定位、操作系统映射、原生应用边界与实现缺口。
|
||||
- [`HOLOLAKE-INTENT-REASONING-MAP-20260807.md`](HOLOLAKE-INTENT-REASONING-MAP-20260807.md):2026-08-07 历史意图层,继续保存形成过程;不再作为当前默认入口。
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue