summaryrefslogtreecommitdiffstats
path: root/atuin-client/src/history.rs
diff options
context:
space:
mode:
authorEllie Huxtable <ellie@elliehuxtable.com>2023-08-19 12:28:39 +0100
committerGitHub <noreply@github.com>2023-08-19 12:28:39 +0100
commit73bd8015c3ba50ceb5168a8b67bb1ac5d3b48dc1 (patch)
tree0fe6dbe55a7dda6bd93a72fbfcb29e6f3993e95c /atuin-client/src/history.rs
parentaa8e5f5c04524d3d5c6f1d5b6c4616dbdb8d40be (diff)
Automatically filter out secrets (#1182)
I'd like to extend the regex list here very soon, but start off by automatically filtering out secrets. Do not store them in history! I've included regex for: 1. AWS key id 2. Github pat (old and new) 3. Slack oauth tokens (bot, user) 4. Slack webhooks 5. Stripe live/test keys Will need updating after #806
Diffstat (limited to 'atuin-client/src/history.rs')
-rw-r--r--atuin-client/src/history.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/atuin-client/src/history.rs b/atuin-client/src/history.rs
index 441960c8..4d084786 100644
--- a/atuin-client/src/history.rs
+++ b/atuin-client/src/history.rs
@@ -3,6 +3,9 @@ use std::env;
use chrono::Utc;
use atuin_common::utils::uuid_v7;
+use regex::RegexSet;
+
+use crate::{secrets::SECRET_PATTERNS, settings::Settings};
mod builder;
@@ -185,4 +188,87 @@ impl History {
pub fn success(&self) -> bool {
self.exit == 0 || self.duration == -1
}
+
+ pub fn should_save(&self, settings: &Settings) -> bool {
+ let secret_regex = SECRET_PATTERNS.iter().map(|f| f.1);
+ let secret_regex = RegexSet::new(secret_regex).expect("Failed to build secrets regex");
+
+ !(self.command.starts_with(' ')
+ || settings.history_filter.is_match(&self.command)
+ || settings.cwd_filter.is_match(&self.cwd)
+ || (secret_regex.is_match(&self.command)) && settings.secrets_filter)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use regex::RegexSet;
+
+ use crate::settings::Settings;
+
+ use super::History;
+
+ // Test that we don't save history where necessary
+ #[test]
+ fn privacy_test() {
+ let mut settings = Settings::default();
+ settings.cwd_filter = RegexSet::new(["^/supasecret"]).unwrap();
+ settings.history_filter = RegexSet::new(["^psql"]).unwrap();
+
+ let normal_command: History = History::capture()
+ .timestamp(chrono::Utc::now())
+ .command("echo foo")
+ .cwd("/")
+ .build()
+ .into();
+
+ let with_space: History = History::capture()
+ .timestamp(chrono::Utc::now())
+ .command(" echo bar")
+ .cwd("/")
+ .build()
+ .into();
+
+ let stripe_key: History = History::capture()
+ .timestamp(chrono::Utc::now())
+ .command("curl foo.com/bar?key=sk_test_1234567890abcdefghijklmnop")
+ .cwd("/")
+ .build()
+ .into();
+
+ let secret_dir: History = History::capture()
+ .timestamp(chrono::Utc::now())
+ .command("echo ohno")
+ .cwd("/supasecret")
+ .build()
+ .into();
+
+ let with_psql: History = History::capture()
+ .timestamp(chrono::Utc::now())
+ .command("psql")
+ .cwd("/supasecret")
+ .build()
+ .into();
+
+ assert!(normal_command.should_save(&settings));
+ assert!(!with_space.should_save(&settings));
+ assert!(!stripe_key.should_save(&settings));
+ assert!(!secret_dir.should_save(&settings));
+ assert!(!with_psql.should_save(&settings));
+ }
+
+ #[test]
+ fn disable_secrets() {
+ let mut settings = Settings::default();
+ settings.secrets_filter = false;
+
+ let stripe_key: History = History::capture()
+ .timestamp(chrono::Utc::now())
+ .command("curl foo.com/bar?key=sk_test_1234567890abcdefghijklmnop")
+ .cwd("/")
+ .build()
+ .into();
+
+ assert!(stripe_key.should_save(&settings));
+ }
}