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
4 changes: 2 additions & 2 deletions docs/improvement-tracks-implementation-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,8 @@ isolation would be a stronger and lighter boundary than one shared Colima VM.

- Steps: split `scripts/workcell` (8,910 lines) into sourced modules (host
detection, environment scrubbing, wrapper assembly, dispatch); write
`docs/launcher-contract.md` (required tools, environment expectations,
exit codes, test override flags).
[`launcher-contract.md`](launcher-contract.md) (required tools, environment
expectations, exit codes, test override flags).
- Exit gates: behavior-identical on the scenario suite; contract doc matches
implementation.
- Validation: scenario suite before/after; bats coverage for extracted
Expand Down
73 changes: 73 additions & 0 deletions docs/launcher-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Launcher contract

`scripts/workcell` is the host-side launcher. Historically it was a single
monolithic script; roadmap item D4 decomposes it into small, sourced,
behaviour-preserving modules under `scripts/lib/launcher/`. The launcher
sources each module from its `source "${ROOT_DIR}/scripts/lib/..."` block
(after `ROOT_DIR` is resolved) so every extracted helper is defined before its
first call site.

This document records the contract of each extracted module. It will grow as
further modules are pulled out of the launcher.

## Host detection (`host-detect.sh`)

`scripts/lib/launcher/host-detect.sh` normalises the host environment into the
lowercased values the launcher's support-matrix logic consumes. Every helper
depends only on `uname`/`ps`/`PPID`/environment variables and each other — no
other launcher function — which makes the module self-contained.

All emitted values are lowercased and newline-terminated. Values are normalised
to canonical tokens where recognised, and otherwise passed through lowercased.

### `support_matrix_host_override_allowed()`

Gate that decides whether the harness-only host overrides (below) are honoured.
Returns `0` (allowed) only when **both** hold:

- `WORKCELL_VERIFY_INVARIANTS_SANITIZED_ENTRYPOINT` is `1`; and
- the parent process command line (read from `/proc/${PPID}/cmdline`, falling
back to `ps -p "${PPID}"`) matches one of the recognised validation harness
entrypoints (`scripts/verify-invariants.sh` or the shared dry-run scenario
scripts).

Returns non-zero otherwise. This keeps the overrides usable by Linux
validation runners exercising launch assembly without weakening the real,
operator-facing support boundary.

### `detected_host_os()`

Prints the normalised host operating system: `macos` (Darwin), `linux`
(Linux), or `windows` (MINGW/MSYS/CYGWIN/`Windows_NT`). Any other `uname -s`
value is passed through lowercased.

### `detected_host_arch()`

Prints the normalised host architecture: `arm64` (`arm64`/`aarch64`) or `amd64`
(`x86_64`/`amd64`). Any other `uname -m` value is passed through lowercased.

### `detected_host_distro()`

On non-Linux hosts prints `none`. On Linux, prints the lowercased `ID` from
`/etc/os-release`, or `unknown` when it cannot be determined.

### `detected_host_distro_version()`

On non-Linux hosts prints `none`. On Linux, prints the lowercased `VERSION_ID`
(falling back to `VERSION_CODENAME`) from `/etc/os-release`, or `unknown` when
it cannot be determined.

### Harness-only overrides

When `support_matrix_host_override_allowed` returns `0`, each detector first
honours a reserved override environment variable if it is non-empty, printing
its value verbatim:

- `WORKCELL_TEST_SUPPORT_MATRIX_HOST_OS`
- `WORKCELL_TEST_SUPPORT_MATRIX_HOST_ARCH`
- `WORKCELL_TEST_SUPPORT_MATRIX_HOST_DISTRO`
- `WORKCELL_TEST_SUPPORT_MATRIX_HOST_DISTRO_VERSION`

