@@ -94,6 +94,7 @@ pub fn redact_snapshot(value: &impl Serialize, workspace_root: &str) -> serde_js
9494 } ) ;
9595
9696 // Normalize Windows program names and paths by stripping common extensions for cross-platform consistency
97+ // This must happen BEFORE shell redaction so that "cmd.exe" becomes "cmd" before comparison
9798 visit_json ( & mut json_value, & mut |v| {
9899 let serde_json:: Value :: Object ( map) = v else {
99100 return ;
@@ -108,6 +109,37 @@ pub fn redact_snapshot(value: &impl Serialize, workspace_root: &str) -> serde_js
108109 }
109110 } ) ;
110111
112+ // Redact shell program and arguments for cross-platform consistency
113+ // Note: os_shell_path still includes .exe because we compare against program_path before extension stripping
114+ let os_shell_path = if cfg ! ( windows) { "C:\\ Windows\\ System32\\ cmd" } else { "/bin/sh" } ;
115+ let os_shell_name = if cfg ! ( windows) { "cmd" } else { "sh" } ;
116+ let os_shell_args: & [ & str ] = if cfg ! ( windows) { & [ "/d" , "/s" , "/c" ] } else { & [ "-c" ] } ;
117+ visit_json ( & mut json_value, & mut |v| {
118+ if let serde_json:: Value :: String ( s) = v {
119+ // Use case-insensitive comparison on Windows since path casing can vary
120+ let matches_shell_path = if cfg ! ( windows) {
121+ s. eq_ignore_ascii_case ( os_shell_path)
122+ } else {
123+ s == os_shell_path
124+ } ;
125+ if matches_shell_path {
126+ * s = "<os_shell_path>" . to_string ( ) ;
127+ } else if s == os_shell_name {
128+ * s = "<os_shell_name>" . to_string ( ) ;
129+ }
130+ } else if let serde_json:: Value :: Array ( array) = v {
131+ // Check if the beginning of the array matches the shell args
132+ for ( n, arg) in os_shell_args. iter ( ) . enumerate ( ) {
133+ if !matches ! ( array. get( n) , Some ( serde_json:: Value :: String ( s) ) if s == * arg) {
134+ return ;
135+ }
136+ }
137+ // Redact the shell args
138+ array. drain ( 0 ..os_shell_args. len ( ) ) ;
139+ array. insert ( 0 , serde_json:: Value :: String ( "<os_shell_args>" . to_string ( ) ) ) ;
140+ }
141+ } ) ;
142+
111143 visit_json ( & mut json_value, & mut |v| {
112144 let serde_json:: Value :: Array ( array) = v else {
113145 return ;
0 commit comments