Skip to content

feat: Trivy Pre-Commit Hook with Security Scanning #1

@cebidhem

Description

@cebidhem

Build Description

Create a Python-based pre-commit hook that integrates Trivy security scanning to detect vulnerabilities in codebases before commits are finalized. The hook will run trivy fs scan on the project directory and block commits if vulnerabilities are found based on configurable severity thresholds.

The implementation must follow modern Python practices, include comprehensive tests using pytest, enforce code quality with pylint and black, manage dependencies with uv (pinned versions), and include GitHub Actions CI/CD workflows for automated testing and linting.

Relevant Files

Use these files to resolve the build:

Existing Files:

  • README.md - Update with comprehensive documentation including installation, usage, configuration options, and examples
  • pyproject.toml - Configure project metadata, dependencies, entry points, tool configurations (pytest, pylint, black), and build system

New Files:

Python Hook Implementation

  • pre_commit_hooks/trivy_scan.py - Main hook script that:
    • Checks for Trivy installation
    • Parses command-line arguments for configuration
    • Executes trivy fs scan with user-specified options
    • Returns appropriate exit codes based on scan results
    • Provides clear error messages and logging

Pre-commit Configuration

  • .pre-commit-hooks.yaml - Pre-commit framework metadata defining:
    • Hook ID, name, and description
    • Entry point to the Python module
    • Language specification (python)
    • File pass mode and default stages

Testing

  • tests/test_trivy_scan.py - Pytest test suite covering:

    • Trivy installation checks
    • Command-line argument parsing
    • Scan execution with various configurations
    • Exit code validation
    • Error handling scenarios
    • Mock subprocess calls for isolated testing
  • tests/conftest.py - Pytest fixtures and test configuration

Linting Configuration

  • .pylintrc - Pylint configuration with exclusions for tests/ and .venv/ folders

CI/CD

  • .github/workflows/ci.yml - GitHub Actions workflow to:
    • Run on push and pull_request events
    • Set up Python environment using uv
    • Install dependencies
    • Run black formatter checks
    • Run pylint for code quality
    • Execute pytest with coverage reporting

Documentation

  • .trivyignore.example - Example file showing how to ignore specific vulnerabilities
  • trivy.yaml.example - Example Trivy configuration file

Step by Step Tasks

IMPORTANT: Execute every step in order, top to bottom.

Step 1: Set up project structure and configuration

  • Create pre_commit_hooks/ directory with __init__.py
  • Update pyproject.toml with:
    • Complete project metadata (name, version, description, authors, license, keywords)
    • Python version requirement (>=3.9 for broader compatibility)
    • Dependencies: pytest, pytest-cov for testing
    • Optional dev dependencies: pylint, black
    • Console scripts entry point: trivy-scan = pre_commit_hooks.trivy_scan:main
    • Tool configurations for pytest (exclude .venv), pylint (exclude tests, .venv), and black (exclude .venv)
    • Build system using hatchling or setuptools

Step 2: Implement the core Trivy scanning hook

  • Create pre_commit_hooks/trivy_scan.py with:
    • check_trivy_installed() function using shutil.which() to verify Trivy availability
    • parse_arguments() function using argparse to handle:
      • --severity (comma-separated list, default: HIGH,CRITICAL)
      • --format (default: table, options: json, sarif, etc.)
      • --exit-code (default: 1 for blocking commits)
      • --config (path to custom trivy.yaml)
      • --skip-db-update flag
      • --scanners (default: vuln, options: vuln,misconfig,secret,license)
      • Additional pass-through arguments for Trivy
    • run_trivy_scan() function that:
      • Constructs trivy command with arguments
      • Executes subprocess.run() with proper error handling
      • Captures stdout/stderr
      • Returns exit code
    • main() function orchestrating the flow:
      • Check Trivy installation (exit with clear message if missing)
      • Parse arguments
      • Execute scan on current directory
      • Print results
      • Exit with appropriate code
    • Comprehensive docstrings and type hints throughout

Step 3: Create pre-commit hook configuration

  • Create .pre-commit-hooks.yaml with:
    • Hook ID: trivy-scan
    • Name: "Trivy Security Scanner"
    • Description explaining the hook's purpose
    • Entry point: trivy-scan
    • Language: python
    • Pass filenames: false (scans entire directory)
    • Stages: [commit]
    • Always run: true (to scan the whole project, not just changed files)