These variables are reserved for the validation harness. The launcher scrubs
them from the host process environment unless the sanitized-entrypoint marker
is set, so they cannot be smuggled in by an operator to spoof the detected host.
1 change: 1 addition & 0 deletions internal/metadatautil/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ func GenerateControlPlaneManifest(rootDir, outputPath string) error {
"scripts/workcell",
"scripts/check-publish-commit-signatures.sh",
"scripts/lib/extract_direct_mounts",
"scripts/lib/launcher/host-detect.sh",
"scripts/lib/render_injection_bundle",
"scripts/lib/sessionctl-shim.sh",
"scripts/lib/shellproto.sh",
Expand Down
6 changes: 5 additions & 1 deletion runtime/container/control-plane-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"host_artifacts": [
{
"repo_path": "scripts/workcell",
"sha256": "4895f0722e5bd532542fda4472aef36b5c809c0816017879ea3f8a047c7c537b"
"sha256": "b637943a4c428a591afe37647358cf8af9fdd54d091c5d1254a9986354b57fe5"
},
{
"repo_path": "scripts/check-publish-commit-signatures.sh",
Expand All @@ -12,6 +12,10 @@
"repo_path": "scripts/lib/extract_direct_mounts",
"sha256": "b7dc19f58db225fb695b87ada176c65be9b13edc5ecf43138eda8d01aa6eb879"
},
{
"repo_path": "scripts/lib/launcher/host-detect.sh",
"sha256": "318ac47025849d41e98b775e8d0d4209ae4ba80e1eeebfa393244ebc24d36fbe"
},
{
"repo_path": "scripts/lib/render_injection_bundle",
"sha256": "f1057951d6f65e12d82a7bc2b5002afde5664670d8f4ed7d9bc289bbec5f5901"
Expand Down
1 change: 1 addition & 0 deletions scripts/dev-quick-check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ shell_files=(
"${ROOT_DIR}/scripts/ci/run-validate-in-validator.sh"
"${ROOT_DIR}/scripts/lib/extract_direct_mounts"
"${ROOT_DIR}/scripts/lib/go-run-env.sh"
"${ROOT_DIR}/scripts/lib/launcher/host-detect.sh"
"${ROOT_DIR}/scripts/lib/manage_injection_policy"
"${ROOT_DIR}/scripts/lib/pty_transcript"
"${ROOT_DIR}/scripts/lib/render_injection_bundle"
Expand Down
130 changes: 130 additions & 0 deletions scripts/lib/launcher/host-detect.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/env -S BASH_ENV= ENV= bash
# shellcheck shell=bash
# SPDX-License-Identifier: Apache-2.0
# Copyright 2026 Omkhar Arasaratnam
#
# scripts/lib/launcher/host-detect.sh — host-detection module extracted
# from scripts/workcell as the first increment of the launcher
# decomposition (roadmap item D4). These helpers normalise the host OS,
# architecture, and (on Linux) distribution/version into the lowercased
# values the launcher's support-matrix logic consumes. They depend only
# on uname/ps/PPID/env vars and each other — no other launcher function —
# so they are a self-contained, behaviour-preserving unit. See
# docs/launcher-contract.md for the module contract.

support_matrix_host_override_allowed() {
local parent_cmdline=""

[[ "${WORKCELL_VERIFY_INVARIANTS_SANITIZED_ENTRYPOINT:-0}" == "1" ]] || return 1
if [[ -r "/proc/${PPID}/cmdline" ]]; then
parent_cmdline="$(tr '\0' ' ' <"/proc/${PPID}/cmdline" 2>/dev/null || true)"
elif command -v ps >/dev/null 2>&1; then
parent_cmdline="$(ps -p "${PPID}" -o command= 2>/dev/null || true)"
fi
case "${parent_cmdline}" in
*"scripts/verify-invariants.sh"* | \
*"tests/scenarios/shared/test-copilot-session-dry-run.sh"* | \
*"tests/scenarios/shared/test-compat-target-dry-run.sh"* | \
*"tests/scenarios/shared/test-gcp-remote-vm-dry-run.sh"* | \
*"tests/scenarios/shared/test-aws-remote-vm-dry-run.sh"*)
return 0
;;
esac
return 1
}

detected_host_os() {
local host_os=""

# verify-invariants uses a reserved harness-only host override so Linux
# validation runners can still exercise launch assembly without weakening the
# real operator-facing support boundary.
if support_matrix_host_override_allowed && [[ -n "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_OS:-}" ]]; then
printf '%s\n' "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_OS}"
return 0
fi

host_os="$(uname -s 2>/dev/null || true)"
case "${host_os}" in
Darwin)
printf 'macos\n'
;;
Linux)
printf 'linux\n'
;;
MINGW* | MSYS* | CYGWIN* | Windows_NT)
printf 'windows\n'
;;
*)
printf '%s\n' "$(printf '%s' "${host_os}" | tr '[:upper:]' '[:lower:]')"
;;
esac
}

