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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
[]
= "forbidden-strings"
= "0.2.0"
= ["command-line-utilities", "development-tools"]
= "2024"
= "https://github.com/Aquaticat/Monochromatic/tree/main/package/cli/forbidden-strings"
= [
"src/**/*.rs",
# The embedded baseline: lib.rs include_str!s it at compile time, so the
# published crate cannot build without it.
"data/builtin-rules.txt",
# The ported baseline: build.rs compiles it into a serialized RegexSet embedded
# via include_bytes!, so the published crate cannot build without it either.
"data/builtin-rules.ported.txt",
# The build script precompiles the ported baseline at build time.
"build.rs",
"Cargo.toml",
"Cargo.lock",
"README.md",
"LICENSES/*.txt",
]
= ["security", "secrets", "scanner", "deny-list", "ci"]
= "LGPL-3.0-or-later"
= "README.md"
= "https://github.com/Aquaticat/Monochromatic.git"
= "Out-of-band scanner for forbidden literal strings and regex patterns. Gitignore-aware, fast, dependency-light: built for CI deny-listing of leaked credentials and banned tokens."
[]
= "deny"
= "deny"
= "allow"
[]
= "forbidden_strings"
= "src/lib.rs"
[[]]
= "forbidden-strings"
= "src/main.rs"
[]
# What: `fuzzing` Cargo feature. When enabled (`cargo build --features fuzzing`),
# the crate exposes `mod fuzz_api`, a curated re-export bundle of
# internal compile/extract/walker helpers used by the fuzz targets in
# `package/fuzz/forbidden-strings/fuzz_targets/*.rs`.
# Why: Production consumers (the bin target, integration tests) build
# with this feature off, so they see the same public surface as
# before. Fuzz targets opt in by depending on
# `forbidden-strings = { path = "../../cli/forbidden-strings", features = ["fuzzing"] }`,
# gaining access to the internal compile pipeline without
# widening the production public API.
= []
[]
# `anyhow` carries application-level errors while preserving their display text for
# CLI stderr output and tests.
= "1"
# `clap` owns argv parsing, generated help/version output, and validation for the
# `forbidden-strings` binary. The derive feature lets `src/cli.rs` declare the
# command shape as a typed struct instead of maintaining a handwritten argv loop.
= { = "4", = ["derive"] }
# The in-house engine the scanner runs on. It owns the restricted dialect, the
# `RegexSet` compile/serialize/reload paths, and the buffer-batch `line_matches`
# API the scan path calls; its own `Cargo.toml` documents that it expects the
# caller (this crate) to provide the `catch_unwind` fail-closed boundary. Its
# internal prefilters pull in aho-corasick, memchr, and regex-automata, so the
# literal-gating machinery this crate once owned directly stays present as a
# transitive dependency. Depended on by path (the same crate the bench sidecar
# drives) plus the published version so `cargo publish` resolves it from
# crates.io; the path wins for local builds.
= { = "../../rust-module/forbidden-regex", = "0.1.0" }
= { = "0.25", = false, = ["sha1", "sha256"] }
= { = "0.51", = false, = ["sha1"] }
= "0.4"
= "2"
= "1"
# The logging facade and its subscriber. tracing routes the compiler's rule-rejection
# warnings and the CLI's top-level errors as structured events to stderr via
# tracing-subscriber (RUST_LOG, default info); the scan findings stay on stdout, and the
# env-gated FORBIDDEN_STRINGS_DEBUG_* developer report dumps stay as direct stderr output.
= "0.1"
= { = "0.3", = ["env-filter"] }
# The build script (`build.rs`) precompiles the ported builtin baseline into a
# serialized `RegexSet` (`to_bytes`) at build time, embedded via `include_bytes!`
# and reloaded at runtime through the validating `from_bytes` path. Compiling the
# baseline at each startup is not viable (the migration measured tens of seconds),
# so the cost is paid once here. Path plus published version, same as the runtime
# dependency: the path wins for local builds, the version lets `cargo publish`
# resolve it from crates.io.
[]
= { = "../../rust-module/forbidden-regex", = "0.1.0" }
# Why `panic = "unwind"` and `overflow-checks = true` instead of the smaller
# "abort" plus default-off overflow checks:
#
# `src/frx_scan.rs` (`scan_one_set`) wraps every `RegexSet::line_matches` call in
# `std::panic::catch_unwind`. The forbidden-regex engine's own `Cargo.toml`
# documents that it deliberately does not install an internal panic guard and
# expects the caller to provide this `catch_unwind` boundary; this crate is that
# caller. On a caught panic the scanner emits a redacted `PATH: engine error`
# synthetic finding, so a matcher fault reports the file and exits non-zero
# instead of aborting or exiting clean.
#
# The combo is defense-in-depth against UNKNOWN engine faults: the dialect is
# restricted and every rule is validated at compile time, but a future matcher
# bug should fail closed, not corrupt CI.
#
# 1. `panic = "unwind"`: `catch_unwind` only intercepts when the process
# unwinds. Under `panic = "abort"` the process dies before the unwind
# barrier runs, and the scanner (a CI gate) aborts instead of surfacing the
# bad file. (A stack-overflow SIGABRT is not caught by either setting; the
# engine caps recursion internally at compile time instead.)
#
# 2. `overflow-checks = true`: an arithmetic overflow is Rust's standard
# checked-arithmetic panic from a `+`. Cargo's default release profile
# disables overflow checks for speed; without this setting an unknown
# overflowing add inside the matcher would silently wrap, the engine would
# resolve the wrong verdict, and the rule would fail open (zero hits on
# content that should match). That is the worst case for a secret scanner: a
# corrupt rule silently passes CI. With this setting the wrap becomes a real
# panic that `catch_unwind` converts to the `PATH: engine error` synthetic
# finding.
#
# Note about `debug-assertions`: deliberately left at the release default of
# OFF. With debug-assertions OFF a matcher postcondition guarded by
# `debug_assert!` would return a wrong verdict rather than panicking, and
# `catch_unwind` cannot help there; the engine's own fuzz suite (run with
# debug-assertions ON) is the durable cover for that class. We do not turn
# debug-assertions on in release because the `forbidden-regex`, `ignore`, and
# `rayon` deps have hot-path debug_asserts whose cost was not measured to be
# acceptable on the CI gate.
[]
= true
= 1
= 3
= "unwind"
= true
= true
# Standalone crate: its own workspace root, so no ancestor Cargo.toml can absorb it.
# Enforced by file-enforcer (doc/planning/cargo-toml-file-enforcer.md).
[]