commitguardian 0.1.0__tar.gz → 0.1.1__tar.gz

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 (485) hide show
  1. {commitguardian-0.1.0 → commitguardian-0.1.1}/CHANGELOG.md +28 -0
  2. {commitguardian-0.1.0 → commitguardian-0.1.1}/CITATION.cff +2 -2
  3. {commitguardian-0.1.0 → commitguardian-0.1.1}/PKG-INFO +7 -3
  4. {commitguardian-0.1.0 → commitguardian-0.1.1}/README.md +6 -2
  5. {commitguardian-0.1.0 → commitguardian-0.1.1}/config/default.yaml +6 -2
  6. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/README.md +1 -1
  7. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/cli/doctor.md +1 -1
  8. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/configuration.md +62 -10
  9. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/deployment/README.md +1 -1
  10. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/deployment/local.md +1 -1
  11. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/deployment/production.md +1 -1
  12. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/deployment/troubleshooting.md +1 -1
  13. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/git-hooks.md +10 -3
  14. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/maintainers/release-process.md +35 -1
  15. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/security/threat-model.md +9 -3
  16. {commitguardian-0.1.0 → commitguardian-0.1.1}/pyproject.toml +1 -1
  17. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/__init__.py +1 -1
  18. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/doctor.py +13 -1
  19. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/hook.py +34 -0
  20. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/render.py +4 -2
  21. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/config/defaults.py +6 -2
  22. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/config/enforcement.py +1 -0
  23. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/config/schema.py +9 -1
  24. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/detectors/identity.py +1 -1
  25. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/git/repository.py +73 -0
  26. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/services/hooks.py +33 -11
  27. commitguardian-0.1.1/src/commitguard/services/push_fix.py +211 -0
  28. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/hooks/test_pre_push.py +249 -0
  29. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/config/test_config_validation.py +29 -0
  30. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/policies/test_governance_resolution.py +9 -0
  31. {commitguardian-0.1.0 → commitguardian-0.1.1}/.gitignore +0 -0
  32. {commitguardian-0.1.0 → commitguardian-0.1.1}/CODE_OF_CONDUCT.md +0 -0
  33. {commitguardian-0.1.0 → commitguardian-0.1.1}/CONTRIBUTING.md +0 -0
  34. {commitguardian-0.1.0 → commitguardian-0.1.1}/LICENSE +0 -0
  35. {commitguardian-0.1.0 → commitguardian-0.1.1}/SECURITY.md +0 -0
  36. {commitguardian-0.1.0 → commitguardian-0.1.1}/action.yml +0 -0
  37. {commitguardian-0.1.0 → commitguardian-0.1.1}/config/examples/allow-ai.yaml +0 -0
  38. {commitguardian-0.1.0 → commitguardian-0.1.1}/config/examples/block-ai-coauthors.yaml +0 -0
  39. {commitguardian-0.1.0 → commitguardian-0.1.1}/config/examples/enterprise.yaml +0 -0
  40. {commitguardian-0.1.0 → commitguardian-0.1.1}/config/strict.yaml +0 -0
  41. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/README.md +0 -0
  42. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/adr/001-detection-separate-from-policy.md +0 -0
  43. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/adr/002-rules-as-data.md +0 -0
  44. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/adr/003-fail-closed.md +0 -0
  45. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/adr/004-trusted-policy-source.md +0 -0
  46. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/adr/005-no-regex-trailer-parser.md +0 -0
  47. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/adr/006-mandatory-policy-only-strengthens.md +0 -0
  48. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/adr/007-immutable-evidence.md +0 -0
  49. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/adr/008-not-published-to-pypi.md +0 -0
  50. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/adr/009-published-to-pypi-as-commitguardian.md +0 -0
  51. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/adr/README.md +0 -0
  52. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/audit.md +0 -0
  53. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/authentication.md +0 -0
  54. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/authorization.md +0 -0
  55. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/bulk-operations.md +0 -0
  56. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/compliance-exports.md +0 -0
  57. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/errors.md +0 -0
  58. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/exceptions.md +0 -0
  59. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/github-installations.md +0 -0
  60. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/notifications.md +0 -0
  61. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/organizations.md +0 -0
  62. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/pagination.md +0 -0
  63. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/policies.md +0 -0
  64. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/policy-drafts.md +0 -0
  65. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/rate-limits.md +0 -0
  66. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/repositories.md +0 -0
  67. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/repository-groups.md +0 -0
  68. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/rollouts.md +0 -0
  69. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/rules.md +0 -0
  70. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/scan-schedules.md +0 -0
  71. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/scans.md +0 -0
  72. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/security-posture.md +0 -0
  73. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/simulations.md +0 -0
  74. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/violations.md +0 -0
  75. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/api/webhooks.md +0 -0
  76. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/architecture.md +0 -0
  77. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/cli/README.md +0 -0
  78. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/cli/benchmark.md +0 -0
  79. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/cli/github.md +0 -0
  80. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/cli/init.md +0 -0
  81. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/cli/install.md +0 -0
  82. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/cli/policy.md +0 -0
  83. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/cli/reproduce.md +0 -0
  84. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/cli/scan.md +0 -0
  85. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/community/README.md +0 -0
  86. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/community/case-study-template.md +0 -0
  87. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/community/data-policy.md +0 -0
  88. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/community/external-evaluation.md +0 -0
  89. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/community/feedback-triage.md +0 -0
  90. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/community/good-first-issues.md +0 -0
  91. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/community/pilot-program.md +0 -0
  92. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/compliance-reporting.md +0 -0
  93. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/dashboard.md +0 -0
  94. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/deployment/github-actions.md +0 -0
  95. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/deployment/github-app.md +0 -0
  96. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/deployment/organization.md +0 -0
  97. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/deployment/self-hosted.md +0 -0
  98. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/deployment.md +0 -0
  99. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/detection-engine.md +0 -0
  100. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/evidence/cli.json +0 -0
  101. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/evidence/phase-10-report.md +0 -0
  102. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/evidence/phase-10-verification-report.md +0 -0
  103. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/evidence/tests.json +0 -0
  104. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/evidence/timeline.md +0 -0
  105. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/evidence/validation-matrix.md +0 -0
  106. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/getting-started/quickstart.md +0 -0
  107. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/github-app.md +0 -0
  108. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/github-enforcement.md +0 -0
  109. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/maintainers/README.md +0 -0
  110. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/maintainers/architecture.md +0 -0
  111. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/maintainers/benchmarking.md +0 -0
  112. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/maintainers/development.md +0 -0
  113. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/maintainers/incident-response.md +0 -0
  114. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/maintainers/repository-management.md +0 -0
  115. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/maintainers/security.md +0 -0
  116. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/merge-queue.md +0 -0
  117. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/notifications.md +0 -0
  118. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/operations/runbook.md +0 -0
  119. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/organization-governance.md +0 -0
  120. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/policy-engine.md +0 -0
  121. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/policy-exceptions.md +0 -0
  122. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/policy-inheritance.md +0 -0
  123. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/policy-management.md +0 -0
  124. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/policy-rollouts.md +0 -0
  125. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/policy-simulation.md +0 -0
  126. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/presentations/commitguard-technical-overview.md +0 -0
  127. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/presentations/technical-article.md +0 -0
  128. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/recovery.md +0 -0
  129. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/repository-management.md +0 -0
  130. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/README.md +0 -0
  131. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/bypass-resistance.md +0 -0
  132. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/commitguard-architecture.md +0 -0
  133. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/cross-platform-validation.md +0 -0
  134. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/detection-evaluation.md +0 -0
  135. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/fuzzing.md +0 -0
  136. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/github-enforcement-validation.md +0 -0
  137. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/impact.md +0 -0
  138. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/innovation.md +0 -0
  139. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/limitations.md +0 -0
  140. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/merge-queue-security.md +0 -0
  141. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/methodology.md +0 -0
  142. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/performance-evaluation.md +0 -0
  143. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/policy-tampering.md +0 -0
  144. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/problem-definition.md +0 -0
  145. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/reliability-evaluation.md +0 -0
  146. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/reproducibility.md +0 -0
  147. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/research/roadmap.md +0 -0
  148. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/security/README.md +0 -0
  149. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/security/authorization-matrix.md +0 -0
  150. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/security/ci-pipeline-security.md +0 -0
  151. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/security/incident-response.md +0 -0
  152. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/security/review-guide.md +0 -0
  153. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/security/security-boundaries.md +0 -0
  154. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/security/supply-chain.md +0 -0
  155. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/security/vulnerability-response.md +0 -0
  156. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/security-posture.md +0 -0
  157. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/support/compatibility-policy.md +0 -0
  158. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/support/compatibility.md +0 -0
  159. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/support/maintenance-policy.md +0 -0
  160. {commitguardian-0.1.0 → commitguardian-0.1.1}/docs/threat-model.md +0 -0
  161. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/README.md +0 -0
  162. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/basic/.commitguard.yaml +0 -0
  163. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/basic/README.md +0 -0
  164. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/basic/commits/ai-coauthor.txt +0 -0
  165. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/basic/commits/ai-tool-footer.txt +0 -0
  166. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/basic/commits/clean.txt +0 -0
  167. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/basic/commits/disguised-coauthor.txt +0 -0
  168. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/basic/commits/malformed-trailer.txt +0 -0
  169. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/basic/expected.json +0 -0
  170. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/exceptions/README.md +0 -0
  171. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/github-actions/README.md +0 -0
  172. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/github-actions/commitguard.yml +0 -0
  173. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/github-app/README.md +0 -0
  174. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/organization-policy/README.md +0 -0
  175. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/organization-policy/mandatory-policy.yaml +0 -0
  176. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/organization-policy/repository-attempt.yaml +0 -0
  177. {commitguardian-0.1.0 → commitguardian-0.1.1}/examples/policy-rollout/README.md +0 -0
  178. {commitguardian-0.1.0 → commitguardian-0.1.1}/hooks/README.md +0 -0
  179. {commitguardian-0.1.0 → commitguardian-0.1.1}/hooks/commit-msg +0 -0
  180. {commitguardian-0.1.0 → commitguardian-0.1.1}/hooks/pre-commit +0 -0
  181. {commitguardian-0.1.0 → commitguardian-0.1.1}/hooks/pre-push +0 -0
  182. {commitguardian-0.1.0 → commitguardian-0.1.1}/requirements/ci.in +0 -0
  183. {commitguardian-0.1.0 → commitguardian-0.1.1}/requirements/ci.txt +0 -0
  184. {commitguardian-0.1.0 → commitguardian-0.1.1}/rules/ai-domains.yaml +0 -0
  185. {commitguardian-0.1.0 → commitguardian-0.1.1}/rules/ai-identities.yaml +0 -0
  186. {commitguardian-0.1.0 → commitguardian-0.1.1}/rules/bot-identities.yaml +0 -0
  187. {commitguardian-0.1.0 → commitguardian-0.1.1}/rules/patterns.yaml +0 -0
  188. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/__main__.py +0 -0
  189. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/api/__init__.py +0 -0
  190. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/api/app.py +0 -0
  191. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/api/governance.py +0 -0
  192. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/api/hosting.py +0 -0
  193. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/api/http.py +0 -0
  194. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/api/settings.py +0 -0
  195. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/audit/__init__.py +0 -0
  196. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/audit/logger.py +0 -0
  197. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/audit/models.py +0 -0
  198. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/audit/storage.py +0 -0
  199. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/ci/__init__.py +0 -0
  200. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/ci/context.py +0 -0
  201. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/__init__.py +0 -0
  202. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/app.py +0 -0
  203. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/__init__.py +0 -0
  204. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/benchmark.py +0 -0
  205. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/check.py +0 -0
  206. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/ci.py +0 -0
  207. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/dashboard.py +0 -0
  208. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/github.py +0 -0
  209. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/init.py +0 -0
  210. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/install.py +0 -0
  211. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/policy.py +0 -0
  212. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/report.py +0 -0
  213. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/reproduce.py +0 -0
  214. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/commands/scan.py +0 -0
  215. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/common.py +0 -0
  216. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/cli/output.py +0 -0
  217. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/config/__init__.py +0 -0
  218. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/config/loader.py +0 -0
  219. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/config/sources.py +0 -0
  220. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/__init__.py +0 -0
  221. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/access.py +0 -0
  222. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/commands.py +0 -0
  223. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/errors.py +0 -0
  224. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/identity.py +0 -0
  225. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/members.py +0 -0
  226. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/notifications.py +0 -0
  227. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/pagination.py +0 -0
  228. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/policies.py +0 -0
  229. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/queries.py +0 -0
  230. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/results.py +0 -0
  231. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/rules.py +0 -0
  232. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/controlplane/views.py +0 -0
  233. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/core/__init__.py +0 -0
  234. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/core/context.py +0 -0
  235. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/core/decision.py +0 -0
  236. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/core/engine.py +0 -0
  237. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/core/result.py +0 -0
  238. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/detectors/__init__.py +0 -0
  239. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/detectors/base.py +0 -0
  240. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/detectors/bot.py +0 -0
  241. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/detectors/coauthor.py +0 -0
  242. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/detectors/registry.py +0 -0
  243. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/detectors/trailer.py +0 -0
  244. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/exceptions/__init__.py +0 -0
  245. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/exceptions/base.py +0 -0
  246. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/exceptions/configuration.py +0 -0
  247. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/exceptions/detection.py +0 -0
  248. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/exceptions/git.py +0 -0
  249. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/exceptions/service.py +0 -0
  250. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/git/__init__.py +0 -0
  251. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/git/commands.py +0 -0
  252. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/git/commit.py +0 -0
  253. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/git/diff.py +0 -0
  254. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/git/hooks.py +0 -0
  255. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/git/push.py +0 -0
  256. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/git/ranges.py +0 -0
  257. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/__init__.py +0 -0
  258. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/actions.py +0 -0
  259. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/app.py +0 -0
  260. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/auth.py +0 -0
  261. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/check_runs.py +0 -0
  262. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/checks.py +0 -0
  263. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/client.py +0 -0
  264. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/enforcement_status.py +0 -0
  265. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/errors.py +0 -0
  266. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/events.py +0 -0
  267. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/identifiers.py +0 -0
  268. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/installations.py +0 -0
  269. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/markdown.py +0 -0
  270. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/permissions.py +0 -0
  271. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/pull_requests.py +0 -0
  272. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/queue.py +0 -0
  273. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/recovery.py +0 -0
  274. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/repositories.py +0 -0
  275. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/server.py +0 -0
  276. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/settings.py +0 -0
  277. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/storage.py +0 -0
  278. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/webhooks.py +0 -0
  279. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/worker.py +0 -0
  280. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/github/workflow.py +0 -0
  281. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/__init__.py +0 -0
  282. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/bulk.py +0 -0
  283. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/cache.py +0 -0
  284. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/common.py +0 -0
  285. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/exceptions.py +0 -0
  286. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/groups.py +0 -0
  287. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/inventory.py +0 -0
  288. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/posture.py +0 -0
  289. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/resolver.py +0 -0
  290. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/rollouts.py +0 -0
  291. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/rules.py +0 -0
  292. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/schedules.py +0 -0
  293. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/service.py +0 -0
  294. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/settings.py +0 -0
  295. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/simulation.py +0 -0
  296. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/governance/workflow.py +0 -0
  297. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/__init__.py +0 -0
  298. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/channels/__init__.py +0 -0
  299. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/channels/base.py +0 -0
  300. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/channels/email.py +0 -0
  301. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/channels/in_app.py +0 -0
  302. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/channels/sink.py +0 -0
  303. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/channels/webhook.py +0 -0
  304. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/deduplication.py +0 -0
  305. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/dispatcher.py +0 -0
  306. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/models.py +0 -0
  307. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/outbox.py +0 -0
  308. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/preferences.py +0 -0
  309. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/retry.py +0 -0
  310. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/service.py +0 -0
  311. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/settings.py +0 -0
  312. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/notifications/templates.py +0 -0
  313. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/observability/__init__.py +0 -0
  314. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/observability/logging.py +0 -0
  315. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/observability/metrics.py +0 -0
  316. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/policies/__init__.py +0 -0
  317. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/policies/defaults.py +0 -0
  318. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/policies/evaluator.py +0 -0
  319. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/policies/governance.py +0 -0
  320. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/policies/loader.py +0 -0
  321. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/policies/mandatory.py +0 -0
  322. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/policies/model.py +0 -0
  323. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/provenance/__init__.py +0 -0
  324. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/provenance/author.py +0 -0
  325. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/provenance/committer.py +0 -0
  326. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/provenance/normalization.py +0 -0
  327. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/provenance/signatures.py +0 -0
  328. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/provenance/trailers.py +0 -0
  329. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/__init__.py +0 -0
  330. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/compare.py +0 -0
  331. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/datasets.py +0 -0
  332. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/detection.py +0 -0
  333. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/environment.py +0 -0
  334. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/gitenv.py +0 -0
  335. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/hooks.py +0 -0
  336. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/metrics.py +0 -0
  337. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/performance.py +0 -0
  338. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/platform.py +0 -0
  339. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/report.py +0 -0
  340. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/repository.py +0 -0
  341. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/reproduction.py +0 -0
  342. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/research/results.py +0 -0
  343. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/rules/__init__.py +0 -0
  344. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/rules/loader.py +0 -0
  345. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/rules/matcher.py +0 -0
  346. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/rules/models.py +0 -0
  347. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/security/__init__.py +0 -0
  348. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/security/hashing.py +0 -0
  349. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/security/rate_limit.py +0 -0
  350. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/security/safe_yaml.py +0 -0
  351. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/security/sanitization.py +0 -0
  352. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/security/secrets.py +0 -0
  353. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/security/validation.py +0 -0
  354. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/services/__init__.py +0 -0
  355. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/services/analysis.py +0 -0
  356. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/services/audit.py +0 -0
  357. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/services/ci.py +0 -0
  358. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/services/enforcement.py +0 -0
  359. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/services/remediation.py +0 -0
  360. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/services/reports.py +0 -0
  361. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/services/scan.py +0 -0
  362. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/utils/__init__.py +0 -0
  363. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/utils/filesystem.py +0 -0
  364. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/utils/platform.py +0 -0
  365. {commitguardian-0.1.0 → commitguardian-0.1.1}/src/commitguard/utils/subprocess.py +0 -0
  366. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/conftest.py +0 -0
  367. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/e2e/dashboard_harness.py +0 -0
  368. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/ai_agent_author.yaml +0 -0
  369. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/ai_wording_only.yaml +0 -0
  370. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/bot_author.yaml +0 -0
  371. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/chatgpt_coauthor.yaml +0 -0
  372. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/claude_coauthor.yaml +0 -0
  373. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/copilot_coauthor.yaml +0 -0
  374. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/generated_with_trailer.yaml +0 -0
  375. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/human_coauthor.yaml +0 -0
  376. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/malformed_trailer.yaml +0 -0
  377. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/malicious_message.yaml +0 -0
  378. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/multiple_coauthors.yaml +0 -0
  379. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/normal_human.yaml +0 -0
  380. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/commits/unknown_ai_agent.yaml +0 -0
  381. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/policies/alias.yaml +0 -0
  382. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/policies/duplicate-keys.yaml +0 -0
  383. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/policies/null-action.yaml +0 -0
  384. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/policies/python-tag.yaml +0 -0
  385. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/policies/string-boolean.yaml +0 -0
  386. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/policies/unknown-key.yaml +0 -0
  387. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/policies/unknown-policy.yaml +0 -0
  388. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/policies/valid-minimal.yaml +0 -0
  389. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/repositories/README.md +0 -0
  390. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/webhooks/README.md +0 -0
  391. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/webhooks/installation.created.json +0 -0
  392. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/webhooks/installation.deleted.json +0 -0
  393. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/webhooks/installation_repositories.added.json +0 -0
  394. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/webhooks/installation_repositories.removed.json +0 -0
  395. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/webhooks/pull_request.closed.json +0 -0
  396. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/webhooks/pull_request.opened.json +0 -0
  397. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/webhooks/pull_request.reopened.json +0 -0
  398. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/webhooks/pull_request.synchronize.json +0 -0
  399. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/fixtures/webhooks/push.json +0 -0
  400. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/git/test_cli_commands.py +0 -0
  401. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/git/test_repository.py +0 -0
  402. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/conftest.py +0 -0
  403. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/conftest.py +0 -0
  404. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_dashboard_api.py +0 -0
  405. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_dashboard_authorization.py +0 -0
  406. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_dashboard_lifecycle.py +0 -0
  407. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_dashboard_notifications.py +0 -0
  408. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_dashboard_performance.py +0 -0
  409. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_dashboard_policies.py +0 -0
  410. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_dashboard_recovery.py +0 -0
  411. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_dashboard_security.py +0 -0
  412. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_governance_end_to_end.py +0 -0
  413. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_governance_isolation.py +0 -0
  414. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_governance_operations.py +0 -0
  415. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_governance_performance.py +0 -0
  416. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_governance_policies.py +0 -0
  417. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_governance_rollouts.py +0 -0
  418. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/dashboard/test_governance_workflow.py +0 -0
  419. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/security/test_server_enforcement_experiments.py +0 -0
  420. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/test_app_action_consistency.py +0 -0
  421. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/test_app_cli.py +0 -0
  422. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/test_app_concurrency.py +0 -0
  423. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/test_app_end_to_end.py +0 -0
  424. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/test_app_http.py +0 -0
  425. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/test_app_merge_queue_reruns.py +0 -0
  426. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/app/test_app_security.py +0 -0
  427. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/conftest.py +0 -0
  428. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/security/test_bypass_resistance.py +0 -0
  429. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/test_action_scripts.py +0 -0
  430. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/test_ci_github.py +0 -0
  431. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/test_ci_security.py +0 -0
  432. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/test_defense_in_depth.py +0 -0
  433. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/test_github_cli.py +0 -0
  434. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/github/test_github_placeholder.py +0 -0
  435. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/hooks/conftest.py +0 -0
  436. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/hooks/test_commit_hooks.py +0 -0
  437. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/hooks/test_end_to_end.py +0 -0
  438. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/hooks/test_hook_templates.py +0 -0
  439. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/hooks/test_install.py +0 -0
  440. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/integration/test_examples.py +0 -0
  441. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/security/conftest.py +0 -0
  442. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/security/test_fuzz_parsers.py +0 -0
  443. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/security/test_properties.py +0 -0
  444. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/security/test_redos.py +0 -0
  445. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/controlplane/test_controlplane.py +0 -0
  446. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/controlplane/test_governance_units.py +0 -0
  447. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/core/test_decision.py +0 -0
  448. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/core/test_engine.py +0 -0
  449. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/core/test_result.py +0 -0
  450. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/detectors/test_bot.py +0 -0
  451. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/detectors/test_coauthor.py +0 -0
  452. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/detectors/test_identity.py +0 -0
  453. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/detectors/test_registry.py +0 -0
  454. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/detectors/test_trailer.py +0 -0
  455. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/git/test_hook_rendering.py +0 -0
  456. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/git/test_push_parsing.py +0 -0
  457. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/app/conftest.py +0 -0
  458. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/app/test_auth.py +0 -0
  459. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/app/test_client.py +0 -0
  460. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/app/test_phase7_events_and_storage.py +0 -0
  461. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/app/test_policy_and_checks.py +0 -0
  462. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/app/test_secrets_and_logging.py +0 -0
  463. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/app/test_service_entry_points.py +0 -0
  464. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/app/test_storage.py +0 -0
  465. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/app/test_webhook_events.py +0 -0
  466. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/app/test_webhooks.py +0 -0
  467. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/test_events_and_output.py +0 -0
  468. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/github/test_workflows_static.py +0 -0
  469. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/notifications/test_notification_units.py +0 -0
  470. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/policies/test_evaluator.py +0 -0
  471. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/policies/test_policy_loader.py +0 -0
  472. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/provenance/test_identity_parsing.py +0 -0
  473. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/provenance/test_models.py +0 -0
  474. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/provenance/test_trailers.py +0 -0
  475. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/research/test_compare.py +0 -0
  476. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/rules/test_matcher.py +0 -0
  477. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/rules/test_rules_loader.py +0 -0
  478. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/security/test_safe_subprocess.py +0 -0
  479. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/security/test_sanitization.py +0 -0
  480. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/security/test_validation.py +0 -0
  481. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/services/test_analyzer.py +0 -0
  482. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/services/test_remediation.py +0 -0
  483. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/test_architecture.py +0 -0
  484. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/test_documented_commands.py +0 -0
  485. {commitguardian-0.1.0 → commitguardian-0.1.1}/tests/unit/test_env_example.py +0 -0
