#git #security-scanning #security #scanning #hook

bin+lib guardy

Fast, secure git hooks in Rust with secret scanning and protected file synchronization

5 releases

Uses new Rust 2024

new 0.2.3 Nov 8, 2025
0.2.2 Nov 6, 2025
0.2.1 Nov 6, 2025
0.2.0 Nov 4, 2025
0.1.0 Aug 22, 2025

#305 in Development tools

MIT license

430KB
9K SLoC

Guardy

Crates.io Documentation License: MIT

Fast, secure git hooks in Rust with secret scanning and protected file synchronization.

Features

  • 🚀 Fast Security Scanning: Multi-threaded secret detection with entropy analysis
  • 🔄 Protected File Synchronization: Keep configuration files in sync across repositories
  • 🪝 Git Hook Support: Pre-commit, pre-push, and other git hooks
  • ⚙️ Flexible Configuration: YAML, TOML, and JSON configuration support
  • 📊 Multiple Output Formats: JSON, HTML, and plain text reporting
  • 🔍 Comprehensive Scanning: Detect secrets, credentials, and sensitive data

Installation

From crates.io

cargo install guardy

From source

git clone https://gitlab.com/deepbrain.space/guardy
cd guardy
cargo build --release

Quick Start

1. Initialize in your repository

cd your-repo/
guardy hooks install

This installs git hooks and creates a default configuration.

2. Configure hooks

Guardy supports both custom commands and built-in actions in hooks:

# guardy.yaml
hooks:
  pre-commit:
    enabled: true
    parallel: false # Run commands in parallel (default: false)
    # Built-in actions
    builtin: ["scan_secrets"]
    # Custom commands
    custom:
      - command: "cargo fmt --check"
        description: "Check formatting"
        fail_on_error: true
        glob: ["*.rs"] # Only run on Rust files (optional)

      - command: "eslint {files} --fix"
        description: "Fix ESLint issues"
        all_files: true # Run on all files matching glob, not just staged
        glob: ["*.js", "*.jsx", "*.ts", "*.tsx"]
        stage_fixed: true # Auto-stage fixed files

  commit-msg:
    enabled: true
    builtin: ["conventional_commits"] # Validates conventional commits format

  pre-push:
    enabled: true
    builtin: ["ensure_clean"] # Ensure no uncommitted changes before push
    parallel: true # Run all commands in parallel for speed
    custom:
      - command: "cargo check"
        description: "Run type check"
        fail_on_error: true
      - command: "guardy sync update --force --config ./guardy.yaml"
        description: "Sync protected files before push"
        fail_on_error: true

3. Configure repository sync (optional)

Keep files synchronized from upstream repositories:

# guardy.yaml
sync:
  repos:
    - name: "shared-configs"
      repo: "https://gitlab.com/your-org/shared-configs"
      version: "v1.0.0" # Can be tag, branch, or commit
      source_path: ".gitlab"
      dest_path: "./.gitlab"
      include: ["**/*"]
      exclude: ["*.md"]

4. Configure scanning (optional)

# guardy.yaml
scanner:
  file_extensions:
    - "*.rs"
    - "*.js"
    - "*.py"
  ignore_patterns:
    - "target/"
    - "node_modules/"
  entropy_threshold: 3.0

hooks:
  pre_commit:
    enabled: true
    commands:
      - scan

3. Use the core features

# Scan files for secrets
guardy scan src/

# Check installation status
guardy status

# Sync configuration files
guardy sync

Commands

Core Commands

  • guardy hooks install - Install git hooks in the current repository
  • guardy scan <PATH> - Scan files/directories for secrets and sensitive data
  • guardy status - Show installation and configuration status
  • guardy config - Manage configuration settings
  • guardy hooks uninstall - Remove all installed git hooks

File Synchronization

  • guardy sync - Interactively update files from remote repositories
  • guardy sync diff - Show differences without making changes
  • guardy sync --force - Update all changes without prompting
  • guardy sync status - Show sync configuration and status

