From 787a5aaf22a2ed0f378325f9e444c2e2e0129253 Mon Sep 17 00:00:00 2001 From: Mick Grove Date: Mon, 28 Jul 2025 10:25:11 -0700 Subject: [PATCH] improved precommit hook, to allow global installation --- README.md | 21 ++++++++++----- install-precommit-hook.sh | 53 ++++++++++++++++++++++++++++++++------ install-prereceive-hook.sh | 0 src/scanner/docker.rs | 4 +-- 4 files changed, 61 insertions(+), 17 deletions(-) mode change 100644 => 100755 install-precommit-hook.sh mode change 100644 => 100755 install-prereceive-hook.sh diff --git a/README.md b/README.md index e2b982f..8dab5ad 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ Kingfisher is a blazingly fast secret‑scanning and validation tool built in Ru Kingfisher originated as a fork of [Nosey Parker](https://github.com/praetorian-inc/noseyparker) by Praetorian Security, Inc, and is built atop their incredible work and the work contributed by the Nosey Parker community. Kingfisher extends Nosey Parker by: -1. Validating secrets in real time via cloud-provider APIs -2. Enhancing regex-based detection with source-code parsing for improved accuracy -3. Adding GitLab repository scanning support -4. Adding support for scanning Docker images via `--docker-image` -5. Providing Jira scanning capabilities +1. **Validating secrets** in real time via cloud-provider APIs +2. Enhancing regex-based detection with **source-code parsing** for improved accuracy +3. Adding **GitLab** repository scanning support +4. Adding support for scanning **Docker** images via `--docker-image` +5. Providing **Jira** scanning capabilities 6. Introducing a baseline feature that suppresses known secrets and reports only newly introduced ones -7. Offering native Windows support +7. Offering native **Windows** support **MongoDB Blog**: [Introducing Kingfisher: Real-Time Secret Detection and Validation](https://www.mongodb.com/blog/post/product-release-announcements/introducing-kingfisher-real-time-secret-detection-validation) @@ -387,12 +387,19 @@ _If no token is provided Kingfisher still works for public repositories._ Run the provided helper script to add a hook that scans staged files before each commit: ```bash -./install-precommit-hook.sh +# local (current repo only ─ default) +./install-kingfisher-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. +```bash +# global (every repo on this machine) +./install-kingfisher-hook.sh --global ### Install a Pre-Receive Hook +``` + +Installs a global pre-commit hook at `$HOME/.git/hooks/pre-commit`; for every Git repository you use, it runs `kingfisher scan --no-update-check` on the staged files and cancels the commit if any secrets are detected. To check incoming pushes on a server-side repository, install the pre-receive hook: diff --git a/install-precommit-hook.sh b/install-precommit-hook.sh old mode 100644 new mode 100755 index 6a6283f..7a81ba6 --- a/install-precommit-hook.sh +++ b/install-precommit-hook.sh @@ -1,17 +1,54 @@ #!/usr/bin/env bash +# +# Install a Git pre-commit hook that runs `kingfisher scan`. +# --global → install once for all repos using core.hooksPath +# --force → overwrite an existing pre-commit hook +# set -euo pipefail -HOOK_DIR="$(git rev-parse --git-dir)/hooks" +MODE="local" +FORCE=0 + +while [[ $# -gt 0 ]]; do + case "$1" in + -g|--global) MODE="global" ;; + -f|--force) FORCE=1 ;; + -h|--help) + echo "Usage: $0 [--global] [--force]" && exit 0 + ;; + *) echo "Unknown flag: $1" >&2; exit 1 ;; + esac + shift +done + +if [[ "$MODE" == "local" ]]; then + # ensure we're inside a Git repo + REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) \ + || { echo "Not inside a Git repository" >&2; exit 1; } + + HOOK_DIR="$(git rev-parse --git-dir)/hooks" +else + # global: honour existing core.hooksPath or default to ~/.git-hooks + HOOK_DIR=$(git config --global --get core.hooksPath || echo "$HOME/.git-hooks") + mkdir -p "$HOOK_DIR" + + # if the user hasn’t set core.hooksPath, do it now + if ! git config --global --get core.hooksPath >/dev/null; then + git config --global core.hooksPath "$HOOK_DIR" + echo "Set git config --global core.hooksPath to $HOOK_DIR" + fi +fi + 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 +if [[ -e "$HOOK_PATH" && $FORCE -eq 0 ]]; then + echo "Error: $HOOK_PATH already exists. Use --force to overwrite." >&2 exit 1 fi -cat > "$HOOK_PATH" <<'HOOK' +cat >"$HOOK_PATH" <<'HOOK' #!/usr/bin/env bash -# Pre-commit hook to run Kingfisher scan on staged changes +# Git pre-commit hook to run Kingfisher on staged changes set -euo pipefail if ! command -v kingfisher >/dev/null 2>&1; then @@ -22,11 +59,11 @@ fi git diff --cached --name-only -z | \ xargs -0 --no-run-if-empty kingfisher scan --no-update-check status=$? -if [ "$status" -ne 0 ]; then +if [[ $status -ne 0 ]]; then echo "Kingfisher detected secrets in staged files. Commit aborted." >&2 - exit "$status" + exit $status fi HOOK chmod +x "$HOOK_PATH" -echo "Pre-commit hook installed to $HOOK_PATH" +echo "Pre-commit hook installed to $HOOK_PATH ($MODE mode)" diff --git a/install-prereceive-hook.sh b/install-prereceive-hook.sh old mode 100644 new mode 100755 diff --git a/src/scanner/docker.rs b/src/scanner/docker.rs index c4915c2..a18ca24 100644 --- a/src/scanner/docker.rs +++ b/src/scanner/docker.rs @@ -140,7 +140,7 @@ impl Docker { std::fs::create_dir_all(out_dir)?; let tar_path = out_dir.join("local_image.tar"); let status = Command::new("docker") - .args(["image", "save", image, "-o", tar_path.to_str().unwrap()]) + .args(["image", "save", image, "-o", &tar_path.to_string_lossy()]) .status() .with_context(|| "running docker save")?; if !status.success() { @@ -202,7 +202,7 @@ impl Docker { platform_resolver: Some(Box::new(linux_amd64_resolver)), ..Default::default() }); - let mut client = client; + let client = client; let auth = registry_auth(&reference); let accepted = vec![ oci_client::manifest::IMAGE_LAYER_MEDIA_TYPE,