commitguardian 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- commitguard/__init__.py +26 -0
- commitguard/__main__.py +6 -0
- commitguard/api/__init__.py +18 -0
- commitguard/api/app.py +1376 -0
- commitguard/api/governance.py +1085 -0
- commitguard/api/hosting.py +196 -0
- commitguard/api/http.py +252 -0
- commitguard/api/settings.py +169 -0
- commitguard/audit/__init__.py +13 -0
- commitguard/audit/logger.py +34 -0
- commitguard/audit/models.py +222 -0
- commitguard/audit/storage.py +59 -0
- commitguard/ci/__init__.py +7 -0
- commitguard/ci/context.py +60 -0
- commitguard/cli/__init__.py +6 -0
- commitguard/cli/app.py +74 -0
- commitguard/cli/commands/__init__.py +1 -0
- commitguard/cli/commands/benchmark.py +441 -0
- commitguard/cli/commands/check.py +100 -0
- commitguard/cli/commands/ci.py +165 -0
- commitguard/cli/commands/dashboard.py +141 -0
- commitguard/cli/commands/doctor.py +533 -0
- commitguard/cli/commands/github.py +449 -0
- commitguard/cli/commands/hook.py +156 -0
- commitguard/cli/commands/init.py +137 -0
- commitguard/cli/commands/install.py +152 -0
- commitguard/cli/commands/policy.py +36 -0
- commitguard/cli/commands/report.py +39 -0
- commitguard/cli/commands/reproduce.py +123 -0
- commitguard/cli/commands/scan.py +47 -0
- commitguard/cli/common.py +44 -0
- commitguard/cli/output.py +89 -0
- commitguard/cli/render.py +367 -0
- commitguard/config/__init__.py +6 -0
- commitguard/config/defaults.py +53 -0
- commitguard/config/enforcement.py +53 -0
- commitguard/config/loader.py +174 -0
- commitguard/config/schema.py +105 -0
- commitguard/config/sources.py +183 -0
- commitguard/controlplane/__init__.py +24 -0
- commitguard/controlplane/access.py +231 -0
- commitguard/controlplane/commands.py +393 -0
- commitguard/controlplane/errors.py +88 -0
- commitguard/controlplane/identity.py +478 -0
- commitguard/controlplane/members.py +219 -0
- commitguard/controlplane/notifications.py +787 -0
- commitguard/controlplane/pagination.py +146 -0
- commitguard/controlplane/policies.py +1204 -0
- commitguard/controlplane/queries.py +1814 -0
- commitguard/controlplane/results.py +909 -0
- commitguard/controlplane/rules.py +184 -0
- commitguard/controlplane/views.py +799 -0
- commitguard/core/__init__.py +6 -0
- commitguard/core/context.py +31 -0
- commitguard/core/decision.py +58 -0
- commitguard/core/engine.py +82 -0
- commitguard/core/result.py +177 -0
- commitguard/detectors/__init__.py +6 -0
- commitguard/detectors/base.py +58 -0
- commitguard/detectors/bot.py +87 -0
- commitguard/detectors/coauthor.py +86 -0
- commitguard/detectors/identity.py +76 -0
- commitguard/detectors/registry.py +72 -0
- commitguard/detectors/trailer.py +211 -0
- commitguard/exceptions/__init__.py +33 -0
- commitguard/exceptions/base.py +9 -0
- commitguard/exceptions/configuration.py +22 -0
- commitguard/exceptions/detection.py +11 -0
- commitguard/exceptions/git.py +41 -0
- commitguard/exceptions/service.py +25 -0
- commitguard/git/__init__.py +12 -0
- commitguard/git/commands.py +101 -0
- commitguard/git/commit.py +97 -0
- commitguard/git/diff.py +36 -0
- commitguard/git/hooks.py +527 -0
- commitguard/git/push.py +93 -0
- commitguard/git/ranges.py +71 -0
- commitguard/git/repository.py +447 -0
- commitguard/github/__init__.py +34 -0
- commitguard/github/actions.py +163 -0
- commitguard/github/app.py +935 -0
- commitguard/github/auth.py +217 -0
- commitguard/github/check_runs.py +172 -0
- commitguard/github/checks.py +210 -0
- commitguard/github/client.py +844 -0
- commitguard/github/enforcement_status.py +209 -0
- commitguard/github/errors.py +129 -0
- commitguard/github/events.py +563 -0
- commitguard/github/identifiers.py +90 -0
- commitguard/github/installations.py +566 -0
- commitguard/github/markdown.py +19 -0
- commitguard/github/permissions.py +70 -0
- commitguard/github/pull_requests.py +53 -0
- commitguard/github/queue.py +47 -0
- commitguard/github/recovery.py +124 -0
- commitguard/github/repositories.py +305 -0
- commitguard/github/server.py +52 -0
- commitguard/github/settings.py +174 -0
- commitguard/github/storage.py +2315 -0
- commitguard/github/webhooks.py +129 -0
- commitguard/github/worker.py +628 -0
- commitguard/github/workflow.py +286 -0
- commitguard/governance/__init__.py +26 -0
- commitguard/governance/bulk.py +765 -0
- commitguard/governance/cache.py +88 -0
- commitguard/governance/common.py +216 -0
- commitguard/governance/exceptions.py +861 -0
- commitguard/governance/groups.py +448 -0
- commitguard/governance/inventory.py +386 -0
- commitguard/governance/posture.py +1272 -0
- commitguard/governance/resolver.py +632 -0
- commitguard/governance/rollouts.py +760 -0
- commitguard/governance/rules.py +371 -0
- commitguard/governance/schedules.py +663 -0
- commitguard/governance/service.py +120 -0
- commitguard/governance/settings.py +365 -0
- commitguard/governance/simulation.py +618 -0
- commitguard/governance/workflow.py +734 -0
- commitguard/notifications/__init__.py +2 -0
- commitguard/notifications/channels/__init__.py +1 -0
- commitguard/notifications/channels/base.py +22 -0
- commitguard/notifications/channels/email.py +110 -0
- commitguard/notifications/channels/in_app.py +74 -0
- commitguard/notifications/channels/sink.py +58 -0
- commitguard/notifications/channels/webhook.py +233 -0
- commitguard/notifications/deduplication.py +57 -0
- commitguard/notifications/dispatcher.py +201 -0
- commitguard/notifications/models.py +439 -0
- commitguard/notifications/outbox.py +106 -0
- commitguard/notifications/preferences.py +224 -0
- commitguard/notifications/retry.py +282 -0
- commitguard/notifications/service.py +128 -0
- commitguard/notifications/settings.py +167 -0
- commitguard/notifications/templates.py +108 -0
- commitguard/observability/__init__.py +5 -0
- commitguard/observability/logging.py +161 -0
- commitguard/observability/metrics.py +105 -0
- commitguard/policies/__init__.py +6 -0
- commitguard/policies/defaults.py +48 -0
- commitguard/policies/evaluator.py +66 -0
- commitguard/policies/governance.py +498 -0
- commitguard/policies/loader.py +23 -0
- commitguard/policies/mandatory.py +52 -0
- commitguard/policies/model.py +46 -0
- commitguard/provenance/__init__.py +9 -0
- commitguard/provenance/author.py +146 -0
- commitguard/provenance/committer.py +16 -0
- commitguard/provenance/normalization.py +158 -0
- commitguard/provenance/signatures.py +34 -0
- commitguard/provenance/trailers.py +256 -0
- commitguard/research/__init__.py +26 -0
- commitguard/research/compare.py +231 -0
- commitguard/research/datasets.py +1484 -0
- commitguard/research/detection.py +183 -0
- commitguard/research/environment.py +185 -0
- commitguard/research/gitenv.py +108 -0
- commitguard/research/hooks.py +247 -0
- commitguard/research/metrics.py +85 -0
- commitguard/research/performance.py +194 -0
- commitguard/research/platform.py +288 -0
- commitguard/research/report.py +372 -0
- commitguard/research/repository.py +111 -0
- commitguard/research/reproduction.py +297 -0
- commitguard/research/results.py +94 -0
- commitguard/rules/__init__.py +11 -0
- commitguard/rules/data/ai-domains.yaml +51 -0
- commitguard/rules/data/ai-identities.yaml +131 -0
- commitguard/rules/data/bot-identities.yaml +53 -0
- commitguard/rules/data/patterns.yaml +52 -0
- commitguard/rules/loader.py +102 -0
- commitguard/rules/matcher.py +212 -0
- commitguard/rules/models.py +269 -0
- commitguard/security/__init__.py +5 -0
- commitguard/security/hashing.py +30 -0
- commitguard/security/rate_limit.py +33 -0
- commitguard/security/safe_yaml.py +69 -0
- commitguard/security/sanitization.py +85 -0
- commitguard/security/secrets.py +169 -0
- commitguard/security/validation.py +89 -0
- commitguard/services/__init__.py +15 -0
- commitguard/services/analysis.py +119 -0
- commitguard/services/audit.py +95 -0
- commitguard/services/ci.py +383 -0
- commitguard/services/enforcement.py +102 -0
- commitguard/services/hooks.py +254 -0
- commitguard/services/remediation.py +99 -0
- commitguard/services/reports.py +146 -0
- commitguard/services/scan.py +172 -0
- commitguard/utils/__init__.py +1 -0
- commitguard/utils/filesystem.py +72 -0
- commitguard/utils/platform.py +35 -0
- commitguard/utils/subprocess.py +84 -0
- commitguardian-0.1.0.dist-info/METADATA +694 -0
- commitguardian-0.1.0.dist-info/RECORD +197 -0
- commitguardian-0.1.0.dist-info/WHEEL +4 -0
- commitguardian-0.1.0.dist-info/entry_points.txt +2 -0
- commitguardian-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,694 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: commitguardian
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Block AI, bot and agent attribution in Git commits, locally and on GitHub.
|
|
5
|
+
Project-URL: Homepage, https://github.com/oyinlola-tech/commitguard
|
|
6
|
+
Project-URL: Repository, https://github.com/oyinlola-tech/commitguard
|
|
7
|
+
Project-URL: Documentation, https://github.com/oyinlola-tech/commitguard/blob/main/docs/README.md
|
|
8
|
+
Project-URL: Changelog, https://github.com/oyinlola-tech/commitguard/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Issues, https://github.com/oyinlola-tech/commitguard/issues
|
|
10
|
+
Author: Oluwayemi Oyinlola
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: ai-attribution,git,git-hooks,policy,provenance,security
|
|
14
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Security
|
|
23
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.12
|
|
26
|
+
Requires-Dist: pydantic<3,>=2.7
|
|
27
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
28
|
+
Requires-Dist: typer>=0.12
|
|
29
|
+
Requires-Dist: tzdata>=2024.1; sys_platform == 'win32'
|
|
30
|
+
Provides-Extra: app
|
|
31
|
+
Requires-Dist: cryptography>=42; extra == 'app'
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: cryptography>=42; extra == 'dev'
|
|
34
|
+
Requires-Dist: hypothesis>=6.100; extra == 'dev'
|
|
35
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=8.2; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
38
|
+
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
<div align="center">
|
|
42
|
+
|
|
43
|
+
<picture>
|
|
44
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/banner-dark.png">
|
|
45
|
+
<img alt="CommitGuard: Git commit provenance and contribution policy enforcement" src="docs/images/banner-light.png" width="100%">
|
|
46
|
+
</picture>
|
|
47
|
+
|
|
48
|
+
<p>
|
|
49
|
+
<a href="https://github.com/oyinlola-tech/commitguard/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/oyinlola-tech/commitguard/actions/workflows/ci.yml/badge.svg"></a>
|
|
50
|
+
<a href="https://github.com/oyinlola-tech/commitguard/actions/workflows/security.yml"><img alt="Security" src="https://github.com/oyinlola-tech/commitguard/actions/workflows/security.yml/badge.svg"></a>
|
|
51
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-101816?style=flat"></a>
|
|
52
|
+
<img alt="Python 3.12+" src="https://img.shields.io/badge/python-3.12%2B-101816?style=flat&logo=python&logoColor=white">
|
|
53
|
+
<img alt="Status: pre-alpha" src="https://img.shields.io/badge/status-pre--alpha-855700?style=flat">
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<p>
|
|
57
|
+
<a href="#see-it-work"><strong>See it work</strong></a> ·
|
|
58
|
+
<a href="#quick-start"><strong>Quick start</strong></a> ·
|
|
59
|
+
<a href="#run-the-demo-locally"><strong>Run the demo</strong></a> ·
|
|
60
|
+
<a href="#test-evidence"><strong>Test evidence</strong></a> ·
|
|
61
|
+
<a href="#documentation"><strong>Docs</strong></a>
|
|
62
|
+
</p>
|
|
63
|
+
|
|
64
|
+
<a href="#built-with"><img alt="Python, TypeScript, React, Vite, Vitest, SQLite, Node.js, Git, GitHub Actions" src="https://skillicons.dev/icons?i=py,ts,react,vite,vitest,sqlite,nodejs,git,githubactions&perline=9" height="40"></a>
|
|
65
|
+
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<br>
|
|
69
|
+
|
|
70
|
+
> [!NOTE]
|
|
71
|
+
> **Pre-alpha, Phase 10: measured, reproducible and open to external evaluation.**
|
|
72
|
+
> Local Git hooks stop violations during `git commit` / `git push`; a GitHub
|
|
73
|
+
> Actions check and a webhook-driven GitHub App run the same engine on pull
|
|
74
|
+
> requests, pushes and merge queues; a web dashboard explains what was scanned,
|
|
75
|
+
> what is blocked and why, notifies the people who need to act, and lets an
|
|
76
|
+
> organization govern policy across hundreds of repositories: groups,
|
|
77
|
+
> approvals, scoped exceptions, staged rollouts and an explicit security posture.
|
|
78
|
+
> Detection accuracy, performance and bypass resistance are **measured against a
|
|
79
|
+
> versioned labelled dataset**, and every result - including the runs that failed
|
|
80
|
+
> and exposed real bypasses - is published and reproducible with
|
|
81
|
+
> [`commitguard reproduce`](docs/cli/reproduce.md).
|
|
82
|
+
|
|
83
|
+
> [!IMPORTANT]
|
|
84
|
+
> **A failing GitHub check blocks merges only when branch protection requires it.**
|
|
85
|
+
> CommitGuard never configures that for you. The CLI cannot see it at all; the
|
|
86
|
+
> GitHub App reports what GitHub's read-only endpoints show and says `unknown`
|
|
87
|
+
> when they show nothing. See [What works today](#what-works-today).
|
|
88
|
+
|
|
89
|
+
## See it work
|
|
90
|
+
|
|
91
|
+
Everything below was produced by running CommitGuard, not typed by hand: the
|
|
92
|
+
terminal images come from real commands in a fresh repository, and the dashboard
|
|
93
|
+
screenshots come from the demo stack, which replays a full lifecycle through
|
|
94
|
+
the real services (see [Run the demo locally](#run-the-demo-locally)).
|
|
95
|
+
|
|
96
|
+
**1. A local hook stops the commit.** Nothing is committed; the message is kept.
|
|
97
|
+
|
|
98
|
+
<img alt="git commit blocked by the CommitGuard commit-msg hook" src="docs/images/cli-commit-blocked.png" width="820">
|
|
99
|
+
|
|
100
|
+
**2. The same engine scans a commit range, as the GitHub check does.** Exit code 1 fails CI.
|
|
101
|
+
|
|
102
|
+
<img alt="commitguard check and scan output for a blocked commit" src="docs/images/cli-scan-blocked.png" width="820">
|
|
103
|
+
|
|
104
|
+
**3. The dashboard explains what was blocked, and why.**
|
|
105
|
+
|
|
106
|
+
<picture>
|
|
107
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/overview-dark.png">
|
|
108
|
+
<img alt="CommitGuard dashboard overview" src="docs/images/overview.png" width="100%">
|
|
109
|
+
</picture>
|
|
110
|
+
|
|
111
|
+
<table>
|
|
112
|
+
<tr>
|
|
113
|
+
<td width="50%"><img alt="Violation detail with evidence" src="docs/images/violation.png"><br><sub><b>Violation</b>: the exact trailer, the matched rule data and remediation; never file contents.</sub></td>
|
|
114
|
+
<td width="50%"><img alt="Scan executions after a GitHub re-run" src="docs/images/scan-executions.png"><br><sub><b>Re-runs</b>: a GitHub "Re-run" is a numbered execution; earlier results are kept.</sub></td>
|
|
115
|
+
</tr>
|
|
116
|
+
<tr>
|
|
117
|
+
<td><img alt="Notification center" src="docs/images/notifications.png"><br><sub><b>Notifications</b>: blocked violations, policy changes, rollbacks and installation outages.</sub></td>
|
|
118
|
+
<td><img alt="Repository enforcement evidence" src="docs/images/repository.png"><br><sub><b>Repositories</b>: protection is shown only with evidence from GitHub.</sub></td>
|
|
119
|
+
</tr>
|
|
120
|
+
<tr>
|
|
121
|
+
<td><img alt="Policy version history and rollback" src="docs/images/policy-rollback.png"><br><sub><b>Policy rollback</b>: immutable versions; a rollback is a new, audited version.</sub></td>
|
|
122
|
+
<td><img alt="Merge queue validation" src="docs/images/merge-queue.png"><br><sub><b>Merge queue</b>: the merge group commit itself is validated.</sub></td>
|
|
123
|
+
</tr>
|
|
124
|
+
</table>
|
|
125
|
+
|
|
126
|
+
## What CommitGuard is
|
|
127
|
+
|
|
128
|
+
CommitGuard analyses Git commit metadata and decides, according to a
|
|
129
|
+
repository's policy, whether a commit is acceptable. It is built as a general
|
|
130
|
+
*provenance and contribution policy engine*: independent detectors report what
|
|
131
|
+
a commit claims about its origin, and a separate policy layer decides what to
|
|
132
|
+
do about it.
|
|
133
|
+
|
|
134
|
+
The first policy is **AI agent attribution**. This commit is blocked by default:
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
feat: implement authentication
|
|
138
|
+
|
|
139
|
+
Co-authored-by: Claude <noreply@anthropic.com>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
This one is not:
|
|
143
|
+
|
|
144
|
+
```text
|
|
145
|
+
feat: implement authentication
|
|
146
|
+
|
|
147
|
+
Co-authored-by: John Doe <john@example.com>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## What it detects — and what it does not
|
|
151
|
+
|
|
152
|
+
CommitGuard detects **explicit attribution and identity evidence** in commit
|
|
153
|
+
metadata:
|
|
154
|
+
|
|
155
|
+
| Rule | Detector | Example | Default |
|
|
156
|
+
|---|---|---|---|
|
|
157
|
+
| `ai_coauthor` | `coauthor` | `Co-authored-by: Claude <noreply@anthropic.com>` | block |
|
|
158
|
+
| `ai_identity` | `identity` | author/committer `Copilot <…+Copilot@users.noreply.github.com>` | block |
|
|
159
|
+
| `ai_trailer` | `trailer` | `Generated-by: Claude Code`, `Generated with [Claude Code](…)` (with or without a leading pictographic symbol) | block |
|
|
160
|
+
| `malformed_trailer` | `trailer` | `Co-authored-by Claude noreply@anthropic.com` | warn |
|
|
161
|
+
| `bot_identity` | `bot` | author `dependabot[bot]` (a bot, **not** an AI) | warn |
|
|
162
|
+
|
|
163
|
+
It does **not**:
|
|
164
|
+
|
|
165
|
+
- determine whether code was written by an AI. A finding means *"this commit
|
|
166
|
+
contains an identity or attribution associated with an AI agent"*, never
|
|
167
|
+
*"this code was written by AI"*;
|
|
168
|
+
- guess from wording (`feat: use AI service for recommendations` is not evidence);
|
|
169
|
+
- analyse diffs or file contents, call any AI/LLM API, or use the network;
|
|
170
|
+
- prove authorship: metadata is self-asserted and can simply be removed.
|
|
171
|
+
|
|
172
|
+
## Why it exists
|
|
173
|
+
|
|
174
|
+
AI coding agents increasingly write commits, and many record themselves in
|
|
175
|
+
commit metadata. Some organisations and projects need to control that for
|
|
176
|
+
licensing or contributor-agreement reasons, accurate provenance records, or a
|
|
177
|
+
consistent contribution policy. Checking by hand does not scale, and naive
|
|
178
|
+
string matching is both easy to evade (casing, malformed trailers, look-alike
|
|
179
|
+
Unicode, escape codes that hide a line) and prone to false positives (a human
|
|
180
|
+
named Claude, an employee with an `@anthropic.com` address).
|
|
181
|
+
|
|
182
|
+
## How AI attribution is identified
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
Git ─▶ Commit parser ─▶ Commit (author, committer, message, trailers)
|
|
186
|
+
│
|
|
187
|
+
Detection engine (4 detectors, pure, offline)
|
|
188
|
+
│ rules/*.yaml ─▶ identity matcher
|
|
189
|
+
▼
|
|
190
|
+
Findings (rule, severity, confidence, evidence)
|
|
191
|
+
│
|
|
192
|
+
Policy evaluator (.commitguard.yaml)
|
|
193
|
+
▼
|
|
194
|
+
Decision: ALLOW / WARN / BLOCK ─▶ exit code 0 / 0 / 1
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
- **Rules are data** (`rules/ai-identities.yaml`, `ai-domains.yaml`,
|
|
198
|
+
`bot-identities.yaml`, `patterns.yaml`), not code.
|
|
199
|
+
- **Matching is deliberate:** exact comparison after case/width/whitespace
|
|
200
|
+
normalisation, removal of invisible characters and folding of Cyrillic/Greek
|
|
201
|
+
look-alikes. No substring or fuzzy matching: `Claude` never matches
|
|
202
|
+
`Claudette` or `Claude Dupont`.
|
|
203
|
+
- **Evidence is combined:** an exact AI email, GitHub bot login or distinctive
|
|
204
|
+
name prefix is strong evidence; a bare alias like `Claude` is medium
|
|
205
|
+
confidence; a vendor domain alone (`jane@anthropic.com`) is never enough.
|
|
206
|
+
- **Explicit evidence > weak inference.** An agent not listed in the rules is
|
|
207
|
+
not guessed; add a rule instead.
|
|
208
|
+
|
|
209
|
+
Details: [docs/detection-engine.md](docs/detection-engine.md).
|
|
210
|
+
|
|
211
|
+
## Detection vs. policy
|
|
212
|
+
|
|
213
|
+
| | Detector | Policy |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| Question | *Does this commit list an AI co-author? What is the evidence?* | *Is that allowed here?* |
|
|
216
|
+
| Output | `Finding` (rule, severity, confidence, evidence, remediation) | `Decision` (allow / warn / block, with reasons) |
|
|
217
|
+
| Knows about | a single commit and rule data | configuration |
|
|
218
|
+
| Side effects | none | none |
|
|
219
|
+
|
|
220
|
+
Precedence is deterministic: **block > warn > allow**, independent of detector
|
|
221
|
+
order. A detector that crashes blocks (fail closed). See
|
|
222
|
+
[docs/policy-engine.md](docs/policy-engine.md).
|
|
223
|
+
|
|
224
|
+
## Install
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
pipx install commitguardian
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
> [!IMPORTANT]
|
|
231
|
+
> **The PyPI name is `commitguardian`; the command is `commitguard`.**
|
|
232
|
+
> `commitguard` and `commitguard-cli` on PyPI are two *unrelated* projects by
|
|
233
|
+
> other authors, so `pip install commitguard` installs someone else's code
|
|
234
|
+
> ([why](docs/adr/009-published-to-pypi-as-commitguardian.md)).
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# in a virtual environment
|
|
238
|
+
python -m pip install commitguardian
|
|
239
|
+
|
|
240
|
+
# pinned to an exact commit, if you prefer provenance over convenience
|
|
241
|
+
pipx install "git+https://github.com/oyinlola-tech/commitguard@<commit-sha>"
|
|
242
|
+
|
|
243
|
+
# from a clone, for development
|
|
244
|
+
git clone https://github.com/oyinlola-tech/commitguard && cd commitguard
|
|
245
|
+
python -m pip install -e ".[dev]"
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Requires Python 3.12+ and Git 2.31+. Full walkthrough:
|
|
249
|
+
[5-minute quick start](docs/getting-started/quickstart.md).
|
|
250
|
+
|
|
251
|
+
## Quick start
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
cd my-project
|
|
255
|
+
commitguard init --install-hooks # .commitguard.yaml + pre-commit, commit-msg, pre-push
|
|
256
|
+
commitguard doctor # Status: HEALTHY
|
|
257
|
+
|
|
258
|
+
git add .
|
|
259
|
+
git commit -m "implement authentication" # checked automatically
|
|
260
|
+
git push # every outgoing commit checked
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Server side (GitHub):
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
commitguard init --github --action-repository OWNER/commitguard --action-ref <commit sha>
|
|
267
|
+
commitguard github setup # required check name + branch protection steps
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Then require the `commitguard` status check on protected branches.
|
|
271
|
+
|
|
272
|
+
## CLI usage
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
commitguard init # write .commitguard.yaml with secure defaults
|
|
276
|
+
commitguard install # install hooks (existing hooks are preserved and chained)
|
|
277
|
+
commitguard uninstall # remove only CommitGuard's hooks, restore previous ones
|
|
278
|
+
commitguard scan # explain findings for HEAD
|
|
279
|
+
commitguard scan origin/main..HEAD # every commit in a range
|
|
280
|
+
commitguard scan --format json # structured report (schema_version 1)
|
|
281
|
+
commitguard check # machine-friendly result for HEAD
|
|
282
|
+
commitguard check --quiet origin/main..HEAD
|
|
283
|
+
commitguard check --message-file .git/COMMIT_EDITMSG # a commit that does not exist yet
|
|
284
|
+
commitguard check --verbose # check with full human-readable evidence
|
|
285
|
+
commitguard policy list # effective policies and config layers
|
|
286
|
+
commitguard doctor # installation, config, engine and hook health
|
|
287
|
+
commitguard hook pre-commit|commit-msg <file>|pre-push # called by installed hooks
|
|
288
|
+
commitguard ci github # GitHub Actions check (reads $GITHUB_EVENT_PATH)
|
|
289
|
+
commitguard github setup # workflow status, check name, setup guidance
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Blocked `scan` output (abridged):
|
|
293
|
+
|
|
294
|
+
```text
|
|
295
|
+
CommitGuard
|
|
296
|
+
✗ BLOCKED: policy violation detected
|
|
297
|
+
|
|
298
|
+
AI coauthor detected
|
|
299
|
+
Commit: 4f71c92
|
|
300
|
+
Detector: coauthor
|
|
301
|
+
Rule: ai_coauthor
|
|
302
|
+
Severity: high
|
|
303
|
+
Confidence: high
|
|
304
|
+
Action: block (policy ai_coauthor)
|
|
305
|
+
Evidence: Claude <noreply@anthropic.com>
|
|
306
|
+
Source: Co-authored-by trailer, line 4
|
|
307
|
+
Matched: email "noreply@anthropic.com" (ai-identities.yaml#claude)
|
|
308
|
+
Remediation: Remove the AI co-author attribution from the commit message ...
|
|
309
|
+
|
|
310
|
+
Result: BLOCK
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
`check` output is one tab-separated line per finding followed by a summary:
|
|
314
|
+
|
|
315
|
+
```text
|
|
316
|
+
BLOCK 4f71c92 coauthor ai_coauthor Claude <noreply@anthropic.com>
|
|
317
|
+
result=BLOCK commits=1 block=1 warn=0 allow=0
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Exit codes
|
|
321
|
+
|
|
322
|
+
| Code | Meaning |
|
|
323
|
+
|---|---|
|
|
324
|
+
| `0` | allowed (no findings, or only `allow`/`warn` findings) |
|
|
325
|
+
| `1` | blocked by policy (a finding or detector failure evaluated to `block`) |
|
|
326
|
+
| `2` | error: invalid configuration/rules, Git error, bad arguments, unexpected failure (hooks block on errors) |
|
|
327
|
+
|
|
328
|
+
CommitGuard never modifies commits or rewrites history; remediation is always
|
|
329
|
+
left to the developer.
|
|
330
|
+
|
|
331
|
+
## Configuration
|
|
332
|
+
|
|
333
|
+
```yaml
|
|
334
|
+
# .commitguard.yaml
|
|
335
|
+
version: 1
|
|
336
|
+
policies:
|
|
337
|
+
ai_coauthor:
|
|
338
|
+
enabled: true
|
|
339
|
+
action: block
|
|
340
|
+
bot_identity:
|
|
341
|
+
enabled: true
|
|
342
|
+
action: warn
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Layers, lowest precedence first: built-in defaults → global
|
|
346
|
+
`~/.config/commitguard/config.yaml` → repository `.commitguard.yaml` →
|
|
347
|
+
`--config PATH`. Omitted policies keep secure defaults; invalid configuration
|
|
348
|
+
is an error (exit 2). Which hooks enforce is set under `enforcement:`
|
|
349
|
+
(all enabled by default). See [docs/configuration.md](docs/configuration.md).
|
|
350
|
+
|
|
351
|
+
## Enforcement layers: local + GitHub
|
|
352
|
+
|
|
353
|
+
```text
|
|
354
|
+
Local Hooks
|
|
355
|
+
│
|
|
356
|
+
▼
|
|
357
|
+
CommitGuard Core (detection engine · policy engine · ScanService)
|
|
358
|
+
│
|
|
359
|
+
├───────────────► GitHub Actions commitguard ci github → job status "commitguard"
|
|
360
|
+
│
|
|
361
|
+
└───────────────► GitHub App commitguard github serve
|
|
362
|
+
│
|
|
363
|
+
▼
|
|
364
|
+
Webhooks (signed, deduplicated)
|
|
365
|
+
│
|
|
366
|
+
▼
|
|
367
|
+
Scan Service (metadata-only fetch, trusted policy)
|
|
368
|
+
│
|
|
369
|
+
▼
|
|
370
|
+
GitHub Checks "commitguard-app"
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
In more detail, for the Action:
|
|
374
|
+
|
|
375
|
+
```text
|
|
376
|
+
Developer ─▶ git commit / push ─▶ Local hooks (Phase 3) ──── fast feedback, bypassable
|
|
377
|
+
│
|
|
378
|
+
▼
|
|
379
|
+
GitHub
|
|
380
|
+
│ pull_request / merge_group / push
|
|
381
|
+
▼
|
|
382
|
+
GitHub Actions: commitguard ci github (Phase 4)
|
|
383
|
+
│ same detectors + policy evaluator
|
|
384
|
+
┌─────┴─────┐
|
|
385
|
+
PASS FAIL
|
|
386
|
+
│ │
|
|
387
|
+
check passes check fails ─▶ merge blocked
|
|
388
|
+
(when branch protection
|
|
389
|
+
requires "commitguard")
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
| Layer | Purpose | Can be bypassed by the contributor? |
|
|
393
|
+
|---|---|---|
|
|
394
|
+
| Local hooks | stop accidents before they leave the machine | yes (`--no-verify`, deleting hooks) |
|
|
395
|
+
| GitHub Actions check | server-side validation of every commit a PR introduces | no, but it only *reports* on its own |
|
|
396
|
+
| Branch protection / rulesets | make the check a merge requirement | no (repository admins configure it) |
|
|
397
|
+
|
|
398
|
+
Why both: hooks give immediate feedback without waiting for CI; the GitHub
|
|
399
|
+
check makes local bypasses visible and, with branch protection, unmergeable.
|
|
400
|
+
|
|
401
|
+
**Local hooks** (`commitguard install`): pre-commit checks the pending identity,
|
|
402
|
+
commit-msg the message, pre-push every outgoing commit. Existing hooks are
|
|
403
|
+
preserved and chained; failures block. See [docs/git-hooks.md](docs/git-hooks.md).
|
|
404
|
+
|
|
405
|
+
**GitHub check** (`commitguard ci github`, `action.yml`):
|
|
406
|
+
|
|
407
|
+
- scans every commit a pull request introduces (`head ^base`), not just the
|
|
408
|
+
latest, plus merge queue entries and pushes (new branches, deletions, tags,
|
|
409
|
+
force pushes);
|
|
410
|
+
- evaluates with the policy from the **base commit**, so a pull request cannot
|
|
411
|
+
relax `.commitguard.yaml` to approve itself; rules come from the installed
|
|
412
|
+
CommitGuard, never the repository;
|
|
413
|
+
- needs only `contents: read`, no secrets, works for fork pull requests;
|
|
414
|
+
- fails closed (exit 2) when policy cannot be evaluated;
|
|
415
|
+
- a push-triggered run happens **after** commits reach GitHub: prevention needs
|
|
416
|
+
protected branches, required pull requests and the required check.
|
|
417
|
+
|
|
418
|
+
See [docs/github-enforcement.md](docs/github-enforcement.md).
|
|
419
|
+
|
|
420
|
+
**GitHub App** (`commitguard github serve`; the App extra adds `cryptography`:
|
|
421
|
+
`python -m pip install "commitguardian[app]"`):
|
|
422
|
+
|
|
423
|
+
- a centralised service you deploy: install it once on an account or
|
|
424
|
+
organisation and it scans pull requests and pushes of the selected
|
|
425
|
+
repositories from signed webhooks;
|
|
426
|
+
- publishes the Check Run `commitguard-app` (queued → in progress → completed)
|
|
427
|
+
on the exact commit it scanned;
|
|
428
|
+
- least privilege: Checks write, and read-only Contents, Metadata and Pull
|
|
429
|
+
requests. Tokens are down-scoped to one repository per scan;
|
|
430
|
+
- never checks out or runs repository code, and never modifies a repository;
|
|
431
|
+
- supports an optional **mandatory policy** that repositories cannot weaken;
|
|
432
|
+
- `commitguard github validate` checks configuration, authentication,
|
|
433
|
+
permissions and installations.
|
|
434
|
+
|
|
435
|
+
Actions or App? Actions: simplest, no service. App: organisation-wide,
|
|
436
|
+
webhook-driven, central policy, but you operate it. Both can run together. See
|
|
437
|
+
[docs/github-app.md](docs/github-app.md) and [docs/deployment.md](docs/deployment.md).
|
|
438
|
+
|
|
439
|
+
## Dashboard
|
|
440
|
+
|
|
441
|
+
```text
|
|
442
|
+
CommitGuard core ──► ScanResult ──┬──► CLI (terminal)
|
|
443
|
+
├──► GitHub Check (GitHub enforces it)
|
|
444
|
+
└──► /api/v1 ──► Dashboard (explains it)
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
The GitHub App service also serves a web dashboard (`web/`) and its API:
|
|
448
|
+
|
|
449
|
+
- **Overview** — monitored repositories, scans in a period, blocked scans,
|
|
450
|
+
open and critical violations, explicit security checks (no invented score);
|
|
451
|
+
- **Repositories** — protection shown only with evidence from GitHub, and
|
|
452
|
+
separate signals for the App, Actions, required check, latest check and
|
|
453
|
+
local hooks (reported as not verifiable);
|
|
454
|
+
- **Scans** — every result with its commit range, findings, evidence and the
|
|
455
|
+
policy, rules and CommitGuard versions that produced it; scan again;
|
|
456
|
+
- **Violations** — open, acknowledged or resolved, where resolution happens
|
|
457
|
+
only when the commit is no longer present; remediation guidance; history kept;
|
|
458
|
+
- **Policies** — versioned, immutable organization floors that repositories
|
|
459
|
+
cannot lower, with confirmation for weakening changes, a structured diff and
|
|
460
|
+
audited **rollback** to an earlier version; **Rules**; **Audit log**;
|
|
461
|
+
**GitHub installations**;
|
|
462
|
+
- **Notifications** — blocked violations, policy changes and rollbacks,
|
|
463
|
+
installation disconnects, merge queue and re-run failures, deduplicated, in
|
|
464
|
+
the dashboard and optionally by e-mail and signed webhooks; **Settings**
|
|
465
|
+
(sessions, members, notification preferences).
|
|
466
|
+
|
|
467
|
+
- **Organization** — security posture as explicit states with reasons (no
|
|
468
|
+
score), "N of M required repositories satisfy all mandatory controls", a
|
|
469
|
+
repository security matrix, repository groups and bulk onboarding;
|
|
470
|
+
organization, group and repository **policies** with mandatory and default
|
|
471
|
+
strength, drafts, **simulation** against recorded scans, approval with
|
|
472
|
+
separation of duties, **staged rollouts**; scoped, expiring **exceptions**;
|
|
473
|
+
per-rule provenance of the effective policy; organization rules; scheduled
|
|
474
|
+
scans; compliance reports (JSON/CSV, explicitly not a certification).
|
|
475
|
+
|
|
476
|
+
Sign-in uses the GitHub App's user authorization; roles (viewer, security
|
|
477
|
+
manager, admin, owner) are granted in CommitGuard, and users only see
|
|
478
|
+
repositories GitHub lets them see. See [docs/dashboard.md](docs/dashboard.md).
|
|
479
|
+
|
|
480
|
+
## What works today
|
|
481
|
+
|
|
482
|
+
- `scan`, `check` (including `--message-file`, `--format json`, `--quiet`,
|
|
483
|
+
`--verbose`), `init`, `policy list`, with documented exit codes
|
|
484
|
+
- Git hook enforcement: `install`/`uninstall` (per repository, or `--global`
|
|
485
|
+
via a Git template directory), `hook pre-commit|commit-msg|pre-push`,
|
|
486
|
+
chaining of existing hooks, integrity checksums, fail-closed wrappers
|
|
487
|
+
- `doctor` with hook presence, integrity, interpreter, enforcement and GitHub
|
|
488
|
+
workflow checks (branch protection is reported as unverifiable)
|
|
489
|
+
- GitHub enforcement: `ci github` (pull_request, merge_group, push), trusted
|
|
490
|
+
policy source (base commit), bundled rules only, annotations, job summary,
|
|
491
|
+
step outputs, JSON report; composite `action.yml` with SHA-pinned actions and
|
|
492
|
+
hash-pinned dependencies; `init --github`; `github setup`
|
|
493
|
+
- Commit model with parsed trailers; lenient, bounded trailer parser that
|
|
494
|
+
records malformed and evasive variants instead of crashing
|
|
495
|
+
- Four detectors (`coauthor`, `identity`, `trailer`, `bot`) driven by YAML rules
|
|
496
|
+
- Detector registry, detection engine (fail closed), policy evaluator
|
|
497
|
+
- Layered, strictly validated configuration
|
|
498
|
+
- Hardened read-only Git access (no shell, `--end-of-options`, no mailmap /
|
|
499
|
+
replace objects, batched reads)
|
|
500
|
+
- Terminal-safe output and ASCII-only JSON
|
|
501
|
+
- GitHub App service: signed webhooks with replay protection, installation
|
|
502
|
+
lifecycle, repository authorization, down-scoped installation tokens,
|
|
503
|
+
metadata-only Git mirrors, Check Runs with stale-write protection,
|
|
504
|
+
mandatory policy floor, policy-weakening detection, SQLite state with
|
|
505
|
+
retention, audit events, structured logs with correlation IDs,
|
|
506
|
+
`/health` and `/ready`, `github validate`, `github webhook-test`, `github serve`
|
|
507
|
+
|
|
508
|
+
- Dashboard and `/api/v1`: GitHub sign-in, roles and tenant isolation,
|
|
509
|
+
overview, repositories with enforcement evidence, scans, violations with a
|
|
510
|
+
lifecycle, versioned organization policy, rules, audit log, installations
|
|
511
|
+
and sync, sessions and members; `commitguard dashboard members`
|
|
512
|
+
- Notifications: transactional outbox, in-app notification center,
|
|
513
|
+
organization and personal preferences, deduplication, SMTP e-mail and
|
|
514
|
+
HMAC-signed webhooks with bounded retries, delivery records and audit
|
|
515
|
+
- GitHub App merge queue validation (`merge_group`), GitHub "Re-run" and
|
|
516
|
+
"Re-run all checks" handling with numbered scan executions, stale re-run
|
|
517
|
+
protection, event processing records with safe redelivery, automatic retry
|
|
518
|
+
of infrastructure failures
|
|
519
|
+
- Organization policy rollback (immutable versions, rollback lineage, diff,
|
|
520
|
+
optimistic concurrency, audit and notification in one transaction)
|
|
521
|
+
- Organization governance: security settings and baseline, repository
|
|
522
|
+
onboarding (enforce / monitor mode), repository groups, background bulk
|
|
523
|
+
operations, organization/group/repository policies resolved per rule with
|
|
524
|
+
provenance and conflicts, effective policy cache with transactional
|
|
525
|
+
invalidation and propagation status, policy drafts and approvals, emergency
|
|
526
|
+
publication, read-only policy simulation, staged rollouts with automatic
|
|
527
|
+
halt and rollback, scoped expiring exceptions, organization identity rules
|
|
528
|
+
(data only), scheduled default-branch scans, posture, drift, trends, alert
|
|
529
|
+
digests, search and compliance reports
|
|
530
|
+
|
|
531
|
+
Not yet: PR comments, SARIF, signature verification, secret detection. The App and dashboard have not yet
|
|
532
|
+
been tested against github.com itself (only an offline model of the API and
|
|
533
|
+
OAuth flow plus real Git).
|
|
534
|
+
|
|
535
|
+
## Run the demo locally
|
|
536
|
+
|
|
537
|
+
The demo stack runs the real API, services and dashboard against an offline
|
|
538
|
+
model of GitHub, then replays a complete lifecycle: a blocked pull request and
|
|
539
|
+
its fix, a GitHub re-run, a merge group, a scan error, a policy change and its
|
|
540
|
+
rollback, an App suspension and reconnection, and notification delivery.
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
./scripts/install-dev.sh && source .venv/bin/activate
|
|
544
|
+
cd web && npm ci && npm run build && cd ..
|
|
545
|
+
python tests/e2e/dashboard_harness.py --demo # http://localhost:4173
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
Open <http://localhost:4173> and choose **Continue with GitHub** (signs in as
|
|
549
|
+
the owner, `alice`), or sign in as another role:
|
|
550
|
+
|
|
551
|
+
| User | Role | Sign-in link |
|
|
552
|
+
|---|---|---|
|
|
553
|
+
| `alice` | owner | <http://localhost:4173/demo/sign-in?user=501> |
|
|
554
|
+
| `ada` | admin | <http://localhost:4173/demo/sign-in?user=504> |
|
|
555
|
+
| `sam` | security manager | <http://localhost:4173/demo/sign-in?user=503> |
|
|
556
|
+
| `victor` | viewer | <http://localhost:4173/demo/sign-in?user=502> |
|
|
557
|
+
|
|
558
|
+
The demo keeps its data in a temporary directory, never contacts github.com,
|
|
559
|
+
and records e-mail and webhook deliveries in memory instead of sending them.
|
|
560
|
+
|
|
561
|
+
## Test evidence
|
|
562
|
+
|
|
563
|
+
<picture>
|
|
564
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/tests-dark.png">
|
|
565
|
+
<img alt="Test evidence: pytest, Vitest and Playwright results with static checks" src="docs/images/tests-light.png" width="100%">
|
|
566
|
+
</picture>
|
|
567
|
+
|
|
568
|
+
The card is rendered from [docs/evidence/tests.json](docs/evidence/tests.json),
|
|
569
|
+
which [scripts/readme_evidence.py](scripts/readme_evidence.py) writes from the
|
|
570
|
+
real test runs and checks; the live status of every push is the
|
|
571
|
+
[CI badge](https://github.com/oyinlola-tech/commitguard/actions/workflows/ci.yml).
|
|
572
|
+
To regenerate the evidence, terminal images and screenshots:
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
python scripts/readme_evidence.py # runs all suites and checks, writes docs/evidence/
|
|
576
|
+
cd web && npm run build && npm run screenshots # renders docs/images/
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
## Built with
|
|
580
|
+
|
|
581
|
+
| | |
|
|
582
|
+
|---|---|
|
|
583
|
+
| **Core and GitHub App** |      |
|
|
584
|
+
| **Dashboard** |     |
|
|
585
|
+
| **Quality** |      |
|
|
586
|
+
|
|
587
|
+
No AI or LLM API is called anywhere: detection is deterministic, offline and
|
|
588
|
+
driven by rule data.
|
|
589
|
+
|
|
590
|
+
## Development
|
|
591
|
+
|
|
592
|
+
Requires Python 3.12+ and Git 2.31+.
|
|
593
|
+
|
|
594
|
+
```bash
|
|
595
|
+
./scripts/install-dev.sh
|
|
596
|
+
source .venv/bin/activate
|
|
597
|
+
pytest
|
|
598
|
+
ruff check . && ruff format --check .
|
|
599
|
+
mypy
|
|
600
|
+
|
|
601
|
+
# Dashboard (Node.js 20.19+)
|
|
602
|
+
cd web && npm ci
|
|
603
|
+
npm test && npm run typecheck && npm run lint
|
|
604
|
+
npm run build && npm run e2e # browser tests against the full stack
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
## Roadmap
|
|
608
|
+
|
|
609
|
+
| Phase | Scope | Status |
|
|
610
|
+
|---|---|---|
|
|
611
|
+
| **1. Foundation** | project structure · CLI · configuration · Git abstraction · commit model · detector and policy interfaces · testing foundation |  |
|
|
612
|
+
| **2. AI attribution detection** | `Co-authored-by` parsing · AI identity and domain rules · identity detection · findings · blocking decisions |  |
|
|
613
|
+
| **3. Git enforcement** | `pre-commit` · `commit-msg` · `pre-push` · hook installation and management · local enforcement |  |
|
|
614
|
+
| **4. GitHub enforcement** | GitHub Actions check · pull request, merge queue and push scanning · trusted policy source · branch protection guidance |  |
|
|
615
|
+
| **5. GitHub App** | webhooks · App authentication · installation lifecycle · Check Runs · ScanService · EnforcementService · audit events · mandatory policy |  |
|
|
616
|
+
| **6. Security dashboard and control plane** | GitHub sign-in · roles and tenant isolation · enforcement evidence · scans · violation lifecycle · versioned organization policy · audit log · `/api/v1` |  |
|
|
617
|
+
| **7. Notifications, merge queue, re-runs, recovery** | notification outbox · in-app, e-mail and signed webhooks · deduplication and retries · merge group validation · scan executions · policy rollback and diff |  |
|
|
618
|
+
| **8. Organization governance** | organization policy hierarchy · repository groups · approvals and separation of duties · policy simulation · staged rollouts · scoped exceptions · security posture · compliance reports |  |
|
|
619
|
+
| **Later: security intelligence** | advanced bot detection · signed commit verification · secret detection · provenance analysis · SARIF |  |
|
|
620
|
+
|
|
621
|
+
## Documentation
|
|
622
|
+
|
|
623
|
+
- [Architecture](docs/architecture.md)
|
|
624
|
+
- [Detection engine](docs/detection-engine.md)
|
|
625
|
+
- [Policy engine](docs/policy-engine.md)
|
|
626
|
+
- [Configuration](docs/configuration.md)
|
|
627
|
+
- [Git hooks](docs/git-hooks.md)
|
|
628
|
+
- [GitHub enforcement (Actions)](docs/github-enforcement.md)
|
|
629
|
+
- [GitHub App](docs/github-app.md)
|
|
630
|
+
- [Dashboard and API](docs/dashboard.md)
|
|
631
|
+
- [Notifications](docs/notifications.md)
|
|
632
|
+
- [Merge queue](docs/merge-queue.md)
|
|
633
|
+
- [Policy management and rollback](docs/policy-management.md)
|
|
634
|
+
- [Organization governance](docs/organization-governance.md)
|
|
635
|
+
- [Policy inheritance](docs/policy-inheritance.md)
|
|
636
|
+
- [Policy simulation](docs/policy-simulation.md)
|
|
637
|
+
- [Policy exceptions](docs/policy-exceptions.md)
|
|
638
|
+
- [Staged policy rollouts](docs/policy-rollouts.md)
|
|
639
|
+
- [Repository management](docs/repository-management.md)
|
|
640
|
+
- [Security posture](docs/security-posture.md)
|
|
641
|
+
- [Compliance reporting](docs/compliance-reporting.md)
|
|
642
|
+
- [Recovery and failure handling](docs/recovery.md)
|
|
643
|
+
- [Deployment](docs/deployment/) — local, GitHub Actions, GitHub App, organization, production
|
|
644
|
+
|
|
645
|
+
**Getting started and reference**
|
|
646
|
+
|
|
647
|
+
- [5-minute quick start](docs/getting-started/quickstart.md)
|
|
648
|
+
- [Examples](examples/) — each one verified by a test against the real engine
|
|
649
|
+
- [CLI reference](docs/cli/) — every command, option and exit code
|
|
650
|
+
- [API reference](docs/api/)
|
|
651
|
+
- [Troubleshooting](docs/deployment/troubleshooting.md) · [Operations runbook](docs/operations/runbook.md)
|
|
652
|
+
- [Compatibility matrix](docs/support/compatibility.md)
|
|
653
|
+
|
|
654
|
+
**Security**
|
|
655
|
+
|
|
656
|
+
- [Security documentation](docs/security/) — threat model, boundaries, authorization matrix, review guide
|
|
657
|
+
- [Vulnerability response](docs/security/vulnerability-response.md) · [Incident response](docs/security/incident-response.md)
|
|
658
|
+
- [Supply chain](docs/security/supply-chain.md) — including the gaps
|
|
659
|
+
|
|
660
|
+
**Research and evidence**
|
|
661
|
+
|
|
662
|
+
- [Research index](docs/research/) — question, methodology, evaluations, limitations
|
|
663
|
+
- [Detection evaluation](docs/research/detection-evaluation.md) — accuracy, and the bypasses these benchmarks found
|
|
664
|
+
- [Performance evaluation](docs/research/performance-evaluation.md) · [Bypass resistance](docs/research/bypass-resistance.md)
|
|
665
|
+
- [Reproducibility](docs/research/reproducibility.md) — re-run all of it yourself
|
|
666
|
+
- [Limitations](docs/research/limitations.md) — read this one
|
|
667
|
+
- [Decision records](docs/adr/) · [Evidence timeline](docs/evidence/timeline.md) · [Validation matrix](docs/evidence/validation-matrix.md)
|
|
668
|
+
|
|
669
|
+
**Project**
|
|
670
|
+
|
|
671
|
+
- [Roadmap](ROADMAP.md) · [Maintainer docs](docs/maintainers/) · [Community](docs/community/)
|
|
672
|
+
|
|
673
|
+
## Evidence, in one command
|
|
674
|
+
|
|
675
|
+
```bash
|
|
676
|
+
commitguard reproduce all --evidence-dir evidence/security --results benchmarks/results
|
|
677
|
+
commitguard report security --results benchmarks/results --evidence evidence/security
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
Rebuilds the labelled dataset, verifies its fingerprint against the published
|
|
681
|
+
files, re-measures detection, runs 350 security tests, and regenerates the reports.
|
|
682
|
+
A step that cannot run reports `SKIPPED` with a reason — never a pass.
|
|
683
|
+
|
|
684
|
+
Measured 2026-09-17 on this machine: **0 false negatives and 0 false positives on
|
|
685
|
+
9,174 labelled cases**, after three real bypasses that these benchmarks found were
|
|
686
|
+
fixed. [All thirteen runs, including the failures](benchmarks/results/), are kept.
|
|
687
|
+
|
|
688
|
+
## Contributing, security, license
|
|
689
|
+
|
|
690
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md) · [good first issues](docs/community/good-first-issues.md)
|
|
691
|
+
- [SECURITY.md](SECURITY.md) — please report vulnerabilities and detection bypasses privately
|
|
692
|
+
- [External evaluation](docs/community/external-evaluation.md) — the most useful thing you can contribute
|
|
693
|
+
- [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
|
|
694
|
+
- [MIT License](LICENSE) · [CITATION.cff](CITATION.cff)
|