Advanced

  • guardy hooks run <HOOK> - Manually run a specific git hook for testing

Configuration

Guardy supports multiple configuration formats (YAML, TOML, JSON) with automatic discovery and merging.

Configuration File Discovery

Guardy automatically searches for configuration files in the following locations (highest to lowest priority):

  1. Current directory: ./.guardy.{json,yaml,yml,toml} or ./guardy.{json,yaml,yml,toml}
  2. Parent directories: Searches up to git root or filesystem root
  3. User config: ~/.config/.guardy.{json,yaml,yml,toml} or ~/.config/guardy.{json,yaml,yml,toml}
  4. System config: /etc/.guardy.{json,yaml,yml,toml} or /etc/guardy.{json,yaml,yml,toml}

Priority Rules:

  • Dot-prefixed files (.guardy.*) take priority over non-prefixed files (guardy.*)
  • JSON format takes priority over YAML, which takes priority over TOML
  • Closer directories (current dir) override farther ones (system config)

Automatic Merging: Guardy automatically merges all discovered config files with higher priority configs overriding lower priority ones. This allows you to:

  • Set organization-wide defaults in /etc/.guardy.yaml
  • Override with personal preferences in ~/.config/.guardy.yaml
  • Customize per-project in ./.guardy.yaml

Example Merge Behavior:

If you have:

# /etc/guardy.yaml (lowest priority)
hooks:
  pre-commit:
    parallel: false
    commands:
      format-rust:
        run: cargo fmt
# ~/.config/.guardy.yaml (medium priority)
hooks:
  pre-commit:
    parallel: true # Overrides system config
# ./.guardy.yaml (highest priority)
hooks:
  pre-commit:
    commands:
      format-rust:
        run: mise exec -- moon run :format # Overrides system config
      clippy-check: # Adds new command
        run: cargo clippy

The final merged configuration will be:

hooks:
  pre-commit:
    parallel: true # From user config
    commands:
      format-rust:
        run: mise exec -- moon run :format # From project config
      clippy-check: # From project config
        run: cargo clippy

Basic Configuration (guardy.yaml)

# Scanner settings
scanner:
  file_extensions:
    - "*.rs"
    - "*.js"
    - "*.py"
    - "*.go"
  ignore_patterns:
    - "target/"
    - "node_modules/"
    - "*.log"
  max_file_size: 1048576 # 1MB
  entropy_threshold: 3.5

# Git hooks configuration
hooks:
  pre-commit:
    enabled: true
    builtin: ["scan_secrets"] # Built-in secret scanning
    custom: [] # Add custom commands here
  pre-push:
    enabled: true
    custom:
      - command: "guardy sync update --force --config ./guardy.yaml"
        description: "Sync protected files"
        fail_on_error: true

# File synchronization
sync:
  repos:
    - name: "shared-configs"
      repo: "https://gitlab.com/yourorg/shared-configs"
      version: "main"
      source_path: "."
      dest_path: "."
      include: ["*.yml", "*.json", ".gitignore"]
      exclude: [".git", "target/"]

Library Usage

Guardy can be used as a library for building custom security tools:

use guardy::scanner::ScannerConfig;
use guardy::config::GuardyConfig;

// Load configuration
let config = GuardyConfig::load("guardy.yaml", None, 0)?;
let scanner_config = ScannerConfig::from_config(&config)?;

// Scan for secrets
let results = scanner_config.scan_path("src/")?;

// Process findings
for finding in results.findings {
    println!(
        "Secret found in {}: {} (confidence: {:.2})",
        finding.file_path,
        finding.secret_type,
        finding.confidence
    );
}

Git Hooks Integration

Guardy provides flexible git hook management with both built-in actions and custom commands:

