This repository contains custom pre-commit hooks that prevent accidental commits of sensitive, large or temporary files (environment files, database dumps, logs, cache files), debug statements and insecure code.
The following hooks are available:
forbid-env-files: Forbids environment files.forbid-dump-files: Forbids database dump files.forbid-log-files: Forbids log files.forbid-cache-files: Forbids cache files.block-debug-statements: Blocks debug statements in PHP and JavaScript/TypeScript files.block-insecure-code: Blocksevaland shell execution functions in PHP and JavaScript/TypeScript files.
Deprecated: block-env-files, block-dump-files, block-log-files and block-cache-files still work but will be removed in 3.0.0. See Migrating from the block-*-files hooks.
Requires pre-commit 3.2.0 or later and Python 3.9 or later. To use these hooks in your project, add the following to your .pre-commit-config.yaml file:
- repo: https://github.com/ctrlwebinc/pre-commit-hooks rev: 2.0.0 # Replace with the desired tag or commit hash hooks: - id: forbid-env-files - id: forbid-dump-files - id: forbid-log-files - id: forbid-cache-files - id: block-debug-statements - id: block-insecure-code
Note: starting with
1.2.1, release tags have novprefix (1.2.1). Older releases keep their original tags (v1.0.0tov1.2.0).
The forbid-*-files hooks fail when a staged file matches. They match file names in any directory, case-insensitively.
- Forbids: files whose name starts with
.envorenv.(e.g.,.env,.env.local,config/.env.production,app/etc/env.php). - Allowed by default: templates meant to be committed (
.env.example,.env.sample,.env.dist,.env.template) and TypeScript'senv.d.ts.
- Forbids:
.sql,.dump,.sqlite,.sqlite3and.dbfiles, and.sql/.dumpfiles compressed as.gz,.zipor.tar.gz.
- Forbids:
.logand.errfiles, and files namederror_log.
- Forbids:
.cachefiles.
Use pre-commit's standard files and exclude options. They are Python regular expressions matched against the file path; start them with (?i) to ignore case.
excludeallows files. Forforbid-env-files, yourexcludereplaces the default one, so keep the templates in it.filesreplaces the list of forbidden files. Copy the default pattern from .pre-commit-hooks.yaml and extend it.
- repo: https://github.com/ctrlwebinc/pre-commit-hooks rev: 2.0.0 hooks: # Also allow .env.testing - id: forbid-env-files exclude: '(?i)(^|/)(\.env\.(example|sample|dist|template|testing)|env\.d\.ts)$' # Allow the schema, also forbid .bak files - id: forbid-dump-files files: '(?i)\.(sql|dump)(\.gz|\.zip|\.tar\.gz)?$|\.(sqlite3?|db|bak)$' exclude: '^database/schema\.sql$'
The content hooks check the code that will be committed. Only actual calls in code are matched:
- Calls in comments (
//,#,/* */, docblocks) and strings (including heredocs and template literals) are ignored. - Blade templates and inline HTML are checked too (
{{ dd($user) }},@dd($user)).
- Default Behavior: Blocks commits that contain debug statements:
- PHP (
.php):var_dump(),print_r(),dd() - JavaScript/TypeScript (
.js,.jsx,.mjs,.cjs,.ts,.tsx):console.log()
- PHP (
- Method calls are matched too (
$collection->dd()), but not similar names ($collection->add()). - Arguments:
--file-types: A pipe-separated list of languages to check:php,js, orphp|js(default).--extra-patterns: A pipe-separated list of additional function names to block (e.g.,die|exit).--exclude-patterns: A pipe-separated list of function names to stop blocking (e.g.,print_r).--check-mode:fullto check the whole committed file (default),diffto check only the added or modified lines.diffchecks the staged changes, so it is meant for local commits. Withpre-commit run --all-filesnothing is staged, so nothing is checked.- In CI, use
pre-commit run --from-ref <base> --to-ref <head>:diffmode then checks the lines changed between those two refs.
- Default Behavior: Blocks calls to functions that run code or shell commands:
- PHP:
eval,exec,shell_exec,system,passthru,popen,proc_open,pcntl_exec,create_function - JavaScript/TypeScript:
eval,Function(new Function(...))
- PHP:
- Only global function calls are matched: method and static calls (
$pdo->exec(),Process::system(),regex.exec()) and function definitions are not.window.eval()andglobalThis.eval()are. - To check other file types, override
types_orin your.pre-commit-config.yaml(e.g.,types_or: [php, javascript, python]). Other languages are checked forevalonly. - Arguments:
--extra-functions: A pipe-separated list of additional functions to block (e.g.,unserialize|assert).--exclude-functions: A pipe-separated list of functions to stop blocking (e.g.,exec).
This hook is a safety net against obvious mistakes, not a security audit. For deeper analysis, use a dedicated tool such as Semgrep.
These hooks don't check file contents for secrets or file sizes. Pair them with:
# Secrets in code (API keys, tokens, passwords) - repo: https://github.com/gitleaks/gitleaks rev: v8.30.1 hooks: - id: gitleaks # Large files whatever their name (default limit: 500 KB), and private keys - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: check-added-large-files - id: detect-private-key
block-env-files, block-dump-files, block-log-files and block-cache-files are deprecated and will be removed in 3.0.0. Until then, their name shows (deprecated, use forbid-…) on every run.
Replace each block-<type>-files with forbid-<type>-files. Without args, the new hooks forbid exactly the same files. With args, convert them to files and exclude, as in Customizing the file hooks:
| 1.x argument | 2.0 equivalent |
|---|---|
--exclude-names, --exclude-extensions, --exclude-prefixes |
Add the files to exclude |
--extra-names, --extra-extensions, --extra-prefixes |
Add the files to files, starting from the default pattern |
For example:
# 1.x - id: block-env-files args: [--exclude-names=.env.testing] - id: block-dump-files args: [--exclude-extensions=.sql] # 2.0 - id: forbid-env-files exclude: '(?i)(^|/)(\.env\.(example|sample|dist|template|testing)|env\.d\.ts)$' - id: forbid-dump-files exclude: '(?i)\.sql$'
The deprecated hooks still accept these arguments:
--extra-extensions/--exclude-extensions: Pipe-separated file extensions to block / never block (e.g.,.bak|.tar|.gz).--extra-names/--exclude-names: Pipe-separated full file names to block / never block (e.g.,.env.testing).--extra-prefixes/--exclude-prefixes: Pipe-separated file name prefixes to block / never block (e.g.,test_|dev_).
pip install pytest pyyaml pre-commit pre-commit install # Lint with ruff and run this repository's own hooks on each commit pytest # Run the tests
The tests create throwaway git repositories and run each hook the way pre-commit does. CI runs the linting and the tests on Ubuntu and Windows, with the oldest and newest supported Python versions.
Shared code lives in ctrlweb_pre_commit_hooks/_common.py (git access, argument parsing, reporting) and ctrlweb_pre_commit_hooks/_masking.py (the scanner that blanks out comments and strings before patterns are matched).
Changes are listed in CHANGELOG.md.