Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions nix/test-guest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,9 @@ Configurations are Ansible playbooks stored under `nix/test-guest/configuration/
Configurations run in the order provided on the command line. OpenShell packages and copied files are installed after all configurations succeed.

`--install` packages and `--copy` files are applied by a dedicated per-run
Ansible playbook. `--copy` preserves each source file's ordinary permission
bits. They are not stored in prepared VM cache entries.
transfer step. `--copy` preserves each source file's ordinary permission bits
unless an octal mode is supplied. They are not stored in prepared VM cache
entries.

## System provisioners

Expand Down Expand Up @@ -319,13 +320,14 @@ For an x86_64 Linux guest, supply x86_64 binaries and use `package:deb:amd64`. T

## Copy files directly

Use `--copy SOURCE:DEST` to copy a regular file without creating a package. The
guest file preserves the source's ordinary permission bits:
Use `--copy SOURCE:DEST[:MODE]` to copy a regular file without creating a
package. If `MODE` is omitted, the guest file preserves the source's ordinary
permission bits. Supply a bare octal mode such as `755` to override them:

```shell
nix run .#test-guest -- \
--distro ubuntu-24-04 \
--copy ./openshell:/usr/local/bin/openshell \
--copy ./openshell:/usr/local/bin/openshell:755 \
-- openshell --version
```

Expand All @@ -352,16 +354,18 @@ runner prints their location after shutdown. The final `30` accepts automatic
recovery for up to 30 seconds; omit it to require the canary's immediate check.


The destination must be an absolute guest path. Copied files are installed with mode `0755`.
The destination must be an absolute guest path. Use bare octal permission bits
from `000` through `777` for explicit modes.

## Runner options

```text
--distro NAME Base distro: ubuntu-24-04, ubuntu-26-04, centos, fedora, or rocky
--with NAME Apply docker, podman-rootless, selinux, or snapd; repeatable
--install PATH Install a .deb or .rpm package; repeatable
--copy SRC:DEST Copy a regular file into the guest, preserving its host mode;
repeatable
--copy SRC:DEST[:MODE]
Copy a regular file into the guest; use MODE when provided,
otherwise preserve the host mode; repeatable
--ssh-port PORT Use a specific loopback SSH forwarding port
--forward-port HOST_PORT:GUEST_PORT
Forward a loopback host port to a guest port; repeatable
Expand Down
22 changes: 16 additions & 6 deletions nix/test-guest/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ Options:
--with NAME Apply a configuration; repeatable (docker, podman-rootless, selinux, snapd)
--provision NAME Apply a post-artifact system provisioner; repeatable
--install PATH Install a .deb or .rpm package; repeatable
--copy SRC:DEST Copy a regular file to an absolute guest path, preserving
its host mode; repeatable
--copy SRC:DEST[:MODE]
Copy a regular file to an absolute guest path, using MODE
when provided, otherwise preserving its host mode; repeatable
--ssh-port PORT Use a specific loopback SSH forwarding port
--forward-port HOST_PORT:GUEST_PORT
Forward a loopback host port to a guest port; repeatable
Expand Down Expand Up @@ -268,13 +269,16 @@ packages=("${resolved_packages[@]}")
resolved_copies=()
for copy_spec in "${copies[@]}"; do
source_path=${copy_spec%%:*}
destination=${copy_spec#*:}
if [ "${source_path}" = "${copy_spec}" ] ||
! source_path=$(realpath -- "${source_path}") ||
[ ! -f "${source_path}" ]; then
echo "invalid --copy source: ${copy_spec}" >&2
exit 2
fi
copy_remainder=${copy_spec#*:}
destination=${copy_remainder%%:*}
mode_spec=${copy_remainder#"${destination}"}
mode_spec=${mode_spec#:}
case "${destination}" in
/*)
if [[ ${destination} == *"/../"* ]] || [[ ${destination} == */.. ]]; then
Expand All @@ -291,7 +295,12 @@ for copy_spec in "${copies[@]}"; do
exit 2
;;
esac
resolved_copies+=("${source_path}:${destination}")
if [ -n "${mode_spec}" ]; then
mode=${mode_spec}
else
mode=$(preserved_file_mode "${source_path}") || exit 2
fi
resolved_copies+=("${source_path}:${destination}:${mode}")
done
copies=("${resolved_copies[@]}")

Expand Down Expand Up @@ -662,8 +671,9 @@ if [ "${#packages[@]}" -gt 0 ] || [ "${#copies[@]}" -gt 0 ]; then
artifact_index=0
for copy_spec in "${copies[@]}"; do
source_path=${copy_spec%%:*}
destination=${copy_spec#*:}
mode=$(preserved_file_mode "${source_path}") || exit 2
copy_remainder=${copy_spec#*:}
destination=${copy_remainder%%:*}
mode=${copy_remainder#*:}
remote_path=${artifact_staging_dir}/copy-${artifact_index}
echo "==> Copying artifact: ${destination}"
scp -q "${scp_args[@]}" \
Expand Down
Loading