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
use std::path::PathBuf;
use clap::{Parser, ValueEnum};
#[derive(Parser)]
pub struct DetectorArgs {
/// Detector TOML directory
#[arg(short, long, default_value = "detectors")]
pub detectors: PathBuf,
#[arg(skip)]
pub(crate) detectors_cli_explicit: bool,
/// Filter detectors by substring match (case-insensitive) against id,
/// name, service, and keywords (e.g. `keyhog detectors --search aws`).
///
/// The short `--help` line is intentionally count-free; the long `--help`
/// (rendered via [`crate::args::command`]) injects the live embedded
/// detector count so the cited corpus size can never drift from the
/// detectors actually compiled into this binary.
#[arg(short, long)]
pub search: Option<String>,
/// Print the matching-policy summary (regexes, keywords, companions,
/// verification presence) instead of the grouped service summary. Pairs
/// naturally with `--search`. Use `--format json` for the redaction-safe
/// declared schema, including verification structure and test coverage.
#[arg(short, long, default_value_t = false)]
pub verbose: bool,
/// Audit detectors against the quality gate (`keyhog_core::validate_detector`).
/// Prints every issue grouped by detector and exits non-zero (3) if any
/// `Error`-severity issue was found. Warnings are reported but do not
/// fail the run. Pairs with `--detectors <DIR>` for CI gating.
#[arg(long, conflicts_with = "fix")]
pub audit: bool,
/// Apply safe automated fixes to the detector TOMLs in `--detectors`.
/// Currently rewrites single-brace template references (`{name}`) to
/// the double-brace form (`{{name}}`) within `[detector.verify*]`
/// blocks: the one fix the interpolator's contract makes safe to
/// perform mechanically. Other validator findings are left alone
/// (they need human judgement). Use `--dry-run` to preview rewrites
/// without touching the filesystem.
#[arg(long, conflicts_with = "audit")]
pub fix: bool,
/// Show the rewrites `--fix` *would* make without writing them. No-op
/// unless `--fix` is also set.
#[arg(long, requires = "fix")]
pub dry_run: bool,
/// Print the generated mechanism manifest: which recovery mechanisms each
/// detector actually declares.
///
/// KeyHog advertises regex matching, structural validation, entropy
/// scoring, BPE token efficiency, decode recovery, companion
/// confirmation, live verification, and detector-owned suppression, but
/// nothing in the product will tell you which of those a given detector
/// uses. This does, and it derives every answer from the loaded corpus:
/// each mechanism is a predicate over detector TOML fields and the field
/// that made it active is reported as its evidence, so there is no
/// per-detector table in Rust to drift.
///
/// A mechanism KeyHog cannot express yet is reported as unavailable with
/// the reason rather than omitted, because a missing row cannot be told
/// apart from "no detector uses this".
///
/// Pairs with `--search` to scope the manifest, and with `--format json`
/// for the machine-readable document. Does not scan.
#[arg(long, conflicts_with_all = ["audit", "fix", "verbose"])]
pub mechanisms: bool,
/// Output format for the detector listing. `text` (default) is the grouped,
/// human-readable summary; `json` emits the structured detector array. This
/// is the canonical flag, it matches `scan --format` so the
/// two surfaces share one convention (CLI-01). Only `text`/`json` apply to a
/// detector listing, so the format set is intentionally narrower than
/// `scan`'s. Mutually exclusive with `--audit` / `--fix` (they emit their own
/// structured formats).
#[arg(long, value_enum, conflicts_with_all = ["audit", "fix"])]
pub format: Option<DetectorFormat>,
}
/// Output formats valid for the `detectors` listing. Deliberately a narrow
/// pair (not the full [`super::OutputFormat`]): a detector listing has exactly
/// one structured form (JSON) and one human form (text); SARIF/JUnit/CSV/HTML
/// are findings-report shapes with no meaning here, so offering them would be
/// an incoherent surface. Shares the `--format` flag *name* with `scan` for
/// convention parity (CLI-01) without sharing the irrelevant variants.
#[derive(Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum DetectorFormat {
Text,
Json,
}