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
use std::path::PathBuf;
/// Resolve the MatcherArtifact cache directory from explicit CLI/TOML config.
///
/// Resolution order:
/// 1. explicit `--matcher-cache <DIR|off>` / `[system].matcher_cache`
/// 2. `dirs::cache_dir()/keyhog-matcher-artifacts`
///
/// `off` / `0` / empty disables persistence. `--lockdown` also disables the
/// cache at the orchestrator layer (unsigned local detector/matcher graphs are
/// incompatible with lockdown's past-findings audit).
///
/// Default-on mirrors Hyperscan's persistent shard cache, which likewise
/// resolves under `dirs::cache_dir()/keyhog` when `--cache-dir` is unset
/// (`simd::backend::resolve_cache_dir`). An explicit path that fails validation
/// is a hard error. The automatic default soft-fails to `None` (cache disabled)
/// when the platform cache root is missing or outside the allowlist.
pub(crate) fn resolve_matcher_cache_path(raw: Option<&str>) -> Result<Option<PathBuf>, String> {
resolve_matcher_cache_path_with_default(raw, dirs::cache_dir())
}
pub(crate) fn resolve_matcher_cache_path_with_default(
raw: Option<&str>,
default_cache_dir: Option<PathBuf>,
) -> Result<Option<PathBuf>, String> {
if let Some(raw) = raw {
let trimmed = raw.trim();
if trimmed.is_empty() || trimmed.eq_ignore_ascii_case("off") || trimmed == "0" {
return Ok(None);
}
let path = PathBuf::from(trimmed);
if !path.is_absolute() {
return Err(format!(
"matcher-artifact cache path must be an absolute directory, got `{trimmed}`. \
Configure with --matcher-cache <DIR|off> or [system].matcher_cache"
));
}
keyhog_scanner::validate_matcher_artifact_cache_dir(&path)?;
return Ok(Some(path));
}
match keyhog_scanner::default_matcher_artifact_cache_dir_from_base(default_cache_dir) {
Ok(path) => match keyhog_scanner::validate_matcher_artifact_cache_dir(&path) {
Ok(()) => Ok(Some(path)),
Err(error) => {
// Default-on soft-fail must not spam ordinary/CI stderr when
// XDG_CACHE_HOME sits outside $HOME. Explicit --matcher-cache
// paths still hard-error above.
tracing::debug!(
error = %error,
path = %path.display(),
"matcher-artifact cache disabled: default cache location is unusable"
);
Ok(None)
}
},
Err(error) => {
tracing::debug!(
error = %error,
"matcher-artifact cache disabled: no default cache location"
);
Ok(None)
}
}
}