Skip to content

test: centralize scrubber fixtures + add regression meta-test - #2

Merged
David Mireles (louzt) merged 2 commits into
mainfrom
fix/test-fixture-hygiene
Jul 28, 2026
Merged

David Mireles (louzt) merged 2 commits into
mainfrom
fix/test-fixture-hygiene

Conversation

@louzt

@louzt louzt commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Consolidates 6 fake-key/fake-PII placeholder strings into a single src/test_fixtures.rs module so the scrubber test suite has one source of truth. Also adds a regression meta-test that catches future fixture/regex drift.

Closes the smell that triggered KeyScout issue #1 (false-positive security alert on the inline Anthropic placeholder).

What changed

  • New src/test_fixtures.rs: public module with 6 FAKE_* constants + module doc explaining why each is obviously not a real secret
  • Modified src/lib.rs: declares #[doc(hidden)] pub mod test_fixtures; + refactors scrubber_patterns_match_realistic_secrets to use the constants
  • Modified src/pipeline/scrubber.rs: refactors 7 redacts_* unit tests to import fixtures
  • Modified tests/pipeline_e2e.rs: refactors pipeline_with_secrets_redacts_and_records_stats to use fixtures
  • New tests/scrubber_fixtures_meta.rs: 2 meta-tests verifying every fixture is recognized by the scrubber's regex patterns and survives redaction

Why this resolves issue #1

The original KeyScout flag pointed at src/pipeline/scrubber.rs:104. That string (sk-ant-api03-abcdefghijklmnopqrstuvwxyz0123456789ABCD) is a constructed test fixture, not a real Anthropic key — real keys have ~93 random base62 chars after the prefix, never contiguous alphabet.

The actual quality issue the report caught was that the same fixture shape was duplicated across 3 files. Consolidating to one source reduces future false-positive hits from upstream scanners that pattern-match on the prefix shape.

Test results

63 tests pass, 0 fail
- 44 unit tests in src/lib.rs
- 4 unit tests in src/main.rs
- 9 CLI e2e tests
- 4 pipeline e2e tests
- 2 NEW meta-tests in tests/scrubber_fixtures_meta.rs

cargo fmt --check: clean
cargo clippy --all-targets -- -D warnings: clean

Scope boundary

This PR does NOT:

  • ❌ Touch the scrubber's regex patterns
  • ❌ Change the public API
  • ❌ Force-push or rewrite history
  • ❌ Add new SecretKind variants

This PR does:

  • ✅ Consolidate fixtures (test-only change)
  • ✅ Add regression meta-test
  • ✅ Update CHANGELOG + bump version 0.6.1 → 0.6.2 (in commit 7a45dca)

Post-merge plan (separate ops, gated)

  1. cargo yank --version 0.6.1 (hide v0.6.1 from new cargo add searches)
  2. cargo publish for v0.6.2
  3. git tag v0.6.2 + push tag
  4. Comment + close issue Security: Exposed API Key Detected (anthropic) #1 with link to this PR

loust davidmirelesll@outlook.com

Summary by CodeRabbit

  • What’s New

    • Released version 0.6.2.
    • Added safeguards to verify that configured secret patterns continue detecting supported sensitive-data formats.
  • Bug Fixes

    • Yanked version 0.6.1 after a false-positive security alert caused by non-real test credentials.
  • Notes

    • No changes to scrubber behavior or the public API.

Consolidates 6 fake-key/fake-PII placeholder strings into a single
`src/test_fixtures.rs` module so the scrubber test suite has one
source of truth. Previously the same literals lived in 3 files
(`src/lib.rs`, `src/pipeline/scrubber.rs`, `tests/pipeline_e2e.rs`),
which is what triggered KeyScout issue #1 on the Anthropic placeholder.

Strings are obviously not real secrets (Amazon publishes
AKIAIOSFODNN7EXAMPLE as their documented 'fake' key; the rest are
alphabet+digits patterns). See `src/test_fixtures.rs` module doc
for full rationale and scanner caveats.

Also adds `tests/scrubber_fixtures_meta.rs` with two meta-tests:
  - every_fixture_is_redacted_by_the_scrubber: catches future
    fixtures added without a matching regex in with_safe_defaults
  - fixture_strings_match_their_declared_regex_pattern: catches
    fixture/regex drift (e.g., tightened regex no longer matching
    the declared literal)

