Turboscan only allows a single combination of tool name and automation details id for testing category uniqueness. Previously, the check in the action was not entirely correct since it only looked at the _category_ and not the combination of the category and the tool name. It's even more precise now since it is looking at the actual, computed value of the automation details id, rather than an inputted value of the category. This change also includes a refactoring where the action is now avoiding multiple parsing/stringifying of the sarif files. Instead, sarif is parsed once at the start of the process and stringified once, after sarif processing is completely finished.
208 lines
No EOL
11 KiB
JavaScript
Generated
208 lines
No EOL
11 KiB
JavaScript
Generated
"use strict";
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
}) : (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const fs = __importStar(require("fs"));
|
|
const path = __importStar(require("path"));
|
|
const ava_1 = __importDefault(require("ava"));
|
|
const logging_1 = require("./logging");
|
|
const testing_utils_1 = require("./testing-utils");
|
|
const uploadLib = __importStar(require("./upload-lib"));
|
|
const util_1 = require("./util");
|
|
(0, testing_utils_1.setupTests)(ava_1.default);
|
|
ava_1.default.beforeEach(() => {
|
|
(0, util_1.initializeEnvironment)(util_1.Mode.actions, "1.2.3");
|
|
});
|
|
(0, ava_1.default)("validateSarifFileSchema - valid", (t) => {
|
|
const inputFile = `${__dirname}/../src/testdata/valid-sarif.sarif`;
|
|
t.notThrows(() => uploadLib.validateSarifFileSchema(inputFile, (0, logging_1.getRunnerLogger)(true)));
|
|
});
|
|
(0, ava_1.default)("validateSarifFileSchema - invalid", (t) => {
|
|
const inputFile = `${__dirname}/../src/testdata/invalid-sarif.sarif`;
|
|
t.throws(() => uploadLib.validateSarifFileSchema(inputFile, (0, logging_1.getRunnerLogger)(true)));
|
|
});
|
|
(0, ava_1.default)("validate correct payload used per version", async (t) => {
|
|
const newVersions = [
|
|
{ type: util_1.GitHubVariant.DOTCOM },
|
|
{ type: util_1.GitHubVariant.GHES, version: "3.1.0" },
|
|
];
|
|
const oldVersions = [
|
|
{ type: util_1.GitHubVariant.GHES, version: "2.22.1" },
|
|
{ type: util_1.GitHubVariant.GHES, version: "3.0.0" },
|
|
];
|
|
const allVersions = newVersions.concat(oldVersions);
|
|
process.env["GITHUB_EVENT_NAME"] = "push";
|
|
for (const version of allVersions) {
|
|
const payload = uploadLib.buildPayload("commit", "refs/heads/master", "key", undefined, "", undefined, "/opt/src", undefined, ["CodeQL", "eslint"], version);
|
|
// Not triggered by a pull request
|
|
t.falsy(payload.base_ref);
|
|
t.falsy(payload.base_sha);
|
|
}
|
|
process.env["GITHUB_EVENT_NAME"] = "pull_request";
|
|
process.env["GITHUB_EVENT_PATH"] = `${__dirname}/../src/testdata/pull_request.json`;
|
|
for (const version of newVersions) {
|
|
const payload = uploadLib.buildPayload("commit", "refs/pull/123/merge", "key", undefined, "", undefined, "/opt/src", undefined, ["CodeQL", "eslint"], version);
|
|
t.deepEqual(payload.base_ref, "refs/heads/master");
|
|
t.deepEqual(payload.base_sha, "f95f852bd8fca8fcc58a9a2d6c842781e32a215e");
|
|
}
|
|
for (const version of oldVersions) {
|
|
const payload = uploadLib.buildPayload("commit", "refs/pull/123/merge", "key", undefined, "", undefined, "/opt/src", undefined, ["CodeQL", "eslint"], version);
|
|
// These older versions won't expect these values
|
|
t.falsy(payload.base_ref);
|
|
t.falsy(payload.base_sha);
|
|
}
|
|
});
|
|
(0, ava_1.default)("finding SARIF files", async (t) => {
|
|
await (0, util_1.withTmpDir)(async (tmpDir) => {
|
|
// include a couple of sarif files
|
|
fs.writeFileSync(path.join(tmpDir, "a.sarif"), "");
|
|
fs.writeFileSync(path.join(tmpDir, "b.sarif"), "");
|
|
// other random files shouldn't be returned
|
|
fs.writeFileSync(path.join(tmpDir, "c.foo"), "");
|
|
// we should recursively look in subdirectories
|
|
fs.mkdirSync(path.join(tmpDir, "dir1"));
|
|
fs.writeFileSync(path.join(tmpDir, "dir1", "d.sarif"), "");
|
|
fs.mkdirSync(path.join(tmpDir, "dir1", "dir2"));
|
|
fs.writeFileSync(path.join(tmpDir, "dir1", "dir2", "e.sarif"), "");
|
|
// we should ignore symlinks
|
|
fs.mkdirSync(path.join(tmpDir, "dir3"));
|
|
fs.symlinkSync(tmpDir, path.join(tmpDir, "dir3", "symlink1"), "dir");
|
|
fs.symlinkSync(path.join(tmpDir, "a.sarif"), path.join(tmpDir, "dir3", "symlink2.sarif"), "file");
|
|
const sarifFiles = uploadLib.findSarifFilesInDir(tmpDir);
|
|
t.deepEqual(sarifFiles, [
|
|
path.join(tmpDir, "a.sarif"),
|
|
path.join(tmpDir, "b.sarif"),
|
|
path.join(tmpDir, "dir1", "d.sarif"),
|
|
path.join(tmpDir, "dir1", "dir2", "e.sarif"),
|
|
]);
|
|
});
|
|
});
|
|
(0, ava_1.default)("populateRunAutomationDetails", (t) => {
|
|
let sarif = {
|
|
runs: [{}],
|
|
};
|
|
const analysisKey = ".github/workflows/codeql-analysis.yml:analyze";
|
|
let expectedSarif = {
|
|
runs: [{ automationDetails: { id: "language:javascript/os:linux/" } }],
|
|
};
|
|
// Category has priority over analysis_key/environment
|
|
let modifiedSarif = uploadLib.populateRunAutomationDetails(sarif, "language:javascript/os:linux", analysisKey, '{"language": "other", "os": "other"}');
|
|
t.deepEqual(modifiedSarif, expectedSarif);
|
|
// It doesn't matter if the category has a slash at the end or not
|
|
modifiedSarif = uploadLib.populateRunAutomationDetails(sarif, "language:javascript/os:linux/", analysisKey, "");
|
|
t.deepEqual(modifiedSarif, expectedSarif);
|
|
// check that the automation details doesn't get overwritten
|
|
sarif = { runs: [{ automationDetails: { id: "my_id" } }] };
|
|
expectedSarif = { runs: [{ automationDetails: { id: "my_id" } }] };
|
|
modifiedSarif = uploadLib.populateRunAutomationDetails(sarif, undefined, analysisKey, '{"os": "linux", "language": "javascript"}');
|
|
t.deepEqual(modifiedSarif, expectedSarif);
|
|
// check multiple runs
|
|
sarif = { runs: [{ automationDetails: { id: "my_id" } }, {}] };
|
|
expectedSarif = {
|
|
runs: [
|
|
{ automationDetails: { id: "my_id" } },
|
|
{
|
|
automationDetails: {
|
|
id: ".github/workflows/codeql-analysis.yml:analyze/language:javascript/os:linux/",
|
|
},
|
|
},
|
|
],
|
|
};
|
|
modifiedSarif = uploadLib.populateRunAutomationDetails(sarif, undefined, analysisKey, '{"os": "linux", "language": "javascript"}');
|
|
t.deepEqual(modifiedSarif, expectedSarif);
|
|
});
|
|
(0, ava_1.default)("validateUniqueCategory when empty", (t) => {
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif()));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif()));
|
|
});
|
|
(0, ava_1.default)("validateUniqueCategory for automation details id", (t) => {
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("abc")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("AbC")));
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("def")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("def")));
|
|
// Our category sanitization is not perfect. Here are some examples
|
|
// of where we see false clashes
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("abc/def")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc@def")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc_def")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc def")));
|
|
// this one is fine
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("abc_ def")));
|
|
});
|
|
(0, ava_1.default)("validateUniqueCategory for tool name", (t) => {
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif(undefined, "AbC")));
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif(undefined, "def")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif(undefined, "def")));
|
|
// Our category sanitization is not perfect. Here are some examples
|
|
// of where we see false clashes
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc/def")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc@def")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc_def")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc def")));
|
|
// this one is fine
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("abc_ def")));
|
|
});
|
|
(0, ava_1.default)("validateUniqueCategory for automation details id and tool name", (t) => {
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("abc", "abc")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc", "abc")));
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("abc_", "def")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc_", "def")));
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("ghi", "_jkl")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("ghi", "_jkl")));
|
|
// Our category sanitization is not perfect. Here are some examples
|
|
// of where we see false clashes
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("abc")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc", "_")));
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("abc", "def__")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc_def")));
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("mno_", "pqr")));
|
|
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("mno", "_pqr")));
|
|
});
|
|
(0, ava_1.default)("validateUniqueCategory for multiple runs", (t) => {
|
|
const sarif1 = createMockSarif("abc", "def");
|
|
const sarif2 = createMockSarif("ghi", "jkl");
|
|
const multiSarif = { runs: [sarif1.runs[0], sarif2.runs[0]] };
|
|
t.notThrows(() => uploadLib.validateUniqueCategory(multiSarif));
|
|
t.throws(() => uploadLib.validateUniqueCategory(sarif1));
|
|
t.throws(() => uploadLib.validateUniqueCategory(sarif2));
|
|
});
|
|
function createMockSarif(id, tool) {
|
|
return {
|
|
runs: [
|
|
{
|
|
automationDetails: {
|
|
id,
|
|
},
|
|
tool: {
|
|
driver: {
|
|
name: tool,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
};
|
|
}
|
|
//# sourceMappingURL=upload-lib.test.js.map
|