git-commit-guard 0.22.2__tar.gz → 0.22.3__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.
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.github/workflows/coverage-baseline.yml +2 -2
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.github/workflows/coverage-comment.yml +2 -2
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.github/workflows/lint-commits.yml +1 -1
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.github/workflows/lint-md.yml +1 -1
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.github/workflows/lint-workflows.yml +2 -2
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.github/workflows/release.yml +1 -1
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.github/workflows/security-audit.yml +4 -2
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.github/workflows/test.yml +2 -2
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/PKG-INFO +12 -12
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/README.md +11 -11
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/docs/index.html +8 -8
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/src/git_commit_guard/__init__.py +11 -11
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/tests/test_git_commit_guard.py +63 -48
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.editorconfig +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.github/workflows/lint-python.yml +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.gitignore +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.markdownlint.json +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.pre-commit-hooks.yaml +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/.python-version +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/LICENSE +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/action.yml +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/cliff.toml +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/docs/commit-guard-icon.svg +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/pyproject.toml +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/ruff.toml +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/tests/__init__.py +0 -0
- {git_commit_guard-0.22.2 → git_commit_guard-0.22.3}/uv.lock +0 -0
|
@@ -16,7 +16,7 @@ jobs:
|
|
|
16
16
|
persist-credentials: false
|
|
17
17
|
- name: Install uv
|
|
18
18
|
# yamllint disable-line rule:line-length
|
|
19
|
-
uses: astral-sh/setup-uv@
|
|
19
|
+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # ratchet:astral-sh/setup-uv@v8.2.0
|
|
20
20
|
- name: Cache NLTK data
|
|
21
21
|
# yamllint disable-line rule:line-length
|
|
22
22
|
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
run: uv run --dev pytest tests/ --cov=git_commit_guard --cov-report=xml
|
|
28
28
|
- name: Upload coverage baseline
|
|
29
29
|
# yamllint disable-line rule:line-length
|
|
30
|
-
uses: actions/upload-artifact@
|
|
30
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # ratchet:actions/upload-artifact@v7
|
|
31
31
|
with:
|
|
32
32
|
name: main-coverage
|
|
33
33
|
path: coverage.xml
|
|
@@ -16,7 +16,7 @@ jobs:
|
|
|
16
16
|
steps:
|
|
17
17
|
- name: Download artifact
|
|
18
18
|
# yamllint disable-line rule:line-length
|
|
19
|
-
uses: actions/download-artifact@
|
|
19
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8
|
|
20
20
|
with:
|
|
21
21
|
run-id: ${{ github.event.workflow_run.id }}
|
|
22
22
|
name: pr
|
|
@@ -57,7 +57,7 @@ jobs:
|
|
|
57
57
|
- name: Download baseline coverage
|
|
58
58
|
if: steps.baseline.outputs.run-id != ''
|
|
59
59
|
# yamllint disable-line rule:line-length
|
|
60
|
-
uses: actions/download-artifact@
|
|
60
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8
|
|
61
61
|
with:
|
|
62
62
|
run-id: ${{ steps.baseline.outputs.run-id }}
|
|
63
63
|
name: main-coverage
|
|
@@ -22,6 +22,6 @@ jobs:
|
|
|
22
22
|
key: nltk-averaged-perceptron-tagger-punkt
|
|
23
23
|
- name: Lint commits
|
|
24
24
|
# yamllint disable-line rule:line-length
|
|
25
|
-
uses: benner/commit-guard@
|
|
25
|
+
uses: benner/commit-guard@e156ca25789cc1824f745d74209f9c2654135dca # v0.22.2
|
|
26
26
|
with:
|
|
27
27
|
range: origin/${{ github.base_ref }}..HEAD
|
|
@@ -37,7 +37,7 @@ jobs:
|
|
|
37
37
|
persist-credentials: false
|
|
38
38
|
- name: Set up uv
|
|
39
39
|
# yamllint disable-line rule:line-length
|
|
40
|
-
uses: astral-sh/setup-uv@
|
|
40
|
+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
|
|
41
41
|
with:
|
|
42
42
|
enable-cache: false
|
|
43
43
|
- name: Set up reviewdog
|
|
@@ -34,7 +34,7 @@ jobs:
|
|
|
34
34
|
persist-credentials: false
|
|
35
35
|
- name: Set up uv
|
|
36
36
|
# yamllint disable-line rule:line-length
|
|
37
|
-
uses: astral-sh/setup-uv@
|
|
37
|
+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # ratchet:astral-sh/setup-uv@v8.2.0
|
|
38
38
|
- name: Set up reviewdog
|
|
39
39
|
# yamllint disable-line rule:line-length
|
|
40
40
|
uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # ratchet:reviewdog/action-setup@v1
|
|
@@ -59,7 +59,7 @@ jobs:
|
|
|
59
59
|
persist-credentials: false
|
|
60
60
|
- name: Set up uv
|
|
61
61
|
# yamllint disable-line rule:line-length
|
|
62
|
-
uses: astral-sh/setup-uv@
|
|
62
|
+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # ratchet:astral-sh/setup-uv@v8.2.0
|
|
63
63
|
- name: Set up reviewdog
|
|
64
64
|
# yamllint disable-line rule:line-length
|
|
65
65
|
uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # ratchet:reviewdog/action-setup@v1
|
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
fetch-depth: 0
|
|
21
21
|
- name: Set up uv
|
|
22
22
|
# yamllint disable-line rule:line-length
|
|
23
|
-
uses: astral-sh/setup-uv@
|
|
23
|
+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
|
|
24
24
|
with:
|
|
25
25
|
enable-cache: false
|
|
26
26
|
- name: Build package
|
|
@@ -17,6 +17,8 @@ jobs:
|
|
|
17
17
|
persist-credentials: false
|
|
18
18
|
- name: Install uv
|
|
19
19
|
# yamllint disable-line rule:line-length
|
|
20
|
-
uses: astral-sh/setup-uv@
|
|
20
|
+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
|
|
21
21
|
- name: Audit dependencies
|
|
22
|
-
run:
|
|
22
|
+
run: >-
|
|
23
|
+
uv audit --frozen --preview-features audit-command
|
|
24
|
+
--ignore-until-fixed GHSA-p4gq-832x-fm9v
|
|
@@ -15,7 +15,7 @@ jobs:
|
|
|
15
15
|
persist-credentials: false
|
|
16
16
|
- name: Install uv
|
|
17
17
|
# yamllint disable-line rule:line-length
|
|
18
|
-
uses: astral-sh/setup-uv@
|
|
18
|
+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
|
|
19
19
|
- name: Cache NLTK data
|
|
20
20
|
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
|
21
21
|
with:
|
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
cp coverage.xml ./pr/
|
|
36
36
|
- name: Upload PR artifact
|
|
37
37
|
# yamllint disable-line rule:line-length
|
|
38
|
-
uses: actions/upload-artifact@
|
|
38
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # ratchet:actions/upload-artifact@v7
|
|
39
39
|
with:
|
|
40
40
|
name: pr
|
|
41
41
|
path: pr/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-commit-guard
|
|
3
|
-
Version: 0.22.
|
|
3
|
+
Version: 0.22.3
|
|
4
4
|
Summary: Opinionated conventional commit message linter with imperative mood detection
|
|
5
5
|
Project-URL: Homepage, https://github.com/benner/commit-guard
|
|
6
6
|
Project-URL: Repository, https://github.com/benner/commit-guard
|
|
@@ -36,7 +36,7 @@ Opinionated conventional commit message linter with imperative mood detection.
|
|
|
36
36
|
verb, verified via nltk POS tagging — not a hand-coded regex of "bad"
|
|
37
37
|
words.
|
|
38
38
|
* **Signature verification without a local keyring.** Resolves the commit
|
|
39
|
-
|
|
39
|
+
committer via the GitHub API and verifies GPG/SSH against their published
|
|
40
40
|
`.gpg`/`.keys` — no per-runner key management.
|
|
41
41
|
* **Strict by default.** Subject format, body, trailers, `Signed-off-by`,
|
|
42
42
|
and signature all enforced out of the box; opt out with `--disable`.
|
|
@@ -242,7 +242,7 @@ independently of `--enable`/`--disable`.
|
|
|
242
242
|
The `signature` check verifies the commit without any local keyring setup:
|
|
243
243
|
|
|
244
244
|
1. If the repo has a GitHub remote, call the Commits API
|
|
245
|
-
(`GET /repos/{owner}/{repo}/commits/{sha}`) to resolve the
|
|
245
|
+
(`GET /repos/{owner}/{repo}/commits/{sha}`) to resolve the committer's GitHub
|
|
246
246
|
username — this works for corporate emails, noreply addresses, or any email
|
|
247
247
|
not listed publicly on a GitHub profile.
|
|
248
248
|
2. If the Commits API is unavailable (no GitHub remote, commit not yet pushed,
|
|
@@ -250,7 +250,7 @@ The `signature` check verifies the commit without any local keyring setup:
|
|
|
250
250
|
(`{id}+{username}@users.noreply.github.com` or
|
|
251
251
|
`{username}@users.noreply.github.com`) — no API call needed.
|
|
252
252
|
3. If neither of the above resolves a username, fall back to searching GitHub
|
|
253
|
-
by the commit
|
|
253
|
+
by the commit committer's email.
|
|
254
254
|
4. Fetch the resolved user's public keys from `github.com/{username}.gpg`
|
|
255
255
|
(GPG) and the `/users/{username}/ssh_signing_keys` API (SSH keys tagged
|
|
256
256
|
with the **Signing key** role). Auth-only SSH keys are deliberately not
|
|
@@ -261,7 +261,7 @@ The `signature` check verifies the commit without any local keyring setup:
|
|
|
261
261
|
`git verify-commit` with the SSH allowed-signers config.
|
|
262
262
|
7. If any key verifies, the check passes. If none do, it fails.
|
|
263
263
|
|
|
264
|
-
If the
|
|
264
|
+
If the committer cannot be resolved via either method, or the GitHub API is
|
|
265
265
|
unreachable, the check fails with a clear error.
|
|
266
266
|
|
|
267
267
|
For private repositories, set `GITHUB_TOKEN` or `GH_TOKEN` so the Commits API
|
|
@@ -316,7 +316,7 @@ COMMIT_GUARD_GIT_TIMEOUT=30 commit-guard --range origin/main..HEAD
|
|
|
316
316
|
In GitHub Actions, set it at the step or job level:
|
|
317
317
|
|
|
318
318
|
```yaml
|
|
319
|
-
- uses: benner/commit-guard@v0.22.
|
|
319
|
+
- uses: benner/commit-guard@v0.22.3
|
|
320
320
|
env:
|
|
321
321
|
COMMIT_GUARD_GIT_TIMEOUT: 30
|
|
322
322
|
with:
|
|
@@ -400,7 +400,7 @@ steps:
|
|
|
400
400
|
- uses: actions/checkout@v4
|
|
401
401
|
with:
|
|
402
402
|
fetch-depth: 0
|
|
403
|
-
- uses: benner/commit-guard@v0.22.
|
|
403
|
+
- uses: benner/commit-guard@v0.22.3
|
|
404
404
|
```
|
|
405
405
|
|
|
406
406
|
Check all commits in a pull request:
|
|
@@ -416,7 +416,7 @@ jobs:
|
|
|
416
416
|
- uses: actions/checkout@v4
|
|
417
417
|
with:
|
|
418
418
|
fetch-depth: 0
|
|
419
|
-
- uses: benner/commit-guard@v0.22.
|
|
419
|
+
- uses: benner/commit-guard@v0.22.3
|
|
420
420
|
with:
|
|
421
421
|
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
422
422
|
```
|
|
@@ -424,7 +424,7 @@ jobs:
|
|
|
424
424
|
Check a specific commit SHA (mirrors the positional CLI argument):
|
|
425
425
|
|
|
426
426
|
```yaml
|
|
427
|
-
- uses: benner/commit-guard@v0.22.
|
|
427
|
+
- uses: benner/commit-guard@v0.22.3
|
|
428
428
|
with:
|
|
429
429
|
rev: ${{ github.sha }}
|
|
430
430
|
```
|
|
@@ -442,7 +442,7 @@ jobs:
|
|
|
442
442
|
- uses: actions/checkout@v4
|
|
443
443
|
with:
|
|
444
444
|
fetch-depth: 0
|
|
445
|
-
- uses: benner/commit-guard@v0.22.
|
|
445
|
+
- uses: benner/commit-guard@v0.22.3
|
|
446
446
|
with:
|
|
447
447
|
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
448
448
|
disable: signed-off,signature
|
|
@@ -462,7 +462,7 @@ jobs:
|
|
|
462
462
|
When `output-file` is set the action exposes the path as an output:
|
|
463
463
|
|
|
464
464
|
```yaml
|
|
465
|
-
- uses: benner/commit-guard@v0.22.
|
|
465
|
+
- uses: benner/commit-guard@v0.22.3
|
|
466
466
|
id: cg
|
|
467
467
|
with:
|
|
468
468
|
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
@@ -478,7 +478,7 @@ Add to your `.pre-commit-config.yaml`:
|
|
|
478
478
|
---
|
|
479
479
|
repos:
|
|
480
480
|
- repo: https://github.com/benner/commit-guard
|
|
481
|
-
rev: v0.22.
|
|
481
|
+
rev: v0.22.3
|
|
482
482
|
hooks:
|
|
483
483
|
- id: commit-guard
|
|
484
484
|
- id: commit-guard-signature
|
|
@@ -15,7 +15,7 @@ Opinionated conventional commit message linter with imperative mood detection.
|
|
|
15
15
|
verb, verified via nltk POS tagging — not a hand-coded regex of "bad"
|
|
16
16
|
words.
|
|
17
17
|
* **Signature verification without a local keyring.** Resolves the commit
|
|
18
|
-
|
|
18
|
+
committer via the GitHub API and verifies GPG/SSH against their published
|
|
19
19
|
`.gpg`/`.keys` — no per-runner key management.
|
|
20
20
|
* **Strict by default.** Subject format, body, trailers, `Signed-off-by`,
|
|
21
21
|
and signature all enforced out of the box; opt out with `--disable`.
|
|
@@ -221,7 +221,7 @@ independently of `--enable`/`--disable`.
|
|
|
221
221
|
The `signature` check verifies the commit without any local keyring setup:
|
|
222
222
|
|
|
223
223
|
1. If the repo has a GitHub remote, call the Commits API
|
|
224
|
-
(`GET /repos/{owner}/{repo}/commits/{sha}`) to resolve the
|
|
224
|
+
(`GET /repos/{owner}/{repo}/commits/{sha}`) to resolve the committer's GitHub
|
|
225
225
|
username — this works for corporate emails, noreply addresses, or any email
|
|
226
226
|
not listed publicly on a GitHub profile.
|
|
227
227
|
2. If the Commits API is unavailable (no GitHub remote, commit not yet pushed,
|
|
@@ -229,7 +229,7 @@ The `signature` check verifies the commit without any local keyring setup:
|
|
|
229
229
|
(`{id}+{username}@users.noreply.github.com` or
|
|
230
230
|
`{username}@users.noreply.github.com`) — no API call needed.
|
|
231
231
|
3. If neither of the above resolves a username, fall back to searching GitHub
|
|
232
|
-
by the commit
|
|
232
|
+
by the commit committer's email.
|
|
233
233
|
4. Fetch the resolved user's public keys from `github.com/{username}.gpg`
|
|
234
234
|
(GPG) and the `/users/{username}/ssh_signing_keys` API (SSH keys tagged
|
|
235
235
|
with the **Signing key** role). Auth-only SSH keys are deliberately not
|
|
@@ -240,7 +240,7 @@ The `signature` check verifies the commit without any local keyring setup:
|
|
|
240
240
|
`git verify-commit` with the SSH allowed-signers config.
|
|
241
241
|
7. If any key verifies, the check passes. If none do, it fails.
|
|
242
242
|
|
|
243
|
-
If the
|
|
243
|
+
If the committer cannot be resolved via either method, or the GitHub API is
|
|
244
244
|
unreachable, the check fails with a clear error.
|
|
245
245
|
|
|
246
246
|
For private repositories, set `GITHUB_TOKEN` or `GH_TOKEN` so the Commits API
|
|
@@ -295,7 +295,7 @@ COMMIT_GUARD_GIT_TIMEOUT=30 commit-guard --range origin/main..HEAD
|
|
|
295
295
|
In GitHub Actions, set it at the step or job level:
|
|
296
296
|
|
|
297
297
|
```yaml
|
|
298
|
-
- uses: benner/commit-guard@v0.22.
|
|
298
|
+
- uses: benner/commit-guard@v0.22.3
|
|
299
299
|
env:
|
|
300
300
|
COMMIT_GUARD_GIT_TIMEOUT: 30
|
|
301
301
|
with:
|
|
@@ -379,7 +379,7 @@ steps:
|
|
|
379
379
|
- uses: actions/checkout@v4
|
|
380
380
|
with:
|
|
381
381
|
fetch-depth: 0
|
|
382
|
-
- uses: benner/commit-guard@v0.22.
|
|
382
|
+
- uses: benner/commit-guard@v0.22.3
|
|
383
383
|
```
|
|
384
384
|
|
|
385
385
|
Check all commits in a pull request:
|
|
@@ -395,7 +395,7 @@ jobs:
|
|
|
395
395
|
- uses: actions/checkout@v4
|
|
396
396
|
with:
|
|
397
397
|
fetch-depth: 0
|
|
398
|
-
- uses: benner/commit-guard@v0.22.
|
|
398
|
+
- uses: benner/commit-guard@v0.22.3
|
|
399
399
|
with:
|
|
400
400
|
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
401
401
|
```
|
|
@@ -403,7 +403,7 @@ jobs:
|
|
|
403
403
|
Check a specific commit SHA (mirrors the positional CLI argument):
|
|
404
404
|
|
|
405
405
|
```yaml
|
|
406
|
-
- uses: benner/commit-guard@v0.22.
|
|
406
|
+
- uses: benner/commit-guard@v0.22.3
|
|
407
407
|
with:
|
|
408
408
|
rev: ${{ github.sha }}
|
|
409
409
|
```
|
|
@@ -421,7 +421,7 @@ jobs:
|
|
|
421
421
|
- uses: actions/checkout@v4
|
|
422
422
|
with:
|
|
423
423
|
fetch-depth: 0
|
|
424
|
-
- uses: benner/commit-guard@v0.22.
|
|
424
|
+
- uses: benner/commit-guard@v0.22.3
|
|
425
425
|
with:
|
|
426
426
|
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
427
427
|
disable: signed-off,signature
|
|
@@ -441,7 +441,7 @@ jobs:
|
|
|
441
441
|
When `output-file` is set the action exposes the path as an output:
|
|
442
442
|
|
|
443
443
|
```yaml
|
|
444
|
-
- uses: benner/commit-guard@v0.22.
|
|
444
|
+
- uses: benner/commit-guard@v0.22.3
|
|
445
445
|
id: cg
|
|
446
446
|
with:
|
|
447
447
|
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
@@ -457,7 +457,7 @@ Add to your `.pre-commit-config.yaml`:
|
|
|
457
457
|
---
|
|
458
458
|
repos:
|
|
459
459
|
- repo: https://github.com/benner/commit-guard
|
|
460
|
-
rev: v0.22.
|
|
460
|
+
rev: v0.22.3
|
|
461
461
|
hooks:
|
|
462
462
|
- id: commit-guard
|
|
463
463
|
- id: commit-guard-signature
|
|
@@ -315,7 +315,7 @@
|
|
|
315
315
|
</li>
|
|
316
316
|
<li>
|
|
317
317
|
<strong>Signature verification without a local keyring.</strong>
|
|
318
|
-
Resolves the commit
|
|
318
|
+
Resolves the commit committer via the GitHub API and verifies GPG/SSH
|
|
319
319
|
against their published <code>.gpg</code>/<code>.keys</code> — no
|
|
320
320
|
per-runner key management.
|
|
321
321
|
</li>
|
|
@@ -456,7 +456,7 @@ require-subject-pattern = "[A-Z]+-[0-9]+"</code></pre>
|
|
|
456
456
|
<ol>
|
|
457
457
|
<li>If the repo has a GitHub remote, call the Commits API
|
|
458
458
|
(<code>GET /repos/{owner}/{repo}/commits/{sha}</code>) to resolve
|
|
459
|
-
the
|
|
459
|
+
the committer's GitHub username — works for corporate emails, noreply
|
|
460
460
|
addresses, or any email not listed publicly on a GitHub profile.</li>
|
|
461
461
|
<li>If the Commits API is unavailable (no GitHub remote, commit not
|
|
462
462
|
yet pushed, or API error), parse the username directly from a
|
|
@@ -464,7 +464,7 @@ require-subject-pattern = "[A-Z]+-[0-9]+"</code></pre>
|
|
|
464
464
|
(<code>{id}+{username}@users.noreply.github.com</code>) — no API
|
|
465
465
|
call needed.</li>
|
|
466
466
|
<li>If neither of the above resolves a username, fall back to
|
|
467
|
-
searching GitHub by the commit
|
|
467
|
+
searching GitHub by the commit committer's email.</li>
|
|
468
468
|
<li>Fetch the resolved user's public keys from
|
|
469
469
|
<code>github.com/{username}.gpg</code> (GPG) and
|
|
470
470
|
<code>/users/{username}/ssh_signing_keys</code> (SSH keys tagged
|
|
@@ -476,7 +476,7 @@ require-subject-pattern = "[A-Z]+-[0-9]+"</code></pre>
|
|
|
476
476
|
<li>Pass if any key verifies; fail if none do.</li>
|
|
477
477
|
</ol>
|
|
478
478
|
<p>
|
|
479
|
-
If the
|
|
479
|
+
If the committer cannot be resolved via either method, or the GitHub API
|
|
480
480
|
is unreachable, the check fails with a clear error. For private
|
|
481
481
|
repositories, set <code>GITHUB_TOKEN</code> or <code>GH_TOKEN</code>
|
|
482
482
|
so the Commits API can authenticate. The official GitHub Action wires
|
|
@@ -566,13 +566,13 @@ require-subject-pattern = "[A-Z]+-[0-9]+"</code></pre>
|
|
|
566
566
|
- uses: actions/checkout@v4
|
|
567
567
|
with:
|
|
568
568
|
fetch-depth: 0
|
|
569
|
-
- uses: benner/commit-guard@v0.22.
|
|
569
|
+
- uses: benner/commit-guard@v0.22.3
|
|
570
570
|
with:
|
|
571
571
|
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
572
572
|
disable: signed-off,signature</code></pre>
|
|
573
573
|
|
|
574
574
|
<p>Check a specific commit SHA:</p>
|
|
575
|
-
<pre><code class="language-yaml"> - uses: benner/commit-guard@v0.22.
|
|
575
|
+
<pre><code class="language-yaml"> - uses: benner/commit-guard@v0.22.3
|
|
576
576
|
with:
|
|
577
577
|
rev: ${{ github.sha }}</code></pre>
|
|
578
578
|
|
|
@@ -591,7 +591,7 @@ require-subject-pattern = "[A-Z]+-[0-9]+"</code></pre>
|
|
|
591
591
|
When <code>output-file</code> is set the action exposes the path as
|
|
592
592
|
a step output, making JSONL results available to subsequent steps:
|
|
593
593
|
</p>
|
|
594
|
-
<pre><code class="language-yaml"> - uses: benner/commit-guard@v0.22.
|
|
594
|
+
<pre><code class="language-yaml"> - uses: benner/commit-guard@v0.22.3
|
|
595
595
|
id: cg
|
|
596
596
|
with:
|
|
597
597
|
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
@@ -604,7 +604,7 @@ require-subject-pattern = "[A-Z]+-[0-9]+"</code></pre>
|
|
|
604
604
|
<p>Add to <code>.pre-commit-config.yaml</code>:</p>
|
|
605
605
|
<pre><code class="language-yaml">repos:
|
|
606
606
|
- repo: https://github.com/benner/commit-guard
|
|
607
|
-
rev: v0.22.
|
|
607
|
+
rev: v0.22.3
|
|
608
608
|
hooks:
|
|
609
609
|
- id: commit-guard
|
|
610
610
|
- id: commit-guard-signature</code></pre>
|
|
@@ -295,9 +295,9 @@ def check_required_trailers(message, required, result):
|
|
|
295
295
|
result.error(f"missing required trailer: {trailer}")
|
|
296
296
|
|
|
297
297
|
|
|
298
|
-
def
|
|
298
|
+
def _get_committer_email(rev):
|
|
299
299
|
return subprocess.check_output( # noqa: S603
|
|
300
|
-
["git", "log", "-1", "--format=%
|
|
300
|
+
["git", "log", "-1", "--format=%ce", rev], # noqa: S607
|
|
301
301
|
text=True,
|
|
302
302
|
stderr=subprocess.PIPE,
|
|
303
303
|
timeout=_git_timeout(),
|
|
@@ -320,7 +320,7 @@ def _get_github_remote_info():
|
|
|
320
320
|
return match.group("owner"), match.group("repo")
|
|
321
321
|
|
|
322
322
|
|
|
323
|
-
def
|
|
323
|
+
def _fetch_github_commit_committer(owner, repo, sha):
|
|
324
324
|
url = f"https://api.github.com/repos/{owner}/{repo}/commits/{sha}"
|
|
325
325
|
headers = {"Accept": "application/vnd.github+json"}
|
|
326
326
|
token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")
|
|
@@ -329,8 +329,8 @@ def _fetch_github_commit_author(owner, repo, sha):
|
|
|
329
329
|
req = urllib.request.Request(url, headers=headers) # noqa: S310 Audit URL open for permitted schemes
|
|
330
330
|
with urllib.request.urlopen(req, timeout=_git_timeout()) as resp: # noqa: S310 Audit URL open for permitted schemes
|
|
331
331
|
data = json.loads(resp.read())
|
|
332
|
-
|
|
333
|
-
return
|
|
332
|
+
committer = data.get("committer")
|
|
333
|
+
return committer["login"] if committer else None
|
|
334
334
|
|
|
335
335
|
|
|
336
336
|
def _parse_noreply_username(email):
|
|
@@ -435,7 +435,7 @@ def _resolve_github_username(rev, email):
|
|
|
435
435
|
if remote:
|
|
436
436
|
owner, repo = remote
|
|
437
437
|
try:
|
|
438
|
-
username =
|
|
438
|
+
username = _fetch_github_commit_committer(owner, repo, rev)
|
|
439
439
|
except urllib.error.HTTPError as e:
|
|
440
440
|
if e.code == HTTPStatus.NOT_FOUND:
|
|
441
441
|
commits_api_404 = True
|
|
@@ -450,24 +450,24 @@ def _resolve_github_username(rev, email):
|
|
|
450
450
|
return username, commits_api_404
|
|
451
451
|
|
|
452
452
|
|
|
453
|
-
def
|
|
453
|
+
def _committer_not_found_message(commits_api_404):
|
|
454
454
|
had_token = bool(os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN"))
|
|
455
455
|
if commits_api_404 and not had_token:
|
|
456
456
|
return (
|
|
457
|
-
"
|
|
457
|
+
"committer not found on GitHub — if the repo is private, "
|
|
458
458
|
"set GITHUB_TOKEN in the workflow step "
|
|
459
459
|
"(env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }})"
|
|
460
460
|
)
|
|
461
|
-
return "
|
|
461
|
+
return "committer not found on GitHub — cannot verify signature"
|
|
462
462
|
|
|
463
463
|
|
|
464
464
|
def check_signature(rev, result):
|
|
465
465
|
try:
|
|
466
|
-
email =
|
|
466
|
+
email = _get_committer_email(rev)
|
|
467
467
|
username, commits_api_404 = _resolve_github_username(rev, email)
|
|
468
468
|
if username is None:
|
|
469
469
|
result.error(
|
|
470
|
-
|
|
470
|
+
_committer_not_found_message(commits_api_404),
|
|
471
471
|
check=Check.SIGNATURE,
|
|
472
472
|
)
|
|
473
473
|
return
|
|
@@ -15,12 +15,12 @@ from git_commit_guard import (
|
|
|
15
15
|
Result,
|
|
16
16
|
_download_if_missing,
|
|
17
17
|
_ensure_nltk_data,
|
|
18
|
-
|
|
18
|
+
_fetch_github_commit_committer,
|
|
19
19
|
_fetch_github_keys,
|
|
20
20
|
_fetch_github_signing_keys,
|
|
21
21
|
_fetch_github_username,
|
|
22
22
|
_fetch_url,
|
|
23
|
-
|
|
23
|
+
_get_committer_email,
|
|
24
24
|
_get_github_remote_info,
|
|
25
25
|
_get_message,
|
|
26
26
|
_get_range_revs,
|
|
@@ -625,13 +625,14 @@ class TestDownloadIfMissing:
|
|
|
625
625
|
mock_dl.assert_called_once_with("punkt_tab", quiet=True)
|
|
626
626
|
|
|
627
627
|
|
|
628
|
-
class
|
|
628
|
+
class TestGetCommitterEmail:
|
|
629
629
|
def test_returns_stripped_email(self):
|
|
630
630
|
with patch(
|
|
631
631
|
"git_commit_guard.subprocess.check_output",
|
|
632
632
|
return_value="user@example.com\n",
|
|
633
|
-
):
|
|
634
|
-
assert
|
|
633
|
+
) as mock_check:
|
|
634
|
+
assert _get_committer_email("abc123") == "user@example.com"
|
|
635
|
+
assert "--format=%ce" in mock_check.call_args.args[0]
|
|
635
636
|
|
|
636
637
|
|
|
637
638
|
class TestFetchUrl:
|
|
@@ -716,7 +717,7 @@ class TestGetGithubRemoteInfo:
|
|
|
716
717
|
assert _get_github_remote_info() is None
|
|
717
718
|
|
|
718
719
|
|
|
719
|
-
class
|
|
720
|
+
class TestFetchGithubCommitCommitter:
|
|
720
721
|
def _mock_response(self, data):
|
|
721
722
|
mock_resp = MagicMock()
|
|
722
723
|
mock_resp.__enter__ = lambda s: s
|
|
@@ -724,20 +725,31 @@ class TestFetchGithubCommitAuthor:
|
|
|
724
725
|
mock_resp.read.return_value = json.dumps(data).encode()
|
|
725
726
|
return mock_resp
|
|
726
727
|
|
|
727
|
-
def
|
|
728
|
-
resp = self._mock_response({"
|
|
728
|
+
def test_returns_committer_login(self):
|
|
729
|
+
resp = self._mock_response({"committer": {"login": "commituser"}})
|
|
730
|
+
with patch("git_commit_guard.urllib.request.urlopen", return_value=resp):
|
|
731
|
+
assert (
|
|
732
|
+
_fetch_github_commit_committer("owner", "repo", "abc123")
|
|
733
|
+
== "commituser"
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
def test_returns_committer_login_not_author(self):
|
|
737
|
+
resp = self._mock_response(
|
|
738
|
+
{"author": {"login": "the-author"}, "committer": {"login": "the-committer"}}
|
|
739
|
+
)
|
|
729
740
|
with patch("git_commit_guard.urllib.request.urlopen", return_value=resp):
|
|
730
741
|
assert (
|
|
731
|
-
|
|
742
|
+
_fetch_github_commit_committer("owner", "repo", "abc123")
|
|
743
|
+
== "the-committer"
|
|
732
744
|
)
|
|
733
745
|
|
|
734
|
-
def
|
|
735
|
-
resp = self._mock_response({"
|
|
746
|
+
def test_null_committer_returns_none(self):
|
|
747
|
+
resp = self._mock_response({"committer": None})
|
|
736
748
|
with patch("git_commit_guard.urllib.request.urlopen", return_value=resp):
|
|
737
|
-
assert
|
|
749
|
+
assert _fetch_github_commit_committer("owner", "repo", "abc123") is None
|
|
738
750
|
|
|
739
751
|
def test_github_token_sent_in_header(self):
|
|
740
|
-
resp = self._mock_response({"
|
|
752
|
+
resp = self._mock_response({"committer": {"login": "user"}})
|
|
741
753
|
captured = []
|
|
742
754
|
|
|
743
755
|
def mock_urlopen(req, **_):
|
|
@@ -748,11 +760,11 @@ class TestFetchGithubCommitAuthor:
|
|
|
748
760
|
patch("git_commit_guard.urllib.request.urlopen", side_effect=mock_urlopen),
|
|
749
761
|
patch.dict("os.environ", {"GITHUB_TOKEN": "mytoken"}, clear=False),
|
|
750
762
|
):
|
|
751
|
-
|
|
763
|
+
_fetch_github_commit_committer("owner", "repo", "abc123")
|
|
752
764
|
assert captured[0].get_header("Authorization") == "Bearer mytoken"
|
|
753
765
|
|
|
754
766
|
def test_gh_token_used_when_github_token_absent(self):
|
|
755
|
-
resp = self._mock_response({"
|
|
767
|
+
resp = self._mock_response({"committer": {"login": "user"}})
|
|
756
768
|
captured = []
|
|
757
769
|
|
|
758
770
|
def mock_urlopen(req, **_):
|
|
@@ -765,7 +777,7 @@ class TestFetchGithubCommitAuthor:
|
|
|
765
777
|
patch("git_commit_guard.urllib.request.urlopen", side_effect=mock_urlopen),
|
|
766
778
|
patch.dict("os.environ", env, clear=True),
|
|
767
779
|
):
|
|
768
|
-
|
|
780
|
+
_fetch_github_commit_committer("owner", "repo", "abc123")
|
|
769
781
|
assert captured[0].get_header("Authorization") == "Bearer ghtoken"
|
|
770
782
|
|
|
771
783
|
|
|
@@ -894,7 +906,7 @@ class TestCheckSignature:
|
|
|
894
906
|
r = Result()
|
|
895
907
|
with (
|
|
896
908
|
patch(
|
|
897
|
-
"git_commit_guard.
|
|
909
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
898
910
|
),
|
|
899
911
|
patch("git_commit_guard._get_github_remote_info", return_value=None),
|
|
900
912
|
patch("git_commit_guard._fetch_github_username", return_value="testuser"),
|
|
@@ -909,7 +921,7 @@ class TestCheckSignature:
|
|
|
909
921
|
r = Result()
|
|
910
922
|
with (
|
|
911
923
|
patch(
|
|
912
|
-
"git_commit_guard.
|
|
924
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
913
925
|
),
|
|
914
926
|
patch("git_commit_guard._get_github_remote_info", return_value=None),
|
|
915
927
|
patch("git_commit_guard._fetch_github_username", return_value="testuser"),
|
|
@@ -925,7 +937,7 @@ class TestCheckSignature:
|
|
|
925
937
|
r = Result()
|
|
926
938
|
with (
|
|
927
939
|
patch(
|
|
928
|
-
"git_commit_guard.
|
|
940
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
929
941
|
),
|
|
930
942
|
patch("git_commit_guard._get_github_remote_info", return_value=None),
|
|
931
943
|
patch("git_commit_guard._fetch_github_username", return_value="testuser"),
|
|
@@ -940,7 +952,7 @@ class TestCheckSignature:
|
|
|
940
952
|
r = Result()
|
|
941
953
|
with (
|
|
942
954
|
patch(
|
|
943
|
-
"git_commit_guard.
|
|
955
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
944
956
|
),
|
|
945
957
|
patch("git_commit_guard._get_github_remote_info", return_value=None),
|
|
946
958
|
patch("git_commit_guard._fetch_github_username", return_value=None),
|
|
@@ -956,14 +968,14 @@ class TestCheckSignature:
|
|
|
956
968
|
}
|
|
957
969
|
with (
|
|
958
970
|
patch(
|
|
959
|
-
"git_commit_guard.
|
|
971
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
960
972
|
),
|
|
961
973
|
patch(
|
|
962
974
|
"git_commit_guard._get_github_remote_info",
|
|
963
975
|
return_value=("owner", "repo"),
|
|
964
976
|
),
|
|
965
977
|
patch(
|
|
966
|
-
"git_commit_guard.
|
|
978
|
+
"git_commit_guard._fetch_github_commit_committer",
|
|
967
979
|
side_effect=urllib.error.HTTPError(
|
|
968
980
|
url="", code=404, msg="Not Found", hdrs=None, fp=None
|
|
969
981
|
),
|
|
@@ -979,14 +991,14 @@ class TestCheckSignature:
|
|
|
979
991
|
r = Result()
|
|
980
992
|
with (
|
|
981
993
|
patch(
|
|
982
|
-
"git_commit_guard.
|
|
994
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
983
995
|
),
|
|
984
996
|
patch(
|
|
985
997
|
"git_commit_guard._get_github_remote_info",
|
|
986
998
|
return_value=("owner", "repo"),
|
|
987
999
|
),
|
|
988
1000
|
patch(
|
|
989
|
-
"git_commit_guard.
|
|
1001
|
+
"git_commit_guard._fetch_github_commit_committer",
|
|
990
1002
|
side_effect=urllib.error.HTTPError(
|
|
991
1003
|
url="", code=404, msg="Not Found", hdrs=None, fp=None
|
|
992
1004
|
),
|
|
@@ -1003,14 +1015,14 @@ class TestCheckSignature:
|
|
|
1003
1015
|
r = Result()
|
|
1004
1016
|
with (
|
|
1005
1017
|
patch(
|
|
1006
|
-
"git_commit_guard.
|
|
1018
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
1007
1019
|
),
|
|
1008
1020
|
patch(
|
|
1009
1021
|
"git_commit_guard._get_github_remote_info",
|
|
1010
1022
|
return_value=("owner", "repo"),
|
|
1011
1023
|
),
|
|
1012
1024
|
patch(
|
|
1013
|
-
"git_commit_guard.
|
|
1025
|
+
"git_commit_guard._fetch_github_commit_committer",
|
|
1014
1026
|
side_effect=urllib.error.HTTPError(
|
|
1015
1027
|
url="", code=500, msg="Server Error", hdrs=None, fp=None
|
|
1016
1028
|
),
|
|
@@ -1026,14 +1038,14 @@ class TestCheckSignature:
|
|
|
1026
1038
|
r = Result()
|
|
1027
1039
|
with (
|
|
1028
1040
|
patch(
|
|
1029
|
-
"git_commit_guard.
|
|
1041
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
1030
1042
|
),
|
|
1031
1043
|
patch(
|
|
1032
1044
|
"git_commit_guard._get_github_remote_info",
|
|
1033
1045
|
return_value=("owner", "repo"),
|
|
1034
1046
|
),
|
|
1035
1047
|
patch(
|
|
1036
|
-
"git_commit_guard.
|
|
1048
|
+
"git_commit_guard._fetch_github_commit_committer",
|
|
1037
1049
|
side_effect=urllib.error.HTTPError(
|
|
1038
1050
|
url="", code=401, msg="Unauthorized", hdrs=None, fp=None
|
|
1039
1051
|
),
|
|
@@ -1047,14 +1059,14 @@ class TestCheckSignature:
|
|
|
1047
1059
|
r = Result()
|
|
1048
1060
|
with (
|
|
1049
1061
|
patch(
|
|
1050
|
-
"git_commit_guard.
|
|
1062
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
1051
1063
|
),
|
|
1052
1064
|
patch(
|
|
1053
1065
|
"git_commit_guard._get_github_remote_info",
|
|
1054
1066
|
return_value=("owner", "repo"),
|
|
1055
1067
|
),
|
|
1056
1068
|
patch(
|
|
1057
|
-
"git_commit_guard.
|
|
1069
|
+
"git_commit_guard._fetch_github_commit_committer",
|
|
1058
1070
|
side_effect=urllib.error.HTTPError(
|
|
1059
1071
|
url="", code=403, msg="Forbidden", hdrs=None, fp=None
|
|
1060
1072
|
),
|
|
@@ -1068,7 +1080,7 @@ class TestCheckSignature:
|
|
|
1068
1080
|
r = Result()
|
|
1069
1081
|
with (
|
|
1070
1082
|
patch(
|
|
1071
|
-
"git_commit_guard.
|
|
1083
|
+
"git_commit_guard._get_committer_email", return_value="corp@example.com"
|
|
1072
1084
|
),
|
|
1073
1085
|
patch("git_commit_guard._get_github_remote_info", return_value=None),
|
|
1074
1086
|
patch(
|
|
@@ -1086,7 +1098,7 @@ class TestCheckSignature:
|
|
|
1086
1098
|
r = Result()
|
|
1087
1099
|
with (
|
|
1088
1100
|
patch(
|
|
1089
|
-
"git_commit_guard.
|
|
1101
|
+
"git_commit_guard._get_committer_email", return_value="corp@example.com"
|
|
1090
1102
|
),
|
|
1091
1103
|
patch("git_commit_guard._get_github_remote_info", return_value=None),
|
|
1092
1104
|
patch(
|
|
@@ -1103,7 +1115,7 @@ class TestCheckSignature:
|
|
|
1103
1115
|
def test_url_error_fails(self):
|
|
1104
1116
|
r = Result()
|
|
1105
1117
|
with patch(
|
|
1106
|
-
"git_commit_guard.
|
|
1118
|
+
"git_commit_guard._get_committer_email",
|
|
1107
1119
|
side_effect=urllib.error.URLError("unreachable"),
|
|
1108
1120
|
):
|
|
1109
1121
|
check_signature("abc123", r)
|
|
@@ -1112,7 +1124,7 @@ class TestCheckSignature:
|
|
|
1112
1124
|
|
|
1113
1125
|
def test_timeout_error_fails(self):
|
|
1114
1126
|
r = Result()
|
|
1115
|
-
with patch("git_commit_guard.
|
|
1127
|
+
with patch("git_commit_guard._get_committer_email", side_effect=TimeoutError()):
|
|
1116
1128
|
check_signature("abc123", r)
|
|
1117
1129
|
assert not r.ok
|
|
1118
1130
|
assert any("API unreachable" in msg for _, _, msg in r.errors)
|
|
@@ -1120,7 +1132,7 @@ class TestCheckSignature:
|
|
|
1120
1132
|
def test_subprocess_timeout_fails_gracefully(self):
|
|
1121
1133
|
r = Result()
|
|
1122
1134
|
with patch(
|
|
1123
|
-
"git_commit_guard.
|
|
1135
|
+
"git_commit_guard._get_committer_email",
|
|
1124
1136
|
side_effect=subprocess.TimeoutExpired(cmd="git", timeout=10),
|
|
1125
1137
|
):
|
|
1126
1138
|
check_signature("abc123", r)
|
|
@@ -1131,14 +1143,15 @@ class TestCheckSignature:
|
|
|
1131
1143
|
r = Result()
|
|
1132
1144
|
with (
|
|
1133
1145
|
patch(
|
|
1134
|
-
"git_commit_guard.
|
|
1146
|
+
"git_commit_guard._get_committer_email", return_value="corp@example.com"
|
|
1135
1147
|
),
|
|
1136
1148
|
patch(
|
|
1137
1149
|
"git_commit_guard._get_github_remote_info",
|
|
1138
1150
|
return_value=("owner", "repo"),
|
|
1139
1151
|
),
|
|
1140
1152
|
patch(
|
|
1141
|
-
"git_commit_guard.
|
|
1153
|
+
"git_commit_guard._fetch_github_commit_committer",
|
|
1154
|
+
return_value="corpuser",
|
|
1142
1155
|
),
|
|
1143
1156
|
patch("git_commit_guard._fetch_github_username") as mock_email_search,
|
|
1144
1157
|
patch("git_commit_guard._fetch_github_keys", return_value=("GPG KEY", "")),
|
|
@@ -1152,14 +1165,14 @@ class TestCheckSignature:
|
|
|
1152
1165
|
r = Result()
|
|
1153
1166
|
with (
|
|
1154
1167
|
patch(
|
|
1155
|
-
"git_commit_guard.
|
|
1168
|
+
"git_commit_guard._get_committer_email", return_value="corp@example.com"
|
|
1156
1169
|
),
|
|
1157
1170
|
patch(
|
|
1158
1171
|
"git_commit_guard._get_github_remote_info",
|
|
1159
1172
|
return_value=("owner", "repo"),
|
|
1160
1173
|
),
|
|
1161
1174
|
patch(
|
|
1162
|
-
"git_commit_guard.
|
|
1175
|
+
"git_commit_guard._fetch_github_commit_committer",
|
|
1163
1176
|
side_effect=urllib.error.URLError("not found"),
|
|
1164
1177
|
),
|
|
1165
1178
|
patch("git_commit_guard._fetch_github_username", return_value="emailuser"),
|
|
@@ -1169,17 +1182,17 @@ class TestCheckSignature:
|
|
|
1169
1182
|
check_signature("abc123", r)
|
|
1170
1183
|
assert r.ok
|
|
1171
1184
|
|
|
1172
|
-
def
|
|
1185
|
+
def test_commits_api_null_committer_falls_back_to_email_search(self):
|
|
1173
1186
|
r = Result()
|
|
1174
1187
|
with (
|
|
1175
1188
|
patch(
|
|
1176
|
-
"git_commit_guard.
|
|
1189
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
1177
1190
|
),
|
|
1178
1191
|
patch(
|
|
1179
1192
|
"git_commit_guard._get_github_remote_info",
|
|
1180
1193
|
return_value=("owner", "repo"),
|
|
1181
1194
|
),
|
|
1182
|
-
patch("git_commit_guard.
|
|
1195
|
+
patch("git_commit_guard._fetch_github_commit_committer", return_value=None),
|
|
1183
1196
|
patch("git_commit_guard._fetch_github_username", return_value="emailuser"),
|
|
1184
1197
|
patch("git_commit_guard._fetch_github_keys", return_value=("", "SSH KEY")),
|
|
1185
1198
|
patch("git_commit_guard._verify_gpg", return_value=False),
|
|
@@ -1192,10 +1205,12 @@ class TestCheckSignature:
|
|
|
1192
1205
|
r = Result()
|
|
1193
1206
|
with (
|
|
1194
1207
|
patch(
|
|
1195
|
-
"git_commit_guard.
|
|
1208
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
1196
1209
|
),
|
|
1197
1210
|
patch("git_commit_guard._get_github_remote_info", return_value=None),
|
|
1198
|
-
patch(
|
|
1211
|
+
patch(
|
|
1212
|
+
"git_commit_guard._fetch_github_commit_committer"
|
|
1213
|
+
) as mock_commits_api,
|
|
1199
1214
|
patch("git_commit_guard._fetch_github_username", return_value="emailuser"),
|
|
1200
1215
|
patch("git_commit_guard._fetch_github_keys", return_value=("GPG KEY", "")),
|
|
1201
1216
|
patch("git_commit_guard._verify_gpg", return_value=True),
|
|
@@ -1208,7 +1223,7 @@ class TestCheckSignature:
|
|
|
1208
1223
|
r = Result()
|
|
1209
1224
|
with (
|
|
1210
1225
|
patch(
|
|
1211
|
-
"git_commit_guard.
|
|
1226
|
+
"git_commit_guard._get_committer_email",
|
|
1212
1227
|
return_value="12345678+alice@users.noreply.github.com",
|
|
1213
1228
|
),
|
|
1214
1229
|
patch("git_commit_guard._get_github_remote_info", return_value=None),
|
|
@@ -1224,7 +1239,7 @@ class TestCheckSignature:
|
|
|
1224
1239
|
r = Result()
|
|
1225
1240
|
with (
|
|
1226
1241
|
patch(
|
|
1227
|
-
"git_commit_guard.
|
|
1242
|
+
"git_commit_guard._get_committer_email",
|
|
1228
1243
|
return_value="12345678+alice@users.noreply.github.com",
|
|
1229
1244
|
),
|
|
1230
1245
|
patch(
|
|
@@ -1232,7 +1247,7 @@ class TestCheckSignature:
|
|
|
1232
1247
|
return_value=("owner", "repo"),
|
|
1233
1248
|
),
|
|
1234
1249
|
patch(
|
|
1235
|
-
"git_commit_guard.
|
|
1250
|
+
"git_commit_guard._fetch_github_commit_committer",
|
|
1236
1251
|
side_effect=urllib.error.URLError("not found"),
|
|
1237
1252
|
),
|
|
1238
1253
|
patch("git_commit_guard._fetch_github_username") as mock_email_search,
|
|
@@ -1630,7 +1645,7 @@ class TestMain:
|
|
|
1630
1645
|
patch("sys.argv", ["cg", "abc123", "--enable", "signature"]),
|
|
1631
1646
|
patch("git_commit_guard._get_message", return_value=_VALID_MSG),
|
|
1632
1647
|
patch(
|
|
1633
|
-
"git_commit_guard.
|
|
1648
|
+
"git_commit_guard._get_committer_email", return_value="user@example.com"
|
|
1634
1649
|
),
|
|
1635
1650
|
patch("git_commit_guard._get_github_remote_info", return_value=None),
|
|
1636
1651
|
patch("git_commit_guard._fetch_github_username", return_value="testuser"),
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|