mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-13 12:30:59 +01:00
vmbox: share host repos by bind mount, not symlink
9p exports a directory TREE and does not follow a symlink pointing out of it. The share directory held `testsAndMisc -> /home/kuhy/testsAndMisc`, so the guest mounted /mnt/hostrepo successfully, listed the symlink, and then got "No such file or directory" following it -- the target path does not exist inside the guest. Measured in a live sandbox, not assumed. `vm share <path>` now bind-mounts the directory into the share and remounts it read-only, so the guest sees real contents while still being unable to write to the host copy. `vm unshare <name>` reverses it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdyMBGCrGVGDWtJ9xe48f3
This commit is contained in:
parent
60571adb40
commit
a18e0da3a9
@ -22,6 +22,8 @@ Usage: vm <command> [args]
|
||||
new <name> [--rtc <ts>] Create a sandbox (instant; thin overlay)
|
||||
run <name> <command...> Run a command in the sandbox, report the verdict
|
||||
ssh <name> [args...] Interactive shell in the sandbox
|
||||
share <host-path> Expose a host dir to sandboxes (read-only bind)
|
||||
unshare <name> Stop exposing it
|
||||
repo <name> <path> [--worktree]
|
||||
Copy a host repo in (clone=HEAD, --worktree=uncommitted)
|
||||
screenshot <name> [out.png] Capture the guest screen (for locker tests)
|
||||
@ -78,6 +80,8 @@ main() {
|
||||
ssh) source "$VMBOX_LIB_DIR/ssh.sh"; vm_ssh_interactive "$@" ;;
|
||||
screenshot) source "$VMBOX_LIB_DIR/screenshot.sh"; vm_screenshot "$@" ;;
|
||||
repo) source "$VMBOX_LIB_DIR/repo.sh"; cmd_repo "$@" ;;
|
||||
share) source "$VMBOX_LIB_DIR/repo.sh"; repo_share "$@" ;;
|
||||
unshare) source "$VMBOX_LIB_DIR/repo.sh"; repo_unshare "$@" ;;
|
||||
list|ls) cmd_list ;;
|
||||
-h|--help|help|'') usage ;;
|
||||
*) die "unknown command '$cmd' (try: vm --help)" ;;
|
||||
|
||||
@ -33,7 +33,10 @@ launch_vm() {
|
||||
serial_n="$(vm_next_serial "$name")"
|
||||
serial="$(vm_serial "$name" "$serial_n")"
|
||||
qmp="$(vm_qmp_sock "$name")"
|
||||
# Symlink the repos you want testable into here; nothing else is exposed.
|
||||
# Repos you want testable go here. Use `vm share <path>` -- it BIND-MOUNTS
|
||||
# rather than symlinks, because 9p exports a directory tree and will not
|
||||
# follow a symlink pointing outside it (the guest would see a dangling
|
||||
# link). Nothing outside this directory is ever exposed.
|
||||
share="${VMBOX_SHARE:-$VMBOX_HOME/share}"
|
||||
install -d -m 755 "$share"
|
||||
|
||||
|
||||
@ -17,6 +17,41 @@ source "$(dirname "${BASH_SOURCE[0]}")/ssh.sh"
|
||||
|
||||
readonly GUEST_MOUNT="/mnt/hostrepo"
|
||||
|
||||
# Expose a host directory to sandboxes. Bind-mount rather than symlink: 9p
|
||||
# exports a directory TREE and does not follow links out of it, so a symlinked
|
||||
# repo appears in the guest as a dangling link (measured, not assumed).
|
||||
# The bind is read-only, so the guest cannot write to the real repo.
|
||||
repo_share() {
|
||||
local src="${1:-}" name share
|
||||
[[ -n "$src" ]] || die "usage: vm share <host-path>"
|
||||
[[ -d "$src" ]] || die "no such directory: $src"
|
||||
src="$(realpath "$src")"
|
||||
name="$(basename "$src")"
|
||||
share="${VMBOX_SHARE:-$VMBOX_HOME/share}"
|
||||
install -d -m 755 "$share/$name"
|
||||
|
||||
if mountpoint -q "$share/$name"; then
|
||||
ok "$name is already shared"
|
||||
return 0
|
||||
fi
|
||||
# A read-only bind needs two steps: mount, then remount ro.
|
||||
sudo mount --bind "$src" "$share/$name" ||
|
||||
die "bind mount failed (needs sudo once per boot)"
|
||||
sudo mount -o remount,ro,bind "$share/$name" ||
|
||||
warn "could not remount read-only -- the guest mount is still ro via 9p"
|
||||
ok "shared $src -> sandboxes see it at $GUEST_MOUNT/$name (read-only)"
|
||||
}
|
||||
|
||||
repo_unshare() {
|
||||
local name="${1:-}" share
|
||||
share="${VMBOX_SHARE:-$VMBOX_HOME/share}"
|
||||
[[ -n "$name" ]] || die "usage: vm unshare <name>"
|
||||
mountpoint -q "$share/$name" || { ok "$name is not shared"; return 0; }
|
||||
sudo umount "$share/$name" || die "umount failed"
|
||||
rmdir "$share/$name" 2>/dev/null || true
|
||||
ok "unshared $name"
|
||||
}
|
||||
|
||||
# $1 vm name, $2 host repo path, $3 mode (clone|worktree)
|
||||
repo_sync() {
|
||||
local name="$1" src="$2" mode="${3:-clone}" repo_name
|
||||
|
||||
Loading…
Reference in New Issue
Block a user