diff --git a/.github/workflows/agentic-token-audit.lock.yml b/.github/workflows/agentic-token-audit.lock.yml index 410e75c95f1..3b2759c2c6b 100644 --- a/.github/workflows/agentic-token-audit.lock.yml +++ b/.github/workflows/agentic-token-audit.lock.yml @@ -1968,6 +1968,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/agentic-token-trend-audit.lock.yml b/.github/workflows/agentic-token-trend-audit.lock.yml index 24c407d290c..94a25cd13be 100644 --- a/.github/workflows/agentic-token-trend-audit.lock.yml +++ b/.github/workflows/agentic-token-trend-audit.lock.yml @@ -1827,6 +1827,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/api-consumption-report.lock.yml b/.github/workflows/api-consumption-report.lock.yml index 277940aca0e..924cc4cd8cb 100644 --- a/.github/workflows/api-consumption-report.lock.yml +++ b/.github/workflows/api-consumption-report.lock.yml @@ -2275,6 +2275,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index a5c1fd580da..1ada583cfb2 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -2166,6 +2166,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index a88455998d6..fcdeeca8d77 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -2033,6 +2033,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index c5d16238bb4..8d08735e18b 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -2093,6 +2093,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/daily-agent-of-the-day-blog-writer.lock.yml b/.github/workflows/daily-agent-of-the-day-blog-writer.lock.yml index 9a7e87ed2a4..bacdb8f1947 100644 --- a/.github/workflows/daily-agent-of-the-day-blog-writer.lock.yml +++ b/.github/workflows/daily-agent-of-the-day-blog-writer.lock.yml @@ -2134,6 +2134,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index a878638e411..29f58c19492 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -2194,6 +2194,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/daily-experiment-report.lock.yml b/.github/workflows/daily-experiment-report.lock.yml index 8d88e653ef8..23b3b948ad9 100644 --- a/.github/workflows/daily-experiment-report.lock.yml +++ b/.github/workflows/daily-experiment-report.lock.yml @@ -1930,6 +1930,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index c24bbbf58d1..5f2b9120bdc 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -1797,6 +1797,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/daily-issues-report.lock.yml b/.github/workflows/daily-issues-report.lock.yml index b0f117a9da4..669dae0b7ce 100644 --- a/.github/workflows/daily-issues-report.lock.yml +++ b/.github/workflows/daily-issues-report.lock.yml @@ -2164,6 +2164,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index d1cb3101f15..cc9c2397dd3 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -2253,6 +2253,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml index eee710a5571..b35ea4a6435 100644 --- a/.github/workflows/daily-performance-summary.lock.yml +++ b/.github/workflows/daily-performance-summary.lock.yml @@ -2370,6 +2370,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index 5d1abc8ac9e..35734967f4e 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -1877,6 +1877,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/daily-security-observability.lock.yml b/.github/workflows/daily-security-observability.lock.yml index a8b9e911e52..3fd0769ec6e 100644 --- a/.github/workflows/daily-security-observability.lock.yml +++ b/.github/workflows/daily-security-observability.lock.yml @@ -2002,6 +2002,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index b52db10e3a5..016f7934178 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -1779,6 +1779,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/github-mcp-structural-analysis.lock.yml b/.github/workflows/github-mcp-structural-analysis.lock.yml index 78f15a49457..7ee3d04d9d1 100644 --- a/.github/workflows/github-mcp-structural-analysis.lock.yml +++ b/.github/workflows/github-mcp-structural-analysis.lock.yml @@ -1943,6 +1943,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/org-health-report.lock.yml b/.github/workflows/org-health-report.lock.yml index c22b1bfe5b7..2c23e3b4181 100644 --- a/.github/workflows/org-health-report.lock.yml +++ b/.github/workflows/org-health-report.lock.yml @@ -1896,6 +1896,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/portfolio-analyst.lock.yml b/.github/workflows/portfolio-analyst.lock.yml index b2ff476e8d8..c66849add80 100644 --- a/.github/workflows/portfolio-analyst.lock.yml +++ b/.github/workflows/portfolio-analyst.lock.yml @@ -2018,6 +2018,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index 78ddc3ef6b1..04020f4fcbf 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -2056,6 +2056,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index 005cbaef4df..c670dfa34bc 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -1979,6 +1979,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml index 5ebd45cd060..7c332b48853 100644 --- a/.github/workflows/stale-repo-identifier.lock.yml +++ b/.github/workflows/stale-repo-identifier.lock.yml @@ -2019,6 +2019,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/weekly-editors-health-check.lock.yml b/.github/workflows/weekly-editors-health-check.lock.yml index c5eb0f0471b..c185696de59 100644 --- a/.github/workflows/weekly-editors-health-check.lock.yml +++ b/.github/workflows/weekly-editors-health-check.lock.yml @@ -1858,6 +1858,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index 35953770998..a1d19c435d7 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -1853,6 +1853,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ASSETS_DIR: "/tmp/gh-aw/safeoutputs/assets" GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}" GH_AW_ASSETS_MAX_SIZE_KB: 10240 GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg,.svg" diff --git a/actions/setup/js/upload_assets.cjs b/actions/setup/js/upload_assets.cjs index f8aa04ca30c..3a25d7e1d63 100644 --- a/actions/setup/js/upload_assets.cjs +++ b/actions/setup/js/upload_assets.cjs @@ -86,13 +86,13 @@ async function main() { core.info(`Found ${uploadItems.length} upload-asset item(s)`); - // Derive the base directory from GH_AW_AGENT_OUTPUT when available. - // In the upload_assets job, the agent artifact (including safeoutputs/assets/) - // is downloaded to the same parent directory as agent_output.json, which may - // differ from RUNNER_TEMP when the download path is explicitly set to /tmp/gh-aw/. - const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT; - const baseDir = agentOutputFile ? path.dirname(agentOutputFile) : path.join(process.env.RUNNER_TEMP || "/tmp", "gh-aw"); - const assetsDir = path.join(baseDir, "safeoutputs", "assets"); + // Read the staged-assets directory directly. The upload_assets job's + // download-artifact step writes the safe-outputs assets artifact to this exact + // directory, and the Go generator passes the same path via GH_AW_ASSETS_DIR, so + // producer and consumer can never disagree on the location. The literal fallback + // matches constants.TmpGhAwAssetsDir for robustness if the env var is unset. + const assetsDir = process.env.GH_AW_ASSETS_DIR || "/tmp/gh-aw/safeoutputs/assets"; + core.info(`Reading staged assets from: ${assetsDir}`); let uploadCount = 0; let missingAssetCount = 0; let hasChanges = false; @@ -130,7 +130,7 @@ async function main() { return; } - // Check if file exists in artifacts + // Check if file exists in the staged-assets directory const assetSourcePath = path.join(assetsDir, fileName); if (!fs.existsSync(assetSourcePath)) { core.warning(`${ERR_SYSTEM}: Asset file not found: ${assetSourcePath} — skipping`); diff --git a/actions/setup/js/upload_assets.test.cjs b/actions/setup/js/upload_assets.test.cjs index 4d8a83e8f29..4423f55ca70 100644 --- a/actions/setup/js/upload_assets.test.cjs +++ b/actions/setup/js/upload_assets.test.cjs @@ -13,8 +13,9 @@ const mockCore = { debug: vi.fn(), info: vi.fn(), notice: vi.fn(), warning: vi.f getAssetsDir = () => path.join(tempBase, "safeoutputs", "assets"), executeScript = async () => ((global.core = mockCore), (global.exec = mockExec), await eval(`(async () => { ${uploadAssetsScript}; await main(); })()`)); (beforeEach(() => { - (vi.clearAllMocks(), delete process.env.GH_AW_ASSETS_BRANCH, delete process.env.GH_AW_AGENT_OUTPUT, delete process.env.GH_AW_SAFE_OUTPUTS_STAGED); + (vi.clearAllMocks(), delete process.env.GH_AW_ASSETS_BRANCH, delete process.env.GH_AW_AGENT_OUTPUT, delete process.env.GH_AW_ASSETS_DIR, delete process.env.GH_AW_SAFE_OUTPUTS_STAGED); tempBase = fs.mkdtempSync(path.join("/tmp", "test-gh-aw-")); + process.env.GH_AW_ASSETS_DIR = path.join(tempBase, "safeoutputs", "assets"); const scriptPath = path.join(__dirname, "upload_assets.cjs"); ((uploadAssetsScript = fs.readFileSync(scriptPath, "utf8")), (mockExec = { exec: vi.fn().mockResolvedValue(0) })); }), @@ -175,5 +176,39 @@ const mockCore = { debug: vi.fn(), info: vi.fn(), notice: vi.fn(), warning: vi.f fs.existsSync(path.join(process.cwd(), presentTargetFile)) && fs.unlinkSync(path.join(process.cwd(), presentTargetFile)); }); }); + describe("staging directory resolution", () => { + it("should read assets from the GH_AW_ASSETS_DIR directory", async () => { + process.env.GH_AW_ASSETS_BRANCH = "assets/test-workflow"; + process.env.GH_AW_SAFE_OUTPUTS_STAGED = "false"; + // Point GH_AW_ASSETS_DIR at a custom directory (distinct from the + // agent-output dir) to confirm the consumer reads exactly the + // directory the download step wrote to — no search, no derivation. + const customAssetsDir = fs.mkdtempSync(path.join("/tmp", "test-gh-aw-assets-")); + process.env.GH_AW_ASSETS_DIR = customAssetsDir; + const assetSourcePath = path.join(customAssetsDir, "chart.png"); + fs.writeFileSync(assetSourcePath, "chart content"); + const crypto = require("crypto"), + fileContent = fs.readFileSync(assetSourcePath), + targetFile = "chart-uploaded.png"; + setAgentOutput({ + items: [{ type: "upload_asset", fileName: "chart.png", sha: crypto.createHash("sha256").update(fileContent).digest("hex"), size: fileContent.length, targetFileName: targetFile, url: "https://example.com/chart.png" }], + }); + mockExec.exec.mockImplementation(async (command, args) => { + const fullCommand = Array.isArray(args) ? `${command} ${args.join(" ")}` : command; + if (fullCommand.includes("rev-parse")) throw new Error("Branch does not exist"); + return 0; + }); + try { + await executeScript(); + expect(mockCore.setFailed).not.toHaveBeenCalled(); + const uploadCountCall = mockCore.setOutput.mock.calls.find(call => "upload_count" === call[0]); + expect(uploadCountCall).toBeDefined(); + uploadCountCall && expect(uploadCountCall[1]).toBe("1"); + } finally { + fs.existsSync(customAssetsDir) && fs.rmSync(customAssetsDir, { recursive: !0, force: !0 }); + fs.existsSync(path.join(process.cwd(), targetFile)) && fs.unlinkSync(path.join(process.cwd(), targetFile)); + } + }); + }); })); })); diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 89e6558aeca..2a324d84ef9 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -405,6 +405,15 @@ const TmpGhAwDirSlash = TmpGhAwDir + "/" // TmpGhAwAgentDir is the agent working directory in the /tmp/gh-aw tree. const TmpGhAwAgentDir = TmpGhAwDir + "/agent/" +// TmpGhAwAssetsDir is the directory the upload_assets job downloads the +// safe-outputs assets artifact into. It is the single source of truth shared by +// the download step (path:) and the upload_assets.cjs consumer script, so the +// two never disagree on where staged assets live. +const TmpGhAwAssetsDir = TmpGhAwDir + "/safeoutputs/assets" + +// TmpGhAwAssetsDirSlash is TmpGhAwAssetsDir with a trailing slash. +const TmpGhAwAssetsDirSlash = TmpGhAwAssetsDir + "/" + // AgentStdioLogPath is the path for capturing agent standard I/O log output. const AgentStdioLogPath = TmpGhAwDir + "/agent-stdio.log" diff --git a/pkg/workflow/publish_assets.go b/pkg/workflow/publish_assets.go index c90b8b99416..bd4a2b3d9f3 100644 --- a/pkg/workflow/publish_assets.go +++ b/pkg/workflow/publish_assets.go @@ -156,17 +156,20 @@ func (c *Compiler) buildUploadAssetsJob(data *WorkflowData, mainJobName string, preSteps = append(preSteps, fmt.Sprintf(" uses: %s\n", c.getActionPin("actions/download-artifact"))) preSteps = append(preSteps, " with:\n") preSteps = append(preSteps, fmt.Sprintf(" name: %ssafe-outputs-assets\n", assetsArtifactPrefix)) - preSteps = append(preSteps, " path: /tmp/gh-aw/safeoutputs/assets/\n") + preSteps = append(preSteps, fmt.Sprintf(" path: %s\n", constants.TmpGhAwAssetsDirSlash)) // Step 4: List files preSteps = append(preSteps, " - name: List downloaded asset files\n") preSteps = append(preSteps, " continue-on-error: true\n") // Continue if no assets were uploaded preSteps = append(preSteps, " run: |\n") preSteps = append(preSteps, " echo \"Downloaded asset files:\"\n") - preSteps = append(preSteps, " find /tmp/gh-aw/safeoutputs/assets/ -maxdepth 1 -ls\n") + preSteps = append(preSteps, fmt.Sprintf(" find %s -maxdepth 1 -ls\n", constants.TmpGhAwAssetsDirSlash)) // Build custom environment variables specific to upload-assets var customEnvVars []string + // Single source of truth for the staged-assets directory: the consumer script + // reads exactly the directory the download step above wrote to. + customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_ASSETS_DIR: %q\n", constants.TmpGhAwAssetsDir)) customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_ASSETS_BRANCH: %q\n", data.SafeOutputs.UploadAssets.BranchName)) customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_ASSETS_MAX_SIZE_KB: %d\n", data.SafeOutputs.UploadAssets.MaxSizeKB)) customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_ASSETS_ALLOWED_EXTS: %q\n", strings.Join(data.SafeOutputs.UploadAssets.AllowedExts, ",")))