Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
97 changes: 49 additions & 48 deletions .github/workflows/smoke-gvisor.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 11 additions & 14 deletions .github/workflows/smoke-gvisor.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,13 @@ jobs:
path: /tmp/gh-aw-agent
- name: Verify gVisor runtime was used
run: |
echo "::group::Check agent logs for gVisor runtime"
LOG_DIR="/tmp/gh-aw-agent/sandbox/agent/logs"
if grep -R -qE 'Linux version .*gVisor' "$LOG_DIR" --include '*.log' 2>/dev/null; then
echo "✅ gVisor runtime confirmed in agent logs"
echo "::group::Check artifacts for gVisor runtime confirmation"
ARTIFACT_ROOT="/tmp/gh-aw-agent"
# Search all text artifacts for gVisor kernel signature or confirmation
if grep -r -l -i 'gVisor' "$ARTIFACT_ROOT" --include '*.log' --include '*.json' --include '*.txt' --include '*.jsonl' 2>/dev/null | head -3; then
echo "✅ gVisor runtime confirmed in agent artifacts"
else
echo "⚠️ Could not confirm gVisor runtime in logs (expected until AWF runtime plumbing is added)"
echo "⚠️ Could not confirm gVisor in artifacts (agent may not have logged /proc/version)"
fi
echo "::endgroup::"
- name: Token-usage sanity check
Expand All @@ -78,11 +79,6 @@ steps:
set -euo pipefail
echo "::group::Install gVisor (runsc)"
ARCH=$(uname -m)
if [ "$ARCH" = "x86_64" ]; then
ARCH="amd64"
elif [ "$ARCH" = "aarch64" ]; then
ARCH="arm64"
fi
URL="https://storage.googleapis.com/gvisor/releases/release/latest/${ARCH}"
echo "Downloading runsc for ${ARCH}..."
curl -fsSL "${URL}/runsc" -o /tmp/runsc
Expand All @@ -94,7 +90,10 @@ steps:

echo "::group::Register runsc as Docker runtime"
sudo runsc install
sudo systemctl reload docker
# Must use restart (not reload): Docker's SIGHUP reload does NOT call
# setHostGatewayIP(), so --add-host host.docker.internal:host-gateway
# breaks for any container started after a reload-only config change.
sudo systemctl restart docker
echo "Docker runtimes:"
docker info --format '{{.Runtimes}}' || docker info | grep -i runtime
echo "::endgroup::"
Expand Down Expand Up @@ -205,9 +204,7 @@ Run `curl -s -o /dev/null -w "%{http_code}" --max-time 5 https://example.com`

## Pre-Fetched PR Data

```
${{ steps.smoke-data.outputs.SMOKE_PR_DATA }}
```
${{ steps.smoke-data.outputs.SMOKE_PR_DATA }}

## Output (MANDATORY)

