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,799 @@
1
+ """The dashboard API's resource models (the ``data`` of API responses).
2
+
3
+ These are the public contract of ``/api/v1``. They are built from database
4
+ rows by the query services and deliberately differ from them: internal columns
5
+ (leases, job keys, delivery IDs, session hashes) never appear here, and every
6
+ status is one value of a closed vocabulary decided by the server. The
7
+ dashboard renders these values; it never derives a security decision itself.
8
+
9
+ Status vocabulary
10
+ =================
11
+
12
+ ===================== ================================================================
13
+ Field Values
14
+ ===================== ================================================================
15
+ scan ``result`` ``queued`` ``running`` ``pass`` ``warning`` ``blocked``
16
+ ``error`` ``cancelled`` ``stale``
17
+ scan ``trigger`` ``push`` ``pull_request`` ``merge_group`` ``manual`` ``rerun``
18
+ ``retry``
19
+ violation ``status`` ``open`` ``acknowledged`` ``resolved``
20
+ ``protection`` ``protected`` ``at_risk`` ``unprotected`` ``configuration_error``
21
+ ``unknown``
22
+ merge queue ``enabled`` ``not_enabled`` ``unknown``
23
+ notification ``state`` ``unread`` ``read`` ``archived``
24
+ GitHub App ``connected`` ``suspended`` ``disconnected``
25
+ GitHub Actions ``detected`` ``not_detected`` ``unknown``
26
+ required check ``required`` ``not_required`` ``unknown``
27
+ local hooks ``not_verifiable``
28
+ integration ``connected`` ``action_required`` ``disconnected``
29
+ severity ``info`` ``low`` ``medium`` ``high`` ``critical`` (core model)
30
+ policy action ``allow`` ``warn`` ``block`` (core model)
31
+ ===================== ================================================================
32
+ """
33
+
34
+ from datetime import datetime
35
+ from enum import StrEnum
36
+ from typing import Literal
37
+
38
+ from pydantic import BaseModel, ConfigDict
39
+
40
+ from commitguard.core.decision import Action
41
+ from commitguard.core.result import Severity
42
+
43
+
44
+ class _View(BaseModel):
45
+ model_config = ConfigDict(frozen=True, extra="forbid")
46
+
47
+
48
+ # --------------------------------------------------------------------------- #
49
+ # Vocabulary
50
+ # --------------------------------------------------------------------------- #
51
+ class ScanResultStatus(StrEnum):
52
+ QUEUED = "queued"
53
+ RUNNING = "running"
54
+ PASS = "pass" # noqa: S105 - status name, not a password
55
+ WARNING = "warning"
56
+ BLOCKED = "blocked"
57
+ ERROR = "error"
58
+ CANCELLED = "cancelled"
59
+ STALE = "stale" # superseded before it could publish: a newer execution owns the check
60
+
61
+
62
+ class ViolationStatus(StrEnum):
63
+ OPEN = "open"
64
+ ACKNOWLEDGED = "acknowledged"
65
+ RESOLVED = "resolved"
66
+
67
+
68
+ class ProtectionStatus(StrEnum):
69
+ PROTECTED = "protected"
70
+ AT_RISK = "at_risk" # the GitHub App lost access: enforcement may no longer run
71
+ UNPROTECTED = "unprotected"
72
+ CONFIGURATION_ERROR = "configuration_error"
73
+ UNKNOWN = "unknown"
74
+
75
+
76
+ class AppConnection(StrEnum):
77
+ CONNECTED = "connected"
78
+ SUSPENDED = "suspended"
79
+ DISCONNECTED = "disconnected"
80
+
81
+
82
+ class ActionsStatus(StrEnum):
83
+ DETECTED = "detected"
84
+ NOT_DETECTED = "not_detected"
85
+ UNKNOWN = "unknown"
86
+
87
+
88
+ class RequiredCheckStatus(StrEnum):
89
+ REQUIRED = "required"
90
+ NOT_REQUIRED = "not_required"
91
+ UNKNOWN = "unknown"
92
+
93
+
94
+ class MergeQueueStatus(StrEnum):
95
+ ENABLED = "enabled"
96
+ NOT_ENABLED = "not_enabled"
97
+ UNKNOWN = "unknown"
98
+
99
+
100
+ class IntegrationStatus(StrEnum):
101
+ CONNECTED = "connected"
102
+ ACTION_REQUIRED = "action_required"
103
+ DISCONNECTED = "disconnected"
104
+
105
+
106
+ class HealthCheckStatus(StrEnum):
107
+ OK = "ok"
108
+ ATTENTION = "attention"
109
+ UNKNOWN = "unknown"
110
+
111
+
112
+ # --------------------------------------------------------------------------- #
113
+ # Shared fragments
114
+ # --------------------------------------------------------------------------- #
115
+ class OrganizationRef(_View):
116
+ id: int
117
+ login: str
118
+ type: str
119
+
120
+
121
+ class RepositoryLink(_View):
122
+ id: int
123
+ installation_id: int
124
+ full_name: str
125
+
126
+
127
+ class ActorView(_View):
128
+ type: Literal["system", "github", "user"]
129
+ id: int | None = None
130
+ login: str | None = None
131
+
132
+
133
+ class PolicyEntry(_View):
134
+ id: str
135
+ enabled: bool
136
+ action: Action
137
+
138
+
139
+ # --------------------------------------------------------------------------- #
140
+ # Scans and findings
141
+ # --------------------------------------------------------------------------- #
142
+ class ScanSummary(_View):
143
+ id: str
144
+ scan_id: str | None
145
+ repository: RepositoryLink
146
+ organization_id: int | None
147
+ event: str
148
+ pull_request_number: int | None
149
+ ref: str | None
150
+ base_sha: str | None
151
+ head_sha: str
152
+ check_name: str
153
+ result: ScanResultStatus
154
+ commits_scanned: int | None
155
+ violations: int | None
156
+ warnings: int | None
157
+ findings: int | None
158
+ created_at: datetime
159
+ started_at: datetime | None
160
+ completed_at: datetime | None
161
+ duration_ms: int | None
162
+ requested_by: str | None
163
+ trigger: str
164
+ execution: int
165
+ failure_source: Literal["pull_request", "push", "merge_queue"]
166
+
167
+
168
+ class MatchView(_View):
169
+ kind: str
170
+ value: str
171
+ rule: str
172
+
173
+
174
+ class EvidenceView(_View):
175
+ source: str
176
+ source_label: str
177
+ value: str
178
+ line_number: int | None
179
+ matched: tuple[MatchView, ...]
180
+ notes: tuple[str, ...]
181
+
182
+
183
+ class FindingView(_View):
184
+ id: int
185
+ violation_id: str | None
186
+ rule_id: str
187
+ detector: str
188
+ title: str
189
+ message: str
190
+ severity: Severity
191
+ confidence: str
192
+ action: Action
193
+ reason: str
194
+ commit_sha: str | None
195
+ author: str | None
196
+ committer: str | None
197
+ evidence: tuple[EvidenceView, ...]
198
+ remediation: str
199
+
200
+
201
+ class ScanFailure(_View):
202
+ kind: str | None
203
+ message: str
204
+
205
+
206
+ class ScanDetail(_View):
207
+ scan: ScanSummary
208
+ conclusion: str | None
209
+ tool_version: str | None
210
+ rules_version: str | None
211
+ policy_version: str | None
212
+ policy_source: str | None
213
+ organization_policy_version: int | None
214
+ effective_policies: tuple[PolicyEntry, ...]
215
+ detector_failures: int | None
216
+ notices: tuple[str, ...]
217
+ failure: ScanFailure | None
218
+ findings: tuple[FindingView, ...]
219
+ can_rescan: bool
220
+ rescan_blocked_reason: str | None
221
+ executions: int
222
+ latest_execution: str
223
+ merge_group: "MergeGroupView | None" = None
224
+
225
+
226
+ class ExecutionView(_View):
227
+ """One execution of a logical scan (same repository, commits and check)."""
228
+
229
+ id: str
230
+ execution: int
231
+ trigger: str
232
+ current: bool # the newest execution: it determines the current status
233
+ result: ScanResultStatus
234
+ head_sha: str
235
+ base_sha: str | None
236
+ organization_policy_version: int | None
237
+ policy_version: str | None
238
+ rules_version: str | None
239
+ tool_version: str | None
240
+ conclusion: str | None
241
+ requested_by: str | None
242
+ failure: ScanFailure | None
243
+ created_at: datetime
244
+ started_at: datetime | None
245
+ completed_at: datetime | None
246
+ duration_ms: int | None
247
+
248
+
249
+ class ExecutionHistory(_View):
250
+ scan_id: str
251
+ items: tuple[ExecutionView, ...]
252
+ policy_changed: bool # executions were evaluated under different policy versions
253
+ rules_changed: bool
254
+
255
+
256
+ class ScanComparison(_View):
257
+ scan_id: str
258
+ previous_scan_id: str | None
259
+ new: tuple[str, ...] # finding fingerprints
260
+ resolved: tuple[str, ...]
261
+ unchanged: tuple[str, ...]
262
+ new_findings: tuple[FindingView, ...]
263
+ resolved_findings: tuple[FindingView, ...]
264
+
265
+
266
+ # --------------------------------------------------------------------------- #
267
+ # Violations
268
+ # --------------------------------------------------------------------------- #
269
+ class ViolationSummary(_View):
270
+ id: str
271
+ rule_id: str
272
+ title: str
273
+ severity: Severity
274
+ action: Action
275
+ repository: RepositoryLink
276
+ organization_id: int | None
277
+ commit_sha: str | None
278
+ author: str | None
279
+ status: ViolationStatus
280
+ first_detected_at: datetime
281
+ last_detected_at: datetime
282
+ detections: int
283
+
284
+
285
+ class ExposureView(_View):
286
+ kind: Literal["pull_request", "branch", "merge_group"]
287
+ label: str
288
+ active: bool
289
+ opened_at: datetime
290
+ closed_at: datetime | None
291
+ closed_reason: str | None
292
+
293
+
294
+ class AcknowledgementView(_View):
295
+ by: str | None
296
+ at: datetime
297
+ note: str | None
298
+
299
+
300
+ class DetectionView(_View):
301
+ scan: str
302
+ result: ScanResultStatus
303
+ detected_at: datetime
304
+ action: Action
305
+ head_sha: str
306
+
307
+
308
+ class ViolationDetail(_View):
309
+ violation: ViolationSummary
310
+ detector: str
311
+ message: str
312
+ committer: str | None
313
+ policy_reason: str
314
+ evidence: tuple[EvidenceView, ...]
315
+ remediation: str
316
+ recommended_steps: tuple[str, ...]
317
+ resolved_at: datetime | None
318
+ resolution: str | None
319
+ acknowledgement: AcknowledgementView | None
320
+ exposures: tuple[ExposureView, ...]
321
+ detections: tuple[DetectionView, ...]
322
+ first_scan_id: str
323
+ last_scan_id: str
324
+ can_manage: bool
325
+
326
+
327
+ # --------------------------------------------------------------------------- #
328
+ # Repositories
329
+ # --------------------------------------------------------------------------- #
330
+ class EnforcementSignal(_View):
331
+ status: str
332
+ detail: str
333
+ checked_at: datetime | None = None
334
+
335
+
336
+ class RequiredCheckSignal(_View):
337
+ status: RequiredCheckStatus
338
+ branch: str | None
339
+ required_checks: tuple[str, ...]
340
+ detail: str
341
+ checked_at: datetime | None
342
+
343
+
344
+ class LatestCheckSignal(_View):
345
+ result: ScanResultStatus | None
346
+ scan: str | None
347
+ head_sha: str | None
348
+ completed_at: datetime | None
349
+
350
+
351
+ class EnforcementView(_View):
352
+ github_app: EnforcementSignal
353
+ github_actions: EnforcementSignal
354
+ required_check: RequiredCheckSignal
355
+ latest_check: LatestCheckSignal
356
+ local_hooks: EnforcementSignal
357
+ merge_queue: EnforcementSignal
358
+ monitoring_enabled: bool
359
+
360
+
361
+ class RepositorySummary(_View):
362
+ id: int
363
+ installation_id: int
364
+ organization: OrganizationRef | None
365
+ owner: str
366
+ name: str
367
+ full_name: str
368
+ github_url: str
369
+ default_branch: str | None
370
+ protection: ProtectionStatus
371
+ protection_reason: str
372
+ app_connection: AppConnection
373
+ monitoring_enabled: bool
374
+ last_scan: ScanSummary | None
375
+ open_violations: int
376
+ open_warnings: int
377
+ critical_open: int
378
+
379
+
380
+ class RepositoryPermissions(_View):
381
+ manage: bool
382
+ trigger_scans: bool
383
+ read_audit: bool
384
+
385
+
386
+ class RepositoryDetail(_View):
387
+ repository: RepositorySummary
388
+ enforcement: EnforcementView
389
+ organization_policy_version: int | None
390
+ effective_policies: tuple[PolicyEntry, ...]
391
+ effective_policy_scan: str | None
392
+ recent_scans: tuple[ScanSummary, ...]
393
+ open_violations: tuple[ViolationSummary, ...]
394
+ audit: tuple["AuditEventView", ...]
395
+ permissions: RepositoryPermissions
396
+
397
+
398
+ class MergeGroupView(_View):
399
+ head_sha: str
400
+ base_sha: str
401
+ base_ref: str
402
+ pull_requests: tuple[int, ...]
403
+ state: Literal["checks_requested", "destroyed"]
404
+ destroyed_reason: str | None
405
+ result: ScanResultStatus | None
406
+ scan: str | None
407
+ created_at: datetime
408
+ updated_at: datetime
409
+ validated_at: datetime | None
410
+
411
+
412
+ class MergeQueueView(_View):
413
+ repository_id: int
414
+ status: MergeQueueStatus
415
+ detail: str
416
+ checked_at: datetime | None
417
+ permission: Literal["granted", "missing"]
418
+ current: MergeGroupView | None
419
+ recent: tuple[MergeGroupView, ...]
420
+
421
+
422
+ # --------------------------------------------------------------------------- #
423
+ # Policies and rules
424
+ # --------------------------------------------------------------------------- #
425
+ class PolicyRuleView(_View):
426
+ policy_id: str
427
+ name: str
428
+ description: str
429
+ default_action: Action
430
+ service_floor: Action | None # operator's mandatory policy file
431
+ organization_floor: Action | None
432
+ minimum_action: Action | None # strongest floor; None = repository decides
433
+ repository_override: Literal["any", "stricter_only"]
434
+ source: Literal[
435
+ "built_in_default", "service_policy", "organization_policy", "organization_default"
436
+ ]
437
+ #: A default-strength organization entry: the baseline repositories may change.
438
+ organization_default: Action | None = None
439
+
440
+
441
+ class PolicyAuthor(_View):
442
+ id: int | None
443
+ login: str | None
444
+
445
+
446
+ class OrganizationPolicyView(_View):
447
+ organization: OrganizationRef
448
+ version: int
449
+ fingerprint: str | None
450
+ updated_at: datetime | None
451
+ updated_by: PolicyAuthor | None
452
+ reason: str | None
453
+ service_policy: str | None
454
+ rules: tuple[PolicyRuleView, ...]
455
+ can_write: bool
456
+
457
+
458
+ class PolicyChange(_View):
459
+ policy_id: str
460
+ old: Action | None
461
+ new: Action | None
462
+ weakening: bool
463
+ enforcement: Literal["mandatory", "default"] = "mandatory"
464
+
465
+
466
+ class PolicyVersionView(_View):
467
+ version: int
468
+ fingerprint: str
469
+ floors: dict[str, Action]
470
+ created_at: datetime
471
+ created_by: PolicyAuthor
472
+ reason: str | None
473
+ status: Literal["active", "archived"]
474
+ kind: Literal["change", "rollback"]
475
+ rollback_of: int | None # rollback: the version that was active before
476
+ restored_version: int | None # rollback: the version whose document was restored
477
+ changes: tuple[PolicyChange, ...] # compared with the previous version
478
+ summary: str
479
+ defaults: dict[str, Action] = {} # default-strength entries (Phase 8)
480
+ draft_id: str | None = None # the reviewed draft this version was published from
481
+ emergency: bool = False # published without the approval workflow
482
+
483
+
484
+ class PolicyDiffEntry(_View):
485
+ policy_id: str
486
+ old: Action | None = None
487
+ new: Action | None = None
488
+ weakening: bool = False
489
+ enforcement: Literal["mandatory", "default"] = "mandatory"
490
+
491
+
492
+ class PolicyDiffView(_View):
493
+ from_version: int
494
+ to_version: int
495
+ added: tuple[PolicyDiffEntry, ...]
496
+ changed: tuple[PolicyDiffEntry, ...]
497
+ removed: tuple[PolicyDiffEntry, ...]
498
+ weakening: bool
499
+
500
+
501
+ class PolicyTargetView(_View):
502
+ type: Literal["organization", "group", "repository"]
503
+ id: str # "" for the organization, a group ID or a repository ID
504
+ label: str
505
+
506
+
507
+ class ScopedRuleView(_View):
508
+ policy_id: str
509
+ name: str
510
+ mandatory: Action | None
511
+ default: Action | None
512
+
513
+
514
+ class ScopedPolicyView(_View):
515
+ """A repository group's or repository's published policy."""
516
+
517
+ organization: OrganizationRef
518
+ target: PolicyTargetView
519
+ version: int # 0: nothing published yet
520
+ fingerprint: str | None
521
+ updated_at: datetime | None
522
+ updated_by: PolicyAuthor | None
523
+ reason: str | None
524
+ rules: tuple[ScopedRuleView, ...]
525
+ can_write: bool
526
+
527
+
528
+ class RuleView(_View):
529
+ id: str
530
+ name: str
531
+ description: str
532
+ detector: str
533
+ severity: Severity
534
+ default_action: Action
535
+ source: Literal["bundled"]
536
+ trusted: bool
537
+ status: Literal["active"]
538
+ rules_version: str
539
+ tool_version: str
540
+
541
+
542
+ class RuleDataFile(_View):
543
+ name: str
544
+ entries: int
545
+
546
+
547
+ class RuleDetail(_View):
548
+ rule: RuleView
549
+ remediation: tuple[str, ...]
550
+ evidence_sources: tuple[str, ...]
551
+ data_files: tuple[RuleDataFile, ...]
552
+ editable: bool
553
+
554
+
555
+ # --------------------------------------------------------------------------- #
556
+ # Audit
557
+ # --------------------------------------------------------------------------- #
558
+ class AuditEventView(_View):
559
+ id: str
560
+ type: str
561
+ occurred_at: datetime
562
+ actor: ActorView
563
+ organization_id: int | None
564
+ installation_id: int | None
565
+ repository: RepositoryLink | None
566
+ head_sha: str | None
567
+ action: Action | None
568
+ summary: str
569
+ data: dict[str, str | int | bool | None]
570
+ scan: str | None
571
+
572
+
573
+ # --------------------------------------------------------------------------- #
574
+ # GitHub
575
+ # --------------------------------------------------------------------------- #
576
+ class InstallationView(_View):
577
+ id: int
578
+ account: OrganizationRef
579
+ status: AppConnection
580
+ repository_selection: str
581
+ repositories: int
582
+ permissions: dict[str, str]
583
+ missing_permissions: tuple[str, ...]
584
+ excessive_permissions: tuple[str, ...]
585
+ installed_at: datetime
586
+ updated_at: datetime
587
+ last_event_at: datetime | None
588
+ github_settings_url: str
589
+ can_manage: bool
590
+
591
+
592
+ class InstallationRepositoryView(_View):
593
+ id: int
594
+ full_name: str
595
+ connected: bool
596
+ monitoring_enabled: bool
597
+ added_at: datetime | None
598
+ removed_at: datetime | None
599
+
600
+
601
+ class InstallationDetail(_View):
602
+ installation: InstallationView
603
+ recent_events: tuple[AuditEventView, ...]
604
+
605
+
606
+ class SyncResult(_View):
607
+ installation_id: int
608
+ repositories: int
609
+ added: tuple[str, ...]
610
+ removed: tuple[str, ...]
611
+ synced_at: datetime
612
+
613
+
614
+ # --------------------------------------------------------------------------- #
615
+ # Overview
616
+ # --------------------------------------------------------------------------- #
617
+ class OverviewPeriod(_View):
618
+ key: Literal["24h", "7d", "30d"]
619
+ start: datetime
620
+ end: datetime
621
+
622
+
623
+ class OverviewSummary(_View):
624
+ repositories_monitored: int
625
+ repositories_protected: int
626
+ repositories_at_risk: int
627
+ repositories_unprotected: int
628
+ repositories_unknown: int
629
+ repositories_configuration_error: int
630
+ scans: int
631
+ scans_passed: int
632
+ scans_blocked: int
633
+ scans_error: int
634
+ open_violations: int
635
+ open_warnings: int
636
+ critical_open: int
637
+ high_open: int
638
+
639
+
640
+ class IntegrationView(_View):
641
+ status: IntegrationStatus
642
+ installations_connected: int
643
+ installations_suspended: int
644
+ installations_disconnected: int
645
+ detail: str
646
+
647
+
648
+ class HealthCheck(_View):
649
+ id: str
650
+ label: str
651
+ status: HealthCheckStatus
652
+ detail: str
653
+
654
+
655
+ class OverviewView(_View):
656
+ period: OverviewPeriod
657
+ summary: OverviewSummary
658
+ integration: IntegrationView
659
+ health: tuple[HealthCheck, ...]
660
+ recent_scans: tuple[ScanSummary, ...]
661
+ recent_violations: tuple[ViolationSummary, ...]
662
+ repository_health: tuple[RepositorySummary, ...]
663
+
664
+
665
+ # --------------------------------------------------------------------------- #
666
+ # Notifications
667
+ # --------------------------------------------------------------------------- #
668
+ class NotificationView(_View):
669
+ id: str
670
+ type: str
671
+ category: str
672
+ severity: Severity
673
+ state: Literal["unread", "read", "archived"]
674
+ title: str
675
+ body: str
676
+ organization_id: int
677
+ repository: RepositoryLink | None
678
+ resource_type: str
679
+ resource_id: str
680
+ link: str | None
681
+ occurrences: int
682
+ created_at: datetime
683
+ last_occurred_at: datetime
684
+ read_at: datetime | None
685
+
686
+
687
+ class NotificationCounts(_View):
688
+ unread: int # at most 1000
689
+ unread_critical: int
690
+ capped: bool # more unread notifications than counted
691
+
692
+
693
+ class ChannelPreferenceView(_View):
694
+ in_app: bool
695
+ email: bool
696
+ webhook: bool
697
+
698
+
699
+ class TypePreferenceView(_View):
700
+ type: str
701
+ label: str
702
+ description: str
703
+ category: str
704
+ mandatory_in_app: bool
705
+ organization: ChannelPreferenceView
706
+ personal_in_app: bool # the member's own inbox (always true when mandatory)
707
+ receives_in_app: bool # the member's role receives this type at all
708
+
709
+
710
+ class NotificationChannelsView(_View):
711
+ in_app: bool
712
+ email: bool
713
+ webhook: bool
714
+ mode: Literal["off", "deliver", "test"]
715
+
716
+
717
+ class WebhookEndpointView(_View):
718
+ id: str
719
+ url: str
720
+ created_at: datetime
721
+ created_by: str | None
722
+
723
+
724
+ class NotificationDeliveryView(_View):
725
+ id: str
726
+ notification_type: str
727
+ title: str
728
+ channel: str
729
+ destination: str
730
+ status: Literal["pending", "sent", "failed", "cancelled"]
731
+ attempts: int
732
+ failure_code: str | None
733
+ last_attempt_at: datetime | None
734
+ next_retry_at: datetime | None
735
+ created_at: datetime
736
+
737
+
738
+ class OrganizationNotificationSettingsView(_View):
739
+ organization: OrganizationRef
740
+ version: int
741
+ updated_at: datetime | None
742
+ updated_by: str | None
743
+ channels: NotificationChannelsView
744
+ types: tuple[TypePreferenceView, ...]
745
+ email_recipients: tuple[str, ...] # only for notifications:manage
746
+ webhooks: tuple[WebhookEndpointView, ...] # only for notifications:manage
747
+ can_manage: bool
748
+
749
+
750
+ class CreatedWebhookView(_View):
751
+ endpoint: WebhookEndpointView
752
+ signing_secret: str # shown once; CommitGuard does not store it
753
+
754
+
755
+ # --------------------------------------------------------------------------- #
756
+ # Accounts, members and sessions
757
+ # --------------------------------------------------------------------------- #
758
+ class OrganizationView(_View):
759
+ organization: OrganizationRef
760
+ role: str
761
+ implicit_role: bool
762
+ permissions: tuple[str, ...]
763
+ installation_ids: tuple[int, ...]
764
+
765
+
766
+ class MemberView(_View):
767
+ user_id: int
768
+ login: str | None
769
+ role: str
770
+ granted_by: str
771
+ created_at: datetime
772
+ updated_at: datetime
773
+ implicit: bool
774
+
775
+
776
+ class SessionView(_View):
777
+ id: str
778
+ created_at: datetime
779
+ last_seen_at: datetime
780
+ expires_at: datetime
781
+ user_agent: str
782
+ current: bool
783
+
784
+
785
+ class UserView(_View):
786
+ id: int
787
+ login: str
788
+
789
+
790
+ class SessionInfo(_View):
791
+ user: UserView
792
+ session: SessionView
793
+ csrf_token: str
794
+ organizations: tuple[OrganizationView, ...]
795
+ reauthentication_required_after: datetime
796
+
797
+
798
+ RepositoryDetail.model_rebuild()
799
+ ScanDetail.model_rebuild()