1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! Generic external-tool detection — `<tool> --version` and
//! `<tool> <args>` probes used by the CLI's `healthcheck` command *and*
//! capability probes elsewhere in core (e.g.
//! `signing::gpg_supports_faked_system_time`, which delegates to
//! [`tool_runs_with_args`]).
//!
//! Centralised here so the `Command::new(<tool>)` probe shell-outs live
//! inside the module-boundaries allow-list. The CLI used to do these
//! probes inline; that put `Command::new` outside the allow-list and
//! counted as a boundary violation. Capability probes in other core
//! modules (signing, etc.) delegate here for the same reason.
use io;
use Command;
/// Probe `<name> --version` and report whether the tool ran successfully.
///
/// `Ok(true)` — `<name> --version` ran and exited zero (tool available).
/// `Ok(false)` — `<name>` ran but exited non-zero (installed but failing
/// `--version`; rare, but possible for stub binaries or version-flag
/// mismatches).
/// `Err(_)` — `<name>` could not be spawned (typically `NotFound` —
/// the binary is not on `PATH`). Distinct from `Ok(false)` so callers
/// can log the underlying `io::Error` at trace level. stdout/stderr
/// are silenced so a missing tool doesn't pollute the log.
/// Run `<name> --version` and return the first stdout line trimmed.
///
/// `Ok(Some(line))` — tool ran, exited zero, returns the first stdout
/// line trimmed.
/// `Ok(None)` — tool ran but exited non-zero; no version string to
/// report.
/// `Err(_)` — tool could not be spawned. Distinct from `Ok(None)` so
/// callers can log why the probe itself failed at trace level rather
/// than collapsing every failure to "tool missing".
/// Probe whether `<name> <args...>` runs and exits zero.
///
/// Used by capability probes that pass extra flags beyond bare
/// `--version` (e.g. `gpg --faked-system-time 0! --version` to check
/// whether the local gpg supports deterministic-timestamp signing).
/// stdout/stderr are silenced; `false` covers both "binary missing"
/// and "exited non-zero" — callers that need to distinguish those two
/// cases should use [`tool_available`] / [`tool_version`] instead.