diff --git a/src/mcp/mod.rs b/src/mcp/mod.rs index 9b52770..a440c8c 100644 --- a/src/mcp/mod.rs +++ b/src/mcp/mod.rs @@ -772,10 +772,8 @@ mod tests { #[test] fn stdio_recording_fixtures_match_dispatcher() { - let fixture_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("tests/mcp/fixtures/stdio_smoke.jsonl"); - let fixture = std::fs::read_to_string(&fixture_path) - .unwrap_or_else(|err| panic!("failed to read {}: {err}", fixture_path.display())); + let fixture_path = stdio_smoke_fixture_path(); + let fixture = read_fixture(&fixture_path); for (line_no, line) in fixture.lines().enumerate() { let trimmed = line.trim(); @@ -819,6 +817,47 @@ mod tests { } } + #[test] + fn stdio_recording_fixtures_are_redacted() { + let fixture_path = stdio_smoke_fixture_path(); + let fixture = read_fixture(&fixture_path); + let denied = [ + "ghp_", + "github_pat_", + "Bearer ", + "Authorization", + "/Users/", + "/home/", + "/var/folders/", + ]; + + for (line_no, line) in fixture.lines().enumerate() { + let trimmed = line.trim(); + if trimmed.is_empty() || trimmed.starts_with('#') { + continue; + } + + for pattern in denied { + assert!( + !trimmed.contains(pattern), + "fixture line {} contains unredacted pattern '{}'", + line_no + 1, + pattern + ); + } + } + } + + fn stdio_smoke_fixture_path() -> std::path::PathBuf { + std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests/mcp/fixtures/stdio_smoke.jsonl") + } + + fn read_fixture(path: &std::path::Path) -> String { + std::fs::read_to_string(path) + .unwrap_or_else(|err| panic!("failed to read {}: {err}", path.display())) + } + fn assert_fixture_assertion( name: &str, response: &serde_json::Value, diff --git a/tests/mcp/README.md b/tests/mcp/README.md index d21c7a8..6b9ae09 100644 --- a/tests/mcp/README.md +++ b/tests/mcp/README.md @@ -47,10 +47,10 @@ secret-bearing values with deterministic placeholders. | Wall-clock timestamps | `` | | Network request IDs | `` | -Reviewers should reject fixtures that contain token-shaped strings such as -`ghp_`, `github_pat_`, `Bearer `, or `Authorization`. Fixture responses should -also avoid raw stdout/stderr dumps from MCP clients; assert only the stable JSON -fields needed by the smoke contract. +The test suite rejects fixtures that contain token-shaped strings such as +`ghp_`, `github_pat_`, `Bearer `, `Authorization`, or common absolute local +path prefixes. Fixture responses should also avoid raw stdout/stderr dumps from +MCP clients; assert only the stable JSON fields needed by the smoke contract. ## Recording Checklist @@ -58,5 +58,5 @@ fields needed by the smoke contract. 2. Redact secrets, local paths, timestamps, and network-generated IDs. 3. Prefer `contains_text`, `kind`, `min_len`, and `contains_tool` over copying full response payloads. -4. Run `cargo test --quiet mcp::tests::stdio_recording_fixtures_match_dispatcher` +4. Run `cargo test --quiet mcp::tests::stdio_recording_fixtures` before opening a PR.