@@ -6125,8 +6125,49 @@ pub async fn sandbox_policy_get(
61256125 name : & str ,
61266126 version : u32 ,
61276127 full : bool ,
6128+ output : & str ,
61286129 tls : & TlsOptions ,
61296130) -> Result < ( ) > {
6131+ let mut stdout = Vec :: new ( ) ;
6132+ let mut stderr = Vec :: new ( ) ;
6133+ sandbox_policy_get_to_writer (
6134+ server,
6135+ name,
6136+ version,
6137+ full,
6138+ output,
6139+ tls,
6140+ ( & mut stdout, & mut stderr) ,
6141+ )
6142+ . await ?;
6143+
6144+ {
6145+ let mut terminal_stdout = std:: io:: stdout ( ) . lock ( ) ;
6146+ terminal_stdout. write_all ( & stdout) . into_diagnostic ( ) ?;
6147+ }
6148+ {
6149+ let mut terminal_stderr = std:: io:: stderr ( ) . lock ( ) ;
6150+ terminal_stderr. write_all ( & stderr) . into_diagnostic ( ) ?;
6151+ }
6152+
6153+ Ok ( ( ) )
6154+ }
6155+
6156+ #[ doc( hidden) ]
6157+ pub async fn sandbox_policy_get_to_writer < W , E > (
6158+ server : & str ,
6159+ name : & str ,
6160+ version : u32 ,
6161+ full : bool ,
6162+ output : & str ,
6163+ tls : & TlsOptions ,
6164+ writers : ( & mut W , & mut E ) ,
6165+ ) -> Result < ( ) >
6166+ where
6167+ W : Write + Send ,
6168+ E : Write + Send ,
6169+ {
6170+ let ( stdout, stderr) = writers;
61306171 let mut client = grpc_client ( server, tls) . await ?;
61316172
61326173 let status_resp = client
@@ -6141,32 +6182,55 @@ pub async fn sandbox_policy_get(
61416182 let inner = status_resp. into_inner ( ) ;
61426183 if let Some ( rev) = inner. revision {
61436184 let status = PolicyStatus :: try_from ( rev. status ) . unwrap_or ( PolicyStatus :: Unspecified ) ;
6144- println ! ( "Version: {}" , rev. version) ;
6145- println ! ( "Hash: {}" , rev. policy_hash) ;
6146- println ! ( "Status: {status:?}" ) ;
6147- println ! ( "Active: {}" , inner. active_version) ;
6185+ match output {
6186+ "json" => {
6187+ let obj = policy_revision_to_json (
6188+ "sandbox" ,
6189+ Some ( name) ,
6190+ Some ( inner. active_version ) ,
6191+ & rev,
6192+ status,
6193+ full,
6194+ ) ?;
6195+ writeln ! (
6196+ stdout,
6197+ "{}" ,
6198+ serde_json:: to_string_pretty( & obj) . into_diagnostic( ) ?
6199+ )
6200+ . into_diagnostic ( ) ?;
6201+ return Ok ( ( ) ) ;
6202+ }
6203+ "table" => { }
6204+ _ => return Err ( miette ! ( "unsupported output format: {output}" ) ) ,
6205+ }
6206+
6207+ writeln ! ( stdout, "Version: {}" , rev. version) . into_diagnostic ( ) ?;
6208+ writeln ! ( stdout, "Hash: {}" , rev. policy_hash) . into_diagnostic ( ) ?;
6209+ writeln ! ( stdout, "Status: {status:?}" ) . into_diagnostic ( ) ?;
6210+ writeln ! ( stdout, "Active: {}" , inner. active_version) . into_diagnostic ( ) ?;
61486211 if rev. created_at_ms > 0 {
6149- println ! ( "Created: {} ms" , rev. created_at_ms) ;
6212+ writeln ! ( stdout , "Created: {} ms" , rev. created_at_ms) . into_diagnostic ( ) ? ;
61506213 }
61516214 if rev. loaded_at_ms > 0 {
6152- println ! ( "Loaded: {} ms" , rev. loaded_at_ms) ;
6215+ writeln ! ( stdout , "Loaded: {} ms" , rev. loaded_at_ms) . into_diagnostic ( ) ? ;
61536216 }
61546217 if !rev. load_error . is_empty ( ) {
6155- println ! ( "Error: {}" , rev. load_error) ;
6218+ writeln ! ( stdout , "Error: {}" , rev. load_error) . into_diagnostic ( ) ? ;
61566219 }
61576220
61586221 if full {
61596222 if let Some ( ref policy) = rev. policy {
6160- println ! ( "---" ) ;
6223+ writeln ! ( stdout , "---" ) . into_diagnostic ( ) ? ;
61616224 let yaml_str = openshell_policy:: serialize_sandbox_policy ( policy)
61626225 . wrap_err ( "failed to serialize policy to YAML" ) ?;
6163- print ! ( "{yaml_str}" ) ;
6226+ write ! ( stdout , "{yaml_str}" ) . into_diagnostic ( ) ? ;
61646227 } else {
6165- eprintln ! ( "Policy payload not available for this version" ) ;
6228+ writeln ! ( stderr, "Policy payload not available for this version" )
6229+ . into_diagnostic ( ) ?;
61666230 }
61676231 }
61686232 } else {
6169- eprintln ! ( "No policy history found for sandbox '{name}'" ) ;
6233+ writeln ! ( stderr , "No policy history found for sandbox '{name}'" ) . into_diagnostic ( ) ? ;
61706234 }
61716235
61726236 Ok ( ( ) )
@@ -6176,6 +6240,7 @@ pub async fn sandbox_policy_get_global(
61766240 server : & str ,
61776241 version : u32 ,
61786242 full : bool ,
6243+ output : & str ,
61796244 tls : & TlsOptions ,
61806245) -> Result < ( ) > {
61816246 let mut client = grpc_client ( server, tls) . await ?;
@@ -6192,6 +6257,16 @@ pub async fn sandbox_policy_get_global(
61926257 let inner = status_resp. into_inner ( ) ;
61936258 if let Some ( rev) = inner. revision {
61946259 let status = PolicyStatus :: try_from ( rev. status ) . unwrap_or ( PolicyStatus :: Unspecified ) ;
6260+ match output {
6261+ "json" => {
6262+ let obj = policy_revision_to_json ( "global" , None , None , & rev, status, full) ?;
6263+ println ! ( "{}" , serde_json:: to_string_pretty( & obj) . into_diagnostic( ) ?) ;
6264+ return Ok ( ( ) ) ;
6265+ }
6266+ "table" => { }
6267+ _ => return Err ( miette ! ( "unsupported output format: {output}" ) ) ,
6268+ }
6269+
61956270 println ! ( "Scope: global" ) ;
61966271 println ! ( "Version: {}" , rev. version) ;
61976272 println ! ( "Hash: {}" , rev. policy_hash) ;
@@ -6220,6 +6295,66 @@ pub async fn sandbox_policy_get_global(
62206295 Ok ( ( ) )
62216296}
62226297
6298+ fn policy_status_json_name ( status : PolicyStatus ) -> & ' static str {
6299+ match status {
6300+ PolicyStatus :: Unspecified => "unspecified" ,
6301+ PolicyStatus :: Pending => "pending" ,
6302+ PolicyStatus :: Loaded => "loaded" ,
6303+ PolicyStatus :: Failed => "failed" ,
6304+ PolicyStatus :: Superseded => "superseded" ,
6305+ }
6306+ }
6307+
6308+ fn policy_revision_to_json (
6309+ scope : & str ,
6310+ sandbox : Option < & str > ,
6311+ active_version : Option < u32 > ,
6312+ rev : & openshell_core:: proto:: SandboxPolicyRevision ,
6313+ status : PolicyStatus ,
6314+ full : bool ,
6315+ ) -> Result < serde_json:: Value > {
6316+ let mut obj = serde_json:: Map :: new ( ) ;
6317+ obj. insert ( "scope" . to_string ( ) , serde_json:: json!( scope) ) ;
6318+ if let Some ( sandbox) = sandbox {
6319+ obj. insert ( "sandbox" . to_string ( ) , serde_json:: json!( sandbox) ) ;
6320+ }
6321+ obj. insert ( "version" . to_string ( ) , serde_json:: json!( rev. version) ) ;
6322+ obj. insert ( "hash" . to_string ( ) , serde_json:: json!( rev. policy_hash) ) ;
6323+ obj. insert (
6324+ "status" . to_string ( ) ,
6325+ serde_json:: json!( policy_status_json_name( status) ) ,
6326+ ) ;
6327+ if let Some ( active_version) = active_version {
6328+ obj. insert (
6329+ "active_version" . to_string ( ) ,
6330+ serde_json:: json!( active_version) ,
6331+ ) ;
6332+ }
6333+ if rev. created_at_ms > 0 {
6334+ obj. insert (
6335+ "created_at_ms" . to_string ( ) ,
6336+ serde_json:: json!( rev. created_at_ms) ,
6337+ ) ;
6338+ }
6339+ if rev. loaded_at_ms > 0 {
6340+ obj. insert (
6341+ "loaded_at_ms" . to_string ( ) ,
6342+ serde_json:: json!( rev. loaded_at_ms) ,
6343+ ) ;
6344+ }
6345+ if !rev. load_error . is_empty ( ) {
6346+ obj. insert ( "load_error" . to_string ( ) , serde_json:: json!( rev. load_error) ) ;
6347+ }
6348+ if full {
6349+ let policy = match rev. policy . as_ref ( ) {
6350+ Some ( policy) => openshell_policy:: sandbox_policy_to_json_value ( policy) ?,
6351+ None => serde_json:: Value :: Null ,
6352+ } ;
6353+ obj. insert ( "policy" . to_string ( ) , policy) ;
6354+ }
6355+ Ok ( serde_json:: Value :: Object ( obj) )
6356+ }
6357+
62236358pub async fn sandbox_policy_list (
62246359 server : & str ,
62256360 name : & str ,
0 commit comments