diff --git a/.github/workflows/avenger.lock.yml b/.github/workflows/avenger.lock.yml index 092aada6f01..3d6eb6ec67f 100644 --- a/.github/workflows/avenger.lock.yml +++ b/.github/workflows/avenger.lock.yml @@ -1,5 +1,5 @@ # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"6807590fb97b42c0858f3b0e068f5f2b823e6d3a5a873b1a1652f5658361eb44","body_hash":"e5fd04fe008ba327d939d9aee395ffb802836e30fd1f3772ca36984bdd1478f4","strict":true,"agent_id":"claude","agent_model":"claude-haiku-4.5","engine_versions":{"claude":"2.1.210"}} -# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]} +# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]} # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # # ___ _ _ @@ -44,7 +44,6 @@ # Custom actions used: # - actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 -# - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1146,7 +1145,7 @@ jobs: GH_HOST="${GH_HOST#http://}" echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Check last CI workflow run status on main branch diff --git a/.github/workflows/hourly-ci-cleaner.lock.yml b/.github/workflows/hourly-ci-cleaner.lock.yml index 7fbc3953765..4c96d7c4a51 100644 --- a/.github/workflows/hourly-ci-cleaner.lock.yml +++ b/.github/workflows/hourly-ci-cleaner.lock.yml @@ -1,5 +1,5 @@ # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8b86cc12904088cf1b7630e0faa28299f64081df184a028b6293cb4f8bfdd07d","body_hash":"8eb6f8fd1e8e3d63cfd268226d09333129d49634435ae9a3c88debb099521ed5","strict":true,"agent_id":"claude","engine_versions":{"claude":"2.1.210"}} -# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]} +# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]} # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # # ___ _ _ @@ -45,7 +45,6 @@ # Custom actions used: # - actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 -# - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1153,7 +1152,7 @@ jobs: GH_HOST="${GH_HOST#http://}" echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Check last CI workflow run status on main branch diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 279d407502e..b670dfbb32e 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -1,5 +1,5 @@ # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"2d6e82aec6fea9061e1ef1cbb085324e6ed6c079230d70bbbb96611bb18cf7cf","body_hash":"646353d7bb4e5523bc85349c2cce38188190095a303f83cc95961ff145a47043","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.70"}} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"anchore/sbom-action","sha":"e22c389904149dbc22b58101806040fa8d37a610","version":"v0.24.0"},{"repo":"docker/build-push-action","sha":"53b7df96c91f9c12dcc8a07bcb9ccacbed38856a","version":"v7.3.0"},{"repo":"docker/login-action","sha":"af1e73f918a031802d376d3c8bbc3fe56130a9b0","version":"v4.4.0"},{"repo":"docker/metadata-action","sha":"dc802804100637a589fabce1cb79ff13a1411302","version":"v6.2.0"},{"repo":"docker/setup-buildx-action","sha":"bb05f3f5519dd87d3ba754cc423b652a5edd6d2c","version":"v4.2.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"b7ad1dad31e06c5925ef5d2fc7ad053ef454303e","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"anchore/sbom-action","sha":"e22c389904149dbc22b58101806040fa8d37a610","version":"v0.24.0"},{"repo":"docker/build-push-action","sha":"53b7df96c91f9c12dcc8a07bcb9ccacbed38856a","version":"v7.3.0"},{"repo":"docker/login-action","sha":"af1e73f918a031802d376d3c8bbc3fe56130a9b0","version":"v4.4.0"},{"repo":"docker/metadata-action","sha":"dc802804100637a589fabce1cb79ff13a1411302","version":"v6.2.0"},{"repo":"docker/setup-buildx-action","sha":"bb05f3f5519dd87d3ba754cc423b652a5edd6d2c","version":"v4.2.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]} # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # # ___ _ _ @@ -47,7 +47,7 @@ # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) -# - actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # b7ad1dad31e06c5925ef5d2fc7ad053ef454303e +# - actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 # - docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 @@ -1949,7 +1949,7 @@ jobs: env: RELEASE_TAG: ${{ needs.config.outputs.release_tag }} - name: Setup Go - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # b7ad1dad31e06c5925ef5d2fc7ad053ef454303e + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: cache: false go-version-file: go.mod diff --git a/.github/workflows/skillet.lock.yml b/.github/workflows/skillet.lock.yml index 8d7320c75be..81a6ce1825b 100644 --- a/.github/workflows/skillet.lock.yml +++ b/.github/workflows/skillet.lock.yml @@ -1,5 +1,5 @@ # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"2b7791e73899163b45a0881db45f5747495a6a7dbd2dc4e17f3f31af4ecf6898","body_hash":"ff6f6b1fbf4788ce998b5ddca9ed8f907259189ec1db98a5cd9768e4e0ed2f50","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.70"}} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"3a2844b7e9c422d3c10d287c895573f7108da1b3"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"3a2844b7e9c422d3c10d287c895573f7108da1b3"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35","digest":"sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.35@sha256:2202f63e8650b2b8b0d38033b44a05387b2b71ad3e690c4d23a34786f5462aed"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35","digest":"sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.35@sha256:755b79d0dfda82bd6b43a208d68666721e504110c5d342a4eeb199802644ff04"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35","digest":"sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.35@sha256:fe83cd274636efa9de3f456e2b078fae137328b9bb6ee4986ae510acaef0cec5"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35","digest":"sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.35@sha256:f69282ec7b1326ba53891c399cf5b10475c0d3ccf4e1519b33d234a5427b57d3"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]} # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # # ___ _ _ @@ -45,7 +45,6 @@ # Custom actions used: # - actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 -# - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 @@ -1728,7 +1727,7 @@ jobs: GH_AW_INFO_AWF_VERSION: "v0.27.35" GH_AW_INFO_ENGINE_ID: "copilot" - name: Checkout skills directory - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false sparse-checkout: | diff --git a/.github/workflows/smoke-ci.lock.yml b/.github/workflows/smoke-ci.lock.yml index dbbf0942dcc..e118a789704 100644 --- a/.github/workflows/smoke-ci.lock.yml +++ b/.github/workflows/smoke-ci.lock.yml @@ -1078,6 +1078,7 @@ jobs: export XDG_CONFIG_HOME="$HOME" export GH_AW_MCP_CONFIG="$HOME/.copilot/mcp-config.json" mkdir -p /tmp/gh-aw + GH_AW_PREV_UMASK="$(umask)" umask 0177 cat > /tmp/gh-aw/engine-command.sh <<'GH_AW_ENGINE_COMMAND_EOF' #!/usr/bin/env bash @@ -1087,6 +1088,7 @@ jobs: GH_AW_ENGINE_COMMAND_EOF chmod 700 /tmp/gh-aw/engine-command.sh + umask "$GH_AW_PREV_UMASK" touch /tmp/gh-aw/agent-step-summary.md GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN diff --git a/actions/setup/sh/install_antigravity_cli.sh b/actions/setup/sh/install_antigravity_cli.sh index 858ffbbe5b3..c185d6ebf4b 100644 --- a/actions/setup/sh/install_antigravity_cli.sh +++ b/actions/setup/sh/install_antigravity_cli.sh @@ -2,13 +2,16 @@ set +o histexpand # Install Antigravity CLI (agy) from Google Cloud Storage -# Usage: install_antigravity_cli.sh VERSION +# Usage: install_antigravity_cli.sh VERSION [--rootless] # # This script downloads and installs the Antigravity CLI binary directly from # Google Cloud Storage (https://storage.googleapis.com/antigravity-public/). # # Arguments: -# VERSION - Antigravity CLI version to install (required) +# VERSION - Antigravity CLI version to install (required) +# --rootless - Install to ~/.local/bin without sudo; appends that directory to +# $GITHUB_PATH so subsequent steps find the binary. Use this on +# ARC/DinD runners that enforce allowPrivilegeEscalation: false. # # Security features: # - Downloads binary directly from Google Cloud Storage over HTTPS @@ -20,16 +23,55 @@ set +o histexpand set -euo pipefail # Configuration -VERSION="${1:-}" GCS_BASE_URL="https://storage.googleapis.com/antigravity-public/antigravity-cli" INSTALL_DIR="/usr/local/bin" BINARY_NAME="agy" +# Parse arguments: treat the first non-flag argument as VERSION, all -- arguments as flags. +VERSION="" +ROOTLESS=false +for arg in "$@"; do + case "$arg" in + --rootless) ROOTLESS=true ;; + --*) echo "WARNING: Unknown flag: $arg" >&2 ;; + *) + if [ -z "$VERSION" ]; then + VERSION="$arg" + fi + ;; + esac +done + if [ -z "$VERSION" ]; then echo "ERROR: Version argument is required" + echo "Usage: $0 VERSION [--rootless]" exit 1 fi +# In rootless mode, install into the user's home directory instead of /usr/local/bin +# so that ARC/DinD runners with allowPrivilegeEscalation: false can run without sudo. +if [ "$ROOTLESS" = "true" ]; then + INSTALL_DIR="${HOME}/.local/bin" +fi + +# maybe_sudo runs a command with sudo unless --rootless was specified. +# In rootless mode, sudo is not available or needed. +maybe_sudo() { + if [ "$ROOTLESS" = "true" ]; then + "$@" + else + sudo "$@" + fi +} + +# Rootless mode preflight: create and verify write access to the install directory. +if [ "$ROOTLESS" = "true" ]; then + if ! { mkdir -p "${INSTALL_DIR}" && [ -w "${INSTALL_DIR}" ]; }; then + echo "ERROR: --rootless could not create a writable install directory at ${INSTALL_DIR}" >&2 + exit 1 + fi +fi + # Detect OS and architecture OS="$(uname -s)" ARCH="$(uname -m)" @@ -131,7 +173,17 @@ if [ ! -f "${TEMP_DIR}/antigravity" ]; then echo "ERROR: Expected binary 'antigravity' not found in the extracted archive" exit 1 fi -sudo install -m 755 "${TEMP_DIR}/antigravity" "${INSTALL_DIR}/${BINARY_NAME}" +maybe_sudo install -m 755 "${TEMP_DIR}/antigravity" "${INSTALL_DIR}/${BINARY_NAME}" + +# In rootless mode, add the install dir to PATH for subsequent steps. +if [ "$ROOTLESS" = "true" ]; then + if [ -n "${GITHUB_PATH:-}" ]; then + echo "${INSTALL_DIR}" >> "${GITHUB_PATH}" + echo " Exported ${INSTALL_DIR} to GITHUB_PATH" + else + echo " GITHUB_PATH not set — binary installed at ${INSTALL_DIR}/${BINARY_NAME}" + fi +fi # Verify installation echo "Verifying Antigravity CLI installation..." diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index d3ba2452ee7..59a408dbe4b 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -2,14 +2,17 @@ set +o histexpand # Install GitHub Copilot CLI with SHA256 checksum verification -# Usage: install_copilot_cli.sh [VERSION] +# Usage: install_copilot_cli.sh [VERSION] [--rootless] # # This script downloads and installs the GitHub Copilot CLI directly from GitHub # releases with SHA256 checksum verification, following the secure pattern from # install_awf_binary.sh to avoid executing unverified downloaded scripts. # # Arguments: -# VERSION - Optional Copilot CLI version to install (default: latest release) +# VERSION - Optional Copilot CLI version to install (default: latest release) +# --rootless - Install to ~/.local/bin without sudo; appends that directory to +# $GITHUB_PATH so subsequent steps find the binary. Use this on +# ARC/DinD runners that enforce allowPrivilegeEscalation: false. # # Security features: # - Downloads binary directly from GitHub releases (no installer script execution) @@ -20,7 +23,6 @@ set -euo pipefail # Configuration SECONDS_PER_DAY=86400 -VERSION="${1:-}" COPILOT_REPO="github/copilot-cli" INSTALL_DIR="/usr/local/bin" COPILOT_DIR="${HOME}/.copilot" @@ -34,6 +36,45 @@ COMPAT_MATCHED_MIN_AGENT="" COMPAT_MATCHED_MAX_AGENT="" COMPAT_CACHE_TTL_DAYS="" +# Parse arguments: treat the first non-flag argument as VERSION, all -- arguments as flags. +VERSION="" +ROOTLESS=false +for arg in "$@"; do + case "$arg" in + --rootless) ROOTLESS=true ;; + --*) echo "WARNING: Unknown flag: $arg" >&2 ;; + *) + if [ -z "$VERSION" ]; then + VERSION="$arg" + fi + ;; + esac +done + +# In rootless mode, install into the user's home directory instead of /usr/local/bin +# so that ARC/DinD runners with allowPrivilegeEscalation: false can run without sudo. +if [ "$ROOTLESS" = "true" ]; then + INSTALL_DIR="${HOME}/.local/bin" +fi + +# maybe_sudo runs a command with sudo unless --rootless was specified. +# In rootless mode, sudo is not available or needed. +maybe_sudo() { + if [ "$ROOTLESS" = "true" ]; then + "$@" + else + sudo "$@" + fi +} + +# Rootless mode preflight: create and verify write access to the install directory. +if [ "$ROOTLESS" = "true" ]; then + if ! { mkdir -p "${INSTALL_DIR}" && [ -w "${INSTALL_DIR}" ]; }; then + echo "ERROR: --rootless could not create a writable install directory at ${INSTALL_DIR}" >&2 + exit 1 + fi +fi + # Fix directory ownership before installation # This is needed because a previous AWF run on the same runner may have used # `sudo -E awf --enable-chroot ...`, which creates the .copilot directory with @@ -41,7 +82,7 @@ COMPAT_CACHE_TTL_DAYS="" # trying to create subdirectories. See: https://github.com/github/gh-aw/issues/12066 echo "Ensuring correct ownership of $COPILOT_DIR..." mkdir -p "$COPILOT_DIR" -sudo chown -R "$(id -u):$(id -g)" "$COPILOT_DIR" +maybe_sudo chown -R "$(id -u):$(id -g)" "$COPILOT_DIR" # Clean up any stale AWF chroot home directories left by previous runs. # When AWF ran with `sudo -E awf --enable-host-access`, it created @@ -50,7 +91,7 @@ sudo chown -R "$(id -u):$(id -g)" "$COPILOT_DIR" # subsequent runs, which reports as "engine terminated unexpectedly". # Remove them here before the agent starts so the runner is in a clean state. echo "Cleaning up stale AWF chroot home directories..." -sudo find /tmp -maxdepth 1 -name 'awf-*-chroot-home' -type d -exec rm -rf -- {} + 2>/dev/null || true +maybe_sudo find /tmp -maxdepth 1 -name 'awf-*-chroot-home' -type d -exec rm -rf -- {} + 2>/dev/null || true # Detect OS and architecture OS="$(uname -s)" @@ -452,7 +493,7 @@ activate_cached_copilot_bin() { #!/usr/bin/env bash exec "$cached_copilot_bin" "\$@" EOF - sudo install -m 0755 "$wrapper_path" "${INSTALL_DIR}/copilot" + maybe_sudo install -m 0755 "$wrapper_path" "${INSTALL_DIR}/copilot" echo " Wrapper installed at ${INSTALL_DIR}/copilot" } @@ -544,12 +585,31 @@ echo "✓ Checksum verification passed for ${TARBALL_NAME}" # Extract and install binary echo "Installing binary to ${INSTALL_DIR}..." -sudo tar -xz -C "${INSTALL_DIR}" -f "${TEMP_DIR}/${TARBALL_NAME}" -sudo chmod +x "${INSTALL_DIR}/copilot" +maybe_sudo tar -xz -C "${INSTALL_DIR}" -f "${TEMP_DIR}/${TARBALL_NAME}" +maybe_sudo chmod +x "${INSTALL_DIR}/copilot" + +# In rootless mode, add the install dir to PATH for subsequent steps. +# $GITHUB_PATH is the mechanism for persisting PATH additions across steps in GitHub Actions. +if [ "$ROOTLESS" = "true" ]; then + if [ -n "${GITHUB_PATH:-}" ]; then + echo "${INSTALL_DIR}" >> "${GITHUB_PATH}" + echo " Exported ${INSTALL_DIR} to GITHUB_PATH" + else + echo "WARNING: --rootless install complete but \$GITHUB_PATH is unset; add ${INSTALL_DIR} to PATH manually" >&2 + fi +fi # Verify installation echo "Verifying Copilot CLI installation..." -if command -v copilot >/dev/null 2>&1; then +if [ "$ROOTLESS" = "true" ]; then + if [ -x "${INSTALL_DIR}/copilot" ]; then + "${INSTALL_DIR}/copilot" --version + echo "✓ Copilot CLI installation complete" + else + echo "ERROR: Copilot CLI installation failed - binary not found at ${INSTALL_DIR}/copilot" + exit 1 + fi +elif command -v copilot >/dev/null 2>&1; then copilot --version echo "✓ Copilot CLI installation complete" else diff --git a/actions/setup/sh/install_threat_detect_binary.sh b/actions/setup/sh/install_threat_detect_binary.sh index 7e50b0135f3..102a3f67bc5 100755 --- a/actions/setup/sh/install_threat_detect_binary.sh +++ b/actions/setup/sh/install_threat_detect_binary.sh @@ -5,10 +5,13 @@ set +o histexpand # Used when `features: gh-aw-detection: true` is set in the workflow frontmatter to enable # the external threat-detect binary detection path instead of inline engine execution. # -# Usage: install_threat_detect_binary.sh VERSION +# Usage: install_threat_detect_binary.sh VERSION [--rootless] # # Arguments: -# VERSION - threat-detect version to install (e.g., v0.2.2) +# VERSION - threat-detect version to install (e.g., v0.2.2) +# --rootless - Install to ~/.local/bin without sudo; appends that directory to +# $GITHUB_PATH so subsequent steps find the binary. Use this on +# ARC/DinD runners that enforce allowPrivilegeEscalation: false. # # Platform support: # - Linux (x64, arm64): Downloads pre-built binary @@ -21,17 +24,55 @@ set +o histexpand set -euo pipefail # Configuration -THREAT_DETECT_VERSION="${1:-}" THREAT_DETECT_REPO="github/gh-aw-threat-detection" THREAT_DETECT_INSTALL_DIR="/usr/local/bin" THREAT_DETECT_INSTALL_NAME="threat-detect" +# Parse arguments: treat the first non-flag argument as VERSION, all -- arguments as flags. +THREAT_DETECT_VERSION="" +ROOTLESS=false +for arg in "$@"; do + case "$arg" in + --rootless) ROOTLESS=true ;; + --*) echo "WARNING: Unknown flag: $arg" >&2 ;; + *) + if [ -z "$THREAT_DETECT_VERSION" ]; then + THREAT_DETECT_VERSION="$arg" + fi + ;; + esac +done + if [ -z "$THREAT_DETECT_VERSION" ]; then echo "ERROR: threat-detect version is required" - echo "Usage: $0 VERSION" + echo "Usage: $0 VERSION [--rootless]" exit 1 fi +# In rootless mode, install into the user's home directory instead of /usr/local/bin +# so that ARC/DinD runners with allowPrivilegeEscalation: false can run without sudo. +if [ "$ROOTLESS" = "true" ]; then + THREAT_DETECT_INSTALL_DIR="${HOME}/.local/bin" +fi + +# maybe_sudo runs a command with sudo unless --rootless was specified. +# In rootless mode, sudo is not available or needed. +maybe_sudo() { + if [ "$ROOTLESS" = "true" ]; then + "$@" + else + sudo "$@" + fi +} + +# Rootless mode preflight: create and verify write access to the install directory. +if [ "$ROOTLESS" = "true" ]; then + if ! { mkdir -p "${THREAT_DETECT_INSTALL_DIR}" && [ -w "${THREAT_DETECT_INSTALL_DIR}" ]; }; then + echo "ERROR: --rootless could not create a writable install directory at ${THREAT_DETECT_INSTALL_DIR}" >&2 + exit 1 + fi +fi + # Detect OS and architecture OS="$(uname -s)" ARCH="$(uname -m)" @@ -106,7 +147,7 @@ install_linux_binary() { # Make binary executable and install chmod +x "${TEMP_DIR}/${binary_name}" - sudo mv "${TEMP_DIR}/${binary_name}" "${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}" + maybe_sudo mv "${TEMP_DIR}/${binary_name}" "${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}" } install_darwin_binary() { @@ -127,7 +168,7 @@ install_darwin_binary() { # Make binary executable and install chmod +x "${TEMP_DIR}/${binary_name}" - sudo mv "${TEMP_DIR}/${binary_name}" "${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}" + maybe_sudo mv "${TEMP_DIR}/${binary_name}" "${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}" } case "$OS" in @@ -143,6 +184,16 @@ case "$OS" in ;; esac +# In rootless mode, add the install dir to PATH for subsequent steps. +if [ "$ROOTLESS" = "true" ]; then + if [ -n "${GITHUB_PATH:-}" ]; then + echo "${THREAT_DETECT_INSTALL_DIR}" >> "${GITHUB_PATH}" + echo " Exported ${THREAT_DETECT_INSTALL_DIR} to GITHUB_PATH" + else + echo " GITHUB_PATH not set — binary installed at ${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}" + fi +fi + # Verify installation "${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}" --version diff --git a/docs/src/content/docs/guides/arc-dind-copilot-agent.md b/docs/src/content/docs/guides/arc-dind-copilot-agent.md index d7daa26de48..f767527b817 100644 --- a/docs/src/content/docs/guides/arc-dind-copilot-agent.md +++ b/docs/src/content/docs/guides/arc-dind-copilot-agent.md @@ -115,7 +115,7 @@ Use versions at or above these minimums: | DinD container mode | **Yes** | GitHub Copilot coding agent needs a Docker daemon in the runner pod. | | `NET_ADMIN` capability | **No** | Not required. AWF enforces egress via Docker network topology (network isolation mode), not host `iptables`. The DinD sidecar daemon manages all network enforcement internally. | | `ghcr.io/actions/actions-runner:latest` | Recommended | Use the official runner image, or a compatible custom image with equivalent runner requirements. | -| Runner user | **Yes** | Non-root runner users are supported. `sudo` must remain available on the runner container for the Copilot CLI install script (binary installation and file ownership operations). | +| Runner user | **Yes** | Non-root runner users are supported. By default, `sudo` must be available on the runner container for the Copilot CLI install script. If your cluster enforces `allowPrivilegeEscalation: false`, use the `--rootless` flag — see [Pod security and rootless install](#pod-security-and-rootless-install) below. | | DinD sidecar privilege | **Yes** | ARC DinD mode configures a privileged sidecar for Docker daemon operation. | | Shared work volume (`/home/runner/_work`) | **Yes** | Runner and Docker daemon share this volume in ARC DinD mode, so workspace mounts work without host path translation. | | Specific Kubernetes distribution | **No** | Any conformant cluster works (for example minikube, EKS, AKS, or GKE). | @@ -133,9 +133,33 @@ To migrate: 4. Add `runner.topology: arc-dind` to frontmatter. 5. Run `gh aw compile` and commit the updated lock file. +## Pod security and rootless install + +Clusters that enforce `allowPrivilegeEscalation: false` (via PodSecurity Admission or OPA policies) prevent the default Copilot CLI install script from using `sudo`. + +Pass `--rootless` to `install_copilot_cli.sh` in your `copilot-setup-steps` to install to `~/.local/bin` without any `sudo` calls. The script adds that directory to `$GITHUB_PATH` so subsequent steps find the binary: + +```yaml +copilot-setup-steps: + runs-on: arc-runner-set + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + repository: github/gh-aw + path: gh-aw + - name: Install Copilot CLI (rootless) + run: bash "${GITHUB_WORKSPACE}/gh-aw/actions/setup/sh/install_copilot_cli.sh" --rootless + env: + GH_HOST: github.com +``` + +In rootless mode: +- The binary is installed to `~/.local/bin/copilot` (no `sudo` required). +- `~/.local/bin` is appended to `$GITHUB_PATH` so `copilot` is on `PATH` for all later steps. +- Ownership and cleanup operations that previously used `sudo` run as the current user (which owns the relevant files in rootless deployments). + ## Known limitations -- **`allowPrivilegeEscalation: false` is not supported.** The Copilot CLI install script uses `sudo`. Clusters that enforce `no-new-privileges` via PodSecurity Admission or OPA policies will fail at the install step. - **MCP gateway Docker socket access** — on runners where `DOCKER_HOST` is a TCP endpoint and no Unix socket exists at `/var/run/docker.sock`, the MCP gateway may fail to connect to the Docker daemon (`Docker daemon is not accessible`). As a workaround, expose the DinD sidecar's Unix socket on the runner container at `/var/run/docker.sock` via a shared volume or symlink. See [#44251](https://github.com/github/gh-aw/issues/44251) for tracking. ## Troubleshooting @@ -155,7 +179,7 @@ The threat-detection job can't find the Copilot binary. This was fixed in gh-aw ### `sudo: The "no new privileges" flag is set` -The runner pod's security context has `allowPrivilegeEscalation: false`. Remove that constraint or adjust your PodSecurity policy to allow privilege escalation in the runner container. +The runner pod's security context has `allowPrivilegeEscalation: false`. Pass `--rootless` to the Copilot CLI install script so it installs without `sudo` — see [Pod security and rootless install](#pod-security-and-rootless-install) above. ### `Docker daemon is not accessible` in MCP gateway diff --git a/docs/src/content/docs/reference/self-hosted-runners.md b/docs/src/content/docs/reference/self-hosted-runners.md index 1049828ac44..7fc85c43da5 100644 --- a/docs/src/content/docs/reference/self-hosted-runners.md +++ b/docs/src/content/docs/reference/self-hosted-runners.md @@ -13,7 +13,7 @@ Self-hosted runners may require `sudo` depending on the selected engine and conf - **AWF (Agentic Workflow Firewall)**: Runs rootless in the default network-isolation mode. Egress is enforced via Docker network topology — an internal Docker network (`awf-net`) with no internet route and a dual-homed Squid proxy as the sole egress path. No `sudo` and no `NET_ADMIN` are required on the runner for AWF in this mode. Container-level `iptables`, Squid proxy ACLs, and capability drops provide defense in depth, all managed inside the Docker daemon's domain. -- **Copilot CLI install**: The `install_copilot_cli.sh` script runs as the runner user but escalates via `sudo` for specific file operations (fixing `.copilot` directory ownership, cleaning stale chroot directories, and installing the Copilot binary). ARC pods with `allowPrivilegeEscalation: false` will fail at this step with `sudo: The "no new privileges" flag is set`. +- **Copilot CLI install**: The `install_copilot_cli.sh` script runs as the runner user. By default it escalates via `sudo` for file operations (fixing `.copilot` directory ownership, cleaning stale chroot directories, and installing the Copilot binary to `/usr/local/bin`). Pass `--rootless` to the script to install to `~/.local/bin` without `sudo`, which is required on ARC pods with `allowPrivilegeEscalation: false`. ## ARC with Docker-in-Docker (DinD) @@ -279,4 +279,4 @@ The dind sidecar requires `privileged: true` so `dockerd` can run. The runner co In network-isolation mode (the default for `topology: arc-dind`), AWF enforces egress via Docker network topology — an internal Docker network with no internet route and a dual-homed Squid proxy. All network enforcement happens inside the Docker daemon's domain (the dind sidecar). The runner container only issues Docker API commands via the socket; it never manipulates host `iptables` or network namespaces. > [!NOTE] -> If your cluster enforces `allowPrivilegeEscalation: false` or `no-new-privileges` on the runner container, the Copilot CLI install script will fail. See [Known limitations](/gh-aw/guides/arc-dind-copilot-agent/#known-limitations) in the ARC DinD guide. +> If your cluster enforces `allowPrivilegeEscalation: false` or `no-new-privileges` on the runner container, pass `--rootless` to the Copilot CLI install script so it installs to `~/.local/bin` without `sudo`. See [Pod security and rootless install](/gh-aw/guides/arc-dind-copilot-agent/#pod-security-and-rootless-install) in the ARC DinD guide. diff --git a/pkg/cli/install_copilot_cli_test.go b/pkg/cli/install_copilot_cli_test.go index 5cc7b9f6c59..d8140f8decf 100644 --- a/pkg/cli/install_copilot_cli_test.go +++ b/pkg/cli/install_copilot_cli_test.go @@ -183,3 +183,57 @@ exit 97 } assert.Equal(t, 1, compatFetches, "compat.json should be fetched exactly once (no double fallback)") } + +func TestInstallCopilotCLIScriptRootlessModeUsesRealScriptWithToolcacheAndNoSudo(t *testing.T) { + wd, err := os.Getwd() + require.NoError(t, err, "Failed to get working directory") + + projectRoot := filepath.Join(wd, "..", "..") + installScript := filepath.Join(projectRoot, "actions", "setup", "sh", "install_copilot_cli.sh") + + testCases := []struct { + name string + args []string + }{ + {name: "rootless flag before version", args: []string{"--rootless", "1.2.3"}}, + {name: "rootless flag after version", args: []string{"1.2.3", "--rootless"}}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tempDir := t.TempDir() + homeDir := filepath.Join(tempDir, "home") + require.NoError(t, os.MkdirAll(homeDir, 0o755)) + + toolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", "1.2.3", "x64", "bin") + require.NoError(t, os.MkdirAll(toolcacheBin, 0o755)) + require.NoError(t, os.WriteFile(filepath.Join(toolcacheBin, "copilot"), []byte("#!/usr/bin/env bash\necho 'copilot 1.2.3'\n"), 0o755)) + + fakeBinDir := filepath.Join(tempDir, "fake-bin") + require.NoError(t, os.MkdirAll(fakeBinDir, 0o755)) + + sudoScript := filepath.Join(fakeBinDir, "sudo") + sudoLog := filepath.Join(tempDir, "sudo.log") + require.NoError(t, os.WriteFile(sudoScript, []byte(`#!/usr/bin/env bash +echo "sudo-called: $*" >> "`+sudoLog+`" +exit 99 +`), 0o755)) + + cmd := exec.Command("bash", append([]string{installScript}, tc.args...)...) + cmd.Env = append(os.Environ(), + "HOME="+homeDir, + "RUNNER_TOOL_CACHE="+filepath.Join(tempDir, "toolcache"), + "GITHUB_PATH=", + "PATH="+fakeBinDir+":"+os.Getenv("PATH"), + ) + + output, err := cmd.CombinedOutput() + require.NoError(t, err, "install_copilot_cli.sh should succeed in rootless mode with toolcache and no sudo: %s", output) + + assert.Contains(t, string(output), "Using cached GitHub Copilot CLI", "script should use cached copilot CLI") + assert.Contains(t, string(output), "GITHUB_PATH not set — installing wrapper at "+filepath.Join(homeDir, ".local", "bin", "copilot")) + assert.FileExists(t, filepath.Join(homeDir, ".local", "bin", "copilot")) + assert.NoFileExists(t, sudoLog, "sudo should not be called in rootless mode") + }) + } +} diff --git a/pkg/workflow/antigravity_engine.go b/pkg/workflow/antigravity_engine.go index 2efc4232708..66b25338722 100644 --- a/pkg/workflow/antigravity_engine.go +++ b/pkg/workflow/antigravity_engine.go @@ -104,7 +104,7 @@ func (e *AntigravityEngine) GetInstallationSteps(workflowData *WorkflowData) []G if workflowData.EngineConfig != nil && workflowData.EngineConfig.Version != "" { version = workflowData.EngineConfig.Version } - installSteps := GenerateAntigravityInstallerSteps(version, "Install Antigravity CLI") + installSteps := GenerateAntigravityInstallerSteps(version, "Install Antigravity CLI", false) return BuildNpmEngineInstallStepsWithAWF(installSteps, workflowData) } diff --git a/pkg/workflow/antigravity_installer.go b/pkg/workflow/antigravity_installer.go index 18342a58973..9f9663a4476 100644 --- a/pkg/workflow/antigravity_installer.go +++ b/pkg/workflow/antigravity_installer.go @@ -9,22 +9,28 @@ var antigravityInstallerLog = logger.New("workflow:antigravity_installer") // GenerateAntigravityInstallerSteps creates GitHub Actions steps to install the Antigravity CLI // using the official binary from Google Cloud Storage. -func GenerateAntigravityInstallerSteps(version, stepName string) []GitHubActionStep { +// When rootless is true, the script installs into $HOME/.local/bin without sudo. +func GenerateAntigravityInstallerSteps(version, stepName string, rootless bool) []GitHubActionStep { // If no version is specified, use the pinned default version from constants. if version == "" { version = string(constants.DefaultAntigravityVersion) antigravityInstallerLog.Printf("No version specified, using default: %s", version) } - antigravityInstallerLog.Printf("Generating Antigravity installer steps using install_antigravity_cli.sh: version=%s", version) + antigravityInstallerLog.Printf("Generating Antigravity installer steps using install_antigravity_cli.sh: version=%s, rootless=%v", version, rootless) // Always pass the version via an env var rather than direct shell interpolation. // This prevents injection from user-supplied engine.version values (e.g. values // with spaces or shell metacharacters) and also handles GitHub Actions expressions // like ${{ inputs.engine-version }} safely. + installCmd := `bash "${RUNNER_TEMP}/gh-aw/actions/install_antigravity_cli.sh" "${ENGINE_VERSION}"` + if rootless { + installCmd += " --rootless" + } + installStep := GitHubActionStep([]string{ " - name: " + stepName, - ` run: bash "${RUNNER_TEMP}/gh-aw/actions/install_antigravity_cli.sh" "${ENGINE_VERSION}"`, + " run: " + installCmd, " env:", " ENGINE_VERSION: " + version, }) diff --git a/pkg/workflow/antigravity_installer_test.go b/pkg/workflow/antigravity_installer_test.go new file mode 100644 index 00000000000..cf9230f635a --- /dev/null +++ b/pkg/workflow/antigravity_installer_test.go @@ -0,0 +1,38 @@ +package workflow + +import ( + "strings" + "testing" +) + +func TestGenerateAntigravityInstallerSteps_Rootless(t *testing.T) { + steps := GenerateAntigravityInstallerSteps("1.0.0", "Install Antigravity CLI", true) + + if len(steps) != 1 { + t.Fatalf("Expected 1 step, got %d", len(steps)) + } + + stepContent := strings.Join(steps[0], "\n") + + if !strings.Contains(stepContent, "--rootless") { + t.Errorf("Expected step to contain --rootless flag, got:\n%s", stepContent) + } + + if !strings.Contains(stepContent, "install_antigravity_cli.sh") { + t.Errorf("Expected step to use install_antigravity_cli.sh, got:\n%s", stepContent) + } +} + +func TestGenerateAntigravityInstallerSteps_NoRootless(t *testing.T) { + steps := GenerateAntigravityInstallerSteps("1.0.0", "Install Antigravity CLI", false) + + if len(steps) != 1 { + t.Fatalf("Expected 1 step, got %d", len(steps)) + } + + stepContent := strings.Join(steps[0], "\n") + + if strings.Contains(stepContent, "--rootless") { + t.Errorf("Expected step to NOT contain --rootless flag, got:\n%s", stepContent) + } +} diff --git a/pkg/workflow/copilot_engine_execution.go b/pkg/workflow/copilot_engine_execution.go index 5d379d0b0bc..6a2ba09fc42 100644 --- a/pkg/workflow/copilot_engine_execution.go +++ b/pkg/workflow/copilot_engine_execution.go @@ -699,11 +699,13 @@ func buildEngineCommandScriptSetup(command string) string { } return fmt.Sprintf(`mkdir -p /tmp/gh-aw +GH_AW_PREV_UMASK="$(umask)" umask 0177 cat > %s <<'%s' %s %s -chmod 700 %s`, customEngineCommandScriptPath, heredocDelimiter, scriptContent, heredocDelimiter, customEngineCommandScriptPath) +chmod 700 %s +umask "$GH_AW_PREV_UMASK"`, customEngineCommandScriptPath, heredocDelimiter, scriptContent, heredocDelimiter, customEngineCommandScriptPath) } // generateCopilotSessionFileCopyStep generates a step to copy the entire Copilot diff --git a/pkg/workflow/copilot_engine_installation.go b/pkg/workflow/copilot_engine_installation.go index 52732d8e744..cdc53042c9a 100644 --- a/pkg/workflow/copilot_engine_installation.go +++ b/pkg/workflow/copilot_engine_installation.go @@ -125,7 +125,12 @@ func (e *CopilotEngine) GetInstallationSteps(workflowData *WorkflowData) []GitHu // Use the installer script for global installation copilotInstallLog.Print("Using new installer script for Copilot installation") - npmSteps := GenerateCopilotInstallerSteps(copilotVersion, "Install GitHub Copilot CLI") + // On ARC/DinD runners, sudo may not be available (allowPrivilegeEscalation: false). + // Pass --rootless so the script installs to ~/.local/bin without sudo. + // The "Copy Copilot CLI to daemon-visible path" step in nodejs.go then copies from + // the rootless location to ${RUNNER_TEMP}/gh-aw/bin/copilot where AWF expects it. + rootless := isArcDindTopology(workflowData) + npmSteps := GenerateCopilotInstallerSteps(copilotVersion, "Install GitHub Copilot CLI", rootless) if len(sdkInstallStep) > 0 { npmSteps = append(npmSteps, sdkInstallStep) } diff --git a/pkg/workflow/copilot_engine_test.go b/pkg/workflow/copilot_engine_test.go index 7199bcca871..06feb003b98 100644 --- a/pkg/workflow/copilot_engine_test.go +++ b/pkg/workflow/copilot_engine_test.go @@ -2802,6 +2802,12 @@ func TestBuildEngineCommandScriptSetup(t *testing.T) { if !strings.Contains(setup, "umask 0177") { t.Fatalf("Expected restrictive umask in script setup, got:\n%s", setup) } + if !strings.Contains(setup, `GH_AW_PREV_UMASK="$(umask)"`) { + t.Fatalf("Expected script setup to preserve original umask, got:\n%s", setup) + } + if !strings.Contains(setup, `umask "$GH_AW_PREV_UMASK"`) { + t.Fatalf("Expected script setup to restore original umask, got:\n%s", setup) + } if !strings.Contains(setup, "chmod 700 /tmp/gh-aw/engine-command.sh") { t.Fatalf("Expected owner-only execute permissions, got:\n%s", setup) } diff --git a/pkg/workflow/copilot_installer.go b/pkg/workflow/copilot_installer.go index 1fc421878b3..c98f8719953 100644 --- a/pkg/workflow/copilot_installer.go +++ b/pkg/workflow/copilot_installer.go @@ -8,14 +8,20 @@ import ( var copilotInstallerLog = logger.New("workflow:copilot_installer") // GenerateCopilotInstallerSteps creates GitHub Actions steps to install the Copilot CLI using the official installer. -func GenerateCopilotInstallerSteps(version, stepName string) []GitHubActionStep { +// When rootless is true, the script installs into $HOME/.local/bin without sudo. +func GenerateCopilotInstallerSteps(version, stepName string, rootless bool) []GitHubActionStep { // If no version is specified, use the pinned default version from constants. if version == "" { version = string(constants.DefaultCopilotVersion) copilotInstallerLog.Printf("No version specified, using default: %s", version) } - copilotInstallerLog.Printf("Generating Copilot installer steps using install_copilot_cli.sh: version=%s", version) + copilotInstallerLog.Printf("Generating Copilot installer steps using install_copilot_cli.sh: version=%s, rootless=%v", version, rootless) + + rootlessFlag := "" + if rootless { + rootlessFlag = " --rootless" + } // Use the install_copilot_cli.sh script from actions/setup/sh // This script includes retry logic for robustness against transient network failures. @@ -30,7 +36,7 @@ func GenerateCopilotInstallerSteps(version, stepName string) []GitHubActionStep copilotInstallerLog.Printf("Version contains GitHub Actions expression, using env var for injection safety: %s", version) stepLines := []string{ " - name: " + stepName, - ` run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" "${ENGINE_VERSION}"`, + ` run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" "${ENGINE_VERSION}"` + rootlessFlag, " env:", " GH_HOST: github.com", " ENGINE_VERSION: " + version, @@ -40,7 +46,7 @@ func GenerateCopilotInstallerSteps(version, stepName string) []GitHubActionStep stepLines := []string{ " - name: " + stepName, - " run: bash \"${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh\" " + version, + " run: bash \"${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh\" " + version + rootlessFlag, " env:", " GH_HOST: github.com", } diff --git a/pkg/workflow/copilot_installer_test.go b/pkg/workflow/copilot_installer_test.go index 356db6d3c35..72072020b41 100644 --- a/pkg/workflow/copilot_installer_test.go +++ b/pkg/workflow/copilot_installer_test.go @@ -76,7 +76,7 @@ func TestGenerateCopilotInstallerSteps(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - steps := GenerateCopilotInstallerSteps(tt.version, tt.stepName) + steps := GenerateCopilotInstallerSteps(tt.version, tt.stepName, false) if len(steps) != 1 { t.Errorf("Expected 1 step, got %d", len(steps)) @@ -180,7 +180,7 @@ func TestGenerateCopilotInstallerSteps_ExpressionVersion(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - steps := GenerateCopilotInstallerSteps(tt.version, "Install GitHub Copilot CLI") + steps := GenerateCopilotInstallerSteps(tt.version, "Install GitHub Copilot CLI", false) if len(steps) != 1 { t.Errorf("Expected 1 step, got %d", len(steps)) @@ -212,6 +212,42 @@ func TestGenerateCopilotInstallerSteps_ExpressionVersion(t *testing.T) { } } +func TestGenerateCopilotInstallerSteps_Rootless(t *testing.T) { + steps := GenerateCopilotInstallerSteps("1.2.3", "Install Copilot CLI", true) + + if len(steps) != 1 { + t.Fatalf("Expected 1 step, got %d", len(steps)) + } + + stepContent := strings.Join(steps[0], "\n") + + if !strings.Contains(stepContent, "--rootless") { + t.Errorf("Expected step to contain --rootless flag, got:\n%s", stepContent) + } + + if !strings.Contains(stepContent, "install_copilot_cli.sh") { + t.Errorf("Expected step to use install_copilot_cli.sh, got:\n%s", stepContent) + } +} + +func TestGenerateCopilotInstallerSteps_RootlessWithExpression(t *testing.T) { + steps := GenerateCopilotInstallerSteps("${{ inputs.version }}", "Install Copilot CLI", true) + + if len(steps) != 1 { + t.Fatalf("Expected 1 step, got %d", len(steps)) + } + + stepContent := strings.Join(steps[0], "\n") + + if !strings.Contains(stepContent, "--rootless") { + t.Errorf("Expected step to contain --rootless flag, got:\n%s", stepContent) + } + + if !strings.Contains(stepContent, `"${ENGINE_VERSION}"`) { + t.Errorf("Expected step to use ENGINE_VERSION env var, got:\n%s", stepContent) + } +} + func TestCopilotInstallerExpressionVersion_ViaEngineConfig(t *testing.T) { // Test that expression version from engine config is ignored in favor of default pinned version engine := NewCopilotEngine() diff --git a/pkg/workflow/nodejs.go b/pkg/workflow/nodejs.go index 85f93f8d073..9a726dfe4fb 100644 --- a/pkg/workflow/nodejs.go +++ b/pkg/workflow/nodejs.go @@ -174,15 +174,16 @@ func BuildNpmEngineInstallStepsWithAWF(npmSteps []GitHubActionStep, workflowData } // Copy Copilot CLI to daemon-visible path for ARC/DinD. - // The install script puts copilot at /usr/local/bin/copilot which is inside the - // sysroot image — not the runner's filesystem. On ARC/DinD, the AWF command - // references ${RUNNER_TEMP}/gh-aw/bin/copilot which is daemon-visible. + // With --rootless, the binary is at ~/.local/bin/copilot; otherwise /usr/local/bin/copilot. + // On ARC/DinD, the AWF command references ${RUNNER_TEMP}/gh-aw/bin/copilot which is + // daemon-visible, so we copy from wherever the install script placed it. if isFirewallEnabled(workflowData) && isArcDindTopology(workflowData) { copyStep := GitHubActionStep([]string{ " - name: Copy Copilot CLI to daemon-visible path", " run: |", " mkdir -p \"${RUNNER_TEMP}/gh-aw/bin\"", - " cp /usr/local/bin/copilot \"${RUNNER_TEMP}/gh-aw/bin/copilot\"", + ` COPILOT_SRC="$(command -v copilot)"`, + " cp \"$COPILOT_SRC\" \"${RUNNER_TEMP}/gh-aw/bin/copilot\"", " chmod +x \"${RUNNER_TEMP}/gh-aw/bin/copilot\"", }) steps = append(steps, copyStep)