Skip to main content

Local-first git commit guardrails: block secrets, forbidden files, and disallowed git identities before they are committed.

Project description

Coditation Sentinel

Local-first git commit guardrails. Sentinel installs a global git hook that runs on every git commit, in every repository on the machine, and blocks the commit before anything leaves the laptop when it finds:

  • 🔑 Secrets — API keys, tokens, private keys (via gitleaks)
  • 📄 Forbidden files.env, *.pem, *.key, keystores, dumps, …
  • 🧑‍💻 Disallowed git identity — commits authored with a personal email

It is built for a services company: developers commit to customer repositories whose remotes and CI we may not control, so enforcement lives on the developer's machine and never writes anything into the customer's repo. It is host-agnostic — GitHub, GitLab, Bitbucket, Azure DevOps, or no remote at all are all protected the same, because the check runs at git commit, before anything is pushed anywhere.

Secret scanning is fail-closed: if gitleaks can't run, the commit is blocked rather than silently allowed, so no change is ever committed unscanned (override with secrets.require_gitleaks: false).

How it works

git commit
   │  git runs the global hook → sentinel scan --staged
   ▼  (scans only the staged diff, so commits stay fast)
 secrets? · forbidden file? · git identity?
   │
 clean → commit proceeds      problem → friendly message + fix, commit aborted

The hook is wired via git config --global core.hooksPath, so a single install covers every repo automatically — nothing per-project, nothing added to customer code.

Git identity — three tiers

Identity Example Behavior
Company you@coditation.com ✅ silent pass
Customer / corporate you@acme-client.com ⚠️ allowed — "assuming valid identity" notice on every commit, recorded locally
Personal @gmail.com, @outlook.com, … ❌ always blocked

We don't allow-list customer domains (impossible to maintain). Instead policy.yaml keeps a deny-list of personal providers; the company domain passes, personal is blocked, and everything else is treated as a legitimate customer identity.

Because tier 2 is "everything not on either list", an unrecognised address like abc@email.com is allowed — Sentinel can't tell a real client domain from a typo, so it says so explicitly: on every commit it prints a notice that it is assuming a legitimate customer identity and shows how to correct it if that's wrong. (Set reporting.fyi_once_per_repo: true to show it only once per repo instead.) To make a domain a hard block, add it to personal_providers; to make it a silent pass, add it to company_domains.

Install

Quick install (recommended) — one-shot scripts

Hand a developer the script for their OS from runner/. It ensures Python 3.11, installs Sentinel into an isolated virtualenv, installs gitleaks, and wires the global git hook — no manual steps.

OS Run
macOS bash runner/run-macos.sh
Ubuntu / Debian bash runner/run-ubuntu.sh
Windows powershell -ExecutionPolicy Bypass -File runner/run-windows.ps1

Open a new terminal afterwards so the PATH change applies. Override the install source or versions via SENTINEL_PACKAGE, PYTHON_VERSION, GITLEAKS_VERSION (see runner/README.md). Prerequisite: git, plus a package manager (Homebrew / apt / winget) so Python 3.11 can be installed if missing.

Manual install

coditation-sentinel is published on public PyPI, so this needs no credentials. Since it's a command-line tool that wires a global git hook, install it with pipx — it puts the sentinel command on your PATH in an isolated environment:

brew install pipx                    # macOS (Linux: python3 -m pip install --user pipx)
pipx ensurepath                      # adds pipx's bin dir to PATH — open a new terminal after
pipx install coditation-sentinel     # installs the `sentinel` command globally
sentinel install                     # sets global core.hooksPath + writes default policy
brew install gitleaks                # required for secret scanning (macOS; see gitleaks docs for Linux/Windows)
sentinel status                      # verify enforcement + gitleaks

macOS / Homebrew Python users: a plain pip install coditation-sentinel fails with error: externally-managed-environment (PEP 668). Use pipx as above, or pip install --user coditation-sentinel. After a pipx/--user install, open a new terminal so the updated PATH takes effect — otherwise sentinel reports "command not found".

Commands