Built-in Actions

  • scan_secrets - Scan staged files for secrets and credentials (pre-commit hook)
  • conventional_commits - Validate commit messages using conventional commits format (commit-msg hook)
  • ensure_clean - Ensure repository has no uncommitted changes before push (pre-push hook)

Hook Features

Parallel Execution

Run commands in parallel for faster execution (enabled by default):

hooks:
  pre-push:
    parallel: true # Default: true - commands run simultaneously with optimal concurrency
    custom:
      - command: "cargo check"
      - command: "cargo clippy"
      - command: "cargo fmt --check"

Guardy automatically profiles your system and workload to determine optimal parallelism:

  • Small workloads (≤3 commands): Sequential execution
  • Medium workloads (4-5 commands): Conservative parallelism
  • Large workloads (6+ commands): Full parallelism (capped at 8 concurrent commands)
  • System-aware: Respects available CPU cores and limits concurrency appropriately

Template Variables (Lefthook-Compatible)

Guardy supports template variables in commands and environment variables, fully compatible with Lefthook syntax:

File Placeholders
  • {staged_files} - Staged files filtered by glob patterns (lefthook-compatible!)

    commands:
      lint:
        run: eslint {staged_files}
        glob: "*.js" # Only staged .js files
    
  • {files} - Custom files from files: command, filtered by glob patterns

    commands:
      lint:
        run: eslint {files}
        files: "git diff --name-only main...HEAD" # Files changed since main
        glob: "*.js" # Only .js files from the diff
    

    Note: {files} requires a files: command. Without it, the command is skipped.

  • {all_files} - All tracked files in the repository (no filtering)

    commands:
      check-all:
        run: prettier --check {all_files}
    
  • {push_files} - Files being pushed (pre-push hook only)

    pre-push:
      commands:
        test-changed:
          run: npm test {push_files}
    
Command Placeholders
  • {cmd} - The command itself (useful in env vars)
  • {guardy_job_name} - Current command/job name
Hook Argument Placeholders
  • {0} - All hook arguments as a single space-joined string
  • {1}, {2}, {3} - Individual hook arguments (1-indexed)
commit-msg:
  commands:
    validate:
      run: ./scripts/validate-msg.sh {1} # First argument is commit message file

Glob Pattern Filtering

Target specific file types with glob patterns:

custom:
  - command: "prettier --write {staged_files}"
    glob: ["*.js", "*.css", "*.html"]
  - command: "black {staged_files}"
    glob: ["*.py"]

All Files Mode

Process all matching files, not just staged ones:

custom:
  - command: "eslint {files} --fix"
    all_files: true # Process all JS files in repo
    glob: ["**/*.js"]
    stage_fixed: true # Auto-stage corrected files

Conventional Commits Validation

Ensures commit messages follow the conventional commits format using the git-conventional library:

hooks:
  commit-msg:
    enabled: true
    builtin: ["conventional_commits"]

Supported formats:

  • feat(scope): add new feature
  • fix: resolve bug in authentication
  • docs: update README
  • chore(deps): update dependencies

Features:

  • Full conventional commits specification support
  • Helpful error messages with examples
  • Optional scope validation warnings
  • Automatic comment filtering from commit messages

Clean Repository Validation

Ensures the repository has no uncommitted changes before pushing, preventing accidental pushes of work-in-progress:

hooks:
  pre-push:
    enabled: true
    builtin: ["ensure_clean"]

What it checks:

  • Modified files in the worktree
  • Deleted files not staged
  • Untracked files
  • Any uncommitted changes

Features:

  • Uses pure Rust gix library for maximum performance
  • Shows helpful error messages listing uncommitted files
  • Only runs in pre-push hook (shows warning if used elsewhere)
  • Fast microsecond-level status checks

Note: This builtin is designed specifically for the pre-push hook. If you need to allow uncommitted changes in certain workflows, simply remove it from your configuration or use git push --no-verify to skip hooks.

Installing Specific Hooks

# Install all hooks
guardy install

# Install specific hooks
guardy install --hooks pre-commit,pre-push

# Force overwrite existing hooks
guardy install --force

File Synchronization from other Repositories

Keep configuration files synchronized across multiple repositories:

# Configure sync in guardy.yaml
guardy sync status          # Show sync configuration

guardy sync diff            # Preview changes without applying
guardy sync                 # Interactive update with diffs
guardy sync --force         # Apply all changes automatically

# Bootstrap from a repository
guardy sync --repo=https://gitlab.com/org/configs --version=main

Automating Sync with Hooks

Integrate sync into your git workflow to ensure files stay synchronized:

# guardy.yaml
sync:
  repos:
    - name: "shared-configs"
      repo: "https://gitlab.com/org/shared-configs"
      version: "v1.0.0"
      source_path: ".gitlab"
      dest_path: "./.gitlab"
      include: ["**/*"]

hooks:
  pre-push:
    enabled: true
    custom:
      - command: "guardy sync update --force --config ./guardy.yaml"
        description: "Ensure configs are synchronized before push"
        fail_on_error: true

This ensures synced files are always synchronized before pushing changes.

Features:

  • Diff visualization with syntax highlighting
  • Interactive updates with per-file control
  • Selective sync with include/exclude patterns
  • Version pinning to specific tags or commits
  • Multi-repository configuration support
  • Automatic restoration of modified protected files

Examples

Scanning specific file types

# Scan only Rust files
guardy scan --include="*.rs" src/

# Scan excluding test files
guardy scan --exclude="*test*" .

# Output as JSON
guardy scan --format=json src/ > scan-results.json

Custom git hooks

# guardy.yaml
hooks:
  pre-commit:
    enabled: true
    builtin: ["scan_secrets"]
    custom:
      - command: "cargo fmt -- --check"
        description: "Check formatting"
        fail_on_error: true
      - command: "cargo clippy -- -D warnings"
        description: "Run clippy"
        fail_on_error: true

File sync with filters

sync:
  repos:
    - name: "eslint-config"
      repo: "https://gitlab.com/company/eslint-configs"
      version: "v2.1.0"
      source_path: "configs"
      dest_path: "."
      include: [".eslintrc*", "prettier.config.js"]
      exclude: ["*.local.*"]

Performance

  • Multi-threaded: Utilizes all CPU cores for scanning
  • Memory efficient: Processes large repositories without high memory usage
  • Fast I/O: Optimized file reading with memory-mapped files
  • Smart filtering: Skips binary files and respects .gitignore patterns
  • OS Cache Optimization: Leverages filesystem caching for dramatic performance improvements

Intelligent Caching Performance

Guardy efficiently utilizes OS-level filesystem caching for exceptional performance:

First Scan (Cold Cache):

  • Initial scan reads files from disk storage
  • Typical performance: ~1,900 files/second
  • OS populates filesystem cache with file data

Subsequent Scans (Warm Cache):

  • Files served from RAM instead of disk
  • Up to 2.7x faster performance: ~5,200 files/second
  • Perfect for CI/CD and iterative development workflows

Real-World Example:

# First run (cold cache)
$ guardy scan ~/code/large-project --stats
⚡ Scan completed in 91.19s (172,832 files scanned)

# Second run (warm cache)
$ guardy scan ~/code/large-project --stats
⚡ Scan completed in 33.37s (172,832 files scanned)
# 🚀 63% faster!

Performance Benchmarks

Typical performance on a modern machine:

  • Cold cache: ~1,900 files/second for secret scanning
  • Warm cache: ~5,200 files/second (2.7x improvement)
  • Memory usage: <200MB for repositories with 100k+ files
  • Startup time: <100ms for git hooks

License

MIT License - see LICENSE for details.

Contributing

Contributions welcome! Please see CONTRIBUTING.md for guidelines.

Support

Dependencies

~42–60MB
~1M SLoC