forked from mirrors/kingfisher
commit
aef163ba55
10 changed files with 162 additions and 29 deletions
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [1.25.0]
|
||||
- Fixed GitLab authentication bug
|
||||
- Added pre-commit and pre-receive installation hooks
|
||||
- MongoDB validator now skips `mongodb+srv://` URIs and returns a message that validation was skipped
|
||||
- Fixed noisy Baseten rule
|
||||
|
||||
## [1.24.0]
|
||||
- Now generating DEB and RPM packages
|
||||
- Now releasing Docker images, and updated README
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ publish = false
|
|||
|
||||
[package]
|
||||
name = "kingfisher"
|
||||
version = "1.24.0"
|
||||
version = "1.25.0"
|
||||
description = "MongoDB's blazingly fast secret scanning and validation tool"
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
|
|
|||
22
README.md
22
README.md
|
|
@ -318,7 +318,27 @@ _If no token is provided Kingfisher still works for public repositories._
|
|||
| 200 | Findings discovered |
|
||||
| 205 | Validated findings discovered |
|
||||
|
||||
---
|
||||
|
||||
## Install a Pre-Commit Hook
|
||||
|
||||
Run the provided helper script to add a hook that scans staged files before each commit:
|
||||
|
||||
```bash
|
||||
./install-precommit-hook.sh
|
||||
```
|
||||
|
||||
This creates `.git/hooks/pre-commit` that scans the files staged for commit with `kingfisher scan --no-update-check` and blocks the commit if any secrets are found.
|
||||
|
||||
### Install a Pre-Receive Hook
|
||||
|
||||
To check incoming pushes on a server-side repository, install the pre-receive hook:
|
||||
|
||||
```bash
|
||||
./install-prereceive-hook.sh
|
||||
```
|
||||
|
||||
The resulting `.git/hooks/pre-receive` script scans the files in each pushed commit and rejects the push if any secrets are detected.
|
||||
|
||||
|
||||
## Update Checks
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ rules:
|
|||
pattern: |
|
||||
(?x)
|
||||
\b
|
||||
baseten
|
||||
(?:.|[\n\r]){0,32}?
|
||||
\b
|
||||
(
|
||||
[A-Za-z0-9]{8}
|
||||
\.
|
||||
|
|
@ -13,10 +16,10 @@ rules:
|
|||
min_entropy: 3.4
|
||||
confidence: medium
|
||||
examples:
|
||||
- WSsDXzCD.uOcxAp7k82IvCKyY36TnpVbP4ZszP1qw
|
||||
- crXCQC3W.CgCGGY1b9IfJan5TppW0Z07C9oMN2DmR
|
||||
- h2wFkhFC.3WFVwVcxGFr4Qup0gyhvIuONwQxEpL0A
|
||||
- XqbIpj04.x73j1zLUOEgGIKROqVbxsmggPdL8JvAY
|
||||
- baseten_key = WSsDXzCD.uOcxAp7k82IvCKyY36TnpVbP4ZszP1qw
|
||||
- baseten_key = crXCQC3W.CgCGGY1b9IfJan5TppW0Z07C9oMN2DmR
|
||||
- baseten_key = h2wFkhFC.3WFVwVcxGFr4Qup0gyhvIuONwQxEpL0A
|
||||
- baseten_key = XqbIpj04.x73j1zLUOEgGIKROqVbxsmggPdL8JvAY
|
||||
references:
|
||||
- https://docs.baseten.co/examples/vllm
|
||||
- https://docs.baseten.co/reference/management-api/api-keys/lists-the-users-api-keys
|
||||
|
|
|
|||
|
|
@ -91,4 +91,6 @@ rules:
|
|||
\b
|
||||
min_entropy: 3.5
|
||||
examples:
|
||||
- mdb_sa_sk_BdIX_jLzut2WTgglKzKvSgWMDDj5hEoTqdwOyLOL
|
||||
- mdb_sa_sk_BdIX_jLzut2WTgglKzKvSgWMDDj5hEoTqdwOyLOL
|
||||
validation:
|
||||
type: MongoDB
|
||||
32
install-precommit-hook.sh
Normal file
32
install-precommit-hook.sh
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
HOOK_DIR="$(git rev-parse --git-dir)/hooks"
|
||||
HOOK_PATH="$HOOK_DIR/pre-commit"
|
||||
|
||||
if [ -e "$HOOK_PATH" ]; then
|
||||
echo "Error: $HOOK_PATH already exists. Move or remove the existing hook to continue." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat > "$HOOK_PATH" <<'HOOK'
|
||||
#!/usr/bin/env bash
|
||||
# Pre-commit hook to run Kingfisher scan on staged changes
|
||||
set -euo pipefail
|
||||
|
||||
if ! command -v kingfisher >/dev/null 2>&1; then
|
||||
echo "kingfisher not found in PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git diff --cached --name-only -z | \
|
||||
xargs -0 --no-run-if-empty kingfisher scan --no-update-check
|
||||
status=$?
|
||||
if [ "$status" -ne 0 ]; then
|
||||
echo "Kingfisher detected secrets in staged files. Commit aborted." >&2
|
||||
exit "$status"
|
||||
fi
|
||||
HOOK
|
||||
|
||||
chmod +x "$HOOK_PATH"
|
||||
echo "Pre-commit hook installed to $HOOK_PATH"
|
||||
39
install-prereceive-hook.sh
Normal file
39
install-prereceive-hook.sh
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
HOOK_DIR="$(git rev-parse --git-dir)/hooks"
|
||||
HOOK_PATH="$HOOK_DIR/pre-receive"
|
||||
|
||||
if [ -e "$HOOK_PATH" ]; then
|
||||
echo "Error: $HOOK_PATH already exists. Move or remove the existing hook to continue." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat > "$HOOK_PATH" <<'HOOK'
|
||||
#!/usr/bin/env bash
|
||||
# Pre-receive hook to scan pushed commits with Kingfisher
|
||||
set -euo pipefail
|
||||
|
||||
if ! command -v kingfisher >/dev/null 2>&1; then
|
||||
echo "kingfisher not found in PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while read -r oldrev newrev refname; do
|
||||
if [ "$oldrev" = "0000000000000000000000000000000000000000" ]; then
|
||||
git diff-tree --name-only -r "$newrev" -z |
|
||||
xargs -0 --no-run-if-empty kingfisher scan --no-update-check
|
||||
else
|
||||
git diff-tree --no-commit-id --name-only -r "$oldrev" "$newrev" -z |
|
||||
xargs -0 --no-run-if-empty kingfisher scan --no-update-check
|
||||
fi
|
||||
status=$?
|
||||
if [ "$status" -ne 0 ]; then
|
||||
echo "Kingfisher detected secrets in push. Push rejected." >&2
|
||||
exit "$status"
|
||||
fi
|
||||
done
|
||||
HOOK
|
||||
|
||||
chmod +x "$HOOK_PATH"
|
||||
echo "Pre-receive hook installed to $HOOK_PATH"
|
||||
|
|
@ -36,17 +36,33 @@ impl Git {
|
|||
/// Create a new `Git` instance.
|
||||
///
|
||||
/// * `ignore_certs`: If `true`, disables SSL certificate verification for `git` operations.
|
||||
pub fn new(ignore_certs: bool) -> Self {
|
||||
let credentials = if std::env::var("KF_GITHUB_TOKEN").is_ok() {
|
||||
vec![
|
||||
"-c".into(),
|
||||
r#"credential.helper="#.into(),
|
||||
"-c".into(),
|
||||
pub fn new(ignore_certs: bool) -> Self {
|
||||
let mut credentials = Vec::new();
|
||||
|
||||
// If either GitHub or GitLab token is set, first clear existing credential.helpers
|
||||
if std::env::var("KF_GITHUB_TOKEN").is_ok()
|
||||
|| std::env::var("KF_GITLAB_TOKEN").is_ok()
|
||||
{
|
||||
credentials.push("-c".into());
|
||||
credentials.push(r#"credential.helper="#.into());
|
||||
}
|
||||
|
||||
// Inject GitHub token helper
|
||||
if std::env::var("KF_GITHUB_TOKEN").is_ok() {
|
||||
credentials.push("-c".into());
|
||||
credentials.push(
|
||||
r#"credential.helper=!_ghcreds() { echo username="kingfisher"; echo password="$KF_GITHUB_TOKEN"; }; _ghcreds"#.into(),
|
||||
]
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
);
|
||||
}
|
||||
|
||||
// Inject GitLab token helper
|
||||
if std::env::var("KF_GITLAB_TOKEN").is_ok() {
|
||||
credentials.push("-c".into());
|
||||
credentials.push(
|
||||
r#"credential.helper=!_glcreds() { echo username="oauth2"; echo password="$KF_GITLAB_TOKEN"; }; _glcreds"#.into(),
|
||||
);
|
||||
}
|
||||
|
||||
Self { credentials, ignore_certs }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -538,16 +538,16 @@ async fn timed_validate_single_match<'a>(
|
|||
}
|
||||
|
||||
match mongodb::validate_mongodb(&uri).await {
|
||||
Ok(ok) => {
|
||||
Ok((ok, msg)) => {
|
||||
m.validation_success = ok;
|
||||
m.validation_response_body = if ok {
|
||||
"MongoDB connection is valid."
|
||||
m.validation_response_body = msg;
|
||||
m.validation_response_status = if uri.starts_with("mongodb+srv://") {
|
||||
StatusCode::CONTINUE
|
||||
} else if ok {
|
||||
StatusCode::OK
|
||||
} else {
|
||||
"MongoDB connection failed."
|
||||
}
|
||||
.to_string();
|
||||
m.validation_response_status =
|
||||
if ok { StatusCode::OK } else { StatusCode::UNAUTHORIZED };
|
||||
StatusCode::UNAUTHORIZED
|
||||
};
|
||||
}
|
||||
Err(e) => {
|
||||
m.validation_success = false;
|
||||
|
|
|
|||
|
|
@ -19,15 +19,24 @@ const FAST_SELECT_MS: u64 = 300;
|
|||
const SRV_CONNECT_MS: u64 = 15_000; // gives Atlas a fighting chance
|
||||
const SRV_SELECT_MS: u64 = 15_000;
|
||||
|
||||
/// Validates a MongoDB URI in ≤ 2 s. Returns `Ok(true)` on successful ping.
|
||||
pub async fn validate_mongodb(uri: &str) -> Result<bool> {
|
||||
/// Validates a MongoDB URI in ≤ 2 s. Returns `(bool, String)` where the
|
||||
/// boolean indicates success and the string provides a status message.
|
||||
pub async fn validate_mongodb(uri: &str) -> Result<(bool, String)> {
|
||||
// ---- quick reject without touching the network
|
||||
if !looks_like_mongodb_uri(uri) {
|
||||
return Ok(false);
|
||||
return Ok((false, "Invalid MongoDB URI".to_string()));
|
||||
}
|
||||
|
||||
let is_srv = uri.starts_with("mongodb+srv://");
|
||||
|
||||
if is_srv {
|
||||
// Skip SRV URIs to avoid slow DNS lookups and topology discovery.
|
||||
return Ok((
|
||||
false,
|
||||
"Validation skipped for mongodb+srv:// URI (performance reasons)".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// ---- build client opts
|
||||
let mut opts = ClientOptions::parse(uri).await?;
|
||||
if !is_srv {
|
||||
|
|
@ -46,7 +55,13 @@ pub async fn validate_mongodb(uri: &str) -> Result<bool> {
|
|||
|
||||
// ---- dial and ping
|
||||
let client = Client::with_options(opts)?;
|
||||
Ok(client.database("admin").run_command(doc! { "ping": 1 }).await.is_ok())
|
||||
let ok = client.database("admin").run_command(doc! { "ping": 1 }).await.is_ok();
|
||||
let msg = if ok {
|
||||
"MongoDB connection is valid.".to_string()
|
||||
} else {
|
||||
"MongoDB connection failed.".to_string()
|
||||
};
|
||||
Ok((ok, msg))
|
||||
}
|
||||
|
||||
// pub fn generate_mongodb_cache_key(mongodb_uri: &str) -> String {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue