Compare commits

...

3 Commits

8 changed files with 1102 additions and 0 deletions

View File

@@ -1723,3 +1723,147 @@ Next recommended step:
- Fruix at the product boundary
- `/frx` as the canonical store root
- stable upstream-derived internal names unless there is strong architectural value in renaming them
## 2026-04-01 — Phase 6.1 completed: real package build validated into `/frx/store`
Completed work:
- added a runnable real-package harness:
- `tests/guix/run-phase6-real-package-build.sh`
- wrote the Phase 6.1 report:
- `docs/reports/phase6-real-package-build-freebsd.md`
- ran the real-package harness successfully and captured metadata under:
- `/tmp/phase6-real-package-metadata.txt`
Important findings:
- the checkout can now build a real package definition derived from Guix's `hello` package through:
- `./pre-inst-env fruix build -f ...`
- the FreeBSD-aware daemon
- `/frx/store`
- this moves the project beyond the deliberately minimal Phase 5 custom derivation path and into a real package-definition flow
- the current successful path still uses a prefetched local GNU Hello tarball as the package source because the built-in downloader path remains a separate unresolved FreeBSD/root-daemon issue
- observed metadata confirmed:
- `drv_path=/frx/store/...-hello-2.12.3.drv`
- `out_path=/frx/store/...-hello-2.12.3`
- `source_store_path=/frx/store/...-hello-2.12.3.tar.gz`
- `runtime_output=Hello, world!`
- a daemon-side references query confirmed that the built output preserved the declared source store item as a direct reference
Current assessment:
- Phase 6.1 is now satisfied on the current FreeBSD prototype track
- the next step is to move the already validated jail/build-user model into this live package-build path rather than keeping it prototype-only
## 2026-04-01 — Phase 6.2 completed: jail/build-user isolation integrated into the real package path
Completed work:
- added a reusable UID/GID drop helper source:
- `tests/daemon/freebsd-drop-exec.c`
- added a runnable jail-integrated package harness:
- `tests/guix/run-phase6-jail-package-build.sh`
- wrote the Phase 6.2 report:
- `docs/reports/phase6-jail-build-integration-freebsd.md`
- ran the jail-integrated harness successfully and captured metadata under:
- `/tmp/phase6-jail-package-metadata.txt`
Important findings:
- a real package build derived from Guix's `hello` definition now runs through the live daemon path inside a FreeBSD jail rather than only through the earlier prototype scripts
- the actual build work inside the jail runs as dropped credentials:
- UID `35001`
- GID `35001`
- the integrated build path required one additional FreeBSD-specific adjustment beyond the earlier prototype:
- the daemon-side host `TMPDIR` path was not automatically valid inside the jail, so the jailed build environment must reset `TMPDIR=/tmp`
- observed metadata confirmed:
- `drv_path=/frx/store/...-hello-2.12.3.drv`
- `out_path=/frx/store/...-hello-2.12.3`
- `runtime_output=Hello, world!`
- `build_uid=35001`
- `build_gid=35001`
- `jail_hostname=fruix-phase6-hello-...`
- `build_mode=freebsd-jail`
- `source_store_path=/frx/store/...-hello-2.12.3.tar.gz`
- the GNU Hello test suite also passed inside the jail-integrated build path
Current assessment:
- Phase 6.2 is now satisfied on the current FreeBSD prototype track
- the next step is to validate a minimal user-facing profile installation flow on top of these real store outputs
## 2026-04-01 — Phase 6.3 completed: minimal profile installation validated on real store outputs
Completed work:
- added a runnable real-store profile harness:
- `tests/packages/run-phase6-real-store-profile-prototype.sh`
- wrote the Phase 6.3 report:
- `docs/reports/phase6-real-store-profile-freebsd.md`
- updated the Phase 6 package-build harnesses so they can recover derivation paths even when the requested outputs are already present in `/frx/store`
- ran the real-store profile harness successfully and captured metadata under:
- `/tmp/phase6-real-store-profile-metadata.txt`
Important findings:
- the current FreeBSD track now has a minimal user-facing profile installation flow built on top of real Phase 6 store outputs rather than the earlier Phase 3 package/profile prototype inputs
- the validated transaction semantics are intentionally small but real:
- generation 1 is created from the Phase 6.1 host-built store item
- generation 2 is created from the Phase 6.2 jail-built store item
- the `profile` symlink switches to generation 2
- both generations remain addressable
- observed metadata confirmed:
- `profile_target=profile-2-link`
- `generation1_store_path=/frx/store/...-hello-2.12.3`
- `generation2_store_path=/frx/store/...-hello-2.12.3`
- `current_store_path=/frx/store/...-hello-2.12.3`
- `profile_hello_output=Hello, world!`
- `clean_env_hello_output=Hello, world!`
- the upstream-derived profile layer is still not fully usable on this FreeBSD track because the current `guix profiles` / `fruix package` path still reaches the unresolved bootstrap-platform blocker:
- `dynamic linker name not known for this system "x86_64-freebsd15.0"`
- despite that blocker, the minimal Fruix-owned profile path is now validated on top of real daemon-built store items
Current assessment:
- Phase 6.3 is now satisfied on the current FreeBSD prototype track
- Phase 6 as a whole is now complete on the active FreeBSD amd64 prototype path
## 2026-04-01 — Phase 6 completed on the current FreeBSD prototype track
Phase 6 is now considered complete for the active FreeBSD amd64 prototype path.
Why this milestone is satisfied:
- **Phase 6.1** success criteria were met on the prototype track:
- a real package definition derived from Guix's `hello` package now builds through `fruix build`
- the output lands in `/frx/store`
- the package runs from the store and preserves a declared source reference
- **Phase 6.2** success criteria were met on the prototype track:
- a real package build now executes inside a FreeBSD jail
- the build work runs under dropped numeric build credentials
- the jailed build succeeds into `/frx/store`
- **Phase 6.3** success criteria were met on the prototype track:
- real Phase 6 store outputs can be installed into a minimal profile environment
- generation switching works in a concrete form
- package execution through the profile succeeds for the current user
Important scope note:
- this completes the **real FreeBSD-backed store-build milestone** on the current prototype track, not full upstream-package-graph support or full upstream profile-layer parity yet
- the current package path still relies on a prefetched local source tarball for GNU Hello because the built-in downloader/root-daemon path remains a separate FreeBSD issue
- the current profile-installation path is a Fruix-owned minimal layer over real store outputs because the upstream-derived profile code still hits the unresolved FreeBSD bootstrap-platform mapping blocker
- nevertheless, the core Phase 6 question has now been answered positively:
- real package definitions can be built into `/frx/store`
- those builds can run under integrated jail/build-user isolation
- and the resulting store items can be exposed through a minimal user-facing profile flow
Next recommended step:
1. begin Phase 7.1 by defining a minimal Fruix operating-system model for FreeBSD
2. carry forward the selective Fruix naming policy:
- Fruix at the product boundary
- `/frx` as the canonical store root
- stable upstream-derived internal names unless there is strong architectural value in renaming them
3. keep the two remaining Phase 6 follow-up blockers visible but scoped:
- built-in downloader/root-daemon integration for real package origins
- upstream-derived profile/bootstrap-platform support for `x86_64-freebsd15.0`

View File

@@ -0,0 +1,72 @@
# Phase 6.2: FreeBSD jail and build-user isolation integrated into the live build path
Date: 2026-04-01
## Summary
This step takes the earlier FreeBSD jail and privilege-drop prototypes and moves them into a real package build submitted through the live Fruix/Guix daemon path.
Added files:
- `tests/daemon/freebsd-drop-exec.c`
- `tests/guix/run-phase6-jail-package-build.sh`
## Validation command
Run command:
```sh
METADATA_OUT=/tmp/phase6-jail-package-metadata.txt \
./tests/guix/run-phase6-jail-package-build.sh
```
## What the harness does
The harness:
1. reuses the patched Phase 5 checkout/runtime setup
2. fetches GNU Hello `2.12.3` and verifies the expected SHA256
3. starts the patched daemon on a temporary Unix socket
4. generates a package file that inherits from Guix's real `hello` package definition
5. lowers that package through a FreeBSD-specific build system whose builder:
- compiles `freebsd-drop-exec`
- creates a thin jail root
- mounts a minimal host tool view with explicit `nullfs` mounts
- mounts the source tarball read-only
- mounts per-build writable work/output areas
- enters the jail
- drops to UID/GID `35001:35001`
- runs the GNU Hello configure/build/check/install sequence inside the jail
6. copies the staged result back to the real `/frx/store` output path
7. validates runtime output, jail metadata, and preserved source references
## Observed results
Observed metadata included:
- `drv_path=/frx/store/...-hello-2.12.3.drv`
- `out_path=/frx/store/...-hello-2.12.3`
- `runtime_output=Hello, world!`
- `build_uid=35001`
- `build_gid=35001`
- `jail_hostname=fruix-phase6-hello-...`
- `build_mode=freebsd-jail`
- `source_store_path=/frx/store/...-hello-2.12.3.tar.gz`
The GNU Hello test suite also passed inside the jail build path.
## Important findings
- this is no longer a separate subsystem prototype; a real package build submitted through the daemon now executes under FreeBSD jail isolation with dropped build credentials
- the daemon's host `TMPDIR` path was not automatically meaningful inside the jail, so the integrated build path had to reset `TMPDIR=/tmp` inside the jailed builder environment
- a small helper binary was still needed to perform the post-`jexec` UID/GID drop reliably using numeric build identities on FreeBSD
- the output preserved a direct reference to the source tarball store item, so the integrated jail path still maintains the store-reference expectations established in Phase 6.1
## Conclusion
Phase 6.2 is satisfied on the current FreeBSD prototype track:
- a real Fruix/Guix package build now runs inside a FreeBSD jail
- the actual build work executes as a dropped numeric build user (`35001:35001`)
- the build succeeds into `/frx/store`
- the previously separate jail/build-user validation work is now connected to the live package-build path

View File

@@ -0,0 +1,65 @@
# Phase 6.1: Real FreeBSD-backed package build into `/frx/store`
Date: 2026-04-01
## Summary
This step moves beyond the Phase 5 minimal custom derivation path and validates a real package definition derived from Guix's `hello` package through the live Fruix/Guix checkout, daemon, and `/frx/store` path on FreeBSD.
Added file:
- `tests/guix/run-phase6-real-package-build.sh`
## Validation command
Run command:
```sh
METADATA_OUT=/tmp/phase6-real-package-metadata.txt \
./tests/guix/run-phase6-real-package-build.sh
```
## What the harness does
The harness:
1. reuses the patched Phase 5 checkout/runtime setup
2. fetches GNU Hello `2.12.3` and verifies the expected SHA256
3. starts the patched daemon on a temporary Unix socket
4. generates a package file that inherits from Guix's real `hello` package definition
5. replaces the source with a prefetched local tarball store item to avoid the still-unresolved built-in downloader/root path on FreeBSD
6. lowers that package through a tiny FreeBSD host build system and invokes it through:
- `./pre-inst-env fruix build -f ...`
7. validates the built result in `/frx/store`
8. queries the daemon for direct references of the output path
## Observed results
Observed metadata included:
- `drv_path=/frx/store/...-hello-2.12.3.drv`
- `out_path=/frx/store/...-hello-2.12.3`
- `source_store_path=/frx/store/...-hello-2.12.3.tar.gz`
- `runtime_output=Hello, world!`
- `frontend_invocation=./pre-inst-env fruix build -f ...`
The direct references query included both:
- the built output path itself
- the source tarball store item recorded by the build output metadata
## Important findings
- this is the first validated `fruix build`-style package build on the current FreeBSD track that lands a real package output in `/frx/store`
- the package definition was not invented from scratch; it inherits from the real Guix `hello` package and only swaps in a FreeBSD-specific build-system path plus a prefetched source item
- the live daemon/store path is now strong enough to materialize and execute a genuine package output rather than only the earlier minimal derivation-backed probes
- the built-in downloader path is still not ready for this FreeBSD/root daemon flow, so Phase 6.1 currently uses a prefetched local tarball to isolate the package-build boundary from that separate runtime issue
## Conclusion
Phase 6.1 is satisfied on the current FreeBSD prototype track:
- a real package definition derived from Guix's `hello` package builds successfully through the Fruix/Guix checkout and daemon path
- the output lands in `/frx/store`
- the package runs successfully from the store
- the output preserves a declared source reference that can be queried through the daemon