All 63 tests pass. No public API changes.
See CHANGELOG.md for full notes. Yanks v0.6.1 post-publish via
`cargo yank --version 0.6.1` (see MANIFEST-2026-07-28).
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The release updates the crate to 0.6.2, centralizes non-secret scrubber fixtures, migrates existing tests to use them, and adds meta-tests verifying every fixture is redacted and matches its configured regex.

Changes

Scrubber fixture maintenance

Layer / File(s) Summary
Shared fixture contract
src/test_fixtures.rs, src/lib.rs
Adds documented fake secret constants and exposes them through a doc-hidden test module.
Existing test migration
src/lib.rs, src/pipeline/scrubber.rs, tests/pipeline_e2e.rs
Replaces hardcoded scrubber test values with shared fixtures in unit and end-to-end tests.
Fixture regression coverage and release metadata
tests/scrubber_fixtures_meta.rs, Cargo.toml, CHANGELOG.md
Adds redaction and regex consistency tests, and records the 0.6.2 release details.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main test-focused changes: centralizing scrubber fixtures and adding regression meta-tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/test-fixture-hygiene

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@louzt
David Mireles (louzt) merged commit 104fd5d into main Jul 28, 2026
2 of 3 checks passed
@louzt
David Mireles (louzt) deleted the fix/test-fixture-hygiene branch July 28, 2026 11:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib.rs`:
- Around line 11-14: Restrict the test_fixtures module declaration in src/lib.rs
to test-only compilation, preferably with #[cfg(test)], so it is not exposed
through the public crate API; no direct change is required in CHANGELOG.md
because the public API change should be removed.

In `@src/pipeline/scrubber.rs`:
- Around line 122-129: Update the redacts_email_address test to assert that the
scrubbed message no longer contains the shared FAKE_EMAIL fixture, rather than
checking the hardcoded `@b.com` suffix. Keep the existing redaction-kind assertion
unchanged.

In `@tests/scrubber_fixtures_meta.rs`:
- Around line 1-15: Replace the separately maintained fixture-name and
fixture-value arrays in the meta-test with one authoritative table containing
each fixture’s name, SecretKind, and value. Update both test paths, including
the sections around the existing arrays and the additional referenced ranges, to
iterate over this shared table so adding or removing a fixture cannot leave the
lists out of sync.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0e4eab56-23eb-48e1-a01d-da08312739b7

📥 Commits

Reviewing files that changed from the base of the PR and between 2be8a44 and 7a45dca.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • Cargo.toml
  • src/lib.rs
  • src/pipeline/scrubber.rs
  • src/test_fixtures.rs
  • tests/pipeline_e2e.rs
  • tests/scrubber_fixtures_meta.rs

Comment thread src/lib.rs
Comment on lines +11 to +14
// Test-only fixtures. `#[doc(hidden)]` keeps this out of rustdoc;
// `pub` is required so integration tests under `tests/` can import it.
#[doc(hidden)]
pub mod test_fixtures;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files matching lib.rs / CHANGELOG =="
git ls-files | grep -E '(^|/)src/lib\.rs$|(^|/)CHANGELOG\.md$' || true

echo
echo "== src/lib.rs outline =="
ast-grep outline src/lib.rs --view expanded 2>/dev/null || true

echo
echo "== src/lib.rs relevant lines =="
cat -n src/lib.rs | sed -n '1,80p'

echo
echo "== CHANGELOG relevant lines =="
cat -n CHANGELOG.md | sed -n '1,60p'

echo
echo "== public declarations / test fixture references =="
rg -n "test_fixtures|fixture|pub (mod|struct|const|enum|fn)|#\[doc\(hidden\)\]" src CHANGELOG.md -S || true

echo
echo "== test_fixtures module files =="
git ls-files | grep 'test_fixtures\|fixtures' || true

Repository: LOUST-PRO/LLMmempipe

Length of output: 13236


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== test_fixtures contents =="
cat -n src/test_fixtures.rs | sed -n '1,120p'

echo
echo "== test import sites =="
cat -n src/pipeline/scrubber.rs | sed -n '55,90p'
cat -n tests/scrubber_fixtures_meta.rs | sed -n '1,140p'

echo
echo "== cargo workspace / test config context =="
git ls-files | grep -E '(^|/)Cargo\.toml$|(^|/)tests/' | sort | sed -n '1,120p'

