Commit 2e446e7
feat: Stringy v1.0 -- pipeline architecture, CLI hardening, and comprehensive testing (#141)
## Summary
This PR delivers the complete v1.0 implementation of Stringy,
transforming it from a prototype into a production-ready binary string
extraction tool. The work spans 56 commits across 132 files (+7,963 /
-6,477 lines), organized into five major workstreams.
**610 tests pass** (23 platform-skipped), **zero clippy warnings**, all
pre-commit hooks green.
## What Changed
### 1. Pipeline Architecture (New)
Introduced a modular pipeline orchestrator that replaces ad-hoc
extraction logic:
- `Pipeline::new(config).run(&path)` -- single entry point for all
analysis
- `PipelineConfig` with builder pattern for extraction, filtering,
output, and debug options
- `FilterEngine` for tag inclusion/exclusion, encoding, min-length, and
top-N filtering
- Score normalizer with 0-100 display scores and section weight /
semantic boost / noise penalty breakdown
- `mmap-guard` integration for safe memory-mapped file I/O (replaces raw
`memmap2`)
- Graceful fallback for unknown formats (raw byte scanning with Info
diagnostic)
- Processing warnings via env-var injection for testable error paths
**Key files:** `src/pipeline/mod.rs`, `src/pipeline/config.rs`,
`src/pipeline/filter.rs`, `src/pipeline/normalizer.rs`
### 2. CLI Hardening
Complete rewrite of the CLI layer with production-quality UX:
- **Typed exit codes**: 0=success, 2=config/validation, 3=not-found,
4=permission-denied, 1=other
- **Short flags**: `-j` (json), `-m` (min-len), `-t` (top), `-e` (enc)
- **Actionable error messages** with fix suggestions
- **NO_COLOR** env var support (no-color.org spec)
- **Graceful spinner** fallback (no `.expect()`, hidden when non-TTY or
NO_COLOR)
- **stdin support** via `patharg::InputArg` with progress feedback
- `--notags` renamed to `--no-tags` (kebab-case consistency)
- `--summary`, `--debug`, `--raw` modes with proper conflict
declarations
- Help text with EXAMPLES section and all 21 tag names listed
**Key files:** `src/main.rs`, `src/types/error.rs`
### 3. Core Data Model Improvements
- `FoundString::new()` + builder methods replace struct literals
(forward-compatible)
- `StringContext` constructors for cleaner extraction code
- `SectionInfo` made `#[non_exhaustive]` with `with_*` builders
- `OutputMetadata` with analysis duration, top tag distribution, builder
pattern
- `FilterContext` with builder methods for test ergonomics
- `ExtractionConfig::with_min_length()` builder
- Container parsers split into module directories (elf/, pe/, macho/)
with separate test files
**Key files:** `src/types/constructors.rs`, `src/types/found_string.rs`,
`src/types/mod.rs`
### 4. Output Enhancements
- **Plain text**: Full C0 control character sanitization (not just
newlines)
- **TTY table**: Analysis duration with minute-level formatting, summary
banner
- **JSON**: Debug-only fields (`section_weight`, `semantic_boost`,
`noise_penalty`) via `skip_serializing_if`
- **YARA**: Long string skip behavior with deterministic comments
- `display_score` always present in non-raw mode; forced to 0 in raw
mode
**Key files:** `src/output/table/plain.rs`, `src/output/table/tty.rs`,
`src/output/json.rs`
### 5. Build & Infrastructure
- **Zig cross-compilation** replaces Docker for test fixtures (ELF, PE,
Mach-O)
- **Release profile** optimization: `strip = true`, `codegen-units = 1`,
`lto = "thin"` (release) / `"fat"` (dist)
- **mmap-guard** dependency for safe memory-mapped I/O
- **cargo-dist** version bump to 0.31.0
- **GOTCHAS.md** added as living documentation for edge cases
- CI workflow updates (action versions, scorecard)
## Test Plan
- [x] 610 tests pass across 25 test files (597 previously + 13 new
short-flag tests)
- [x] `cargo clippy --all-targets -- -D warnings` clean
- [x] `cargo fmt --check` clean
- [x] All pre-commit hooks pass (fmt, clippy, cargo-check, mdformat,
cargo-audit)
- [x] Integration test coverage for all CLI flags, exit codes, and
conflict combinations
- [x] Score determinism verified across consecutive runs
- [x] Warning emission tested via debug-build env var injection
- [x] Unknown/empty binary fallback paths tested
- [x] Short flag equivalence verified (-j = --json, -m = --min-len,
etc.)
- [x] NO_COLOR env var tested
- [x] stdin pipe tested with ELF binary and empty input
- [x] Permission denied exit code 4 tested (Unix)
### New Test Files in This PR
| File | Tests | Coverage Area |
|------|-------|--------------|
| `integration_flows_1_5.rs` | 16 | Quick analysis, filtering, top-N,
JSON, YARA |
| `integration_flows_6_7.rs` | 11 | Plain text output, summary mode |
| `integration_flow8_errors.rs` | 11 | Argument conflicts, validation
failures |
| `integration_flow8_diagnostics.rs` | 13 | Warnings, fallback, score
determinism, debug |
| `integration_cli_errors.rs` | 10 | Exit codes, error messages |
| `integration_cli_coverage.rs` | 18 | Encoding, stdin, combined
filters, permissions |
| `integration_cli_short_flags.rs` | 13 | Short flags, NO_COLOR, OR
logic, edge cases |
| `integration_flow1_minlen.rs` | 2 | Min-length default and explicit
filter |
| `integration_flows_5_yara.rs` | 1 | YARA long string deterministic
skip |
## Breaking Changes
- `--notags` renamed to `--no-tags` (CLI flag)
- `FoundString` struct fields are no longer public for direct
construction (use `FoundString::new()` + builders)
- `SectionInfo` is `#[non_exhaustive]` (external crate consumers must
use constructors)
- Exit codes changed: file-not-found is now 3 (was 1), permission-denied
is now 4 (was 1)
## Risk Assessment
**Risk Level: Medium**
| Factor | Assessment |
|--------|-----------|
| Size | Large (132 files), but most changes are additive |
| Breaking changes | CLI flag rename + exit code changes -- documented
above |
| Test coverage | Strong -- 610 tests covering all new paths |
| Dependencies | +mmap-guard (thin wrapper), +patharg (stdin handling) |
| Security | `#![forbid(unsafe_code)]` maintained, no new unsafe |
## Reviewer Notes
- The pipeline module (`src/pipeline/`) is entirely new -- start review
there
- Container parser splits (elf.rs -> elf/mod.rs + elf/tests.rs) are
mechanical moves with no logic changes
- Documentation changes are extensive but mostly rewrites for accuracy
- GOTCHAS.md is a new file worth reading for context on edge cases
---
Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>1 parent 99dc2e4 commit 2e446e7
File tree
129 files changed
+8251
-6488
lines changed- .github
- workflows
- docs
- plans
- src
- project_plan
- specs
- tickets
- src
- classification
- patterns
- container
- elf
- macho
- pe
- extraction
- ascii
- dedup
- tests
- filters
- pe_resources
- utf16
- output
- table
- pipeline
- types
- tests
- fixtures
- snapshots
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
129 files changed
+8251
-6488
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
81 | 85 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| 70 | + | |
70 | 71 | | |
| 72 | + | |
71 | 73 | | |
| 74 | + | |
72 | 75 | | |
73 | 76 | | |
74 | 77 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
26 | | - | |
| 25 | + | |
| 26 | + | |
27 | 27 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | | - | |
| 32 | + | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
38 | 44 | | |
39 | 45 | | |
40 | 46 | | |
| |||
52 | 58 | | |
53 | 59 | | |
54 | 60 | | |
55 | | - | |
| 61 | + | |
56 | 62 | | |
57 | 63 | | |
58 | 64 | | |
59 | 65 | | |
60 | 66 | | |
61 | 67 | | |
62 | | - | |
| 68 | + | |
63 | 69 | | |
64 | 70 | | |
65 | 71 | | |
66 | 72 | | |
67 | 73 | | |
68 | 74 | | |
69 | 75 | | |
70 | | - | |
71 | | - | |
| 76 | + | |
| 77 | + | |
72 | 78 | | |
73 | 79 | | |
74 | 80 | | |
75 | 81 | | |
76 | 82 | | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
77 | 86 | | |
78 | 87 | | |
79 | 88 | | |
| |||
93 | 102 | | |
94 | 103 | | |
95 | 104 | | |
96 | | - | |
97 | | - | |
| 105 | + | |
| 106 | + | |
98 | 107 | | |
99 | 108 | | |
100 | 109 | | |
101 | 110 | | |
102 | 111 | | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
103 | 115 | | |
104 | 116 | | |
105 | 117 | | |
| |||
109 | 121 | | |
110 | 122 | | |
111 | 123 | | |
112 | | - | |
113 | | - | |
| 124 | + | |
| 125 | + | |
114 | 126 | | |
115 | 127 | | |
116 | 128 | | |
117 | 129 | | |
118 | 130 | | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
119 | 134 | | |
120 | 135 | | |
121 | 136 | | |
122 | 137 | | |
123 | | - | |
| 138 | + | |
124 | 139 | | |
125 | 140 | | |
126 | 141 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
| 25 | + | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | | - | |
| 30 | + | |
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| |||
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | | - | |
| 62 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
67 | | - | |
| 67 | + | |
68 | 68 | | |
69 | | - | |
| 69 | + | |
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | | - | |
| 85 | + | |
86 | 86 | | |
87 | 87 | | |
88 | 88 | | |
| |||
135 | 135 | | |
136 | 136 | | |
137 | 137 | | |
138 | | - | |
| 138 | + | |
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
| |||
151 | 151 | | |
152 | 152 | | |
153 | 153 | | |
154 | | - | |
| 154 | + | |
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
| |||
168 | 168 | | |
169 | 169 | | |
170 | 170 | | |
171 | | - | |
| 171 | + | |
172 | 172 | | |
173 | 173 | | |
174 | 174 | | |
| |||
190 | 190 | | |
191 | 191 | | |
192 | 192 | | |
193 | | - | |
| 193 | + | |
194 | 194 | | |
195 | 195 | | |
196 | 196 | | |
| |||
202 | 202 | | |
203 | 203 | | |
204 | 204 | | |
205 | | - | |
| 205 | + | |
206 | 206 | | |
207 | 207 | | |
208 | 208 | | |
| |||
233 | 233 | | |
234 | 234 | | |
235 | 235 | | |
236 | | - | |
| 236 | + | |
237 | 237 | | |
238 | 238 | | |
239 | 239 | | |
| |||
259 | 259 | | |
260 | 260 | | |
261 | 261 | | |
262 | | - | |
| 262 | + | |
263 | 263 | | |
264 | 264 | | |
265 | 265 | | |
266 | 266 | | |
267 | 267 | | |
268 | 268 | | |
269 | | - | |
| 269 | + | |
270 | 270 | | |
271 | 271 | | |
272 | 272 | | |
| |||
279 | 279 | | |
280 | 280 | | |
281 | 281 | | |
282 | | - | |
| 282 | + | |
283 | 283 | | |
284 | 284 | | |
285 | 285 | | |
286 | 286 | | |
287 | 287 | | |
288 | 288 | | |
289 | | - | |
| 289 | + | |
290 | 290 | | |
291 | 291 | | |
292 | 292 | | |
| |||
326 | 326 | | |
327 | 327 | | |
328 | 328 | | |
329 | | - | |
| 329 | + | |
330 | 330 | | |
331 | 331 | | |
332 | 332 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
41 | | - | |
| 41 | + | |
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| |||
0 commit comments