authenticate.scm 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. (define-module (guix scripts git authenticate)
  19. #:use-module (git)
  20. #:use-module (guix ui)
  21. #:use-module (guix scripts)
  22. #:use-module (guix git-authenticate)
  23. #:autoload (guix openpgp) (openpgp-format-fingerprint
  24. openpgp-public-key-fingerprint)
  25. #:use-module ((guix channels) #:select (openpgp-fingerprint))
  26. #:use-module ((guix git) #:select (with-git-error-handling))
  27. #:use-module (guix progress)
  28. #:use-module (guix base64)
  29. #:use-module (srfi srfi-1)
  30. #:use-module (srfi srfi-26)
  31. #:use-module (srfi srfi-37)
  32. #:use-module (ice-9 format)
  33. #:use-module (ice-9 match)
  34. #:export (guix-git-authenticate))
  35. ;;; Commentary:
  36. ;;;
  37. ;;; Authenticate a Git checkout by reading '.guix-authorizations' files and
  38. ;;; following the "authorizations invariant" also used by (guix channels).
  39. ;;;
  40. ;;; Code:
  41. (define %options
  42. ;; Specifications of the command-line options.
  43. (list (option '(#\h "help") #f #f
  44. (lambda args
  45. (show-help)
  46. (exit 0)))
  47. (option '(#\V "version") #f #f
  48. (lambda args
  49. (show-version-and-exit "guix git authenticate")))
  50. (option '(#\r "repository") #t #f
  51. (lambda (opt name arg result)
  52. (alist-cons 'directory arg result)))
  53. (option '(#\e "end") #t #f
  54. (lambda (opt name arg result)
  55. (alist-cons 'end-commit (string->oid arg) result)))
  56. (option '(#\k "keyring") #t #f
  57. (lambda (opt name arg result)
  58. (alist-cons 'keyring-reference arg result)))
  59. (option '("cache-key") #t #f
  60. (lambda (opt name arg result)
  61. (alist-cons 'cache-key arg result)))
  62. (option '("historical-authorizations") #t #f
  63. (lambda (opt name arg result)
  64. (alist-cons 'historical-authorizations arg
  65. result)))
  66. (option '("stats") #f #f
  67. (lambda (opt name arg result)
  68. (alist-cons 'show-stats? #t result)))))
  69. (define %default-options
  70. '((directory . ".")
  71. (keyring-reference . "keyring")))
  72. (define (show-stats stats)
  73. "Display STATS, an alist containing commit signing stats as returned by
  74. 'authenticate-repository'."
  75. (format #t (G_ "Signing statistics:~%"))
  76. (for-each (match-lambda
  77. ((signer . count)
  78. (format #t " ~a ~10d~%"
  79. (openpgp-format-fingerprint
  80. (openpgp-public-key-fingerprint signer))
  81. count)))
  82. (sort stats
  83. (match-lambda*
  84. (((_ . count1) (_ . count2))
  85. (> count1 count2))))))
  86. (define (show-help)
  87. (display (G_ "Usage: guix git authenticate COMMIT SIGNER [OPTIONS...]
  88. Authenticate the given Git checkout using COMMIT/SIGNER as its introduction.\n"))
  89. (display (G_ "
  90. -r, --repository=DIRECTORY
  91. open the Git repository at DIRECTORY"))
  92. (display (G_ "
  93. -k, --keyring=REFERENCE
  94. load keyring from REFERENCE, a Git branch"))
  95. (display (G_ "
  96. --stats display commit signing statistics upon completion"))
  97. (display (G_ "
  98. --cache-key=KEY cache authenticated commits under KEY"))
  99. (display (G_ "
  100. --historical-authorizations=FILE
  101. read historical authorizations from FILE"))
  102. (newline)
  103. (display (G_ "
  104. -h, --help display this help and exit"))
  105. (display (G_ "
  106. -V, --version display version information and exit"))
  107. (newline)
  108. (show-bug-report-information))
  109. ;;;
  110. ;;; Entry point.
  111. ;;;
  112. (define (guix-git-authenticate . args)
  113. (define options
  114. (parse-command-line args %options (list %default-options)
  115. #:build-options? #f))
  116. (define (command-line-arguments lst)
  117. (reverse (filter-map (match-lambda
  118. (('argument . arg) arg)
  119. (_ #f))
  120. lst)))
  121. (define commit-short-id
  122. (compose (cut string-take <> 7) oid->string commit-id))
  123. (define (make-reporter start-commit end-commit commits)
  124. (format (current-error-port)
  125. (G_ "Authenticating commits ~a to ~a (~h new \
  126. commits)...~%")
  127. (commit-short-id start-commit)
  128. (commit-short-id end-commit)
  129. (length commits))
  130. (if (isatty? (current-error-port))
  131. (progress-reporter/bar (length commits))
  132. progress-reporter/silent))
  133. (with-error-handling
  134. (with-git-error-handling
  135. (match (command-line-arguments options)
  136. ((commit signer)
  137. (let* ((directory (assoc-ref options 'directory))
  138. (show-stats? (assoc-ref options 'show-stats?))
  139. (keyring (assoc-ref options 'keyring-reference))
  140. (repository (repository-open directory))
  141. (end (match (assoc-ref options 'end-commit)
  142. (#f (reference-target
  143. (repository-head repository)))
  144. (oid oid)))
  145. (history (match (assoc-ref options 'historical-authorizations)
  146. (#f '())
  147. (file (call-with-input-file file
  148. read-authorizations))))
  149. (cache-key (or (assoc-ref options 'cache-key)
  150. (repository-cache-key repository))))
  151. (define stats
  152. (authenticate-repository repository (string->oid commit)
  153. (openpgp-fingerprint signer)
  154. #:end end
  155. #:keyring-reference keyring
  156. #:historical-authorizations history
  157. #:cache-key cache-key
  158. #:make-reporter make-reporter))
  159. (when (and show-stats? (not (null? stats)))
  160. (show-stats stats))))
  161. (_
  162. (leave (G_ "wrong number of arguments; \
  163. expected COMMIT and SIGNER~%")))))))