@@ -557,58 +557,6 @@ fn probe_processcontainer(wxc: &PathBuf) -> Result<(), String> {
557557 Ok ( ( ) )
558558}
559559
560- /// Probe the released binary's live `network.proxy` support separately from
561- /// ordinary `ProcessContainer` support. Some builds accept the proxy JSON during
562- /// `--dry-run` but return `ERROR_INVALID_PARAMETER` from the live launcher.
563- fn probe_processcontainer_proxy ( wxc : & PathBuf ) -> Result < ( ) , String > {
564- let ( _tempdir, temp_path) = temp_fixture ( ) ;
565- let proxy_listener = std:: net:: TcpListener :: bind ( "127.0.0.1:0" )
566- . map_err ( |error| format ! ( "failed to reserve proxy probe port: {error}" ) ) ?;
567- let proxy_port = proxy_listener
568- . local_addr ( )
569- . map_err ( |error| format ! ( "failed to read proxy probe port: {error}" ) ) ?
570- . port ( ) ;
571- let config = serde_json:: json!( {
572- "version" : "0.6.0-alpha" ,
573- "containerId" : "probe-pc-proxy" ,
574- "containment" : "processcontainer" ,
575- "process" : {
576- "commandLine" : "C:\\ Windows\\ System32\\ cmd.exe /c exit 0" ,
577- "cwd" : temp_path,
578- "timeout" : 30_000 ,
579- } ,
580- "filesystem" : {
581- "readwritePaths" : [ temp_path] ,
582- } ,
583- "processContainer" : {
584- "leastPrivilege" : false ,
585- } ,
586- "network" : {
587- "defaultPolicy" : "block" ,
588- "proxy" : { "localhost" : proxy_port } ,
589- } ,
590- } ) ;
591-
592- let json = serde_json:: to_string ( & config) . unwrap ( ) ;
593- let b64 = base64:: engine:: general_purpose:: STANDARD . encode ( json. as_bytes ( ) ) ;
594- let output = Command :: new ( wxc)
595- . arg ( "--config-base64" )
596- . arg ( & b64)
597- . output ( )
598- . map_err ( |error| format ! ( "wxc-exec proxy probe failed to spawn: {error}" ) ) ?;
599-
600- if output. status . success ( ) {
601- return Ok ( ( ) ) ;
602- }
603-
604- Err ( format ! (
605- "live network.proxy probe returned exit {}: stdout={} stderr={}" ,
606- output. status. code( ) . unwrap_or( -1 ) ,
607- String :: from_utf8_lossy( & output. stdout) ,
608- String :: from_utf8_lossy( & output. stderr) ,
609- ) )
610- }
611-
612560/// Probe the `isolation_session` backend.
613561///
614562/// Attempts a `provision` phase. Returns `Ok(sandbox_id)` when live, or
@@ -816,11 +764,6 @@ async fn pc_https_egress_reads_injected_ca_bundle() {
816764 eprintln ! ( "SKIP: processcontainer not live: {reason}" ) ;
817765 return ;
818766 }
819- if let Err ( reason) = probe_processcontainer_proxy ( & wxc) {
820- eprintln ! ( "SKIP: processcontainer network.proxy not live: {reason}" ) ;
821- return ;
822- }
823-
824767 let system_root = std:: env:: var ( "SYSTEMROOT" ) . expect ( "SYSTEMROOT must be set on Windows" ) ;
825768 let cmd = PathBuf :: from ( & system_root) . join ( "System32" ) . join ( "cmd.exe" ) ;
826769 let curl = PathBuf :: from ( system_root) . join ( "System32" ) . join ( "curl.exe" ) ;
@@ -832,10 +775,14 @@ async fn pc_https_egress_reads_injected_ca_bundle() {
832775 let output_dir = tempfile:: tempdir ( ) . expect ( "HTTPS output directory" ) ;
833776 let output_path = output_dir. path ( ) . join ( "example.html" ) ;
834777 let certificate_path = output_dir. path ( ) . join ( "peer-certificate.txt" ) ;
778+ let post_response_path = output_dir. path ( ) . join ( "post-response.json" ) ;
779+ let post_status_path = output_dir. path ( ) . join ( "post-status.txt" ) ;
835780 let diagnostic_path = output_dir. path ( ) . join ( "https-diagnostic.txt" ) ;
836781 let output_dir_string = output_dir. path ( ) . to_string_lossy ( ) . into_owned ( ) ;
837782 let output_path_string = output_path. to_string_lossy ( ) . into_owned ( ) ;
838783 let certificate_path_string = certificate_path. to_string_lossy ( ) . into_owned ( ) ;
784+ let post_response_path_string = post_response_path. to_string_lossy ( ) . into_owned ( ) ;
785+ let post_status_path_string = post_status_path. to_string_lossy ( ) . into_owned ( ) ;
839786 let diagnostic_path_string = diagnostic_path. to_string_lossy ( ) . into_owned ( ) ;
840787 let cmd_string = cmd. to_string_lossy ( ) . into_owned ( ) ;
841788 // Schannel's revocation lookup targets are intentionally outside this
@@ -849,8 +796,15 @@ async fn pc_https_egress_reads_injected_ca_bundle() {
849796 --cacert \" %CURL_CA_BUNDLE%\" \
850797 https://example.com/ --output \" {output_path_string}\" \
851798 --write-out \" %{{certs}}\" 1>\" {certificate_path_string}\" \
799+ 2>>\" {diagnostic_path_string}\" && \
800+ \" {}\" --silent --show-error --ssl-no-revoke \
801+ --cacert \" %CURL_CA_BUNDLE%\" --request POST \
802+ --header \" Content-Type: application/json\" --data \" {{}}\" \
803+ https://example.com/ --output \" {post_response_path_string}\" \
804+ --write-out \" %{{http_code}}\" 1>\" {post_status_path_string}\" \
852805 2>>\" {diagnostic_path_string}\" ",
853- curl. display( )
806+ curl. display( ) ,
807+ curl. display( ) ,
854808 ) ;
855809 let command = vec ! [
856810 cmd_string. clone( ) ,
@@ -962,6 +916,19 @@ async fn pc_https_egress_reads_injected_ca_bundle() {
962916 peer_certificate. contains( "OpenShell Sandbox CA" ) ,
963917 "HTTPS response must use a certificate issued by the host proxy CA"
964918 ) ;
919+ let post_status = std:: fs:: read_to_string ( post_status_path) . expect ( "POST status output" ) ;
920+ assert_eq ! (
921+ post_status. trim( ) ,
922+ "403" ,
923+ "read-only policy must deny HTTPS POST"
924+ ) ;
925+ let post_response =
926+ std:: fs:: read_to_string ( post_response_path) . expect ( "POST denial response body" ) ;
927+ assert ! (
928+ post_response. contains( "policy_denied" )
929+ || post_response. contains( "no matching L7 allow rule" ) ,
930+ "POST denial must come from the OpenShell L7 policy: {post_response}"
931+ ) ;
965932}
966933
967934/// Write to a path OUTSIDE the granted dir; assert exit non-zero and file absent.
0 commit comments