Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file.

### Features

- *(client)* Identify several other GitHub token types as secrets
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be overwritten when we next generate the changelog (with git cliff), but I appreciate the thought 😊

- *(daemon)* Follow XDG_RUNTIME_DIR if set ([#2171](https://github.com/atuinsh/atuin/issues/2171))
- *(gui)* Automatically install and setup the cli/shell ([#2139](https://github.com/atuinsh/atuin/issues/2139))
- *(gui)* Add activity calendar to the homepage ([#2160](https://github.com/atuinsh/atuin/issues/2160))
Expand Down
81 changes: 63 additions & 18 deletions crates/atuin-client/src/secrets.rs
Original file line number Diff line number Diff line change
@@ -1,84 +1,129 @@
// This file will probably trigger a lot of scanners. Sorry.

pub enum TestValue<'a> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea!

Single(&'a str),
Multiple(&'a [&'a str]),
}

// A list of (name, regex, test), where test should match against regex
pub static SECRET_PATTERNS: &[(&str, &str, &str)] = &[
pub static SECRET_PATTERNS: &[(&str, &str, TestValue)] = &[
(
"AWS Access Key ID",
"AKIA[0-9A-Z]{16}",
"AKIAIOSFODNN7EXAMPLE",
TestValue::Single("AKIAIOSFODNN7EXAMPLE"),
),
(
"AWS secret access key env var",
"AWS_ACCESS_KEY_ID",
"export AWS_ACCESS_KEY_ID=KEYDATA",
TestValue::Single("export AWS_ACCESS_KEY_ID=KEYDATA"),
),
(
"AWS secret access key env var",
"AWS_ACCESS_KEY_ID",
"export AWS_ACCESS_KEY_ID=KEYDATA",
TestValue::Single("export AWS_ACCESS_KEY_ID=KEYDATA"),
),
(
"Microsoft Azure secret access key env var",
"AZURE_.*_KEY",
"export AZURE_STORAGE_ACCOUNT_KEY=KEYDATA",
TestValue::Single("export AZURE_STORAGE_ACCOUNT_KEY=KEYDATA"),
),
(
"Google cloud platform key env var",
"GOOGLE_SERVICE_ACCOUNT_KEY",
"export GOOGLE_SERVICE_ACCOUNT_KEY=KEYDATA",
TestValue::Single("export GOOGLE_SERVICE_ACCOUNT_KEY=KEYDATA"),
),
(
"Atuin login",
r"atuin\s+login",
"atuin login -u mycoolusername -p mycoolpassword -k \"lots of random words\"",
TestValue::Single("atuin login -u mycoolusername -p mycoolpassword -k \"lots of random words\""),
),
(
"GitHub PAT (old)",
"ghp_[a-zA-Z0-9]{36}",
"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", // legit, I expired it
TestValue::Single("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"), // legit, I expired it
),
(
"GitHub PAT (new)",
"github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}",
"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", // also legit, also expired
"gh1_[A-Za-z0-9]{21}_[A-Za-z0-9]{59}|github_pat_[0-9][A-Za-z0-9]{21}_[A-Za-z0-9]{59}",
TestValue::Multiple(&[
"gh1_1234567890abcdefghijk_1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklm",
"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", // also legit, also expired
])
),
(
"GitHub OAuth Access Token",
"gho_[A-Za-z0-9]{36}",
TestValue::Single("gho_1234567890abcdefghijklmnopqrstuvwx000"), // not a real token
),
(
"GitHub OAuth Access Token (user)",
"ghu_[A-Za-z0-9]{36}",
TestValue::Single("ghu_1234567890abcdefghijklmnopqrstuvwx000"), // not a real token
),
(
"GitHub App Installation Access Token",
"ghs_[A-Za-z0-9]{36}",
TestValue::Single("ghs_1234567890abcdefghijklmnopqrstuvwx000"), // not a real token
),
(
"GitHub Refresh Token",
"ghr_[A-Za-z0-9]{76}",
TestValue::Single("ghr_1234567890abcdefghijklmnopqrstuvwx1234567890abcdefghijklmnopqrstuvwx1234567890abcdefghijklmnopqrstuvwx"), // not a real token
),
(
"GitHub App Installation Access Token v1",
"v1\\.[0-9A-Fa-f]{40}",
TestValue::Single("v1.1234567890abcdef1234567890abcdef12345678"), // not a real token
),
(
"GitLab PAT",
"glpat-[a-zA-Z0-9_]{20}",
"glpat-RkE_BG5p_bbjML21WSfy",
TestValue::Single("glpat-RkE_BG5p_bbjML21WSfy"),
),
(
"Slack OAuth v2 bot",
"xoxb-[0-9]{11}-[0-9]{11}-[0-9a-zA-Z]{24}",
"xoxb-17653672481-19874698323-pdFZKVeTuE8sk7oOcBrzbqgy",
TestValue::Single("xoxb-17653672481-19874698323-pdFZKVeTuE8sk7oOcBrzbqgy"),
),
(
"Slack OAuth v2 user token",
"xoxp-[0-9]{11}-[0-9]{11}-[0-9a-zA-Z]{24}",
"xoxp-17653672481-19874698323-pdFZKVeTuE8sk7oOcBrzbqgy",
TestValue::Single("xoxp-17653672481-19874698323-pdFZKVeTuE8sk7oOcBrzbqgy"),
),
(
"Slack webhook",
"T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}",
"https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
TestValue::Single("https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX"),
),
("Stripe test key", "sk_test_[0-9a-zA-Z]{24}", "sk_test_1234567890abcdefghijklmnop"),
("Stripe live key", "sk_live_[0-9a-zA-Z]{24}", "sk_live_1234567890abcdefghijklmnop"),
("Stripe test key", "sk_test_[0-9a-zA-Z]{24}", TestValue::Single("sk_test_1234567890abcdefghijklmnop")),
("Stripe live key", "sk_live_[0-9a-zA-Z]{24}", TestValue::Single("sk_live_1234567890abcdefghijklmnop")),
];

#[cfg(test)]
mod tests {
use regex::Regex;

use crate::secrets::SECRET_PATTERNS;
use crate::secrets::{TestValue, SECRET_PATTERNS};

#[test]
fn test_secrets() {
for (name, regex, test) in SECRET_PATTERNS {
let re =
Regex::new(regex).unwrap_or_else(|_| panic!("Failed to compile regex for {name}"));

assert!(re.is_match(test), "{name} test failed!");
match test {
TestValue::Single(test) => {
assert!(re.is_match(test), "{name} test failed!");
}
TestValue::Multiple(tests) => {
for test_str in tests.iter() {
assert!(
re.is_match(test_str),
"{name} test with value \"{test_str}\" failed!"
);
}
}
}
}
}
}