aboutsummaryrefslogtreecommitdiff
path: root/guix/scripts/substitute.scm
diff options
context:
space:
mode:
Diffstat (limited to 'guix/scripts/substitute.scm')
-rwxr-xr-xguix/scripts/substitute.scm141
1 files changed, 85 insertions, 56 deletions
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index ba2b2d2d4e..0de0215807 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -352,41 +352,34 @@ No authentication and authorization checks are performed here!"
(and (every (cut member <> signed-fields) %mandatory-fields)
(sha256 (string->utf8 above-signature))))))))
-(define* (valid-narinfo? narinfo #:optional (acl (current-acl))
- #:key verbose?)
- "Return #t if NARINFO's signature is not valid."
+(define* (compute-valid-narinfo-set narinfos #:optional (acl (current-acl))
+ #:key verbose?)
+ "Return a list of narinfos from NARINFO's, if they together meet the ACL.
+If the ACL permits narinfos from a single source, then the return value could
+be a list of a single narinfo, if the ACL requires multiple public keys to be
+matched, then in the case where the ACL is matched, the return value will be
+the list containing all the narinfos that together meet the ACL, the order
+will be consistent with the order of the narinfos in NARINFOS."
(or (%allow-unauthenticated-substitutes?)
- (let ((hash (narinfo-sha256 narinfo))
- (signature (narinfo-signature narinfo))
- (uri (uri->string (first (narinfo-uris narinfo)))))
- (and hash signature
- (signature-case (signature hash acl)
- (valid-signature #t)
- (invalid-signature
- (when verbose?
- (format (current-error-port)
- "invalid signature for substitute at '~a'~%"
- uri))
- #f)
- (hash-mismatch
- (when verbose?
- (format (current-error-port)
- "hash mismatch for substitute at '~a'~%"
- uri))
- #f)
- (unauthorized-key
- (when verbose?
- (format (current-error-port)
- "substitute at '~a' is signed by an \
-unauthorized party~%"
- uri))
- #f)
- (corrupt-signature
- (when verbose?
- (format (current-error-port)
- "corrupt signature for substitute at '~a'~%"
- uri))
- #f))))))
+ (let ((narinfos-by-hash
+ (fold (lambda (narinfo result)
+ (let ((hash (narinfo-hash narinfo)))
+ (alist-cons hash
+ (cons narinfo
+ (or (assoc-ref result hash)
+ '()))
+ (assoc-delete hash result))))
+ '()
+ ;; reverse narinfos, so that the ordering on the alist
+ ;; values is consistent with the ordering of narinfos
+ (reverse narinfos))))
+ (any (match-lambda
+ ((hash . narinfos)
+ (let ((signatures (map narinfo-signature narinfos)))
+ (signature-case (signatures hash acl)
+ (matching-acl-entry narinfos)
+ (else #f)))))
+ narinfos-by-hash))))
(define (write-narinfo narinfo port)
"Write NARINFO to PORT."
@@ -729,7 +722,7 @@ the same store item. This ignores unnecessary metadata such as the Nar URL."
(= (narinfo-size narinfo1)
(narinfo-size narinfo2))))
-(define (lookup-narinfos/diverse caches paths authorized?)
+(define (lookup-narinfos/diverse caches paths acl)
"Look up narinfos for PATHS on all of CACHES, a list of URLS, in that order.
That is, when a cache lacks an AUTHORIZED? narinfo, look it up in the next
cache, and so on.
@@ -749,27 +742,63 @@ AUTHORIZED? narinfo."
several)))))))
(let loop ((caches caches)
- (paths paths)
- (result vlist-null) ;path->narinfo vhash
- (hits '())) ;paths
- (match paths
- (() ;we're done
- ;; Now iterate on all the HITS, and return exactly one match for each
- ;; hit: the first narinfo that is authorized, or that has the same hash
- ;; as an authorized narinfo, in the order of CACHES.
- (filter-map (select-hit result) hits))
- (_
- (match caches
- ((cache rest ...)
- (let* ((narinfos (lookup-narinfos cache paths))
- (definite (map narinfo-path (filter authorized? narinfos)))
- (missing (lset-difference string=? paths definite))) ;XXX: perf
- (loop rest missing
- (fold vhash-cons result
- (map narinfo-path narinfos) narinfos)
- (append definite hits))))
- (() ;that's it
- (filter-map (select-hit result) hits)))))))
+ ;; the narinfos for each path, each narinfo will be for a
+ ;; specific cache. The ordering of the values for
+ ;; paths-to-narinfos will be the reverse of the ordering of the
+ ;; caches, so this needs to be taken in to account when using it.
+ (paths-to-narinfos (fold (lambda (path result)
+ (vhash-cons path
+ '()
+ result))
+ vlist-null
+ paths))
+ ;; list of selected narinfos for the subset of paths for which a
+ ;; narinfo that is sutitable to use could be found. These
+ ;; narinfo's should correspond to the first cache from which it
+ ;; was available. While the ACL might not trust this cache alone,
+ ;; these narinfos should be suitable based on querying multiple
+ ;; cache servers for narinfos.
+ (result '()))
+ (match caches
+ (() result)
+ ((cache remaining-caches ...)
+ (let* ((paths-to-fetch (vhash-fold (lambda (path narinfos result)
+ (cons path result))
+ '()
+ paths-to-narinfos))
+ (narinfos-by-path (fold (lambda (narinfo result)
+ (vhash-cons (narinfo-path narinfo)
+ narinfo
+ result))
+ vlist-null
+ (lookup-narinfos cache paths-to-fetch)))
+ (updated-paths-to-narinfos
+ (fold (lambda (path result)
+ )))
+ (selected-narinfos
+ (vhash-fold (lambda (path narinfos result)
+ (let ((valid-narinfo-set
+ (compute-valid-narinfo-set
+ ;; reverse narinfos, so that the order
+ ;; matches that of the caches
+ (reverse narinfos)
+ acl)))
+ (if valid-narinfo-set
+ (cons (first valid-narinfo-set)
+ result)
+ result)))
+ '()
+ updated-paths-to-narinfos))
+ (paths-to-narinfos-for-remaining-paths
+ (fold (lambda (path result)
+ (vhash-delete path result))
+ updated-paths-to-narinfos
+ (map narinfo-path selected-narinfos))))
+
+ (loop remaining-caches
+ paths-to-narinfos-for-remaining-paths
+ (append selected-narinfos
+ result)))))))
(define (lookup-narinfo caches path authorized?)
"Return the narinfo for PATH in CACHES, or #f when no substitute for PATH