summary refs log tree commit diff
path: root/guix/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 /guix/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 'guix/git-authenticate.scm')
-rw-r--r--guix/git-authenticate.scm17
1 files changed, 15 insertions, 2 deletions
diff --git a/guix/git-authenticate.scm b/guix/git-authenticate.scm
index ab3fcd8b2f..419cb85afc 100644
--- a/guix/git-authenticate.scm
+++ b/guix/git-authenticate.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2019, 2020, 2021, 2022 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -22,7 +22,9 @@
   #:use-module (guix base16)
   #:autoload   (guix base64) (base64-encode)
   #:use-module ((guix git)
-                #:select (commit-difference false-if-git-not-found))
+                #:select (commit-difference
+                          commit-descendant?
+                          false-if-git-not-found))
   #:use-module (guix i18n)
   #:use-module ((guix diagnostics) #:select (formatted-message))
   #:use-module (guix openpgp)
@@ -426,6 +428,17 @@ denoting the authorized keys for commits whose parent lack the
           (verify-introductory-commit repository keyring
                                       start-commit signer))
 
+        ;; Make sure END-COMMIT is a descendant of START-COMMIT or of one of
+        ;; AUTHENTICATED-COMMITS, which are known to be descendants of
+        ;; START-COMMIT.
+        (unless (commit-descendant? end-commit
+                                    (cons start-commit
+                                          authenticated-commits))
+          (raise (formatted-message
+                  (G_ "commit ~a is not a descendant of introductory commit ~a")
+                  (oid->string (commit-id end-commit))
+                  (oid->string (commit-id start-commit)))))
+
         (let ((stats (call-with-progress-reporter reporter
                        (lambda (report)
                          (authenticate-commits repository commits