>From aab42bcb212698bc1f61beb9f321ffbd751f36f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?=
Date: Fri, 15 Dec 2017 09:57:04 +0100
Subject: [PATCH 1/2] substitute: Always allow substitutes for fixed-output
derivation results.
Fixes .
* guix/scripts/substitute.scm (content-addressed-item?): New procedure.
(valid-narinfo?): Use it.
* nix/libstore/build.cc (DerivationGoal::haveDerivation): Always make a
substitution goal when 'fixedOutput' is true.
* tests/substitute.scm ("query unsigned narinfo for content-addressed
item"): New test.
---
guix/scripts/substitute.scm | 31 ++++++++++++++++++++++++++++++-
nix/libstore/build.cc | 6 ++++--
tests/substitute.scm | 24 +++++++++++++++++++++++-
3 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm
index 2fd2bf810..670a9b4dd 100755
--- a/guix/scripts/substitute.scm
+++ b/guix/scripts/substitute.scm
@@ -25,6 +25,9 @@
#:use-module (guix config)
#:use-module (guix records)
#:use-module ((guix serialization) #:select (restore-file))
+ #:use-module ((guix derivations)
+ #:select (read-derivation-from-file
+ fixed-output-derivation?))
#:use-module (guix hash)
#:use-module (guix base32)
#:use-module (guix base64)
@@ -406,10 +409,36 @@ No authentication and authorization checks are performed here!"
(let ((above-signature (string-take contents index)))
(sha256 (string->utf8 above-signature)))))))
+(define* (content-addressed-item? item)
+ "Return true if ITEM is content-addressed---i.e., if ITEM is the result of a
+fixed-output derivation."
+ (guard (c ((nix-connection-error? c)
+ ;; We failed to connect, maybe because we have the wrong
+ ;; GUIX_DAEMON_SOCKET? Let's conservatively assume that
+ ;; nothing's content-addressed.
+ #f))
+ (with-store store
+ (match (valid-derivers store item)
+ (()
+ ;; If there are no valid derivers it's most likely because ITEM is a
+ ;; source (added with 'add-to-store' or similar). Nevertheless,
+ ;; since we can't be certain, return #f.
+ #f)
+ ((drv . _)
+ (fixed-output-derivation?
+ (read-derivation-from-file drv)))))))
+
(define* (valid-narinfo? narinfo #:optional (acl (current-acl))
#:key verbose?)
- "Return #t if NARINFO's signature is not valid."
+ "Return #t if NARINFO is \"valid\"---signed by an authorized key, or
+designating a content-addressed item."
(or %allow-unauthenticated-substitutes?
+
+ ;; If NARINFO designates a content-addressed item, there's no point
+ ;; authenticating it. Don't explicitly check 'narinfo-hash' for
+ ;; integrity: this will be done by the daemon once we've downloaded it.
+ (content-addressed-item? (narinfo-path narinfo))
+
(let ((hash (narinfo-sha256 narinfo))
(signature (narinfo-signature narinfo))
(uri (uri->string (narinfo-uri narinfo))))
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index d68e8b2bc..03a8f5080 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -1034,8 +1034,10 @@ void DerivationGoal::haveDerivation()
/* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build
- them. */
- if (settings.useSubstitutes && substitutesAllowed(drv))
+ them. Always enable substitutes for fixed-output derivations to
+ protect against disappearing files and in-place modifications on
+ upstream sites. */
+ if ((fixedOutput || settings.useSubstitutes) && substitutesAllowed(drv))
foreach (PathSet::iterator, i, invalidOutputs)
addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
diff --git a/tests/substitute.scm b/tests/substitute.scm
index 0ad624795..03579b9f1 100644
--- a/tests/substitute.scm
+++ b/tests/substitute.scm
@@ -21,15 +21,17 @@
#:use-module (guix scripts substitute)
#:use-module (guix base64)
#:use-module (guix hash)
+ #:use-module (guix derivations)
#:use-module (guix serialization)
#:use-module (guix pk-crypto)
#:use-module (guix pki)
#:use-module (guix config)
#:use-module (guix base32)
- #:use-module ((guix store) #:select (%store-prefix))
+ #:use-module ((guix store) #:select (%store-prefix with-store))
#:use-module ((guix ui) #:select (guix-warning-port))
#:use-module ((guix build utils)
#:select (mkdir-p delete-file-recursively))
+ #:use-module (guix tests)
#:use-module (guix tests http)
#:use-module (rnrs bytevectors)
#:use-module (rnrs io ports)
@@ -241,6 +243,26 @@ a file for NARINFO."
(lambda ()
(guix-substitute "--query"))))))))
+(test-assert "query unsigned narinfo for content-addressed item"
+ (with-store store
+ (let* ((hash (sha256 (random-bytevector 128)))
+ (drv (derivation store "content-addressed"
+ "builtin:download" '()
+ #:hash-algo 'sha256 #:hash hash)))
+ (define output
+ (with-output-to-string
+ (lambda ()
+ (with-derivation-narinfo drv (sha256 => hash)
+ (with-input-from-string (string-append "have "
+ (derivation->output-path drv))
+ (lambda ()
+ (set! (@@ (guix scripts substitute)
+ %allow-unauthenticated-substitutes?)
+ #f)
+ (guix-substitute "--query")))))))
+
+ (string=? (string-trim-both output) (derivation->output-path drv)))))
+
(test-quit "substitute, no signature"
"no valid substitute"
(with-narinfo %narinfo
--
2.15.1