@@ -73,6 +73,30 @@ use std::time::{Duration, Instant};
7373use tonic:: { Code , Status } ;
7474
7575const PROVISIONAL_CONTAINER_EXIT_RECONCILIATION_TIMEOUT : Duration = Duration :: from_secs ( 5 ) ;
76+ const POLICY_WAIT_TIMEOUT_EXIT_CODE : i32 = 124 ;
77+
78+ fn report_policy_wait_timeout ( status : & Status ) -> Option < i32 > {
79+ if status. code ( ) != Code :: DeadlineExceeded {
80+ return None ;
81+ }
82+ let operation_id = status
83+ . metadata ( )
84+ . get ( "operation-id" )
85+ . and_then ( |value| value. to_str ( ) . ok ( ) ) ;
86+ if let Some ( operation_id) = operation_id {
87+ eprintln ! (
88+ "{} Timeout waiting for policy update operation {}; update remains committed" ,
89+ "✗" . red( ) . bold( ) ,
90+ operation_id
91+ ) ;
92+ } else {
93+ eprintln ! (
94+ "{} Timeout waiting for policy update; update remains committed" ,
95+ "✗" . red( ) . bold( )
96+ ) ;
97+ }
98+ Some ( POLICY_WAIT_TIMEOUT_EXIT_CODE )
99+ }
76100
77101fn report_config_update_operation (
78102 operation : Option < & ConfigUpdateOperation > ,
@@ -4976,7 +5000,7 @@ pub async fn sandbox_policy_set(
49765000 timeout_secs : u64 ,
49775001 workspace : & str ,
49785002 tls : & TlsOptions ,
4979- ) -> Result < ( ) > {
5003+ ) -> Result < i32 > {
49805004 let policy = load_sandbox_policy ( Some ( policy_path) ) ?
49815005 . ok_or_else ( || miette:: miette!( "No policy loaded from {policy_path}" ) ) ?;
49825006
@@ -4997,7 +5021,7 @@ pub async fn sandbox_policy_set(
49975021 . and_then ( |r| r. into_inner ( ) . revision )
49985022 . map_or ( 0 , |r| r. version ) ;
49995023
5000- let response = client
5024+ let response = match client
50015025 . update_config ( UpdateConfigRequest {
50025026 sandbox : name. to_string ( ) ,
50035027 workspace_scope : Some ( openshell_core:: proto:: workspace_selector (
@@ -5016,7 +5040,16 @@ pub async fn sandbox_policy_set(
50165040 ..Default :: default ( )
50175041 } )
50185042 . await
5019- . into_diagnostic ( ) ?;
5043+ {
5044+ Ok ( response) => response,
5045+ Err ( status) if wait => {
5046+ if let Some ( exit_code) = report_policy_wait_timeout ( & status) {
5047+ return Ok ( exit_code) ;
5048+ }
5049+ return Err ( status) . into_diagnostic ( ) ;
5050+ }
5051+ Err ( status) => return Err ( status) . into_diagnostic ( ) ,
5052+ } ;
50205053
50215054 let resp = response. into_inner ( ) ;
50225055
@@ -5027,7 +5060,7 @@ pub async fn sandbox_policy_set(
50275060 resp. version,
50285061 & resp. policy_hash[ ..12 ]
50295062 ) ;
5030- return Ok ( ( ) ) ;
5063+ return Ok ( 0 ) ;
50315064 }
50325065
50335066 eprintln ! (
@@ -5038,10 +5071,11 @@ pub async fn sandbox_policy_set(
50385071 ) ;
50395072
50405073 if !wait {
5041- return Ok ( ( ) ) ;
5074+ return Ok ( 0 ) ;
50425075 }
50435076
5044- report_config_update_operation ( resp. operation . as_ref ( ) , resp. version )
5077+ report_config_update_operation ( resp. operation . as_ref ( ) , resp. version ) ?;
5078+ Ok ( 0 )
50455079}
50465080
50475081/// Preview or atomically submit explicitly scoped incremental policy operations.
@@ -5063,7 +5097,7 @@ pub async fn sandbox_policy_update(
50635097 timeout_secs : u64 ,
50645098 workspace : & str ,
50655099 tls : & TlsOptions ,
5066- ) -> Result < ( ) > {
5100+ ) -> Result < i32 > {
50675101 if dry_run && wait {
50685102 return Err ( miette ! ( "--wait cannot be combined with --dry-run" ) ) ;
50695103 }
@@ -5112,12 +5146,12 @@ pub async fn sandbox_policy_update(
51125146 ) ;
51135147 print_policy_merge_warnings ( & merged. warnings ) ;
51145148 print_sandbox_policy ( & merged. policy ) ;
5115- return Ok ( ( ) ) ;
5149+ return Ok ( 0 ) ;
51165150 }
51175151
51185152 let current_version = current. version ;
51195153 let current_hash = current. policy_hash . clone ( ) ;
5120- let response = client
5154+ let response = match client
51215155 . update_config ( UpdateConfigRequest {
51225156 sandbox : name. to_string ( ) ,
51235157 workspace_scope : Some ( openshell_core:: proto:: workspace_selector (
@@ -5136,8 +5170,16 @@ pub async fn sandbox_policy_update(
51365170 ..Default :: default ( )
51375171 } )
51385172 . await
5139- . into_diagnostic ( ) ?
5140- . into_inner ( ) ;
5173+ {
5174+ Ok ( response) => response. into_inner ( ) ,
5175+ Err ( status) if wait => {
5176+ if let Some ( exit_code) = report_policy_wait_timeout ( & status) {
5177+ return Ok ( exit_code) ;
5178+ }
5179+ return Err ( status) . into_diagnostic ( ) ;
5180+ }
5181+ Err ( status) => return Err ( status) . into_diagnostic ( ) ,
5182+ } ;
51415183
51425184 print_policy_merge_warnings ( & merged. warnings ) ;
51435185
@@ -5148,7 +5190,7 @@ pub async fn sandbox_policy_update(
51485190 response. version,
51495191 short_hash( & response. policy_hash)
51505192 ) ;
5151- return Ok ( ( ) ) ;
5193+ return Ok ( 0 ) ;
51525194 }
51535195
51545196 eprintln ! (
@@ -5159,10 +5201,11 @@ pub async fn sandbox_policy_update(
51595201 ) ;
51605202
51615203 if !wait {
5162- return Ok ( ( ) ) ;
5204+ return Ok ( 0 ) ;
51635205 }
51645206
5165- report_config_update_operation ( response. operation . as_ref ( ) , response. version )
5207+ report_config_update_operation ( response. operation . as_ref ( ) , response. version ) ?;
5208+ Ok ( 0 )
51665209}
51675210
51685211pub async fn sandbox_policy_get (
0 commit comments