detected_host_arch() {
local host_arch=""

if support_matrix_host_override_allowed && [[ -n "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_ARCH:-}" ]]; then
printf '%s\n' "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_ARCH}"
return 0
fi

host_arch="$(uname -m 2>/dev/null || true)"
case "${host_arch}" in
arm64 | aarch64)
printf 'arm64\n'
;;
x86_64 | amd64)
printf 'amd64\n'
;;
*)
printf '%s\n' "$(printf '%s' "${host_arch}" | tr '[:upper:]' '[:lower:]')"
;;
esac
}

detected_host_distro() {
local host_distro=""

if support_matrix_host_override_allowed && [[ -n "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_DISTRO:-}" ]]; then
printf '%s\n' "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_DISTRO}"
return 0
fi

if [[ "$(detected_host_os)" != "linux" ]]; then
printf 'none\n'
return 0
fi
if [[ -r /etc/os-release ]]; then
# shellcheck disable=SC1091
. /etc/os-release
host_distro="${ID:-}"
fi
if [[ -z "${host_distro}" ]]; then
host_distro="unknown"
fi
printf '%s\n' "$(printf '%s' "${host_distro}" | tr '[:upper:]' '[:lower:]')"
}

detected_host_distro_version() {
local host_distro_version=""

if support_matrix_host_override_allowed && [[ -n "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_DISTRO_VERSION:-}" ]]; then
printf '%s\n' "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_DISTRO_VERSION}"
return 0
fi

if [[ "$(detected_host_os)" != "linux" ]]; then
printf 'none\n'
return 0
fi
if [[ -r /etc/os-release ]]; then
# shellcheck disable=SC1091
. /etc/os-release
host_distro_version="${VERSION_ID:-${VERSION_CODENAME:-}}"
fi
if [[ -z "${host_distro_version}" ]]; then
host_distro_version="unknown"
fi
printf '%s\n' "$(printf '%s' "${host_distro_version}" | tr '[:upper:]' '[:lower:]')"
}
1 change: 1 addition & 0 deletions scripts/validate-repo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ shell_files=(
"${ROOT_DIR}/scripts/lint-dockerfiles.sh"
"${ROOT_DIR}/scripts/lib/extract_direct_mounts"
"${ROOT_DIR}/scripts/lib/go-run-env.sh"
"${ROOT_DIR}/scripts/lib/launcher/host-detect.sh"
"${ROOT_DIR}/scripts/lib/trusted-entrypoint.sh"
"${ROOT_DIR}/scripts/lib/manage_injection_policy"
"${ROOT_DIR}/scripts/lib/pty_transcript"
Expand Down
119 changes: 2 additions & 117 deletions scripts/workcell
Original file line number Diff line number Diff line change
Expand Up @@ -31,123 +31,6 @@ scrub_host_process_env() {

scrub_host_process_env

support_matrix_host_override_allowed() {
local parent_cmdline=""

[[ "${WORKCELL_VERIFY_INVARIANTS_SANITIZED_ENTRYPOINT:-0}" == "1" ]] || return 1
if [[ -r "/proc/${PPID}/cmdline" ]]; then
parent_cmdline="$(tr '\0' ' ' <"/proc/${PPID}/cmdline" 2>/dev/null || true)"
elif command -v ps >/dev/null 2>&1; then
parent_cmdline="$(ps -p "${PPID}" -o command= 2>/dev/null || true)"
fi
case "${parent_cmdline}" in
*"scripts/verify-invariants.sh"* | \
*"tests/scenarios/shared/test-copilot-session-dry-run.sh"* | \
*"tests/scenarios/shared/test-compat-target-dry-run.sh"* | \
*"tests/scenarios/shared/test-gcp-remote-vm-dry-run.sh"* | \
*"tests/scenarios/shared/test-aws-remote-vm-dry-run.sh"*)
return 0
;;
esac
return 1
}

detected_host_os() {
local host_os=""

# verify-invariants uses a reserved harness-only host override so Linux
# validation runners can still exercise launch assembly without weakening the
# real operator-facing support boundary.
if support_matrix_host_override_allowed && [[ -n "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_OS:-}" ]]; then
printf '%s\n' "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_OS}"
return 0
fi

host_os="$(uname -s 2>/dev/null || true)"
case "${host_os}" in
Darwin)
printf 'macos\n'
;;
Linux)
printf 'linux\n'
;;
MINGW* | MSYS* | CYGWIN* | Windows_NT)
printf 'windows\n'
;;
*)
printf '%s\n' "$(printf '%s' "${host_os}" | tr '[:upper:]' '[:lower:]')"
;;
esac
}

