GForge (Python)
Governance Forge — an engineering governance platform that helps teams forge consistent development standards through Git automation, quality gates, and developer tooling.
GForge brings engineering standards to the one place every change passes through: the commit. Its first governance capability is a secret firewall — a managed global Git hook that stops credentials from ever entering your history, on every repository, across your whole team.
This is the Python port of GForge. The idea, the product design, and the detection engine are the work of Gaurang Joshi, Shrey Tandel, and Dwij Acharya, who built the original together. See Credits and attribution.
Why GForge
A single leaked API key, database password, or private key in a commit can mean a production incident, a costly rotation, and a permanent entry in Git history. Per-project hooks drift, get skipped, or are never installed. GForge makes the guardrail global, automatic, and uniform for every developer and every repo — so the standard is enforced by default, not by discipline.
Features
- Install once, protected everywhere. Configures Git's global
core.hooksPath, so the firewall applies to every repository on the machine. - Deep, layered detection
.envcross-reference — blocks any staged file that hardcodes a real value from your git-ignored.envfiles (the classic "pasted a token out of.env").- Provider rules — 25+ credential shapes: AWS, GitHub/GitLab, Google, Slack, Stripe, Twilio, SendGrid, npm, PyPI, OpenAI/Anthropic, PEM private keys, JWTs, database URLs, and more.
- Generic secrets — any credential keyword assigned to a hardcoded value
(
DB_PASSWORD=…,password: "…",api_key = "…"). - Entropy — high-entropy strings that carry no recognizable name.
- Low noise by design. References like
os.environ["DB_PASSWORD"], f-string interpolation, placeholders, and env templates (.env.example) are not flagged, so correct code keeps flowing. - Never leaks the secret. Reports only file paths, line numbers, and rule names — the matched value is never printed.
- Encoding-aware. Handles UTF‑8, UTF‑16, and BOM-prefixed files (e.g. those written by PowerShell) so nothing slips through as "binary".
- gitleaks turbo (optional). If gitleaks
is on
PATH, GForge runs it too and merges the findings. - Cross-platform, zero runtime dependencies. Standard library only.
Requirements
- Python 3.9 or newer
- Git
Installation
pipx install gforge-python # or: pip install --user gforge-python
gforge install
The PyPI project is gforge-python; the command it installs is gforge.
gforge install is the one-time setup step: it writes the managed hook and points
your global core.hooksPath at it. From the next commit onward, changes are
scanned for secrets on every repository. Confirm anytime with:
gforge verify
Why two steps, unlike the npm original? Python wheels have no
postinstallhook — pip deliberately runs no package code at install time. Rather than smuggle setup into an import side effect, GForge asks for one explicit command. It is also the honest boundary: reconfiguring your global Git config is a decision, not a side effect ofpip install.
Quick start
# See the current status of your workstation
gforge verify
# Try it — a hardcoded secret is blocked before it can be committed
echo 'DB_PASSWORD=S3cr3t-Value-123' > config.txt
git add config.txt
git commit -m "add config"
# → GForge blocks the commit and names config.txt (the value is never printed)
Commands
gforge <command> [--force]
| Command | Description |
|---|---|
gforge install |
Upgrade to the latest version (if any) and install the global hooks. |
gforge verify |
Read-only health check of the environment and installed hooks. |
gforge update |
Upgrade to the latest version (if any) and refresh the hooks. |
gforge uninstall |
Remove GForge-owned hooks and restore your previous Git config. |
gforge version |
Print the installed version. |
gforge help |
Print usage. |
--force (with install/update) reinstalls the latest release even if you are
already on it. GForge never downgrades below your installed version.
How detection works
The pre-commit hook scans only the files staged for the current commit — not the
whole repository — and blocks the commit if any appear to contain a secret. It
reports file paths, line numbers, and rule names, and never prints the matched
value. Detection runs several layers in order:
.envcross-reference — the highest-precision signal: values read (in memory only) from your git-ignored.envfiles, matched verbatim in staged code.- Provider rules — fixed credential shapes for the major cloud and SaaS providers.
- Generic secrets — credential keywords assigned to a hardcoded value; smart
enough to ignore
os.environ[...], function calls, f-strings and${VAR}interpolation, and obvious placeholders. - Entropy — unnamed high-entropy strings, tuned to skip Git SHAs, UUIDs, lockfiles, and file paths (a path is scored per segment, so a long import path is not mistaken for a base64 blob).
- Secret files —
.env(and.env.*except templates),id_rsa,*.p12/*.pfx, keystores,.git-credentials,.netrc, and more.
Detection is best-effort and complements — not replaces — good secret hygiene.
Managing false positives
Maximum coverage occasionally flags something safe. Three escape hatches:
-
Inline: add a
gforge:allow(orgitleaks:allow) comment on the line. -
Per-repo: add a path or pattern to a
.gforgeignorefile at the repo root (a.gitleaksignoreis also honored):# .gforgeignore tests/fixtures/ ^docs/sample-config\.md$
-
One-off: bypass a single commit with
git commit --no-verify.
Staying up to date
gforge update upgrades the package to the latest published release and refreshes
the hook. GForge also keeps itself current on its own: at most once a day it checks
PyPI in a detached background process (it never delays or blocks a commit),
installs the update, and prints a one-line notice on commit:
gforge: v1.2.0 is available (you have v1.1.0). Run: gforge update
The background upgrade only runs when the hook's interpreter is the one GForge is installed into, so it can never install into the wrong environment.
Configuration
Behavior is controlled entirely through environment variables — there is no config file to manage.
| Variable | Effect |
|---|---|
GFORGE_AUTO_UPDATE=0 |
Notify only; do not auto-install new versions (default: auto-install on). |
GFORGE_NO_SELF_UPDATE=1 |
Skip the pip self-upgrade in install/update (CI / air-gapped). |
GFORGE_PYTHON=/path/to/python |
Pin the Python runtime the hook uses. |
NO_COLOR=1 |
Disable ANSI colour in all output. |
If a repository or the system already defines its own core.hooksPath (e.g. Husky,
lefthook, or pre-commit), that value shadows GForge in the affected repository;
gforge verify warns when it detects this. Your previous global value is recorded
at install time and restored by gforge uninstall.
Cross-platform support
| Platform | Shells |
|---|---|
| macOS | Bash, Zsh |
| Linux | Bash |
| Windows | Git Bash, WSL, PowerShell (via Git for Windows) |
The scanner runs on Python; the hook is a small POSIX shell shim that locates a Python interpreter robustly (including on Git for Windows) and fails closed if it cannot — a commit is never allowed through unscanned.
What GForge changes on your machine
GForge is transparent and fully reversible. It touches only your global Git config and a single directory in your home folder:
~/.gforge/hooks/— the managed hook and scanner (core.hooksPathpoints here).~/.gforge/state.json— records your previouscore.hooksPathsouninstallcan restore it.~/.gforge/update-check.json— the once-a-day version-check cache.
gforge uninstall removes GForge-owned files and restores your prior configuration.
Programmatic use
GForge is primarily a CLI, but both the command runner and the detection engine are importable:
import sys
from gforge import run_cli
result = run_cli(["verify"], sys.stdout, sys.stderr)
sys.exit(result.exit_code)
from gforge.scanner import scan_text
findings = scan_text("config.py", 'API_KEY = "s3cr3tValue123"')
for finding in findings:
print(finding.file, finding.line, finding.rule_id) # the value is never exposed
Development
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytest # run the test suite
ruff check . && ruff format --check .
mypy # strict type checking
python -m build # build the sdist and wheel
Differences from the Node original
The behaviour of the detection engine is intentionally identical; the differences are the ones Python's packaging model forces:
Node (npm i -g gforge) |
Python (this port) | |
|---|---|---|
| Setup | Automatic via postinstall |
Explicit gforge install |
| Self-upgrade | npm install -g gforge@latest |
pip install --upgrade gforge-python |
| Version source | package.json |
Installed distribution metadata |
| Package name | gforge |
gforge-python on PyPI, gforge to import and run |
| Hook engine | ~/.gforge/hooks/gforge-scan.mjs |
~/.gforge/hooks/gforge_scan.py |
| Interpreter preference | node from PATH, then baked path |
Baked path first, then PATH |
The interpreter preference is inverted deliberately: any node runs the scanner
equally well, but on Python the interpreter recorded at install time is the one
GForge lives in, which keeps self-upgrade targeting the right environment.
Roadmap
The secret firewall is the first governance capability. Planned directions:
- Additional commit-time quality gates (commit message and branch conventions, large-file and merge-conflict guards).
- Shareable, versioned org policy packs.
- Reporting and audit for governance coverage across a team.
Credits and attribution
GForge was created by Gaurang Joshi, Shrey Tandel, and Dwij Acharya, who contributed to it equally. The original Node.js implementation lives at github.com/psspl-gaurang/gforge and is the source of everything that makes this tool what it is: the idea, the product design, the command surface, the layered detection strategy, and the carefully tuned false-positive heuristics that the test suite here still encodes.
| Gaurang Joshi | Original author — @psspl-gaurang |
| Shrey Tandel | Original author |
| Dwij Acharya | Original author |
This package is a Python translation of their work, published under the same
Apache-2.0 licence, with the original NOTICE reproduced verbatim. It is not a
fork that claims originality — if GForge is useful to you, the credit belongs
upstream.
Thanks to everyone who has contributed to GForge:
Contributing
Issues and pull requests are welcome. Please run the checks below before
submitting, keep changes focused, and preserve the Apache-2.0 licence header and
the NOTICE file.
pytest
ruff check .
mypy
Changes to the detection engine should stay behaviour-compatible with the upstream Node implementation wherever practical, so a fix in one can be carried to the other.
Security
To report a vulnerability, follow the process in SECURITY.md. Do not open a public issue for security reports, and never include real secrets in a report.
Licence
Licensed under the Apache License 2.0, the same licence as the upstream
project. Please preserve the NOTICE file when redistributing.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gforge_python-0.1.0.tar.gz.
File metadata
- Download URL: gforge_python-0.1.0.tar.gz
- Upload date:
- Size: 60.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ed20507ba3f5127026be046a85916725c78ce2fb546080d3b6e5d4418d36611
|
|
| MD5 |
677e782c97ba5a35ff4e782f5d6c7633
|
|
| BLAKE2b-256 |
97148f33b32e4cd0344e15c4bc80af0eac8f34a42bf5a70ec7880218cec7c8a0
|
File details
Details for the file gforge_python-0.1.0-py3-none-any.whl.
File metadata
- Download URL: gforge_python-0.1.0-py3-none-any.whl
- Upload date:
- Size: 48.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fc12ad090d77fff0628402fef50cf51a81073dd503cc3227bd515f6daa30e15f
|
|
| MD5 |
f7d4d62deb09eb9b9cecf235341d752d
|
|
| BLAKE2b-256 |
9bd4d7adcaff8ed75f5bbe516cdfdf1418138b2dbc0c7d78f80fee55f7cc005a
|