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.
Files changed (197) hide show
  1. commitguard/__init__.py +26 -0
  2. commitguard/__main__.py +6 -0
  3. commitguard/api/__init__.py +18 -0
  4. commitguard/api/app.py +1376 -0
  5. commitguard/api/governance.py +1085 -0
  6. commitguard/api/hosting.py +196 -0
  7. commitguard/api/http.py +252 -0
  8. commitguard/api/settings.py +169 -0
  9. commitguard/audit/__init__.py +13 -0
  10. commitguard/audit/logger.py +34 -0
  11. commitguard/audit/models.py +222 -0
  12. commitguard/audit/storage.py +59 -0
  13. commitguard/ci/__init__.py +7 -0
  14. commitguard/ci/context.py +60 -0
  15. commitguard/cli/__init__.py +6 -0
  16. commitguard/cli/app.py +74 -0
  17. commitguard/cli/commands/__init__.py +1 -0
  18. commitguard/cli/commands/benchmark.py +441 -0
  19. commitguard/cli/commands/check.py +100 -0
  20. commitguard/cli/commands/ci.py +165 -0
  21. commitguard/cli/commands/dashboard.py +141 -0
  22. commitguard/cli/commands/doctor.py +533 -0
  23. commitguard/cli/commands/github.py +449 -0
  24. commitguard/cli/commands/hook.py +156 -0
  25. commitguard/cli/commands/init.py +137 -0
  26. commitguard/cli/commands/install.py +152 -0
  27. commitguard/cli/commands/policy.py +36 -0
  28. commitguard/cli/commands/report.py +39 -0
  29. commitguard/cli/commands/reproduce.py +123 -0
  30. commitguard/cli/commands/scan.py +47 -0
  31. commitguard/cli/common.py +44 -0
  32. commitguard/cli/output.py +89 -0
  33. commitguard/cli/render.py +367 -0
  34. commitguard/config/__init__.py +6 -0
  35. commitguard/config/defaults.py +53 -0
  36. commitguard/config/enforcement.py +53 -0
  37. commitguard/config/loader.py +174 -0
  38. commitguard/config/schema.py +105 -0
  39. commitguard/config/sources.py +183 -0
  40. commitguard/controlplane/__init__.py +24 -0
  41. commitguard/controlplane/access.py +231 -0
  42. commitguard/controlplane/commands.py +393 -0
  43. commitguard/controlplane/errors.py +88 -0
  44. commitguard/controlplane/identity.py +478 -0
  45. commitguard/controlplane/members.py +219 -0
  46. commitguard/controlplane/notifications.py +787 -0
  47. commitguard/controlplane/pagination.py +146 -0
  48. commitguard/controlplane/policies.py +1204 -0
  49. commitguard/controlplane/queries.py +1814 -0
  50. commitguard/controlplane/results.py +909 -0
  51. commitguard/controlplane/rules.py +184 -0
  52. commitguard/controlplane/views.py +799 -0
  53. commitguard/core/__init__.py +6 -0
  54. commitguard/core/context.py +31 -0
  55. commitguard/core/decision.py +58 -0
  56. commitguard/core/engine.py +82 -0
  57. commitguard/core/result.py +177 -0
  58. commitguard/detectors/__init__.py +6 -0
  59. commitguard/detectors/base.py +58 -0
  60. commitguard/detectors/bot.py +87 -0
  61. commitguard/detectors/coauthor.py +86 -0
  62. commitguard/detectors/identity.py +76 -0
  63. commitguard/detectors/registry.py +72 -0
  64. commitguard/detectors/trailer.py +211 -0
  65. commitguard/exceptions/__init__.py +33 -0
  66. commitguard/exceptions/base.py +9 -0
  67. commitguard/exceptions/configuration.py +22 -0
  68. commitguard/exceptions/detection.py +11 -0
  69. commitguard/exceptions/git.py +41 -0
  70. commitguard/exceptions/service.py +25 -0
  71. commitguard/git/__init__.py +12 -0
  72. commitguard/git/commands.py +101 -0
  73. commitguard/git/commit.py +97 -0
  74. commitguard/git/diff.py +36 -0
  75. commitguard/git/hooks.py +527 -0
  76. commitguard/git/push.py +93 -0
  77. commitguard/git/ranges.py +71 -0
  78. commitguard/git/repository.py +447 -0
  79. commitguard/github/__init__.py +34 -0
  80. commitguard/github/actions.py +163 -0
  81. commitguard/github/app.py +935 -0
  82. commitguard/github/auth.py +217 -0
  83. commitguard/github/check_runs.py +172 -0
  84. commitguard/github/checks.py +210 -0
  85. commitguard/github/client.py +844 -0
  86. commitguard/github/enforcement_status.py +209 -0
  87. commitguard/github/errors.py +129 -0
  88. commitguard/github/events.py +563 -0
  89. commitguard/github/identifiers.py +90 -0
  90. commitguard/github/installations.py +566 -0
  91. commitguard/github/markdown.py +19 -0
  92. commitguard/github/permissions.py +70 -0
  93. commitguard/github/pull_requests.py +53 -0
  94. commitguard/github/queue.py +47 -0
  95. commitguard/github/recovery.py +124 -0
  96. commitguard/github/repositories.py +305 -0
  97. commitguard/github/server.py +52 -0
  98. commitguard/github/settings.py +174 -0
  99. commitguard/github/storage.py +2315 -0
  100. commitguard/github/webhooks.py +129 -0
  101. commitguard/github/worker.py +628 -0
  102. commitguard/github/workflow.py +286 -0
  103. commitguard/governance/__init__.py +26 -0
  104. commitguard/governance/bulk.py +765 -0
  105. commitguard/governance/cache.py +88 -0
  106. commitguard/governance/common.py +216 -0
  107. commitguard/governance/exceptions.py +861 -0
  108. commitguard/governance/groups.py +448 -0
  109. commitguard/governance/inventory.py +386 -0
  110. commitguard/governance/posture.py +1272 -0
  111. commitguard/governance/resolver.py +632 -0
  112. commitguard/governance/rollouts.py +760 -0
  113. commitguard/governance/rules.py +371 -0
  114. commitguard/governance/schedules.py +663 -0
  115. commitguard/governance/service.py +120 -0
  116. commitguard/governance/settings.py +365 -0
  117. commitguard/governance/simulation.py +618 -0
  118. commitguard/governance/workflow.py +734 -0
  119. commitguard/notifications/__init__.py +2 -0
  120. commitguard/notifications/channels/__init__.py +1 -0
  121. commitguard/notifications/channels/base.py +22 -0
  122. commitguard/notifications/channels/email.py +110 -0
  123. commitguard/notifications/channels/in_app.py +74 -0
  124. commitguard/notifications/channels/sink.py +58 -0
  125. commitguard/notifications/channels/webhook.py +233 -0
  126. commitguard/notifications/deduplication.py +57 -0
  127. commitguard/notifications/dispatcher.py +201 -0
  128. commitguard/notifications/models.py +439 -0
  129. commitguard/notifications/outbox.py +106 -0
  130. commitguard/notifications/preferences.py +224 -0
  131. commitguard/notifications/retry.py +282 -0
  132. commitguard/notifications/service.py +128 -0
  133. commitguard/notifications/settings.py +167 -0
  134. commitguard/notifications/templates.py +108 -0
  135. commitguard/observability/__init__.py +5 -0
  136. commitguard/observability/logging.py +161 -0
  137. commitguard/observability/metrics.py +105 -0
  138. commitguard/policies/__init__.py +6 -0
  139. commitguard/policies/defaults.py +48 -0
  140. commitguard/policies/evaluator.py +66 -0
  141. commitguard/policies/governance.py +498 -0
  142. commitguard/policies/loader.py +23 -0
  143. commitguard/policies/mandatory.py +52 -0
  144. commitguard/policies/model.py +46 -0
  145. commitguard/provenance/__init__.py +9 -0
  146. commitguard/provenance/author.py +146 -0
  147. commitguard/provenance/committer.py +16 -0
  148. commitguard/provenance/normalization.py +158 -0
  149. commitguard/provenance/signatures.py +34 -0
  150. commitguard/provenance/trailers.py +256 -0
  151. commitguard/research/__init__.py +26 -0
  152. commitguard/research/compare.py +231 -0
  153. commitguard/research/datasets.py +1484 -0
  154. commitguard/research/detection.py +183 -0
  155. commitguard/research/environment.py +185 -0
  156. commitguard/research/gitenv.py +108 -0
  157. commitguard/research/hooks.py +247 -0
  158. commitguard/research/metrics.py +85 -0
  159. commitguard/research/performance.py +194 -0
  160. commitguard/research/platform.py +288 -0
  161. commitguard/research/report.py +372 -0
  162. commitguard/research/repository.py +111 -0
  163. commitguard/research/reproduction.py +297 -0
  164. commitguard/research/results.py +94 -0
  165. commitguard/rules/__init__.py +11 -0
  166. commitguard/rules/data/ai-domains.yaml +51 -0
  167. commitguard/rules/data/ai-identities.yaml +131 -0
  168. commitguard/rules/data/bot-identities.yaml +53 -0
  169. commitguard/rules/data/patterns.yaml +52 -0
  170. commitguard/rules/loader.py +102 -0
  171. commitguard/rules/matcher.py +212 -0
  172. commitguard/rules/models.py +269 -0
  173. commitguard/security/__init__.py +5 -0
  174. commitguard/security/hashing.py +30 -0
  175. commitguard/security/rate_limit.py +33 -0
  176. commitguard/security/safe_yaml.py +69 -0
  177. commitguard/security/sanitization.py +85 -0
  178. commitguard/security/secrets.py +169 -0
  179. commitguard/security/validation.py +89 -0
  180. commitguard/services/__init__.py +15 -0
  181. commitguard/services/analysis.py +119 -0
  182. commitguard/services/audit.py +95 -0
  183. commitguard/services/ci.py +383 -0
  184. commitguard/services/enforcement.py +102 -0
  185. commitguard/services/hooks.py +254 -0
  186. commitguard/services/remediation.py +99 -0
  187. commitguard/services/reports.py +146 -0
  188. commitguard/services/scan.py +172 -0
  189. commitguard/utils/__init__.py +1 -0
  190. commitguard/utils/filesystem.py +72 -0
  191. commitguard/utils/platform.py +35 -0
  192. commitguard/utils/subprocess.py +84 -0
  193. commitguardian-0.1.0.dist-info/METADATA +694 -0
  194. commitguardian-0.1.0.dist-info/RECORD +197 -0
  195. commitguardian-0.1.0.dist-info/WHEEL +4 -0
  196. commitguardian-0.1.0.dist-info/entry_points.txt +2 -0
  197. commitguardian-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,184 @@
