1#![doc(
2 html_logo_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png",
3 html_favicon_url = "https://raw.githubusercontent.com/getsentry/relay/master/artwork/relay-icon.png"
4)]
5
6use std::fs;
7use std::path::PathBuf;
8
9use anyhow::{Context, Result, format_err};
10use clap::Parser;
11use relay_pii::{PiiAttachmentsProcessor, PiiConfig};
12
13#[derive(Debug, Parser)]
30#[structopt(verbatim_doc_comment)]
31struct Cli {
32 #[arg(short, long)]
34 config: PathBuf,
35
36 minidump: PathBuf,
38
39 #[arg(short, long)]
41 output: Option<PathBuf>,
42}
43
44impl Cli {
45 fn load_pii_config(&self) -> Result<PiiConfig> {
46 let json = fs::read_to_string(&self.config).with_context(|| "failed to read PII config")?;
47 let config = serde_json::from_str(&json).with_context(|| "failed to parse PII config")?;
48 Ok(config)
49 }
50
51 fn load_minidump(&self) -> Result<Vec<u8>> {
52 let buf = fs::read(&self.minidump).with_context(|| "failed to open minidump")?;
53 Ok(buf)
54 }
55
56 fn minidump_name(&self) -> &str {
57 self.minidump
58 .file_name()
59 .and_then(|os_str| os_str.to_str())
60 .unwrap_or_default()
61 }
62
63 fn write_output(&self, data: &[u8]) -> Result<()> {
64 let path = match self.output {
65 Some(ref output) => output,
66 None => &self.minidump,
67 };
68
69 fs::write(path, data)
70 .with_context(|| format!("failed to write minidump to {}", path.display()))?;
71
72 println!("output written to {}", path.display());
73
74 Ok(())
75 }
76
77 pub fn run(self) -> Result<()> {
78 let config = self.load_pii_config()?;
79 let processor = PiiAttachmentsProcessor::new(config.compiled());
80
81 let mut data = self.load_minidump()?;
82 let changed = processor
83 .scrub_minidump(self.minidump_name(), &mut data)
84 .map_err(|e| format_err!("{e}"))?; if changed {
87 self.write_output(&data)?;
88 } else {
89 println!("nothing changed.");
90 }
91
92 Ok(())
93 }
94}
95
96fn print_error(error: &anyhow::Error) {
97 eprintln!("Error: {error}");
98
99 let mut cause = error.source();
100 while let Some(ref e) = cause {
101 eprintln!(" caused by: {e}");
102 cause = e.source();
103 }
104}
105
106fn main() {
107 let cli = Cli::parse();
108
109 match cli.run() {
110 Ok(()) => (),
111 Err(error) => {
112 print_error(&error);
113 std::process::exit(1);
114 }
115 }
116}