diff --git a/lib/analyze-action-post.js b/lib/analyze-action-post.js index 7c1046ab3a..e5ef4f0f52 100644 --- a/lib/analyze-action-post.js +++ b/lib/analyze-action-post.js @@ -162463,7 +162463,7 @@ var getFileOidsUnderPath = async function(basePath) { "Cannot list Git OIDs of tracked files." ); const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + const regex = /^[0-9]+ ([0-9a-f]{40,64}) [0-9]+\t(.+)$/; for (const line of stdout.split("\n")) { if (line) { const match = line.match(regex); diff --git a/lib/analyze-action.js b/lib/analyze-action.js index f77401d3a4..08089c6ece 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -107998,7 +107998,7 @@ var determineBaseBranchHeadCommitOid = async function(checkoutPathOverride) { } } } - if (commitOid === mergeSha && headOid.length === 40 && baseOid.length === 40) { + if (commitOid === mergeSha && (headOid.length === 40 || headOid.length === 64) && (baseOid.length === 40 || baseOid.length === 64)) { return baseOid; } return void 0; @@ -108064,7 +108064,7 @@ var getFileOidsUnderPath = async function(basePath) { "Cannot list Git OIDs of tracked files." ); const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + const regex = /^[0-9]+ ([0-9a-f]{40,64}) [0-9]+\t(.+)$/; for (const line of stdout.split("\n")) { if (line) { const match = line.match(regex); diff --git a/lib/autobuild-action.js b/lib/autobuild-action.js index 8fdbf5fa64..d11ddd0f9c 100644 --- a/lib/autobuild-action.js +++ b/lib/autobuild-action.js @@ -104517,7 +104517,7 @@ var getFileOidsUnderPath = async function(basePath) { "Cannot list Git OIDs of tracked files." ); const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + const regex = /^[0-9]+ ([0-9a-f]{40,64}) [0-9]+\t(.+)$/; for (const line of stdout.split("\n")) { if (line) { const match = line.match(regex); diff --git a/lib/init-action-post.js b/lib/init-action-post.js index b129fc9ae2..b1a1428da0 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -165917,7 +165917,7 @@ var determineBaseBranchHeadCommitOid = async function(checkoutPathOverride) { } } } - if (commitOid === mergeSha && headOid.length === 40 && baseOid.length === 40) { + if (commitOid === mergeSha && (headOid.length === 40 || headOid.length === 64) && (baseOid.length === 40 || baseOid.length === 64)) { return baseOid; } return void 0; @@ -165983,7 +165983,7 @@ var getFileOidsUnderPath = async function(basePath) { "Cannot list Git OIDs of tracked files." ); const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + const regex = /^[0-9]+ ([0-9a-f]{40,64}) [0-9]+\t(.+)$/; for (const line of stdout.split("\n")) { if (line) { const match = line.match(regex); diff --git a/lib/init-action.js b/lib/init-action.js index 6acd2a5670..825ef8abfe 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -105595,7 +105595,7 @@ var getFileOidsUnderPath = async function(basePath) { "Cannot list Git OIDs of tracked files." ); const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + const regex = /^[0-9]+ ([0-9a-f]{40,64}) [0-9]+\t(.+)$/; for (const line of stdout.split("\n")) { if (line) { const match = line.match(regex); diff --git a/lib/resolve-environment-action.js b/lib/resolve-environment-action.js index efa88bd40f..4c18bb10e5 100644 --- a/lib/resolve-environment-action.js +++ b/lib/resolve-environment-action.js @@ -104510,7 +104510,7 @@ var getFileOidsUnderPath = async function(basePath) { "Cannot list Git OIDs of tracked files." ); const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + const regex = /^[0-9]+ ([0-9a-f]{40,64}) [0-9]+\t(.+)$/; for (const line of stdout.split("\n")) { if (line) { const match = line.match(regex); diff --git a/lib/setup-codeql-action.js b/lib/setup-codeql-action.js index 1d25f46c20..222d58aa17 100644 --- a/lib/setup-codeql-action.js +++ b/lib/setup-codeql-action.js @@ -104358,7 +104358,7 @@ var getFileOidsUnderPath = async function(basePath) { "Cannot list Git OIDs of tracked files." ); const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + const regex = /^[0-9]+ ([0-9a-f]{40,64}) [0-9]+\t(.+)$/; for (const line of stdout.split("\n")) { if (line) { const match = line.match(regex); diff --git a/lib/upload-lib.js b/lib/upload-lib.js index a0e9fc0c5f..323d4675cd 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -107606,7 +107606,7 @@ var determineBaseBranchHeadCommitOid = async function(checkoutPathOverride) { } } } - if (commitOid === mergeSha && headOid.length === 40 && baseOid.length === 40) { + if (commitOid === mergeSha && (headOid.length === 40 || headOid.length === 64) && (baseOid.length === 40 || baseOid.length === 64)) { return baseOid; } return void 0; @@ -107672,7 +107672,7 @@ var getFileOidsUnderPath = async function(basePath) { "Cannot list Git OIDs of tracked files." ); const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + const regex = /^[0-9]+ ([0-9a-f]{40,64}) [0-9]+\t(.+)$/; for (const line of stdout.split("\n")) { if (line) { const match = line.match(regex); diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 088eef3937..b11d83766e 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -107277,7 +107277,7 @@ var determineBaseBranchHeadCommitOid = async function(checkoutPathOverride) { } } } - if (commitOid === mergeSha && headOid.length === 40 && baseOid.length === 40) { + if (commitOid === mergeSha && (headOid.length === 40 || headOid.length === 64) && (baseOid.length === 40 || baseOid.length === 64)) { return baseOid; } return void 0; @@ -107343,7 +107343,7 @@ var getFileOidsUnderPath = async function(basePath) { "Cannot list Git OIDs of tracked files." ); const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + const regex = /^[0-9]+ ([0-9a-f]{40,64}) [0-9]+\t(.+)$/; for (const line of stdout.split("\n")) { if (line) { const match = line.match(regex); diff --git a/src/git-utils.test.ts b/src/git-utils.test.ts index 8804e1f998..cf9f170be3 100644 --- a/src/git-utils.test.ts +++ b/src/git-utils.test.ts @@ -8,7 +8,7 @@ import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; import * as gitUtils from "./git-utils"; -import { setupActionsVars, setupTests } from "./testing-utils"; +import { setupActionsVars, setupTests, SHA256_GITHUB_SHA } from "./testing-utils"; import { withTmpDir } from "./util"; setupTests(test); @@ -193,6 +193,94 @@ test.serial( }, ); +test.serial( + "getRef() returns merge PR ref if GITHUB_SHA still checked out (SHA-256)", + async (t) => { + await withTmpDir(async (tmpDir: string) => { + setupActionsVars(tmpDir, tmpDir); + const expectedRef = "refs/pull/1/merge"; + const currentSha = "a".repeat(64); + process.env["GITHUB_REF"] = expectedRef; + process.env["GITHUB_SHA"] = currentSha; + + const callback = sinon.stub(gitUtils, "getCommitOid"); + callback.withArgs("HEAD").resolves(currentSha); + + const actualRef = await gitUtils.getRef(); + t.deepEqual(actualRef, expectedRef); + callback.restore(); + }); + }, +); + +test.serial( + "getRef() returns merge PR ref if GITHUB_REF still checked out but sha has changed (actions checkout@v1) (SHA-256)", + async (t) => { + await withTmpDir(async (tmpDir: string) => { + setupActionsVars(tmpDir, tmpDir); + const expectedRef = "refs/pull/1/merge"; + process.env["GITHUB_REF"] = expectedRef; + process.env["GITHUB_SHA"] = "b".repeat(64); + const sha = "a".repeat(64); + + const callback = sinon.stub(gitUtils, "getCommitOid"); + callback.withArgs("refs/remotes/pull/1/merge").resolves(sha); + callback.withArgs("HEAD").resolves(sha); + + const actualRef = await gitUtils.getRef(); + t.deepEqual(actualRef, expectedRef); + callback.restore(); + }); + }, +); + +test.serial( + "getRef() returns head PR ref if GITHUB_REF no longer checked out (SHA-256)", + async (t) => { + await withTmpDir(async (tmpDir: string) => { + setupActionsVars(tmpDir, tmpDir); + process.env["GITHUB_REF"] = "refs/pull/1/merge"; + process.env["GITHUB_SHA"] = "a".repeat(64); + + const callback = sinon.stub(gitUtils, "getCommitOid"); + callback.withArgs(tmpDir, "refs/pull/1/merge").resolves("a".repeat(64)); + callback.withArgs(tmpDir, "HEAD").resolves("b".repeat(64)); + + const actualRef = await gitUtils.getRef(); + t.deepEqual(actualRef, "refs/pull/1/head"); + callback.restore(); + }); + }, +); + +test.serial( + "getRef() returns ref provided as an input and ignores current HEAD (SHA-256)", + async (t) => { + await withTmpDir(async (tmpDir: string) => { + setupActionsVars(tmpDir, tmpDir); + const getAdditionalInputStub = sinon.stub( + actionsUtil, + "getOptionalInput", + ); + getAdditionalInputStub.withArgs("ref").resolves("refs/pull/2/merge"); + getAdditionalInputStub.withArgs("sha").resolves("b".repeat(64)); + + // These values are be ignored + process.env["GITHUB_REF"] = "refs/pull/1/merge"; + process.env["GITHUB_SHA"] = "a".repeat(64); + + const callback = sinon.stub(gitUtils, "getCommitOid"); + callback.withArgs("refs/pull/1/merge").resolves("b".repeat(64)); + callback.withArgs("HEAD").resolves("b".repeat(64)); + + const actualRef = await gitUtils.getRef(); + t.deepEqual(actualRef, "refs/pull/2/merge"); + callback.restore(); + getAdditionalInputStub.restore(); + }); + }, +); + test.serial("isAnalyzingDefaultBranch()", async (t) => { process.env["GITHUB_EVENT_NAME"] = "push"; process.env["CODE_SCANNING_IS_ANALYZING_DEFAULT_BRANCH"] = "true"; @@ -305,6 +393,27 @@ test.serial("determineBaseBranchHeadCommitOid other error", async (t) => { infoStub.restore(); }); +test.serial( + "determineBaseBranchHeadCommitOid returns baseOid for SHA-256 merge commit", + async (t) => { + const mergeSha = "a".repeat(64); + const baseOid = "b".repeat(64); + const headOid = "c".repeat(64); + + process.env["GITHUB_EVENT_NAME"] = "pull_request"; + process.env["GITHUB_SHA"] = mergeSha; + + sinon + .stub(gitUtils as any, "runGitCommand") + .resolves( + `commit ${mergeSha}\nparent ${baseOid}\nparent ${headOid}\n`, + ); + + const result = await gitUtils.determineBaseBranchHeadCommitOid(__dirname); + t.deepEqual(result, baseOid); + }, +); + test.serial("decodeGitFilePath unquoted strings", async (t) => { t.deepEqual(gitUtils.decodeGitFilePath("foo"), "foo"); t.deepEqual(gitUtils.decodeGitFilePath("foo bar"), "foo bar"); @@ -482,6 +591,61 @@ test.serial( }, ); +test.serial( + "getFileOidsUnderPath handles SHA-256 OIDs (64-char)", + async (t) => { + await withTmpDir(async (tmpDir) => { + sinon + .stub(gitUtils as any, "runGitCommand") + .callsFake(async (_cwd: any, args: any) => { + if (args[0] === "rev-parse") { + return `${tmpDir}\n`; + } + return ( + "100644 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2c0d4b7e8f9a1234567890ab 0\tlib/git-utils.js\n" + + "100644 aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899 0\tsrc/git-utils.ts" + ); + }); + + const result = await gitUtils.getFileOidsUnderPath("/fake/path"); + + t.deepEqual(result, { + "lib/git-utils.js": + "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2c0d4b7e8f9a1234567890ab", + "src/git-utils.ts": + "aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899", + }); + }); + }, +); + +test.serial( + "getFileOidsUnderPath handles mixed SHA-1 and SHA-256 OIDs", + async (t) => { + await withTmpDir(async (tmpDir) => { + sinon + .stub(gitUtils as any, "runGitCommand") + .callsFake(async (_cwd: any, args: any) => { + if (args[0] === "rev-parse") { + return `${tmpDir}\n`; + } + return ( + "100644 30d998ded095371488be3a729eb61d86ed721a18 0\tlib/sha1-file.js\n" + + "100644 aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899 0\tsrc/sha256-file.ts" + ); + }); + + const result = await gitUtils.getFileOidsUnderPath("/fake/path"); + + t.deepEqual(result, { + "lib/sha1-file.js": "30d998ded095371488be3a729eb61d86ed721a18", + "src/sha256-file.ts": + "aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899", + }); + }); + }, +); + test.serial( "getGitVersionOrThrow returns version for valid git output", async (t) => { diff --git a/src/git-utils.ts b/src/git-utils.ts index ec0478fa89..d0745e507b 100644 --- a/src/git-utils.ts +++ b/src/git-utils.ts @@ -166,8 +166,8 @@ export const determineBaseBranchHeadCommitOid = async function ( // Let's confirm our assumptions: We had a merge commit and the parsed parent data looks correct if ( commitOid === mergeSha && - headOid.length === 40 && - baseOid.length === 40 + (headOid.length === 40 || headOid.length === 64) && + (baseOid.length === 40 || baseOid.length === 64) ) { return baseOid; } @@ -296,7 +296,7 @@ export const getFileOidsUnderPath = async function ( // 100644 4c51bc1d9e86cd86e01b0f340cb8ce095c33b283 0\tsrc/git-utils.test.ts // 100644 6b792ea543ce75d7a8a03df591e3c85311ecb64f 0\tsrc/git-utils.ts // The fields are: \t - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + const regex = /^[0-9]+ ([0-9a-f]{40,64}) [0-9]+\t(.+)$/; for (const line of stdout.split("\n")) { if (line) { const match = line.match(regex); diff --git a/src/testing-utils.ts b/src/testing-utils.ts index fcb7149b56..2d942d09cc 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -160,6 +160,9 @@ export const DEFAULT_ACTIONS_VARS = { RUNNER_OS: "Linux", } as const satisfies Record; +/** A 64-character SHA-256 Git OID for use in SHA-256 repository test scenarios. */ +export const SHA256_GITHUB_SHA = "0".repeat(64); + // Sets environment variables that make using some libraries designed for // use only on actions safe to use outside of actions. export function setupActionsVars( diff --git a/src/upload-lib.test.ts b/src/upload-lib.test.ts index 2c27d56c1c..36ec3da489 100644 --- a/src/upload-lib.test.ts +++ b/src/upload-lib.test.ts @@ -12,7 +12,7 @@ import * as api from "./api-client"; import * as diffUtils from "./diff-informed-analysis-utils"; import { getRunnerLogger, Logger } from "./logging"; import * as sarif from "./sarif"; -import { setupTests } from "./testing-utils"; +import { setupTests, SHA256_GITHUB_SHA } from "./testing-utils"; import * as uploadLib from "./upload-lib"; import { UploadPayload } from "./upload-lib/types"; import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util"; @@ -110,6 +110,35 @@ test.serial( }, ); +test.serial( + "validate correct payload used for PR merge commit with SHA-256 OIDs", + async (t) => { + process.env["GITHUB_EVENT_NAME"] = "pull_request"; + process.env["GITHUB_SHA"] = SHA256_GITHUB_SHA; + process.env["GITHUB_BASE_REF"] = "master"; + process.env["GITHUB_EVENT_PATH"] = + `${__dirname}/../src/testdata/pull_request.json`; + + const sha256MergeBase = "b".repeat(64); + const prMergePayload: any = uploadLib.buildPayload( + SHA256_GITHUB_SHA, + "refs/pull/123/merge", + "key", + undefined, + "", + 1234, + 1, + "/opt/src", + undefined, + ["CodeQL", "eslint"], + sha256MergeBase, + ); + // Uploads for a merge commit use the merge base (SHA-256) + t.deepEqual(prMergePayload.base_ref, "refs/heads/master"); + t.deepEqual(prMergePayload.base_sha, sha256MergeBase); + }, +); + test.serial("finding SARIF files", async (t) => { await withTmpDir(async (tmpDir) => { // include a couple of sarif files