@@ -210,6 +210,15 @@ async def handle_handshake(
210210 if nack is not None :
211211 return nack
212212
213+ # Ensure rotation chain exists for this initiator (idempotent)
214+ chain_registry = getattr (request .app .state , "chain_registry" , None )
215+ if chain_registry is not None :
216+ try :
217+ verify_key = resolve_public_key (body .initiator .did )
218+ chain_registry .register_chain (body .initiator .did , bytes (verify_key ))
219+ except Exception :
220+ pass # Best-effort; chain registration may already exist
221+
213222 # --- Proof-of-Work verification (anti-Sybil, v0.2) ---
214223 from airlock .config import get_config
215224
@@ -405,6 +414,16 @@ async def handle_register(profile: AgentProfile, request: Request) -> dict[str,
405414 registry : dict [str , AgentProfile ] = request .app .state .agent_registry
406415 registry [profile .did .did ] = profile
407416 request .app .state .agent_store .upsert (profile )
417+
418+ # Auto-register rotation chain so key rotation works for this DID
419+ chain_registry = getattr (request .app .state , "chain_registry" , None )
420+ if chain_registry is not None :
421+ try :
422+ verify_key = resolve_public_key (profile .did .did )
423+ chain_registry .register_chain (profile .did .did , bytes (verify_key ))
424+ except Exception as exc :
425+ logger .debug ("Chain registration skipped for %s: %s" , profile .did .did , exc )
426+
408427 _audit_bg (
409428 request ,
410429 event_type = "agent_registered" ,
@@ -811,9 +830,9 @@ async def handle_rotate_key(
811830 new_public_key_bytes = bytes (new_verify_key )
812831
813832 # Check pre-rotation commitment BEFORE first-write-wins
814- commitment_store : dict [ str , PreRotationCommitment ] = getattr (
815- request . app . state , "precommit_store" , {}
816- )
833+ from airlock . rotation . precommit_store import PreCommitmentStore
834+
835+ commitment_store : PreCommitmentStore = request . app . state . precommit_store
817836 existing_commitment = commitment_store .get (rotation_req .rotation_chain_id )
818837
819838 # Mandatory pre-commitment check for higher tiers
@@ -863,6 +882,16 @@ async def handle_rotate_key(
863882 grace_seconds = cfg .key_rotation_grace_seconds
864883 await revocation_store .rotate_out (rotation_req .old_did , grace_seconds = grace_seconds )
865884
885+ # On compromise: force immediate CRL regeneration so relying parties see it
886+ if reason == "compromise" :
887+ crl_gen = getattr (request .app .state , "crl_generator" , None )
888+ if crl_gen is not None :
889+ try :
890+ await crl_gen .force_regenerate ()
891+ logger .info ("CRL force-regenerated after key compromise: %s" , rotation_req .old_did )
892+ except Exception as exc :
893+ logger .error ("CRL force-regeneration failed: %s" , exc )
894+
866895 # Transfer trust score via chain_id with penalty
867896 if trust_score is not None :
868897 penalty = cfg .key_rotation_trust_penalty
@@ -893,16 +922,19 @@ async def handle_rotate_key(
893922
894923 # Handle chained commitment (N+2)
895924 if rotation_req .next_key_commitment :
896- commitment_store [rotation_req .rotation_chain_id ] = PreRotationCommitment (
897- alg = "sha256" ,
898- digest = rotation_req .next_key_commitment ,
899- committed_at = datetime .now (UTC ),
900- committed_by_did = rotation_req .new_did ,
901- signature = "" , # Commitment is embedded in the signed rotation request
925+ commitment_store .put (
926+ rotation_req .rotation_chain_id ,
927+ PreRotationCommitment (
928+ alg = "sha256" ,
929+ digest = rotation_req .next_key_commitment ,
930+ committed_at = datetime .now (UTC ),
931+ committed_by_did = rotation_req .new_did ,
932+ signature = "" , # Commitment is embedded in the signed rotation request
933+ ),
902934 )
903935 else :
904936 # Clear the used commitment
905- commitment_store .pop (rotation_req .rotation_chain_id , None )
937+ commitment_store .delete (rotation_req .rotation_chain_id )
906938
907939 _audit_bg (
908940 request ,
@@ -998,9 +1030,9 @@ async def handle_pre_commit_key(
9981030 raise HTTPException (status_code = 404 , detail = "DID not registered in any chain" )
9991031
10001032 # Check existing commitment and lockout
1001- commitment_store : dict [ str , PreRotationCommitment ] = getattr (
1002- request . app . state , "precommit_store" , {}
1003- )
1033+ from airlock . rotation . precommit_store import PreCommitmentStore
1034+
1035+ commitment_store : PreCommitmentStore = request . app . state . precommit_store
10041036 existing = commitment_store .get (chain_id )
10051037 if existing is not None :
10061038 if not can_update_commitment (existing , lockout_hours = cfg .pre_rotation_update_lockout_hours ):
@@ -1017,7 +1049,7 @@ async def handle_pre_commit_key(
10171049 committed_by_did = commit_req .did ,
10181050 signature = commit_req .signature ,
10191051 )
1020- commitment_store [ chain_id ] = commitment
1052+ commitment_store . put ( chain_id , commitment )
10211053
10221054 _audit_bg (
10231055 request ,
0 commit comments