Created
July 11, 2026 15:03
-
-
Save quinnjr/f9d0bea41b21c61dbed373911b93ba71 to your computer and use it in GitHub Desktop.
Headless FreeBSD VM in VirtualBox: setup + cargo:libsecret provider verification (rust-lang/cargo#17197)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # 01-freebsd-vm-create.sh — create a headless FreeBSD VM in VirtualBox from the | |
| # official pre-installed VM image, and bootstrap passwordless root SSH into it. | |
| # | |
| # Host requirements: VirtualBox (VBoxManage), curl, xz, ssh-keygen. | |
| # Everything is driven from the host shell; no VirtualBox GUI needed. | |
| # | |
| # Usage: ./01-freebsd-vm-create.sh | |
| set -euo pipefail | |
| VM_NAME="FreeBSD-15.1" | |
| RELEASE="15.1-RELEASE" | |
| ARCH="amd64" | |
| SSH_PORT=2222 | |
| SSH_KEY="$HOME/.ssh/freebsd-vm" | |
| VM_DIR="$HOME/VirtualBox VMs/$VM_NAME" | |
| IMAGE="FreeBSD-${RELEASE}-${ARCH}-ufs.vmdk" | |
| BASE_URL="https://download.freebsd.org/releases/VM-IMAGES/${RELEASE}/${ARCH}/Latest" | |
| # --- 1. Download the official VM image and verify its checksum --------------- | |
| mkdir -p "$VM_DIR" | |
| cd "$VM_DIR" | |
| [ -f CHECKSUM.SHA256 ] || curl -O "$BASE_URL/CHECKSUM.SHA256" | |
| [ -f "$IMAGE.xz" ] || [ -f "$VM_NAME.vdi" ] || curl -O "$BASE_URL/$IMAGE.xz" | |
| if [ -f "$IMAGE.xz" ]; then | |
| # The checksum file is in BSD format; reshape it for sha256sum. | |
| grep "$IMAGE.xz" CHECKSUM.SHA256 \ | |
| | sed 's/SHA256 (\(.*\)) = \(.*\)/\2 \1/' | sha256sum -c - | |
| unxz -T0 "$IMAGE.xz" | |
| fi | |
| # --- 2. Create and configure the VM ------------------------------------------ | |
| VBoxManage createvm --name "$VM_NAME" --ostype FreeBSD_64 --register | |
| VBoxManage modifyvm "$VM_NAME" --memory 4096 --cpus 4 --nic1 nat \ | |
| --graphicscontroller vmsvga --vram 16 --audio-driver none --usb off --boot1 disk | |
| VBoxManage storagectl "$VM_NAME" --name SATA --add sata --controller IntelAhci --portcount 2 | |
| # --- 3. Convert VMDK -> VDI and grow it (FreeBSD growfs expands on first boot) | |
| VBoxManage clonemedium disk "$IMAGE" "$VM_NAME.vdi" --format VDI | |
| VBoxManage modifymedium disk "$VM_NAME.vdi" --resize 20480 | |
| VBoxManage storageattach "$VM_NAME" --storagectl SATA --port 0 --device 0 \ | |
| --type hdd --medium "$VM_NAME.vdi" | |
| VBoxManage closemedium disk "$IMAGE" | |
| rm -f "$IMAGE" | |
| # --- 4. SSH port-forward and headless boot ------------------------------------ | |
| VBoxManage modifyvm "$VM_NAME" --natpf1 "ssh,tcp,127.0.0.1,${SSH_PORT},,22" | |
| VBoxManage startvm "$VM_NAME" --type headless | |
| echo "Waiting 75s for first boot (growfs + login prompt)..." | |
| sleep 75 | |
| # --- 5. Bootstrap SSH via console keystrokes ---------------------------------- | |
| # The official image has root with an EMPTY password and no sshd. | |
| # NOTE: the key must be passphrase-less or non-interactive SSH breaks. | |
| [ -f "$SSH_KEY" ] || ssh-keygen -t ed25519 -N '' -C freebsd-vm -f "$SSH_KEY" -q | |
| PUB=$(cat "$SSH_KEY.pub") | |
| type_line() { VBoxManage controlvm "$VM_NAME" keyboardputstring "$1 | |
| "; sleep 2; } | |
| type_line "root" | |
| type_line "mkdir -p /root/.ssh && echo '$PUB' > /root/.ssh/authorized_keys && chmod 600 /root/.ssh/authorized_keys" | |
| # PerSourcePenalties: FreeBSD 15's OpenSSH temporarily bans sources whose early | |
| # connection attempts fail (e.g. while host keys generate) with the error | |
| # "Not allowed at this time" — disable it up front. | |
| type_line "sysrc sshd_enable=YES && echo 'PermitRootLogin prohibit-password' >> /etc/ssh/sshd_config && echo 'PerSourcePenalties no' >> /etc/ssh/sshd_config && service sshd start" | |
| # --- 6. Wait for SSH ---------------------------------------------------------- | |
| echo "Waiting for SSH..." | |
| for _ in $(seq 1 30); do | |
| if ssh -p "$SSH_PORT" -i "$SSH_KEY" -o IdentitiesOnly=yes -o BatchMode=yes \ | |
| -o StrictHostKeyChecking=accept-new -o ConnectTimeout=3 \ | |
| root@127.0.0.1 'freebsd-version' 2>/dev/null; then | |
| echo "VM ready: ssh -p $SSH_PORT -i $SSH_KEY root@127.0.0.1" | |
| exit 0 | |
| fi | |
| sleep 5 | |
| done | |
| echo "SSH did not come up; check the console:" >&2 | |
| echo " VBoxManage controlvm $VM_NAME screenshotpng /tmp/console.png" >&2 | |
| exit 1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # 02-freebsd-vm-provision.sh — install the keyring test stack in the FreeBSD VM | |
| # and smoke-test libsecret -> D-Bus -> gnome-keyring before any Rust code runs. | |
| # | |
| # Usage: ./02-freebsd-vm-provision.sh | |
| set -euo pipefail | |
| SSH_PORT=2222 | |
| SSH_KEY="$HOME/.ssh/freebsd-vm" | |
| SSH=(ssh -p "$SSH_PORT" -i "$SSH_KEY" -o IdentitiesOnly=yes -o BatchMode=yes root@127.0.0.1) | |
| # --- 1. Install packages ------------------------------------------------------ | |
| # rust: may lag the cargo repo's MSRV; build with --ignore-rust-version then. | |
| "${SSH[@]}" 'env ASSUME_ALWAYS_YES=yes pkg install -y \ | |
| rust git-lite libsecret gnome-keyring dbus pkgconf' | |
| # --- 2. Smoke-test the Secret Service stack ----------------------------------- | |
| # The Secret Service needs a D-Bus session bus and an unlocked keyring; neither | |
| # survives a new SSH session, so tests always run inside one wrapper shell. | |
| # Skipping this setup fails with "Cannot autolaunch D-Bus without X11 $DISPLAY". | |
| "${SSH[@]}" 'sh -s' <<'EOF' | |
| set -e | |
| sysrc dbus_enable=YES >/dev/null | |
| service dbus onestatus >/dev/null 2>&1 || service dbus onestart | |
| dbus-uuidgen --ensure | |
| export $(dbus-launch) | |
| eval "$(printf 'vmtest' | gnome-keyring-daemon --unlock --components=secrets | sed 's/^/export /')" | |
| printf 'hunter2' | secret-tool store --label=smoke smoke test | |
| [ "$(secret-tool lookup smoke test)" = "hunter2" ] | |
| secret-tool clear smoke test | |
| echo "SECRET_SERVICE_OK: libsecret -> D-Bus -> gnome-keyring round-trip works" | |
| EOF |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # 03-test-cargo-libsecret.sh — verify the cargo:libsecret credential provider on | |
| # FreeBSD, as done for https://github.com/rust-lang/cargo/pull/17197. | |
| # | |
| # Clones the PR branch inside the VM, builds a small harness that drives the | |
| # provider's Credential trait directly, and runs the full token lifecycle | |
| # (login -> get -> logout -> get) against gnome-keyring via the Secret Service. | |
| # | |
| # Usage: ./03-test-cargo-libsecret.sh [git-url] [branch] | |
| set -euo pipefail | |
| REPO_URL="${1:-https://github.com/quinnjr/cargo.git}" # after merge: rust-lang/cargo.git | |
| BRANCH="${2:-libsecret-bsd-support}" # after merge: master | |
| SSH_PORT=2222 | |
| SSH_KEY="$HOME/.ssh/freebsd-vm" | |
| SSH=(ssh -p "$SSH_PORT" -i "$SSH_KEY" -o IdentitiesOnly=yes -o BatchMode=yes root@127.0.0.1) | |
| # --- 1. Clone the branch in the VM -------------------------------------------- | |
| "${SSH[@]}" "[ -d /root/cargo ] || git clone --depth 1 --branch '$BRANCH' '$REPO_URL' /root/cargo" | |
| # --- 2. Create the test harness ------------------------------------------------ | |
| # The provider is a library crate; this driver exercises the Credential trait | |
| # directly via path dependencies into the clone. | |
| "${SSH[@]}" 'mkdir -p /root/libsecret-test/src && cat > /root/libsecret-test/Cargo.toml' <<'EOF' | |
| [package] | |
| name = "libsecret-test" | |
| version = "0.1.0" | |
| edition = "2021" | |
| [dependencies] | |
| cargo-credential = { path = "/root/cargo/credential/cargo-credential" } | |
| cargo-credential-libsecret = { path = "/root/cargo/credential/cargo-credential-libsecret" } | |
| EOF | |
| "${SSH[@]}" 'cat > /root/libsecret-test/src/main.rs' <<'EOF' | |
| use cargo_credential::{ | |
| Action, Credential, CredentialResponse, LoginOptions, Operation, RegistryInfo, Secret, | |
| }; | |
| use cargo_credential_libsecret::LibSecretCredential; | |
| fn main() { | |
| let cred = LibSecretCredential::new().expect("failed to load libsecret"); | |
| // The Credential impl is on `&LibSecretCredential`, so take a reference. | |
| let cred = &cred; | |
| println!("NEW: libsecret loaded via dlopen on {}", std::env::consts::OS); | |
| let reg = RegistryInfo { | |
| index_url: "https://bsd-test.invalid/index", | |
| name: Some("bsd-test"), | |
| headers: vec![], | |
| }; | |
| let token = "cargo-bsd-test-token-12345"; | |
| cred.perform( | |
| ®, | |
| &Action::Login(LoginOptions { | |
| token: Some(Secret::from(token)), | |
| login_url: None, | |
| }), | |
| &[], | |
| ) | |
| .expect("login failed"); | |
| println!("LOGIN: token stored in secret service"); | |
| match cred | |
| .perform(®, &Action::Get(Operation::Read), &[]) | |
| .expect("get failed") | |
| { | |
| CredentialResponse::Get { token: t, .. } => { | |
| assert_eq!(t.expose(), token, "retrieved token does not match"); | |
| println!("GET: retrieved token matches"); | |
| } | |
| other => panic!("unexpected response: {other:?}"), | |
| } | |
| cred.perform(®, &Action::Logout, &[]).expect("logout failed"); | |
| println!("LOGOUT: token removed"); | |
| match cred.perform(®, &Action::Get(Operation::Read), &[]) { | |
| Err(e) => println!("GET-AFTER-LOGOUT: correctly absent ({e})"), | |
| Ok(_) => panic!("token still present after logout"), | |
| } | |
| println!("ALL LIBSECRET PROVIDER TESTS PASSED"); | |
| } | |
| EOF | |
| # --- 3. Build and run inside a D-Bus/keyring session --------------------------- | |
| # --ignore-rust-version: FreeBSD's packaged Rust may lag the crate's MSRV. | |
| # Watch for the "Compiling" lines — a pass against a stale binary proves nothing. | |
| "${SSH[@]}" 'sh -s' <<'EOF' | |
| set -e | |
| export $(dbus-launch) | |
| eval "$(printf 'vmtest' | gnome-keyring-daemon --unlock --components=secrets | sed 's/^/export /')" | |
| cd /root/libsecret-test | |
| cargo build --ignore-rust-version | |
| ./target/debug/libsecret-test | |
| EOF | |
| cat <<'DONE' | |
| Expected output ends with: | |
| ALL LIBSECRET PROVIDER TESTS PASSED | |
| The five test lines prove: dlopen of libsecret-1.so.0 works on FreeBSD, and | |
| Login/Get/Logout round-trip through the Secret Service, with a correct | |
| not-found error once the token is gone. | |
| DONE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment