weather: Report unauthorized substitute servers.

The goal is to make it easier to diagnose substitute
misconfiguration (where we’re passing a substitute URL whose
corresponding key is not authorized).

Suggested by Emmanuel Agullo.

* guix/scripts/weather.scm (check-narinfo-authorization): New procedure.
(report-server-coverage): Use it.
* doc/guix.texi (Invoking guix weather): Document it.
(Getting Substitutes from Other Servers): Add “Troubleshooting” frame.

Change-Id: I0a049c39eefb10d6a06634c8b16aa86902769791
This commit is contained in:
Ludovic Courtès 2023-11-10 22:33:14 +01:00
parent 7e11369586
commit 4348947c74
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
2 changed files with 71 additions and 3 deletions

View File

@ -4059,6 +4059,7 @@ guix-daemon}). It can also be disabled temporarily by passing the
@node Getting Substitutes from Other Servers @node Getting Substitutes from Other Servers
@subsection Getting Substitutes from Other Servers @subsection Getting Substitutes from Other Servers
@c Note: This section name appears in a hint printed by 'guix weather'.
@cindex substitute servers, adding more @cindex substitute servers, adding more
Guix can look up and fetch substitutes from several servers. This is Guix can look up and fetch substitutes from several servers. This is
@ -4158,6 +4159,21 @@ can list as many substitute servers as you like, with the caveat that
substitute lookup can be slowed down if too many servers need to be substitute lookup can be slowed down if too many servers need to be
contacted. contacted.
@quotation Troubleshooting
To diagnose problems, you can run @command{guix weather}. For example,
running:
@example
guix weather coreutils
@end example
@noindent
not only tells you which of the currently-configured servers has
substitutes for the @code{coreutils} package, it also reports whether
one of these servers is unauthorized. @xref{Invoking guix weather}, for
more information.
@end quotation
Note that there are also situations where one may want to add the URL of Note that there are also situations where one may want to add the URL of
a substitute server @emph{without} authorizing its key. a substitute server @emph{without} authorizing its key.
@xref{Substitute Authentication}, to understand this fine point. @xref{Substitute Authentication}, to understand this fine point.
@ -16499,7 +16515,10 @@ up building packages by yourself (@pxref{Substitutes}). The
specified servers so you can have an idea of whether you'll be grumpy specified servers so you can have an idea of whether you'll be grumpy
today. It can sometimes be useful info as a user, but it is primarily today. It can sometimes be useful info as a user, but it is primarily
useful to people running @command{guix publish} (@pxref{Invoking guix useful to people running @command{guix publish} (@pxref{Invoking guix
publish}). publish}). Sometimes substitutes @emph{are} available but they are not
authorized on your system; @command{guix weather} reports it so you can
authorize them if you want (@pxref{Getting Substitutes from Other
Servers}).
@cindex statistics, for substitutes @cindex statistics, for substitutes
@cindex availability of substitutes @cindex availability of substitutes

View File

@ -35,6 +35,8 @@
#:use-module ((guix build utils) #:select (every*)) #:use-module ((guix build utils) #:select (every*))
#:use-module (guix substitutes) #:use-module (guix substitutes)
#:use-module (guix narinfo) #:use-module (guix narinfo)
#:use-module (guix pki)
#:autoload (gcrypt pk-crypto) (canonical-sexp->string)
#:use-module (guix http-client) #:use-module (guix http-client)
#:use-module (guix ci) #:use-module (guix ci)
#:use-module (guix sets) #:use-module (guix sets)
@ -185,6 +187,44 @@ or #f if it could not be determined."
(() (()
#f))) #f)))
(define (check-narinfo-authorization narinfo)
"Print a warning when NARINFO is not signed by an authorized key."
(define acl
(catch 'system-error
(lambda ()
(current-acl))
(lambda args
(warning (G_ "could not read '~a': ~a~%")
%acl-file (strerror (system-error-errno args)))
(warning (G_ "'~a' is unreadable, cannot determine whether \
substitutes are authorized~%")
%acl-file)
#f)))
(unless (or (not acl) (valid-narinfo? narinfo acl))
(warning (G_ "substitutes from '~a' are unauthorized~%")
(narinfo-uri-base narinfo))
;; The "all substitutes" below reflects the fact that, in reality, it *is*
;; possible to download "unauthorized" substitutes, as long as they match
;; authorized substitutes.
(display-hint (G_ "To authorize all substitutes from @uref{~a} to be
downloaded, the following command needs to be run as root:
@example
guix archive --authorize <<EOF
~a
EOF
@end example
Alternatively, on Guix System, you can add the signing key above to the
@code{authorized-keys} field of @code{guix-configuration}.
See \"Getting Substitutes from Other Servers\" in the manual for more
information.")
(narinfo-uri-base narinfo)
(canonical-sexp->string
(signature-subject (narinfo-signature narinfo))))))
(define* (report-server-coverage server items (define* (report-server-coverage server items
#:key display-missing?) #:key display-missing?)
"Report the subset of ITEMS available as substitutes on SERVER. "Report the subset of ITEMS available as substitutes on SERVER.
@ -204,6 +244,12 @@ In case ITEMS is an empty list, return 1 instead."
#:make-progress-reporter #:make-progress-reporter
(lambda* (total #:key url #:allow-other-keys) (lambda* (total #:key url #:allow-other-keys)
(progress-reporter/bar total))))) (progress-reporter/bar total)))))
(match narinfos
(() #f)
((narinfo . _)
;; Help diagnose missing substitute authorizations.
(check-narinfo-authorization narinfo)))
(let ((obtained (length narinfos)) (let ((obtained (length narinfos))
(requested (length items)) (requested (length items))
(missing (lset-difference string=? (missing (lset-difference string=?
@ -586,8 +632,11 @@ SERVER. Display information for packages with at least THRESHOLD dependents."
(with-store store (with-store store
(substitute-urls store)) (substitute-urls store))
(begin (begin
(warning (G_ "could not determine current \ ;; Could not determine the daemon's current
substitute URLs; using defaults~%")) ;; substitute URLs, presumably because it's too
;; old.
(warning (G_ "using default \
substitute URLs~%"))
%default-substitute-urls))) %default-substitute-urls)))
(systems (match (filter-map (match-lambda (systems (match (filter-map (match-lambda
(('system . system) system) (('system . system) system)