Command Purpose
sentinel install [--force] Install the global hook and default policy
sentinel scan --staged Scan staged changes (this is what the hook calls)
sentinel status Show enforcement status, policy source, resolved gitleaks path + whether secret scanning is active
sentinel selftest Verify the hook blocks a bad commit (throwaway repo, auto-deleted)
sentinel uninstall Remove the hook and revert core.hooksPath

Configuration

Policy lives at ~/.coditation-sentinel/policy.yaml (a copy of the packaged default). Edit it to adjust company domains, the personal-provider deny-list, and forbidden-file patterns. gitleaks rules live alongside it in gitleaks.toml.

Key secret-scanning knob: secrets.require_gitleaks (default true) makes scanning fail-closed — if gitleaks is missing or errors, the commit is blocked. Set it to false only to knowingly accept committing without secret scanning. Sentinel finds gitleaks on PATH and in the usual install dirs (~/.local/bin, /usr/local/bin, /opt/homebrew/bin, %LOCALAPPDATA%\CoditationSentinel\bin), so an installed binary still works even when the git hook runs with a reduced PATH.

A metadata-only log of non-Coditation identities used is kept at ~/.coditation-sentinel/identity-usage.log (timestamp, repo, email — never code).

Scope (Phase 1)

In: secrets, forbidden files, three-tier identity, global hook, CLI. Out (later): dependency/IaC scanning, PII detection, MDM/device enforcement, central dashboards. The local hook is the guarantee; server-side CI is intentionally not relied on.

Development

python3 -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest

Publishing to PyPI (maintainers)

Automated (recommended) — push a version tag

.github/workflows/publish.yml runs tests, builds, and publishes whenever a v* tag is pushed (the tag must match version in pyproject.toml):

# bump version in pyproject.toml, commit, then:
git tag v0.1.1 && git push origin v0.1.1

This uses PyPI Trusted Publishing (OIDC) — no token stored in GitHub. One-time setup on PyPI: project → Settings → Publishing → Add a trusted publisher: owner rajeshd-coditation, repo coditation-sentinel, workflow publish.yml, environment pypi. (Prefer a token? See the commented alternative in the workflow.)

Manual

. .venv/bin/activate && pip install build twine
# bump `version` in pyproject.toml first (PyPI rejects re-uploading an existing version)
rm -rf dist build *.egg-info && python -m build && twine check dist/*
twine upload dist/*    # auth: __token__ + a PyPI API token

After it lands, pipx install coditation-sentinel and the runner/ scripts work with no credentials. The import package is coditation_sentinel; the CLI is sentinel.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

coditation_sentinel-0.1.3.tar.gz (22.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

coditation_sentinel-0.1.3-py3-none-any.whl (23.9 kB view details)

Uploaded Python 3

File details

Details for the file coditation_sentinel-0.1.3.tar.gz.

File metadata

  • Download URL: coditation_sentinel-0.1.3.tar.gz
  • Upload date:
  • Size: 22.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for coditation_sentinel-0.1.3.tar.gz
Algorithm Hash digest
SHA256 4d72ec7ecddf98e1cc96afb544eabca2134a902c8d509f9a1e10d475e5f32c6f
MD5 db469a22a5b2f5f6a80d1c50e4a0f7f6
BLAKE2b-256 a42deec91cf227b85b1ae13c07efc4a44b5084a66697084b8449be3a91766c57

See more details on using hashes here.

Provenance

The following attestation bundles were made for coditation_sentinel-0.1.3.tar.gz:

Publisher: publish.yml on rajeshd-coditation/coditation-sentinel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file coditation_sentinel-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for coditation_sentinel-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 18013cc7a3b2e5b510c694e699f63607b9704ff81cb0b0fd4100d57be0d16f99
MD5 82c59fed9704cb33d06aa12cb44f46ac
BLAKE2b-256 1321bb2b0ee61f7652445c9ee2d96711edaf3ddb7ce3f4731279851c1d82849e

See more details on using hashes here.

Provenance

The following attestation bundles were made for coditation_sentinel-0.1.3-py3-none-any.whl:

Publisher: publish.yml on rajeshd-coditation/coditation-sentinel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page