CommitSieve
Catch what should not be committed, while it is still only staged.
.env files, private keys, 200 MB dumps, node_modules/, .DS_Store, conflict markers, it.only( and debugger; - flagged in VS Code before you press Commit. No hooks, no setup, no network.
The problem
It is 6 pm, the fix works, and you stage everything with one click. The commit goes in with
your .env (database password included), a dump.sql you made while debugging, a
debugger; in the middle of the handler and an it.only( that silently turns off the other
400 tests in CI. The secret is now in history - removing it means rewriting history and
rotating the credential, and anyone who fetched in the meantime already has it.
Pre-commit hooks can catch this, but they have to be installed per repository and per
clone, and most repositories never get them. CommitSieve checks the staged changes (the
git index) of every repository in your workspace, live, with zero configuration, and shows
the result in the status bar the moment you stage something.
Further reading:
What it shows
- Status bar:
CommitSieve: clean, or CommitSieve: 3 issues on a warning background.
Click it for a Quick Pick of every finding; selecting one opens the file (at the line for
content findings). Each entry also has Unstage and Add to .gitignore buttons.
- Problems panel: content findings (conflict markers, focused tests, debugger calls and
so on) appear on the matching line of the working file, with source
CommitSieve.
- One notification when a newly staged change triggers a blocker (error-level) rule,
with a shortcut to review or unstage it. Turn it off with
commitsieve.notifyOnStage.
Only what is staged is checked. A conflict marker that exists only in an unstaged edit is
not reported until you stage it; content rules look only at the lines your staged diff
adds, so old code already in HEAD is never flagged.
Rules
| Code |
Default severity |
What it catches |
| CS001 |
Warning |
A staged file larger than commitsieve.maxFileSizeKB (default 1024 KB). |
| CS002 |
Warning |
A newly added binary file (executables, archives, databases, .bin dumps). Images, fonts, PDFs and audio are not reported. |
| CS003 |
Error |
.env and .env.* files. .env.example, .env.sample and .env.template are allowed. |
| CS004 |
Error |
Key material files: *.pem, *.key, *.p12, *.pfx, *.jks, *.keystore, id_rsa, id_dsa, id_ecdsa, id_ed25519 (the .pub halves are fine). |
| CS005 |
Error |
credentials.json, client_secret*.json, .git-credentials. |
| CS006 |
Error |
An auth token added to .npmrc / .yarnrc (_authToken=, _auth=, _password=, npmAuthToken:) or a password added to .pypirc. ${NPM_TOKEN}-style references are fine. |
| CS007 |
Warning |
Newly added generated or junk paths: node_modules/, dist/, build/, coverage/, __pycache__/, .terraform/, .idea/, .DS_Store, Thumbs.db, desktop.ini, *.pyc, *.log. A whole directory is reported once (with a file count). A directory that already exists in HEAD is never reported, so repositories that commit dist/ on purpose are left alone. |
| CS008 |
Error |
A newly added *.tfstate / *.tfstate.backup - Terraform state often holds secrets in plain text. |
| CS010 |
Error |
A merge conflict marker (<<<<<<<, >>>>>>>, \|\|\|\|\|\|\|) on an added line. A lone ======= is not reported (it is also a Markdown heading underline). |
| CS011 |
Error |
A private key block (-----BEGIN ... PRIVATE KEY-----, including OpenSSH, RSA, EC and PGP) on an added line, in any file. |
| CS012 |
Warning |
A focused test in JavaScript/TypeScript: it.only(, describe.only(, test.only(, test.describe.only(, fit(, fdescribe(. model.fit( and commented-out lines are ignored. |
| CS013 |
Warning |
A leftover debugger call: debugger; (JS/TS), breakpoint() / pdb.set_trace() (Python), binding.pry / byebug (Ruby), dd( (PHP). |
| CS014 |
Information |
A JS/TS line that does nothing but console.log(...) / console.debug(...). |
Blockers are the error-level rules. Any rule can be switched off with
commitsieve.disabledRules or re-leveled with commitsieve.ruleSeverity.
Settings
| Setting |
Default |
Description |
commitsieve.enabled |
true |
Turn CommitSieve on or off. |
commitsieve.maxFileSizeKB |
1024 |
Size limit for CS001, in KB. |
commitsieve.disabledRules |
[] |
Rule codes to turn off, for example ["CS014"]. |
commitsieve.ruleSeverity |
{} |
Per-rule severity: error, warning, information, hint or off, for example {"CS007": "error"}. |
commitsieve.ignorePaths |
[] |
Repository-relative globs that are never checked, for example ["test/fixtures/**", "*.snap"]. A pattern without a slash matches the file name anywhere. |
commitsieve.notifyOnStage |
true |
Show one warning notification when a newly staged change triggers a blocker rule. |
Commands
- CommitSieve: Show staged issues - the Quick Pick of findings (also the status bar click).
- CommitSieve: Unstage file - removes the file (or the whole flagged directory) from the
index with
git restore --staged. Your working copy is not touched. On a repository with
no commits yet it uses git rm --cached instead.
- CommitSieve: Add to .gitignore - appends a pattern to the repository root
.gitignore
(the generic pattern for junk such as node_modules/ or .DS_Store, otherwise the
anchored path). The file is still staged afterwards; the confirmation offers to unstage it.
- CommitSieve: Rescan staged changes - scan again now.
Privacy and safety
- No network access and no telemetry. Everything is computed locally from your own git.
- Workspace Trust. CommitSieve runs
git inside your repositories, so it does nothing
in an untrusted workspace (the built-in Git extension it builds on is also disabled there)
and starts once you trust the workspace.
- Hardened git calls.
git is started without a shell and with an argument list; global
and system git config are ignored; core.fsmonitor is forced off so a repository cannot
make it run a program; pagers, external diff tools and textconv filters are disabled; path
arguments always follow -- and are taken literally (a file named -rf, --output=x or
* is only ever that file). Output size and run time are capped.
- Stays inside your workspace. Only repositories whose real root is inside an open
workspace folder are checked. Every path taken from git output is resolved and must stay
inside the repository root before it is opened or shown in the Problems panel, so a staged
symlink pointing elsewhere is never followed.
.gitignore edits go through a VS Code
workspace edit and are refused if the root .gitignore is a symlink.
- File contents are read from the index (
git diff --cached), never uploaded or stored.
Limitations
- VS Code has no API to intercept a commit, so CommitSieve cannot block one. It warns early
(status bar, notification, Problems panel); pressing Commit is still up to you.
- Line numbers refer to the staged version of the file. If you kept editing after staging,
the Problems marker may sit a few lines off until you stage again.
- Detection is pattern based. It is a safety net for the common accidents, not a full secret
scanner: an API key pasted into ordinary source code is not detected unless it is a
private key block or sits in one of the files above.
- Files over 4 MB are checked by name and size only, not by content. A
.gitattributes
that marks text files as binary does not hide them - CommitSieve checks the real bytes.
- Only repositories the built-in Git extension has opened are checked.
License
MIT - included with the extension.
| |