From 5c6b07f314cb004933ba592ea2b6794b1ba19604 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 12:58:27 +0000 Subject: [PATCH 1/4] chore: prepare for sandbox.agent id defaulting fix Agent-Logs-Url: https://github.com/github/gh-aw/sessions/e8273d71-b787-4a08-9ed6-0803b71440bf Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/stale-pr-cleanup.lock.yml | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/stale-pr-cleanup.lock.yml b/.github/workflows/stale-pr-cleanup.lock.yml index 654e891948..885ba45c79 100644 --- a/.github/workflows/stale-pr-cleanup.lock.yml +++ b/.github/workflows/stale-pr-cleanup.lock.yml @@ -1,5 +1,5 @@ # gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"07e071eb8a3e78f3eecb8071e562e1f8291f76cb7a7610e5e007f8d4d12f0a43","strict":true,"agent_id":"copilot"} -# gh-aw-manifest: {"version":1,"secrets":["GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.38"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.38"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.25.38"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.38"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.6"},{"image":"ghcr.io/github/github-mcp-server:v1.0.3","digest":"sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} +# gh-aw-manifest: {"version":1,"secrets":["GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.39"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.39"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.25.39"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.39"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.6"},{"image":"ghcr.io/github/github-mcp-server:v1.0.3","digest":"sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -38,10 +38,10 @@ # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.25.38 -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.38 -# - ghcr.io/github/gh-aw-firewall/cli-proxy:0.25.38 -# - ghcr.io/github/gh-aw-firewall/squid:0.25.38 +# - ghcr.io/github/gh-aw-firewall/agent:0.25.39 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.39 +# - ghcr.io/github/gh-aw-firewall/cli-proxy:0.25.39 +# - ghcr.io/github/gh-aw-firewall/squid:0.25.39 # - ghcr.io/github/gh-aw-mcpg:v0.3.6 # - ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 # - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f @@ -112,7 +112,7 @@ jobs: GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.25.38" + GH_AW_INFO_AWF_VERSION: "v0.25.39" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_COMPILED_STRICT: "true" @@ -393,7 +393,7 @@ jobs: env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.38 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.39 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 @@ -416,7 +416,7 @@ jobs: GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.38 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.38 ghcr.io/github/gh-aw-firewall/cli-proxy:0.25.38 ghcr.io/github/gh-aw-firewall/squid:0.25.38 ghcr.io/github/gh-aw-mcpg:v0.3.6 ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.39 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.39 ghcr.io/github/gh-aw-firewall/cli-proxy:0.25.39 ghcr.io/github/gh-aw-firewall/squid:0.25.39 ghcr.io/github/gh-aw-mcpg:v0.3.6 ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" @@ -734,7 +734,7 @@ jobs: GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN (umask 177 && touch /tmp/gh-aw/agent-stdio.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.38/awf-config.schema.json","network":{"allowDomains":["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","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","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.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","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"]},"apiProxy":{"enabled":true},"container":{"imageTag":"0.25.38"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.39/awf-config.schema.json","network":{"allowDomains":["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","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","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.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","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"]},"apiProxy":{"enabled":true},"container":{"imageTag":"0.25.39"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json # shellcheck disable=SC1003 sudo -E 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" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GH_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull --difc-proxy-host host.docker.internal:18443 --difc-proxy-ca-cert /tmp/gh-aw/difc-proxy-tls/ca.crt \ -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -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 || echo node)"; 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-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date *)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq *)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --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 @@ -1135,7 +1135,7 @@ jobs: rm -rf /tmp/gh-aw/sandbox/firewall/logs rm -rf /tmp/gh-aw/sandbox/firewall/audit - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.38 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.38 ghcr.io/github/gh-aw-firewall/squid:0.25.38 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.39 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.39 ghcr.io/github/gh-aw-firewall/squid:0.25.39 - name: Check if detection needed id: detection_guard if: always() @@ -1198,7 +1198,7 @@ jobs: env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.38 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.39 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' continue-on-error: true @@ -1211,7 +1211,7 @@ jobs: GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.38/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true},"container":{"imageTag":"0.25.38"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.39/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true},"container":{"imageTag":"0.25.39"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json # shellcheck disable=SC1003 sudo -E 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" --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -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 || echo node)"; 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 --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log From 6882fabf49c31a859eb216fca646e8fd9f156e4a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 13:02:17 +0000 Subject: [PATCH 2/4] fix: default sandbox.agent id to awf instead of requiring explicit id in strict mode Agent-Logs-Url: https://github.com/github/gh-aw/sessions/e8273d71-b787-4a08-9ed6-0803b71440bf Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/strict_mode_sandbox_validation.go | 17 +---------------- .../strict_mode_sandbox_validation_test.go | 18 ++++++++---------- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/pkg/workflow/strict_mode_sandbox_validation.go b/pkg/workflow/strict_mode_sandbox_validation.go index 3fbcbb4163..06e646d70e 100644 --- a/pkg/workflow/strict_mode_sandbox_validation.go +++ b/pkg/workflow/strict_mode_sandbox_validation.go @@ -6,7 +6,6 @@ package workflow import ( - "errors" "fmt" ) @@ -29,8 +28,7 @@ func internalSandboxFieldError(fieldPath string) error { // - sandbox.mcp.container, sandbox.mcp.version, sandbox.mcp.entrypoint, // sandbox.mcp.args, sandbox.mcp.entrypointArgs (MCP gateway customization) // -// Additionally, a sandbox.agent object without an explicit 'id' field is rejected in -// strict mode: users must be unambiguous about which sandbox they are enabling. +// A sandbox.agent object without an explicit 'id' is allowed and defaults to awf. func (c *Compiler) validateStrictSandboxCustomization(sandboxConfig *SandboxConfig) error { if !c.strictMode { strictModeValidationLog.Printf("Strict mode disabled, skipping sandbox customization validation") @@ -43,19 +41,6 @@ func (c *Compiler) validateStrictSandboxCustomization(sandboxConfig *SandboxConf // Check agent sandbox internal fields if agent := sandboxConfig.Agent; agent != nil { - // In strict mode, sandbox.agent must carry an explicit type/id so the sandbox - // configuration is unambiguous. A bare object (e.g. { version: "v0.25.29" } - // with no id) would silently default to AWF in non-strict builds but that - // implicit defaulting is not acceptable in strict mode. - if !agent.Disabled && !isSupportedSandboxType(getAgentType(agent)) { - return errors.New( - "strict mode: 'sandbox.agent' must specify an explicit 'id' (e.g., id: awf). " + - "A sandbox agent without an 'id' is ambiguous and not allowed in strict mode. " + - "Add 'id: awf' to your sandbox.agent configuration. " + - "See: https://github.github.com/gh-aw/reference/sandbox/", - ) - } - if agent.Command != "" { return internalSandboxFieldError("sandbox.agent.command") } diff --git a/pkg/workflow/strict_mode_sandbox_validation_test.go b/pkg/workflow/strict_mode_sandbox_validation_test.go index 09de46894b..82c2308643 100644 --- a/pkg/workflow/strict_mode_sandbox_validation_test.go +++ b/pkg/workflow/strict_mode_sandbox_validation_test.go @@ -134,26 +134,24 @@ func TestValidateStrictSandboxCustomization(t *testing.T) { expectError: false, }, { - // A bare sandbox.agent object with no id/type is ambiguous and must be - // rejected in strict mode. Users must write id: awf explicitly. - name: "sandbox.agent without id is rejected in strict mode", + // A bare sandbox.agent object with no id/type defaults to awf. + // It should be accepted in strict mode. + name: "sandbox.agent without id is allowed in strict mode (defaults to awf)", sandbox: &SandboxConfig{ Agent: &AgentSandboxConfig{ Version: "v0.25.29", }, }, - expectError: true, - errorMsg: "strict mode: 'sandbox.agent' must specify an explicit 'id'", + expectError: false, }, { - // An empty AgentSandboxConfig (no id, no type, no version) is equally - // ambiguous and must be rejected in strict mode. - name: "empty sandbox.agent is rejected in strict mode", + // An empty AgentSandboxConfig (no id, no type, no version) also defaults to awf. + // It should be accepted in strict mode. + name: "empty sandbox.agent is allowed in strict mode (defaults to awf)", sandbox: &SandboxConfig{ Agent: &AgentSandboxConfig{}, }, - expectError: true, - errorMsg: "strict mode: 'sandbox.agent' must specify an explicit 'id'", + expectError: false, }, { // sandbox.agent: false (Disabled) is handled by validateStrictFirewall, not here. From 736cf94b572f4b6dea79b72af41061822074baf9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 13:03:29 +0000 Subject: [PATCH 3/4] fix: capitalize AWF consistently in comments Agent-Logs-Url: https://github.com/github/gh-aw/sessions/e8273d71-b787-4a08-9ed6-0803b71440bf Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/strict_mode_sandbox_validation.go | 2 +- pkg/workflow/strict_mode_sandbox_validation_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/workflow/strict_mode_sandbox_validation.go b/pkg/workflow/strict_mode_sandbox_validation.go index 06e646d70e..dde46b9794 100644 --- a/pkg/workflow/strict_mode_sandbox_validation.go +++ b/pkg/workflow/strict_mode_sandbox_validation.go @@ -28,7 +28,7 @@ func internalSandboxFieldError(fieldPath string) error { // - sandbox.mcp.container, sandbox.mcp.version, sandbox.mcp.entrypoint, // sandbox.mcp.args, sandbox.mcp.entrypointArgs (MCP gateway customization) // -// A sandbox.agent object without an explicit 'id' is allowed and defaults to awf. +// A sandbox.agent object without an explicit 'id' is allowed and defaults to AWF. func (c *Compiler) validateStrictSandboxCustomization(sandboxConfig *SandboxConfig) error { if !c.strictMode { strictModeValidationLog.Printf("Strict mode disabled, skipping sandbox customization validation") diff --git a/pkg/workflow/strict_mode_sandbox_validation_test.go b/pkg/workflow/strict_mode_sandbox_validation_test.go index 82c2308643..215324e9d7 100644 --- a/pkg/workflow/strict_mode_sandbox_validation_test.go +++ b/pkg/workflow/strict_mode_sandbox_validation_test.go @@ -134,7 +134,7 @@ func TestValidateStrictSandboxCustomization(t *testing.T) { expectError: false, }, { - // A bare sandbox.agent object with no id/type defaults to awf. + // A bare sandbox.agent object with no id/type defaults to AWF. // It should be accepted in strict mode. name: "sandbox.agent without id is allowed in strict mode (defaults to awf)", sandbox: &SandboxConfig{ @@ -145,7 +145,7 @@ func TestValidateStrictSandboxCustomization(t *testing.T) { expectError: false, }, { - // An empty AgentSandboxConfig (no id, no type, no version) also defaults to awf. + // An empty AgentSandboxConfig (no id, no type, no version) also defaults to AWF. // It should be accepted in strict mode. name: "empty sandbox.agent is allowed in strict mode (defaults to awf)", sandbox: &SandboxConfig{ From 188e315e7947ccd0dd0db923983cf6812187bfd3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 13:18:28 +0000 Subject: [PATCH 4/4] fix: explicitly set sandbox.agent type to AWF in strict mode when id is empty Agent-Logs-Url: https://github.com/github/gh-aw/sessions/01b042cb-deca-4a8a-beee-8ac62f9dd027 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../strict_mode_sandbox_validation.go | 9 ++++- .../strict_mode_sandbox_validation_test.go | 40 +++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/pkg/workflow/strict_mode_sandbox_validation.go b/pkg/workflow/strict_mode_sandbox_validation.go index dde46b9794..744ef37eca 100644 --- a/pkg/workflow/strict_mode_sandbox_validation.go +++ b/pkg/workflow/strict_mode_sandbox_validation.go @@ -28,7 +28,7 @@ func internalSandboxFieldError(fieldPath string) error { // - sandbox.mcp.container, sandbox.mcp.version, sandbox.mcp.entrypoint, // sandbox.mcp.args, sandbox.mcp.entrypointArgs (MCP gateway customization) // -// A sandbox.agent object without an explicit 'id' is allowed and defaults to AWF. +// A sandbox.agent object without an explicit 'id' is explicitly set to AWF in strict mode. func (c *Compiler) validateStrictSandboxCustomization(sandboxConfig *SandboxConfig) error { if !c.strictMode { strictModeValidationLog.Printf("Strict mode disabled, skipping sandbox customization validation") @@ -41,6 +41,13 @@ func (c *Compiler) validateStrictSandboxCustomization(sandboxConfig *SandboxConf // Check agent sandbox internal fields if agent := sandboxConfig.Agent; agent != nil { + // In strict mode, if sandbox.agent has no id/type set, explicitly default it to AWF + // so the sandbox configuration is always unambiguous. + if !agent.Disabled && !isSupportedSandboxType(getAgentType(agent)) { + strictModeValidationLog.Printf("sandbox.agent has no id/type in strict mode, defaulting to awf") + agent.Type = SandboxTypeAWF + } + if agent.Command != "" { return internalSandboxFieldError("sandbox.agent.command") } diff --git a/pkg/workflow/strict_mode_sandbox_validation_test.go b/pkg/workflow/strict_mode_sandbox_validation_test.go index 215324e9d7..f706252be4 100644 --- a/pkg/workflow/strict_mode_sandbox_validation_test.go +++ b/pkg/workflow/strict_mode_sandbox_validation_test.go @@ -134,8 +134,7 @@ func TestValidateStrictSandboxCustomization(t *testing.T) { expectError: false, }, { - // A bare sandbox.agent object with no id/type defaults to AWF. - // It should be accepted in strict mode. + // A bare sandbox.agent object with no id/type is explicitly set to AWF in strict mode. name: "sandbox.agent without id is allowed in strict mode (defaults to awf)", sandbox: &SandboxConfig{ Agent: &AgentSandboxConfig{ @@ -145,8 +144,7 @@ func TestValidateStrictSandboxCustomization(t *testing.T) { expectError: false, }, { - // An empty AgentSandboxConfig (no id, no type, no version) also defaults to AWF. - // It should be accepted in strict mode. + // An empty AgentSandboxConfig (no id, no type, no version) is explicitly set to AWF in strict mode. name: "empty sandbox.agent is allowed in strict mode (defaults to awf)", sandbox: &SandboxConfig{ Agent: &AgentSandboxConfig{}, @@ -213,3 +211,37 @@ func TestValidateStrictSandboxCustomizationNonStrictMode(t *testing.T) { t.Errorf("Expected non-strict mode to allow all sandbox fields, got error: %v", err) } } + +// TestValidateStrictSandboxCustomizationSetsAWFDefault verifies that in strict mode +// a sandbox.agent with no id/type is explicitly set to AWF. +func TestValidateStrictSandboxCustomizationSetsAWFDefault(t *testing.T) { + tests := []struct { + name string + agent *AgentSandboxConfig + }{ + { + name: "version-only agent gets AWF type", + agent: &AgentSandboxConfig{Version: "v0.25.29"}, + }, + { + name: "empty agent gets AWF type", + agent: &AgentSandboxConfig{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + compiler := NewCompiler() + compiler.strictMode = true + + sandbox := &SandboxConfig{Agent: tt.agent} + err := compiler.validateStrictSandboxCustomization(sandbox) + if err != nil { + t.Errorf("Expected validation to succeed but it failed: %v", err) + } + if sandbox.Agent.Type != SandboxTypeAWF { + t.Errorf("Expected sandbox.agent.Type to be %q after strict mode validation, got %q", SandboxTypeAWF, sandbox.Agent.Type) + } + }) + } +}