From b017e66e175c8b7efa2be38fda89978914de72f0 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Wed, 2 Sep 2026 22:06:43 -0500 Subject: [PATCH] test(capabilities): workspace/tooling selftests + live demo fixture (#21) - mock plumbing cases: workspace path + tools delivered (asserted from run-record stderr), host workspace created, absent fields = empty vars - validation negatives: unknown tool, workspace traversal - tasks/workspace-demo.json: pi uses bash inside the persistent demo workspace; host-visible proof.txt verified live Closes #21 --- scripts/test-task.sh | 32 ++++++++++++++++++++++++++++++++ tasks/workspace-demo.json | 9 +++++++++ 2 files changed, 41 insertions(+) create mode 100644 tasks/workspace-demo.json diff --git a/scripts/test-task.sh b/scripts/test-task.sh index d5506f3d..b4333391 100755 --- a/scripts/test-task.sh +++ b/scripts/test-task.sh @@ -146,6 +146,38 @@ else echo "skip adapter seam cases (docker daemon unavailable)" fi +# ---------- workspace + capabilities (M5): deterministic mock cases ---------- +if docker info >/dev/null 2>&1; then + printf '{"taskVersion":1,"id":"t-ws","prompt":"ignored","workspace":"suitews","capabilities":{"tools":["read","bash"]}}' > "$SANDBOX/ws-task.json" + expect_exit "workspace+tools task runs via mock" 0 -- \ + env MOSAIC_CONFIG="$SANDBOX/mock-adapters.json" MOSAIC_MOCK_RESPONSE=MOCKED \ + scripts/run-task.sh run "$SANDBOX/ws-task.json" + WSL="$(ls -dt "$SANDBOX/data/runs"/r-* 2>/dev/null | head -1)" + grep -q '^MOSAIC_WORKSPACE=/var/lib/mosaic/workspaces/suitews$' "$WSL/stderr.txt" 2>/dev/null \ + && grep -q '^MOSAIC_TOOLS=read,bash$' "$WSL/stderr.txt" 2>/dev/null \ + && check "workspace path + tools delivered to adapter" 0 \ + || check "workspace path + tools delivered to adapter" 1 + [ -d "$SANDBOX/data/workspaces/suitews" ] \ + && check "persistent workspace created on host" 0 \ + || check "persistent workspace created on host" 1 + + expect_exit "plain task still runs (no workspace/tools)" 0 -- \ + env MOSAIC_CONFIG="$SANDBOX/mock-adapters.json" MOSAIC_MOCK_RESPONSE=MOSAIC_HELLO_OK \ + scripts/run-task.sh run "$SANDBOX/ok.json" + PL="$(ls -dt "$SANDBOX/data/runs"/r-* 2>/dev/null | head -1)" + grep -q '^MOSAIC_WORKSPACE=$' "$PL/stderr.txt" 2>/dev/null \ + && check "workspace var present but empty when absent" 0 || check "workspace var present but empty when absent" 1 + grep -q '^MOSAIC_TOOLS=$' "$PL/stderr.txt" 2>/dev/null \ + && check "tools empty when absent" 0 || check "tools empty when absent" 1 + + printf '{"taskVersion":1,"id":"t-badtool","prompt":"x","capabilities":{"tools":["sudo"]}}' > "$SANDBOX/badtool.json" + expect_exit "unknown tool exits 2" 2 -- $TASK validate "$SANDBOX/badtool.json" + printf '{"taskVersion":1,"id":"t-badws","prompt":"x","workspace":"../escape"}' > "$SANDBOX/badws.json" + expect_exit "workspace traversal exits 2" 2 -- $TASK validate "$SANDBOX/badws.json" +else + echo "skip workspace/capability cases (docker daemon unavailable)" +fi + # ---------- live: real runs (Docker + credentials required) ---------- # On failure, surface the run record + agent stderr BEFORE the sandbox # cleanup destroys them. Never let a wrong-exit mask the real reason. diff --git a/tasks/workspace-demo.json b/tasks/workspace-demo.json new file mode 100644 index 00000000..ed861970 --- /dev/null +++ b/tasks/workspace-demo.json @@ -0,0 +1,9 @@ +{ + "taskVersion": 1, + "id": "t-workspace-demo", + "prompt": "Use the bash tool to create a file named proof.txt in the current directory containing exactly the text: workspace works. Then reply with exactly: WORKSPACE_OK", + "workspace": "demo", + "capabilities": { "tools": ["bash", "read", "write"] }, + "expectExact": "WORKSPACE_OK", + "timeoutSeconds": 180 +}