detected_host_arch() {
local host_arch=""

if support_matrix_host_override_allowed && [[ -n "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_ARCH:-}" ]]; then
printf '%s\n' "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_ARCH}"
return 0
fi

host_arch="$(uname -m 2>/dev/null || true)"
case "${host_arch}" in
arm64 | aarch64)
printf 'arm64\n'
;;
x86_64 | amd64)
printf 'amd64\n'
;;
*)
printf '%s\n' "$(printf '%s' "${host_arch}" | tr '[:upper:]' '[:lower:]')"
;;
esac
}

detected_host_distro() {
local host_distro=""

if support_matrix_host_override_allowed && [[ -n "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_DISTRO:-}" ]]; then
printf '%s\n' "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_DISTRO}"
return 0
fi

if [[ "$(detected_host_os)" != "linux" ]]; then
printf 'none\n'
return 0
fi
if [[ -r /etc/os-release ]]; then
# shellcheck disable=SC1091
. /etc/os-release
host_distro="${ID:-}"
fi
if [[ -z "${host_distro}" ]]; then
host_distro="unknown"
fi
printf '%s\n' "$(printf '%s' "${host_distro}" | tr '[:upper:]' '[:lower:]')"
}

detected_host_distro_version() {
local host_distro_version=""

if support_matrix_host_override_allowed && [[ -n "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_DISTRO_VERSION:-}" ]]; then
printf '%s\n' "${WORKCELL_TEST_SUPPORT_MATRIX_HOST_DISTRO_VERSION}"
return 0
fi

if [[ "$(detected_host_os)" != "linux" ]]; then
printf 'none\n'
return 0
fi
if [[ -r /etc/os-release ]]; then
# shellcheck disable=SC1091
. /etc/os-release
host_distro_version="${VERSION_ID:-${VERSION_CODENAME:-}}"
fi
if [[ -z "${host_distro_version}" ]]; then
host_distro_version="unknown"
fi
printf '%s\n' "$(printf '%s' "${host_distro_version}" | tr '[:upper:]' '[:lower:]')"
}

resolve_self_path() {
local source_path="${BASH_SOURCE[0]}"
local source_dir=""
Expand Down Expand Up @@ -181,6 +64,8 @@ source "${ROOT_DIR}/scripts/lib/go-run-env.sh"
source "${ROOT_DIR}/scripts/lib/shellproto.sh"
# shellcheck source=/dev/null
source "${ROOT_DIR}/scripts/lib/sessionctl-shim.sh"
# shellcheck source=/dev/null
source "${ROOT_DIR}/scripts/lib/launcher/host-detect.sh"
Comment thread
omkhar marked this conversation as resolved.
resolve_fixed_host_tool() {
local name="$1"
shift
Expand Down
Loading