Add policy-driven jailed build config
This commit is contained in:
@@ -228,11 +228,195 @@
|
||||
(define (current-user-home)
|
||||
(user-home-directory (current-user-name)))
|
||||
|
||||
(define jail-default-path
|
||||
"/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin")
|
||||
|
||||
(define (native-build-executor-property-ref executor key default)
|
||||
(match (assoc key (native-build-executor-properties executor))
|
||||
((_ . value) value)
|
||||
(#f default)))
|
||||
|
||||
(define (string-list? value)
|
||||
(and (list? value)
|
||||
(every string? value)))
|
||||
|
||||
(define (environment-bindings? value)
|
||||
(and (list? value)
|
||||
(every (lambda (entry)
|
||||
(and (pair? entry)
|
||||
(string? (car entry))
|
||||
(string? (cdr entry))))
|
||||
value)))
|
||||
|
||||
(define (jail-mount-pairs? value)
|
||||
(and (list? value)
|
||||
(every (lambda (entry)
|
||||
(match entry
|
||||
((source target)
|
||||
(and (string? source)
|
||||
(string? target)))
|
||||
((source . target)
|
||||
(and (string? source)
|
||||
(string? target)))
|
||||
(_ #f)))
|
||||
value)))
|
||||
|
||||
(define %build-jail-unspecified
|
||||
(list 'build-jail-unspecified))
|
||||
|
||||
(define (build-jail-unspecified? value)
|
||||
(eq? value %build-jail-unspecified))
|
||||
|
||||
(define* (build-jail-config #:key (name %build-jail-unspecified)
|
||||
(network? %build-jail-unspecified)
|
||||
(read-only-mounts %build-jail-unspecified)
|
||||
(writable-mounts %build-jail-unspecified)
|
||||
(mounts %build-jail-unspecified)
|
||||
(env %build-jail-unspecified)
|
||||
(user %build-jail-unspecified)
|
||||
(home %build-jail-unspecified)
|
||||
(workdir %build-jail-unspecified)
|
||||
(directories %build-jail-unspecified)
|
||||
(metadata-file %build-jail-unspecified)
|
||||
(keep-root? %build-jail-unspecified))
|
||||
(unless (or (build-jail-unspecified? name) (not name) (string? name))
|
||||
(error "build jail config name must be a string or #f" name))
|
||||
(unless (or (build-jail-unspecified? network?) (boolean? network?))
|
||||
(error "build jail config network? must be a boolean" network?))
|
||||
(unless (or (build-jail-unspecified? read-only-mounts)
|
||||
(jail-mount-pairs? read-only-mounts))
|
||||
(error "build jail config read-only-mounts must be source/target pairs" read-only-mounts))
|
||||
(unless (or (build-jail-unspecified? writable-mounts)
|
||||
(jail-mount-pairs? writable-mounts))
|
||||
(error "build jail config writable-mounts must be source/target pairs" writable-mounts))
|
||||
(unless (or (build-jail-unspecified? env)
|
||||
(environment-bindings? env))
|
||||
(error "build jail config env must be an association list of strings" env))
|
||||
(unless (or (build-jail-unspecified? user) (not user) (string? user))
|
||||
(error "build jail config user must be a string or #f" user))
|
||||
(unless (or (build-jail-unspecified? home) (not home) (string? home))
|
||||
(error "build jail config home must be a string or #f" home))
|
||||
(unless (or (build-jail-unspecified? workdir) (string? workdir))
|
||||
(error "build jail config workdir must be a string" workdir))
|
||||
(unless (or (build-jail-unspecified? directories)
|
||||
(string-list? directories))
|
||||
(error "build jail config directories must be a list of strings" directories))
|
||||
(unless (or (build-jail-unspecified? metadata-file) (not metadata-file) (string? metadata-file))
|
||||
(error "build jail config metadata-file must be a string or #f" metadata-file))
|
||||
(unless (or (build-jail-unspecified? keep-root?) (boolean? keep-root?))
|
||||
(error "build jail config keep-root? must be a boolean" keep-root?))
|
||||
`((name . ,name)
|
||||
(network? . ,network?)
|
||||
(read-only-mounts . ,read-only-mounts)
|
||||
(writable-mounts . ,writable-mounts)
|
||||
(mounts . ,mounts)
|
||||
(env . ,env)
|
||||
(user . ,user)
|
||||
(home . ,home)
|
||||
(workdir . ,workdir)
|
||||
(directories . ,directories)
|
||||
(metadata-file . ,metadata-file)
|
||||
(keep-root? . ,keep-root?)))
|
||||
|
||||
(define (build-jail-config-ref config key default)
|
||||
(match (assoc key config)
|
||||
((_ . value) value)
|
||||
(#f default)))
|
||||
|
||||
(define (build-jail-config-value config key default)
|
||||
(let ((value (build-jail-config-ref config key %build-jail-unspecified)))
|
||||
(if (build-jail-unspecified? value)
|
||||
default
|
||||
value)))
|
||||
|
||||
(define (alist-replace entries key value same-key?)
|
||||
(cons (cons key value)
|
||||
(filter (lambda (entry)
|
||||
(not (same-key? (car entry) key)))
|
||||
entries)))
|
||||
|
||||
(define (merge-environment-bindings base overrides)
|
||||
(fold (lambda (entry result)
|
||||
(alist-replace result (car entry) (cdr entry) string=?))
|
||||
base
|
||||
overrides))
|
||||
|
||||
(define (default-jail-environment user home)
|
||||
(let ((effective-user (or user "build"))
|
||||
(effective-home (or home "/tmp")))
|
||||
`(("HOME" . ,effective-home)
|
||||
("LOGNAME" . ,effective-user)
|
||||
("PATH" . ,jail-default-path)
|
||||
("SHELL" . "/bin/sh")
|
||||
("TMPDIR" . "/tmp")
|
||||
("USER" . ,effective-user))))
|
||||
|
||||
(define (build-jail-base-config executor)
|
||||
(let* ((user (or (native-build-executor-property-ref executor 'user #f)
|
||||
(current-user-name)))
|
||||
(home (or (native-build-executor-property-ref executor 'home #f)
|
||||
(user-home-directory user)
|
||||
"/tmp")))
|
||||
(build-jail-config
|
||||
#:network? (native-build-executor-property-ref executor 'network? #f)
|
||||
#:read-only-mounts (or (native-build-executor-property-ref executor 'read-only-mounts #f)
|
||||
'())
|
||||
#:writable-mounts (or (native-build-executor-property-ref executor 'writable-mounts #f)
|
||||
'())
|
||||
#:env (merge-environment-bindings
|
||||
(default-jail-environment user home)
|
||||
(or (native-build-executor-property-ref executor 'env #f)
|
||||
'()))
|
||||
#:user user
|
||||
#:home home
|
||||
#:workdir (or (native-build-executor-property-ref executor 'workdir #f)
|
||||
"/tmp")
|
||||
#:directories (or (native-build-executor-property-ref executor 'directories #f)
|
||||
'())
|
||||
#:metadata-file (native-build-executor-property-ref executor 'metadata-file #f)
|
||||
#:keep-root? (native-build-executor-property-ref executor 'keep-root? #f))))
|
||||
|
||||
(define (build-jail-config-merge base override)
|
||||
(build-jail-config
|
||||
#:name (build-jail-config-value override 'name
|
||||
(build-jail-config-value base 'name #f))
|
||||
#:network? (build-jail-config-value override 'network?
|
||||
(build-jail-config-value base 'network? #f))
|
||||
#:read-only-mounts (append (build-jail-config-value base 'read-only-mounts '())
|
||||
(build-jail-config-value override 'read-only-mounts '()))
|
||||
#:writable-mounts (append (build-jail-config-value base 'writable-mounts '())
|
||||
(build-jail-config-value override 'writable-mounts '()))
|
||||
#:mounts (append (build-jail-config-value base 'mounts '())
|
||||
(build-jail-config-value override 'mounts '()))
|
||||
#:env (merge-environment-bindings (build-jail-config-value base 'env '())
|
||||
(build-jail-config-value override 'env '()))
|
||||
#:user (build-jail-config-value override 'user
|
||||
(build-jail-config-value base 'user #f))
|
||||
#:home (build-jail-config-value override 'home
|
||||
(build-jail-config-value base 'home #f))
|
||||
#:workdir (build-jail-config-value override 'workdir
|
||||
(build-jail-config-value base 'workdir "/tmp"))
|
||||
#:directories (append (build-jail-config-value base 'directories '())
|
||||
(build-jail-config-value override 'directories '()))
|
||||
#:metadata-file (build-jail-config-value override 'metadata-file
|
||||
(build-jail-config-value base 'metadata-file #f))
|
||||
#:keep-root? (build-jail-config-value override 'keep-root?
|
||||
(build-jail-config-value base 'keep-root? #f))))
|
||||
|
||||
(define (default-jail-build-executor)
|
||||
(if (jail-build-available?)
|
||||
(jail-native-build-executor #:host-name (or (safe-command-output "hostname") "localhost")
|
||||
#:sudo-command "sudo -n")
|
||||
(host-native-build-executor #:host-name (or (safe-command-output "hostname") "localhost"))))
|
||||
(let* ((host-name (or (safe-command-output "hostname") "localhost"))
|
||||
(user (current-user-name))
|
||||
(home (or (current-user-home) "/tmp")))
|
||||
(if (jail-build-available?)
|
||||
(jail-native-build-executor #:host-name host-name
|
||||
#:sudo-command "sudo -n"
|
||||
#:network? #f
|
||||
#:env (default-jail-environment user home)
|
||||
#:user user
|
||||
#:home home
|
||||
#:workdir "/tmp"
|
||||
#:directories '("/tmp"))
|
||||
(host-native-build-executor #:host-name host-name))))
|
||||
|
||||
(define (default-copy-build-executor)
|
||||
(default-jail-build-executor))
|
||||
@@ -241,7 +425,8 @@
|
||||
(default-jail-build-executor))
|
||||
|
||||
(define (jail-sudo-command executor)
|
||||
(native-build-executor-ref executor 'sudo-command "sudo -n"))
|
||||
(or (native-build-executor-property-ref executor 'sudo-command #f)
|
||||
"sudo -n"))
|
||||
|
||||
(define (jail-nullfs-mount source target mode)
|
||||
`(nullfs ,source ,target ,mode))
|
||||
@@ -296,48 +481,157 @@
|
||||
(shell-quote mountpoint)))
|
||||
mountpoint))))
|
||||
|
||||
(define (jail-mount-pair-source entry)
|
||||
(match entry
|
||||
((source target) source)
|
||||
((source . target) source)
|
||||
(_ (error "invalid jail mount pair" entry))))
|
||||
|
||||
(define (jail-mount-pair-target entry)
|
||||
(match entry
|
||||
((source target) target)
|
||||
((source . target) target)
|
||||
(_ (error "invalid jail mount pair" entry))))
|
||||
|
||||
(define (build-jail-config-mounts config)
|
||||
(append (map (lambda (entry)
|
||||
(jail-nullfs-mount (jail-mount-pair-source entry)
|
||||
(jail-mount-pair-target entry)
|
||||
'ro))
|
||||
(build-jail-config-value config 'read-only-mounts '()))
|
||||
(map (lambda (entry)
|
||||
(jail-nullfs-mount (jail-mount-pair-source entry)
|
||||
(jail-mount-pair-target entry)
|
||||
'rw))
|
||||
(build-jail-config-value config 'writable-mounts '()))
|
||||
(build-jail-config-value config 'mounts '())))
|
||||
|
||||
(define (build-jail-effective-directories config)
|
||||
(delete-duplicates
|
||||
(filter identity
|
||||
(append (build-jail-config-value config 'directories '())
|
||||
(list (build-jail-config-value config 'workdir "/tmp")
|
||||
(build-jail-config-value config 'home #f))))
|
||||
string=?))
|
||||
|
||||
(define (environment-variable-name-valid? name)
|
||||
(and (string? name)
|
||||
(> (string-length name) 0)
|
||||
(let ((chars (string->list name)))
|
||||
(and (let ((first (car chars)))
|
||||
(or (char-alphabetic? first)
|
||||
(char=? first #\_)))
|
||||
(every (lambda (character)
|
||||
(or (char-alphabetic? character)
|
||||
(char-numeric? character)
|
||||
(char=? character #\_)))
|
||||
(cdr chars))))))
|
||||
|
||||
(define (environment-binding->shell-fragment entry)
|
||||
(let ((name (car entry))
|
||||
(value (cdr entry)))
|
||||
(unless (environment-variable-name-valid? name)
|
||||
(error "invalid jail environment variable name" name))
|
||||
(string-append " "
|
||||
name
|
||||
"="
|
||||
(shell-quote value))))
|
||||
|
||||
(define (build-jail-runner-script config)
|
||||
(string-append
|
||||
"#!/bin/sh\n"
|
||||
"set -eu\n"
|
||||
"cd " (shell-quote (build-jail-config-value config 'workdir "/tmp")) "\n"
|
||||
"exec /usr/bin/env -i"
|
||||
(string-concatenate
|
||||
(map environment-binding->shell-fragment
|
||||
(build-jail-config-value config 'env '())))
|
||||
" /bin/sh /build.sh\n"))
|
||||
|
||||
(define (build-jail-command-string executor jail-root jail-name config runner-target)
|
||||
(let ((jail-user (build-jail-config-value config 'user #f))
|
||||
(network? (build-jail-config-value config 'network? #f)))
|
||||
(string-append
|
||||
(jail-sudo-command executor)
|
||||
" jail -c path=" (shell-quote jail-root)
|
||||
" name=" (shell-quote jail-name)
|
||||
" host.hostname=" (shell-quote jail-name)
|
||||
" exec.clean"
|
||||
(if network?
|
||||
""
|
||||
" ip4=disable ip6=disable")
|
||||
(if jail-user
|
||||
(string-append " exec.jail_user=" (shell-quote jail-user))
|
||||
"")
|
||||
" command=/bin/sh " (shell-quote runner-target))))
|
||||
|
||||
(define (build-jail-run-metadata executor config jail-root jail-name script mount-specs)
|
||||
`((executor . ,executor)
|
||||
(name . ,jail-name)
|
||||
(root . ,jail-root)
|
||||
(network? . ,(build-jail-config-value config 'network? #f))
|
||||
(user . ,(build-jail-config-value config 'user #f))
|
||||
(home . ,(build-jail-config-value config 'home #f))
|
||||
(workdir . ,(build-jail-config-value config 'workdir "/tmp"))
|
||||
(env . ,(build-jail-config-value config 'env '()))
|
||||
(mounts . ,mount-specs)
|
||||
(directories . ,(build-jail-effective-directories config))
|
||||
(script . ,script)
|
||||
(command . ,(build-jail-command-string executor jail-root jail-name config "/run.sh"))))
|
||||
|
||||
(define* (run-script-in-temporary-jail executor script
|
||||
#:key
|
||||
name
|
||||
config
|
||||
(mounts '())
|
||||
(directories '("/tmp")))
|
||||
(let* ((jail-root (mktemp-directory "/tmp/fruix-build-jail.XXXXXX"))
|
||||
(let* ((effective-config (build-jail-config-merge
|
||||
(build-jail-config-merge
|
||||
(build-jail-base-config executor)
|
||||
(build-jail-config #:name name
|
||||
#:mounts mounts
|
||||
#:directories directories))
|
||||
(or config
|
||||
(build-jail-config))))
|
||||
(mount-specs (build-jail-config-mounts effective-config))
|
||||
(jail-root (mktemp-directory "/tmp/fruix-build-jail.XXXXXX"))
|
||||
(script-path (string-append jail-root "/build.sh"))
|
||||
(jail-name (string-append (or name "fruix-build")
|
||||
(runner-path (string-append jail-root "/run.sh"))
|
||||
(jail-name (string-append (or (build-jail-config-value effective-config 'name #f)
|
||||
"fruix-build")
|
||||
"-"
|
||||
(store-hash-string (or name script) #:kind 'jail)))
|
||||
(jail-user (current-user-name))
|
||||
(jail-home (current-user-home))
|
||||
(store-hash-string (or (build-jail-config-value effective-config 'name #f)
|
||||
script)
|
||||
#:kind 'jail)))
|
||||
(metadata-file (build-jail-config-value effective-config 'metadata-file #f))
|
||||
(mounted '()))
|
||||
(dynamic-wind
|
||||
(lambda ()
|
||||
(for-each (lambda (directory)
|
||||
(mkdir-p (jail-root-target jail-root directory)))
|
||||
directories)
|
||||
(when (and jail-user jail-home)
|
||||
(mkdir-p (jail-root-target jail-root jail-home)))
|
||||
(build-jail-effective-directories effective-config))
|
||||
(for-each (lambda (spec)
|
||||
(ensure-jail-mount-target jail-root spec))
|
||||
mounts)
|
||||
mount-specs)
|
||||
(write-file script-path script)
|
||||
(write-file runner-path (build-jail-runner-script effective-config))
|
||||
(chmod script-path #o555)
|
||||
(chmod runner-path #o555)
|
||||
(when metadata-file
|
||||
(mkdir-p (dirname metadata-file))
|
||||
(write-file metadata-file
|
||||
(object->string
|
||||
(build-jail-run-metadata executor effective-config
|
||||
jail-root jail-name script mount-specs))))
|
||||
(for-each (lambda (spec)
|
||||
(set! mounted (cons (mount-jail-spec executor jail-root spec)
|
||||
mounted)))
|
||||
mounts))
|
||||
mount-specs))
|
||||
(lambda ()
|
||||
(let ((status
|
||||
(system* "sh" "-c"
|
||||
(string-append
|
||||
(jail-sudo-command executor)
|
||||
" jail -c path=" (shell-quote jail-root)
|
||||
" name=" (shell-quote jail-name)
|
||||
" host.hostname=" (shell-quote jail-name)
|
||||
" exec.clean"
|
||||
(if jail-user
|
||||
(string-append " exec.jail_user=" (shell-quote jail-user))
|
||||
"")
|
||||
" command=/bin/sh /build.sh"))))
|
||||
(build-jail-command-string executor jail-root jail-name
|
||||
effective-config "/run.sh"))))
|
||||
(unless (zero? status)
|
||||
(error "jail build command failed" jail-name status))))
|
||||
(lambda ()
|
||||
@@ -347,7 +641,8 @@
|
||||
(string-append "umount "
|
||||
(shell-quote mountpoint)))))
|
||||
mounted)
|
||||
(delete-path-if-exists jail-root)))))
|
||||
(unless (build-jail-config-value effective-config 'keep-root? #f)
|
||||
(delete-path-if-exists jail-root))))))
|
||||
|
||||
(define copy-build-mounted-host-paths
|
||||
'("/bin"
|
||||
@@ -372,12 +667,12 @@
|
||||
"/frx"
|
||||
"/etc"))
|
||||
|
||||
(define (copy-build-jail-mounts output-path)
|
||||
(append (map (lambda (path)
|
||||
(jail-nullfs-mount path path 'ro))
|
||||
(filter file-exists? copy-build-mounted-host-paths))
|
||||
(list (jail-devfs-mount "/dev")
|
||||
(jail-nullfs-mount output-path "/out" 'rw))))
|
||||
(define (host-path->jail-mount-pair path)
|
||||
(cons path path))
|
||||
|
||||
(define (copy-build-read-only-mounts)
|
||||
(map host-path->jail-mount-pair
|
||||
(filter file-exists? copy-build-mounted-host-paths)))
|
||||
|
||||
(define (native-build-extra-host-paths common)
|
||||
(let ((candidate-paths (filter identity
|
||||
@@ -389,13 +684,30 @@
|
||||
native-build-mounted-host-paths))))
|
||||
candidate-paths)))
|
||||
|
||||
(define (native-build-jail-mounts common build-root)
|
||||
(append (map (lambda (path)
|
||||
(jail-nullfs-mount path path 'ro))
|
||||
(append (filter file-exists? native-build-mounted-host-paths)
|
||||
(native-build-extra-host-paths common)))
|
||||
(list (jail-devfs-mount "/dev")
|
||||
(jail-nullfs-mount build-root build-root 'rw))))
|
||||
(define (native-build-read-only-mounts common)
|
||||
(map host-path->jail-mount-pair
|
||||
(append (filter file-exists? native-build-mounted-host-paths)
|
||||
(native-build-extra-host-paths common))))
|
||||
|
||||
(define (copy-build-jail-config package output-path)
|
||||
(build-jail-config
|
||||
#:name (string-append "fruix-copy-" (freebsd-package-name package))
|
||||
#:read-only-mounts (copy-build-read-only-mounts)
|
||||
#:writable-mounts (list (cons output-path "/out"))
|
||||
#:mounts (list (jail-devfs-mount "/dev"))
|
||||
#:workdir "/out"
|
||||
#:directories '("/tmp" "/out" "/dev")
|
||||
#:metadata-file (string-append output-path "/.fruix-build-jail.scm")))
|
||||
|
||||
(define (native-build-jail-config common build-root log-file)
|
||||
(build-jail-config
|
||||
#:name "fruix-native"
|
||||
#:read-only-mounts (native-build-read-only-mounts common)
|
||||
#:writable-mounts (list (cons build-root build-root))
|
||||
#:mounts (list (jail-devfs-mount "/dev"))
|
||||
#:workdir build-root
|
||||
#:directories '("/tmp" "/dev")
|
||||
#:metadata-file (string-append log-file ".jail.scm")))
|
||||
|
||||
(define (copy-plan-entry-script entry)
|
||||
(match entry
|
||||
@@ -436,10 +748,7 @@
|
||||
(define (run-copy-build-in-jail executor package output-path)
|
||||
(run-script-in-temporary-jail executor
|
||||
(copy-build-jail-script package)
|
||||
#:name (string-append "fruix-copy-"
|
||||
(freebsd-package-name package))
|
||||
#:mounts (copy-build-jail-mounts output-path)
|
||||
#:directories '("/tmp" "/out" "/dev")))
|
||||
#:config (copy-build-jail-config package output-path)))
|
||||
|
||||
(define (run-command/log-with-executor executor common build-root log-file command)
|
||||
(mkdir-p (dirname log-file))
|
||||
@@ -447,9 +756,7 @@
|
||||
((jail)
|
||||
(run-script-in-temporary-jail executor
|
||||
(native-command-jail-script command log-file)
|
||||
#:name "fruix-native"
|
||||
#:mounts (native-build-jail-mounts common build-root)
|
||||
#:directories '("/tmp" "/dev")))
|
||||
#:config (native-build-jail-config common build-root log-file)))
|
||||
(else
|
||||
(let ((status (system* "sh" "-c" (string-append command " >" log-file " 2>&1"))))
|
||||
(unless (zero? status)
|
||||
|
||||
@@ -95,14 +95,29 @@
|
||||
(working-directory . ,working-directory)))))
|
||||
|
||||
(define* (jail-native-build-executor #:key (name "jail")
|
||||
host-name root-directory sudo-command)
|
||||
host-name root-directory sudo-command
|
||||
(network? #f)
|
||||
(env '())
|
||||
user home workdir
|
||||
(read-only-mounts '())
|
||||
(writable-mounts '())
|
||||
(directories '())
|
||||
(keep-root? #f))
|
||||
(native-build-executor
|
||||
#:kind 'jail
|
||||
#:name name
|
||||
#:properties (filter-map identity
|
||||
`((host-name . ,host-name)
|
||||
(root-directory . ,root-directory)
|
||||
(sudo-command . ,sudo-command)))))
|
||||
#:properties `((host-name . ,host-name)
|
||||
(root-directory . ,root-directory)
|
||||
(sudo-command . ,sudo-command)
|
||||
(network? . ,network?)
|
||||
(env . ,env)
|
||||
(user . ,user)
|
||||
(home . ,home)
|
||||
(workdir . ,workdir)
|
||||
(read-only-mounts . ,read-only-mounts)
|
||||
(writable-mounts . ,writable-mounts)
|
||||
(directories . ,directories)
|
||||
(keep-root? . ,keep-root?))))
|
||||
|
||||
(define* (ssh-guest-native-build-executor #:key (name "ssh-guest")
|
||||
transport orchestrator
|
||||
|
||||
+88
-20
@@ -11,8 +11,6 @@
|
||||
(@@ (fruix system freebsd build) default-copy-build-executor))
|
||||
(define default-native-build-executor
|
||||
(@@ (fruix system freebsd build) default-native-build-executor))
|
||||
(define jail-nullfs-mount
|
||||
(@@ (fruix system freebsd build) jail-nullfs-mount))
|
||||
(define jail-devfs-mount
|
||||
(@@ (fruix system freebsd build) jail-devfs-mount))
|
||||
(define run-script-in-temporary-jail
|
||||
@@ -21,6 +19,14 @@
|
||||
(@@ (fruix system freebsd build) run-command/log-with-executor))
|
||||
(define native-install-command-string
|
||||
(@@ (fruix system freebsd build) native-install-command-string))
|
||||
(define build-jail-config
|
||||
(@@ (fruix system freebsd build) build-jail-config))
|
||||
(define build-jail-config-ref
|
||||
(@@ (fruix system freebsd build) build-jail-config-ref))
|
||||
(define build-jail-base-config
|
||||
(@@ (fruix system freebsd build) build-jail-base-config))
|
||||
(define build-jail-command-string
|
||||
(@@ (fruix system freebsd build) build-jail-command-string))
|
||||
|
||||
(define (trim text)
|
||||
(string-trim-both text))
|
||||
@@ -37,32 +43,91 @@
|
||||
(if (jail-build-available?) 'jail 'host)
|
||||
(native-build-executor-kind executor)))
|
||||
|
||||
(let* ((config (build-jail-base-config (jail-native-build-executor)))
|
||||
(env (build-jail-config-ref config 'env '()))
|
||||
(path-entry (assoc "PATH" env))
|
||||
(tmpdir-entry (assoc "TMPDIR" env)))
|
||||
(test-equal "jail build config disables network by default"
|
||||
#f
|
||||
(build-jail-config-ref config 'network? #t))
|
||||
(test-equal "jail build config defaults to /tmp workdir"
|
||||
"/tmp"
|
||||
(build-jail-config-ref config 'workdir #f))
|
||||
(test-equal "jail build config exposes minimal PATH"
|
||||
"/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin"
|
||||
(and path-entry (cdr path-entry)))
|
||||
(test-equal "jail build config sets TMPDIR"
|
||||
"/tmp"
|
||||
(and tmpdir-entry (cdr tmpdir-entry))))
|
||||
|
||||
(let* ((command (build-jail-command-string
|
||||
(jail-native-build-executor)
|
||||
"/tmp/fruix-jail-root"
|
||||
"fruix-test"
|
||||
(build-jail-base-config (jail-native-build-executor))
|
||||
"/run.sh"))
|
||||
(networked-command (build-jail-command-string
|
||||
(jail-native-build-executor #:network? #t)
|
||||
"/tmp/fruix-jail-root"
|
||||
"fruix-test"
|
||||
(build-jail-base-config (jail-native-build-executor #:network? #t))
|
||||
"/run.sh")))
|
||||
(test-assert "jail command disables IPv4 and IPv6 by default"
|
||||
(and (string-contains command " ip4=disable")
|
||||
(string-contains command " ip6=disable")))
|
||||
(test-assert "jail command can opt into network access"
|
||||
(and (not (string-contains networked-command " ip4=disable"))
|
||||
(not (string-contains networked-command " ip6=disable")))))
|
||||
|
||||
(when (jail-build-available?)
|
||||
(let* ((executor (default-copy-build-executor))
|
||||
(output-dir (mktemp-directory "/tmp/fruix-build-jails-copy.XXXXXX"))
|
||||
(result-file (string-append output-dir "/result"))
|
||||
(user-file (string-append output-dir "/user")))
|
||||
(run-script-in-temporary-jail
|
||||
executor
|
||||
(string-append "#!/bin/sh\n"
|
||||
"set -eu\n"
|
||||
"printf ok > /out/result\n"
|
||||
"id -un > /out/user\n")
|
||||
#:name "fruix-build-jails-copy"
|
||||
#:mounts (list (jail-nullfs-mount "/bin" "/bin" 'ro)
|
||||
(jail-nullfs-mount "/lib" "/lib" 'ro)
|
||||
(jail-nullfs-mount "/libexec" "/libexec" 'ro)
|
||||
(jail-nullfs-mount "/usr" "/usr" 'ro)
|
||||
(jail-nullfs-mount "/etc" "/etc" 'ro)
|
||||
(jail-devfs-mount "/dev")
|
||||
(jail-nullfs-mount output-dir "/out" 'rw))
|
||||
#:directories '("/tmp" "/dev" "/out"))
|
||||
(user-file (string-append output-dir "/user"))
|
||||
(env-file (string-append output-dir "/env"))
|
||||
(pwd-file (string-append output-dir "/pwd"))
|
||||
(config (build-jail-config
|
||||
#:name "fruix-build-jails-copy"
|
||||
#:read-only-mounts (list (cons "/bin" "/bin")
|
||||
(cons "/lib" "/lib")
|
||||
(cons "/libexec" "/libexec")
|
||||
(cons "/usr" "/usr")
|
||||
(cons "/etc" "/etc"))
|
||||
#:writable-mounts (list (cons output-dir "/out"))
|
||||
#:mounts (list (jail-devfs-mount "/dev"))
|
||||
#:workdir "/out"
|
||||
#:directories '("/tmp" "/dev" "/out"))))
|
||||
(dynamic-wind
|
||||
(lambda ()
|
||||
(setenv "FRUIX_BUILD_JAIL_TEST_SECRET" "should-not-leak"))
|
||||
(lambda ()
|
||||
(run-script-in-temporary-jail
|
||||
executor
|
||||
(string-append "#!/bin/sh\n"
|
||||
"set -eu\n"
|
||||
"printf ok > /out/result\n"
|
||||
"id -un > /out/user\n"
|
||||
"env | sort > /out/env\n"
|
||||
"pwd > /out/pwd\n")
|
||||
#:config config))
|
||||
(lambda ()
|
||||
(unsetenv "FRUIX_BUILD_JAIL_TEST_SECRET")))
|
||||
(test-equal "generic jail runner writes result"
|
||||
"ok"
|
||||
(trim (command-output "cat" result-file)))
|
||||
(test-equal "generic jail runner uses current user ownership context"
|
||||
(trim (command-output "id" "-un"))
|
||||
(trim (command-output "cat" user-file)))))
|
||||
(trim (command-output "cat" user-file)))
|
||||
(test-equal "generic jail runner uses configured workdir"
|
||||
"/out"
|
||||
(trim (command-output "cat" pwd-file)))
|
||||
(let ((env-text (command-output "cat" env-file)))
|
||||
(test-assert "generic jail runner drops inherited host environment"
|
||||
(not (string-contains env-text "FRUIX_BUILD_JAIL_TEST_SECRET=")))
|
||||
(test-assert "generic jail runner preserves whitelisted PATH"
|
||||
(string-contains env-text "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin"))
|
||||
(test-assert "generic jail runner preserves whitelisted TMPDIR"
|
||||
(string-contains env-text "TMPDIR=/tmp")))))
|
||||
|
||||
(let* ((executor (default-native-build-executor))
|
||||
(build-root (mktemp-directory "/tmp/fruix-build-jails-native.XXXXXX"))
|
||||
@@ -80,6 +145,9 @@
|
||||
(run-command/log-with-executor executor common build-root log-file
|
||||
"make -C /usr/src -V .CURDIR")
|
||||
(test-assert "native build executor can run make with mounted source tree"
|
||||
(string-contains (trim (command-output "cat" log-file)) "/usr/src")))
|
||||
(string-contains (trim (command-output "cat" log-file)) "/usr/src"))
|
||||
(when (eq? (native-build-executor-kind executor) 'jail)
|
||||
(test-assert "native build executor records jail metadata"
|
||||
(file-exists? (string-append log-file ".jail.scm")))))
|
||||
|
||||
(test-end "build-jails")
|
||||
|
||||
Reference in New Issue
Block a user