@@ -4,6 +4,34 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
5
  [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.1] - 2026-09-19
10
+
11
+ ### Added
12
+
13
+ - **`remediation.fix_on_push`** (opt-in, off by default): the `pre-push` hook
14
+ removes AI, bot and agent attribution from *unpushed* commits that never
15
+ passed through `commit-msg` - made with `git commit --no-verify`,
16
+ `git cherry-pick`, `git rebase`, `git am`, or tools that skip hooks - then
17
+ stops that push so the next `git push` sends the cleaned commits (a hook
18
+ cannot change what a push in progress sends). Only the message changes: the
19
+ tree, author, committer and timestamps are copied byte for byte, and the
20
+ originals stay in the reflog. It refuses, and blocks as before, for any
21
+ commit a remote-tracking branch contains, tags, signed commits, identity
22
+ findings, a message that would be left empty, or an unfinished rebase, merge,
23
+ cherry-pick, revert or bisect; if any commit cannot be fixed, none are
24
+ rewritten; and nothing moves unless every rewritten commit re-analyses clean.
25
+ Branches move atomically with a compare-and-swap. `commitguard doctor` warns
26
+ while it is on, and a mandatory policy cannot enable it. Each of these guards
27
+ is covered by a test that fails when the guard is removed.
28
+
29
+ ### Changed
30
+
31
+ - The blocked-push message no longer says "CommitGuard never modifies
32
+ commits", which is not true when `fix_on_push` is enabled. It now says the
33
+ commits were not changed and points to the setting.
34
+
7
35
  ## [0.1.0] - 2026-09-18