View File

@@ -0,0 +1,70 @@
# Phase 6.3: Minimal profile installation validated on top of real store outputs
Date: 2026-04-01
## Summary
This step validates a minimal user-facing profile installation flow using the real `/frx/store` outputs produced in Phases 6.1 and 6.2.
Added file:
- `tests/packages/run-phase6-real-store-profile-prototype.sh`
## Validation command
Run command:
```sh
METADATA_OUT=/tmp/phase6-real-store-profile-metadata.txt \
./tests/packages/run-phase6-real-store-profile-prototype.sh
```
## What the harness does
The harness:
1. reruns the Phase 6.1 real-package build harness
2. reruns the Phase 6.2 jail-integrated package build harness
3. creates a minimal Fruix-owned profile transaction layout using those real store outputs
4. installs generation 1 from the Phase 6.1 store item
5. installs generation 2 from the Phase 6.2 store item
6. switches the current `profile` symlink to generation 2
7. validates:
- preserved generation links
- current-profile switching
- `PATH` usability
- execution from a nearly empty environment
## Observed results
Observed metadata included:
- `profile=.../profile`
- `profile_target=profile-2-link`
- `generation1_store_path=/frx/store/...-hello-2.12.3`
- `generation2_store_path=/frx/store/...-hello-2.12.3`
- `current_store_path=/frx/store/...-hello-2.12.3`
- `profile_hello_output=Hello, world!`
- `clean_env_hello_output=Hello, world!`
- `installation_mode=minimal-real-store-profile`
## Important findings
- the current FreeBSD track now has a minimal profile-generation and profile-switching story that operates on real store outputs rather than the earlier Phase 3 package/profile prototype layer
- the profile transaction semantics are intentionally small but real:
- generation 1 is retained
- generation 2 is created
- the `profile` symlink is switched to generation 2
- executables become reachable through `PATH`
- this step intentionally uses a Fruix-owned minimal profile harness because the upstream-derived `guix profiles` / `fruix package` path still runs into the unresolved FreeBSD bootstrap-platform issue:
- `dynamic linker name not known for this system "x86_64-freebsd15.0"`
- even with that upstream profile-layer gap still open, the user-facing package-installation boundary is now validated in minimal form on top of real daemon-built store items
## Conclusion
Phase 6.3 is satisfied on the current FreeBSD prototype track:
- packages built through the real store path can be installed into a profile-like user environment
- generation switching works in a minimal but concrete form
- package execution through the profile succeeds for the current user
- Phase 6 as a whole is now complete on the active FreeBSD prototype path, with deeper upstream profile-layer integration remaining follow-up work rather than a blocker to this milestone

View File

@@ -0,0 +1,73 @@
#include <errno.h>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
static void
usage(const char *argv0)
{
fprintf(stderr, "usage: %s --uid UID --gid GID -- cmd...\n", argv0);
}
static unsigned long
parse_ulong(const char *text)
{
char *end = NULL;
unsigned long value;
errno = 0;
value = strtoul(text, &end, 10);
if (errno != 0 || end == text || *end != '\0')
exit(2);
return value;
}
int
main(int argc, char **argv)
{
uid_t uid = (uid_t)-1;
gid_t gid = (gid_t)-1;
gid_t groups[1];
int i;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--uid") == 0 && i + 1 < argc) {
uid = (uid_t)parse_ulong(argv[++i]);
} else if (strcmp(argv[i], "--gid") == 0 && i + 1 < argc) {
gid = (gid_t)parse_ulong(argv[++i]);
} else if (strcmp(argv[i], "--") == 0) {
i++;
break;
} else {
usage(argv[0]);
return 2;
}
}
if (uid == (uid_t)-1 || gid == (gid_t)-1 || i >= argc) {
usage(argv[0]);
return 2;
}
groups[0] = gid;
if (setgroups(1, groups) != 0) {
perror("setgroups");
return 1;
}
if (setgid(gid) != 0) {
perror("setgid");
return 1;
}
if (setuid(uid) != 0) {
perror("setuid");
return 1;
}
execvp(argv[i], &argv[i]);
perror("execvp");
return 1;
}

View File

