diff --git a/.changeset/patch-add-runtime-mount-manager.md b/.changeset/patch-add-runtime-mount-manager.md new file mode 100644 index 0000000000..13aae6167f --- /dev/null +++ b/.changeset/patch-add-runtime-mount-manager.md @@ -0,0 +1,10 @@ +--- +"gh-aw": patch +--- + +Add a runtime mount manager that contributes host toolcache and runtime cache +folders (Node, Python, Go, Ruby, Java, Dotnet, Bun, Deno, UV, Elixir, +Haskell) into sandboxed agent containers so runtime binaries and caches are +available inside the agent environment. The compiler now auto-adds mounts when +runtimes are detected; smoke tests validate runtime commands inside containers. + diff --git a/.changeset/patch-add-runtime-mounts.md b/.changeset/patch-add-runtime-mounts.md new file mode 100644 index 0000000000..13aae6167f --- /dev/null +++ b/.changeset/patch-add-runtime-mounts.md @@ -0,0 +1,10 @@ +--- +"gh-aw": patch +--- + +Add a runtime mount manager that contributes host toolcache and runtime cache +folders (Node, Python, Go, Ruby, Java, Dotnet, Bun, Deno, UV, Elixir, +Haskell) into sandboxed agent containers so runtime binaries and caches are +available inside the agent environment. The compiler now auto-adds mounts when +runtimes are detected; smoke tests validate runtime commands inside containers. + diff --git a/.changeset/patch-runtime-mount-manager.md b/.changeset/patch-runtime-mount-manager.md new file mode 100644 index 0000000000..4f45fa1e5d --- /dev/null +++ b/.changeset/patch-runtime-mount-manager.md @@ -0,0 +1,14 @@ +--- +"gh-aw": patch +--- + +Add a runtime mount manager that contributes well-known host toolcache +and cache folders into sandboxed agent containers so runtime binaries +and caches (Node, Python, Go, Ruby, Java, Dotnet, Bun, Deno, UV, +Elixir, Haskell) are available inside the agent environment. + +This change centralizes runtime mount definitions, hooks them into the +compiler so mounts are automatically added when runtimes are detected, +and adds smoke-test validation to ensure runtime commands (for example +`npm ls`) work inside containers. + diff --git a/.changeset/patch-runtime-mounts.md b/.changeset/patch-runtime-mounts.md new file mode 100644 index 0000000000..099a1db99b --- /dev/null +++ b/.changeset/patch-runtime-mounts.md @@ -0,0 +1,6 @@ +--- +"gh-aw": patch +--- + +Add runtime mount manager that contributes host toolcache and runtime cache folders (Node, Python, Go, Ruby, Java, Dotnet, Bun, Deno, UV, Elixir, Haskell) into sandboxed agent containers so runtime binaries and caches are available inside the agent environment. Compiler now auto-adds mounts when runtimes are detected; smoke tests validate runtime commands inside containers. + diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index a6bd5ce3a4..b57f14db13 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -80,6 +80,11 @@ "version": "v4.8.0", "sha": "c1e323688fd81a25caa38c78aa6df2d33d3e20d9" }, + "actions/setup-node@v4": { + "repo": "actions/setup-node", + "version": "v4", + "sha": "49933ea5288caeca8642d1e84afbd3f7d6820020" + }, "actions/setup-node@v6": { "repo": "actions/setup-node", "version": "v6", diff --git a/.github/workflows/ci-coach.lock.yml b/.github/workflows/ci-coach.lock.yml index db9e08ce15..36f2a5084d 100644 --- a/.github/workflows/ci-coach.lock.yml +++ b/.github/workflows/ci-coach.lock.yml @@ -1372,7 +1372,7 @@ jobs: timeout-minutes: 30 run: | set -o pipefail - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --mount /home/runner/.npm:/home/runner/.npm:rw --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ -- /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"} \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index ef13bfc048..ac49b8e926 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -1002,7 +1002,7 @@ jobs: timeout-minutes: 15 run: | set -o pipefail - sudo -E awf --env-all --tty --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains '*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,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,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.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,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ + sudo -E awf --env-all --tty --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --mount /opt/gh-aw:/opt/gh-aw:ro --mount /home/runner/.npm:/home/runner/.npm:rw --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --allow-domains '*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,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,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.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,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ -- /bin/bash -c 'NODE_BIN_PATH="$(find /opt/hostedtoolcache/node -mindepth 1 -maxdepth 1 -type d | head -1 | xargs basename)/x64/bin" && export PATH="/opt/hostedtoolcache/node/$NODE_BIN_PATH:$PATH" && claude --print --disable-slash-commands --no-chrome --mcp-config /tmp/gh-aw/mcp-config/mcp-servers.json --allowed-tools '\''Bash(./gh-aw compile *),Bash(cat),Bash(date),Bash(echo),Bash(find pkg -name '\''\'\'''\''*.go'\''\'\'''\'' -type f ! -name '\''\'\'''\''*_test.go'\''\'\'''\''),Bash(git add:*),Bash(git branch:*),Bash(git checkout:*),Bash(git commit:*),Bash(git merge:*),Bash(git rm:*),Bash(git status),Bash(git switch:*),Bash(grep -n '\''\'\'''\''func '\''\'\'''\'' pkg/*.go),Bash(grep -r '\''\'\'''\''var log = logger.New'\''\'\'''\'' pkg --include='\''\'\'''\''*.go'\''\'\'''\''),Bash(grep),Bash(head -n * pkg/**/*.go),Bash(head),Bash(ls),Bash(make build),Bash(make recompile),Bash(pwd),Bash(sort),Bash(tail),Bash(uniq),Bash(wc -l pkg/**/*.go),Bash(wc),Bash(yq),BashOutput,Edit,Edit(/tmp/gh-aw/cache-memory/*),ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,MultiEdit(/tmp/gh-aw/cache-memory/*),NotebookEdit,NotebookRead,Read,Read(/tmp/gh-aw/cache-memory/*),Task,TodoWrite,Write,Write(/tmp/gh-aw/cache-memory/*),mcp__github__download_workflow_run_artifact,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__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,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__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,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'\'' --debug --verbose --permission-mode bypassPermissions --output-format json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_CLAUDE:+ --model "$GH_AW_MODEL_AGENT_CLAUDE"}' \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: diff --git a/.github/workflows/hourly-ci-cleaner.lock.yml b/.github/workflows/hourly-ci-cleaner.lock.yml index 8cc89c4cb0..b3ef67cb7e 100644 --- a/.github/workflows/hourly-ci-cleaner.lock.yml +++ b/.github/workflows/hourly-ci-cleaner.lock.yml @@ -971,7 +971,7 @@ jobs: timeout-minutes: 45 run: | set -o pipefail - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --mount /opt/hostedtoolcache/go:/opt/hostedtoolcache/go:ro --mount /usr/bin/go:/usr/bin/go:ro --mount /usr/bin/make:/usr/bin/make:ro --mount /usr/local/bin/node:/usr/local/bin/node:ro --mount /usr/local/bin/npm:/usr/local/bin/npm:ro --mount /usr/local/lib/node_modules:/usr/local/lib/node_modules:ro --allow-domains 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,go.dev,golang.org,goproxy.io,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,pkg.go.dev,ppa.launchpad.net,proxy.golang.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sum.golang.org,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --mount /home/runner/.npm:/home/runner/.npm:rw --mount /opt/hostedtoolcache/go:/opt/hostedtoolcache/go:ro --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --mount /usr/bin/go:/usr/bin/go:ro --mount /usr/bin/make:/usr/bin/make:ro --mount /usr/local/bin/node:/usr/local/bin/node:ro --mount /usr/local/bin/npm:/usr/local/bin/npm:ro --mount /usr/local/lib/node_modules:/usr/local/lib/node_modules:ro --allow-domains 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,go.dev,golang.org,goproxy.io,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,pkg.go.dev,ppa.launchpad.net,proxy.golang.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sum.golang.org,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ -- /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --agent ci-cleaner --allow-all-tools --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"} \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: diff --git a/.github/workflows/jsweep.lock.yml b/.github/workflows/jsweep.lock.yml index 92c68274e8..b3f58605f1 100644 --- a/.github/workflows/jsweep.lock.yml +++ b/.github/workflows/jsweep.lock.yml @@ -889,7 +889,7 @@ jobs: timeout-minutes: 20 run: | set -o pipefail - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --mount /home/runner/.npm:/home/runner/.npm:rw --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ -- /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"} \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index 556d789f23..7f04c02f9e 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -1235,7 +1235,7 @@ jobs: timeout-minutes: 20 run: | set -o pipefail - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains '*.docker.com,*.docker.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.snapcraft.io,archive.ubuntu.com,auth.docker.io,azure.archive.ubuntu.com,bun.sh,cdn.jsdelivr.net,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,deb.nodesource.com,deno.land,dl.k8s.io,fonts.googleapis.com,fonts.gstatic.com,gcr.io,get.pnpm.io,ghcr.io,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,learn.microsoft.com,localhost,mcp.datadoghq.com,mcp.deepwiki.com,mcp.tavily.com,mcr.microsoft.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,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,pkgs.k8s.io,ppa.launchpad.net,production.cloudflare.docker.com,quay.io,raw.githubusercontent.com,registry.bower.io,registry.hub.docker.com,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --mount /home/runner/.cache/pip:/home/runner/.cache/pip:rw --mount /home/runner/.cache/uv:/home/runner/.cache/uv:rw --mount /home/runner/.npm:/home/runner/.npm:rw --mount /opt/hostedtoolcache/Python:/opt/hostedtoolcache/Python:ro --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --allow-domains '*.docker.com,*.docker.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.snapcraft.io,archive.ubuntu.com,auth.docker.io,azure.archive.ubuntu.com,bun.sh,cdn.jsdelivr.net,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,deb.nodesource.com,deno.land,dl.k8s.io,fonts.googleapis.com,fonts.gstatic.com,gcr.io,get.pnpm.io,ghcr.io,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,learn.microsoft.com,localhost,mcp.datadoghq.com,mcp.deepwiki.com,mcp.tavily.com,mcr.microsoft.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,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,pkgs.k8s.io,ppa.launchpad.net,production.cloudflare.docker.com,quay.io,raw.githubusercontent.com,registry.bower.io,registry.hub.docker.com,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ -- /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool arxiv --allow-tool 'arxiv(get_paper_details)' --allow-tool 'arxiv(get_paper_pdf)' --allow-tool 'arxiv(search_arxiv)' --allow-tool ast-grep --allow-tool 'ast-grep(*)' --allow-tool brave-search --allow-tool 'brave-search(*)' --allow-tool context7 --allow-tool 'context7(get-library-docs)' --allow-tool 'context7(resolve-library-id)' --allow-tool datadog --allow-tool 'datadog(get_datadog_metric)' --allow-tool 'datadog(search_datadog_dashboards)' --allow-tool 'datadog(search_datadog_metrics)' --allow-tool 'datadog(search_datadog_slos)' --allow-tool deepwiki --allow-tool 'deepwiki(ask_question)' --allow-tool 'deepwiki(read_wiki_contents)' --allow-tool 'deepwiki(read_wiki_structure)' --allow-tool fabric-rti --allow-tool 'fabric-rti(get_eventstream)' --allow-tool 'fabric-rti(get_eventstream_definition)' --allow-tool 'fabric-rti(kusto_get_entities_schema)' --allow-tool 'fabric-rti(kusto_get_function_schema)' --allow-tool 'fabric-rti(kusto_get_shots)' --allow-tool 'fabric-rti(kusto_get_table_schema)' --allow-tool 'fabric-rti(kusto_known_services)' --allow-tool 'fabric-rti(kusto_list_databases)' --allow-tool 'fabric-rti(kusto_list_tables)' --allow-tool 'fabric-rti(kusto_query)' --allow-tool 'fabric-rti(kusto_sample_function_data)' --allow-tool 'fabric-rti(kusto_sample_table_data)' --allow-tool 'fabric-rti(list_eventstreams)' --allow-tool gh-aw --allow-tool github --allow-tool markitdown --allow-tool 'markitdown(*)' --allow-tool memory --allow-tool 'memory(delete_memory)' --allow-tool 'memory(list_memories)' --allow-tool 'memory(retrieve_memory)' --allow-tool 'memory(store_memory)' --allow-tool microsoftdocs --allow-tool 'microsoftdocs(*)' --allow-tool notion --allow-tool 'notion(get_database)' --allow-tool 'notion(get_page)' --allow-tool 'notion(query_database)' --allow-tool 'notion(search_pages)' --allow-tool safeoutputs --allow-tool sentry --allow-tool 'sentry(analyze_issue_with_seer)' --allow-tool 'sentry(find_dsns)' --allow-tool 'sentry(find_organizations)' --allow-tool 'sentry(find_projects)' --allow-tool 'sentry(find_releases)' --allow-tool 'sentry(find_teams)' --allow-tool 'sentry(get_doc)' --allow-tool 'sentry(get_event_attachment)' --allow-tool 'sentry(get_issue_details)' --allow-tool 'sentry(get_trace_details)' --allow-tool 'sentry(search_docs requires SENTRY_OPENAI_API_KEY)' --allow-tool 'sentry(search_events)' --allow-tool 'sentry(search_issues)' --allow-tool 'sentry(whoami)' --allow-tool 'shell(cat)' --allow-tool 'shell(date)' --allow-tool 'shell(echo)' --allow-tool 'shell(grep)' --allow-tool 'shell(head)' --allow-tool 'shell(ls)' --allow-tool 'shell(pwd)' --allow-tool 'shell(sort)' --allow-tool 'shell(tail)' --allow-tool 'shell(uniq)' --allow-tool 'shell(wc)' --allow-tool 'shell(yq)' --allow-tool tavily --allow-tool 'tavily(*)' --allow-tool write --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"} \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index ead963124f..f89eb0eb24 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -1055,8 +1055,10 @@ jobs: 3. **Serena MCP Testing**: Use the Serena MCP server tool `activate_project` to initialize the workspace at `__GH_AW_GITHUB_WORKSPACE__` and verify it succeeds (do NOT use bash to run go commands - use Serena's MCP tools) 4. **Playwright Testing**: Use playwright to navigate to https://github.com and verify the page title contains "GitHub" 5. **Tavily Web Search Testing**: Use the Tavily MCP server to perform a web search for "GitHub Agentic Workflows" and verify that results are returned with at least one item - 6. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-claude-__GH_AW_GITHUB_RUN_ID__.txt` with content "Smoke test passed for Claude at $(date)" (create the directory if it doesn't exist) - 7. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) + 6. **Runtime Mount Testing - Go Build**: Build the gh-aw binary by running `go build -o /tmp/gh-aw-test ./cmd/gh-aw` to verify that Go runtime is fully functional with all dependencies and build tools (this tests that the runtime manager properly mounted Go folders including toolcache, GOPATH, and build cache) + 7. **Runtime Mount Testing - Go Test**: Run Go unit tests by executing `go test ./pkg/console -v -run TestFormatSuccess` to verify Go can compile and run tests with all mounts working correctly + 8. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-claude-__GH_AW_GITHUB_RUN_ID__.txt` with content "Smoke test passed for Claude at $(date)" (create the directory if it doesn't exist) + 9. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) ## Output @@ -1229,7 +1231,7 @@ jobs: timeout-minutes: 10 run: | set -o pipefail - sudo -E awf --env-all --tty --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains '*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,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,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,mcp.tavily.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,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ + sudo -E awf --env-all --tty --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --mount /opt/gh-aw:/opt/gh-aw:ro --mount /home/runner/.cache/go-build:/home/runner/.cache/go-build:rw --mount /home/runner/go:/home/runner/go:rw --mount /opt/hostedtoolcache/go:/opt/hostedtoolcache/go:ro --allow-domains '*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,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,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,mcp.tavily.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,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ -- /bin/bash -c 'NODE_BIN_PATH="$(find /opt/hostedtoolcache/node -mindepth 1 -maxdepth 1 -type d | head -1 | xargs basename)/x64/bin" && export PATH="/opt/hostedtoolcache/node/$NODE_BIN_PATH:$PATH" && claude --print --disable-slash-commands --no-chrome --max-turns 15 --mcp-config /tmp/gh-aw/mcp-config/mcp-servers.json --allowed-tools '\''Bash,BashOutput,Edit,Edit(/tmp/gh-aw/cache-memory/*),ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,MultiEdit(/tmp/gh-aw/cache-memory/*),NotebookEdit,NotebookRead,Read,Read(/tmp/gh-aw/cache-memory/*),Task,TodoWrite,Write,Write(/tmp/gh-aw/cache-memory/*),mcp__github__download_workflow_run_artifact,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__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,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__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,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__playwright__browser_click,mcp__playwright__browser_close,mcp__playwright__browser_console_messages,mcp__playwright__browser_drag,mcp__playwright__browser_evaluate,mcp__playwright__browser_file_upload,mcp__playwright__browser_fill_form,mcp__playwright__browser_handle_dialog,mcp__playwright__browser_hover,mcp__playwright__browser_install,mcp__playwright__browser_navigate,mcp__playwright__browser_navigate_back,mcp__playwright__browser_network_requests,mcp__playwright__browser_press_key,mcp__playwright__browser_resize,mcp__playwright__browser_select_option,mcp__playwright__browser_snapshot,mcp__playwright__browser_tabs,mcp__playwright__browser_take_screenshot,mcp__playwright__browser_type,mcp__playwright__browser_wait_for,mcp__tavily'\'' --debug --verbose --permission-mode bypassPermissions --output-format json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_CLAUDE:+ --model "$GH_AW_MODEL_AGENT_CLAUDE"}' \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: diff --git a/.github/workflows/smoke-claude.md b/.github/workflows/smoke-claude.md index 6fe2aa7980..106cea4170 100644 --- a/.github/workflows/smoke-claude.md +++ b/.github/workflows/smoke-claude.md @@ -74,8 +74,10 @@ timeout-minutes: 10 3. **Serena MCP Testing**: Use the Serena MCP server tool `activate_project` to initialize the workspace at `${{ github.workspace }}` and verify it succeeds (do NOT use bash to run go commands - use Serena's MCP tools) 4. **Playwright Testing**: Use playwright to navigate to https://github.com and verify the page title contains "GitHub" 5. **Tavily Web Search Testing**: Use the Tavily MCP server to perform a web search for "GitHub Agentic Workflows" and verify that results are returned with at least one item -6. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-claude-${{ github.run_id }}.txt` with content "Smoke test passed for Claude at $(date)" (create the directory if it doesn't exist) -7. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) +6. **Runtime Mount Testing - Go Build**: Build the gh-aw binary by running `go build -o /tmp/gh-aw-test ./cmd/gh-aw` to verify that Go runtime is fully functional with all dependencies and build tools (this tests that the runtime manager properly mounted Go folders including toolcache, GOPATH, and build cache) +7. **Runtime Mount Testing - Go Test**: Run Go unit tests by executing `go test ./pkg/console -v -run TestFormatSuccess` to verify Go can compile and run tests with all mounts working correctly +8. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-claude-${{ github.run_id }}.txt` with content "Smoke test passed for Claude at $(date)" (create the directory if it doesn't exist) +9. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) ## Output diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index a3c8f2f16e..e63df3d795 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -1037,8 +1037,10 @@ jobs: 3. **Serena MCP Testing**: Use the Serena MCP server tool `activate_project` to initialize the workspace at `__GH_AW_GITHUB_WORKSPACE__` and verify it succeeds (do NOT use bash to run go commands - use Serena's MCP tools) 4. **Playwright Testing**: Use playwright to navigate to https://github.com and verify the page title contains "GitHub" 5. **Tavily Web Search Testing**: Use the Tavily MCP server to perform a web search for "GitHub Agentic Workflows" and verify that results are returned with at least one item - 6. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-codex-__GH_AW_GITHUB_RUN_ID__.txt` with content "Smoke test passed for Codex at $(date)" (create the directory if it doesn't exist) - 7. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) + 6. **Runtime Mount Testing - Go Build**: Build the gh-aw binary by running `go build -o /tmp/gh-aw-test ./cmd/gh-aw` to verify that Go runtime is fully functional with all dependencies and build tools (this tests that the runtime manager properly mounted Go folders including toolcache, GOPATH, and build cache) + 7. **Runtime Mount Testing - Go Test**: Run Go unit tests by executing `go test ./pkg/console -v -run TestFormatSuccess` to verify Go can compile and run tests with all mounts working correctly + 8. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-codex-__GH_AW_GITHUB_RUN_ID__.txt` with content "Smoke test passed for Codex at $(date)" (create the directory if it doesn't exist) + 9. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) ## Output @@ -1106,7 +1108,7 @@ jobs: set -o pipefail INSTRUCTION="$(cat "$GH_AW_PROMPT")" mkdir -p "$CODEX_HOME/logs" - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains '*.githubusercontent.com,api.openai.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,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,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,mcp.tavily.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,openai.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --mount /opt/gh-aw:/opt/gh-aw:ro --mount /home/runner/.cache/go-build:/home/runner/.cache/go-build:rw --mount /home/runner/go:/home/runner/go:rw --mount /opt/hostedtoolcache/go:/opt/hostedtoolcache/go:ro --allow-domains '*.githubusercontent.com,api.openai.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,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,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,mcp.tavily.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,openai.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ -- NODE_BIN_PATH="$(find /opt/hostedtoolcache/node -mindepth 1 -maxdepth 1 -type d | head -1 | xargs basename)/x64/bin" && export PATH="/opt/hostedtoolcache/node/$NODE_BIN_PATH:$PATH" && codex ${GH_AW_MODEL_AGENT_CODEX:+-c model="$GH_AW_MODEL_AGENT_CODEX" }exec --full-auto --skip-git-repo-check --sandbox danger-full-access "$INSTRUCTION" \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: diff --git a/.github/workflows/smoke-codex.md b/.github/workflows/smoke-codex.md index b6c21ab088..88d47524c4 100644 --- a/.github/workflows/smoke-codex.md +++ b/.github/workflows/smoke-codex.md @@ -71,8 +71,10 @@ timeout-minutes: 10 3. **Serena MCP Testing**: Use the Serena MCP server tool `activate_project` to initialize the workspace at `${{ github.workspace }}` and verify it succeeds (do NOT use bash to run go commands - use Serena's MCP tools) 4. **Playwright Testing**: Use playwright to navigate to https://github.com and verify the page title contains "GitHub" 5. **Tavily Web Search Testing**: Use the Tavily MCP server to perform a web search for "GitHub Agentic Workflows" and verify that results are returned with at least one item -6. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-codex-${{ github.run_id }}.txt` with content "Smoke test passed for Codex at $(date)" (create the directory if it doesn't exist) -7. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) +6. **Runtime Mount Testing - Go Build**: Build the gh-aw binary by running `go build -o /tmp/gh-aw-test ./cmd/gh-aw` to verify that Go runtime is fully functional with all dependencies and build tools (this tests that the runtime manager properly mounted Go folders including toolcache, GOPATH, and build cache) +7. **Runtime Mount Testing - Go Test**: Run Go unit tests by executing `go test ./pkg/console -v -run TestFormatSuccess` to verify Go can compile and run tests with all mounts working correctly +8. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-codex-${{ github.run_id }}.txt` with content "Smoke test passed for Codex at $(date)" (create the directory if it doesn't exist) +9. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) ## Output diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 69356f38d0..405114b9f1 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -945,8 +945,11 @@ jobs: 2. **Safe Inputs GH CLI Testing**: Use the `safeinputs-gh` tool to query 2 pull requests from __GH_AW_GITHUB_REPOSITORY__ (use args: "pr list --repo __GH_AW_GITHUB_REPOSITORY__ --limit 2 --json number,title,author") 3. **Serena MCP Testing**: Use the Serena MCP server tool `activate_project` to initialize the workspace at `__GH_AW_GITHUB_WORKSPACE__` and verify it succeeds (do NOT use bash to run go commands - use Serena's MCP tools) 4. **Playwright Testing**: Use playwright to navigate to and verify the page title contains "GitHub" - 5. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-copilot-__GH_AW_GITHUB_RUN_ID__.txt` with content "Smoke test passed for Copilot at $(date)" (create the directory if it doesn't exist) - 6. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) + 5. **Runtime Mount Testing - Show Go Paths**: Display Go binary locations by running `which go && go version && go env GOROOT GOPATH GOCACHE` to verify Go is accessible and show mount points + 6. **Runtime Mount Testing - Go Build**: Build the gh-aw binary by running `go build -o /tmp/gh-aw-test ./cmd/gh-aw` to verify that Go runtime is fully functional with all dependencies and build tools (this tests that the runtime manager properly mounted Go folders including toolcache, GOPATH, and build cache) + 7. **Runtime Mount Testing - Go Test**: Run Go unit tests by executing `go test ./pkg/console -v -run TestFormatSuccess` to verify Go can compile and run tests with all mounts working correctly + 8. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-copilot-__GH_AW_GITHUB_RUN_ID__.txt` with content "Smoke test passed for Copilot at $(date)" (create the directory if it doesn't exist) + 9. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) ## Output @@ -1030,7 +1033,7 @@ jobs: timeout-minutes: 5 run: | set -o pipefail - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains '*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.playwright.dev,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,deb.nodesource.com,deno.land,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,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,playwright.download.prss.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --mount /home/runner/.cache/go-build:/home/runner/.cache/go-build:rw --mount /home/runner/go:/home/runner/go:rw --mount /opt/hostedtoolcache/go:/opt/hostedtoolcache/go:ro --allow-domains '*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,cdn.playwright.dev,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,deb.nodesource.com,deno.land,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,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,playwright.download.prss.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ -- /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"} \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: diff --git a/.github/workflows/smoke-copilot.md b/.github/workflows/smoke-copilot.md index 07a2d35b82..545d0b3d1a 100644 --- a/.github/workflows/smoke-copilot.md +++ b/.github/workflows/smoke-copilot.md @@ -74,8 +74,11 @@ strict: true 2. **Safe Inputs GH CLI Testing**: Use the `safeinputs-gh` tool to query 2 pull requests from ${{ github.repository }} (use args: "pr list --repo ${{ github.repository }} --limit 2 --json number,title,author") 3. **Serena MCP Testing**: Use the Serena MCP server tool `activate_project` to initialize the workspace at `${{ github.workspace }}` and verify it succeeds (do NOT use bash to run go commands - use Serena's MCP tools) 4. **Playwright Testing**: Use playwright to navigate to and verify the page title contains "GitHub" -5. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-copilot-${{ github.run_id }}.txt` with content "Smoke test passed for Copilot at $(date)" (create the directory if it doesn't exist) -6. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) +5. **Runtime Mount Testing - Show Go Paths**: Display Go binary locations by running `which go && go version && go env GOROOT GOPATH GOCACHE` to verify Go is accessible and show mount points +6. **Runtime Mount Testing - Go Build**: Build the gh-aw binary by running `go build -o /tmp/gh-aw-test ./cmd/gh-aw` to verify that Go runtime is fully functional with all dependencies and build tools (this tests that the runtime manager properly mounted Go folders including toolcache, GOPATH, and build cache) +7. **Runtime Mount Testing - Go Test**: Run Go unit tests by executing `go test ./pkg/console -v -run TestFormatSuccess` to verify Go can compile and run tests with all mounts working correctly +8. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-copilot-${{ github.run_id }}.txt` with content "Smoke test passed for Copilot at $(date)" (create the directory if it doesn't exist) +9. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back) ## Output diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index d1f7e1c673..b0eb961ce5 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -1295,7 +1295,7 @@ jobs: timeout-minutes: 10 run: | set -o pipefail - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains '*.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,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,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,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/gh-aw:/opt/gh-aw:ro --mount /home/runner/.npm:/home/runner/.npm:rw --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --allow-domains '*.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,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,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,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ -- /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --agent technical-doc-writer --allow-tool github --allow-tool safeoutputs --allow-tool shell --allow-tool write --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"} \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index bdbd910d0c..171d822867 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -1274,7 +1274,7 @@ jobs: timeout-minutes: 12 run: | set -o pipefail - sudo -E awf --env-all --tty --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains '*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,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,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,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,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ + sudo -E awf --env-all --tty --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --mount /opt/gh-aw:/opt/gh-aw:ro --mount /home/runner/.npm:/home/runner/.npm:rw --mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro --allow-domains '*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,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,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,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,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.10.0 \ -- /bin/bash -c 'NODE_BIN_PATH="$(find /opt/hostedtoolcache/node -mindepth 1 -maxdepth 1 -type d | head -1 | xargs basename)/x64/bin" && export PATH="/opt/hostedtoolcache/node/$NODE_BIN_PATH:$PATH" && claude --print --disable-slash-commands --no-chrome --max-turns 90 --mcp-config /tmp/gh-aw/mcp-config/mcp-servers.json --allowed-tools '\''Bash(cat *),Bash(cat),Bash(cd *),Bash(cp *),Bash(curl *),Bash(date),Bash(echo *),Bash(echo),Bash(find docs/src/content/docs -name '\''\'\'''\''*.md'\''\'\'''\''),Bash(git add:*),Bash(git branch:*),Bash(git checkout:*),Bash(git commit:*),Bash(git merge:*),Bash(git rm:*),Bash(git status),Bash(git switch:*),Bash(grep -n *),Bash(grep),Bash(head *),Bash(head),Bash(kill *),Bash(ls),Bash(mkdir *),Bash(mv *),Bash(node *),Bash(npm *),Bash(ps *),Bash(pwd),Bash(sleep *),Bash(sort),Bash(tail *),Bash(tail),Bash(uniq),Bash(wc -l *),Bash(wc),Bash(yq),BashOutput,Edit,Edit(/tmp/gh-aw/cache-memory/*),ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,MultiEdit(/tmp/gh-aw/cache-memory/*),NotebookEdit,NotebookRead,Read,Read(/tmp/gh-aw/cache-memory/*),Task,TodoWrite,Write,Write(/tmp/gh-aw/cache-memory/*),mcp__github__download_workflow_run_artifact,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__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,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__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,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__playwright__browser_click,mcp__playwright__browser_close,mcp__playwright__browser_console_messages,mcp__playwright__browser_drag,mcp__playwright__browser_evaluate,mcp__playwright__browser_file_upload,mcp__playwright__browser_fill_form,mcp__playwright__browser_handle_dialog,mcp__playwright__browser_hover,mcp__playwright__browser_install,mcp__playwright__browser_navigate,mcp__playwright__browser_navigate_back,mcp__playwright__browser_network_requests,mcp__playwright__browser_press_key,mcp__playwright__browser_resize,mcp__playwright__browser_select_option,mcp__playwright__browser_snapshot,mcp__playwright__browser_tabs,mcp__playwright__browser_take_screenshot,mcp__playwright__browser_type,mcp__playwright__browser_wait_for'\'' --debug --verbose --permission-mode bypassPermissions --output-format json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_CLAUDE:+ --model "$GH_AW_MODEL_AGENT_CLAUDE"}' \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: diff --git a/actions/setup/js/safe_outputs_mcp_server_defaults.test.cjs b/actions/setup/js/safe_outputs_mcp_server_defaults.test.cjs index f00919196d..dbd548a13c 100644 --- a/actions/setup/js/safe_outputs_mcp_server_defaults.test.cjs +++ b/actions/setup/js/safe_outputs_mcp_server_defaults.test.cjs @@ -168,11 +168,11 @@ import { spawn } from "child_process"; setTimeout(() => { const initMessage = JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "test-client", version: "1.0.0" } } }) + "\n"; child.stdin.write(initMessage); - }, 100), + }, 300), setTimeout(() => { const listToolsMessage = JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} }) + "\n"; child.stdin.write(listToolsMessage); - }, 200), + }, 600), setTimeout(() => { (clearTimeout(timeout), child.kill()); const listResponse = receivedMessages.find(m => 2 === m.id); @@ -185,7 +185,7 @@ import { spawn } from "child_process"; expect(createPrTool.inputSchema.properties.branch.description).toContain("If omitted"), expect(createPrTool.inputSchema.properties.branch.description).toContain("current"), resolve()); - }, 500)); + }, 1500)); }); }), it("should have optional branch parameter for push_to_pull_request_branch", async () => { @@ -216,11 +216,11 @@ import { spawn } from "child_process"; setTimeout(() => { const initMessage = JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "test-client", version: "1.0.0" } } }) + "\n"; child.stdin.write(initMessage); - }, 100), + }, 300), setTimeout(() => { const listToolsMessage = JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} }) + "\n"; child.stdin.write(listToolsMessage); - }, 200), + }, 600), setTimeout(() => { (clearTimeout(timeout), child.kill()); const listResponse = receivedMessages.find(m => 2 === m.id); @@ -233,7 +233,7 @@ import { spawn } from "child_process"; expect(pushTool.inputSchema.properties.branch.description).toContain("If omitted"), expect(pushTool.inputSchema.properties.branch.description).toContain("current"), resolve()); - }, 500)); + }, 1500)); }); })); }), @@ -312,11 +312,11 @@ import { spawn } from "child_process"; setTimeout(() => { const initMessage = JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "test-client", version: "1.0.0" } } }) + "\n"; child.stdin.write(initMessage); - }, 100), + }, 300), setTimeout(() => { const toolCallMessage = JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/call", params: { name: "create_issue", arguments: { title: "Test Issue", body: "Test body" } } }) + "\n"; child.stdin.write(toolCallMessage); - }, 200), + }, 600), setTimeout(() => { (clearTimeout(timeout), child.kill()); const toolCallResponse = receivedMessages.find(m => 2 === m.id); @@ -329,7 +329,7 @@ import { spawn } from "child_process"; (expect(firstContent.type).toBe("text"), expect(firstContent.text).toBeDefined(), expect(() => JSON.parse(firstContent.text)).not.toThrow()); const parsedResult = JSON.parse(firstContent.text); (expect(parsedResult).toHaveProperty("result"), expect(parsedResult.result).toBe("success"), resolve()); - }, 500)); + }, 1500)); }); })); })); diff --git a/pkg/workflow/compiler_yaml_main_job.go b/pkg/workflow/compiler_yaml_main_job.go index 1934173089..95c81224b2 100644 --- a/pkg/workflow/compiler_yaml_main_job.go +++ b/pkg/workflow/compiler_yaml_main_job.go @@ -39,6 +39,13 @@ func (c *Compiler) generateMainJobSteps(yaml *strings.Builder, data *WorkflowDat // This detects runtimes from custom steps and MCP configs runtimeRequirements := DetectRuntimeRequirements(data) + // Contribute runtime-specific mounts to sandbox agent configuration + // This ensures runtime binaries, caches, and supporting folders are available in the container + if data.SandboxConfig != nil && data.SandboxConfig.Agent != nil && len(runtimeRequirements) > 0 { + ContributeRuntimeMounts(data.SandboxConfig.Agent, runtimeRequirements) + compilerYamlLog.Printf("Contributed runtime mounts to sandbox agent configuration") + } + // Deduplicate runtime setup steps from custom steps // This removes any runtime setup action steps (like actions/setup-go) from custom steps // since we're adding them. It also preserves user-customized setup actions and diff --git a/pkg/workflow/data/action_pins.json b/pkg/workflow/data/action_pins.json index a6bd5ce3a4..b57f14db13 100644 --- a/pkg/workflow/data/action_pins.json +++ b/pkg/workflow/data/action_pins.json @@ -80,6 +80,11 @@ "version": "v4.8.0", "sha": "c1e323688fd81a25caa38c78aa6df2d33d3e20d9" }, + "actions/setup-node@v4": { + "repo": "actions/setup-node", + "version": "v4", + "sha": "49933ea5288caeca8642d1e84afbd3f7d6820020" + }, "actions/setup-node@v6": { "repo": "actions/setup-node", "version": "v6", diff --git a/pkg/workflow/runtime_mounts.go b/pkg/workflow/runtime_mounts.go new file mode 100644 index 0000000000..2afb0dbf5b --- /dev/null +++ b/pkg/workflow/runtime_mounts.go @@ -0,0 +1,180 @@ +package workflow + +import ( + "sort" + + "github.com/githubnext/gh-aw/pkg/logger" +) + +var runtimeMountsLog = logger.New("workflow:runtime_mounts") + +// RuntimeMountDefinition defines mount paths for a specific runtime +type RuntimeMountDefinition struct { + // RuntimeID is the unique identifier for the runtime (e.g., "node", "python") + RuntimeID string + + // Mounts is a list of mount specifications in the format "source:dest:mode" + // These mounts make runtime binaries, caches, and supporting folders + // available inside the agent container + Mounts []string +} + +// GetRuntimeMounts returns mount specifications for detected runtimes +// This ensures that runtime binaries, caches, and other supporting folders +// are available inside the agent container +func GetRuntimeMounts(requirements []RuntimeRequirement) []string { + runtimeMountsLog.Printf("Generating runtime mounts for %d requirements", len(requirements)) + + // Collect unique mounts across all detected runtimes + mountSet := make(map[string]bool) + + for _, req := range requirements { + mountDef := getRuntimeMountDefinition(req.Runtime.ID) + if mountDef != nil { + for _, mount := range mountDef.Mounts { + mountSet[mount] = true + } + runtimeMountsLog.Printf("Added %d mounts for runtime: %s", len(mountDef.Mounts), req.Runtime.ID) + } + } + + // Convert set to sorted slice for consistent output + mounts := make([]string, 0, len(mountSet)) + for mount := range mountSet { + mounts = append(mounts, mount) + } + sort.Strings(mounts) + + runtimeMountsLog.Printf("Total unique runtime mounts: %d", len(mounts)) + return mounts +} + +// getRuntimeMountDefinition returns mount definitions for a specific runtime +// Returns nil if the runtime has no special mount requirements +func getRuntimeMountDefinition(runtimeID string) *RuntimeMountDefinition { + // Map of runtime IDs to their mount definitions + // These paths are based on GitHub Actions runner standard locations + definitions := map[string]*RuntimeMountDefinition{ + "node": { + RuntimeID: "node", + Mounts: []string{ + "/opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro", + "/home/runner/.npm:/home/runner/.npm:rw", + }, + }, + "python": { + RuntimeID: "python", + Mounts: []string{ + "/opt/hostedtoolcache/Python:/opt/hostedtoolcache/Python:ro", + "/home/runner/.cache/pip:/home/runner/.cache/pip:rw", + }, + }, + "go": { + RuntimeID: "go", + Mounts: []string{ + "/opt/hostedtoolcache/go:/opt/hostedtoolcache/go:ro", + "/home/runner/go:/home/runner/go:rw", + "/home/runner/.cache/go-build:/home/runner/.cache/go-build:rw", + }, + }, + "ruby": { + RuntimeID: "ruby", + Mounts: []string{ + "/opt/hostedtoolcache/Ruby:/opt/hostedtoolcache/Ruby:ro", + "/home/runner/.gem:/home/runner/.gem:rw", + }, + }, + "java": { + RuntimeID: "java", + Mounts: []string{ + "/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk:/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk:ro", + "/home/runner/.m2:/home/runner/.m2:rw", + "/home/runner/.gradle:/home/runner/.gradle:rw", + }, + }, + "dotnet": { + RuntimeID: "dotnet", + Mounts: []string{ + "/opt/hostedtoolcache/dotnet:/opt/hostedtoolcache/dotnet:ro", + "/home/runner/.nuget:/home/runner/.nuget:rw", + }, + }, + "bun": { + RuntimeID: "bun", + Mounts: []string{ + "/opt/hostedtoolcache/bun-x64:/opt/hostedtoolcache/bun-x64:ro", + "/home/runner/.bun:/home/runner/.bun:rw", + }, + }, + "deno": { + RuntimeID: "deno", + Mounts: []string{ + "/opt/hostedtoolcache/deno:/opt/hostedtoolcache/deno:ro", + "/home/runner/.cache/deno:/home/runner/.cache/deno:rw", + }, + }, + "uv": { + RuntimeID: "uv", + Mounts: []string{ + "/home/runner/.cache/uv:/home/runner/.cache/uv:rw", + }, + }, + "elixir": { + RuntimeID: "elixir", + Mounts: []string{ + "/opt/hostedtoolcache/elixir:/opt/hostedtoolcache/elixir:ro", + }, + }, + "haskell": { + RuntimeID: "haskell", + Mounts: []string{ + "/opt/hostedtoolcache/ghc:/opt/hostedtoolcache/ghc:ro", + "/home/runner/.cabal:/home/runner/.cabal:rw", + "/home/runner/.stack:/home/runner/.stack:rw", + }, + }, + } + + return definitions[runtimeID] +} + +// ContributeRuntimeMounts adds runtime-specific mounts to the sandbox agent configuration +// This is called during sandbox configuration to ensure runtime binaries and caches +// are available inside the agent container +func ContributeRuntimeMounts(agentConfig *AgentSandboxConfig, requirements []RuntimeRequirement) { + if agentConfig == nil { + runtimeMountsLog.Print("Agent config is nil, skipping runtime mounts contribution") + return + } + + runtimeMounts := GetRuntimeMounts(requirements) + if len(runtimeMounts) == 0 { + runtimeMountsLog.Print("No runtime mounts to contribute") + return + } + + // Initialize Mounts slice if nil + if agentConfig.Mounts == nil { + agentConfig.Mounts = make([]string, 0) + } + + // Add runtime mounts to agent config + // User-specified mounts take precedence (added first) + // Runtime mounts are added at the end + agentConfig.Mounts = append(agentConfig.Mounts, runtimeMounts...) + runtimeMountsLog.Printf("Contributed %d runtime mounts to agent config", len(runtimeMounts)) +} + +// GetRuntimeMountsForWorkflow is a convenience function that extracts runtime requirements +// from workflow data and returns the corresponding mounts +func GetRuntimeMountsForWorkflow(workflowData *WorkflowData) []string { + if workflowData == nil { + return []string{} + } + + // Detect runtime requirements + requirements := DetectRuntimeRequirements(workflowData) + + // Get mounts for detected runtimes + return GetRuntimeMounts(requirements) +} diff --git a/pkg/workflow/runtime_mounts_integration_test.go b/pkg/workflow/runtime_mounts_integration_test.go new file mode 100644 index 0000000000..8b2584ea27 --- /dev/null +++ b/pkg/workflow/runtime_mounts_integration_test.go @@ -0,0 +1,284 @@ +package workflow + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestRuntimeMountsIntegration tests that runtime mounts are automatically +// contributed to the sandbox agent configuration during workflow compilation +func TestRuntimeMountsIntegration(t *testing.T) { + tests := []struct { + name string + workflowData *WorkflowData + expectedMounts []string + unexpectedMounts []string + }{ + { + name: "node runtime adds toolcache and npm cache mounts", + workflowData: &WorkflowData{ + Name: "test-workflow", + EngineConfig: &EngineConfig{ + ID: "copilot", + }, + SandboxConfig: &SandboxConfig{ + Agent: &AgentSandboxConfig{ + ID: "awf", + }, + }, + CustomSteps: ` - name: Install deps + run: npm install`, + }, + expectedMounts: []string{ + "/opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro", + "/home/runner/.npm:/home/runner/.npm:rw", + }, + }, + { + name: "python runtime adds toolcache and pip cache mounts", + workflowData: &WorkflowData{ + Name: "test-workflow", + EngineConfig: &EngineConfig{ + ID: "copilot", + }, + SandboxConfig: &SandboxConfig{ + Agent: &AgentSandboxConfig{ + ID: "awf", + }, + }, + CustomSteps: ` - name: Run script + run: python script.py`, + }, + expectedMounts: []string{ + "/opt/hostedtoolcache/Python:/opt/hostedtoolcache/Python:ro", + "/home/runner/.cache/pip:/home/runner/.cache/pip:rw", + }, + }, + { + name: "multiple runtimes add combined mounts", + workflowData: &WorkflowData{ + Name: "test-workflow", + EngineConfig: &EngineConfig{ + ID: "copilot", + }, + SandboxConfig: &SandboxConfig{ + Agent: &AgentSandboxConfig{ + ID: "awf", + }, + }, + CustomSteps: ` - name: Install deps + run: npm install + - name: Run script + run: python script.py`, + }, + expectedMounts: []string{ + "/opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro", + "/home/runner/.npm:/home/runner/.npm:rw", + "/opt/hostedtoolcache/Python:/opt/hostedtoolcache/Python:ro", + "/home/runner/.cache/pip:/home/runner/.cache/pip:rw", + }, + }, + { + name: "user-specified mounts are preserved", + workflowData: &WorkflowData{ + Name: "test-workflow", + EngineConfig: &EngineConfig{ + ID: "copilot", + }, + SandboxConfig: &SandboxConfig{ + Agent: &AgentSandboxConfig{ + ID: "awf", + Mounts: []string{ + "/custom/path:/custom/path:ro", + }, + }, + }, + CustomSteps: ` - name: Install deps + run: npm install`, + }, + expectedMounts: []string{ + "/custom/path:/custom/path:ro", + "/opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro", + "/home/runner/.npm:/home/runner/.npm:rw", + }, + }, + { + name: "no runtime commands means no runtime mounts", + workflowData: &WorkflowData{ + Name: "test-workflow", + EngineConfig: &EngineConfig{ + ID: "copilot", + }, + SandboxConfig: &SandboxConfig{ + Agent: &AgentSandboxConfig{ + ID: "awf", + }, + }, + CustomSteps: ` - name: Echo + run: echo "hello"`, + }, + expectedMounts: []string{}, + unexpectedMounts: []string{"/opt/hostedtoolcache"}, + }, + { + name: "go runtime adds toolcache, GOPATH, and build cache", + workflowData: &WorkflowData{ + Name: "test-workflow", + EngineConfig: &EngineConfig{ + ID: "copilot", + }, + SandboxConfig: &SandboxConfig{ + Agent: &AgentSandboxConfig{ + ID: "awf", + }, + }, + CustomSteps: ` - name: Build + run: go build main.go`, + }, + expectedMounts: []string{ + "/opt/hostedtoolcache/go:/opt/hostedtoolcache/go:ro", + "/home/runner/go:/home/runner/go:rw", + "/home/runner/.cache/go-build:/home/runner/.cache/go-build:rw", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Detect runtime requirements + runtimeRequirements := DetectRuntimeRequirements(tt.workflowData) + + // Contribute runtime mounts to sandbox agent configuration + if tt.workflowData.SandboxConfig != nil && tt.workflowData.SandboxConfig.Agent != nil { + ContributeRuntimeMounts(tt.workflowData.SandboxConfig.Agent, runtimeRequirements) + } + + // Verify expected mounts are present + if tt.workflowData.SandboxConfig != nil && tt.workflowData.SandboxConfig.Agent != nil { + agentMounts := tt.workflowData.SandboxConfig.Agent.Mounts + for _, expectedMount := range tt.expectedMounts { + assert.Contains(t, agentMounts, expectedMount, + "Expected mount %q to be present in agent config", expectedMount) + } + + // Verify unexpected mounts are not present + for _, unexpectedMount := range tt.unexpectedMounts { + for _, mount := range agentMounts { + assert.NotContains(t, mount, unexpectedMount, + "Unexpected mount pattern %q found in mount %q", unexpectedMount, mount) + } + } + } + }) + } +} + +// TestRuntimeMountsInCopilotEngine tests that runtime mounts appear in the +// generated AWF command for the Copilot engine +func TestRuntimeMountsInCopilotEngine(t *testing.T) { + t.Run("runtime mounts appear in AWF command", func(t *testing.T) { + workflowData := &WorkflowData{ + Name: "test-workflow", + EngineConfig: &EngineConfig{ + ID: "copilot", + }, + SandboxConfig: &SandboxConfig{ + Agent: &AgentSandboxConfig{ + ID: "awf", + }, + }, + NetworkPermissions: &NetworkPermissions{ + Firewall: &FirewallConfig{ + Enabled: true, + }, + }, + CustomSteps: ` - name: Install deps + run: npm install`, + } + + // Detect runtime requirements + runtimeRequirements := DetectRuntimeRequirements(workflowData) + require.NotEmpty(t, runtimeRequirements, "Should detect runtime requirements") + + // Contribute runtime mounts + ContributeRuntimeMounts(workflowData.SandboxConfig.Agent, runtimeRequirements) + + // Generate execution steps + engine := NewCopilotEngine() + steps := engine.GetExecutionSteps(workflowData, "test.log") + + require.NotEmpty(t, steps, "Should generate execution steps") + + stepContent := strings.Join(steps[0], "\n") + + // Verify runtime mounts are included in AWF command + assert.Contains(t, stepContent, "--mount /opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro", + "AWF command should include node toolcache mount") + assert.Contains(t, stepContent, "--mount /home/runner/.npm:/home/runner/.npm:rw", + "AWF command should include npm cache mount") + }) + + t.Run("runtime mounts are sorted in AWF command", func(t *testing.T) { + workflowData := &WorkflowData{ + Name: "test-workflow", + EngineConfig: &EngineConfig{ + ID: "copilot", + }, + SandboxConfig: &SandboxConfig{ + Agent: &AgentSandboxConfig{ + ID: "awf", + // Add custom mounts to test sorting with runtime mounts + Mounts: []string{ + "/zzz/custom:/zzz/custom:ro", // Should appear after runtime mounts + "/aaa/custom:/aaa/custom:ro", // Should appear before runtime mounts + }, + }, + }, + NetworkPermissions: &NetworkPermissions{ + Firewall: &FirewallConfig{ + Enabled: true, + }, + }, + CustomSteps: ` - name: Build + run: go build`, + } + + // Detect runtime requirements + runtimeRequirements := DetectRuntimeRequirements(workflowData) + + // Contribute runtime mounts + ContributeRuntimeMounts(workflowData.SandboxConfig.Agent, runtimeRequirements) + + // Generate execution steps + engine := NewCopilotEngine() + steps := engine.GetExecutionSteps(workflowData, "test.log") + + require.NotEmpty(t, steps, "Should generate execution steps") + + stepContent := strings.Join(steps[0], "\n") + + // Find positions of mounts in the output + aaaPos := strings.Index(stepContent, "--mount /aaa/custom:/aaa/custom:ro") + goToolcachePos := strings.Index(stepContent, "--mount /opt/hostedtoolcache/go:/opt/hostedtoolcache/go:ro") + zzzPos := strings.Index(stepContent, "--mount /zzz/custom:/zzz/custom:ro") + + // Verify all mounts are present + assert.NotEqual(t, -1, aaaPos, "Should find custom /aaa mount") + assert.NotEqual(t, -1, goToolcachePos, "Should find go toolcache mount") + assert.NotEqual(t, -1, zzzPos, "Should find custom /zzz mount") + + // Verify mounts are in alphabetical order by checking positions + // Custom mounts and runtime mounts should all be sorted together + if aaaPos != -1 && goToolcachePos != -1 { + assert.Less(t, aaaPos, goToolcachePos, + "/aaa mount should appear before /opt mount (alphabetically)") + } + if goToolcachePos != -1 && zzzPos != -1 { + assert.Less(t, goToolcachePos, zzzPos, + "/opt mount should appear before /zzz mount (alphabetically)") + } + }) +} diff --git a/pkg/workflow/runtime_mounts_test.go b/pkg/workflow/runtime_mounts_test.go new file mode 100644 index 0000000000..dcc0b65f0b --- /dev/null +++ b/pkg/workflow/runtime_mounts_test.go @@ -0,0 +1,379 @@ +package workflow + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetRuntimeMounts(t *testing.T) { + tests := []struct { + name string + requirements []RuntimeRequirement + expectedContains []string + expectedExcludes []string + expectedMinCount int + }{ + { + name: "node runtime includes toolcache and npm cache", + requirements: []RuntimeRequirement{ + { + Runtime: findRuntimeByID("node"), + Version: "20", + }, + }, + expectedContains: []string{ + "/opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro", + "/home/runner/.npm:/home/runner/.npm:rw", + }, + expectedMinCount: 2, + }, + { + name: "python runtime includes toolcache and pip cache", + requirements: []RuntimeRequirement{ + { + Runtime: findRuntimeByID("python"), + Version: "3.11", + }, + }, + expectedContains: []string{ + "/opt/hostedtoolcache/Python:/opt/hostedtoolcache/Python:ro", + "/home/runner/.cache/pip:/home/runner/.cache/pip:rw", + }, + expectedMinCount: 2, + }, + { + name: "go runtime includes toolcache, GOPATH, and build cache", + requirements: []RuntimeRequirement{ + { + Runtime: findRuntimeByID("go"), + Version: "1.22", + }, + }, + expectedContains: []string{ + "/opt/hostedtoolcache/go:/opt/hostedtoolcache/go:ro", + "/home/runner/go:/home/runner/go:rw", + "/home/runner/.cache/go-build:/home/runner/.cache/go-build:rw", + }, + expectedMinCount: 3, + }, + { + name: "multiple runtimes combine mounts", + requirements: []RuntimeRequirement{ + { + Runtime: findRuntimeByID("node"), + Version: "20", + }, + { + Runtime: findRuntimeByID("python"), + Version: "3.11", + }, + }, + expectedContains: []string{ + "/opt/hostedtoolcache/node:/opt/hostedtoolcache/node:ro", + "/home/runner/.npm:/home/runner/.npm:rw", + "/opt/hostedtoolcache/Python:/opt/hostedtoolcache/Python:ro", + "/home/runner/.cache/pip:/home/runner/.cache/pip:rw", + }, + expectedMinCount: 4, + }, + { + name: "uv runtime includes cache", + requirements: []RuntimeRequirement{ + { + Runtime: findRuntimeByID("uv"), + Version: "", + }, + }, + expectedContains: []string{ + "/home/runner/.cache/uv:/home/runner/.cache/uv:rw", + }, + expectedMinCount: 1, + }, + { + name: "java runtime includes toolcache, maven, and gradle", + requirements: []RuntimeRequirement{ + { + Runtime: findRuntimeByID("java"), + Version: "17", + }, + }, + expectedContains: []string{ + "/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk:/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk:ro", + "/home/runner/.m2:/home/runner/.m2:rw", + "/home/runner/.gradle:/home/runner/.gradle:rw", + }, + expectedMinCount: 3, + }, + { + name: "no requirements returns empty list", + requirements: []RuntimeRequirement{}, + expectedContains: []string{}, + expectedMinCount: 0, + }, + { + name: "deduplicates identical mounts from multiple runtimes", + requirements: []RuntimeRequirement{ + { + Runtime: findRuntimeByID("python"), + Version: "3.11", + }, + { + Runtime: findRuntimeByID("uv"), + Version: "", + }, + }, + // Both python and uv might share cache directories + // Ensure no duplicates in final list + expectedMinCount: 2, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mounts := GetRuntimeMounts(tt.requirements) + + // Check minimum count + assert.GreaterOrEqual(t, len(mounts), tt.expectedMinCount, + "Should have at least %d mounts, got %d", tt.expectedMinCount, len(mounts)) + + // Check that expected mounts are present + for _, expectedMount := range tt.expectedContains { + assert.Contains(t, mounts, expectedMount, + "Expected mount %q to be present", expectedMount) + } + + // Check that excluded mounts are not present + for _, excludedMount := range tt.expectedExcludes { + assert.NotContains(t, mounts, excludedMount, + "Expected mount %q to be excluded", excludedMount) + } + + // Verify mounts are sorted + if len(mounts) > 1 { + for i := 0; i < len(mounts)-1; i++ { + assert.LessOrEqual(t, mounts[i], mounts[i+1], + "Mounts should be sorted alphabetically") + } + } + + // Verify no duplicate mounts + seen := make(map[string]bool) + for _, mount := range mounts { + assert.False(t, seen[mount], "Found duplicate mount: %s", mount) + seen[mount] = true + } + + // Verify mount format (source:dest:mode) + for _, mount := range mounts { + parts := strings.Split(mount, ":") + assert.Len(t, parts, 3, + "Mount %q should have 3 parts (source:dest:mode)", mount) + assert.NotEmpty(t, parts[0], "Source path should not be empty in mount %q", mount) + assert.NotEmpty(t, parts[1], "Destination path should not be empty in mount %q", mount) + assert.Contains(t, []string{"ro", "rw"}, parts[2], + "Mode in mount %q should be 'ro' or 'rw'", mount) + } + }) + } +} + +func TestGetRuntimeMountDefinition(t *testing.T) { + tests := []struct { + name string + runtimeID string + expectNil bool + expectedMinMounts int + }{ + { + name: "node has mount definitions", + runtimeID: "node", + expectNil: false, + expectedMinMounts: 2, + }, + { + name: "python has mount definitions", + runtimeID: "python", + expectNil: false, + expectedMinMounts: 2, + }, + { + name: "go has mount definitions", + runtimeID: "go", + expectNil: false, + expectedMinMounts: 3, + }, + { + name: "unknown runtime returns nil", + runtimeID: "unknown-runtime", + expectNil: true, + expectedMinMounts: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + def := getRuntimeMountDefinition(tt.runtimeID) + + if tt.expectNil { + assert.Nil(t, def, "Expected nil for runtime %s", tt.runtimeID) + } else { + require.NotNil(t, def, "Expected non-nil definition for runtime %s", tt.runtimeID) + assert.Equal(t, tt.runtimeID, def.RuntimeID, + "RuntimeID should match") + assert.GreaterOrEqual(t, len(def.Mounts), tt.expectedMinMounts, + "Should have at least %d mounts", tt.expectedMinMounts) + } + }) + } +} + +func TestContributeRuntimeMounts(t *testing.T) { + tests := []struct { + name string + agentConfig *AgentSandboxConfig + requirements []RuntimeRequirement + expectedMinMounts int + expectNoChange bool + }{ + { + name: "adds runtime mounts to empty agent config", + agentConfig: &AgentSandboxConfig{ + ID: "awf", + }, + requirements: []RuntimeRequirement{ + { + Runtime: findRuntimeByID("node"), + Version: "20", + }, + }, + expectedMinMounts: 2, + expectNoChange: false, + }, + { + name: "adds runtime mounts to existing user mounts", + agentConfig: &AgentSandboxConfig{ + ID: "awf", + Mounts: []string{ + "/custom/path:/custom/path:ro", + }, + }, + requirements: []RuntimeRequirement{ + { + Runtime: findRuntimeByID("python"), + Version: "3.11", + }, + }, + expectedMinMounts: 3, // 1 custom + 2 runtime + expectNoChange: false, + }, + { + name: "nil agent config does not panic", + agentConfig: nil, + requirements: []RuntimeRequirement{}, + expectedMinMounts: 0, + expectNoChange: true, + }, + { + name: "no requirements does not add mounts", + agentConfig: &AgentSandboxConfig{ + ID: "awf", + }, + requirements: []RuntimeRequirement{}, + expectedMinMounts: 0, + expectNoChange: true, + }, + { + name: "multiple runtimes add combined mounts", + agentConfig: &AgentSandboxConfig{ + ID: "awf", + }, + requirements: []RuntimeRequirement{ + { + Runtime: findRuntimeByID("node"), + Version: "20", + }, + { + Runtime: findRuntimeByID("go"), + Version: "1.22", + }, + }, + expectedMinMounts: 5, // 2 (node) + 3 (go) + expectNoChange: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + originalMountCount := 0 + if tt.agentConfig != nil { + originalMountCount = len(tt.agentConfig.Mounts) + } + + ContributeRuntimeMounts(tt.agentConfig, tt.requirements) + + if tt.expectNoChange { + if tt.agentConfig != nil { + assert.Len(t, tt.agentConfig.Mounts, originalMountCount, + "Mount count should not change") + } + } else { + require.NotNil(t, tt.agentConfig, "Agent config should not be nil") + assert.GreaterOrEqual(t, len(tt.agentConfig.Mounts), tt.expectedMinMounts, + "Should have at least %d mounts after contribution", tt.expectedMinMounts) + } + }) + } +} + +func TestGetRuntimeMountsForWorkflow(t *testing.T) { + tests := []struct { + name string + workflowData *WorkflowData + expectedMinMounts int + }{ + { + name: "workflow with node in custom steps", + workflowData: &WorkflowData{ + Name: "test-workflow", + CustomSteps: ` - name: Install deps + run: npm install`, + }, + expectedMinMounts: 2, // node mounts + }, + { + name: "workflow with python in custom steps", + workflowData: &WorkflowData{ + Name: "test-workflow", + CustomSteps: ` - name: Run script + run: python script.py`, + }, + expectedMinMounts: 2, // python mounts + }, + { + name: "nil workflow returns empty list", + workflowData: nil, + expectedMinMounts: 0, + }, + { + name: "workflow with no runtime commands", + workflowData: &WorkflowData{ + Name: "test-workflow", + CustomSteps: ` - name: Echo + run: echo "hello"`, + }, + expectedMinMounts: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mounts := GetRuntimeMountsForWorkflow(tt.workflowData) + + assert.GreaterOrEqual(t, len(mounts), tt.expectedMinMounts, + "Should have at least %d mounts", tt.expectedMinMounts) + }) + } +} diff --git a/pkg/workflow/sandbox_mounts_test.go b/pkg/workflow/sandbox_mounts_test.go index fcc1ec43fa..e70eb9257f 100644 --- a/pkg/workflow/sandbox_mounts_test.go +++ b/pkg/workflow/sandbox_mounts_test.go @@ -186,7 +186,7 @@ func TestSandboxConfigWithMounts(t *testing.T) { }, }, wantErr: true, - errMsg: "invalid mount syntax", + errMsg: "mount syntax must follow 'source:destination:mode' format", }, { name: "invalid mode in mount",