diff options
author | Ludovic Courtès <ludo@gnu.org> | 2020-06-08 12:01:24 +0200 |
---|---|---|
committer | Ludovic Courtès <ludo@gnu.org> | 2020-06-16 16:10:47 +0200 |
commit | 43badf261f4688c8a7a7a9004a4bff8acb205835 (patch) | |
tree | 9e170e9088dc39219f2c7043972a1c9c61681b00 /tests | |
parent | 1e2b9bf2d4ed4edc9ed70c51f414bb2890074a21 (diff) |
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.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/channels.scm | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/tests/channels.scm b/tests/channels.scm index 3b141428c8..2c857083e9 100644 --- a/tests/channels.scm +++ b/tests/channels.scm @@ -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") |