summary refs log tree commit diff
path: root/tests/git-authenticate.scm
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2022-01-28 17:20:43 +0100
committerLudovic Courtès <ludo@gnu.org>2022-02-14 11:23:08 +0100
commitca87601dd97dd9d356409827802eb0f8a3a535f0 (patch)
treee3a6c9e4abb95e45c27aa80dcdc9d99a2f661a6e /tests/git-authenticate.scm
parent87d49346f3072f7b4343b6fb387ee5f9311493b7 (diff)
downloadguix-ca87601dd97dd9d356409827802eb0f8a3a535f0.tar.gz
git-authenticate: Ensure the target is a descendant of the introductory commit.
Fixes a bug whereby authentication of a commit *not* descending from the
introductory commit could succeed, provided the commit verifies the
authorization invariant.

In the example below, A is a common ancestor of the introductory commit
I and of commit X.  Authentication of X would succeed, even though it is
not a descendant of I, as long as X is authorized according to the
'.guix-authorizations' in A:

   X   	 I
    \   /
      A

This is because, 'authenticate-repository' would not check whether X
descends from I, and the call (commit-difference X I) would return X.

In practice that only affects forks because it means that ancestors of
the introductory commit already contain a '.guix-authorizations' file.

* guix/git-authenticate.scm (authenticate-repository): Add call to
'commit-descendant?'.
* tests/channels.scm ("authenticate-channel, not a descendant of introductory commit"):
New test.
* tests/git-authenticate.scm ("authenticate-repository, target not a descendant of intro"):
New test.
* tests/guix-git-authenticate.sh: Expect earlier test to fail since
9549f0283a78fe36f2d4ff2a04ef8ad6b0c02604 is not a descendant of
$intro_commit.  Add new test targeting an ancestor of the introductory
commit, and another test targeting the v1.2.0 commit.
* doc/guix.texi (Specifying Channel Authorizations): Add a sentence.
Diffstat (limited to 'tests/git-authenticate.scm')
-rw-r--r--tests/git-authenticate.scm44
1 files changed, 44 insertions, 0 deletions
diff --git a/tests/git-authenticate.scm b/tests/git-authenticate.scm
index 6ec55fb2e5..c063920c12 100644
--- a/tests/git-authenticate.scm
+++ b/tests/git-authenticate.scm
@@ -431,4 +431,48 @@
                                       #:keyring-reference "master"
                                       #:cache-key (random-text)))))))))
 
+(unless (gpg+git-available?) (test-skip 1))
+(test-equal "authenticate-repository, target not a descendant of intro"
+  'target-commit-not-a-descendant-of-intro
+  (with-fresh-gnupg-setup (list %ed25519-public-key-file
+                                %ed25519-secret-key-file)
+    (let ((fingerprint (key-fingerprint %ed25519-public-key-file)))
+      (with-temporary-git-repository directory
+          `((add "signer.key" ,(call-with-input-file %ed25519-public-key-file
+                                 get-string-all))
+            (add ".guix-authorizations"
+                 ,(object->string
+                   `(authorizations (version 0)
+                                    ((,(key-fingerprint
+                                        %ed25519-public-key-file)
+                                      (name "Charlie"))))))
+            (commit "zeroth commit" (signer ,fingerprint))
+            (branch "pre-intro-branch")
+            (checkout "pre-intro-branch")
+            (add "b.txt" "B")
+            (commit "alternate commit" (signer ,fingerprint))
+            (checkout "master")
+            (add "a.txt" "A")
+            (commit "first commit" (signer ,fingerprint))
+            (add "c.txt" "C")
+            (commit "second commit" (signer ,fingerprint)))
+        (with-repository directory repository
+          (let ((commit1 (find-commit repository "first"))
+                (commit-alt
+                 (commit-lookup repository
+                                (reference-target
+                                 (branch-lookup repository
+                                                "pre-intro-branch")))))
+            (guard (c ((formatted-message? c)
+                       (and (equal? (formatted-message-arguments c)
+                                    (list (oid->string (commit-id commit-alt))
+                                          (oid->string (commit-id commit1))))
+                            'target-commit-not-a-descendant-of-intro)))
+              (authenticate-repository repository
+                                       (commit-id commit1)
+                                       (openpgp-fingerprint fingerprint)
+                                       #:end (commit-id commit-alt)
+                                       #:keyring-reference "master"
+                                       #:cache-key (random-text)))))))))
+
 (test-end "git-authenticate")