Skip to content
Merged
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
26 changes: 26 additions & 0 deletions infra/firecracker/build-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,32 @@ build_rootfs() {
sudo cp "${HARNESS_BIN}" "${mnt}/sbin/init"
sudo chmod 0755 "${mnt}/usr/local/bin/lantern-harness" "${mnt}/sbin/init"

# A static shell, so the guest can actually run a tool.
#
# The harness's `shell_exec` tool spawns `/bin/sh -c <command>`; without a
# shell in the image every tool call fails with "spawn failed: No such file
# or directory", so the in-guest tool path cannot be exercised at all. Must
# be STATIC — this rootfs has no libc.
#
# Optional: when no static busybox is present the image is built without a
# shell exactly as before, and only shell_exec is unavailable.
if [ -n "${FC_BUSYBOX_BIN:-}" ] && [ -x "${FC_BUSYBOX_BIN}" ]; then
BUSYBOX_SRC="${FC_BUSYBOX_BIN}"
elif [ -x /bin/busybox ] && file /bin/busybox 2>/dev/null | grep -q "statically linked"; then
BUSYBOX_SRC=/bin/busybox
else
BUSYBOX_SRC=""
fi
if [ -n "${BUSYBOX_SRC}" ]; then
sudo mkdir -p "${mnt}/bin"
sudo cp "${BUSYBOX_SRC}" "${mnt}/bin/busybox"
sudo chmod 0755 "${mnt}/bin/busybox"
sudo ln -sf busybox "${mnt}/bin/sh"
log "Installed static shell: ${BUSYBOX_SRC} -> /bin/sh"
else
log "No static busybox found — image has NO /bin/sh; shell_exec tool calls will fail"
fi

# Minimal defaults file (ADR-0004). The manager overrides these via the
# kernel cmdline (build_boot_args) and the per-VM env contract.
sudo tee "${mnt}/etc/lantern/harness.toml" >/dev/null <<'TOML'
Expand Down
26 changes: 26 additions & 0 deletions infra/firecracker/integration-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,32 @@ else
skip "VendSecret round-trip PENDING in-guest harness agent (services/harness manager_client.rs is a stub); set EXPECT_VENDSECRET=1 to assert it. Secret-value-never-leaked invariant: enforced."
fi

# ---------------------------------------------------------------------------
# 4b. Invoke a tool in the guest via ExecTool.
#
# This is the workflow-engine's tool_call path end to end: manager -> in-guest
# harness exec server -> tool registry -> real execution -> typed result. It can
# only succeed after the harness has opened its Heartbeat stream (that is what
# gives the manager the guest address to dial back on), so it also proves the
# harness is reachable, not just that it started.
#
# Needs a shell in the image; build-image.sh installs a static busybox when one
# is available, and skips this assertion when it did not.
# ---------------------------------------------------------------------------
log "Invoking a tool in the guest (ExecTool -> shell_exec)"
TOOL_RESP=$(grpcurl -cacert "${WORK}/ca.crt" -cert "${WORK}/client.crt" -key "${WORK}/client.key" -servername localhost \
-import-path "${PROTO_DIR}" -proto "${PROTO_FILE}" \
-d "{\"vm_id\":\"${VM_ID}\",\"run_id\":\"itest-run-001\",\"step_id\":\"itest-step-1\",\"tool_name\":\"shell_exec\",\"args\":{\"command\":\"echo lantern-tool-marker\"},\"idempotency_key\":\"itest-run-001:itest-step-1:1\"}" \
"${MANAGER_ADDR}" lantern.v1.RuntimeManager/ExecTool 2>>"${MANAGER_LOG}") || TOOL_RESP=""

if printf '%s' "${TOOL_RESP}" | grep -q "lantern-tool-marker"; then
pass "tool invoked in-guest and returned its output (ExecTool -> shell_exec)"
elif printf '%s' "${TOOL_RESP}" | grep -q "No such file or directory"; then
skip "in-guest tool ran but the image has no /bin/sh — install a static busybox to assert execution"
else
fail "ExecTool did not return the tool's output. Response:\n${TOOL_RESP}\nLog:\n$(tail -30 "${MANAGER_LOG}")"
fi

# ---------------------------------------------------------------------------
# 5. Tear down.
# ---------------------------------------------------------------------------
Expand Down
Loading