diff --git a/.github/workflows/smoke-docker-sbx-build-test.lock.yml b/.github/workflows/smoke-docker-sbx-build-test.lock.yml index eceb66dc8..3f4779687 100644 --- a/.github/workflows/smoke-docker-sbx-build-test.lock.yml +++ b/.github/workflows/smoke-docker-sbx-build-test.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"2b3d1a1b7e61ccf42fe2931b834a2b1aa51317f24dc2522295fcdc75cbfe80ad","body_hash":"2d4dcf7e34d42a3446cfe200a502ce615ceafe4409f93f4b3f427c5910b558ac","compiler_version":"v0.82.8-28-ge0a0e5d23d","agent_id":"copilot","engine_versions":{"copilot":"1.0.68"}} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"924ae3a1cded613372ab5595356fb5720e22ba16","version":"v6.5.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"e0a0e5d23d0e2b9f065b71469a1a75578d8a7047","version":"e0a0e5d23d0e2b9f065b71469a1a75578d8a7047"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30","digest":"sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30","digest":"sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30@sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30","digest":"sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30@sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.32","digest":"sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.32@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.5.0","digest":"sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4","pinned_image":"ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"77660eb54c914d09a091e63a5064a5fdd6588806b6d3b4ecd0fab228160b1a7e","body_hash":"2d4dcf7e34d42a3446cfe200a502ce615ceafe4409f93f4b3f427c5910b558ac","compiler_version":"v0.82.8-29-ga1dd8bbd65","agent_id":"copilot","engine_versions":{"copilot":"1.0.68"}} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","DOCKER_PAT","DOCKER_USERNAME","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"924ae3a1cded613372ab5595356fb5720e22ba16","version":"v6.5.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65","version":"a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30","digest":"sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30","digest":"sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30@sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30","digest":"sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30@sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.32","digest":"sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.32@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.5.0","digest":"sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4","pinned_image":"ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4"}]} # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # # ___ _ _ @@ -27,6 +27,8 @@ # # Secrets used: # - COPILOT_GITHUB_TOKEN +# - DOCKER_PAT +# - DOCKER_USERNAME # - GH_AW_GITHUB_MCP_SERVER_TOKEN # - GH_AW_GITHUB_TOKEN # - GITHUB_TOKEN @@ -41,7 +43,7 @@ # - actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 # - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 +# - github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 # # Container images used: # - ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613 @@ -111,7 +113,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -463,7 +465,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -578,8 +580,120 @@ jobs: run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.68 env: GH_HOST: github.com - - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.30 --rootless + - name: Check KVM availability for docker-sbx + run: | + set -euo pipefail + echo "::group::KVM availability check" + if ! lsmod | grep -q kvm; then + echo "::error::KVM kernel module is not loaded. docker-sbx requires a KVM-capable runner with nested virtualisation enabled." + exit 1 + fi + if ! test -e /dev/kvm; then + echo "::error::/dev/kvm is missing. docker-sbx requires the KVM device to be present on the runner." + exit 1 + fi + echo "KVM is available and /dev/kvm is present ✅" + echo "::endgroup::" + - name: Check Docker Hub secrets for docker-sbx + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + set -euo pipefail + echo "::group::Docker Hub secrets check" + if [[ -z "${DOCKER_PAT_VAL}" ]]; then + echo "::error::secrets.DOCKER_PAT is empty. docker-sbx requires a Docker Hub personal access token to pull the sandbox template image. Add a DOCKER_PAT secret to your repository." + exit 1 + fi + if [[ -z "${DOCKER_USERNAME_VAL}" ]]; then + echo "::error::secrets.DOCKER_USERNAME is empty. docker-sbx requires a Docker Hub username. Add a DOCKER_USERNAME secret to your repository." + exit 1 + fi + echo "Docker Hub secrets are present ✅" + echo "::endgroup::" + - name: Install docker-sbx + run: | + set -euo pipefail + echo "::group::Install docker-sbx" + # Add Docker apt repo without installing Docker Engine (already present). + curl -fsSL https://get.docker.com | sudo REPO_ONLY=1 sh + sudo apt-get install -y docker-sbx + sbx version + # Fix KVM permissions so the runner user can create microVMs. + sudo chmod 666 /dev/kvm + echo "docker-sbx installed successfully ✅" + echo "::endgroup::" + - name: Start docker-sbx daemon and authenticate + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + set -euo pipefail + export DOCKER_CONFIG="$(mktemp -d)" + trap 'rm -rf "${DOCKER_CONFIG}"' EXIT + echo "::group::Start sbx daemon" + nohup sbx daemon start > /tmp/sbx-daemon.log 2>&1 & + # Poll until daemon is running (up to 10 s). + for i in $(seq 1 10); do + if sbx daemon status 2>/dev/null | grep -q -i running; then + echo "sbx daemon is running" + break + fi + sleep 1 + done + echo "::endgroup::" + echo "::group::Authenticate with Docker Hub" + printf '%s' "${DOCKER_PAT_VAL}" | docker login --username "${DOCKER_USERNAME_VAL}" --password-stdin + printf '%s' "${DOCKER_PAT_VAL}" | sbx login --username "${DOCKER_USERNAME_VAL}" --password-stdin + echo "::endgroup::" + echo "::group::Reset and initialise sbx policy" + sbx daemon stop || true + sbx policy reset --force || true + sbx policy init allow-all + nohup sbx daemon start > /tmp/sbx-daemon.log 2>&1 & + for i in $(seq 1 10); do + if sbx daemon status 2>/dev/null | grep -q -i running; then + echo "sbx daemon restarted" + break + fi + sleep 1 + done + printf '%s' "${DOCKER_PAT_VAL}" | docker login --username "${DOCKER_USERNAME_VAL}" --password-stdin + printf '%s' "${DOCKER_PAT_VAL}" | sbx login --username "${DOCKER_USERNAME_VAL}" --password-stdin + echo "::endgroup::" + echo "::group::Pre-pull sandbox template image" + docker pull docker/sandbox-templates:shell-docker + echo "Template image ready ✅" + echo "::endgroup::" + - name: docker-sbx pre-flight smoke test + run: | + set -euo pipefail + echo "::group::docker-sbx pre-flight smoke test" + sandbox_name="test-sandbox-direct" + cleanup() { + sbx stop "${sandbox_name}" >/dev/null 2>&1 || true + sbx rm --force "${sandbox_name}" >/dev/null 2>&1 || true + } + trap cleanup EXIT + echo "y" | sbx create shell --name "${sandbox_name}" "${GITHUB_WORKSPACE}" + sbx exec "${sandbox_name}" uname -a + sbx stop "${sandbox_name}" + echo "✅ sbx ready" + echo "::endgroup::" + - name: Install AWF binary (from source — includes stdin pipe fix) + run: | + set -euo pipefail + cd "${GITHUB_WORKSPACE}" + npm ci + npm run build + cat > /usr/local/bin/awf <<'WRAPPER' + #!/usr/bin/env bash + exec node "$(dirname "$(readlink -f "$0")")/../lib/node_modules/@github/awf/dist/cli.js" "$@" + WRAPPER + chmod +x /usr/local/bin/awf + mkdir -p /usr/local/lib/node_modules/@github/awf + cp -r dist package.json node_modules containers /usr/local/lib/node_modules/@github/awf/ + awf --version || echo "awf installed (source build)" - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) @@ -764,8 +878,8 @@ jobs: # Export gateway environment variables for MCP config and gateway script export MCP_GATEWAY_PORT="8080" - export MCP_GATEWAY_DOMAIN="awmg-mcpg" - export MCP_GATEWAY_HOST_DOMAIN="localhost" + export MCP_GATEWAY_DOMAIN="host.docker.internal" + export MCP_GATEWAY_HOST_DOMAIN="host.docker.internal" MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') echo "::add-mask::${MCP_GATEWAY_API_KEY}" export MCP_GATEWAY_API_KEY @@ -778,7 +892,7 @@ jobs: MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 127.0.0.1:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.3.32' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 0.0.0.0:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.3.32' mkdir -p "$HOME/.copilot" GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) @@ -864,6 +978,15 @@ jobs: id: pre_agent_audit continue-on-error: true run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh" + - name: Refresh sbx credentials + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + # Re-authenticate sbx immediately before AWF runs. + # Docker Hub OAuth tokens from sbx login can expire between steps. + printf '%s' "$DOCKER_PAT_VAL" | sbx login --username "$DOCKER_USERNAME_VAL" --password-stdin + echo "✅ sbx credentials refreshed" - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): @@ -900,7 +1023,7 @@ jobs: fi fi # shellcheck disable=SC1003,SC2016,SC2086 - awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --skip-pull \ + awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --container-runtime sbx --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --skip-pull \ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; export PATH="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: AWF_REFLECT_ENABLED: 1 @@ -966,7 +1089,9 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); await main(); env: - GH_AW_SECRET_NAMES: 'GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + GH_AW_SECRET_NAMES: 'DOCKER_PAT,DOCKER_USERNAME,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + SECRET_DOCKER_PAT: ${{ secrets.DOCKER_PAT }} + SECRET_DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -1106,7 +1231,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1352,7 +1477,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1413,7 +1538,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} diff --git a/.github/workflows/smoke-docker-sbx-build-test.md b/.github/workflows/smoke-docker-sbx-build-test.md index 11440b5e6..ad2c045f8 100644 --- a/.github/workflows/smoke-docker-sbx-build-test.md +++ b/.github/workflows/smoke-docker-sbx-build-test.md @@ -47,6 +47,10 @@ safe-outputs: run-failure: "🐳🏗️ [{workflow_name}]({run_url}) reports {status}. Docker sbx build compatibility issue detected." timeout-minutes: 30 sandbox: + agent: + id: awf + runtime: docker-sbx + sudo: true mcp: version: v0.3.32 strict: false diff --git a/.github/workflows/smoke-docker-sbx-claude.lock.yml b/.github/workflows/smoke-docker-sbx-claude.lock.yml index 45131c585..df1d0769e 100644 --- a/.github/workflows/smoke-docker-sbx-claude.lock.yml +++ b/.github/workflows/smoke-docker-sbx-claude.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"df1d731fc978225ad0488f838bf32d1ffb1c01b6cd3cc16912f73a9b18467957","body_hash":"c3cd4e80799ab7a941ec178f1c283a1fd76d1862bafd2058ce3009b4654d1c8b","compiler_version":"v0.82.8-28-ge0a0e5d23d","agent_id":"claude","agent_model":"claude-haiku-4-5","engine_versions":{"claude":"2.1.201"}} -# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"e0a0e5d23d0e2b9f065b71469a1a75578d8a7047","version":"e0a0e5d23d0e2b9f065b71469a1a75578d8a7047"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30","digest":"sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30","digest":"sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30@sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30","digest":"sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30@sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.32","digest":"sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.32@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.5.0","digest":"sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4","pinned_image":"ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"f8a17420e87b50dc819fa3db024dd5d485c0728a53ac74cbaa94689ccfe0ff25","body_hash":"c3cd4e80799ab7a941ec178f1c283a1fd76d1862bafd2058ce3009b4654d1c8b","compiler_version":"v0.82.8-29-ga1dd8bbd65","agent_id":"claude","agent_model":"claude-haiku-4-5","engine_versions":{"claude":"2.1.201"}} +# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","DOCKER_PAT","DOCKER_USERNAME","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65","version":"a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30","digest":"sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30","digest":"sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30@sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30","digest":"sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30@sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.32","digest":"sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.32@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.5.0","digest":"sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4","pinned_image":"ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4"}]} # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # # ___ _ _ @@ -28,6 +28,8 @@ # Secrets used: # - ANTHROPIC_API_KEY # - COPILOT_GITHUB_TOKEN +# - DOCKER_PAT +# - DOCKER_USERNAME # - GH_AW_GITHUB_MCP_SERVER_TOKEN # - GH_AW_GITHUB_TOKEN # - GITHUB_TOKEN @@ -41,7 +43,7 @@ # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) # - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 +# - github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 # # Container images used: # - ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613 @@ -112,7 +114,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -485,7 +487,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -551,8 +553,120 @@ jobs: with: node-version: '24' package-manager-cache: false - - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.30 --rootless + - name: Check KVM availability for docker-sbx + run: | + set -euo pipefail + echo "::group::KVM availability check" + if ! lsmod | grep -q kvm; then + echo "::error::KVM kernel module is not loaded. docker-sbx requires a KVM-capable runner with nested virtualisation enabled." + exit 1 + fi + if ! test -e /dev/kvm; then + echo "::error::/dev/kvm is missing. docker-sbx requires the KVM device to be present on the runner." + exit 1 + fi + echo "KVM is available and /dev/kvm is present ✅" + echo "::endgroup::" + - name: Check Docker Hub secrets for docker-sbx + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + set -euo pipefail + echo "::group::Docker Hub secrets check" + if [[ -z "${DOCKER_PAT_VAL}" ]]; then + echo "::error::secrets.DOCKER_PAT is empty. docker-sbx requires a Docker Hub personal access token to pull the sandbox template image. Add a DOCKER_PAT secret to your repository." + exit 1 + fi + if [[ -z "${DOCKER_USERNAME_VAL}" ]]; then + echo "::error::secrets.DOCKER_USERNAME is empty. docker-sbx requires a Docker Hub username. Add a DOCKER_USERNAME secret to your repository." + exit 1 + fi + echo "Docker Hub secrets are present ✅" + echo "::endgroup::" + - name: Install docker-sbx + run: | + set -euo pipefail + echo "::group::Install docker-sbx" + # Add Docker apt repo without installing Docker Engine (already present). + curl -fsSL https://get.docker.com | sudo REPO_ONLY=1 sh + sudo apt-get install -y docker-sbx + sbx version + # Fix KVM permissions so the runner user can create microVMs. + sudo chmod 666 /dev/kvm + echo "docker-sbx installed successfully ✅" + echo "::endgroup::" + - name: Start docker-sbx daemon and authenticate + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + set -euo pipefail + export DOCKER_CONFIG="$(mktemp -d)" + trap 'rm -rf "${DOCKER_CONFIG}"' EXIT + echo "::group::Start sbx daemon" + nohup sbx daemon start > /tmp/sbx-daemon.log 2>&1 & + # Poll until daemon is running (up to 10 s). + for i in $(seq 1 10); do + if sbx daemon status 2>/dev/null | grep -q -i running; then + echo "sbx daemon is running" + break + fi + sleep 1 + done + echo "::endgroup::" + echo "::group::Authenticate with Docker Hub" + printf '%s' "${DOCKER_PAT_VAL}" | docker login --username "${DOCKER_USERNAME_VAL}" --password-stdin + printf '%s' "${DOCKER_PAT_VAL}" | sbx login --username "${DOCKER_USERNAME_VAL}" --password-stdin + echo "::endgroup::" + echo "::group::Reset and initialise sbx policy" + sbx daemon stop || true + sbx policy reset --force || true + sbx policy init allow-all + nohup sbx daemon start > /tmp/sbx-daemon.log 2>&1 & + for i in $(seq 1 10); do + if sbx daemon status 2>/dev/null | grep -q -i running; then + echo "sbx daemon restarted" + break + fi + sleep 1 + done + printf '%s' "${DOCKER_PAT_VAL}" | docker login --username "${DOCKER_USERNAME_VAL}" --password-stdin + printf '%s' "${DOCKER_PAT_VAL}" | sbx login --username "${DOCKER_USERNAME_VAL}" --password-stdin + echo "::endgroup::" + echo "::group::Pre-pull sandbox template image" + docker pull docker/sandbox-templates:shell-docker + echo "Template image ready ✅" + echo "::endgroup::" + - name: docker-sbx pre-flight smoke test + run: | + set -euo pipefail + echo "::group::docker-sbx pre-flight smoke test" + sandbox_name="test-sandbox-direct" + cleanup() { + sbx stop "${sandbox_name}" >/dev/null 2>&1 || true + sbx rm --force "${sandbox_name}" >/dev/null 2>&1 || true + } + trap cleanup EXIT + echo "y" | sbx create shell --name "${sandbox_name}" "${GITHUB_WORKSPACE}" + sbx exec "${sandbox_name}" uname -a + sbx stop "${sandbox_name}" + echo "✅ sbx ready" + echo "::endgroup::" + - name: Install AWF binary (from source — includes stdin pipe fix) + run: | + set -euo pipefail + cd "${GITHUB_WORKSPACE}" + npm ci + npm run build + cat > /usr/local/bin/awf <<'WRAPPER' + #!/usr/bin/env bash + exec node "$(dirname "$(readlink -f "$0")")/../lib/node_modules/@github/awf/dist/cli.js" "$@" + WRAPPER + chmod +x /usr/local/bin/awf + mkdir -p /usr/local/lib/node_modules/@github/awf + cp -r dist package.json node_modules containers /usr/local/lib/node_modules/@github/awf/ + awf --version || echo "awf installed (source build)" - name: Install Claude Code CLI run: npm install -g @anthropic-ai/claude-code@2.1.201 - name: Determine automatic lockdown mode for GitHub MCP Server @@ -739,8 +853,8 @@ jobs: # Export gateway environment variables for MCP config and gateway script export MCP_GATEWAY_PORT="8080" - export MCP_GATEWAY_DOMAIN="awmg-mcpg" - export MCP_GATEWAY_HOST_DOMAIN="localhost" + export MCP_GATEWAY_DOMAIN="host.docker.internal" + export MCP_GATEWAY_HOST_DOMAIN="host.docker.internal" MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') echo "::add-mask::${MCP_GATEWAY_API_KEY}" export MCP_GATEWAY_API_KEY @@ -753,7 +867,7 @@ jobs: MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 127.0.0.1:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.3.32' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 0.0.0.0:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.3.32' GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) cat << GH_AW_MCP_CONFIG_dac460792b0f83aa_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" @@ -836,6 +950,15 @@ jobs: id: pre_agent_audit continue-on-error: true run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh" + - name: Refresh sbx credentials + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + # Re-authenticate sbx immediately before AWF runs. + # Docker Hub OAuth tokens from sbx login can expire between steps. + printf '%s' "$DOCKER_PAT_VAL" | sbx login --username "$DOCKER_USERNAME_VAL" --password-stdin + echo "✅ sbx credentials refreshed" - name: Execute Claude Code CLI id: agentic_execution # Allowed tools (sorted): @@ -934,7 +1057,7 @@ jobs: fi fi # shellcheck disable=SC1003,SC2016,SC2086 - awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --tty --env-all --exclude-env ANTHROPIC_API_KEY --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --skip-pull \ + awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --tty --container-runtime sbx --env-all --exclude-env ANTHROPIC_API_KEY --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --skip-pull \ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; export PATH="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/claude_harness.cjs claude --print --no-chrome --allowed-tools '\''Bash,BashOutput,Edit,Edit(/tmp/*),Edit(/tmp/gh-aw/agent/*),ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,MultiEdit(/tmp/*),MultiEdit(/tmp/gh-aw/agent/*),NotebookEdit,NotebookRead,Read,Read(/tmp/*),Read(/tmp/gh-aw/agent/*),Task,TodoWrite,Write,Write(/tmp/*),Write(/tmp/gh-aw/agent/*),mcp__github__actions_get,mcp__github__actions_list,mcp__github__get_code_scanning_alert,mcp__github__get_commit,mcp__github__get_dependabot_alert,mcp__github__get_discussion,mcp__github__get_discussion_comments,mcp__github__get_file_contents,mcp__github__get_job_logs,mcp__github__get_label,mcp__github__get_latest_release,mcp__github__get_me,mcp__github__get_notification_details,mcp__github__get_pull_request,mcp__github__get_pull_request_comments,mcp__github__get_pull_request_diff,mcp__github__get_pull_request_files,mcp__github__get_pull_request_review_comments,mcp__github__get_pull_request_reviews,mcp__github__get_pull_request_status,mcp__github__get_release_by_tag,mcp__github__get_secret_scanning_alert,mcp__github__get_tag,mcp__github__issue_read,mcp__github__list_branches,mcp__github__list_code_scanning_alerts,mcp__github__list_commits,mcp__github__list_dependabot_alerts,mcp__github__list_discussion_categories,mcp__github__list_discussions,mcp__github__list_issue_types,mcp__github__list_issues,mcp__github__list_label,mcp__github__list_notifications,mcp__github__list_pull_requests,mcp__github__list_releases,mcp__github__list_secret_scanning_alerts,mcp__github__list_starred_repositories,mcp__github__list_tags,mcp__github__pull_request_read,mcp__github__search_code,mcp__github__search_issues,mcp__github__search_orgs,mcp__github__search_pull_requests,mcp__github__search_repositories,mcp__github__search_users,mcp__safeoutputs'\'' --debug-file /tmp/gh-aw/agent-stdio.log --verbose --permission-mode acceptEdits --output-format stream-json --mcp-config "${RUNNER_TEMP}/gh-aw/mcp-config/mcp-servers.json" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} @@ -993,8 +1116,10 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); await main(); env: - GH_AW_SECRET_NAMES: 'ANTHROPIC_API_KEY,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + GH_AW_SECRET_NAMES: 'ANTHROPIC_API_KEY,DOCKER_PAT,DOCKER_USERNAME,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' SECRET_ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + SECRET_DOCKER_PAT: ${{ secrets.DOCKER_PAT }} + SECRET_DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -1132,7 +1257,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1379,7 +1504,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1439,7 +1564,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} diff --git a/.github/workflows/smoke-docker-sbx-claude.md b/.github/workflows/smoke-docker-sbx-claude.md index cf428efc6..c0b3a4849 100644 --- a/.github/workflows/smoke-docker-sbx-claude.md +++ b/.github/workflows/smoke-docker-sbx-claude.md @@ -39,6 +39,10 @@ safe-outputs: run-failure: "🐳🟣 [{workflow_name}]({run_url}) reports {status}. Docker sbx + Claude compatibility issue detected." timeout-minutes: 15 sandbox: + agent: + id: awf + runtime: docker-sbx + sudo: true mcp: version: v0.3.32 strict: false diff --git a/.github/workflows/smoke-docker-sbx-codex.lock.yml b/.github/workflows/smoke-docker-sbx-codex.lock.yml index 2fdcfc971..38620ab9f 100644 --- a/.github/workflows/smoke-docker-sbx-codex.lock.yml +++ b/.github/workflows/smoke-docker-sbx-codex.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8246825886ce9a323e2615e20e6d08e439c50e045960b04e7e8e9b3605c64203","body_hash":"1018c109863e472a09e7443f722cf83304e8c0561285d4fbf8ede1930ddc505b","compiler_version":"v0.82.8-28-ge0a0e5d23d","agent_id":"codex","agent_model":"gpt-5.4","engine_versions":{"codex":"0.142.5"}} -# gh-aw-manifest: {"version":1,"secrets":["CODEX_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN","OPENAI_API_KEY"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"e0a0e5d23d0e2b9f065b71469a1a75578d8a7047","version":"e0a0e5d23d0e2b9f065b71469a1a75578d8a7047"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30","digest":"sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30","digest":"sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30@sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30","digest":"sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30@sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a"},{"image":"ghcr.io/github/gh-aw-mcpg:latest","digest":"sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477","pinned_image":"ghcr.io/github/gh-aw-mcpg:latest@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.5.0","digest":"sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4","pinned_image":"ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"dfd5fe831b683692ee1e902ff243acb2ec33a29457aafa8de8ddf70a0cb1cd7a","body_hash":"1018c109863e472a09e7443f722cf83304e8c0561285d4fbf8ede1930ddc505b","compiler_version":"v0.82.8-29-ga1dd8bbd65","agent_id":"codex","agent_model":"gpt-5.4","engine_versions":{"codex":"0.142.5"}} +# gh-aw-manifest: {"version":1,"secrets":["CODEX_API_KEY","COPILOT_GITHUB_TOKEN","DOCKER_PAT","DOCKER_USERNAME","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN","OPENAI_API_KEY"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65","version":"a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30","digest":"sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30","digest":"sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30@sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30","digest":"sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30@sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a"},{"image":"ghcr.io/github/gh-aw-mcpg:latest","digest":"sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477","pinned_image":"ghcr.io/github/gh-aw-mcpg:latest@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.5.0","digest":"sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4","pinned_image":"ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4"}]} # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # # ___ _ _ @@ -28,6 +28,8 @@ # Secrets used: # - CODEX_API_KEY # - COPILOT_GITHUB_TOKEN +# - DOCKER_PAT +# - DOCKER_USERNAME # - GH_AW_GITHUB_MCP_SERVER_TOKEN # - GH_AW_GITHUB_TOKEN # - GITHUB_TOKEN @@ -42,7 +44,7 @@ # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) # - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 +# - github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 # # Container images used: # - ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613 @@ -113,7 +115,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -487,7 +489,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -555,8 +557,120 @@ jobs: package-manager-cache: false - name: Install Codex CLI run: npm install --ignore-scripts -g @openai/codex@0.142.5 - - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.30 --rootless + - name: Check KVM availability for docker-sbx + run: | + set -euo pipefail + echo "::group::KVM availability check" + if ! lsmod | grep -q kvm; then + echo "::error::KVM kernel module is not loaded. docker-sbx requires a KVM-capable runner with nested virtualisation enabled." + exit 1 + fi + if ! test -e /dev/kvm; then + echo "::error::/dev/kvm is missing. docker-sbx requires the KVM device to be present on the runner." + exit 1 + fi + echo "KVM is available and /dev/kvm is present ✅" + echo "::endgroup::" + - name: Check Docker Hub secrets for docker-sbx + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + set -euo pipefail + echo "::group::Docker Hub secrets check" + if [[ -z "${DOCKER_PAT_VAL}" ]]; then + echo "::error::secrets.DOCKER_PAT is empty. docker-sbx requires a Docker Hub personal access token to pull the sandbox template image. Add a DOCKER_PAT secret to your repository." + exit 1 + fi + if [[ -z "${DOCKER_USERNAME_VAL}" ]]; then + echo "::error::secrets.DOCKER_USERNAME is empty. docker-sbx requires a Docker Hub username. Add a DOCKER_USERNAME secret to your repository." + exit 1 + fi + echo "Docker Hub secrets are present ✅" + echo "::endgroup::" + - name: Install docker-sbx + run: | + set -euo pipefail + echo "::group::Install docker-sbx" + # Add Docker apt repo without installing Docker Engine (already present). + curl -fsSL https://get.docker.com | sudo REPO_ONLY=1 sh + sudo apt-get install -y docker-sbx + sbx version + # Fix KVM permissions so the runner user can create microVMs. + sudo chmod 666 /dev/kvm + echo "docker-sbx installed successfully ✅" + echo "::endgroup::" + - name: Start docker-sbx daemon and authenticate + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + set -euo pipefail + export DOCKER_CONFIG="$(mktemp -d)" + trap 'rm -rf "${DOCKER_CONFIG}"' EXIT + echo "::group::Start sbx daemon" + nohup sbx daemon start > /tmp/sbx-daemon.log 2>&1 & + # Poll until daemon is running (up to 10 s). + for i in $(seq 1 10); do + if sbx daemon status 2>/dev/null | grep -q -i running; then + echo "sbx daemon is running" + break + fi + sleep 1 + done + echo "::endgroup::" + echo "::group::Authenticate with Docker Hub" + printf '%s' "${DOCKER_PAT_VAL}" | docker login --username "${DOCKER_USERNAME_VAL}" --password-stdin + printf '%s' "${DOCKER_PAT_VAL}" | sbx login --username "${DOCKER_USERNAME_VAL}" --password-stdin + echo "::endgroup::" + echo "::group::Reset and initialise sbx policy" + sbx daemon stop || true + sbx policy reset --force || true + sbx policy init allow-all + nohup sbx daemon start > /tmp/sbx-daemon.log 2>&1 & + for i in $(seq 1 10); do + if sbx daemon status 2>/dev/null | grep -q -i running; then + echo "sbx daemon restarted" + break + fi + sleep 1 + done + printf '%s' "${DOCKER_PAT_VAL}" | docker login --username "${DOCKER_USERNAME_VAL}" --password-stdin + printf '%s' "${DOCKER_PAT_VAL}" | sbx login --username "${DOCKER_USERNAME_VAL}" --password-stdin + echo "::endgroup::" + echo "::group::Pre-pull sandbox template image" + docker pull docker/sandbox-templates:shell-docker + echo "Template image ready ✅" + echo "::endgroup::" + - name: docker-sbx pre-flight smoke test + run: | + set -euo pipefail + echo "::group::docker-sbx pre-flight smoke test" + sandbox_name="test-sandbox-direct" + cleanup() { + sbx stop "${sandbox_name}" >/dev/null 2>&1 || true + sbx rm --force "${sandbox_name}" >/dev/null 2>&1 || true + } + trap cleanup EXIT + echo "y" | sbx create shell --name "${sandbox_name}" "${GITHUB_WORKSPACE}" + sbx exec "${sandbox_name}" uname -a + sbx stop "${sandbox_name}" + echo "✅ sbx ready" + echo "::endgroup::" + - name: Install AWF binary (from source — includes stdin pipe fix) + run: | + set -euo pipefail + cd "${GITHUB_WORKSPACE}" + npm ci + npm run build + cat > /usr/local/bin/awf <<'WRAPPER' + #!/usr/bin/env bash + exec node "$(dirname "$(readlink -f "$0")")/../lib/node_modules/@github/awf/dist/cli.js" "$@" + WRAPPER + chmod +x /usr/local/bin/awf + mkdir -p /usr/local/lib/node_modules/@github/awf + cp -r dist package.json node_modules containers /usr/local/lib/node_modules/@github/awf/ + awf --version || echo "awf installed (source build)" - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) @@ -742,8 +856,8 @@ jobs: # Export gateway environment variables for MCP config and gateway script export MCP_GATEWAY_PORT="8080" - export MCP_GATEWAY_DOMAIN="awmg-mcpg" - export MCP_GATEWAY_HOST_DOMAIN="localhost" + export MCP_GATEWAY_DOMAIN="host.docker.internal" + export MCP_GATEWAY_HOST_DOMAIN="host.docker.internal" MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') echo "::add-mask::${MCP_GATEWAY_API_KEY}" export MCP_GATEWAY_API_KEY @@ -756,7 +870,7 @@ jobs: MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 127.0.0.1:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -e CODEX_HOME -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:latest' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 0.0.0.0:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -e CODEX_HOME -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:latest' cat > "${RUNNER_TEMP}/gh-aw/mcp-config/config.toml" << GH_AW_MCP_CONFIG_1b4d94f6fe337333_EOF [history] @@ -897,6 +1011,15 @@ jobs: id: pre_agent_audit continue-on-error: true run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh" + - name: Refresh sbx credentials + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + # Re-authenticate sbx immediately before AWF runs. + # Docker Hub OAuth tokens from sbx login can expire between steps. + printf '%s' "$DOCKER_PAT_VAL" | sbx login --username "$DOCKER_USERNAME_VAL" --password-stdin + echo "✅ sbx credentials refreshed" - name: Execute Codex CLI id: agentic_execution run: | @@ -923,7 +1046,7 @@ jobs: fi fi # shellcheck disable=SC1003,SC2016,SC2086 - awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env CODEX_API_KEY --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --exclude-env OPENAI_API_KEY --log-level info --skip-pull \ + awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --container-runtime sbx --env-all --exclude-env CODEX_API_KEY --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --exclude-env OPENAI_API_KEY --log-level info --skip-pull \ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; export PATH="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/codex_harness.cjs codex exec${GH_AW_MODEL_AGENT_CODEX:+ --model "$GH_AW_MODEL_AGENT_CODEX"} -c web_search="disabled" -c fetch="disabled" --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: CODEX_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }} @@ -975,8 +1098,10 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); await main(); env: - GH_AW_SECRET_NAMES: 'CODEX_API_KEY,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN,OPENAI_API_KEY' + GH_AW_SECRET_NAMES: 'CODEX_API_KEY,DOCKER_PAT,DOCKER_USERNAME,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN,OPENAI_API_KEY' SECRET_CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} + SECRET_DOCKER_PAT: ${{ secrets.DOCKER_PAT }} + SECRET_DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -1117,7 +1242,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1364,7 +1489,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1424,7 +1549,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@e0a0e5d23d0e2b9f065b71469a1a75578d8a7047 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} diff --git a/.github/workflows/smoke-docker-sbx-codex.md b/.github/workflows/smoke-docker-sbx-codex.md index 83f9cdbd2..bb5f5fa1e 100644 --- a/.github/workflows/smoke-docker-sbx-codex.md +++ b/.github/workflows/smoke-docker-sbx-codex.md @@ -39,6 +39,10 @@ safe-outputs: run-failure: "🐳🔮 [{workflow_name}]({run_url}) reports {status}. Docker sbx + Codex compatibility issue detected." timeout-minutes: 15 sandbox: + agent: + id: awf + runtime: docker-sbx + sudo: true mcp: version: latest strict: false diff --git a/.github/workflows/smoke-docker-sbx.lock.yml b/.github/workflows/smoke-docker-sbx.lock.yml index d0035c909..5ae068c7c 100644 --- a/.github/workflows/smoke-docker-sbx.lock.yml +++ b/.github/workflows/smoke-docker-sbx.lock.yml @@ -1,15 +1,15 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"2aa04abd7302afdaf0513c4258d8643f2b4951947e257a1517e60bb6bfef0173","body_hash":"831b52f3f9d8ef07ec152f72dd2e49d5c8e208a8742a3f940de10c8f5653898d","compiler_version":"v0.82.1-97-g53fed35aa3","agent_id":"copilot","engine_versions":{"copilot":"1.0.67"}} -# gh-aw-manifest: {"version":1,"secrets":["GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"c8f6736ab6ec57204ee018e5365cac440be629a9","version":"c8f6736ab6ec57204ee018e5365cac440be629a9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.22"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.22"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.22"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.32","digest":"sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.32@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.5.0","digest":"sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4","pinned_image":"ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"b2417d2342d04b758a9789ec726cf2b46eed2d9a8257797c56d44be987b982d4","body_hash":"831b52f3f9d8ef07ec152f72dd2e49d5c8e208a8742a3f940de10c8f5653898d","compiler_version":"v0.82.8-29-ga1dd8bbd65","agent_id":"copilot","engine_versions":{"copilot":"1.0.68"}} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","DOCKER_PAT","DOCKER_USERNAME","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65","version":"a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30","digest":"sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30","digest":"sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30@sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30","digest":"sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.30@sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.32","digest":"sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.32@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.5.0","digest":"sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4","pinned_image":"ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4"}]} # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # -# ___ _ _ -# / _ \ | | (_) -# | |_| | __ _ ___ _ __ | |_ _ ___ +# ___ _ _ +# / _ \ | | (_) +# | |_| | __ _ ___ _ __ | |_ _ ___ # | _ |/ _` |/ _ \ '_ \| __| |/ __| -# | | | | (_| | __/ | | | |_| | (__ +# | | | | (_| | __/ | | | |_| | (__ # \_| |_/\__, |\___|_| |_|\__|_|\___| # __/ | -# _ _ |___/ +# _ _ |___/ # | | | | / _| | # | | | | ___ _ __ _ __| |_| | _____ ____ # | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| @@ -26,6 +26,9 @@ # Smoke Docker Sbx # # Secrets used: +# - COPILOT_GITHUB_TOKEN +# - DOCKER_PAT +# - DOCKER_USERNAME # - GH_AW_GITHUB_MCP_SERVER_TOKEN # - GH_AW_GITHUB_TOKEN # - GITHUB_TOKEN @@ -38,12 +41,12 @@ # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 -# - github/gh-aw/actions/setup@c8f6736ab6ec57204ee018e5365cac440be629a9 +# - github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.27.22 -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.22 -# - ghcr.io/github/gh-aw-firewall/squid:0.27.22 +# - ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30@sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785 +# - ghcr.io/github/gh-aw-firewall/squid:0.27.30@sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a # - ghcr.io/github/gh-aw-mcpg:v0.3.32@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477 # - ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b # - ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4 @@ -52,7 +55,7 @@ name: "Smoke Docker Sbx" on: pull_request: types: - - labeled + - labeled # roles: all # Roles processed as role check in pre-activation job workflow_dispatch: inputs: @@ -99,6 +102,7 @@ jobs: label_command: ${{ steps.get_trigger_label.outputs.label_name }} lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} model: ${{ steps.generate_aw_info.outputs.model }} + oauth_token_check_failed: ${{ steps.check-oauth-tokens.outputs.oauth_token_check_failed == 'true' }} setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} setup-span-id: ${{ steps.setup.outputs.span-id }} setup-trace-id: ${{ steps.setup.outputs.trace-id }} @@ -106,7 +110,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@c8f6736ab6ec57204ee018e5365cac440be629a9 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -115,7 +119,7 @@ jobs: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Docker Sbx" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-docker-sbx.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.34" - GH_AW_INFO_AWF_VERSION: "v0.27.22" + GH_AW_INFO_AWF_VERSION: "v0.27.30" GH_AW_INFO_ENGINE_ID: "copilot" - name: Generate agentic run info id: generate_aw_info @@ -131,7 +135,7 @@ jobs: GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","github"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.27.22" + GH_AW_INFO_AWF_VERSION: "v0.27.30" GH_AW_INFO_AWMG_VERSION: "v0.3.32" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "false" @@ -204,6 +208,13 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/add_reaction.cjs'); await main(); + - name: Check for OAuth tokens + id: check-oauth-tokens + run: bash "${RUNNER_TEMP}/gh-aw/actions/check_oauth_tokens.sh" + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - name: Checkout .github and .agents folders uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: @@ -325,7 +336,7 @@ jobs: - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ {{/if}} - + GH_AW_PROMPT_9fbcad3bf9624399_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" cat << 'GH_AW_PROMPT_9fbcad3bf9624399_EOF' @@ -372,9 +383,9 @@ jobs: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); setupGlobals(core, github, context, exec, io, getOctokit); - + const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs'); - + // Call the substitution function return await substitutePlaceholders({ file: process.env.GH_AW_PROMPT, @@ -464,7 +475,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@c8f6736ab6ec57204ee018e5365cac440be629a9 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -474,7 +485,7 @@ jobs: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Docker Sbx" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-docker-sbx.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.34" - GH_AW_INFO_AWF_VERSION: "v0.27.22" + GH_AW_INFO_AWF_VERSION: "v0.27.30" GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths @@ -494,11 +505,16 @@ jobs: run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" env: GH_TOKEN: ${{ github.token }} + - name: Download activation artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: activation + path: /tmp/gh-aw - env: GH_TOKEN: ${{ github.token }} id: smoke-data name: Pre-compute smoke test data - run: "echo \"::group::Fetching last 2 merged PRs\"\nPR_DATA=$(gh pr list --repo \"$GITHUB_REPOSITORY\" --state merged --limit 2 \\\n --json number,title,author,mergedAt \\\n --jq '.[] | \"PR #\\(.number): \\(.title) (by @\\(.author.login), merged \\(.mergedAt))\"')\necho \"$PR_DATA\"\necho \"::endgroup::\"\n\necho \"::group::GitHub.com connectivity check\"\nHTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 https://github.com)\necho \"github.com returned HTTP $HTTP_CODE\"\necho \"::endgroup::\"\n\necho \"::group::File write/read test\"\nTEST_DIR=\"/tmp/gh-aw/agent\"\nTEST_FILE=\"$TEST_DIR/smoke-test-docker-sbx-${GITHUB_RUN_ID}.txt\"\nmkdir -p \"$TEST_DIR\"\necho \"Smoke test passed for Docker Sbx at $(date)\" > \"$TEST_FILE\"\nFILE_CONTENT=$(cat \"$TEST_FILE\")\necho \"Wrote and read back: $FILE_CONTENT\"\necho \"::endgroup::\"\n\n# Export results for agent context\n{\n echo \"SMOKE_PR_DATA<> \"$GITHUB_OUTPUT\"\n" + run: "echo \"::group::Fetching last 2 merged PRs\"\nPR_DATA=$(gh pr list --repo \"$GITHUB_REPOSITORY\" --state merged --limit 2 \\\n --json number,title,author,mergedAt \\\n --jq '.[] | \"PR #\\(.number): \\(.title) (by @\\(.author.login), merged \\(.mergedAt))\"')\necho \"$PR_DATA\"\necho \"::endgroup::\"\n\necho \"::group::GitHub.com connectivity check\"\nHTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" --max-time 10 https://github.com)\necho \"github.com returned HTTP $HTTP_CODE\"\necho \"::endgroup::\"\n\necho \"::group::File write/read test\"\nTEST_DIR=\"/tmp/gh-aw/agent\"\nTEST_FILE=\"$TEST_DIR/smoke-test-docker-sbx-${GITHUB_RUN_ID}.txt\"\nmkdir -p \"$TEST_DIR\"\necho \"Smoke test passed for Docker Sbx at $(date)\" > \"$TEST_FILE\"\nFILE_CONTENT=$(cat \"$TEST_FILE\")\necho \"Wrote and read back: $FILE_CONTENT\"\necho \"::endgroup::\"\n\n# Export results for agent context\n{\n echo \"SMOKE_PR_DATA<> \"$GITHUB_OUTPUT\"" - name: Configure Git credentials env: @@ -521,11 +537,123 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.67 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.68 env: GH_HOST: github.com - - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.22 --rootless + - name: Check KVM availability for docker-sbx + run: | + set -euo pipefail + echo "::group::KVM availability check" + if ! lsmod | grep -q kvm; then + echo "::error::KVM kernel module is not loaded. docker-sbx requires a KVM-capable runner with nested virtualisation enabled." + exit 1 + fi + if ! test -e /dev/kvm; then + echo "::error::/dev/kvm is missing. docker-sbx requires the KVM device to be present on the runner." + exit 1 + fi + echo "KVM is available and /dev/kvm is present ✅" + echo "::endgroup::" + - name: Check Docker Hub secrets for docker-sbx + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + set -euo pipefail + echo "::group::Docker Hub secrets check" + if [[ -z "${DOCKER_PAT_VAL}" ]]; then + echo "::error::secrets.DOCKER_PAT is empty. docker-sbx requires a Docker Hub personal access token to pull the sandbox template image. Add a DOCKER_PAT secret to your repository." + exit 1 + fi + if [[ -z "${DOCKER_USERNAME_VAL}" ]]; then + echo "::error::secrets.DOCKER_USERNAME is empty. docker-sbx requires a Docker Hub username. Add a DOCKER_USERNAME secret to your repository." + exit 1 + fi + echo "Docker Hub secrets are present ✅" + echo "::endgroup::" + - name: Install docker-sbx + run: | + set -euo pipefail + echo "::group::Install docker-sbx" + # Add Docker apt repo without installing Docker Engine (already present). + curl -fsSL https://get.docker.com | sudo REPO_ONLY=1 sh + sudo apt-get install -y docker-sbx + sbx version + # Fix KVM permissions so the runner user can create microVMs. + sudo chmod 666 /dev/kvm + echo "docker-sbx installed successfully ✅" + echo "::endgroup::" + - name: Start docker-sbx daemon and authenticate + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + set -euo pipefail + export DOCKER_CONFIG="$(mktemp -d)" + trap 'rm -rf "${DOCKER_CONFIG}"' EXIT + echo "::group::Start sbx daemon" + nohup sbx daemon start > /tmp/sbx-daemon.log 2>&1 & + # Poll until daemon is running (up to 10 s). + for i in $(seq 1 10); do + if sbx daemon status 2>/dev/null | grep -q -i running; then + echo "sbx daemon is running" + break + fi + sleep 1 + done + echo "::endgroup::" + echo "::group::Authenticate with Docker Hub" + printf '%s' "${DOCKER_PAT_VAL}" | docker login --username "${DOCKER_USERNAME_VAL}" --password-stdin + printf '%s' "${DOCKER_PAT_VAL}" | sbx login --username "${DOCKER_USERNAME_VAL}" --password-stdin + echo "::endgroup::" + echo "::group::Reset and initialise sbx policy" + sbx daemon stop || true + sbx policy reset --force || true + sbx policy init allow-all + nohup sbx daemon start > /tmp/sbx-daemon.log 2>&1 & + for i in $(seq 1 10); do + if sbx daemon status 2>/dev/null | grep -q -i running; then + echo "sbx daemon restarted" + break + fi + sleep 1 + done + printf '%s' "${DOCKER_PAT_VAL}" | docker login --username "${DOCKER_USERNAME_VAL}" --password-stdin + printf '%s' "${DOCKER_PAT_VAL}" | sbx login --username "${DOCKER_USERNAME_VAL}" --password-stdin + echo "::endgroup::" + echo "::group::Pre-pull sandbox template image" + docker pull docker/sandbox-templates:shell-docker + echo "Template image ready ✅" + echo "::endgroup::" + - name: docker-sbx pre-flight smoke test + run: | + set -euo pipefail + echo "::group::docker-sbx pre-flight smoke test" + sandbox_name="test-sandbox-direct" + cleanup() { + sbx stop "${sandbox_name}" >/dev/null 2>&1 || true + sbx rm --force "${sandbox_name}" >/dev/null 2>&1 || true + } + trap cleanup EXIT + echo "y" | sbx create shell --name "${sandbox_name}" "${GITHUB_WORKSPACE}" + sbx exec "${sandbox_name}" uname -a + sbx stop "${sandbox_name}" + echo "✅ sbx ready" + echo "::endgroup::" + - name: Install AWF binary (from source — includes stdin pipe fix) + run: | + set -euo pipefail + cd "${GITHUB_WORKSPACE}" + npm ci + npm run build + cat > /usr/local/bin/awf <<'WRAPPER' + #!/usr/bin/env bash + exec node "$(dirname "$(readlink -f "$0")")/../lib/node_modules/@github/awf/dist/cli.js" "$@" + WRAPPER + chmod +x /usr/local/bin/awf + mkdir -p /usr/local/lib/node_modules/@github/awf + cp -r dist package.json node_modules containers /usr/local/lib/node_modules/@github/awf/ + awf --version || echo "awf installed (source build)" - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) @@ -536,11 +664,6 @@ jobs: script: | const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs'); await determineAutomaticLockdown(github, context, core); - - name: Download activation artifact - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: activation - path: /tmp/gh-aw - name: Restore agent config folders from base branch if: steps.checkout-pr.outcome == 'success' env: @@ -557,7 +680,7 @@ jobs: GH_AW_SKILL_DIR: ".github/skills" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.22 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.22 ghcr.io/github/gh-aw-firewall/squid:0.27.22 ghcr.io/github/gh-aw-mcpg:v0.3.32@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477 ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.30@sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.30@sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785 ghcr.io/github/gh-aw-firewall/squid:0.27.30@sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a ghcr.io/github/gh-aw-mcpg:v0.3.32@sha256:63e46b56dfd70895a701b6fc6dd0189e11e2d875f327f1781e81b31848735477 ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4 - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" @@ -712,11 +835,11 @@ jobs: run: | set -eo pipefail mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config" - + # Export gateway environment variables for MCP config and gateway script export MCP_GATEWAY_PORT="8080" - export MCP_GATEWAY_DOMAIN="awmg-mcpg" - export MCP_GATEWAY_HOST_DOMAIN="localhost" + export MCP_GATEWAY_DOMAIN="host.docker.internal" + export MCP_GATEWAY_HOST_DOMAIN="host.docker.internal" MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') echo "::add-mask::${MCP_GATEWAY_API_KEY}" export MCP_GATEWAY_API_KEY @@ -724,21 +847,16 @@ jobs: mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" export DEBUG="*" - + export GH_AW_ENGINE="copilot" MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') - case "${DOCKER_HOST:-}" in - unix://* ) DOCKER_SOCK_PATH="${DOCKER_HOST#unix://}" ;; - /* ) DOCKER_SOCK_PATH="$DOCKER_HOST" ;; - * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; - esac - DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 127.0.0.1:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.3.32' - + source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh" + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 0.0.0.0:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.3.32' + mkdir -p "$HOME/.copilot" GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_6d07dd66db4da6da_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_bc7e27cd2f1d24d8_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { @@ -776,6 +894,7 @@ jobs: "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}", "GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST": "\${GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST}", "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}", + "GITHUB_SHA": "\${GITHUB_SHA}", "GITHUB_TOKEN": "\${GITHUB_TOKEN}", "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}", "RUNNER_TEMP": "\${RUNNER_TEMP}" @@ -784,7 +903,8 @@ jobs: "write-sink": { "accept": [ "*" - ] + ], + "sink-visibility": ${{ toJSON(steps.determine-automatic-lockdown.outputs.visibility) }} } } } @@ -796,7 +916,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_6d07dd66db4da6da_EOF + GH_AW_MCP_CONFIG_bc7e27cd2f1d24d8_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true @@ -818,6 +938,15 @@ jobs: id: pre_agent_audit continue-on-error: true run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh" + - name: Refresh sbx credentials + env: + DOCKER_PAT_VAL: ${{ secrets.DOCKER_PAT }} + DOCKER_USERNAME_VAL: ${{ secrets.DOCKER_USERNAME }} + run: | + # Re-authenticate sbx immediately before AWF runs. + # Docker Hub OAuth tokens from sbx login can expire between steps. + printf '%s' "$DOCKER_PAT_VAL" | sbx login --username "$DOCKER_USERNAME_VAL" --password-stdin + echo "✅ sbx credentials refreshed" - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): @@ -836,16 +965,14 @@ jobs: export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-1000}" - printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.22/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.githubusercontent.com\",\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"codeload.github.com\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"docs.github.com\",\"github-cloud.githubusercontent.com\",\"github-cloud.s3.amazonaws.com\",\"github.blog\",\"github.com\",\"github.githubassets.com\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"keyserver.ubuntu.com\",\"lfs.github.com\",\"objects.githubusercontent.com\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"patch-diff.githubusercontent.com\",\"patchdiff.githubusercontent.com\",\"ppa.launchpad.net\",\"raw.githubusercontent.com\",\"registry.npmjs.org\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"telemetry.enterprise.githubcopilot.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\"],\"isolation\":true,\"topologyAttach\":[\"awmg-mcpg\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.5\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"large\":[\"fable\",\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.22\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.30/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.githubusercontent.com\",\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"codeload.github.com\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"docs.github.com\",\"github-cloud.githubusercontent.com\",\"github-cloud.s3.amazonaws.com\",\"github.blog\",\"github.com\",\"github.githubassets.com\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"keyserver.ubuntu.com\",\"lfs.github.com\",\"objects.githubusercontent.com\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"patch-diff.githubusercontent.com\",\"patchdiff.githubusercontent.com\",\"ppa.launchpad.net\",\"raw.githubusercontent.com\",\"registry.npmjs.org\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"telemetry.enterprise.githubcopilot.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\"],\"isolation\":true,\"topologyAttach\":[\"awmg-mcpg\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"fable\",\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.30,squid=sha256:eb74fca5309c7542df0f32aef41b92c728ecef7ac3b0cca9f9a6b97cc324d22a,agent=sha256:3cc1e14efa9e52ed1fc29d72a0eabf02ff86b30c6af9685fa9ddd687caca6613,agent-act=sha256:d0beee47dd38e2df577d15b9ddf763a2b771367326fecb02e1aa924bc395954a,api-proxy=sha256:fdbd94bb668ed736a27c146633842db5c7e658dc7a0d6a0e6011e74e18132785,cli-proxy=sha256:959c876217038ac6f9c2047b591e819e5f1f726625a34490ccdcacaa71d83e4c\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" GH_AW_DOCKER_HOST="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then GH_AW_DOCKER_HOST="${DOCKER_HOST}" fi - GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then - GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix ${RUNNER_TEMP}/gh-aw" GH_AW_CHROOT_BINARIES_SOURCE_PATH="${RUNNER_TEMP}/gh-aw" GH_AW_CHROOT_IDENTITY_HOME="${RUNNER_TEMP}/gh-aw/home" node "${RUNNER_TEMP}/gh-aw/actions/patch_awf_chroot_config.cjs" fi GH_AW_TOOL_CACHE_MOUNT="" @@ -856,8 +983,8 @@ jobs: fi fi # shellcheck disable=SC1003,SC2016,SC2086 - awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --skip-pull \ - -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; export PATH="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --container-runtime sbx --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --skip-pull \ + -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; export PATH="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE @@ -922,7 +1049,9 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); await main(); env: - GH_AW_SECRET_NAMES: 'GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + GH_AW_SECRET_NAMES: 'DOCKER_PAT,DOCKER_USERNAME,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + SECRET_DOCKER_PAT: ${{ secrets.DOCKER_PAT }} + SECRET_DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -957,6 +1086,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -978,13 +1108,7 @@ jobs: continue-on-error: true env: AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs - run: | - # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) - if command -v awf &> /dev/null; then - awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" - else - echo 'AWF binary not installed, skipping firewall log summary' - fi + run: bash "${RUNNER_TEMP}/gh-aw/actions/print_firewall_logs.sh" --rootless - name: Parse token usage for step summary if: always() continue-on-error: true @@ -1012,7 +1136,7 @@ jobs: echo '{"items":[]}' > /tmp/gh-aw/agent_output.json fi - name: Validate safe outputs were invoked - run: "OUTPUTS_FILE=\"${GH_AW_SAFE_OUTPUTS:-${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl}\"\nif [ ! -s \"$OUTPUTS_FILE\" ]; then\n echo \"::error::No safe outputs were invoked. Smoke tests require the agent to call safe output tools.\"\n echo \"Checked path: $OUTPUTS_FILE\"\n exit 1\nfi\necho \"Safe output entries found: $(wc -l < \"$OUTPUTS_FILE\")\"\nif [ \"$GITHUB_EVENT_NAME\" = \"pull_request\" ]; then\n if ! grep -q '\"add_comment\"' \"$OUTPUTS_FILE\"; then\n echo \"::error::Agent did not call add_comment on a pull_request trigger.\"\n exit 1\n fi\n echo \"add_comment verified for PR trigger\"\nfi\necho \"Safe output validation passed\"\n" + run: "OUTPUTS_FILE=\"${GH_AW_SAFE_OUTPUTS:-${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl}\"\nif [ ! -s \"$OUTPUTS_FILE\" ]; then\n echo \"::error::No safe outputs were invoked. Smoke tests require the agent to call safe output tools.\"\n echo \"Checked path: $OUTPUTS_FILE\"\n exit 1\nfi\necho \"Safe output entries found: $(wc -l < \"$OUTPUTS_FILE\")\"\nif [ \"$GITHUB_EVENT_NAME\" = \"pull_request\" ]; then\n if ! grep -q '\"add_comment\"' \"$OUTPUTS_FILE\"; then\n echo \"::error::Agent did not call add_comment on a pull_request trigger.\"\n exit 1\n fi\n echo \"add_comment verified for PR trigger\"\nfi\necho \"Safe output validation passed\"" - name: Upload agent artifacts if: always() @@ -1046,7 +1170,8 @@ jobs: - verify_token_usage if: > always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' || - needs.activation.outputs.stale_lock_file_failed == 'true' || needs.activation.outputs.daily_ai_credits_exceeded == 'true') + needs.activation.outputs.oauth_token_check_failed == 'true' || needs.activation.outputs.stale_lock_file_failed == 'true' || + needs.activation.outputs.secret_verification_result == 'failed' || needs.activation.outputs.daily_ai_credits_exceeded == 'true') runs-on: ubuntu-slim permissions: contents: read @@ -1066,7 +1191,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@c8f6736ab6ec57204ee018e5365cac440be629a9 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1075,8 +1200,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Docker Sbx" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-docker-sbx.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.67" - GH_AW_INFO_AWF_VERSION: "v0.27.22" + GH_AW_INFO_VERSION: "1.0.68" + GH_AW_INFO_AWF_VERSION: "v0.27.30" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output @@ -1092,6 +1217,14 @@ jobs: mkdir -p /tmp/gh-aw/ find "/tmp/gh-aw/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Download safe outputs items manifest + id: download-safe-outputs-manifest + if: always() + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: safe-outputs-items + path: /tmp/gh-aw/ - name: Collect usage artifact files if: always() continue-on-error: true @@ -1251,6 +1384,7 @@ jobs: GH_AW_HTTP_400_RESPONSE_ERROR: ${{ needs.agent.outputs.http_400_response_error }} GH_AW_ENGINE_API_HOSTS: "api.enterprise.githubcopilot.com,api.githubcopilot.com,api.business.githubcopilot.com,api.individual.githubcopilot.com" GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} + GH_AW_OAUTH_TOKEN_CHECK_FAILED: ${{ needs.activation.outputs.oauth_token_check_failed }} GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }} GH_AW_DAILY_AI_CREDITS_TOTAL_EFFECTIVE_TOKENS: ${{ needs.activation.outputs.daily_ai_credits_total_effective_tokens }} @@ -1307,7 +1441,7 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} - GH_AW_ENGINE_VERSION: "1.0.67" + GH_AW_ENGINE_VERSION: "1.0.68" GH_AW_LABEL_COMMANDS: "[\"ready-for-aw\"]" GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e 📰 *BREAKING: Report filed by [{workflow_name}]({run_url})*\",\"runStarted\":\"📰 BREAKING: [{workflow_name}]({run_url}) is now investigating this {event_type}. Sources say the story is developing...\",\"runSuccess\":\"📰 VERDICT: [{workflow_name}]({run_url}) has concluded. All systems operational. This is a developing story. 🎤\",\"runFailure\":\"📰 DEVELOPING STORY: [{workflow_name}]({run_url}) reports {status}. Our correspondents are investigating the incident...\"}" @@ -1326,7 +1460,7 @@ jobs: steps: - name: Setup Scripts id: setup - uses: github/gh-aw/actions/setup@c8f6736ab6ec57204ee018e5365cac440be629a9 + uses: github/gh-aw/actions/setup@a1dd8bbd6543f6dc7e76c3169cb6c2b122ccfc65 with: destination: ${{ runner.temp }}/gh-aw/actions job-name: ${{ github.job }} @@ -1335,8 +1469,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Docker Sbx" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-docker-sbx.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.67" - GH_AW_INFO_AWF_VERSION: "v0.27.22" + GH_AW_INFO_VERSION: "1.0.68" + GH_AW_INFO_AWF_VERSION: "v0.27.30" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output @@ -1416,4 +1550,3 @@ jobs: path: /tmp/gh-aw-agent - name: Token-usage sanity check run: node scripts/ci/check-token-usage.js --artifact-root /tmp/gh-aw-agent --engine copilot - diff --git a/.github/workflows/smoke-docker-sbx.md b/.github/workflows/smoke-docker-sbx.md index 36b8fd300..6825cc797 100644 --- a/.github/workflows/smoke-docker-sbx.md +++ b/.github/workflows/smoke-docker-sbx.md @@ -41,6 +41,10 @@ safe-outputs: run-failure: "📰 DEVELOPING STORY: [{workflow_name}]({run_url}) reports {status}. Our correspondents are investigating the incident..." timeout-minutes: 15 sandbox: + agent: + id: awf + runtime: docker-sbx + sudo: true mcp: version: v0.3.32 strict: false diff --git a/src/sbx-manager.test.ts b/src/sbx-manager.test.ts index 91c866e9e..3c1e5ec2a 100644 --- a/src/sbx-manager.test.ts +++ b/src/sbx-manager.test.ts @@ -104,13 +104,12 @@ describe('sbx-manager', () => { process.env.HOME || '/home/runner', ], expect.objectContaining({ input: 'y\n', - env: expect.objectContaining({ - DOCKER_SANDBOXES_PROXY: 'http://172.30.0.10:3128', - }), })); - // XDG_CONFIG_HOME must not reach the sbx CLI - const sbxCreateCallEnv: Record = mockExecaFn.mock.calls[1][2].env; - expect(sbxCreateCallEnv).not.toMatchObject({ XDG_CONFIG_HOME: expect.anything() }); + // sbx create must NOT pass a custom env — it inherits process.env so the + // sbx CLI can find daemon credentials. The sandbox interior is isolated + // separately by execInSandbox() which uses sanitizeEnvForSbx(). + const sbxCreateCall = mockExecaFn.mock.calls[1][2]; + expect(sbxCreateCall.env).toBeUndefined(); }); it('uses SBX_DEFAULT_NAME when no name provided', async () => { @@ -126,36 +125,31 @@ describe('sbx-manager', () => { expect(name).toBe(SBX_DEFAULT_NAME); }); - it('uses default squidPort 3128 when not specified', async () => { + it('does not pass custom env during create (inherits process.env)', async () => { mockExecaFn .mockResolvedValueOnce({ exitCode: 0, stdout: '', stderr: '' }) .mockResolvedValueOnce({ exitCode: 0, stdout: 'Created sandbox', stderr: '' }); await createSandbox({ workspaceDir: '/ws', squidIp: '172.30.0.10' }); - expect(mockExecaFn).toHaveBeenCalledWith( - 'sbx', - expect.arrayContaining(['create']), - expect.objectContaining({ - env: expect.objectContaining({ DOCKER_SANDBOXES_PROXY: 'http://172.30.0.10:3128' }), - }), - ); + const sbxCreateCall = mockExecaFn.mock.calls[1][2]; + expect(sbxCreateCall.env).toBeUndefined(); }); - it('uses custom squidPort when specified', async () => { + it('temporarily removes DOCKER_SANDBOXES_PROXY and XDG_CONFIG_HOME during create', async () => { + process.env.DOCKER_SANDBOXES_PROXY = 'http://old-proxy:3128'; + process.env.XDG_CONFIG_HOME = '/home/runner'; mockExecaFn .mockResolvedValueOnce({ exitCode: 0, stdout: '', stderr: '' }) .mockResolvedValueOnce({ exitCode: 0, stdout: 'Created sandbox', stderr: '' }); await createSandbox({ workspaceDir: '/ws', squidIp: '172.30.0.10', squidPort: 8080 }); - expect(mockExecaFn).toHaveBeenCalledWith( - 'sbx', - expect.arrayContaining(['create']), - expect.objectContaining({ - env: expect.objectContaining({ DOCKER_SANDBOXES_PROXY: 'http://172.30.0.10:8080' }), - }), - ); + // Both should be restored after create + expect(process.env.DOCKER_SANDBOXES_PROXY).toBe('http://old-proxy:3128'); + expect(process.env.XDG_CONFIG_HOME).toBe('/home/runner'); + delete process.env.DOCKER_SANDBOXES_PROXY; + delete process.env.XDG_CONFIG_HOME; }); it('throws when auth check fails (non-zero exit)', async () => { diff --git a/src/sbx-manager.ts b/src/sbx-manager.ts index 72c92a81f..417db434d 100644 --- a/src/sbx-manager.ts +++ b/src/sbx-manager.ts @@ -157,18 +157,39 @@ export async function createSandbox(config: SbxConfig): Promise { logger.info(`[sbx] Running: sbx ${args.join(' ')}`); - const env = sanitizeEnvForSbx(); - delete env.XDG_CONFIG_HOME; - env.DOCKER_SANDBOXES_PROXY = proxyUrl; + // Do NOT pass a custom `env` to sbx create. The sanitized env (which strips + // vars matching TOKEN, SECRET, KEY, etc.) also strips variables the sbx CLI + // needs internally for credential lookup against the daemon's auth store. + // Since sbx create is a management command that talks to the local daemon + // (not user code running inside the sandbox), inheriting process.env is safe — + // these env vars never enter the sandbox interior. The sandbox interior's env + // is controlled separately by execInSandbox() which uses sanitizeEnvForSbx(). + // + // DOCKER_SANDBOXES_PROXY must NOT be set during create — it forces the daemon + // to route Docker Hub registry auth through Squid, which isn't ready yet. + // XDG_CONFIG_HOME must also be removed — the Copilot harness sets it to $HOME, + // which makes the sbx CLI look for credentials in $HOME/ instead of the + // default $HOME/.config/ where `sbx login` stored them. + const savedProxy = process.env.DOCKER_SANDBOXES_PROXY; + const savedXdg = process.env.XDG_CONFIG_HOME; + delete process.env.DOCKER_SANDBOXES_PROXY; + delete process.env.XDG_CONFIG_HOME; const createResult = await execa('sbx', args, { - env, input: 'y\n', - stdio: ['ignore', 'pipe', 'pipe'], + stdio: ['pipe', 'pipe', 'pipe'], reject: false, timeout: 120_000, // 2 minute timeout for sandbox creation }); + // Restore env vars + if (savedProxy !== undefined) { + process.env.DOCKER_SANDBOXES_PROXY = savedProxy; + } + if (savedXdg !== undefined) { + process.env.XDG_CONFIG_HOME = savedXdg; + } + const stdout = (createResult.stdout || '').trim(); const stderr = (createResult.stderr || '').trim(); const sbxSucceeded = stdout.includes('Created sandbox');