summaryrefslogtreecommitdiff
path: root/tests/substitute.scm
diff options
context:
space:
mode:
authorReepca Russelstein <reepca@russelstein.xyz>2026-07-03 17:37:11 -0500
committerLudovic Courtès <ludo@gnu.org>2026-07-05 11:47:15 +0200
commit57fd857c1e3ff11511ba451021d559e874b50e34 (patch)
tree3de94e8c946a2f90c3ae03626945a781b0699e04 /tests/substitute.scm
parentcf583b3a3df0741dcc6ab9906da191db2f527a01 (diff)
scripts: substitute: Accommodate renaming unwritable directories.
This fixes a regression introduced in 26d7eb8a4adafc648ef035e91b6bbc4945d4c962 when running ‘guix-daemon’ without root privileges. On rootless installations, we must abide by the usual file access rules, which include the requirement that a directory be writable before it be renamed (the rationale being that its ".." entry needs to be modified). * guix/scripts/substitute.scm (rename-file*): New procedure. (guix-substitute): Use it. * tests/substitute.scm (directory-nar-sha256): New procedure. (%narinfo/directory): New variable. (call-with-narinfo): Add '#:directory?' keyword argument. (with-directory-narinfo): New syntax. ("substitute, authorized key, directory"): New test case. Fixes: guix/guix#9686 Change-Id: I9d399dd5f1717b7d02854d97e1100a0a464fac75 Signed-off-by: Ludovic Courtès <ludo@gnu.org> Merges: #9702
Diffstat (limited to 'tests/substitute.scm')
-rw-r--r--tests/substitute.scm75
1 files changed, 70 insertions, 5 deletions
diff --git a/tests/substitute.scm b/tests/substitute.scm
index b749561347a..fe1e29adb6b 100644
--- a/tests/substitute.scm
+++ b/tests/substitute.scm
@@ -38,6 +38,7 @@
38 #:use-module (rnrs bytevectors) 38 #:use-module (rnrs bytevectors)
39 #:use-module (rnrs io ports) 39 #:use-module (rnrs io ports)
40 #:use-module (web uri) 40 #:use-module (web uri)
41 #:use-module (ice-9 match)
41 #:use-module (ice-9 regex) 42 #:use-module (ice-9 regex)
42 #:use-module (ice-9 binary-ports) 43 #:use-module (ice-9 binary-ports)
43 #:use-module (srfi srfi-11) 44 #:use-module (srfi srfi-11)
@@ -65,7 +66,7 @@ it writes to GUIX-WARNING-PORT a messages that matches ERROR-RX."
65 66
66(define (request-substitution item destination) 67(define (request-substitution item destination)
67 "Run 'guix substitute --substitute' to fetch ITEM to DESTINATION." 68 "Run 'guix substitute --substitute' to fetch ITEM to DESTINATION."
68 (false-if-exception (delete-file destination)) 69 (false-if-exception (delete-file-recursively destination))
69 (with-input-from-string (string-append "substitute " item " " 70 (with-input-from-string (string-append "substitute " item " "
70 destination "\n") 71 destination "\n")
71 (lambda () 72 (lambda ()
@@ -143,6 +144,29 @@ version identifier.."
143 ;; <https://www.rfc-editor.org/rfc/rfc5737>. 144 ;; <https://www.rfc-editor.org/rfc/rfc5737>.
144 "http://203.0.113.1") 145 "http://203.0.113.1")
145 146
147(define (directory-nar-sha256 string)
148 "Compute the sha256 of the nar of a directory containing a single regular
149file named \"foo\" containing STRING."
150 (sha256 (call-with-output-bytevector
151 (lambda (port)
152 (let ((bv (string->utf8 string)))
153 (call-with-input-bytevector
154 bv
155 (lambda (contents)
156 (write-file-tree "root" port
157 #:file-type+size
158 (match-lambda
159 ("root"
160 (values 'directory #f))
161 ("root/foo"
162 (values 'regular
163 (bytevector-length
164 bv))))
165 #:file-port
166 (const contents)
167 #:directory-entries
168 (const '("foo"))))))))))
169
146(define (plain-file-nar-sha256 string) 170(define (plain-file-nar-sha256 string)
147 (sha256 (call-with-output-bytevector 171 (sha256 (call-with-output-bytevector
148 (lambda (port) 172 (lambda (port)
@@ -172,9 +196,22 @@ References: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bar bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
172Deriver: cccccccccccccccccccccccccccccccc-foo.drv 196Deriver: cccccccccccccccccccccccccccccccc-foo.drv
173System: mips64el-linux\n")) 197System: mips64el-linux\n"))
174 198
199(define %narinfo/directory
200 (string-append "StorePath: " (%store-prefix)
201 "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo
202URL: example.nar
203Compression: none
204NarHash: sha256:" (bytevector->nix-base32-string
205 (directory-nar-sha256 "Substitutable data.")) "
206NarSize: 304
207References: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bar bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-baz
208Deriver: cccccccccccccccccccccccccccccccc-foo.drv
209System: mips64el-linux\n"))
210
175(define* (call-with-narinfo narinfo thunk 211(define* (call-with-narinfo narinfo thunk
176 #:optional 212 #:optional
177 (narinfo-directory %main-substitute-directory)) 213 (narinfo-directory %main-substitute-directory)
214 #:key directory?)
178 "Call THUNK in a context where the directory at URL is populated with 215 "Call THUNK in a context where the directory at URL is populated with
179a file for NARINFO." 216a file for NARINFO."
180 (mkdir-p narinfo-directory) 217 (mkdir-p narinfo-directory)
@@ -195,9 +232,16 @@ a file for NARINFO."
195 (cut display narinfo <>)) 232 (cut display narinfo <>))
196 233
197 ;; Prepare the nar. 234 ;; Prepare the nar.
198 (call-with-output-file 235 (let ((out (string-append narinfo-directory "/example.out")))
199 (string-append narinfo-directory "/example.out") 236 (when (file-exists? out)
200 (cut display "Substitutable data." <>)) 237 (delete-file-recursively out))
238 (if directory?
239 (begin
240 (mkdir out)
241 (call-with-output-file (string-append out "/foo")
242 (cut display "Substitutable data." <>)))
243 (call-with-output-file out
244 (cut display "Substitutable data." <>))))
201 (call-with-output-file 245 (call-with-output-file
202 (string-append narinfo-directory "/example.nar") 246 (string-append narinfo-directory "/example.nar")
203 (cute write-file 247 (cute write-file
@@ -215,6 +259,9 @@ a file for NARINFO."
215(define-syntax-rule (with-narinfo* narinfo directory body ...) 259(define-syntax-rule (with-narinfo* narinfo directory body ...)
216 (call-with-narinfo narinfo (lambda () body ...) directory)) 260 (call-with-narinfo narinfo (lambda () body ...) directory))
217 261
262(define-syntax-rule (with-directory-narinfo narinfo body ...)
263 (call-with-narinfo narinfo (lambda () body ...) #:directory? #t))
264
218;; Transmit these options to 'guix substitute'. 265;; Transmit these options to 'guix substitute'.
219(substitute-urls (list (getenv "GUIX_BINARY_SUBSTITUTE_URL"))) 266(substitute-urls (list (getenv "GUIX_BINARY_SUBSTITUTE_URL")))
220 267
@@ -524,6 +571,24 @@ System: mips64el-linux\n")))
524 (lambda () 571 (lambda ()
525 (false-if-exception (delete-file "substitute-retrieved")))))) 572 (false-if-exception (delete-file "substitute-retrieved"))))))
526 573
574(test-equal "substitute, authorized key, directory"
575 '("Substitutable data." 1 #o555)
576 (with-directory-narinfo (string-append %narinfo/directory "Signature: "
577 (signature-field %narinfo/directory))
578 (dynamic-wind
579 (const #t)
580 (lambda ()
581 (request-substitution (string-append (%store-prefix)
582 "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
583 "substitute-retrieved")
584 (list (call-with-input-file "substitute-retrieved/foo" get-string-all)
585 (stat:mtime (lstat "substitute-retrieved"))
586 (stat:perms (lstat "substitute-retrieved"))))
587 (lambda ()
588 ;; Needs to be writable to be deleted
589 (false-if-exception (chmod "substitute-retrieved" #o755))
590 (false-if-exception (delete-file-recursively "substitute-retrieved"))))))
591
527(test-equal "substitute, authorized key, first substitute URL is unroutable" 592(test-equal "substitute, authorized key, first substitute URL is unroutable"
528 '("Substitutable data." 1 #o444) 593 '("Substitutable data." 1 #o444)
529 (with-narinfo (string-append %narinfo "Signature: " 594 (with-narinfo (string-append %narinfo "Signature: "