@@ -0,0 +1,314 @@
#!/bin/sh
set -eu
repo_root=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd)
metadata_target=${METADATA_OUT:-}
cleanup=0
if [ -n "${WORKDIR:-}" ]; then
workdir=$WORKDIR
mkdir -p "$workdir"
else
workdir=$(mktemp -d /tmp/fruix-phase6-jail-package.XXXXXX)
cleanup=1
fi
if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then
cleanup=0
fi
setup_metadata=$workdir/setup-metadata.txt
setup_env=$workdir/setup-env.sh
metadata_file=$workdir/phase6-jail-package-metadata.txt
daemon_socket=$workdir/guix-daemon.sock
daemon_log=$workdir/guix-daemon.log
fetch_tarball=$workdir/hello-2.12.3.tar.gz
build_stdout=$workdir/fruix-build.out
build_stderr=$workdir/fruix-build.err
drv_stdout=$workdir/fruix-build-derivation.out
references_log=$workdir/references.log
package_template=$workdir/phase6-jail-hello.scm.in
package_file=$workdir/phase6-jail-hello.scm
helper_source=$repo_root/tests/daemon/freebsd-drop-exec.c
daemon_pid=
cleanup_workdir() {
if [ -n "$daemon_pid" ]; then
sudo kill "$daemon_pid" >/dev/null 2>&1 || true
wait "$daemon_pid" 2>/dev/null || true
fi
rm -f "$daemon_socket"
if [ "$cleanup" -eq 1 ]; then
rm -rf "$workdir"
fi
}
trap cleanup_workdir EXIT INT TERM
fetch -o "$fetch_tarball" https://ftp.gnu.org/gnu/hello/hello-2.12.3.tar.gz >/dev/null
[ "$(sha256 -q "$fetch_tarball")" = '0d5f60154382fee10b114a1c34e785d8b1f492073ae2d3a6f7b147687b366aa0' ] || {
echo "unexpected hello tarball hash" >&2
exit 1
}
WORKDIR=$workdir/setup KEEP_WORKDIR=1 \
METADATA_OUT=$setup_metadata ENV_OUT=$setup_env \
"$repo_root/tests/guix/setup-phase5-checkout.sh" >"$workdir/setup.log" 2>&1
# shellcheck disable=SC1090
. "$setup_env"
cd "$PHASE5_BUILDDIR"
export LD_LIBRARY_PATH GUILE_LOAD_PATH GUILE_LOAD_COMPILED_PATH GUILE_EXTENSIONS_PATH
export GUILE_AUTO_COMPILE=0
cat >"$package_template" <<'EOF'
(use-modules (gnu packages base)
(guix packages)
(guix build-system)
(guix store)
(guix monads)
(guix gexp)
(guix derivations))
(define source-file "__SOURCE_FILE__")
(define helper-source-file "__HELPER_SOURCE_FILE__")
(define source-item
(local-file source-file "hello-2.12.3.tar.gz"))
(define helper-source-item
(local-file helper-source-file "freebsd-drop-exec.c"))
(define* (phase6-lower name #:key source inputs native-inputs outputs system target #:allow-other-keys)
(bag
(name name)
(system system)
(target target)
(host-inputs `(,@(if source `(("source" ,source)) '())
("freebsd-drop-exec-source" ,helper-source-item)
,@inputs))
(build-inputs native-inputs)
(outputs outputs)
(build phase6-build)
(arguments `(#:source ,source #:package-name ,name))))
(define* (phase6-build name inputs #:key source (outputs '("out")) (system (%current-system)) #:allow-other-keys)
(mlet* %store-monad ((shell (interned-file "/bin/sh" "sh" #:recursive? #t))
(source* (lower-object source system))
(helper* (lower-object helper-source-item system))
(builder (text-file "phase6-jail-hello-builder.sh"
"#!/bin/sh
set -eu
src_tar=\"$1\"
helper_src=\"$2\"
work_root=\"$TMPDIR/phase6-jail-build\"
root=\"$work_root/jail-root\"
build_dir=\"$work_root/build\"
stage_out=\"$work_root/stage-output\"
helper_dir=\"$work_root/helper-dir\"
helper_bin=\"$helper_dir/freebsd-drop-exec\"
jid=''
cleanup() {
set +e
if [ -n \"$jid\" ]; then /usr/sbin/jail -r \"$jid\" >/dev/null 2>&1 || true; fi
/sbin/umount \"$root/dev\" >/dev/null 2>&1 || true
/sbin/umount \"$root/output\" >/dev/null 2>&1 || true
/sbin/umount \"$root/inputs/hello-2.12.3.tar.gz\" >/dev/null 2>&1 || true
/sbin/umount \"$root/work\" >/dev/null 2>&1 || true
/sbin/umount \"$root/tools\" >/dev/null 2>&1 || true
/sbin/umount \"$root/usr/local/lib\" >/dev/null 2>&1 || true
/sbin/umount \"$root/usr/local/include\" >/dev/null 2>&1 || true
/sbin/umount \"$root/usr/local/bin\" >/dev/null 2>&1 || true
/sbin/umount \"$root/usr/libexec\" >/dev/null 2>&1 || true
/sbin/umount \"$root/usr/libdata\" >/dev/null 2>&1 || true
/sbin/umount \"$root/usr/lib\" >/dev/null 2>&1 || true
/sbin/umount \"$root/usr/include\" >/dev/null 2>&1 || true
/sbin/umount \"$root/usr/bin\" >/dev/null 2>&1 || true
/sbin/umount \"$root/libexec\" >/dev/null 2>&1 || true
/sbin/umount \"$root/lib\" >/dev/null 2>&1 || true
/sbin/umount \"$root/bin\" >/dev/null 2>&1 || true
}
trap cleanup EXIT INT TERM
/bin/mkdir -p \"$root\" \"$build_dir\" \"$stage_out\" \"$helper_dir\"
/usr/bin/cc -Wall -Wextra -std=c11 \"$helper_src\" -o \"$helper_bin\"
/bin/mkdir -p \"$root/tmp\" \"$root/inputs\" \"$root/output\" \"$root/work\" \"$root/tools\" \"$root/etc\" \"$root/dev\" \"$root/usr\" \"$root/usr/local\"
/bin/chmod 1777 \"$root/tmp\"
: > \"$root/inputs/hello-2.12.3.tar.gz\"
printf 'builder:x:35001:35001:builder:/tmp:/bin/sh\\n' > \"$root/etc/passwd\"
printf 'builder:x:35001:\\n' > \"$root/etc/group\"
for p in /bin /lib /libexec /usr/bin /usr/include /usr/lib /usr/libdata /usr/libexec /usr/local/bin /usr/local/include /usr/local/lib; do
/bin/mkdir -p \"$root$p\"
/sbin/mount_nullfs -o ro \"$p\" \"$root$p\"
done
/sbin/mount_nullfs -o ro \"$helper_dir\" \"$root/tools\"
/sbin/mount_nullfs \"$build_dir\" \"$root/work\"
/sbin/mount_nullfs -o ro \"$src_tar\" \"$root/inputs/hello-2.12.3.tar.gz\"
/sbin/mount_nullfs \"$stage_out\" \"$root/output\"
/sbin/mount -t devfs devfs \"$root/dev\"
/usr/sbin/chown 35001:35001 \"$build_dir\" \"$stage_out\"
jail_name=\"fruix-phase6-hello-$$\"
jid=$(/usr/sbin/jail -i -c name=\"$jail_name\" path=\"$root\" host.hostname=\"$jail_name\" persist ip4=disable ip6=disable)
/usr/sbin/jexec \"$jid\" /tools/freebsd-drop-exec --uid 35001 --gid 35001 -- /bin/sh -eu -c '
export HOME=/tmp
export LC_ALL=C
export TMPDIR=/tmp
mkdir -p /work/toolsbin
ln -sf /usr/local/bin/gmake /work/toolsbin/make
export PATH=/work/toolsbin:/bin:/usr/bin:/usr/local/bin
cd /work
/usr/bin/tar -xf /inputs/hello-2.12.3.tar.gz
cd hello-2.12.3
export CC=/usr/bin/cc
export CONFIG_SHELL=/bin/sh
export CPPFLAGS=\"-I/usr/local/include\"
export LDFLAGS=\"-L/usr/local/lib -Wl,-rpath,/usr/local/lib\"
./configure --prefix=/output
/usr/local/bin/gmake -j1
/usr/local/bin/gmake -j1 check
/usr/local/bin/gmake -j1 install
/bin/mkdir -p /output/share/fruix-phase6
/usr/bin/id -u > /output/share/fruix-phase6/build-uid.txt
/usr/bin/id -g > /output/share/fruix-phase6/build-gid.txt
/bin/hostname > /output/share/fruix-phase6/jail-hostname.txt
'
/bin/mkdir -p \"$out\"
/bin/cp -a \"$stage_out/.\" \"$out/\"
/bin/mkdir -p \"$out/share/fruix-phase6\"
/bin/echo \"$src_tar\" > \"$out/share/fruix-phase6/source-store-path.txt\"
/bin/echo freebsd-jail > \"$out/share/fruix-phase6/build-mode.txt\"
"
(list (if (derivation? source*)
(derivation->output-path source*)
source*)
(if (derivation? helper*)
(derivation->output-path helper*)
helper*)))))
(lambda (store)
(values (derivation store name shell
(list "-e" builder
(if (derivation? source*)
(derivation->output-path source*)
source*)
(if (derivation? helper*)
(derivation->output-path helper*)
helper*))
#:env-vars '(("HOME" . "/homeless")
("PATH" . "/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin"))
#:inputs `(,@(if (derivation? source*) `((,source*)) '())
,@(if (derivation? helper*) `((,helper*)) '())
(,shell) (,builder))
#:sources `(,shell ,builder)
#:system system
#:outputs outputs)
store))))
(define phase6-build-system
(build-system
(name 'phase6-freebsd-jail-gnu)
(description "Phase 6 FreeBSD jail GNU build system")
(lower phase6-lower)))
(package/inherit hello
(source source-item)
(build-system phase6-build-system)
(supported-systems (list (%current-system))))
EOF
sed \
-e "s|__SOURCE_FILE__|$fetch_tarball|g" \
-e "s|__HELPER_SOURCE_FILE__|$helper_source|g" \
"$package_template" > "$package_file"
sudo env GUIX_DAEMON_SOCKET=unix://$daemon_socket \
"$PHASE5_GUIX_DAEMON" --disable-chroot --listen "$daemon_socket" --no-substitutes \
>"$daemon_log" 2>&1 &
daemon_pid=$!
for _ in 1 2 3 4 5 6 7 8 9 10; do
[ -S "$daemon_socket" ] && break
sleep 1
done
[ -S "$daemon_socket" ] || {
echo "daemon socket was not created: $daemon_socket" >&2
exit 1
}
GUIX_DAEMON_SOCKET=unix://$daemon_socket \
./pre-inst-env fruix build -d -f "$package_file" >"$drv_stdout" 2>>"$build_stderr"
GUIX_DAEMON_SOCKET=unix://$daemon_socket \
./pre-inst-env fruix build -f "$package_file" >"$build_stdout" 2>>"$build_stderr"
out_path=$(awk 'NF { last = $0 } END { print last }' "$build_stdout")
drv_path=$(awk 'NF { last = $0 } END { print last }' "$drv_stdout")
runtime_output=$("$out_path/bin/hello")
source_store_path=$(tr -d '\n' < "$out_path/share/fruix-phase6/source-store-path.txt")
build_uid=$(tr -d '\n' < "$out_path/share/fruix-phase6/build-uid.txt")
build_gid=$(tr -d '\n' < "$out_path/share/fruix-phase6/build-gid.txt")
jail_hostname=$(tr -d '\n' < "$out_path/share/fruix-phase6/jail-hostname.txt")
build_mode=$(tr -d '\n' < "$out_path/share/fruix-phase6/build-mode.txt")
GUIX_DAEMON_SOCKET=unix://$daemon_socket \
./pre-inst-env fruix gc --references "$out_path" >"$references_log" 2>"$workdir/fruix-gc.err"
[ -n "$drv_path" ] || { echo "missing derivation path in $drv_stdout" >&2; exit 1; }
case "$drv_path" in
/frx/store/*.drv) : ;;
*) echo "unexpected derivation path: $drv_path" >&2; exit 1 ;;
esac
case "$out_path" in
/frx/store/*-hello-2.12.3) : ;;
*) echo "unexpected output path: $out_path" >&2; exit 1 ;;
esac
case "$source_store_path" in
/frx/store/*-hello-2.12.3.tar.gz) : ;;
*) echo "unexpected source store path: $source_store_path" >&2; exit 1 ;;
esac
[ "$runtime_output" = 'Hello, world!' ] || {
echo "unexpected runtime output: $runtime_output" >&2
exit 1
}
[ "$build_uid" = '35001' ] || { echo "unexpected build uid: $build_uid" >&2; exit 1; }
[ "$build_gid" = '35001' ] || { echo "unexpected build gid: $build_gid" >&2; exit 1; }
case "$jail_hostname" in
fruix-phase6-hello-*) : ;;
*) echo "unexpected jail hostname: $jail_hostname" >&2; exit 1 ;;
esac
[ "$build_mode" = 'freebsd-jail' ] || { echo "unexpected build mode: $build_mode" >&2; exit 1; }
grep -Fx "$source_store_path" "$references_log" >/dev/null || {
echo "source store path was not preserved as a reference" >&2
exit 1
}
cat >"$metadata_file" <<EOF
workdir=$workdir
setup_metadata=$setup_metadata
setup_env=$setup_env
phase5_builddir=$PHASE5_BUILDDIR
daemon_socket=$daemon_socket
daemon_log=$daemon_log
fetch_tarball=$fetch_tarball
helper_source=$helper_source
package_file=$package_file
build_stdout=$build_stdout
build_stderr=$build_stderr
drv_stdout=$drv_stdout
references_log=$references_log
drv_path=$drv_path
out_path=$out_path
source_store_path=$source_store_path
runtime_output=$runtime_output
build_uid=$build_uid
build_gid=$build_gid
jail_hostname=$jail_hostname
build_mode=$build_mode
frontend_invocation=./pre-inst-env fruix build -f $package_file
EOF
if [ -n "$metadata_target" ]; then
mkdir -p "$(dirname "$metadata_target")"
cp "$metadata_file" "$metadata_target"
fi
printf 'PASS phase6-jail-package-build\n'
printf 'Work directory: %s\n' "$workdir"
printf 'Metadata file: %s\n' "$metadata_file"
if [ -n "$metadata_target" ]; then
printf 'Copied metadata to: %s\n' "$metadata_target"
fi
printf '%s\n' '--- metadata ---'
cat "$metadata_file"

View File

@@ -0,0 +1,220 @@
#!/bin/sh
set -eu
repo_root=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd)
metadata_target=${METADATA_OUT:-}
cleanup=0
if [ -n "${WORKDIR:-}" ]; then
workdir=$WORKDIR
mkdir -p "$workdir"
else
workdir=$(mktemp -d /tmp/fruix-phase6-real-package.XXXXXX)
cleanup=1
fi
if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then
cleanup=0
fi
setup_metadata=$workdir/setup-metadata.txt
setup_env=$workdir/setup-env.sh
metadata_file=$workdir/phase6-real-package-metadata.txt
daemon_socket=$workdir/guix-daemon.sock
daemon_log=$workdir/guix-daemon.log
fetch_tarball=$workdir/hello-2.12.3.tar.gz
build_stdout=$workdir/fruix-build.out
build_stderr=$workdir/fruix-build.err
drv_stdout=$workdir/fruix-build-derivation.out
references_log=$workdir/references.log
package_template=$workdir/phase6-hello.scm.in
package_file=$workdir/phase6-hello.scm
daemon_pid=
cleanup_workdir() {
if [ -n "$daemon_pid" ]; then
sudo kill "$daemon_pid" >/dev/null 2>&1 || true
wait "$daemon_pid" 2>/dev/null || true
fi
rm -f "$daemon_socket"
if [ "$cleanup" -eq 1 ]; then
rm -rf "$workdir"
fi
}
trap cleanup_workdir EXIT INT TERM
fetch -o "$fetch_tarball" https://ftp.gnu.org/gnu/hello/hello-2.12.3.tar.gz >/dev/null
[ "$(sha256 -q "$fetch_tarball")" = '0d5f60154382fee10b114a1c34e785d8b1f492073ae2d3a6f7b147687b366aa0' ] || {
echo "unexpected hello tarball hash" >&2
exit 1
}
WORKDIR=$workdir/setup KEEP_WORKDIR=1 \
METADATA_OUT=$setup_metadata ENV_OUT=$setup_env \
"$repo_root/tests/guix/setup-phase5-checkout.sh" >"$workdir/setup.log" 2>&1
# shellcheck disable=SC1090
. "$setup_env"
cd "$PHASE5_BUILDDIR"
export LD_LIBRARY_PATH GUILE_LOAD_PATH GUILE_LOAD_COMPILED_PATH GUILE_EXTENSIONS_PATH
export GUILE_AUTO_COMPILE=0
cat >"$package_template" <<'EOF'
(use-modules (gnu packages base)
(guix packages)
(guix build-system)
(guix store)
(guix monads)
(guix gexp)
(guix derivations))
(define source-file "__SOURCE_FILE__")
(define source-item
(local-file source-file "hello-2.12.3.tar.gz"))
(define* (phase6-lower name #:key source inputs native-inputs outputs system target #:allow-other-keys)
(bag
(name name)
(system system)
(target target)
(host-inputs `(,@(if source `(("source" ,source)) '()) ,@inputs))
(build-inputs native-inputs)
(outputs outputs)
(build phase6-build)
(arguments `(#:source ,source #:package-name ,name))))
(define* (phase6-build name inputs #:key source (outputs '("out")) (system (%current-system)) #:allow-other-keys)
(mlet* %store-monad ((shell (interned-file "/bin/sh" "sh" #:recursive? #t))
(source* (lower-object source system))
(builder (text-file "phase6-hello-builder.sh"
"#!/bin/sh
set -eu
export PATH=/bin:/usr/bin:/usr/local/bin
src_tar=\"$1\"
/bin/mkdir -p \"$TMPDIR/phase6-build\"
cd \"$TMPDIR/phase6-build\"
/usr/bin/tar -xf \"$src_tar\"
cd hello-2.12.3
export CC=/usr/bin/cc
export CONFIG_SHELL=/bin/sh
export CPPFLAGS='-I/usr/local/include'
export LDFLAGS='-L/usr/local/lib -Wl,-rpath,/usr/local/lib'
./configure --prefix=\"$out\"
/usr/local/bin/gmake -j1
/usr/local/bin/gmake -j1 check
/usr/local/bin/gmake -j1 install
/bin/mkdir -p \"$out/share/fruix-phase6\"
printf '%s\\n' \"$src_tar\" > \"$out/share/fruix-phase6/source-store-path.txt\"
"
(list (if (derivation? source*)
(derivation->output-path source*)
source*)))))
(lambda (store)
(values (derivation store name shell
(list "-e" builder
(if (derivation? source*)
(derivation->output-path source*)
source*))
#:env-vars '(("HOME" . "/homeless")
("PATH" . "/bin:/usr/bin:/usr/local/bin"))
#:inputs `(,@(if (derivation? source*) `((,source*)) '())
(,shell) (,builder))
#:sources `(,shell ,builder)
#:system system
#:outputs outputs)
store))))
(define phase6-build-system
(build-system
(name 'phase6-freebsd-host-gnu)
(description "Phase 6 FreeBSD host GNU build system")
(lower phase6-lower)))
(package/inherit hello
(source source-item)
(build-system phase6-build-system)
(supported-systems (list (%current-system))))
EOF
sed "s|__SOURCE_FILE__|$fetch_tarball|g" "$package_template" > "$package_file"
sudo env GUIX_DAEMON_SOCKET=unix://$daemon_socket \
"$PHASE5_GUIX_DAEMON" --disable-chroot --listen "$daemon_socket" --no-substitutes \
>"$daemon_log" 2>&1 &
daemon_pid=$!
for _ in 1 2 3 4 5 6 7 8 9 10; do
[ -S "$daemon_socket" ] && break
sleep 1
done
[ -S "$daemon_socket" ] || {
echo "daemon socket was not created: $daemon_socket" >&2
exit 1
}
GUIX_DAEMON_SOCKET=unix://$daemon_socket \
./pre-inst-env fruix build -d -f "$package_file" >"$drv_stdout" 2>>"$build_stderr"
GUIX_DAEMON_SOCKET=unix://$daemon_socket \
./pre-inst-env fruix build -f "$package_file" >"$build_stdout" 2>>"$build_stderr"
out_path=$(awk 'NF { last = $0 } END { print last }' "$build_stdout")
drv_path=$(awk 'NF { last = $0 } END { print last }' "$drv_stdout")
source_store_path=$(tr -d '\n' < "$out_path/share/fruix-phase6/source-store-path.txt")
runtime_output=$("$out_path/bin/hello")
GUIX_DAEMON_SOCKET=unix://$daemon_socket \
./pre-inst-env fruix gc --references "$out_path" >"$references_log" 2>"$workdir/fruix-gc.err"
[ -n "$drv_path" ] || { echo "missing derivation path in $drv_stdout" >&2; exit 1; }
case "$drv_path" in
/frx/store/*.drv) : ;;
*) echo "unexpected derivation path: $drv_path" >&2; exit 1 ;;
esac
case "$out_path" in
/frx/store/*-hello-2.12.3) : ;;
*) echo "unexpected output path: $out_path" >&2; exit 1 ;;
esac
case "$source_store_path" in
/frx/store/*-hello-2.12.3.tar.gz) : ;;
*) echo "unexpected source store path: $source_store_path" >&2; exit 1 ;;
esac
[ "$runtime_output" = 'Hello, world!' ] || {
echo "unexpected runtime output: $runtime_output" >&2
exit 1
}
grep -Fx "$source_store_path" "$references_log" >/dev/null || {
echo "source store path was not preserved as a reference" >&2
exit 1
}
cat >"$metadata_file" <<EOF
workdir=$workdir
setup_metadata=$setup_metadata
setup_env=$setup_env
phase5_builddir=$PHASE5_BUILDDIR
daemon_socket=$daemon_socket
daemon_log=$daemon_log
fetch_tarball=$fetch_tarball
package_file=$package_file
build_stdout=$build_stdout
build_stderr=$build_stderr
drv_stdout=$drv_stdout
references_log=$references_log
drv_path=$drv_path
out_path=$out_path
source_store_path=$source_store_path
runtime_output=$runtime_output
frontend_invocation=./pre-inst-env fruix build -f $package_file
EOF
if [ -n "$metadata_target" ]; then
mkdir -p "$(dirname "$metadata_target")"
cp "$metadata_file" "$metadata_target"
fi
printf 'PASS phase6-real-package-build\n'
printf 'Work directory: %s\n' "$workdir"
printf 'Metadata file: %s\n' "$metadata_file"
if [ -n "$metadata_target" ]; then
printf 'Copied metadata to: %s\n' "$metadata_target"
fi
printf '%s\n' '--- metadata ---'
cat "$metadata_file"

View File

@@ -0,0 +1,144 @@
#!/bin/sh
set -eu
repo_root=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd)
metadata_target=${METADATA_OUT:-}
cleanup=0
if [ -n "${WORKDIR:-}" ]; then
workdir=$WORKDIR
mkdir -p "$workdir"
else
workdir=$(mktemp -d /tmp/fruix-phase6-profile.XXXXXX)
cleanup=1
fi
if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then
cleanup=0
fi
metadata_file=$workdir/phase6-real-store-profile-metadata.txt
phase61_metadata=$workdir/phase6-real-package-metadata.txt
phase62_metadata=$workdir/phase6-jail-package-metadata.txt
profile=$workdir/profile
phase61_log=$workdir/phase6-real-package.log
phase62_log=$workdir/phase6-jail-package.log
cleanup_workdir() {
if [ "$cleanup" -eq 1 ]; then
rm -rf "$workdir"
fi
}
trap cleanup_workdir EXIT INT TERM
install_generation() {
generation=$1
store_path=$2
label=$3
generation_dir=$workdir/profile-generation-$generation
generation_link=$profile-$generation-link
rm -rf "$generation_dir"
mkdir -p "$generation_dir"
for entry in "$store_path"/*; do
[ -e "$entry" ] || continue
ln -s "$entry" "$generation_dir/$(basename "$entry")"
done
cat >"$generation_dir/.fruix-profile-entry" <<EOF
label=$label
store_path=$store_path
generation=$generation
EOF
rm -f "$generation_link.new" "$generation_link"
ln -s "$generation_dir" "$generation_link.new"
mv -f "$generation_link.new" "$generation_link"
rm -f "$profile"
ln -s "$(basename "$generation_link")" "$profile"
}
METADATA_OUT=$phase61_metadata WORKDIR=$workdir/phase6-61 KEEP_WORKDIR=1 \
"$repo_root/tests/guix/run-phase6-real-package-build.sh" >"$phase61_log" 2>&1
METADATA_OUT=$phase62_metadata WORKDIR=$workdir/phase6-62 KEEP_WORKDIR=1 \
"$repo_root/tests/guix/run-phase6-jail-package-build.sh" >"$phase62_log" 2>&1
phase61_out=$(sed -n 's/^out_path=//p' "$phase61_metadata")
phase62_out=$(sed -n 's/^out_path=//p' "$phase62_metadata")
phase61_runtime=$(sed -n 's/^runtime_output=//p' "$phase61_metadata")
phase62_runtime=$(sed -n 's/^runtime_output=//p' "$phase62_metadata")
[ "$phase61_runtime" = 'Hello, world!' ] || {
echo "phase6.1 prerequisite failed: $phase61_runtime" >&2
exit 1
}
[ "$phase62_runtime" = 'Hello, world!' ] || {
echo "phase6.2 prerequisite failed: $phase62_runtime" >&2
exit 1
}
install_generation 1 "$phase61_out" phase6-real-package
install_generation 2 "$phase62_out" phase6-jail-package
profile_target=$(readlink "$profile")
generation1_target=$(readlink "$profile-1-link")
generation2_target=$(readlink "$profile-2-link")
current_bin_target=$(readlink "$profile/bin")
current_store_path=$(dirname "$current_bin_target")
profile_hello_output=$(PATH="$profile/bin:/bin:/usr/bin" hello)
clean_env_hello_output=$(env -i PATH="$profile/bin:/bin:/usr/bin" HOME="$workdir/home" USER="${USER:-self}" LOGNAME="${LOGNAME:-self}" "$profile/bin/hello")
user_uid=$(id -u)
user_name=$(id -un)
[ "$profile_target" = 'profile-2-link' ] || {
echo "unexpected current profile target: $profile_target" >&2
exit 1
}
[ "$current_store_path" = "$phase62_out" ] || {
echo "profile does not point at the expected current store path" >&2
exit 1
}
[ "$profile_hello_output" = 'Hello, world!' ] || {
echo "unexpected profile hello output: $profile_hello_output" >&2
exit 1
}
[ "$clean_env_hello_output" = 'Hello, world!' ] || {
echo "unexpected clean-env hello output: $clean_env_hello_output" >&2
exit 1
}
cat >"$metadata_file" <<EOF
workdir=$workdir
phase61_metadata=$phase61_metadata
phase62_metadata=$phase62_metadata
phase61_log=$phase61_log
phase62_log=$phase62_log
profile=$profile
profile_target=$profile_target
generation1_link=$profile-1-link
generation1_target=$generation1_target
generation1_store_path=$phase61_out
generation2_link=$profile-2-link
generation2_target=$generation2_target
generation2_store_path=$phase62_out
current_bin_target=$current_bin_target
current_store_path=$current_store_path
profile_hello_output=$profile_hello_output
clean_env_hello_output=$clean_env_hello_output
user_uid=$user_uid
user_name=$user_name
installation_mode=minimal-real-store-profile
EOF
if [ -n "$metadata_target" ]; then
mkdir -p "$(dirname "$metadata_target")"
cp "$metadata_file" "$metadata_target"
fi
printf 'PASS phase6-real-store-profile\n'
printf 'Work directory: %s\n' "$workdir"
printf 'Metadata file: %s\n' "$metadata_file"
if [ -n "$metadata_target" ]; then
printf 'Copied metadata to: %s\n' "$metadata_target"
fi
printf '%s\n' '--- metadata ---'
cat "$metadata_file"