@@ -211,6 +211,20 @@ pub fn parse_helper_line(raw: &str) -> Result<HelperEvent> { |
| 211 | 211 | return Ok(HelperEvent::Info(message.to_string())); |
| 212 | 212 | } |
| 213 | 213 | |
| 214 | + // Some helper builds emit plain-text diagnostics instead of PAM_* protocol |
| 215 | + // lines. Classify known auth failures so callers can present proper retry UX |
| 216 | + // without treating successful paths as generic errors. |
| 217 | + let lower = line.to_ascii_lowercase(); |
| 218 | + if lower.contains("pam_authenticate failed") |
| 219 | + || lower.contains("authentication failure") |
| 220 | + || lower.contains("no session for cookie") |
| 221 | + { |
| 222 | + return Ok(HelperEvent::Failure); |
| 223 | + } |
| 224 | + if line.starts_with("polkit-agent-helper-1:") { |
| 225 | + return Ok(HelperEvent::Info(line.to_string())); |
| 226 | + } |
| 227 | + |
| 214 | 228 | anyhow::bail!("unsupported helper protocol line: {}", line); |
| 215 | 229 | } |
| 216 | 230 | |
@@ -310,6 +324,30 @@ mod tests { |
| 310 | 324 | assert!(err.to_string().contains("unsupported helper protocol line")); |
| 311 | 325 | } |
| 312 | 326 | |
| 327 | + #[test] |
| 328 | + fn parse_helper_line_maps_plaintext_failure_diagnostics() { |
| 329 | + assert_eq!( |
| 330 | + parse_helper_line( |
| 331 | + "polkit-agent-helper-1: pam_authenticate failed: Authentication failure" |
| 332 | + ) |
| 333 | + .expect("maps failure"), |
| 334 | + HelperEvent::Failure |
| 335 | + ); |
| 336 | + assert_eq!( |
| 337 | + parse_helper_line("polkit-agent-helper-1: error response to PolicyKit daemon: GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: No session for cookie") |
| 338 | + .expect("maps cookie failure"), |
| 339 | + HelperEvent::Failure |
| 340 | + ); |
| 341 | + } |
| 342 | + |
| 343 | + #[test] |
| 344 | + fn parse_helper_line_maps_plaintext_info() { |
| 345 | + assert_eq!( |
| 346 | + parse_helper_line("polkit-agent-helper-1: informational message").expect("maps info"), |
| 347 | + HelperEvent::Info("polkit-agent-helper-1: informational message".to_string()) |
| 348 | + ); |
| 349 | + } |
| 350 | + |
| 313 | 351 | #[test] |
| 314 | 352 | fn helper_client_drives_prompt_round_trip() { |
| 315 | 353 | let socket_path = temp_socket_path(); |