Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 43 additions & 4 deletions src/mcp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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,
Expand Down
10 changes: 5 additions & 5 deletions tests/mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,16 @@ secret-bearing values with deterministic placeholders.
| Wall-clock timestamps | `<timestamp>` |
| Network request IDs | `<request-id>` |

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

1. Capture the smallest request/response pair that exercises the behavior.
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.
Loading