@@ -480,36 +480,7 @@ impl ComputeRuntime {
480480 . map_err ( |e| Status :: internal ( format ! ( "persist sandbox failed: {e}" ) ) ) ?;
481481 self . sandbox_index . update_from_sandbox ( & sandbox) ;
482482 self . sandbox_watch_bus . notify ( & id) ;
483-
484- if let Ok ( records) = self . store . list ( SshSession :: object_type ( ) , 1000 , 0 ) . await {
485- for record in records {
486- if let Ok ( session) = SshSession :: decode ( record. payload . as_slice ( ) )
487- && session. sandbox_id == id
488- && let Err ( e) = self
489- . store
490- . delete ( SshSession :: object_type ( ) , session. object_id ( ) )
491- . await
492- {
493- warn ! (
494- session_id = %session. object_id( ) ,
495- error = %e,
496- "Failed to delete SSH session during sandbox cleanup"
497- ) ;
498- }
499- }
500- }
501-
502- if let Err ( e) = self
503- . store
504- . delete_by_name ( SANDBOX_SETTINGS_OBJECT_TYPE , sandbox. object_name ( ) )
505- . await
506- {
507- warn ! (
508- sandbox_id = %id,
509- error = %e,
510- "Failed to delete sandbox settings during cleanup"
511- ) ;
512- }
483+ self . cleanup_sandbox_owned_records ( & sandbox) . await ;
513484
514485 let driver_sandbox = driver_sandbox_from_public ( & sandbox) ;
515486 let deleted = self
@@ -959,6 +930,15 @@ impl ComputeRuntime {
959930 }
960931
961932 async fn apply_deleted_locked ( & self , sandbox_id : & str ) -> Result < ( ) , String > {
933+ let sandbox = self
934+ . store
935+ . get_message :: < Sandbox > ( sandbox_id)
936+ . await
937+ . map_err ( |e| e. to_string ( ) ) ?;
938+ if let Some ( sandbox) = sandbox. as_ref ( ) {
939+ self . cleanup_sandbox_owned_records ( sandbox) . await ;
940+ }
941+
962942 let _ = self
963943 . store
964944 . delete ( Sandbox :: object_type ( ) , sandbox_id)
@@ -970,6 +950,44 @@ impl ComputeRuntime {
970950 Ok ( ( ) )
971951 }
972952
953+ async fn cleanup_sandbox_owned_records ( & self , sandbox : & Sandbox ) {
954+ self . cleanup_sandbox_ssh_sessions ( sandbox. object_id ( ) ) . await ;
955+
956+ if let Err ( e) = self
957+ . store
958+ . delete_by_name ( SANDBOX_SETTINGS_OBJECT_TYPE , sandbox. object_name ( ) )
959+ . await
960+ {
961+ warn ! (
962+ sandbox_id = %sandbox. object_id( ) ,
963+ sandbox_name = %sandbox. object_name( ) ,
964+ error = %e,
965+ "Failed to delete sandbox settings during cleanup"
966+ ) ;
967+ }
968+ }
969+
970+ async fn cleanup_sandbox_ssh_sessions ( & self , sandbox_id : & str ) {
971+ if let Ok ( records) = self . store . list ( SshSession :: object_type ( ) , 1000 , 0 ) . await {
972+ for record in records {
973+ if let Ok ( session) = SshSession :: decode ( record. payload . as_slice ( ) )
974+ && session. sandbox_id == sandbox_id
975+ && let Err ( e) = self
976+ . store
977+ . delete ( SshSession :: object_type ( ) , session. object_id ( ) )
978+ . await
979+ {
980+ warn ! (
981+ sandbox_id = %sandbox_id,
982+ session_id = %session. object_id( ) ,
983+ error = %e,
984+ "Failed to delete SSH session during sandbox cleanup"
985+ ) ;
986+ }
987+ }
988+ }
989+ }
990+
973991 fn cleanup_sandbox_state ( & self , sandbox_id : & str ) {
974992 self . tracing_log_bus . remove ( sandbox_id) ;
975993 self . tracing_log_bus . platform_event_bus . remove ( sandbox_id) ;
@@ -1776,6 +1794,21 @@ mod tests {
17761794 }
17771795 }
17781796
1797+ fn ssh_session_record ( id : & str , sandbox_id : & str ) -> SshSession {
1798+ SshSession {
1799+ metadata : Some ( openshell_core:: proto:: datamodel:: v1:: ObjectMeta {
1800+ id : id. to_string ( ) ,
1801+ name : format ! ( "session-{id}" ) ,
1802+ created_at_ms : 1000000 ,
1803+ labels : std:: collections:: HashMap :: new ( ) ,
1804+ } ) ,
1805+ sandbox_id : sandbox_id. to_string ( ) ,
1806+ token : format ! ( "token-{id}" ) ,
1807+ revoked : false ,
1808+ expires_at_ms : 0 ,
1809+ }
1810+ }
1811+
17791812 fn make_driver_condition ( reason : & str , message : & str ) -> DriverCondition {
17801813 DriverCondition {
17811814 r#type : "Ready" . to_string ( ) ,
@@ -2427,6 +2460,19 @@ mod tests {
24272460 let sandbox = sandbox_record ( "sb-1" , "sandbox-a" , SandboxPhase :: Provisioning ) ;
24282461 runtime. store . put_message ( & sandbox) . await . unwrap ( ) ;
24292462 runtime. sandbox_index . update_from_sandbox ( & sandbox) ;
2463+ runtime
2464+ . store
2465+ . put (
2466+ SANDBOX_SETTINGS_OBJECT_TYPE ,
2467+ "settings-sb-1" ,
2468+ sandbox. object_name ( ) ,
2469+ br#"{"revision":1,"settings":{}}"# ,
2470+ None ,
2471+ )
2472+ . await
2473+ . unwrap ( ) ;
2474+ let session = ssh_session_record ( "session-1" , sandbox. object_id ( ) ) ;
2475+ runtime. store . put_message ( & session) . await . unwrap ( ) ;
24302476
24312477 let mut watch_rx = runtime. sandbox_watch_bus . subscribe ( sandbox. object_id ( ) ) ;
24322478
@@ -2449,6 +2495,22 @@ mod tests {
24492495 . sandbox_id_for_sandbox_name( sandbox. object_name( ) )
24502496 . is_none( )
24512497 ) ;
2498+ assert ! (
2499+ runtime
2500+ . store
2501+ . get_by_name( SANDBOX_SETTINGS_OBJECT_TYPE , sandbox. object_name( ) )
2502+ . await
2503+ . unwrap( )
2504+ . is_none( )
2505+ ) ;
2506+ assert ! (
2507+ runtime
2508+ . store
2509+ . get_message:: <SshSession >( session. object_id( ) )
2510+ . await
2511+ . unwrap( )
2512+ . is_none( )
2513+ ) ;
24522514 let _ = watch_rx. try_recv ( ) ;
24532515 assert ! ( matches!(
24542516 watch_rx. try_recv( ) ,
0 commit comments