8
36
 
9
37
  ### Packaging
@@ -22,5 +22,5 @@ keywords:
22
22
  - ai-attribution
23
23
  - software-supply-chain
24
24
  license: MIT
25
- version: 0.1.0.dev0
26
- date-released: "2026-09-17"
25
+ version: 0.1.1
26
+ date-released: "2026-09-19"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: commitguardian
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Block AI, bot and agent attribution in Git commits, locally and on GitHub.
5
5
  Project-URL: Homepage, https://github.com/oyinlola-tech/commitguard
6
6
  Project-URL: Repository, https://github.com/oyinlola-tech/commitguard
@@ -325,8 +325,12 @@ result=BLOCK commits=1 block=1 warn=0 allow=0
325
325
  | `1` | blocked by policy (a finding or detector failure evaluated to `block`) |
326
326
  | `2` | error: invalid configuration/rules, Git error, bad arguments, unexpected failure (hooks block on errors) |
327
327
 
328
- CommitGuard never modifies commits or rewrites history; remediation is always
329
- left to the developer.
328
+ By default CommitGuard never modifies commits or rewrites history; remediation
329
+ is left to the developer. Two opt-in settings change that, locally only:
330
+ `remediation.auto_remove` deletes AI attribution from a message before the
331
+ commit is created, and `remediation.fix_on_push` rewrites *unpushed* commits
332
+ that slipped past it (see [configuration](docs/configuration.md#remediation)).
333
+ The GitHub Action and App never rewrite anything.
330
334
 
331
335
  ## Configuration
332
336
 
@@ -285,8 +285,12 @@ result=BLOCK commits=1 block=1 warn=0 allow=0
285
285
  | `1` | blocked by policy (a finding or detector failure evaluated to `block`) |
286
286
  | `2` | error: invalid configuration/rules, Git error, bad arguments, unexpected failure (hooks block on errors) |
287
287
 
288
- CommitGuard never modifies commits or rewrites history; remediation is always
289
- left to the developer.
288
+ By default CommitGuard never modifies commits or rewrites history; remediation
289
+ is left to the developer. Two opt-in settings change that, locally only:
290
+ `remediation.auto_remove` deletes AI attribution from a message before the
291
+ commit is created, and `remediation.fix_on_push` rewrites *unpushed* commits
292
+ that slipped past it (see [configuration](docs/configuration.md#remediation)).
293
+ The GitHub Action and App never rewrite anything.
290
294
 
291
295
  ## Configuration
292
296
 
@@ -33,7 +33,11 @@ enforcement:
33
33
  # What to do about a violation. By default CommitGuard blocks and leaves the
34
34
  # message to you. Set auto_remove: true and the commit-msg hook deletes the
35
35
  # offending lines instead, reports what it removed, and lets the commit through.
36
- # Attribution in the author or committer identity still blocks: no edit to the
37
- # message can fix that. `commitguard doctor` shows when this is on.
36
+ # Set fix_on_push: true and pre-push also rewrites unpushed commits that skipped
37
+ # commit-msg (--no-verify, cherry-pick, rebase), then asks you to push again; it
38
+ # never touches a commit any remote already has. Attribution in the author or
39
+ # committer identity always blocks: no edit to the message can fix that.
40
+ # `commitguard doctor` shows when either is on.
38
41
  # remediation:
39
42
  # auto_remove: true
43
+ # fix_on_push: true
@@ -5,7 +5,7 @@ dashboard is built on it. It exposes repositories, scans, violations, policies
5
5
  and their governance, exceptions, audit events, notifications and GitHub
6
6
  installations. The same process also receives GitHub webhooks.
7
7
 
8
- > **Stability.** CommitGuard is pre-alpha (`0.1.0`, "Development Status :: 2
8
+ > **Stability.** CommitGuard is pre-alpha (`0.1.1`, "Development Status :: 2
9
9
  > - Pre-Alpha"). The API is versioned `v1` in its path, but no compatibility
10
10
  > promise exists yet. Endpoints, fields and error codes can change between
11
11
  > commits. There is no OpenAPI document; these pages, the view models in
@@ -60,7 +60,7 @@ commitguard doctor --json
60
60
 
61
61
  ```json
62
62
  {
63
- "commitguard_version": "0.1.0",
63
+ "commitguard_version": "0.1.1",
64
64
  "status": "HEALTHY",
65
65
  "enforcement": "LOCAL ENFORCEMENT ONLY",
66
66
  "counts": {"PASS": 14, "INFO": 1, "NOT CONFIGURED": 2, "WARNING": 0, "FAIL": 0},
@@ -73,7 +73,8 @@ never treated as a fully protected state.
73
73
 
74
74
  ```yaml
75
75
  remediation:
76
- auto_remove: false # default
76
+ auto_remove: false # default: remove attribution before a commit is created
77
+ fix_on_push: false # default: rewrite unpushed commits that slipped past it
77
78
  ```
78
79
 
79
80
  By default CommitGuard blocks a violating commit and leaves the message to you.
@@ -98,17 +99,68 @@ The stripped message is re-analysed before the commit is allowed. If it is still
98
99
  blocked, the original block stands: nothing is ever allowed on the assumption
99
100
  that the removal worked.
100
101
 
101
- Two deliberate constraints:
102
+ A mandatory policy cannot set either option. A floor may only make enforcement
103
+ stricter, and both turn a block into something that proceeds, so `remediation:`
104
+ in a mandatory policy is a configuration error.
102
105
 
103
- * **`pre-push` is unaffected.** By then the commits exist, and correcting them
104
- means rewriting history. CommitGuard never does that on its own; it blocks and
105
- tells you which commits to amend or reword.
106
- * **A mandatory policy cannot set it.** A floor may only make enforcement
107
- stricter, and `auto_remove` turns a block into a commit, so
108
- `remediation:` in a mandatory policy is a configuration error.
106
+ ### `fix_on_push`: commits the commit-msg hook never saw
109
107
 
110
- `commitguard doctor` reports `! WARNING remediation.auto_remove is on` whenever
111
- it is enabled, because it changes a block into a commit.
108
+ `auto_remove` only sees commits made with `git commit`. These create commits
109
+ without running `commit-msg`, so their attribution reaches `pre-push` intact:
110
+
111
+ | How the commit was made | Cleaned by `auto_remove`? |
112
+ |---|---|
113
+ | `git commit`, `git commit --amend`, `git merge` | yes |
114
+ | `git commit --no-verify` | no |
115
+ | `git cherry-pick`, `git rebase`, `git am` | no |
116
+ | tools that create commits without running hooks | no |
117
+
118
+ With `fix_on_push: true`, the `pre-push` hook rewrites those commits' messages
119
+ to remove the attribution. **It then stops that push.** Git decides which
120
+ objects a push sends before the hook runs, so the push in progress would still
121
+ carry the old commits; the next `git push` sends the cleaned ones:
122
+
123
+ ```
124
+ $ git push
125
+ CommitGuard
126
+ ! CLEANED 2 unpushed commits (AI attribution removed; history rewritten)
127
+
128
+ e70fd0f -> 23acf33 feat: two
129
+ removed: Co-Authored-By: Claude <noreply@anthropic.com> [ai_coauthor]
130
+ d91e62b -> 06d7cc6 feat: three
131
+
132
+ Only commits that no remote has were changed; the old ones are in
133
+ `git reflog`. Branch updated: main.
134
+
135
+ This push was stopped (Git had already chosen what to send).
136
+ Run `git push` again to send the cleaned commits.
137
+
138
+ $ git push
139
+ CommitGuard: ✓ 3 outgoing commits checked, no policy violations
140
+ ```
141
+
142
+ This rewrites history, so it is deliberately narrow. It does nothing - and the
143
+ push is blocked as usual - unless every one of these holds:
144
+
145
+ * **No remote has the commits.** A commit contained in *any* remote-tracking
146
+ branch, not only the one you are pushing to, has been shared and is never
147
+ rewritten.
148
+ * **Only a local branch is being pushed.** Tags are never touched.
149
+ * **Every blocking finding is a message line.** An AI author or committer still
150
+ blocks. If any commit cannot be fixed, *none* are rewritten.
151
+ * **No commit is signed** (`gpgsig`, `mergetag`), since rewriting would silently
152
+ drop the signature, and none carries a header CommitGuard does not recognise.
153
+ * **No rebase, merge, cherry-pick, revert or bisect is in progress.**
154
+ * **Every rewritten commit re-analyses clean.** Nothing moves on assumption.
155
+
156
+ Only the message changes. The tree, author, committer and both timestamps are
157
+ copied byte for byte, so your working tree and index are untouched. Commits
158
+ after a cleaned one get new IDs because their parent changed; commits before it
159
+ keep theirs. Branches move atomically, and only if they still point where they
160
+ did when the push began. The originals stay in `git reflog`.
161
+
162
+ `commitguard doctor` reports a warning whenever either option is on, because
163
+ each changes a block into something that proceeds.
112
164
 
113
165
  ## Validation (security-relevant)
114
166
 
@@ -1,6 +1,6 @@
1
1
  # Deploying CommitGuard
2
2
 
3
- CommitGuard 0.1.0 is pre-alpha software. This section describes the ways it
3
+ CommitGuard 0.1.1 is pre-alpha software. This section describes the ways it
4
4
  can be deployed today, what each way protects against, and what it does not.
5
5
  Every mode runs the same detection engine and policy evaluator; they differ in
6
6
  where the check runs, who controls it, and whether it can prevent a merge.
@@ -25,7 +25,7 @@ and `commitguard-cli` on PyPI are unrelated projects.)
25
25
 
26
26
  ```bash
27
27
  pipx install commitguardian
28
- commitguard --version # commitguard 0.1.0
28
+ commitguard --version # commitguard 0.1.1
29
29
 
30
30
  # or pinned to an exact commit:
31
31
  pipx install "git+https://github.com/oyinlola-tech/commitguard@<commit-sha>"
@@ -1,6 +1,6 @@
1
1
  # Running the App service in production
2
2
 
3
- > Status: **Experimental.** CommitGuard is pre-alpha (0.1.0).
3
+ > Status: **Experimental.** CommitGuard is pre-alpha (0.1.1).
4
4
  > No external production deployments have been recorded yet.
5
5
  > The App service and organization governance have been validated only by this
6
6
  > repository's test suites, against an offline model of GitHub. There are no
@@ -30,7 +30,7 @@ repository. Uninstall it and install from source, pinned to a commit:
30
30
  ```bash
31
31
  python -m pip uninstall commitguard
32
32
  pipx install "git+https://github.com/oyinlola-tech/commitguard@<commit-sha>"
33
- commitguard --version # commitguard 0.1.0
33
+ commitguard --version # commitguard 0.1.1
34
34
  ```
35
35
 
36
36
  **`the GitHub App needs the optional dependencies: pip install 'commitguard[app]'`**
@@ -111,7 +111,7 @@ Allowed: 1
111
111
  Evidence: Claude <noreply@anthropic.com> (Co-authored-by trailer, line 3)
112
112
  ...
113
113
  How to fix:
114
- CommitGuard never modifies commits. ...
114
+ CommitGuard did not change these commits. ...
115
115
  No changes were pushed to the remote repository.
116
116
  ```
117
117
 
@@ -266,8 +266,15 @@ CommitGuard
266
266
  ```
267
267
 
268
268
  It is off by default and never applies to identity-based findings, which cannot
269
- be fixed by editing text. `pre-push` never removes anything. See
270
- [configuration.md](configuration.md#remediation) for the full rules.
269
+ be fixed by editing text. See [configuration.md](configuration.md#remediation)
270
+ for the full rules.
271
+
272
+ Commits made with `git commit --no-verify`, `git cherry-pick`, `git rebase` or
273
+ `git am` skip `commit-msg`. `remediation.fix_on_push: true` makes `pre-push`
274
+ rewrite those *unpushed* commits' messages and stop the push, so the next
275
+ `git push` sends the cleaned commits. It never touches a commit any remote
276
+ already has, tags, signed commits or identity findings; see
277
+ [configuration.md](configuration.md#fix_on_push-commits-the-commit-msg-hook-never-saw).
271
278
 
272
279
  ## Doctor
273
280
 
@@ -29,7 +29,7 @@ Artifacts are not signed, and no build provenance attestation is generated.
29
29
  | Runtime version (`commitguard --version`) | `src/commitguard/__init__.py`, `__version__` |
30
30
  | Dashboard package version | `web/package.json` (`"private": true`, not released separately; currently `0.1.0`, independent of the Python version) |
31
31
 
32
- Both Python locations must be changed together; today they both say `0.1.0`.
32
+ Both Python locations must be changed together; today they both say `0.1.1`.
33
33
  `tests/integration/git/test_cli_commands.py` checks that `commitguard --version`
34
34
  prints `__version__`; no test compares it with `pyproject.toml`, so check both by
35
35
  hand. The name in `pyproject.toml` is pinned by
@@ -234,6 +234,40 @@ Marketplace shows the tag, so a release candidate must not be listed - which is
234
234
  why the workflow leaves an `rc` tag as a **draft prerelease** and only publishes
235
235
  a final tag.
236
236
 
237
+ ## When a release only half-finishes
238
+
239
+ The first real tag, `v0.1.0`, exposed two faults at once. Both are fixed; this
240
+ is what to do if a release stops partway.
241
+
242
+ **Symptom:** the tag exists, the GitHub release exists, but PyPI has nothing.
243
+
244
+ **Cause 1 - the build job imported the package it had just built.** It ran
245
+ `python -c "import commitguard"` from inside `dist/`, where the package is
246
+ neither installed nor on the path. The gate installs the package, so the gate
247
+ passed and the build failed. The version now comes from the wheel filename.
248
+
249
+ **Cause 2 - the release job assumed it was the one creating the release.**
250
+ Listing an Action on the Marketplace *requires* a published release, and the
251
+ web form creates the tag and the release together - which triggers this
252
+ workflow, which then found the release already there. `gh release create`
253
+ failed, so `publish` never ran. The job now creates **or updates**: it uploads
254
+ the artifacts to the existing release with `--clobber`, and leaves hand-written
255
+ notes alone.
256
+
257
+ **To finish a stalled release, do not move or reuse the tag.** Run the workflow
258
+ manually against it:
259
+
260
+ > Actions -> Release -> Run workflow -> *Use workflow from:* `main`
261
+ > -> *ref:* `v0.1.0`
262
+
263
+ The workflow definition comes from `main` (so you get the fixes) while the code
264
+ built comes from the tag (so you release what you tagged). The gate still
265
+ checks that the tag matches `__version__`, the release job attaches the missing
266
+ artifacts, and `publish` uploads to PyPI.
267
+
268
+ Passing a commit SHA instead of a tag stays a dry run: it builds and tests, and
269
+ skips both the release and the publish.
270
+
237
271
  ## Manual release checklist
238
272
 
239
273
  - [ ] CI, Security and CommitGuard workflows green on the tagged commit
@@ -706,9 +706,15 @@ not file contents) of repositories while they are installed. See
706
706
  - Detectors receive data, not a repository handle; architecture tests forbid
707
707
  I/O imports in detection layers **[done]**.
708
708
  - Git reads use `GIT_OPTIONAL_LOCKS=0` **[done]**.
709
- - CommitGuard never rewrites commits or history; it never runs `git reset`,
710
- `rebase`, `commit --amend`, `filter-branch` or `filter-repo`. Remediation
711
- text explains the scope of any command it suggests **[by design]**.
709
+ - CommitGuard never runs `git reset`, `rebase`, `commit --amend`,
710
+ `filter-branch` or `filter-repo`, and by default never rewrites commits or
711
+ history. The one exception is opt-in: with `remediation.fix_on_push`, the
712
+ `pre-push` hook rewrites the *message* of unpushed commits. It refuses any
713
+ commit a remote-tracking branch contains, tags, signed commits, identity
714
+ findings and in-progress rebases or merges; moves branches atomically with a
715
+ compare-and-swap; re-analyses every rewritten commit before moving anything;
716
+ and leaves the originals in the reflog. The server side (Action, App) never
717
+ rewrites anything **[by design; `tests/integration/hooks/test_pre_push.py`]**.
712
718
  - `init` never overwrites an existing file **[done]**.
713
719
 
714
720
  ## Maintaining this document
@@ -7,7 +7,7 @@ build-backend = "hatchling.build"
7
7
  # "commitguard-cli", belong to two unrelated projects (see docs/adr/009). The
8
8
  # import package and the console script stay `commitguard`.
9
9
  name = "commitguardian"
10
- version = "0.1.0"
10
+ version = "0.1.1"
11
11
  description = "Block AI, bot and agent attribution in Git commits, locally and on GitHub."
12
12
  readme = "README.md"
13
13
  license = "MIT"
@@ -21,6 +21,6 @@ Package layout (dependency direction flows downwards only)::
21
21
  utils -> subprocess / filesystem / platform helpers
22
22
  """
23
23
 
24
- __version__ = "0.1.0"
24
+ __version__ = "0.1.1"
25
25
 
26
26
  __all__ = ["__version__"]
@@ -182,7 +182,8 @@ def _hook_checks(repository: Repository, loaded: LoadedConfig | None) -> list[Ch
182
182
  "set enforcement." + name.replace("-", "_") + ": true",
183
183
  )
184
184
  )
185
- if loaded is not None and build_remediation(*loaded.configs).auto_remove:
185
+ remediation = build_remediation(*loaded.configs) if loaded is not None else None
186
+ if remediation is not None and remediation.auto_remove:
186
187
  # This turns a blocked commit into a commit. It must never be invisible.
187
188
  checks.append(
188
189
  Check(
@@ -193,6 +194,17 @@ def _hook_checks(repository: Repository, loaded: LoadedConfig | None) -> list[Ch
193
194
  "set remediation.auto_remove: false to block instead",
194
195
  )
195
196
  )
197
+ if remediation is not None and remediation.fix_on_push:
198
+ checks.append(
199
+ Check(
200
+ "Enforcement",
201
+ Status.WARN,
202
+ "remediation.fix_on_push is on: pre-push rewrites unpushed commits to remove "
203
+ "prohibited attribution, then asks you to push again (never commits a remote "
204
+ "already has; identity findings still block)",
205
+ "set remediation.fix_on_push: false to block instead",
206
+ )
207
+ )
196
208
  return checks
197
209
 
198
210
 
@@ -28,6 +28,7 @@ from commitguard.services.hooks import (
28
28
  run_pre_commit,
29
29
  run_pre_push,
30
30
  )
31
+ from commitguard.services.push_fix import PushFix
31
32
 
32
33
  MAX_PRE_PUSH_STDIN_BYTES = 8 * 1024 * 1024
33
34
 
@@ -86,6 +87,35 @@ def _removal_notice(run: HookRun) -> str:
86
87
  return "\n".join(lines)
87
88
 
88
89
 
90
+ def _push_fix_notice(fixed: PushFix) -> str:
91
+ """What ``remediation.fix_on_push`` rewrote. Always shown in full: it
92
+ changed commits the developer made."""
93
+ count = len(fixed.commits)
94
+ lines = [
95
+ "CommitGuard",
96
+ f"! CLEANED {count} unpushed commit{'s' if count != 1 else ''} "
97
+ "(AI attribution removed; history rewritten)",
98
+ "",
99
+ ]
100
+ for commit in fixed.commits:
101
+ subject = sanitize_block(commit.subject, max_length=72)
102
+ lines.append(f" {commit.old_sha[:7]} -> {commit.new_sha[:7]} {subject}")
103
+ lines += [
104
+ f" removed: {sanitize_block(r.text, max_length=200)} [{r.rule_id}]"
105
+ for r in commit.removed
106
+ ]
107
+ branches = ", ".join(ref.removeprefix("refs/heads/") for ref in fixed.branches)
108
+ lines += [
109
+ "",
110
+ " Only commits that no remote has were changed; the old ones are in",
111
+ f" `git reflog`. Branch updated: {branches}.",
112
+ "",
113
+ " This push was stopped (Git had already chosen what to send).",
114
+ " Run `git push` again to send the cleaned commits.",
115
+ ]
116
+ return "\n".join(lines)
117
+
118
+
89
119
  def _finish(run: HookRun, text: str) -> None:
90
120
  if not run.enabled:
91
121
  _err(
@@ -95,6 +125,10 @@ def _finish(run: HookRun, text: str) -> None:
95
125
  return
96
126
  if run.removed:
97
127
  _err(_removal_notice(run))
128
+ if run.fixed is not None:
129
+ # The commits being pushed are the old ones: this push must not proceed.
130
+ _err(_push_fix_notice(run.fixed))
131
+ raise typer.Exit(code=int(ExitCode.BLOCKED))
98
132
  _err(text)
99
133
  if run.report is not None and run.report.action is Action.BLOCK:
100
134
  raise typer.Exit(code=int(ExitCode.BLOCKED))
@@ -153,13 +153,15 @@ def render_check_text(report: ScanReport) -> str:
153
153
  # --------------------------------------------------------------------------- #
154
154
  _PUSH_REMEDIATION = [
155
155
  "How to fix:",
156
- " CommitGuard never modifies commits. Rewrite the blocked commits so they no",
157
- " longer carry the attribution, then push again:",
156
+ " CommitGuard did not change these commits. Rewrite the blocked commits so",
157
+ " they no longer carry the attribution, then push again:",
158
158
  " - latest commit only: git commit --amend",
159
159
  " (replaces that one local commit with an edited copy)",
160
160
  " - older commits: git rebase -i <commit>^ and mark them 'reword'",
161
161
  " (recreates the selected commits and every commit after them)",
162
162
  " Only rewrite commits that have not already been shared with others.",
163
+ " To have CommitGuard do this for unpushed commits, set",
164
+ " remediation.fix_on_push: true (see docs/configuration.md).",
163
165
  ]
164
166
 
165
167
 
@@ -46,8 +46,12 @@ enforcement:
46
46
  # What to do about a violation. By default CommitGuard blocks and leaves the
47
47
  # message to you. Set auto_remove: true and the commit-msg hook deletes the
48
48
  # offending lines instead, reports what it removed, and lets the commit through.
49
- # Attribution in the author or committer identity still blocks: no edit to the
50
- # message can fix that. `commitguard doctor` shows when this is on.
49
+ # Set fix_on_push: true and pre-push also rewrites unpushed commits that skipped
50
+ # commit-msg (--no-verify, cherry-pick, rebase), then asks you to push again; it
51
+ # never touches a commit any remote already has. Attribution in the author or
52
+ # committer identity always blocks: no edit to the message can fix that.
53
+ # `commitguard doctor` shows when either is on.
51
54
  # remediation:
52
55
  # auto_remove: true
56
+ # fix_on_push: true
53
57
  """
@@ -41,6 +41,7 @@ class Remediation(BaseModel):
41
41
  model_config = ConfigDict(frozen=True, extra="forbid")
42
42
 
43
43
  auto_remove: bool = False
44
+ fix_on_push: bool = False
44
45
 
45
46
 
46
47
  def build_remediation(*configs: CommitGuardConfig) -> Remediation:
@@ -64,13 +64,21 @@ class RemediationOverride(BaseModel):
64
64
  it is then clean.
65
65
 
66
66
  It is off by default, because it edits what the developer wrote.
67
+
68
+ ``fix_on_push`` covers the commits ``commit-msg`` never saw (``--no-verify``,
69
+ cherry-pick, rebase, ``git am``). The ``pre-push`` hook rewrites the
70
+ *unpushed* commits on the branch to remove the same lines, then stops that
71
+ push: Git has already chosen which objects to send, so the corrected
72
+ commits go out on the next ``git push``. This rewrites history, so it is a
73
+ separate switch and also off by default.
67
74
  """
68
75
 
69
76
  model_config = ConfigDict(frozen=True, extra="forbid")
70
77
 
71
78
  auto_remove: StrictBool | None = None
79
+ fix_on_push: StrictBool | None = None
72
80
 
73
- @field_validator("auto_remove", mode="before")
81
+ @field_validator("auto_remove", "fix_on_push", mode="before")
74
82
  @classmethod
75
83
  def _reject_explicit_null(cls, value: object) -> object:
76
84
  if value is None:
@@ -69,7 +69,7 @@ class IdentityDetector(Detector):
69
69
  commit_sha=commit.sha,
70
70
  remediation=(
71
71
  "Recreate the commit under the responsible human contributor's identity "
72
- "before pushing. CommitGuard never rewrites commits itself."
72
+ "before pushing. CommitGuard never changes who authored a commit."
73
73
  ),
74
74
  )
75
75
  )
@@ -386,6 +386,79 @@ class Repository:
386
386
  raise UnsafeInputError(f"{path} at {commit[:12]} is larger than {max_bytes} bytes")
387
387
  return self._git(["cat-file", "blob", oid]).stdout
388
388
 
389
+ # ------------------------------------------------------------------ #
390
+ # Rewriting unpushed commits (remediation.fix_on_push)
391
+ # ------------------------------------------------------------------ #
392
+ #: State files that mean a rebase, merge, cherry-pick, revert or bisect is
393
+ #: in progress. Moving a branch underneath one of those corrupts it.
394
+ _IN_PROGRESS = (
395
+ "rebase-merge",
396
+ "rebase-apply",
397
+ "MERGE_HEAD",
398
+ "CHERRY_PICK_HEAD",
399
+ "REVERT_HEAD",
400
+ "BISECT_LOG",
401
+ )
402
+
403
+ def operation_in_progress(self) -> str | None:
404
+ """Name of an unfinished rebase/merge/cherry-pick/revert/bisect, if any."""
405
+ for name in self._IN_PROGRESS:
406
+ result = self._git(["rev-parse", "--git-path", name])
407
+ path = Path(result.stdout.decode("utf-8", errors="replace").strip())
408
+ if not path.is_absolute():
409
+ path = self.root / path
410
+ if path.exists():
411
+ return name
412
+ return None
413
+
414
+ def read_raw_commit(self, sha: str) -> bytes:
415
+ """The commit object exactly as stored (headers, blank line, message)."""
416
+ if not is_git_sha(sha):
417
+ raise UnsafeInputError("read_raw_commit requires a full commit id")
418
+ return self._git(["cat-file", "commit", sha]).stdout
419
+
420
+ def write_commit_object(self, data: bytes) -> str:
421
+ """Store a commit object and return its id. Nothing references it yet."""
422
+ result = self._git(["hash-object", "-t", "commit", "-w", "--stdin"], input_bytes=data)
423
+ sha = result.stdout.decode("ascii", errors="replace").strip()
424
+ if not is_git_sha(sha):
425
+ raise MalformedGitOutputError("git hash-object returned no object id")
426
+ return sha
427
+
428
+ def not_on_any_remote(self, shas: Sequence[str]) -> set[str]:
429
+ """The subset of ``shas`` not reachable from any remote-tracking branch.
430
+
431
+ A commit that some remote already has - even a different remote than the
432
+ one being pushed to - has been shared, and must never be rewritten.
433
+ """
434
+ for sha in shas:
435
+ if not is_git_sha(sha):
436
+ raise UnsafeInputError("not_on_any_remote requires full commit ids")
437
+ if not shas:
438
+ return set()
439
+ result = self._git(
440
+ ["rev-list", "--not", "--remotes", "--not", "--end-of-options", *shas, "--"]
441
+ )
442
+ reachable = set(result.stdout.decode("ascii", errors="replace").split())
443
+ return {sha for sha in shas if sha in reachable}
444
+
445
+ def move_branches(self, moves: Sequence[tuple[str, str, str]], reason: str) -> None:
446
+ """Atomically point each ``refs/heads/...`` at a new commit.
447
+
448
+ Each move is ``(ref, new, old)`` and applies only if the ref still points
449
+ at ``old``; either every ref moves or none does. Old commits stay in the
450
+ reflog.
451
+ """
452
+ lines = []
453
+ for ref, new, old in moves:
454
+ if not ref.startswith("refs/heads/") or any(ord(c) <= 0x20 for c in ref):
455
+ raise UnsafeInputError("move_branches only updates local branches")
456
+ if not (is_git_sha(new) and is_git_sha(old)):
457
+ raise UnsafeInputError("move_branches requires full commit ids")
458
+ lines.append(f"update {ref} {new} {old}\n")
459
+ payload = "start\n" + "".join(lines) + "prepare\ncommit\n"
460
+ self._git(["update-ref", "-m", reason, "--stdin"], input_bytes=payload.encode("ascii"))
461
+
389
462
  def config_get(self, key: str) -> str | None:
390
463
  """Return a Git configuration value, or None if it is unset."""
391
464
  validate_git_config_key(key)