assay_core/render_safety/
corpus.rs1use lazy_static::lazy_static;
9use serde_json::json;
10use sha2::{Digest, Sha256};
11
12pub struct Probe {
15 pub name: &'static str,
16 pub class: &'static str, pub input: String,
18 pub needle: String,
19}
20
21fn p(name: &'static str, class: &'static str, input: String, needle: String) -> Probe {
22 Probe {
23 name,
24 class,
25 input,
26 needle,
27 }
28}
29
30lazy_static! {
31 static ref FAKE_PEM: String = format!("{}{}{}", "-----BEGIN ", "PRIVATE ", "KEY-----");
33 pub static ref HOSTILE: Vec<Probe> = {
34 let github = format!("ghp_{}", "A".repeat(36));
35 let aws = format!("AKIA{}", "A".repeat(16));
36 let bearer = format!("Bearer {}", "abcdABCD0123".repeat(2));
38 let slack = format!("xoxb-{}", "0123456789abcdef");
39 let boundary = format!("{} ghp_{}", "x".repeat(239), "D".repeat(36));
42 vec![
43 p("github_pat", "secret", github.clone(), github),
44 p("aws_key", "secret", aws.clone(), aws),
45 p("bearer_token", "secret", bearer.clone(), bearer),
46 p("slack_token", "secret", slack.clone(), slack),
47 p("private_key", "secret", FAKE_PEM.clone(), FAKE_PEM.clone()),
48 p("email", "pii", "alice@example.com".to_string(), "alice@example.com".to_string()),
49 p("slack_user_id", "pii", "U01ABCDEFG".to_string(), "U01ABCDEFG".to_string()),
50 p("ansi_escape", "control", "\u{1b}[31mRED\u{1b}[0m".to_string(), "\u{1b}".to_string()),
51 p("c1_csi", "control", "\u{009b}31mRED".to_string(), "\u{009b}".to_string()),
52 p("unicode_bidi", "control", "\u{202e}reversed\u{202c}".to_string(), "\u{202e}".to_string()),
53 p("long_secret_prefix", "secret", boundary, "ghp_".to_string()),
55 ]
56 };
57 pub static ref BENIGN: Vec<Probe> = vec![
58 p("fake_short_token", "benign", "tok_12345".to_string(), "tok_12345".to_string()),
59 p(
60 "schema_text",
61 "benign",
62 "assay.mcp_server_inventory.v0".to_string(),
63 "mcp_server_inventory".to_string(),
64 ),
65 p(
66 "ordinary_uuid",
67 "benign",
68 "id 123e4567-e89b-12d3-a456-426614174000".to_string(),
69 "123e4567".to_string(),
70 ),
71 p(
72 "content_hash",
73 "benign",
74 format!("digest sha256:{}", "a".repeat(64)),
75 "sha256:".to_string(),
76 ),
77 p(
78 "non_secret_path",
79 "benign",
80 "/usr/local/bin/assay".to_string(),
81 "/usr/local/bin/assay".to_string(),
82 ),
83 ];
84}
85
86pub fn corpus_digest() -> String {
89 let value = json!({
90 "hostile": HOSTILE.iter().map(|x| json!({"name": x.name, "input": x.input})).collect::<Vec<_>>(),
91 "benign": BENIGN.iter().map(|x| json!({"name": x.name, "input": x.input})).collect::<Vec<_>>(),
92 });
93 let bytes = serde_jcs::to_vec(&value).expect("corpus is JSON-serializable");
94 format!("sha256:{}", hex::encode(Sha256::digest(&bytes)))
95}