-
Notifications
You must be signed in to change notification settings - Fork 424
fix: upload_assets looks in RUNNER_TEMP but artifact is downloaded to /tmp #40062
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,21 +4,24 @@ import path from "path"; | |
| const mockCore = { debug: vi.fn(), info: vi.fn(), notice: vi.fn(), warning: vi.fn(), error: vi.fn(), setFailed: vi.fn(), setOutput: vi.fn(), summary: { addRaw: vi.fn().mockReturnThis(), write: vi.fn().mockResolvedValue(void 0) } }; | ||
| ((global.core = mockCore), | ||
| describe("upload_assets.cjs", () => { | ||
| let uploadAssetsScript, mockExec, tempFilePath; | ||
| let uploadAssetsScript, mockExec, tempFilePath, tempBase; | ||
| const setAgentOutput = data => { | ||
| tempFilePath = path.join("/tmp", `test_agent_output_${Date.now()}_${Math.random().toString(36).slice(2)}.json`); | ||
| tempFilePath = path.join(tempBase, "agent_output.json"); | ||
| const content = "string" == typeof data ? data : JSON.stringify(data); | ||
| (fs.writeFileSync(tempFilePath, content), (process.env.GH_AW_AGENT_OUTPUT = tempFilePath)); | ||
| }, | ||
| getAssetsDir = () => path.join(process.env.RUNNER_TEMP || "/tmp", "gh-aw", "safeoutputs", "assets"), | ||
| 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); | ||
| tempBase = fs.mkdtempSync(path.join("/tmp", "test-gh-aw-")); | ||
| const scriptPath = path.join(__dirname, "upload_assets.cjs"); | ||
| ((uploadAssetsScript = fs.readFileSync(scriptPath, "utf8")), (mockExec = { exec: vi.fn().mockResolvedValue(0) })); | ||
| }), | ||
| afterEach(() => { | ||
| tempFilePath && fs.existsSync(tempFilePath) && fs.unlinkSync(tempFilePath); | ||
| tempBase && fs.existsSync(tempBase) && fs.rmSync(tempBase, { recursive: !0, force: !0 }); | ||
| tempBase = void 0; | ||
| tempFilePath = void 0; | ||
| }), | ||
| describe("git commit command - vulnerability fix", () => { | ||
| it("should not wrap commit message in extra quotes to prevent command injection", async () => { | ||
|
|
@@ -138,13 +141,11 @@ const mockCore = { debug: vi.fn(), info: vi.fn(), notice: vi.fn(), warning: vi.f | |
| fs.existsSync("test.png") && fs.unlinkSync("test.png")); | ||
| })); | ||
| describe("missing asset handling", () => { | ||
| it("should skip missing assets while uploading present assets from RUNNER_TEMP", async () => { | ||
| it("should skip missing assets while uploading present assets", async () => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RUNNER_TEMP fallback path is now untested: the renamed test only exercises the 💡 Details and suggestionThe old test ("should skip missing assets while uploading present assets from RUNNER_TEMP") explicitly set The fallback is the code path that runs when Suggest adding a dedicated test like: it('should derive asset dir from RUNNER_TEMP when GH_AW_AGENT_OUTPUT is not set', async () => {
const runnerTempDir = fs.mkdtempSync(path.join('/tmp', 'runner-temp-'));
process.env.RUNNER_TEMP = runnerTempDir;
delete process.env.GH_AW_AGENT_OUTPUT;
const assetDir = path.join(runnerTempDir, 'gh-aw', 'safeoutputs', 'assets');
fs.mkdirSync(assetDir, { recursive: true });
// ... write a test asset and verify upload ...
fs.rmSync(runnerTempDir, { recursive: true, force: true });
delete process.env.RUNNER_TEMP;
}); |
||
| process.env.GH_AW_ASSETS_BRANCH = "assets/test-workflow"; | ||
| process.env.GH_AW_SAFE_OUTPUTS_STAGED = "false"; | ||
| const runnerTempDir = fs.mkdtempSync(path.join("/tmp", "upload-assets-runner-temp-")); | ||
| process.env.RUNNER_TEMP = runnerTempDir; | ||
| const assetDir = path.join(runnerTempDir, "gh-aw", "safeoutputs", "assets"); | ||
| fs.mkdirSync(assetDir, { recursive: !0 }); | ||
| const assetDir = getAssetsDir(); | ||
| fs.existsSync(assetDir) || fs.mkdirSync(assetDir, { recursive: !0 }); | ||
|
pelikhan marked this conversation as resolved.
|
||
| const presentAssetSourcePath = path.join(assetDir, "present.png"); | ||
| fs.writeFileSync(presentAssetSourcePath, "present content"); | ||
| const crypto = require("crypto"), | ||
|
|
@@ -172,8 +173,6 @@ const mockCore = { debug: vi.fn(), info: vi.fn(), notice: vi.fn(), warning: vi.f | |
| uploadCountCall && expect(uploadCountCall[1]).toBe("1"); | ||
| fs.existsSync(presentAssetSourcePath) && fs.unlinkSync(presentAssetSourcePath); | ||
| fs.existsSync(path.join(process.cwd(), presentTargetFile)) && fs.unlinkSync(path.join(process.cwd(), presentTargetFile)); | ||
| fs.rmSync(runnerTempDir, { recursive: !0, force: !0 }); | ||
| delete process.env.RUNNER_TEMP; | ||
| }); | ||
| }); | ||
| })); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fragile path derivation — wrong
GH_AW_AGENT_OUTPUTlocation silently breaks all asset uploads: if the env var ever points to a path more than one level below the artifact root,baseDirwill resolve to the wrong directory and every asset will appear missing, with no error distinguishing this failure from "no assets found".💡 Details and suggestion
The fix works today because
GH_AW_AGENT_OUTPUTis set to/tmp/gh-aw/agent_output.json, sopath.dirname()correctly yields/tmp/gh-aw/. But this is an implicit structural contract: the code assumessafeoutputs/assets/is always a direct sibling ofagent_output.json. Anything that changes the download layout (a nested subdirectory, a renamed artifact path, a self-hosted runner with a non-standard workspace) will silently break uploads.A more robust alternative is a dedicated env var, or at minimum a log warning when the resolved
assetsDirdoes not exist:The per-item "missing asset" warning is too granular to diagnose a path resolution bug in CI logs.