Repository: LOUST-PRO/LLMmempipe

Length of output: 150


Avoid exposing the test fixture module to the public crate API.

#[doc(hidden)] suppresses rustdoc, but pub mod test_fixtures still allows downstream crates to import the module and its #\[doc(hidden)\] pub const fixtures. Keep it test-only, e.g. behind a #[cfg(test)] or test-only Cargo feature; if it must remain public, update the CHANGELOG note to acknowledge the public API change.

📍 Affects 2 files
  • src/lib.rs#L11-L14 (this comment)
  • CHANGELOG.md#L21-L24
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib.rs` around lines 11 - 14, Restrict the test_fixtures module
declaration in src/lib.rs to test-only compilation, preferably with
#[cfg(test)], so it is not exposed through the public crate API; no direct
change is required in CHANGELOG.md because the public API change should be
removed.

Comment thread src/pipeline/scrubber.rs
Comment on lines 122 to 129
#[test]
fn redacts_email_address() {
let cfg = PipelineConfig::with_safe_defaults();
let mut msg = make_msg("ping davidmirelesll@outlook.com later");
let mut msg = make_msg(&format!("ping {} later", FAKE_EMAIL));
let report = scrub(&mut msg, &cfg);
assert!(report.redacted_kinds.contains(&SecretKind::EmailAddress));
assert!(!msg.content.contains("@outlook.com"));
assert!(!msg.content.contains("@b.com"));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert removal of the shared fixture, not a stale suffix.

The input now uses FAKE_EMAIL, but the assertion still hardcodes @b.com. If the fixture changes, this can pass while the actual email remains in the output.

Proposed fix
-        assert!(!msg.content.contains("`@b.com`"));
+        assert!(!msg.content.contains(FAKE_EMAIL));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[test]
fn redacts_email_address() {
let cfg = PipelineConfig::with_safe_defaults();
let mut msg = make_msg("ping davidmirelesll@outlook.com later");
let mut msg = make_msg(&format!("ping {} later", FAKE_EMAIL));
let report = scrub(&mut msg, &cfg);
assert!(report.redacted_kinds.contains(&SecretKind::EmailAddress));
assert!(!msg.content.contains("@outlook.com"));
assert!(!msg.content.contains("@b.com"));
}
#[test]
fn redacts_email_address() {
let cfg = PipelineConfig::with_safe_defaults();
let mut msg = make_msg(&format!("ping {} later", FAKE_EMAIL));
let report = scrub(&mut msg, &cfg);
assert!(report.redacted_kinds.contains(&SecretKind::EmailAddress));
assert!(!msg.content.contains(FAKE_EMAIL));
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pipeline/scrubber.rs` around lines 122 - 129, Update the
redacts_email_address test to assert that the scrubbed message no longer
contains the shared FAKE_EMAIL fixture, rather than checking the hardcoded
`@b.com` suffix. Keep the existing redaction-kind assertion unchanged.

Comment on lines +1 to +15
//! Meta-test: verifies the scrubber recognizes every fixture in
//! `test_fixtures` as a redactable pattern.
//!
//! This is a regression guard against two failure modes:
//!
//! 1. **Fixture added but regex not updated to match.** If a future
//! contributor adds a new `FAKE_*` constant to `src/test_fixtures.rs`
//! but forgets to add a corresponding pattern to
//! `PipelineConfig::with_safe_defaults`, this test catches it.
//!
//! 2. **Regex updated but fixture strings no longer match.** If the
//! scrubber's regex patterns get tightened (e.g., length minimum
//! increased), the fixture strings may no longer match, and this
//! test catches it before the individual `redacts_*` unit tests
//! silently start failing.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the meta-test fixture table authoritative.

The tests iterate manually maintained arrays, so adding a new FAKE_* constant without adding it to both arrays leaves the suite green, contrary to the documentation. The two lists can also drift. Define one table containing the fixture name, SecretKind, and value, then drive both tests from it.

Also applies to: 49-56, 84-91

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/scrubber_fixtures_meta.rs` around lines 1 - 15, Replace the separately
maintained fixture-name and fixture-value arrays in the meta-test with one
authoritative table containing each fixture’s name, SecretKind, and value.
Update both test paths, including the sections around the existing arrays and
the additional referenced ranges, to iterate over this shared table so adding or
removing a fixture cannot leave the lists out of sync.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant