feat: define signed persona authorization trust contract

This commit is contained in:
冰朔 2026-08-12 05:09:56 +08:00
commit c4504fa115
13 changed files with 470 additions and 14 deletions

View file

@ -56,7 +56,7 @@ describe('PersonaLanguageShellPanel', () => {
repositoryPaths: ['/persona'],
providers: [provider],
developmentId: 'DEV-20260811-010',
sourceLanguageAnchor: 'HLP-CURRENT-ARCH-001@2026-08-12.11',
sourceLanguageAnchor: 'HLP-CURRENT-ARCH-001@2026-08-12.12',
}))
expect(await screen.findByText('我还不能执行:需要当前证据。')).toBeInTheDocument()
expect(screen.getByText('核验当前事实后规划下一步')).toBeInTheDocument()

View file

@ -13,7 +13,7 @@ import {
type LanguageShellViewState,
} from './HotPluggableLanguageShell'
const CURRENT_ARCHITECTURE_ANCHOR = 'HLP-CURRENT-ARCH-001@2026-08-12.11'
const CURRENT_ARCHITECTURE_ANCHOR = 'HLP-CURRENT-ARCH-001@2026-08-12.12'
const DEVELOPMENT_ID = 'DEV-20260811-010'
type Planner = typeof planPersonaLanguageShellGoal

View file

@ -11,7 +11,7 @@ const expected = {
repositoryHead: 'a'.repeat(40),
modelInstanceId: 'MODEL-INSTANCE-001',
requestId: 'REQ-001',
sourceLanguageAnchor: 'HLP-CURRENT-ARCH-001@2026-08-12.11',
sourceLanguageAnchor: 'HLP-CURRENT-ARCH-001@2026-08-12.12',
observedAt: Date.parse('2026-08-12T04:35:00+08:00'),
}
@ -30,6 +30,9 @@ const receipt = {
issuedAt: '2026-08-12T04:30:00+08:00',
validUntil: '2026-08-12T04:40:00+08:00',
evidenceDigest: 'b'.repeat(64),
signerId: 'GH-AIOS-AUTHORIZER-001',
signatureAlgorithm: 'Ed25519',
signature: 'A'.repeat(86),
}
describe('hasPersonaPrimaryControlAuthorization', () => {
@ -48,6 +51,8 @@ describe('hasPersonaPrimaryControlAuthorization', () => {
['expired', { ...receipt, validUntil: '2026-08-12T04:34:59+08:00' }],
['future', { ...receipt, issuedAt: '2026-08-12T04:35:01+08:00' }],
['invalid digest', { ...receipt, evidenceDigest: 'not-a-digest' }],
['missing signer', { ...receipt, signerId: '' }],
['invalid signature', { ...receipt, signature: 'not-a-signature' }],
])('fails closed for %s evidence', (_label, candidate) => {
expect(hasPersonaPrimaryControlAuthorization(candidate, expected)).toBe(false)
})

View file

@ -1,4 +1,4 @@
export const PERSONA_CONTROL_AUTHORIZATION_SCHEMA = 'hololake.persona-control-authorization/v1' as const
export const PERSONA_CONTROL_AUTHORIZATION_SCHEMA = 'hololake.persona-control-authorization/v2' as const
export const PERSONA_PRIMARY_LANGUAGE_PLANNING_SCOPE = 'PERSONA_PRIMARY_LANGUAGE_PLANNING' as const
export type PersonaControlAuthorizationReceipt = {
@ -16,6 +16,9 @@ export type PersonaControlAuthorizationReceipt = {
issuedAt: string
validUntil: string
evidenceDigest: string
signerId: string
signatureAlgorithm: 'Ed25519'
signature: string
}
export type PersonaControlAuthorizationExpectation = {
@ -48,6 +51,7 @@ export function hasPersonaPrimaryControlAuthorization(
if (!exactString(receipt, 'schema', PERSONA_CONTROL_AUTHORIZATION_SCHEMA)
|| !exactString(receipt, 'outcome', 'VERIFIED')
|| !exactString(receipt, 'verifier', 'GUANGHU_OS')
|| !exactString(receipt, 'signatureAlgorithm', 'Ed25519')
|| !exactString(receipt, 'scope', PERSONA_PRIMARY_LANGUAGE_PLANNING_SCOPE)
|| !exactString(receipt, 'personaId', expected.personaId)
|| !exactString(receipt, 'humanResponsibilitySubject', expected.humanResponsibilitySubject)
@ -60,10 +64,14 @@ export function hasPersonaPrimaryControlAuthorization(
const authorizationId = Reflect.get(receipt, 'authorizationId')
const evidenceDigest = Reflect.get(receipt, 'evidenceDigest')
const signerId = Reflect.get(receipt, 'signerId')
const signature = Reflect.get(receipt, 'signature')
const issuedAt = Reflect.get(receipt, 'issuedAt')
const validUntil = Reflect.get(receipt, 'validUntil')
if (typeof authorizationId !== 'string' || !authorizationId.trim()
|| typeof evidenceDigest !== 'string' || !/^[a-f0-9]{64}$/.test(evidenceDigest)
|| typeof signerId !== 'string' || !/^[A-Z0-9][A-Z0-9._:@-]{1,159}$/.test(signerId)
|| typeof signature !== 'string' || !/^[A-Za-z0-9_-]{80,128}$/.test(signature)
|| typeof issuedAt !== 'string'
|| typeof validUntil !== 'string') {
return false

View file

@ -181,7 +181,7 @@ describe('planPersonaLanguageShellGoal', () => {
await planPersonaLanguageShellGoal({
...input(),
loadPersonaControlAuthorization: vi.fn().mockResolvedValue({
schema: 'hololake.persona-control-authorization/v1',
schema: 'hololake.persona-control-authorization/v2',
outcome: 'VERIFIED',
authorizationId: 'AUTH-001',
verifier: 'GUANGHU_OS',
@ -195,6 +195,9 @@ describe('planPersonaLanguageShellGoal', () => {
issuedAt: '2026-08-12T04:30:00+08:00',
validUntil: '2026-08-12T04:40:00+08:00',
evidenceDigest: 'c'.repeat(64),
signerId: 'GH-AIOS-AUTHORIZER-001',
signatureAlgorithm: 'Ed25519',
signature: 'A'.repeat(86),
}),
authorizationObservedAt: Date.parse('2026-08-12T04:35:00+08:00'),
resolveRepository: vi.fn().mockResolvedValue(boundResolution()),