diff --git a/lib/upload-lib.js b/lib/upload-lib.js index e7c0bb5ecd..508e16a109 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -84831,6 +84831,7 @@ __export(upload_lib_exports, { shouldShowCombineSarifFilesDeprecationWarning: () => shouldShowCombineSarifFilesDeprecationWarning, throwIfCombineSarifFilesDisabled: () => throwIfCombineSarifFilesDisabled, uploadFiles: () => uploadFiles, + uploadPayload: () => uploadPayload, uploadSpecifiedFiles: () => uploadSpecifiedFiles, validateSarifFileSchema: () => validateSarifFileSchema, validateUniqueCategory: () => validateUniqueCategory, @@ -92944,6 +92945,7 @@ function filterAlertsByDiffRange(logger, sarif) { shouldShowCombineSarifFilesDeprecationWarning, throwIfCombineSarifFilesDisabled, uploadFiles, + uploadPayload, uploadSpecifiedFiles, validateSarifFileSchema, validateUniqueCategory, diff --git a/src/upload-lib.test.ts b/src/upload-lib.test.ts index a1fdf218e1..7a5be6382f 100644 --- a/src/upload-lib.test.ts +++ b/src/upload-lib.test.ts @@ -1,9 +1,14 @@ import * as fs from "fs"; import * as path from "path"; +import * as github from "@actions/github"; +import { HTTPError } from "@actions/tool-cache"; import test from "ava"; +import * as sinon from "sinon"; +import * as analyses from "./analyses"; import { AnalysisKind, CodeQuality, CodeScanning } from "./analyses"; +import * as api from "./api-client"; import { getRunnerLogger, Logger } from "./logging"; import { setupTests } from "./testing-utils"; import * as uploadLib from "./upload-lib"; @@ -867,3 +872,91 @@ function createMockSarif(id?: string, tool?: string) { ], }; } + +function uploadPayloadFixtures(analysis: analyses.AnalysisConfig) { + const mockData = { + payload: { sarif: "base64data", commit_sha: "abc123" }, + owner: "test-owner", + repo: "test-repo", + response: { + status: 200, + data: { id: "uploaded-sarif-id" }, + headers: {}, + url: analysis.target, + }, + }; + const client = github.getOctokit("123"); + sinon.stub(api, "getApiClient").value(() => client); + const requestStub = sinon.stub(client, "request"); + + const upload = async () => + uploadLib.uploadPayload( + mockData.payload, + { + owner: mockData.owner, + repo: mockData.repo, + }, + getRunnerLogger(true), + analysis, + ); + + return { + upload, + requestStub, + mockData, + }; +} + +for (const analysis of [CodeScanning, CodeQuality]) { + test(`uploadPayload on ${analysis.name} uploads successfully`, async (t) => { + const { upload, requestStub, mockData } = uploadPayloadFixtures(analysis); + requestStub + .withArgs(analysis.target, { + owner: mockData.owner, + repo: mockData.repo, + data: mockData.payload, + }) + .onFirstCall() + .returns(Promise.resolve(mockData.response)); + const result = await upload(); + t.is(result, mockData.response.data.id); + t.true(requestStub.calledOnce); + }); + + for (const envVar of [ + "CODEQL_ACTION_SKIP_SARIF_UPLOAD", + "CODEQL_ACTION_TEST_MODE", + ]) { + test(`uploadPayload on ${analysis.name} skips upload when ${envVar} is set`, async (t) => { + const { upload, requestStub, mockData } = uploadPayloadFixtures(analysis); + await withTmpDir(async (tmpDir) => { + process.env.RUNNER_TEMP = tmpDir; + process.env[envVar] = "true"; + const result = await upload(); + t.is(result, "dummy-sarif-id"); + t.false(requestStub.called); + + const payloadFile = path.join(tmpDir, `payload-${analysis.kind}.json`); + t.true(fs.existsSync(payloadFile)); + + const savedPayload = JSON.parse(fs.readFileSync(payloadFile, "utf8")); + t.deepEqual(savedPayload, mockData.payload); + }); + }); + } + + test(`uploadPayload on ${analysis.name} wraps request errors using wrapApiConfigurationError`, async (t) => { + const { upload, requestStub } = uploadPayloadFixtures(analysis); + const wrapApiConfigurationErrorStub = sinon.stub( + api, + "wrapApiConfigurationError", + ); + const originalError = new HTTPError(404); + const wrappedError = new Error("Wrapped error message"); + requestStub.rejects(originalError); + wrapApiConfigurationErrorStub.withArgs(originalError).returns(wrappedError); + await t.throwsAsync(upload, { + is: wrappedError, + }); + }); +} diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 7c630204bc..90f0342de5 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -346,9 +346,12 @@ function getAutomationID( return api.computeAutomationID(analysis_key, environment); } -// Upload the given payload. -// If the request fails then this will retry a small number of times. -async function uploadPayload( +/** + * Upload the given payload. + * If the request fails then this will retry a small number of times. + * This is exported for testing purposes only. + */ +export async function uploadPayload( payload: any, repositoryNwo: RepositoryNwo, logger: Logger,