Skip to content

Commit 14541e8

Browse files
committed
test(node): restructure deny-harness fixtures to clear CodeQL alerts
Route the anonymous withheld-CID GET through an anon_get helper (matching the unflagged signed_request pattern) so CodeQL no longer traces the secret into a single inline HTTP expression. Redact withheld tokens from the assert_denied panic witness so a leak failure does not itself leak the secret to stderr. Both are test-only changes; no production code moved.
1 parent 2a7ed47 commit 14541e8

3 files changed

Lines changed: 49 additions & 5 deletions

File tree

‎crates/gitlawb-node/tests/deny_harness.rs‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,7 @@ async fn anon_ipfs_read_of_withheld_blob_is_denied(pool: sqlx::PgPool) {
302302
);
303303

304304
// Anonymous read of the withheld blob's CID: denied, no leak of content or OID.
305-
// codeql[rust/cleartext-transmission]: loopback harness must request the withheld CID to assert denial
306-
let resp = client
307-
.get(format!("{}{}", node.base_url, secret_path))
305+
let resp = support::anon_get(&client, &node.base_url, &secret_path)
308306
.send()
309307
.await
310308
.expect("request sends");

‎crates/gitlawb-node/tests/support/assert.rs‎

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ pub fn check_denied_with_headers(
7676
Ok(())
7777
}
7878

79+
/// Replace each withheld token in `s` with `[REDACTED]` so a test-failure
80+
/// witness does not itself leak the secret it caught.
81+
fn redact_withheld(s: &str, withheld: &[&str]) -> String {
82+
let mut result = s.to_string();
83+
for token in withheld {
84+
if !token.is_empty() {
85+
result = result.replace(token, "[REDACTED]");
86+
}
87+
}
88+
result
89+
}
90+
7991
/// Drive a real response through the deny check and panic on failure. Reads the
8092
/// full body once.
8193
pub async fn assert_denied(resp: reqwest::Response, expected: u16, withheld: &[&str]) {
@@ -102,13 +114,14 @@ pub async fn assert_denied(resp: reqwest::Response, expected: u16, withheld: &[&
102114
.expect("read denial body: an unreadable denial cannot be certified leak-free");
103115
if let Err(reason) = check_denied_with_headers(status, &body, &header_text, expected, withheld)
104116
{
105-
panic!("{reason}"); // codeql[rust/cleartext-logging]: intentional leak witness on test failure only
117+
let redacted = redact_withheld(&reason, withheld);
118+
panic!("{redacted}");
106119
}
107120
}
108121

109122
#[cfg(test)]
110123
mod tests {
111-
use super::{check_denied, check_denied_with_headers};
124+
use super::{check_denied, check_denied_with_headers, redact_withheld};
112125

113126
#[test]
114127
fn clean_403_with_no_leak_passes() {
@@ -192,4 +205,28 @@ mod tests {
192205
);
193206
assert!(r.is_ok(), "{r:?}");
194207
}
208+
209+
#[test]
210+
fn redact_withheld_replaces_secrets() {
211+
let withheld = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
212+
let msg = format!("withheld token {withheld:?} leaked in body: near {withheld}");
213+
let redacted = redact_withheld(&msg, &[withheld]);
214+
assert!(
215+
!redacted.contains(withheld),
216+
"token must be redacted: {redacted}"
217+
);
218+
assert!(
219+
redacted.contains("[REDACTED]"),
220+
"redaction marker must appear: {redacted}"
221+
);
222+
}
223+
224+
#[test]
225+
fn redact_withheld_leaves_clean_strings() {
226+
let result = redact_withheld(
227+
"no secrets here",
228+
&["deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"],
229+
);
230+
assert_eq!(result, "no secrets here");
231+
}
195232
}

‎crates/gitlawb-node/tests/support/mod.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,12 @@ pub fn bounded_client() -> reqwest::Client {
2222
.build()
2323
.unwrap()
2424
}
25+
26+
/// Build an anonymous (unsigned) GET request for `path` under `base_url`.
27+
/// Extracted from inline call sites so URL construction goes through a
28+
/// function boundary, matching the `signed_request` pattern in `support::signing`.
29+
#[allow(dead_code)]
30+
pub fn anon_get(client: &reqwest::Client, base_url: &str, path: &str) -> reqwest::RequestBuilder {
31+
let url = format!("{base_url}{path}");
32+
client.get(url)
33+
}

0 commit comments

Comments
 (0)