1
+ """The rule catalogue shown in the dashboard.
2
+
3
+ Rule IDs are the IDs the detectors emit and policies configure - the same
4
+ ``ai_coauthor`` the CLI, hooks, GitHub Action and GitHub App print. This module
5
+ only *describes* them for display (name, detector, severity, remediation
6
+ steps); detection stays in :mod:`commitguard.detectors` and decisions in
7
+ :mod:`commitguard.policies`. A unit test checks that the catalogue matches the
8
+ registered detectors, the built-in policies and the severities the detectors
9
+ actually emit, so the description cannot drift from the behaviour.
10
+
11
+ Rules are bundled with the installed package and are trusted; there are no
12
+ repository-defined rules, so nothing here is editable from the dashboard.
13
+ """
14
+
15
+ from dataclasses import dataclass
16
+ from functools import cache
17
+
18
+ from commitguard import __version__
19
+ from commitguard.controlplane.views import RuleDataFile, RuleDetail, RuleView
20
+ from commitguard.core.result import EvidenceSource, Severity
21
+ from commitguard.policies.defaults import DEFAULT_POLICIES
22
+ from commitguard.rules.loader import builtin_rules_fingerprint, load_builtin_rules
23
+ from commitguard.rules.models import (
24
+ AI_DOMAINS_FILE,
25
+ AI_IDENTITIES_FILE,
26
+ BOT_IDENTITIES_FILE,
27
+ PATTERNS_FILE,
28
+ )
29
+
30
+ RULES_VERSION_LENGTH = 12
31
+ NO_REWRITE_NOTICE = "CommitGuard does not rewrite Git history or modify commits automatically."
32
+
33
+
34
+ @dataclass(frozen=True, slots=True)
35
+ class RuleDescription:
36
+ rule_id: str
37
+ name: str
38
+ detector: str
39
+ severity: Severity
40
+ evidence_sources: tuple[EvidenceSource, ...]
41
+ data_files: tuple[str, ...]
42
+ steps: tuple[str, ...]
43
+
44
+
45
+ _HISTORY_STEPS = (
46
+ "Rewrite the affected commit on your branch (for example `git commit --amend` for the "
47
+ "latest commit, or an interactive rebase for older ones) and push the corrected branch.",
48
+ "CommitGuard scans the updated pull request or branch automatically; the violation is "
49
+ "resolved when the commit is no longer part of it.",
50
+ )
51
+
52
+ CATALOG: tuple[RuleDescription, ...] = (
53
+ RuleDescription(
54
+ rule_id="ai_coauthor",
55
+ name="AI co-author attribution",
56
+ detector="coauthor",
57
+ severity=Severity.HIGH,
58
+ evidence_sources=(EvidenceSource.COAUTHOR_TRAILER,),
59
+ data_files=(PATTERNS_FILE, AI_IDENTITIES_FILE, AI_DOMAINS_FILE),
60
+ steps=(
61
+ "Remove the Co-authored-by line that names the AI agent from the commit message.",
62
+ *_HISTORY_STEPS,
63
+ ),
64
+ ),
65
+ RuleDescription(
66
+ rule_id="ai_identity",
67
+ name="AI agent as author or committer",
68
+ detector="identity",
69
+ severity=Severity.HIGH,
70
+ evidence_sources=(EvidenceSource.AUTHOR, EvidenceSource.COMMITTER),
71
+ data_files=(AI_IDENTITIES_FILE, AI_DOMAINS_FILE),
72
+ steps=(
73
+ "Recreate the commit under the responsible human contributor's identity "
74
+ "(for example `git commit --amend --reset-author`).",
75
+ *_HISTORY_STEPS,
76
+ ),
77
+ ),
78
+ RuleDescription(
79
+ rule_id="ai_trailer",
80
+ name="AI attribution trailer or footer",
81
+ detector="trailer",
82
+ severity=Severity.HIGH,
83
+ evidence_sources=(EvidenceSource.TRAILER, EvidenceSource.MESSAGE),
84
+ data_files=(PATTERNS_FILE,),
85
+ steps=(
86
+ "Remove the attribution trailer or tool-generated footer from the commit message.",
87
+ *_HISTORY_STEPS,
88
+ ),
89
+ ),
90
+ RuleDescription(
91
+ rule_id="malformed_trailer",
92
+ name="Malformed trailer",
93
+ detector="trailer",
94
+ severity=Severity.LOW,
95
+ evidence_sources=(EvidenceSource.TRAILER,),
96
+ data_files=(PATTERNS_FILE,),
97
+ steps=(
98
+ "Rewrite the trailer as `Key: Name <email>` or remove it; malformed trailers can be "
99
+ "used to hide attribution from parsers.",
100
+ *_HISTORY_STEPS,
101
+ ),
102
+ ),
103
+ RuleDescription(
104
+ rule_id="bot_identity",
105
+ name="Automation or bot identity",
106
+ detector="bot",
107
+ severity=Severity.LOW,
108
+ evidence_sources=(
109
+ EvidenceSource.AUTHOR,
110
+ EvidenceSource.COMMITTER,
111
+ EvidenceSource.COAUTHOR_TRAILER,
112
+ ),
113
+ data_files=(BOT_IDENTITIES_FILE,),
114
+ steps=(
115
+ "Confirm the automation is expected in this repository.",
116
+ "If it is, an administrator can lower the policy for bot_identity in the repository's "
117
+ "trusted .commitguard.yaml; otherwise investigate where the commit came from.",
118
+ ),
119
+ ),
120
+ )
121
+
122
+ CATALOG_BY_ID = {entry.rule_id: entry for entry in CATALOG}
123
+
124
+
125
+ def rules_version() -> str:
126
+ return builtin_rules_fingerprint()[:RULES_VERSION_LENGTH]
127
+
128
+
129
+ def remediation_steps(rule_id: str) -> tuple[str, ...]:
130
+ entry = CATALOG_BY_ID.get(rule_id)
131
+ steps = entry.steps if entry else ()
132
+ return (*steps, NO_REWRITE_NOTICE)
133
+
134
+
135
+ def rule_view(entry: RuleDescription) -> RuleView:
136
+ policy = DEFAULT_POLICIES[entry.rule_id]
137
+ return RuleView(
138
+ id=entry.rule_id,
139
+ name=entry.name,
140
+ description=policy.description,
141
+ detector=entry.detector,
142
+ severity=entry.severity,
143
+ default_action=policy.action,
144
+ source="bundled",
145
+ trusted=True,
146
+ status="active",
147
+ rules_version=rules_version(),
148
+ tool_version=__version__,
149
+ )
150
+
151
+
152
+ def list_rules() -> tuple[RuleView, ...]:
153
+ return tuple(rule_view(entry) for entry in CATALOG)
154
+
155
+
156
+ @cache
157
+ def _data_file_entries() -> dict[str, int]:
158
+ rules = load_builtin_rules().rules
159
+ patterns = rules.patterns
160
+ return {
161
+ AI_IDENTITIES_FILE: len(rules.ai_identities.agents),
162
+ AI_DOMAINS_FILE: len(rules.ai_domains.domains),
163
+ BOT_IDENTITIES_FILE: len(rules.bots.bots),
164
+ PATTERNS_FILE: len(patterns.coauthor_trailer_keys)
165
+ + len(patterns.attribution_trailers)
166
+ + len(patterns.malformed_trailer_checks)
167
+ + len(patterns.message_markers),
168
+ }
169
+
170
+
171
+ def rule_detail(rule_id: str) -> RuleDetail | None:
172
+ entry = CATALOG_BY_ID.get(rule_id)
173
+ if entry is None:
174
+ return None
175
+ counts = _data_file_entries()
176
+ return RuleDetail(
177
+ rule=rule_view(entry),
178
+ remediation=remediation_steps(rule_id),
179
+ evidence_sources=tuple(source.label for source in entry.evidence_sources),
180
+ data_files=tuple(
181
+ RuleDataFile(name=name, entries=counts[name]) for name in entry.data_files
182
+ ),
183
+ editable=False,
184
+ )