Skip to content
Open
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
27 changes: 21 additions & 6 deletions go/internal/runtime/microvm_isolation_microvm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,23 @@ func sweepScript(needle, roots string) string {
// The awk program: scan every FILENAME handed to this invocation, print
// `<path>:<line>` per match, and exit non-zero when the batch had none — so
// the caller's `found` accumulator keeps grep's semantics across batches.
const awkProg = `index($0, ENVIRON["SWEEP_NEEDLE"]) { print FILENAME ":" $0; hit=1 } END { exit !hit }`
//
// BEGINFILE/ERRNO is load-bearing, not defensive: gawk (agent-image ships
// pkgs.gawk) makes an unopenable input FATAL, aborting there and dropping
// later paths plus the batch's exit-status contribution. It covers OPEN
// errors only — a read error still aborts, why the scan below shows stderr.
const awkProg = `BEGINFILE { if (ERRNO) nextfile } ` +
`index($0, ENVIRON["SWEEP_NEEDLE"]) { print FILENAME ":" $0; hit=1 } END { exit !hit }`
return "export SWEEP_NEEDLE='" + needle + "'; " +
"shopt -s globstar nullglob dotglob; found=1; batch=(); " +
// scan() runs one awk over the accumulated batch and clears it. Guarded
// on a non-empty batch so a trailing flush with nothing pending does not
// invoke awk on zero files (which would read stdin and hang).
//
// stderr is NOT suppressed: it carries the one signal that separates a
// real negative from a dead probe.
"scan() { ((${#batch[@]})) || return 0; " +
"if awk '" + awkProg + "' \"${batch[@]}\" 2>/dev/null; then found=0; fi; batch=(); }; " +
"if awk '" + awkProg + "' \"${batch[@]}\"; then found=0; fi; batch=(); }; " +
"for root in " + roots + "; do " +
"for f in \"$root\"/**/*; do " +
// Collapse repeated slashes before matching: a "/" root globs to
Expand All @@ -186,7 +195,10 @@ func sweepScript(needle, roots string) string {
"[[ -f $f && -r $f ]] || continue; " +
"batch+=(\"$f\"); " +
"((${#batch[@]} >= " + strconv.Itoa(sweepBatchSize) + ")) && scan; " +
"done; done 2>/dev/null; scan; exit $found"
// One `done` closes the per-file loop, the next the per-root loop.
"done; " +
"done; " +
"scan; exit $found"
}

// TestMicroVMSweepScriptFindsItsNeedle is the non-vacuity control for
Expand Down Expand Up @@ -239,8 +251,11 @@ func TestMicroVMSweepScriptFindsANeedleAcrossBatches(t *testing.T) {
// Comfortably more than two full batches, so at least two mid-loop flushes
// happen before the trailing one.
fileCount := sweepBatchSize*2 + 25
// Zero-padded so the glob's lexicographic order matches numeric order in ANY
// collation. Unpadded, f425.txt sorts mid-run (index 362 in the guest's C
// locale), so the "final batch" row never reached the trailing flush it names.
plant := "mkdir -p /workspace/many && for i in $(seq 1 " + strconv.Itoa(fileCount) + "); do " +
"printf 'filler line %s\\n' \"$i\" > /workspace/many/f$i.txt; done && ls /workspace/many | wc -l"
"printf 'filler line %s\\n' \"$i\" > \"$(printf '/workspace/many/f%03d.txt' \"$i\")\"; done && ls /workspace/many | wc -l"
out, code := guestSh(t, m, id, plant)
if code != 0 {
t.Fatalf("planting %d filler files: exit %d, %q", fileCount, code, truncate(out))
Expand All @@ -251,10 +266,10 @@ func TestMicroVMSweepScriptFindsANeedleAcrossBatches(t *testing.T) {

for _, tt := range []struct{ name, file, needle string }{
// Last file: only the TRAILING flush can find it.
{"in the final batch", "/workspace/many/f" + strconv.Itoa(fileCount) + ".txt", "SWEEP-BATCH-LAST-6c1e8f30"},
{"in the final batch", fmt.Sprintf("/workspace/many/f%03d.txt", fileCount), "SWEEP-BATCH-LAST-6c1e8f30"},
// First file: found by a MID-LOOP flush, so `found` must survive every
// later batch that matched nothing.
{"in the first batch", "/workspace/many/f1.txt", "SWEEP-BATCH-FIRST-91ad47b2"},
{"in the first batch", "/workspace/many/f001.txt", "SWEEP-BATCH-FIRST-91ad47b2"},
} {
t.Run(tt.name, func(t *testing.T) {
if out, code := guestSh(t, m, id,
Expand Down
47 changes: 46 additions & 1 deletion go/internal/runtime/microvm_quota_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ package runtime
//
// These are separate from microvm_quota_test.go because mountRoot and deviceOf
// only exist under //go:build linux — the pure decision they feed is covered
// there, on every GOOS.
// there, on every GOOS. The two readVolumeQuota probes at the end are here for
// the same reason: off Linux they reach the refusal stub, so one fails outright
// and the other passes for the wrong reason.

import (
"math"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -208,3 +211,45 @@ func TestReadVolumeQuotaPropagatesInconclusiveMountRoot(t *testing.T) {
"required-quota startup fails closed with the real cause", volume, reading)
}
}

// TestReadVolumeQuotaOnRealPath exercises the PRODUCTION statfs probe against a
// real directory. What it can honestly assert without root is bounded but real:
// the probe succeeds, reports a plausible filesystem, resolves a mount root, and
// — since no test box's temp dir carries a project quota — reads as NOT active.
// That negative is load-bearing: it is what proves the detection does not
// false-positive and pass an unbounded volume off as quota'd.
func TestReadVolumeQuotaOnRealPath(t *testing.T) {
dir := t.TempDir()
reading, err := readVolumeQuota(dir)
if err != nil {
t.Fatalf("readVolumeQuota(%q) = %v, want a successful rootless read", dir, err)
}
if reading.LimitBytes <= 0 {
t.Fatalf("reading %s has no block total; statfs must report the filesystem size", reading)
}
if reading.MountRoot == "" {
t.Fatalf("reading %s resolved no mount root", reading)
}
if reading.UsedBytes < 0 || reading.UsedBytes > reading.LimitBytes {
t.Fatalf("reading %s has nonsensical usage", reading)
}
if reading.Active() {
t.Fatalf("reading %s reports an active project quota on a plain temp dir; "+
"the detection must not false-positive (that would pass an unbounded volume as quota'd)", reading)
}
// The utilization the preflight logs must be finite and in range even with
// no quota — V7 meters this value.
if ratio := reading.UsedRatio(); ratio < 0 || ratio > 1 || math.IsNaN(ratio) {
t.Fatalf("UsedRatio() = %v on reading %s, want a finite ratio in [0,1]", ratio, reading)
}
}

// TestReadVolumeQuotaAbsentPath: a path that does not exist is a probe ERROR,
// not a silent "no quota". Under QuotaRequired that difference decides whether
// startup fails with the real cause (an unreachable volume) or with a misleading
// missing-quota message.
func TestReadVolumeQuotaAbsentPath(t *testing.T) {
if _, err := readVolumeQuota(t.TempDir() + "/does-not-exist"); err == nil {
t.Fatal("readVolumeQuota on an absent path = nil error, want a failure naming the path")
}
}
51 changes: 4 additions & 47 deletions go/internal/runtime/microvm_quota_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ package runtime
// quotaReadFn precisely so it is covered here rather than left to a leg that
// skips.
//
// The real statfs probe (readVolumeQuota) is exercised too, but only for what is
// honestly assertable without a quota'd filesystem: that it reads a real path,
// and that an unquota'd tree correctly reads as NOT active. A green here does
// not claim quota enforcement was proven — the guest-side ENOSPC/EDQUOT proof is
// the root-gated leg in microvm_isolation_microvm_test.go.
// The real statfs probe is Linux-only; it is exercised in
// microvm_quota_linux_test.go. Enforcement itself is proven by the
// ENOSPC/EDQUOT leg in microvm_isolation_microvm_test.go, which needs the
// microvm tag and an operator-provided quota'd filesystem.

import (
"errors"
Expand Down Expand Up @@ -310,45 +309,3 @@ func TestVerifyVolumeQuotaNeverAssigns(t *testing.T) {
t.Fatalf("returned reading Path = %q, want the verified path", got.Path)
}
}

// TestReadVolumeQuotaOnRealPath exercises the PRODUCTION statfs probe against a
// real directory. What it can honestly assert without root is bounded but real:
// the probe succeeds, reports a plausible filesystem, resolves a mount root, and
// — since no test box's temp dir carries a project quota — reads as NOT active.
// That negative is load-bearing: it is what proves the detection does not
// false-positive and pass an unbounded volume off as quota'd.
func TestReadVolumeQuotaOnRealPath(t *testing.T) {
dir := t.TempDir()
reading, err := readVolumeQuota(dir)
if err != nil {
t.Fatalf("readVolumeQuota(%q) = %v, want a successful rootless read", dir, err)
}
if reading.LimitBytes <= 0 {
t.Fatalf("reading %s has no block total; statfs must report the filesystem size", reading)
}
if reading.MountRoot == "" {
t.Fatalf("reading %s resolved no mount root", reading)
}
if reading.UsedBytes < 0 || reading.UsedBytes > reading.LimitBytes {
t.Fatalf("reading %s has nonsensical usage", reading)
}
if reading.Active() {
t.Fatalf("reading %s reports an active project quota on a plain temp dir; "+
"the detection must not false-positive (that would pass an unbounded volume as quota'd)", reading)
}
// The utilization the preflight logs must be finite and in range even with
// no quota — V7 meters this value.
if ratio := reading.UsedRatio(); ratio < 0 || ratio > 1 || math.IsNaN(ratio) {
t.Fatalf("UsedRatio() = %v on reading %s, want a finite ratio in [0,1]", ratio, reading)
}
}

// TestReadVolumeQuotaAbsentPath: a path that does not exist is a probe ERROR,
// not a silent "no quota". Under QuotaRequired that difference decides whether
// startup fails with the real cause (an unreachable volume) or with a misleading
// missing-quota message.
func TestReadVolumeQuotaAbsentPath(t *testing.T) {
if _, err := readVolumeQuota(t.TempDir() + "/does-not-exist"); err == nil {
t.Fatal("readVolumeQuota on an absent path = nil error, want a failure naming the path")
}
}
Loading