Expand Down
1 change: 1 addition & 0 deletions docs/awf-config-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ AWF settings MAY be supplied via config files, including stdin (`--config -`).
- `container.dockerHostPathPrefix` → `--docker-host-path-prefix`
- `container.runnerToolCachePath` → *(config-only; checked first for optional read-only runner tool cache mount, before `RUNNER_TOOL_CACHE` and `/home/runner/work/_tool` auto-detection)*
- `container.mounts[]` → `-v, --mount` *(repeatable; each array entry maps to one Docker volume mount in `/host_path:/container_path[:ro|rw]` format (both paths must be absolute; host path must exist); in chroot mode, container paths are automatically prefixed with `/host`)*
- `container.containerRuntime` → `--container-runtime` *(user-facing runtime name, e.g. `"gvisor"`; AWF translates to the Docker OCI runtime identifier, e.g. `"runsc"`. Only the agent container uses the custom runtime; infrastructure containers always use `runc`. When set, AWF injects `extra_hosts` entries for compose-internal services to work around DNS issues with non-default runtimes. Requires the runtime to be installed and registered with Docker on the host.)*
- `chroot.binariesSourcePath` → *(config-only; overlays a runner-side binaries directory at `/usr/local/bin` inside chroot mode)*
- `chroot.identity.home` → *(config-only; forwarded as `AWF_CHROOT_IDENTITY_HOME` and applied after chroot pivot)*
- `chroot.identity.user` → *(config-only; forwarded as `AWF_CHROOT_IDENTITY_USER` and applied to `USER`/`LOGNAME` after chroot pivot)*
Expand Down
5 changes: 5 additions & 0 deletions docs/awf-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,11 @@
"pattern": "^/[^:]+:/[^:]+(:(ro|rw))?$"
},
"description": "Custom volume mounts for the agent container. Format: \"/host_path:/container_path[:ro|rw]\" (both paths must be absolute). In chroot mode, container paths are automatically prefixed with /host."
},
"containerRuntime": {
"type": "string",
"enum": ["gvisor"],
"description": "Container runtime for the agent container. Set to \"gvisor\" to run the agent under gVisor's runsc runtime for additional sandboxing. Only the agent container uses the custom runtime; infrastructure containers (squid-proxy, api-proxy) always use the default runc runtime. When set, AWF automatically injects extra_hosts entries for compose-internal services to work around DNS resolution issues with non-default runtimes. Requires gVisor (runsc) to be installed and registered with Docker on the host."
}
}
},
Expand Down
19 changes: 19 additions & 0 deletions scripts/ci/postprocess-smoke-workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,22 @@ for (const workflowPath of codexWorkflowPaths) {
console.log(`Skipping ${workflowPath}: no xpia.md changes needed.`);
}
}

// ── gVisor workflow: inject --container-runtime gvisor into the AWF command ───
const gvisorLockPath = path.join(workflowsDir, 'smoke-gvisor.lock.yml');
try {
let gvisorContent = fs.readFileSync(gvisorLockPath, 'utf-8');
// Insert --container-runtime gvisor before --config on the awf command line.
// The compiler doesn't support sandbox.agent.containerRuntime yet, so we inject it here.
const awfCmdPattern = /awf --config /g;
const replacedContent = gvisorContent.replace(awfCmdPattern, 'awf --container-runtime gvisor --config ');
if (replacedContent !== gvisorContent) {
fs.writeFileSync(gvisorLockPath, replacedContent);
console.log(` Injected --container-runtime gvisor into AWF command`);
console.log(`Updated ${gvisorLockPath}`);
} else {
console.log(`Skipping ${gvisorLockPath}: no AWF command found to patch.`);
}
} catch {
console.log(`Skipping ${gvisorLockPath}: file not found.`);
}
5 changes: 5 additions & 0 deletions src/awf-config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,11 @@
"pattern": "^/[^:]+:/[^:]+(:(ro|rw))?$"
},
"description": "Custom volume mounts for the agent container. Format: \"/host_path:/container_path[:ro|rw]\" (both paths must be absolute). In chroot mode, container paths are automatically prefixed with /host."
},
"containerRuntime": {
"type": "string",
"enum": ["gvisor"],
"description": "Container runtime for the agent container. Set to \"gvisor\" to run the agent under gVisor's runsc runtime for additional sandboxing. Only the agent container uses the custom runtime; infrastructure containers (squid-proxy, api-proxy) always use the default runc runtime. When set, AWF automatically injects extra_hosts entries for compose-internal services to work around DNS resolution issues with non-default runtimes. Requires gVisor (runsc) to be installed and registered with Docker on the host."
}
}
},
Expand Down
6 changes: 6 additions & 0 deletions src/cli-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ program
' Useful for split runner/daemon filesystems (e.g. ARC DinD).\n' +
' Example: /host'
)
.option(
'--container-runtime <runtime>',
'Container runtime for the agent container (e.g. "gvisor" for gVisor sandboxing).\n' +
' AWF translates friendly names to Docker runtime identifiers\n' +
' (gvisor → runsc). Unknown values are passed through as-is.'
)

// -- Container Configuration --
.option(
Expand Down
Loading
Loading