1
0
mirror of https://git.savannah.gnu.org/git/guix.git synced 2026-05-28 03:51:53 +02:00

channels: 'latest-channel-instance' authenticates Git checkouts.

Fixes <https://bugs.gnu.org/22883>.

* guix/channels.scm (<channel>)[introduction]: New field.
(<channel-introduction>): New record type.
(%guix-channel-introduction): New variable.
(%default-channels): Use it.
(<channel-metadata>)[keyring-reference]: New field.
(%default-keyring-reference): New variable.
(read-channel-metadata, read-channel-metadata-from-source): Initialize
the 'keyring-reference' field.
(commit-short-id, verify-introductory-commit)
(authenticate-channel): New procedures.
(latest-channel-instance): Call 'authenticate-channel' when CHANNEL has
an introduction.
* tests/channels.scm (gpg+git-available?, commit-id-string): New
procedures.
("authenticate-channel, wrong first commit signer"):
("authenticate-channel, .guix-authorizations"): New tests.
* doc/guix.texi (Invoking guix pull): Mention authentication.
This commit is contained in:
Ludovic Courtès
2020-06-08 12:01:24 +02:00
parent 1e2b9bf2d4
commit 43badf261f
4 changed files with 304 additions and 7 deletions
+122
View File
@@ -31,15 +31,28 @@
#:use-module ((guix build utils) #:select (which))
#:use-module (git)
#:use-module (guix git)
#:use-module (guix git-authenticate)
#:use-module (guix openpgp)
#:use-module (guix tests git)
#:use-module (guix tests gnupg)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
#:use-module (srfi srfi-64)
#:use-module (rnrs bytevectors)
#:use-module (rnrs io ports)
#:use-module (ice-9 control)
#:use-module (ice-9 match))
(define (gpg+git-available?)
(and (which (git-command))
(which (gpg-command)) (which (gpgconf-command))))
(define commit-id-string
(compose oid->string commit-id))
(test-begin "channels")
(define* (make-instance #:key
@@ -389,4 +402,113 @@
(channel-news-for-commit channel commit5 commit1))
'(#f "tag-for-first-news-entry")))))))
(unless (gpg+git-available?) (test-skip 1))
(test-assert "authenticate-channel, wrong first commit signer"
(with-fresh-gnupg-setup (list %ed25519-public-key-file
%ed25519-secret-key-file
%ed25519bis-public-key-file
%ed25519bis-secret-key-file)
(with-temporary-git-repository directory
`((add ".guix-channel"
,(object->string
'(channel (version 0)
(keyring-reference "master"))))
(add ".guix-authorizations"
,(object->string
`(authorizations (version 0)
((,(key-fingerprint
%ed25519-public-key-file)
(name "Charlie"))))))
(add "signer.key" ,(call-with-input-file %ed25519-public-key-file
get-string-all))
(commit "first commit"
(signer ,(key-fingerprint %ed25519-public-key-file))))
(with-repository directory repository
(let* ((commit1 (find-commit repository "first"))
(intro ((@@ (guix channels) make-channel-introduction)
(commit-id-string commit1)
(openpgp-public-key-fingerprint
(read-openpgp-packet
%ed25519bis-public-key-file)) ;different key
#f)) ;no signature
(channel (channel (name 'example)
(url (string-append "file://" directory))
(introduction intro))))
(guard (c ((message? c)
(->bool (string-contains (condition-message c)
"initial commit"))))
(authenticate-channel channel directory
(commit-id-string commit1)
#:keyring-reference-prefix "")
'failed))))))
(unless (gpg+git-available?) (test-skip 1))
(test-assert "authenticate-channel, .guix-authorizations"
(with-fresh-gnupg-setup (list %ed25519-public-key-file
%ed25519-secret-key-file
%ed25519bis-public-key-file
%ed25519bis-secret-key-file)
(with-temporary-git-repository directory
`((add ".guix-channel"
,(object->string
'(channel (version 0)
(keyring-reference "channel-keyring"))))
(add ".guix-authorizations"
,(object->string
`(authorizations (version 0)
((,(key-fingerprint
%ed25519-public-key-file)
(name "Charlie"))))))
(commit "zeroth commit")
(add "a.txt" "A")
(commit "first commit"
(signer ,(key-fingerprint %ed25519-public-key-file)))
(add "b.txt" "B")
(commit "second commit"
(signer ,(key-fingerprint %ed25519-public-key-file)))
(add "c.txt" "C")
(commit "third commit"
(signer ,(key-fingerprint %ed25519bis-public-key-file)))
(branch "channel-keyring")
(checkout "channel-keyring")
(add "signer.key" ,(call-with-input-file %ed25519-public-key-file
get-string-all))
(add "other.key" ,(call-with-input-file %ed25519bis-public-key-file
get-string-all))
(commit "keyring commit")
(checkout "master"))
(with-repository directory repository
(let* ((commit1 (find-commit repository "first"))
(commit2 (find-commit repository "second"))
(commit3 (find-commit repository "third"))
(intro ((@@ (guix channels) make-channel-introduction)
(commit-id-string commit1)
(openpgp-public-key-fingerprint
(read-openpgp-packet
%ed25519-public-key-file))
#f)) ;no signature
(channel (channel (name 'example)
(url (string-append "file://" directory))
(introduction intro))))
;; COMMIT1 and COMMIT2 are fine.
(and (authenticate-channel channel directory
(commit-id-string commit2)
#:keyring-reference-prefix "")
;; COMMIT3 is signed by an unauthorized key according to its
;; parent's '.guix-authorizations' file.
(guard (c ((unauthorized-commit-error? c)
(and (oid=? (git-authentication-error-commit c)
(commit-id commit3))
(bytevector=?
(openpgp-public-key-fingerprint
(unauthorized-commit-error-signing-key c))
(openpgp-public-key-fingerprint
(read-openpgp-packet
%ed25519bis-public-key-file))))))
(authenticate-channel channel directory
(commit-id-string commit3)
#:keyring-reference-prefix "")
'failed)))))))
(test-end "channels")