Step 4: Implement comprehensive test suite

  • Create tests/conftest.py with pytest fixtures:
    • Mock subprocess results
    • Temporary directory fixtures
    • Mock Trivy installation states
  • Create tests/test_trivy_scan.py with tests for:
    • test_trivy_not_installed() - Verify error when Trivy is missing
    • test_trivy_installed() - Verify successful detection
    • test_parse_arguments_defaults() - Check default argument values
    • test_parse_arguments_custom() - Validate custom argument parsing
    • test_run_trivy_scan_success() - Mock successful scan with no vulnerabilities
    • test_run_trivy_scan_vulnerabilities_found() - Mock scan finding issues
    • test_run_trivy_scan_with_severity() - Test severity filtering
    • test_run_trivy_scan_with_format() - Test output format options
    • test_run_trivy_scan_with_config_file() - Test custom config usage
    • test_main_integration() - End-to-end integration test
    • Use unittest.mock.patch for subprocess calls
    • Achieve >90% code coverage

Step 5: Set up linting and formatting

  • Create .pylintrc with:
    • ignore-paths: tests/,.venv/
    • Reasonable message controls for pre-commit hooks
    • Max line length: 100
  • Configure black in pyproject.toml:
    • Line length: 100
    • Exclude: .venv/
    • Target Python versions

Step 6: Create GitHub Actions workflow

  • Create .github/workflows/ci.yml with:
    • Name: "CI - Tests and Linting"
    • Trigger on push to all branches and pull requests
    • Job: test-and-lint
    • Steps:
      1. Checkout code
      2. Set up Python 3.11 (using actions/setup-python)
      3. Install uv: pip install uv
      4. Create virtual environment: uv venv
      5. Install dependencies: uv pip install -e ".[dev]"
      6. Run black: uv run black --check .
      7. Run pylint: uv run pylint pre_commit_hooks
      8. Run pytest: uv run pytest tests/ --cov=pre_commit_hooks --cov-report=term-missing
    • Use matrix strategy for multiple Python versions (3.9, 3.10, 3.11, 3.12)

Step 7: Create example configuration files

  • Create .trivyignore.example with:
    • Comments explaining the format
    • Example CVE ignores
    • Instructions for usage
  • Create trivy.yaml.example with:
    • Example severity configuration
    • Scanner configurations
    • Timeout settings
    • Comments explaining each option

Step 8: Update documentation

  • Update README.md with:
    • Project description and badges (CI status)
    • Prerequisites (Python 3.9+, Trivy installation)
    • Installation instructions using pip and pre-commit
    • Usage section with .pre-commit-config.yaml example
    • Configuration options table with all arguments
    • Examples showing different use cases:
      • Default usage
      • Custom severity levels
      • JSON output format
      • Using custom Trivy config
    • Development setup instructions using uv
    • Testing and linting commands
    • Contributing guidelines
    • License information

Step 9: Pin dependencies using uv

  • Run uv pip compile to generate lock file with pinned versions
  • Ensure all dependencies are explicitly versioned in pyproject.toml
  • Prefer standard library where possible (subprocess, argparse, pathlib, shutil)

Step 10: Validate the complete build

  • Execute all validation commands listed below
  • Ensure zero errors and all tests pass
  • Fix any issues discovered during validation

Validation Commands

Execute every command to validate the build is complete with zero regressions.

  • uv venv && source .venv/bin/activate - Create and activate virtual environment
  • uv pip install -e ".[dev]" - Install package in development mode with dev dependencies
  • black --check pre_commit_hooks tests - Verify code formatting
  • pylint pre_commit_hooks - Check code quality (target score >8.0)
  • pytest tests/ --cov=pre_commit_hooks --cov-report=term-missing -v - Run tests with coverage (target >90%)
  • python -m pre_commit_hooks.trivy_scan --help - Verify CLI works
  • pip install -e . - Test package installation
  • trivy-scan --help - Verify console script entry point works
  • .github/workflows/ci.yml syntax check - Validate workflow file

Notes

  • Trivy Installation: The hook will check for Trivy but not install it. Users must install Trivy separately (via brew, apt, or binary download). Include clear installation links in README.
  • Exit Codes: Use exit code 1 when vulnerabilities are found to block commits, 0 for success, 2 for execution errors.
  • Standard Library First: Use subprocess for command execution, argparse for CLI, pathlib for file operations, shutil for binary checks.
  • Flexibility: All Trivy options should be pass-through compatible, allowing users to leverage any Trivy feature.
  • Error Messages: Provide actionable error messages (e.g., "Trivy not found. Install from https://trivy.dev/")
  • Testing Strategy: Use mocks extensively to avoid requiring Trivy during test execution
  • Performance: Consider adding --skip-db-update for faster repeated scans in development
  • Git Compatibility: This follows pre-commit.com framework standards for maximum compatibility
  • Documentation: Follow pre-commit hook documentation standards: https://pre-commit.com/#new-hooks

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions