aboutsummaryrefslogtreecommitdiff
path: root/build-aux/git-authenticate.scm
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2020-04-30 16:39:44 +0200
committerLudovic Courtès <ludo@gnu.org>2020-05-04 09:56:13 +0200
commit051a45e642ff21908375bee24d272c536096d026 (patch)
tree21539c66ff45bea0628d0784d4b5fc026ae8f654 /build-aux/git-authenticate.scm
parentb835e158d51c873a99367afd27f3d57cfe92e10e (diff)
downloadguix-051a45e642ff21908375bee24d272c536096d026.tar
guix-051a45e642ff21908375bee24d272c536096d026.tar.gz
git-authenticate: Use (guix openpgp).
It can now authenticate 14K+ commits in 23s instead of 4mn20. * build-aux/git-authenticate.scm (%authorized-signing-keys): Turn fingerprints into bytevectors. (with-temporary-files): Remove. (commit-signing-key): Add 'keyring' parameter. Use 'string->openpgp-packet' and 'verify-openpgp-signature' instead of (guix gnupg) procedures. (authenticate-commit): Add 'keyring' parameter. Pass it to 'commit-signing-key'. Adjust to SIGNING-KEY being an <openpgp-public-key>. (authenticate-commits): Remove 'parameterize'. Load keyring with 'get-openpgp-keyring'. (git-authenticate): When printing stats, adjust to SIGNER being an <openpgp-public-key>.
Diffstat (limited to 'build-aux/git-authenticate.scm')
-rw-r--r--build-aux/git-authenticate.scm131
1 files changed, 62 insertions, 69 deletions
diff --git a/build-aux/git-authenticate.scm b/build-aux/git-authenticate.scm
index bb48dddc59..0d5eb4caa9 100644
--- a/build-aux/git-authenticate.scm
+++ b/build-aux/git-authenticate.scm
@@ -23,8 +23,9 @@
(use-modules (git)
(guix git)
- (guix gnupg)
- (guix utils)
+ (guix openpgp)
+ ((guix utils) #:select (config-directory))
+ (guix base16)
((guix build utils) #:select (mkdir-p))
(guix i18n)
(guix progress)
@@ -215,7 +216,8 @@
;; Fingerprint of authorized signing keys.
(map (match-lambda
((name fingerprint)
- (string-filter char-set:graphic fingerprint)))
+ (base16-string->bytevector
+ (string-downcase (string-filter char-set:graphic fingerprint)))))
%committers))
(define %commits-with-bad-signature
@@ -226,75 +228,63 @@
;; Commits lacking a signature.
'())
-(define-syntax-rule (with-temporary-files file1 file2 exp ...)
- (call-with-temporary-output-file
- (lambda (file1 port1)
- (call-with-temporary-output-file
- (lambda (file2 port2)
- exp ...)))))
-
-(define (commit-signing-key repo commit-id)
- "Return the OpenPGP key ID that signed COMMIT-ID (an OID). Raise an
-exception if the commit is unsigned or has an invalid signature."
+(define (commit-signing-key repo commit-id keyring)
+ "Return the OpenPGP key that signed COMMIT-ID (an OID). Raise an exception
+if the commit is unsigned, has an invalid signature, or if its signing key is
+not in KEYRING."
(let-values (((signature signed-data)
(catch 'git-error
(lambda ()
(commit-extract-signature repo commit-id))
(lambda _
(values #f #f)))))
- (if (not signature)
- (raise (condition
- (&message
- (message (format #f (G_ "commit ~a lacks a signature")
- commit-id)))))
- (begin
- (with-fluids ((%default-port-encoding "UTF-8"))
- (with-temporary-files data-file signature-file
- (call-with-output-file data-file
- (cut display signed-data <>))
- (call-with-output-file signature-file
- (cut display signature <>))
-
- (let-values (((status data)
- (with-error-to-port (%make-void-port "w")
- (lambda ()
- (gnupg-verify* signature-file data-file
- #:key-download 'always)))))
- (match status
- ('invalid-signature
- ;; There's a signature but it's invalid.
- (raise (condition
- (&message
- (message (format #f (G_ "signature verification failed \
+ (unless signature
+ (raise (condition
+ (&message
+ (message (format #f (G_ "commit ~a lacks a signature")
+ commit-id))))))
+
+ (let ((signature (string->openpgp-packet signature)))
+ (with-fluids ((%default-port-encoding "UTF-8"))
+ (let-values (((status data)
+ (verify-openpgp-signature signature keyring
+ (open-input-string signed-data))))
+ (match status
+ ('bad-signature
+ ;; There's a signature but it's invalid.
+ (raise (condition
+ (&message
+ (message (format #f (G_ "signature verification failed \
for commit ~a")
- (oid->string commit-id)))))))
- ('missing-key
- (raise (condition
- (&message
- (message (format #f (G_ "could not authenticate \
+ (oid->string commit-id)))))))
+ ('missing-key
+ (raise (condition
+ (&message
+ (message (format #f (G_ "could not authenticate \
commit ~a: key ~a is missing")
- (oid->string commit-id)
- data))))))
- ('valid-signature
- (match data
- ((fingerprint . user)
- fingerprint)))))))))))
-
-(define (authenticate-commit repository commit)
+ (oid->string commit-id)
+ data))))))
+ ('good-signature data)))))))
+
+(define (authenticate-commit repository commit keyring)
"Authenticate COMMIT from REPOSITORY and return the signing key fingerprint.
Raise an error when authentication fails."
(define id
(commit-id commit))
(define signing-key
- (commit-signing-key repository id))
+ (commit-signing-key repository id keyring))
- (unless (member signing-key %authorized-signing-keys)
+ (unless (member (openpgp-public-key-fingerprint signing-key)
+ %authorized-signing-keys)
(raise (condition
(&message
(message (format #f (G_ "commit ~a not signed by an authorized \
key: ~a")
- (oid->string id) signing-key))))))
+ (oid->string id)
+ (openpgp-format-fingerprint
+ (openpgp-public-key-fingerprint
+ signing-key))))))))
signing-key)
@@ -302,17 +292,21 @@ key: ~a")
#:key (report-progress (const #t)))
"Authenticate COMMITS, a list of commit objects, calling REPORT-PROGRESS for
each of them. Return an alist showing the number of occurrences of each key."
- (parameterize ((current-keyring (string-append (config-directory)
- "/keyrings/channels/guix.kbx")))
- (fold (lambda (commit stats)
- (report-progress)
- (let ((signer (authenticate-commit repository commit)))
- (match (assoc signer stats)
- (#f (cons `(,signer . 1) stats))
- ((_ . count) (cons `(,signer . ,(+ count 1))
- (alist-delete signer stats))))))
- '()
- commits)))
+ (define keyring-file
+ (string-append (config-directory) "/keyrings/channels/guix.kbx"))
+
+ (define keyring
+ (call-with-input-file keyring-file get-openpgp-keyring))
+
+ (fold (lambda (commit stats)
+ (report-progress)
+ (let ((signer (authenticate-commit repository commit keyring)))
+ (match (assq signer stats)
+ (#f (cons `(,signer . 1) stats))
+ ((_ . count) (cons `(,signer . ,(+ count 1))
+ (alist-delete signer stats))))))
+ '()
+ commits))
(define commit-short-id
(compose (cut string-take <> 7) oid->string commit-id))
@@ -409,7 +403,10 @@ COMMIT-ID is written to cache, though)."
(format #t (G_ "Signing statistics:~%"))
(for-each (match-lambda
((signer . count)
- (format #t " ~a ~10d~%" signer count)))
+ (format #t " ~a ~10d~%"
+ (openpgp-format-fingerprint
+ (openpgp-public-key-fingerprint signer))
+ count)))
(sort stats
(match-lambda*
(((_ . count1) (_ . count2))
@@ -423,7 +420,3 @@ COMMIT-ID is written to cache, though)."
(G_ "Usage: git-authenticate START [END]
Authenticate commits START to END or the current head.\n"))))))
-
-;;; Local Variables:
-;;; eval: (put 'with-temporary-files 'scheme-indent-function 2)
-;;; End: