feat: add lighthouse and fifth-domain entry flow
This commit is contained in:
parent
674c9e7764
commit
a35d61e227
12 changed files with 1056 additions and 3 deletions
|
|
@ -0,0 +1,159 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
INITIAL_DOMAIN_ACCESS_STATE,
|
||||
acceptDomainConnectionReceipt,
|
||||
acceptDomainSession,
|
||||
assertVerifiedDomainManifest,
|
||||
beginDomainAccess,
|
||||
disconnectDomainRuntime,
|
||||
enterDomainRuntime,
|
||||
projectPublicDomainVestibule,
|
||||
selectPublicDomain,
|
||||
type DomainConnectionReceipt,
|
||||
type DomainSessionCapability,
|
||||
type VerifiedDomainManifest,
|
||||
} from './domainRuntimeContract'
|
||||
|
||||
const DIGEST = 'a'.repeat(64)
|
||||
const NOW = 1_786_291_200_000
|
||||
|
||||
function manifest(): VerifiedDomainManifest {
|
||||
return {
|
||||
public: {
|
||||
accessModes: ['LOCAL_TERMINAL_NODE', 'CLOUD_RESIDENT_NODE'],
|
||||
displayName: '第五域 · 光湖本源域',
|
||||
domainId: 'DOM-FIFTH-0001',
|
||||
formalName: '光湖本源域',
|
||||
publicStatus: 'PUBLIC_PREVIEW',
|
||||
purpose: '零点原核的工程本体与语言架构源点域',
|
||||
responsibleParty: '第五域主控',
|
||||
themePreview: {
|
||||
assetRef: 'theme-preview://origin-domain/lake-reflects-stars',
|
||||
description: '湖面映星公开预览',
|
||||
},
|
||||
},
|
||||
provenance: {
|
||||
digest: DIGEST,
|
||||
repositoryId: 'REPO-012',
|
||||
signature: 'signature-envelope-reference',
|
||||
signerId: 'SIGNER-FIFTH-DOMAIN-001',
|
||||
sourceCommit: '6e26d1f35439759542efb317c3ddd7661ba27d58',
|
||||
},
|
||||
runtime: {
|
||||
backendVersion: 'not-published',
|
||||
channelIds: ['CHANNEL-ZERO-CORE'],
|
||||
forbiddenDataScopes: ['private-relationship-core'],
|
||||
frontendVersion: 'not-published',
|
||||
healthCheckRef: 'health://origin-domain/runtime',
|
||||
moduleIds: ['MODULE-LANGUAGE-ARCHITECTURE'],
|
||||
rollbackVersion: 'not-published',
|
||||
routeRef: 'domain-route://origin-domain/runtime',
|
||||
themePackageRef: 'theme://origin-domain/lake-reflects-stars',
|
||||
},
|
||||
schema: 'gh-aios.domain-manifest/v1',
|
||||
verification: {
|
||||
manifestDigest: DIGEST,
|
||||
state: 'verified',
|
||||
verifiedAt: NOW,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function session(overrides: Partial<DomainSessionCapability> = {}): DomainSessionCapability {
|
||||
return {
|
||||
capabilityId: 'CAP-001',
|
||||
domainId: 'DOM-FIFTH-0001',
|
||||
expiresAt: NOW + 60_000,
|
||||
nodeId: 'LOCAL-NODE-001',
|
||||
scopes: ['domain:enter'],
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
function receipt(overrides: Partial<DomainConnectionReceipt> = {}): DomainConnectionReceipt {
|
||||
return {
|
||||
connectionId: 'CONNECTION-001',
|
||||
domainId: 'DOM-FIFTH-0001',
|
||||
manifestDigest: DIGEST,
|
||||
nodeId: 'LOCAL-NODE-001',
|
||||
receiptId: 'RECEIPT-001',
|
||||
state: 'online',
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
describe('domain runtime contract', () => {
|
||||
it('projects only public vestibule fields', () => {
|
||||
const publicView = projectPublicDomainVestibule(manifest())
|
||||
const serialized = JSON.stringify(publicView)
|
||||
|
||||
expect(publicView.displayName).toBe('第五域 · 光湖本源域')
|
||||
expect(serialized).not.toContain('domain-route://')
|
||||
expect(serialized).not.toContain('CHANNEL-ZERO-CORE')
|
||||
expect(serialized).not.toContain('private-relationship-core')
|
||||
expect(serialized).not.toContain('REPO-012')
|
||||
})
|
||||
|
||||
it('rejects a manifest that has not passed the external signature verifier', () => {
|
||||
const candidate = manifest()
|
||||
candidate.verification.state = 'verified'
|
||||
candidate.verification.manifestDigest = 'b'.repeat(64)
|
||||
|
||||
expect(() => assertVerifiedDomainManifest(candidate)).toThrow('domain_manifest_digest_invalid')
|
||||
})
|
||||
|
||||
it.each(['LOCAL_TERMINAL_NODE', 'CLOUD_RESIDENT_NODE'] as const)(
|
||||
'accepts %s as a user-owned access node type',
|
||||
(nodeType) => {
|
||||
const selected = selectPublicDomain(INITIAL_DOMAIN_ACCESS_STATE, manifest().public)
|
||||
const access = beginDomainAccess(selected, manifest(), nodeType)
|
||||
|
||||
expect(access).toMatchObject({ nodeType, stage: 'access' })
|
||||
},
|
||||
)
|
||||
|
||||
it('does not enter a runtime with only a selected vestibule or frontend login state', () => {
|
||||
const selected = selectPublicDomain(INITIAL_DOMAIN_ACCESS_STATE, manifest().public)
|
||||
const access = beginDomainAccess(selected, manifest(), 'LOCAL_TERMINAL_NODE')
|
||||
|
||||
expect(() => enterDomainRuntime(access, NOW)).toThrow('domain_runtime_session_missing')
|
||||
const withSession = acceptDomainSession(access, session(), NOW)
|
||||
expect(() => enterDomainRuntime(withSession, NOW)).toThrow('domain_runtime_connection_receipt_missing')
|
||||
})
|
||||
|
||||
it('enters only after a matching live session and connection receipt', () => {
|
||||
const selected = selectPublicDomain(INITIAL_DOMAIN_ACCESS_STATE, manifest().public)
|
||||
const access = beginDomainAccess(selected, manifest(), 'LOCAL_TERMINAL_NODE')
|
||||
const withSession = acceptDomainSession(access, session(), NOW)
|
||||
const connected = acceptDomainConnectionReceipt(withSession, receipt())
|
||||
const runtime = enterDomainRuntime(connected, NOW)
|
||||
|
||||
expect(runtime).toMatchObject({
|
||||
mode: 'connected',
|
||||
nodeType: 'LOCAL_TERMINAL_NODE',
|
||||
stage: 'runtime',
|
||||
})
|
||||
})
|
||||
|
||||
it('fails closed when the session or receipt belongs to another domain', () => {
|
||||
const selected = selectPublicDomain(INITIAL_DOMAIN_ACCESS_STATE, manifest().public)
|
||||
const access = beginDomainAccess(selected, manifest(), 'LOCAL_TERMINAL_NODE')
|
||||
|
||||
expect(() => acceptDomainSession(access, session({ domainId: 'DOMAIN-OTHER' }), NOW))
|
||||
.toThrow('domain_session_domain_mismatch')
|
||||
|
||||
const withSession = acceptDomainSession(access, session(), NOW)
|
||||
expect(() => acceptDomainConnectionReceipt(withSession, receipt({ domainId: 'DOMAIN-OTHER' })))
|
||||
.toThrow('domain_connection_domain_mismatch')
|
||||
})
|
||||
|
||||
it('drops execution authority and keeps an explicit read-only scene after disconnect', () => {
|
||||
const selected = selectPublicDomain(INITIAL_DOMAIN_ACCESS_STATE, manifest().public)
|
||||
const access = beginDomainAccess(selected, manifest(), 'LOCAL_TERMINAL_NODE')
|
||||
const withSession = acceptDomainSession(access, session(), NOW)
|
||||
const connected = acceptDomainConnectionReceipt(withSession, receipt())
|
||||
const runtime = enterDomainRuntime(connected, NOW)
|
||||
|
||||
expect(disconnectDomainRuntime(runtime).mode).toBe('disconnected-readonly')
|
||||
})
|
||||
})
|
||||
Loading…
Reference in a new issue