diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2020-06-01 23:20:06 +0200 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2020-06-05 22:54:06 +0200 |
| commit | c83eedba2361c3831d3efb5ad63d5077d636fb28 (patch) | |
| tree | cc639c0113537fb187d1fa0fb28a1c2510dbb3cc /tests/git-authenticate.scm | |
| parent | f8213f1bca912ec41be61bc5e166c702968fcf89 (diff) | |
git-authenticate: Add tests.
* guix/tests/git.scm (call-with-environment-variables)
(with-environment-variables): Remove.
* guix/tests/git.scm (populate-git-repository): Add clauses for signed
commits and signed merges.
* guix/tests/gnupg.scm: New file.
* tests/git-authenticate.scm: New file.
* tests/ed25519bis.key, tests/ed25519bis.sec: New files.
* Makefile.am (dist_noinst_DATA): Add 'guix/tests/gnupg.scm'.
(SCM_TESTS): Add 'tests/git-authenticate.scm'.
(EXTRA_DIST): Add tests/ed25519bis.{key,sec}.
Diffstat (limited to 'tests/git-authenticate.scm')
| -rw-r--r-- | tests/git-authenticate.scm | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/tests/git-authenticate.scm b/tests/git-authenticate.scm new file mode 100644 index 00000000000..5937c37ee68 --- /dev/null +++ b/tests/git-authenticate.scm | |||
| @@ -0,0 +1,286 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2020 Ludovic Courtès <ludo@gnu.org> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (test-git-authenticate) | ||
| 20 | #:use-module (git) | ||
| 21 | #:use-module (guix git) | ||
| 22 | #:use-module (guix git-authenticate) | ||
| 23 | #:use-module (guix openpgp) | ||
| 24 | #:use-module (guix tests git) | ||
| 25 | #:use-module (guix tests gnupg) | ||
| 26 | #:use-module (guix build utils) | ||
| 27 | #:use-module (srfi srfi-1) | ||
| 28 | #:use-module (srfi srfi-34) | ||
| 29 | #:use-module (srfi srfi-64) | ||
| 30 | #:use-module (rnrs bytevectors) | ||
| 31 | #:use-module (rnrs io ports)) | ||
| 32 | |||
| 33 | ;; Test the (guix git-authenticate) tools. | ||
| 34 | |||
| 35 | (define %ed25519-public-key-file | ||
| 36 | (search-path %load-path "tests/ed25519.key")) | ||
| 37 | (define %ed25519-secret-key-file | ||
| 38 | (search-path %load-path "tests/ed25519.sec")) | ||
| 39 | (define %ed25519bis-public-key-file | ||
| 40 | (search-path %load-path "tests/ed25519bis.key")) | ||
| 41 | (define %ed25519bis-secret-key-file | ||
| 42 | (search-path %load-path "tests/ed25519bis.sec")) | ||
| 43 | |||
| 44 | (define (read-openpgp-packet file) | ||
| 45 | (get-openpgp-packet | ||
| 46 | (open-bytevector-input-port | ||
| 47 | (call-with-input-file file read-radix-64)))) | ||
| 48 | |||
| 49 | (define key-fingerprint | ||
| 50 | (compose openpgp-format-fingerprint | ||
| 51 | openpgp-public-key-fingerprint | ||
| 52 | read-openpgp-packet)) | ||
| 53 | |||
| 54 | (define (key-id file) | ||
| 55 | (define id | ||
| 56 | (openpgp-public-key-id (read-openpgp-packet))) | ||
| 57 | |||
| 58 | (string-pad (number->string id 16) 16 #\0)) | ||
| 59 | |||
| 60 | (define (gpg+git-available?) | ||
| 61 | (and (which (git-command)) | ||
| 62 | (which (gpg-command)) (which (gpgconf-command)))) | ||
| 63 | |||
| 64 | |||
| 65 | (test-begin "git-authenticate") | ||
| 66 | |||
| 67 | (unless (which (git-command)) (test-skip 1)) | ||
| 68 | (test-assert "unsigned commits" | ||
| 69 | (with-temporary-git-repository directory | ||
| 70 | '((add "a.txt" "A") | ||
| 71 | (commit "first commit") | ||
| 72 | (add "b.txt" "B") | ||
| 73 | (commit "second commit")) | ||
| 74 | (with-repository directory repository | ||
| 75 | (let ((commit1 (find-commit repository "first")) | ||
| 76 | (commit2 (find-commit repository "second"))) | ||
| 77 | (guard (c ((unsigned-commit-error? c) | ||
| 78 | (oid=? (git-authentication-error-commit c) | ||
| 79 | (commit-id commit1)))) | ||
| 80 | (authenticate-commits repository (list commit1 commit2) | ||
| 81 | #:keyring-reference "master") | ||
| 82 | 'failed))))) | ||
| 83 | |||
| 84 | (unless (gpg+git-available?) (test-skip 1)) | ||
| 85 | (test-assert "signed commits, default authorizations" | ||
| 86 | (with-fresh-gnupg-setup (list %ed25519-public-key-file | ||
| 87 | %ed25519-secret-key-file) | ||
| 88 | (with-temporary-git-repository directory | ||
| 89 | `((add "signer.key" ,(call-with-input-file %ed25519-public-key-file | ||
| 90 | get-string-all)) | ||
| 91 | (commit "zeroth commit") | ||
| 92 | (add "a.txt" "A") | ||
| 93 | (commit "first commit" | ||
| 94 | (signer ,(key-fingerprint %ed25519-public-key-file))) | ||
| 95 | (add "b.txt" "B") | ||
| 96 | (commit "second commit" | ||
| 97 | (signer ,(key-fingerprint %ed25519-public-key-file)))) | ||
| 98 | (with-repository directory repository | ||
| 99 | (let ((commit1 (find-commit repository "first")) | ||
| 100 | (commit2 (find-commit repository "second"))) | ||
| 101 | (authenticate-commits repository (list commit1 commit2) | ||
| 102 | #:default-authorizations | ||
| 103 | (list (openpgp-public-key-fingerprint | ||
| 104 | (read-openpgp-packet | ||
| 105 | %ed25519-public-key-file))) | ||
| 106 | #:keyring-reference "master")))))) | ||
| 107 | |||
| 108 | (unless (gpg+git-available?) (test-skip 1)) | ||
| 109 | (test-assert "signed commits, .guix-authorizations" | ||
| 110 | (with-fresh-gnupg-setup (list %ed25519-public-key-file | ||
| 111 | %ed25519-secret-key-file) | ||
| 112 | (with-temporary-git-repository directory | ||
| 113 | `((add "signer.key" ,(call-with-input-file %ed25519-public-key-file | ||
| 114 | get-string-all)) | ||
| 115 | (add ".guix-authorizations" | ||
| 116 | ,(object->string | ||
| 117 | `(authorizations (version 0) | ||
| 118 | ((,(key-fingerprint | ||
| 119 | %ed25519-public-key-file) | ||
| 120 | (name "Charlie")))))) | ||
| 121 | (commit "zeroth commit") | ||
| 122 | (add "a.txt" "A") | ||
| 123 | (commit "first commit" | ||
| 124 | (signer ,(key-fingerprint %ed25519-public-key-file))) | ||
| 125 | (add ".guix-authorizations" | ||
| 126 | ,(object->string `(authorizations (version 0) ()))) ;empty | ||
| 127 | (commit "second commit" | ||
| 128 | (signer ,(key-fingerprint %ed25519-public-key-file))) | ||
| 129 | (add "b.txt" "B") | ||
| 130 | (commit "third commit" | ||
| 131 | (signer ,(key-fingerprint %ed25519-public-key-file)))) | ||
| 132 | (with-repository directory repository | ||
| 133 | (let ((commit1 (find-commit repository "first")) | ||
| 134 | (commit2 (find-commit repository "second")) | ||
| 135 | (commit3 (find-commit repository "third"))) | ||
| 136 | ;; COMMIT1 and COMMIT2 are fine. | ||
| 137 | (and (authenticate-commits repository (list commit1 commit2) | ||
| 138 | #:keyring-reference "master") | ||
| 139 | |||
| 140 | ;; COMMIT3 is signed by an unauthorized key according to its | ||
| 141 | ;; parent's '.guix-authorizations' file. | ||
| 142 | (guard (c ((unauthorized-commit-error? c) | ||
| 143 | (and (oid=? (git-authentication-error-commit c) | ||
| 144 | (commit-id commit3)) | ||
| 145 | (bytevector=? | ||
| 146 | (openpgp-public-key-fingerprint | ||
| 147 | (unauthorized-commit-error-signing-key c)) | ||
| 148 | (openpgp-public-key-fingerprint | ||
| 149 | (read-openpgp-packet | ||
| 150 | %ed25519-public-key-file)))))) | ||
| 151 | (authenticate-commits repository | ||
| 152 | (list commit1 commit2 commit3) | ||
| 153 | #:keyring-reference "master") | ||
| 154 | 'failed))))))) | ||
| 155 | |||
| 156 | (unless (gpg+git-available?) (test-skip 1)) | ||
| 157 | (test-assert "signed commits, .guix-authorizations, unauthorized merge" | ||
| 158 | (with-fresh-gnupg-setup (list %ed25519-public-key-file | ||
| 159 | %ed25519-secret-key-file | ||
| 160 | %ed25519bis-public-key-file | ||
| 161 | %ed25519bis-secret-key-file) | ||
| 162 | (with-temporary-git-repository directory | ||
| 163 | `((add "signer1.key" | ||
| 164 | ,(call-with-input-file %ed25519-public-key-file | ||
| 165 | get-string-all)) | ||
| 166 | (add "signer2.key" | ||
| 167 | ,(call-with-input-file %ed25519bis-public-key-file | ||
| 168 | get-string-all)) | ||
| 169 | (add ".guix-authorizations" | ||
| 170 | ,(object->string | ||
| 171 | `(authorizations (version 0) | ||
| 172 | ((,(key-fingerprint | ||
| 173 | %ed25519-public-key-file) | ||
| 174 | (name "Alice")))))) | ||
| 175 | (commit "zeroth commit") | ||
| 176 | (add "a.txt" "A") | ||
| 177 | (commit "first commit" | ||
| 178 | (signer ,(key-fingerprint %ed25519-public-key-file))) | ||
| 179 | (branch "devel") | ||
| 180 | (checkout "devel") | ||
| 181 | (add "devel/1.txt" "1") | ||
| 182 | (commit "first devel commit" | ||
| 183 | (signer ,(key-fingerprint %ed25519bis-public-key-file))) | ||
| 184 | (checkout "master") | ||
| 185 | (add "b.txt" "B") | ||
| 186 | (commit "second commit" | ||
| 187 | (signer ,(key-fingerprint %ed25519-public-key-file))) | ||
| 188 | (merge "devel" "merge" | ||
| 189 | (signer ,(key-fingerprint %ed25519-public-key-file)))) | ||
| 190 | (with-repository directory repository | ||
| 191 | (let ((master1 (find-commit repository "first commit")) | ||
| 192 | (master2 (find-commit repository "second commit")) | ||
| 193 | (devel1 (find-commit repository "first devel commit")) | ||
| 194 | (merge (find-commit repository "merge"))) | ||
| 195 | (define (correct? c commit) | ||
| 196 | (and (oid=? (git-authentication-error-commit c) | ||
| 197 | (commit-id commit)) | ||
| 198 | (bytevector=? | ||
| 199 | (openpgp-public-key-fingerprint | ||
| 200 | (unauthorized-commit-error-signing-key c)) | ||
| 201 | (openpgp-public-key-fingerprint | ||
| 202 | (read-openpgp-packet %ed25519bis-public-key-file))))) | ||
| 203 | |||
| 204 | (and (authenticate-commits repository (list master1 master2) | ||
| 205 | #:keyring-reference "master") | ||
| 206 | |||
| 207 | ;; DEVEL1 is signed by an unauthorized key according to its | ||
| 208 | ;; parent's '.guix-authorizations' file. | ||
| 209 | (guard (c ((unauthorized-commit-error? c) | ||
| 210 | (correct? c devel1))) | ||
| 211 | (authenticate-commits repository | ||
| 212 | (list master1 devel1) | ||
| 213 | #:keyring-reference "master") | ||
| 214 | #f) | ||
| 215 | |||
| 216 | ;; MERGE is authorized but one of its ancestors is not. | ||
| 217 | (guard (c ((unauthorized-commit-error? c) | ||
| 218 | (correct? c devel1))) | ||
| 219 | (authenticate-commits repository | ||
| 220 | (list master1 master2 | ||
| 221 | devel1 merge) | ||
| 222 | #:keyring-reference "master") | ||
| 223 | #f))))))) | ||
| 224 | |||
| 225 | (unless (gpg+git-available?) (test-skip 1)) | ||
| 226 | (test-assert "signed commits, .guix-authorizations, authorized merge" | ||
| 227 | (with-fresh-gnupg-setup (list %ed25519-public-key-file | ||
| 228 | %ed25519-secret-key-file | ||
| 229 | %ed25519bis-public-key-file | ||
| 230 | %ed25519bis-secret-key-file) | ||
| 231 | (with-temporary-git-repository directory | ||
| 232 | `((add "signer1.key" | ||
| 233 | ,(call-with-input-file %ed25519-public-key-file | ||
| 234 | get-string-all)) | ||
| 235 | (add "signer2.key" | ||
| 236 | ,(call-with-input-file %ed25519bis-public-key-file | ||
| 237 | get-string-all)) | ||
| 238 | (add ".guix-authorizations" | ||
| 239 | ,(object->string | ||
| 240 | `(authorizations (version 0) | ||
| 241 | ((,(key-fingerprint | ||
| 242 | %ed25519-public-key-file) | ||
| 243 | (name "Alice")))))) | ||
| 244 | (commit "zeroth commit") | ||
| 245 | (add "a.txt" "A") | ||
| 246 | (commit "first commit" | ||
| 247 | (signer ,(key-fingerprint %ed25519-public-key-file))) | ||
| 248 | (branch "devel") | ||
| 249 | (checkout "devel") | ||
| 250 | (add ".guix-authorizations" | ||
| 251 | ,(object->string ;add the second signer | ||
| 252 | `(authorizations (version 0) | ||
| 253 | ((,(key-fingerprint | ||
| 254 | %ed25519-public-key-file) | ||
| 255 | (name "Alice")) | ||
| 256 | (,(key-fingerprint | ||
| 257 | %ed25519bis-public-key-file)))))) | ||
| 258 | (commit "first devel commit" | ||
| 259 | (signer ,(key-fingerprint %ed25519-public-key-file))) | ||
| 260 | (add "devel/2.txt" "2") | ||
| 261 | (commit "second devel commit" | ||
| 262 | (signer ,(key-fingerprint %ed25519bis-public-key-file))) | ||
| 263 | (checkout "master") | ||
| 264 | (add "b.txt" "B") | ||
| 265 | (commit "second commit" | ||
| 266 | (signer ,(key-fingerprint %ed25519-public-key-file))) | ||
| 267 | (merge "devel" "merge" | ||
| 268 | (signer ,(key-fingerprint %ed25519-public-key-file))) | ||
| 269 | ;; After the merge, the second signer is authorized. | ||
| 270 | (add "c.txt" "C") | ||
| 271 | (commit "third commit" | ||
| 272 | (signer ,(key-fingerprint %ed25519bis-public-key-file)))) | ||
| 273 | (with-repository directory repository | ||
| 274 | (let ((master1 (find-commit repository "first commit")) | ||
| 275 | (master2 (find-commit repository "second commit")) | ||
| 276 | (devel1 (find-commit repository "first devel commit")) | ||
| 277 | (devel2 (find-commit repository "second devel commit")) | ||
| 278 | (merge (find-commit repository "merge")) | ||
| 279 | (master3 (find-commit repository "third commit"))) | ||
| 280 | (authenticate-commits repository | ||
| 281 | (list master1 master2 devel1 devel2 | ||
| 282 | merge master3) | ||
| 283 | #:keyring-reference "master")))))) | ||
| 284 | |||
| 285 | (test-end "git-authenticate") | ||
| 286 | |||
