workspace: drop --readonly flag — advisory only against root guests
--readonly ran `chmod -R a-w` over the workspace after copying, but
every banger guest boots as root, and root bypasses DAC mode checks.
So a user running `vm workspace prepare ... --readonly` got the
mode bits set to 0444 but `echo x >> file` in the guest still
succeeded. The flag promised enforcement it couldn't deliver.
The feature also doesn't match the product model: workspaces are
prepared precisely so the guest CAN edit them, and `workspace
export` exists to pull those edits back as a patch. A
"read-only workspace" contradicts that loop.
Removed:
- CLI flag `--readonly` on `vm workspace prepare`
- api.VMWorkspacePrepareParams.ReadOnly field
- model.WorkspacePrepareResult.ReadOnly field
- daemon chmod dispatch in prepareVMWorkspaceGuestIO
- smoke scenario pinning the (advisory) mode-bit behavior
- misleading "exportbox-readonly" VM name in an unrelated export
test (the test is about not mutating the real git index;
renamed to exportbox-noindex-mutation)
If real enforcement becomes a user need later, the right primitive
is `chattr +i` (immutable bit — root CAN'T write) or a ro bind-mount.
Reintroducing a new flag is cheaper than debugging what the current
one actually guarantees.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bafe816fc7
commit
235758e5b2
6 changed files with 6 additions and 54 deletions
|
|
@ -392,40 +392,6 @@ grep -q 'sshd' <<<"$ports_out" \
|
|||
# shellcheck disable=SC2064
|
||||
trap "rm -rf '$runtime_dir'" EXIT
|
||||
|
||||
# --- workspace prepare --readonly -------------------------------------
|
||||
# --readonly runs `chmod -R a-w` over the workspace. Root in the
|
||||
# guest bypasses DAC anyway, so this is advisory rather than
|
||||
# enforced — the point of the flag is tooling contract: "the
|
||||
# mode bits SAY readonly". Assert that contract: the write bit
|
||||
# must be cleared on the guest file after --readonly prepare, and
|
||||
# set without it. A regression where the chmod silently no-op'd
|
||||
# would leave the bits unchanged.
|
||||
log 'workspace prepare --readonly: mode bits reflect the request'
|
||||
# shellcheck disable=SC2064
|
||||
trap "\"$BANGER\" vm delete smoke-ro >/dev/null 2>&1 || true; rm -rf '$runtime_dir'" EXIT
|
||||
|
||||
"$BANGER" vm create --name smoke-ro >/dev/null || die 'workspace ro: create failed'
|
||||
"$BANGER" vm workspace prepare smoke-ro "$repodir" --readonly >/dev/null \
|
||||
|| die 'workspace ro: prepare --readonly failed'
|
||||
|
||||
# stat octal mode. a-w clears the 0222 write bits across u/g/o, so
|
||||
# none of the write bits should be set on the file.
|
||||
ro_mode="$("$BANGER" vm ssh smoke-ro -- stat -c '%a' /root/repo/smoke-file.txt | tr -d '[:space:]')"
|
||||
[[ -n "$ro_mode" ]] || die 'workspace ro: could not read mode bits'
|
||||
case "$ro_mode" in
|
||||
*[2367])
|
||||
die "workspace ro: file still has write bit set after --readonly (mode=$ro_mode)"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Read must still succeed (--readonly means a-w, not a-r).
|
||||
"$BANGER" vm ssh smoke-ro -- cat /root/repo/smoke-file.txt >/dev/null \
|
||||
|| die 'workspace ro: read denied — --readonly dropped read perm too'
|
||||
|
||||
"$BANGER" vm delete smoke-ro >/dev/null || die 'workspace ro: delete failed'
|
||||
# shellcheck disable=SC2064
|
||||
trap "rm -rf '$runtime_dir'" EXIT
|
||||
|
||||
# --- workspace prepare --mode full_copy -------------------------------
|
||||
# Default mode is shallow_overlay. full_copy copies the repo via a
|
||||
# different transfer path (tar stream into the guest's rootfs with
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue