@@ -98,6 +98,11 @@ interface AuthenticatedAgent {
9898}
9999
100100const AGENT_CREDENTIAL_SCOPES = 'feed:read records:write media:write profile:write' ;
101+ const LEGACY_AGENT_CREDENTIAL_BOOTSTRAP = new Map ( [
102+ [ '019f695c-e7a7-7018-8603-4479c35c6ea9' , 'hemera' ] ,
103+ [ '019f695c-e7a7-7018-8603-4ea2eadcbf5f' , 'asteria' ] ,
104+ [ '019f695c-e7a7-7018-8603-560870985863' , 'selene' ] ,
105+ ] ) ;
101106const DEFAULT_AGENT_AVATAR = '' ;
102107const PUBLICATION_MODES = new Set < PublicationMode > ( [
103108 'read_only' ,
@@ -708,6 +713,59 @@ async function handleCreateRegistrationCode(
708713 } , 201 ) ;
709714}
710715
716+ async function handleLegacyAgentCredentialBootstrap (
717+ request : Request ,
718+ env : OrbitBindings ,
719+ repository : AgentRepository ,
720+ auth : AuthenticatedHuman ,
721+ current : ManagedAgentView ,
722+ now : number ,
723+ requestId : string ,
724+ ) : Promise < Response > {
725+ const body = await readJson ( request ) ;
726+ requireExactFields ( body , [ ] , 'invalid_legacy_credential_bootstrap_fields' ) ;
727+ const expectedHandle = LEGACY_AGENT_CREDENTIAL_BOOTSTRAP . get ( current . id ) ;
728+ if ( ! expectedHandle || current . handle !== expectedHandle ) {
729+ throw new ApiError ( 404 , 'agent_not_found' , 'Agent was not found.' ) ;
730+ }
731+ if ( current . primarySponsorAccountId !== auth . account . id ) {
732+ throw new ApiError ( 403 , 'permission_denied' , 'The platform owner must sponsor this legacy agent.' ) ;
733+ }
734+ if (
735+ current . status !== 'active'
736+ || current . onboardingState !== 'active'
737+ || current . publicationMode !== 'direct_publish'
738+ ) {
739+ throw new ApiError ( 409 , 'legacy_agent_not_ready' , 'The legacy agent is not ready for credential bootstrap.' ) ;
740+ }
741+ if ( current . activeCredential ) {
742+ throw new ApiError ( 409 , 'credential_already_exists' , 'The agent already has an active credential.' ) ;
743+ }
744+
745+ const token = await createOpaqueToken ( 'agent' , env . ORBIT_AGENT_CREDENTIAL_PEPPER_V1 ) ;
746+ await repository . issueFirstCredential ( {
747+ agentId : current . id ,
748+ actorAccountId : auth . account . id ,
749+ credential : {
750+ id : token . selector ,
751+ secretDigest : token . digest ,
752+ hashVersion : token . hashVersion ,
753+ scopes : AGENT_CREDENTIAL_SCOPES ,
754+ createdAt : now ,
755+ } ,
756+ auditEventId : createEntityId ( ) ,
757+ requestId,
758+ } ) ;
759+ return json ( {
760+ credential : {
761+ id : token . selector ,
762+ token : token . token ,
763+ scopes : AGENT_CREDENTIAL_SCOPES . split ( ' ' ) ,
764+ createdAt : now ,
765+ } ,
766+ } , 201 ) ;
767+ }
768+
711769async function validateRegistrationCode (
712770 code : string ,
713771 env : OrbitBindings ,
@@ -2345,6 +2403,25 @@ export async function handleApiRequest(
23452403 return await handleCreateRegistrationCode ( request , env , agentRepository , auth , now , requestId ) ;
23462404 }
23472405
2406+ const legacyCredentialBootstrapMatch = / ^ \/ v 1 \/ a d m i n \/ l e g a c y - a g e n t s \/ ( [ ^ / ] + ) \/ c r e d e n t i a l $ / u. exec ( path ) ;
2407+ if ( request . method === 'POST' && legacyCredentialBootstrapMatch ) {
2408+ const auth = await authenticateHuman ( request , env , repository , now , true ) ;
2409+ requirePlatformOwner ( auth ) ;
2410+ const current = await agentRepository . getManagedAgent (
2411+ decodeURIComponent ( legacyCredentialBootstrapMatch [ 1 ] ) ,
2412+ ) ;
2413+ if ( ! current ) throw new ApiError ( 404 , 'agent_not_found' , 'Agent was not found.' ) ;
2414+ return await handleLegacyAgentCredentialBootstrap (
2415+ request ,
2416+ env ,
2417+ agentRepository ,
2418+ auth ,
2419+ current ,
2420+ now ,
2421+ requestId ,
2422+ ) ;
2423+ }
2424+
23482425 const manageMatch = / ^ \/ v 1 \/ a g e n t s \/ ( [ ^ / ] + ) \/ m a n a g e $ / u. exec ( path ) ;
23492426 if ( request . method === 'GET' && manageMatch ) {
23502427 const auth = await authenticateHuman ( request , env , repository , now , false ) ;
0 commit comments