workerlib/
redact.rs

1//!
2//! Helper utility that can redact sensitive strings common in Lorry
3//!
4
5use fancy_regex::Regex;
6use std::fmt::Display;
7use std::sync::OnceLock;
8
9fn get_expressions() -> &'static Vec<Regex> {
10    static EXPRESSIONS: OnceLock<Vec<Regex>> = OnceLock::new();
11    EXPRESSIONS.get_or_init(|| {
12        vec![
13            // List of token patterns referenced from https://docs.gitlab.com/18.7/security/tokens/#token-prefixes
14            Regex::new(
15                r##"gl(pat|oas|dt|rt|rtr|cbt|ptt|ft|imt|agent|wt|soat|ffct)-[0-9a-zA-Z\-_]*"##,
16            )
17            .unwrap(),
18            // List of token patterns referenced from
19            // https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-authentication-to-github#githubs-token-formats
20            Regex::new(r##"g(hp|ithub_pat|ho|hu|hs|hr)_[0-9a-zA-Z\-_]*"##).unwrap(),
21        ]
22    })
23}
24
25/// Removes any known sensitive strings from the input and replaces them
26/// with LORRY_REDACTED
27pub fn redact(input: &impl Display) -> String {
28    let mut copy = input.to_string();
29    for expr in get_expressions() {
30        copy = expr.replace_all(&copy, "LORRY_REDACTED").to_string();
31    }
32    copy
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38
39    struct TestCase<'a> {
40        pub input: &'a str,
41        pub expected: &'a str,
42    }
43
44    impl TestCase<'_> {
45        pub fn check(&self) {
46            let result = redact(&self.input.to_string());
47            assert!(result == self.expected);
48        }
49    }
50
51    #[test]
52    fn test_redact() {
53        TestCase {
54            input: "glpat-Y38-kU_3pviux6H1D9ec",
55            expected: "LORRY_REDACTED",
56        }
57        .check();
58        TestCase {
59            input: "glpat-AdmAbJdT-FMYPa_2bQyy",
60            expected: "LORRY_REDACTED",
61        }
62        .check();
63        TestCase {
64            input: "glpat-MjW2FqijnvVBs7yPEoDG",
65            expected: "LORRY_REDACTED",
66        }
67        .check();
68        TestCase {
69            input: "Using git binary to push remote: http://oauth2:glpat-25HjHgcpRJsY_JQweJYa@localhost:9999/lorry-mirrors/test/lorry.git",
70            expected: "Using git binary to push remote: http://oauth2:LORRY_REDACTED@localhost:9999/lorry-mirrors/test/lorry.git",
71        }.check();
72    }
73}