action: add signature verification support#6
action: add signature verification support#6BKPepe wants to merge 1 commit intoGeorgeSapkin:mainfrom
Conversation
dcc992b to
403698d
Compare
|
Interesting. I stopped signing my commits long time ago, because it broke lots of GH workflows, e.g. in OpenWrt org case merging a PR by rebasing would make the commit unsigned (which makes sense, since it's changed), defeating the purpose. Has anything improved recently? |
No, this is still happening. 😭😭 That said, there are repositories like Turris where commits within their repo have to be GPG signed to trigger the build. So it comes in handy there. But you’re right that OpenWrt commits used to be signed a lot more—pretty much every single commit was signed back then—and now those signatures are just vanishing. :-/ Luckily, this check isn't mandatory; it's more that if you actually click to open it, you’ll see it was signed, or it will be visible in the comments. |
82fdb4a to
813290c
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds signature verification support to the commit formality checker. The implementation checks GPG/SSH signatures on commits and reports their status, with different outcomes based on signature validity: Good signatures pass, Bad/Revoked/Error signatures fail, Unknown/Expired signatures warn, and unsigned commits skip the check.
Key changes:
- Added signature status capture to git format strings using %G?
- Implemented
check_signature()function with appropriate helper predicates - Added comprehensive test infrastructure including SSH key generation and certificate handling
- Enforced
commit.gpgsign=falsein test environment for deterministic results
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/check_formalities.sh | Added signature status extraction to git format, implemented helper functions (is_bad_sign, is_warn_sign, is_unsigned) and check_signature function, integrated signature check into main workflow |
| src/test.sh | Added SIGN_KEYS array tracking, implemented setup_ssh_keys() for test key generation, updated commit() function to support signing, added three signature test cases, updated all expected results to account for new check, enforced commit.gpgsign=false |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| define \ | ||
| -test 'Signature: good signature (G)' \ | ||
| -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0' \ | ||
| -author 'Good Author' \ | ||
| -email 'good.author@example.com' \ | ||
| -subject 'package: signed commit' \ | ||
| -sign-key 'good' \ | ||
| -body <<-'EOF' | ||
| This commit has a good SSH signature. | ||
|
|
||
| Signed-off-by: Good Author <good.author@example.com> | ||
| EOF | ||
|
|
||
| define \ | ||
| -test 'Signature: expired key (X)' \ | ||
| -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 2' \ | ||
| -author 'Good Author' \ | ||
| -email 'good.author@example.com' \ | ||
| -subject 'package: expired key signature' \ | ||
| -sign-key 'expired' \ | ||
| -body <<-'EOF' | ||
| This commit has a signature from an expired SSH key. | ||
|
|
||
| Signed-off-by: Good Author <good.author@example.com> | ||
| EOF | ||
|
|
||
| define \ | ||
| -test 'Signature: unknown key (U)' \ | ||
| -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 2' \ | ||
| -author 'Good Author' \ | ||
| -email 'good.author@example.com' \ | ||
| -subject 'package: unknown key signature' \ | ||
| -sign-key 'unknown' \ | ||
| -body <<-'EOF' | ||
| This commit has a signature from an unknown SSH key. | ||
|
|
||
| Signed-off-by: Good Author <good.author@example.com> | ||
| EOF |
There was a problem hiding this comment.
The test cases only cover three signature statuses: Good (G), Expired (X), and Unknown (U). According to the PR description, the check should also handle Bad (B), Revoked (R), and Error (E) signatures (which all result in FAIL). Consider adding test cases for these failure scenarios to ensure the check_signature function correctly fails on bad/revoked/error signatures.
There was a problem hiding this comment.
Described in the commit description. :)
ef3cb2a to
8dc1a73
Compare
This comment has been minimized.
This comment has been minimized.
8dc1a73 to
af96611
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| define \ | ||
| -test 'Signature: good signature (G)' \ | ||
| -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0' \ | ||
| -author 'Good Author' \ | ||
| -email 'good.author@example.com' \ | ||
| -subject 'package: signed commit' \ | ||
| -sign-key 'good' \ | ||
| -body <<-'EOF' | ||
| This commit has a good SSH signature. | ||
|
|
||
| Signed-off-by: Good Author <good.author@example.com> | ||
| EOF | ||
|
|
||
| define \ | ||
| -test 'Signature: expired key (X)' \ | ||
| -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 2' \ | ||
| -author 'Good Author' \ | ||
| -email 'good.author@example.com' \ | ||
| -subject 'package: expired key signature' \ | ||
| -sign-key 'expired' \ | ||
| -body <<-'EOF' | ||
| This commit has a signature from an expired SSH key. | ||
|
|
||
| Signed-off-by: Good Author <good.author@example.com> | ||
| EOF | ||
|
|
||
| define \ | ||
| -test 'Signature: unknown key (U)' \ | ||
| -expected '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 2' \ | ||
| -author 'Good Author' \ | ||
| -email 'good.author@example.com' \ | ||
| -subject 'package: unknown key signature' \ | ||
| -sign-key 'unknown' \ | ||
| -body <<-'EOF' | ||
| This commit has a signature from an unknown SSH key. | ||
|
|
||
| Signed-off-by: Good Author <good.author@example.com> | ||
| EOF |
There was a problem hiding this comment.
The signature verification tests only cover three signature statuses: G (good), X (expired), and U (unknown). Consider adding test cases for the remaining statuses defined in the check logic: B (bad), R (revoked), E (error), and Y (expired signature). While N (none) is implicitly tested by all other existing tests that don't specify a sign-key, the failure cases (B, R, E) would provide valuable coverage for the critical failure paths in the signature verification logic.
src/check_formalities.sh
Outdated
| check_body "$body" "$sob" | ||
| check_signature "$sign_status" |
There was a problem hiding this comment.
Does this work if there's a skip reason remaining after check_body or should it be reset? I'm not certain about the intended logic.
|
And I suppose it makes sense to update the README with the new check. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
746cb3c to
336c313
Compare
This comment has been minimized.
This comment has been minimized.
336c313 to
8c9ae75
Compare
8c9ae75 to
24e9e08
Compare
24e9e08 to
fec30b1
Compare
|
Something is up with the expired test: it's giving me unknown. Not sure if relevant to fix or not. I re-worded the check and README. |
| case "$status" in | ||
| B) reason='bad signature' ;; | ||
| E) reason='signature cannot be checked' ;; | ||
| R) reason='revoked key signature' ;; | ||
| U) reason='good signature, validity unknown' ;; | ||
| X) reason='good signature, expired' ;; | ||
| Y) reason='good signature, expired key' ;; | ||
| *) reason='no signature' ;; | ||
| esac |
There was a problem hiding this comment.
Oh, this is very good! I was thinking how to do this this way. Thanks!
Let me check this. |
This comment has been minimized.
This comment has been minimized.
|
Also, what is the supposed outcome when a signature cannot be verified because of a rebase from a different user? Perhaps this should be behind a config flag? |
|
If I’m not mistaken, if you rebase it and sign it, it will be marked as Verified. But since you didn’t sign it, Git correctly flagged it as unsigned, and yes — in the case of a rebase, it won’t be fully usable. That’s true, and it was actually discussed here: openwrt/packages#13654 (comment). However, I agree that OpenWrt is slowly moving away from supporting GPG. And you’re right. I’ll add it behind a check so that users can enable or disable it. The more configuration options, the better. |
b6984b7 to
e5a3a39
Compare
|
Okay, added configure flag. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
e5a3a39 to
4a452e7
Compare
a3f54c5 to
3ae4a55
Compare
| -subject 'package: unsigned commit' \ | ||
| -check-signature 'true' \ | ||
| -body <<-'EOF' | ||
| This commit has no signature but should pass. |
There was a problem hiding this comment.
Thinking out loud here: does it actually make sense to enable signature verification, but then pass unsigned commits?
There was a problem hiding this comment.
Good question, though. It does not, but Copilot requested it - #6 (comment)
This adds a new check to verify GPG/SSH signatures on commits. The check reports the signature status (Good, Bad, Unknown, etc.) and validates it: - Good (G): PASS - Bad (B), Revoked (R), Error (E): FAIL - Unknown (U), Expired (X, Y): WARN - None (N): SKIP The test suite has been updated to cover these changes and to enforce commit.gpgsign=false within the test environment to ensure deterministic results. Co-authored-by: George Sapkin <george@sapk.in> Signed-off-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
3ae4a55 to
fbada74
Compare
|
Rebased. |

This adds a new check to verify GPG/SSH signatures on commits. The check reports the signature status (Good, Bad, Unknown, etc.) and validates it:
The test suite has been updated to cover these changes and to enforce
commit.gpgsign=falsewithin the test environment to ensure deterministic results.