diff --git a/.github/workflows/__quality-queries.yml b/.github/workflows/__quality-queries.yml index 1260241cb2..bbd5decf78 100644 --- a/.github/workflows/__quality-queries.yml +++ b/.github/workflows/__quality-queries.yml @@ -32,16 +32,58 @@ jobs: include: - os: ubuntu-latest version: linked + analysis-kinds: code-scanning + - os: ubuntu-latest + version: linked + analysis-kinds: code-quality + - os: ubuntu-latest + version: linked + analysis-kinds: code-scanning,code-quality + - os: macos-latest + version: linked + analysis-kinds: code-scanning - os: macos-latest version: linked + analysis-kinds: code-quality + - os: macos-latest + version: linked + analysis-kinds: code-scanning,code-quality + - os: windows-latest + version: linked + analysis-kinds: code-scanning + - os: windows-latest + version: linked + analysis-kinds: code-quality - os: windows-latest version: linked + analysis-kinds: code-scanning,code-quality - os: ubuntu-latest version: nightly-latest + analysis-kinds: code-scanning + - os: ubuntu-latest + version: nightly-latest + analysis-kinds: code-quality + - os: ubuntu-latest + version: nightly-latest + analysis-kinds: code-scanning,code-quality + - os: macos-latest + version: nightly-latest + analysis-kinds: code-scanning - os: macos-latest version: nightly-latest + analysis-kinds: code-quality + - os: macos-latest + version: nightly-latest + analysis-kinds: code-scanning,code-quality + - os: windows-latest + version: nightly-latest + analysis-kinds: code-scanning + - os: windows-latest + version: nightly-latest + analysis-kinds: code-quality - os: windows-latest version: nightly-latest + analysis-kinds: code-scanning,code-quality name: Quality queries input permissions: contents: read @@ -61,25 +103,30 @@ jobs: - uses: ./../action/init with: languages: javascript - quality-queries: code-quality + analysis-kinds: ${{ matrix.analysis-kinds }} tools: ${{ steps.prepare-test.outputs.tools-url }} - uses: ./../action/analyze with: output: ${{ runner.temp }}/results upload-database: false - name: Upload security SARIF + if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/upload-artifact@v4 with: - name: quality-queries-${{ matrix.os }}-${{ matrix.version }}.sarif.json + name: | + quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json path: ${{ runner.temp }}/results/javascript.sarif retention-days: 7 - name: Upload quality SARIF + if: contains(matrix.analysis-kinds, 'code-quality') uses: actions/upload-artifact@v4 with: - name: quality-queries-${{ matrix.os }}-${{ matrix.version }}.quality.sarif.json + name: | + quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json path: ${{ runner.temp }}/results/javascript.quality.sarif retention-days: 7 - name: Check quality query does not appear in security SARIF + if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/github-script@v7 env: SARIF_PATH: ${{ runner.temp }}/results/javascript.sarif @@ -87,6 +134,7 @@ jobs: with: script: ${{ env.CHECK_SCRIPT }} - name: Check quality query appears in quality SARIF + if: contains(matrix.analysis-kinds, 'code-quality') uses: actions/github-script@v7 env: SARIF_PATH: ${{ runner.temp }}/results/javascript.quality.sarif diff --git a/.github/workflows/__upload-quality-sarif.yml b/.github/workflows/__upload-quality-sarif.yml index d122d40861..2332aff841 100644 --- a/.github/workflows/__upload-quality-sarif.yml +++ b/.github/workflows/__upload-quality-sarif.yml @@ -73,7 +73,7 @@ jobs: languages: cpp,csharp,java,javascript,python config-file: ${{ github.repository }}/tests/multi-language-repo/.github/codeql/custom-queries.yml@${{ github.sha }} - quality-queries: code-quality + analysis-kinds: code-scanning,code-quality - name: Build code shell: bash run: ./build.sh diff --git a/lib/analyze-action-post.js b/lib/analyze-action-post.js index 5398605d40..3a10dad154 100644 --- a/lib/analyze-action-post.js +++ b/lib/analyze-action-post.js @@ -20288,7 +20288,7 @@ var require_dist_node2 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -20296,7 +20296,7 @@ var require_dist_node2 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -20308,14 +20308,14 @@ var require_dist_node2 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -20323,12 +20323,12 @@ var require_dist_node2 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -20343,7 +20343,7 @@ var require_dist_node2 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -21028,7 +21028,7 @@ var require_dist_node6 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -21036,7 +21036,7 @@ var require_dist_node6 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -21048,14 +21048,14 @@ var require_dist_node6 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -21063,12 +21063,12 @@ var require_dist_node6 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -21083,7 +21083,7 @@ var require_dist_node6 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -31821,14 +31821,14 @@ var require_typeGuards = __commonJS({ "node_modules/@azure/core-util/dist/commonjs/typeGuards.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isDefined = isDefined; + exports2.isDefined = isDefined2; exports2.isObjectWithProperties = isObjectWithProperties; exports2.objectHasProperty = objectHasProperty; - function isDefined(thing) { + function isDefined2(thing) { return typeof thing !== "undefined" && thing !== null; } function isObjectWithProperties(thing, properties) { - if (!isDefined(thing) || typeof thing !== "object") { + if (!isDefined2(thing) || typeof thing !== "object") { return false; } for (const property of properties) { @@ -31839,7 +31839,7 @@ var require_typeGuards = __commonJS({ return true; } function objectHasProperty(thing, property) { - return isDefined(thing) && typeof thing === "object" && property in thing; + return isDefined2(thing) && typeof thing === "object" && property in thing; } } }); @@ -102910,7 +102910,7 @@ var require_dist_node16 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -102918,7 +102918,7 @@ var require_dist_node16 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -102928,12 +102928,12 @@ var require_dist_node16 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push(encodeValue(operator, value2, isKeyOperator(operator) ? key : "")); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -102941,12 +102941,12 @@ var require_dist_node16 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -102961,7 +102961,7 @@ var require_dist_node16 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 12628f9bd2..709a1546f3 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -20288,7 +20288,7 @@ var require_dist_node2 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -20296,7 +20296,7 @@ var require_dist_node2 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -20308,14 +20308,14 @@ var require_dist_node2 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -20323,12 +20323,12 @@ var require_dist_node2 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -20343,7 +20343,7 @@ var require_dist_node2 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -21028,7 +21028,7 @@ var require_dist_node6 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -21036,7 +21036,7 @@ var require_dist_node6 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -21048,14 +21048,14 @@ var require_dist_node6 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -21063,12 +21063,12 @@ var require_dist_node6 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -21083,7 +21083,7 @@ var require_dist_node6 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -37670,14 +37670,14 @@ var require_typeGuards = __commonJS({ "node_modules/@azure/core-util/dist/commonjs/typeGuards.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isDefined = isDefined; + exports2.isDefined = isDefined2; exports2.isObjectWithProperties = isObjectWithProperties; exports2.objectHasProperty = objectHasProperty; - function isDefined(thing) { + function isDefined2(thing) { return typeof thing !== "undefined" && thing !== null; } function isObjectWithProperties(thing, properties) { - if (!isDefined(thing) || typeof thing !== "object") { + if (!isDefined2(thing) || typeof thing !== "object") { return false; } for (const property of properties) { @@ -37688,7 +37688,7 @@ var require_typeGuards = __commonJS({ return true; } function objectHasProperty(thing, property) { - return isDefined(thing) && typeof thing === "object" && property in thing; + return isDefined2(thing) && typeof thing === "object" && property in thing; } } }); @@ -90113,12 +90113,6 @@ function fixCodeQualityCategory(logger, category) { return category; } -// src/analyze.ts -var fs15 = __toESM(require("fs")); -var path16 = __toESM(require("path")); -var import_perf_hooks2 = require("perf_hooks"); -var io5 = __toESM(require_io()); - // src/analyses.ts var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; @@ -90127,6 +90121,28 @@ var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); var codeQualityQueries = ["code-quality"]; +var CodeScanning = { + kind: "code-scanning" /* CodeScanning */, + name: "code scanning", + target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, + sarifExtension: ".sarif", + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name), + sentinelPrefix: "CODEQL_UPLOAD_SARIF_" +}; +var CodeQuality = { + kind: "code-quality" /* CodeQuality */, + name: "code quality", + target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, + sarifExtension: ".quality.sarif", + sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" +}; + +// src/analyze.ts +var fs15 = __toESM(require("fs")); +var path16 = __toESM(require("path")); +var import_perf_hooks2 = require("perf_hooks"); +var io5 = __toESM(require_io()); // src/api-client.ts var core5 = __toESM(require_core()); @@ -91601,9 +91617,18 @@ function appendExtraQueryExclusions(extraQueryExclusions, cliConfig) { } return augmentedConfig; } +function isCodeScanningEnabled(config) { + return config.analysisKinds.includes("code-scanning" /* CodeScanning */); +} function isCodeQualityEnabled(config) { return config.analysisKinds.includes("code-quality" /* CodeQuality */); } +function getPrimaryAnalysisKind(config) { + return isCodeScanningEnabled(config) ? "code-scanning" /* CodeScanning */ : "code-quality" /* CodeQuality */; +} +function getPrimaryAnalysisConfig(config) { + return getPrimaryAnalysisKind(config) === "code-scanning" /* CodeScanning */ ? CodeScanning : CodeQuality; +} // src/setup-codeql.ts var fs12 = __toESM(require("fs")); @@ -93560,6 +93585,9 @@ function resolveQuerySuiteAlias(language, maybeSuite) { } return maybeSuite; } +function addSarifExtension(analysis, base) { + return `${base}${analysis.sarifExtension}`; +} async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag, diffRangePackDir, automationDetailsId, codeql, config, logger, features) { const statusReport = {}; const queryFlags = [memoryFlag, threadsFlag]; @@ -93579,14 +93607,16 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag, incrementalMode.push("overlay"); } const sarifRunPropertyFlag = incrementalMode.length > 0 ? `--sarif-run-property=incrementalMode=${incrementalMode.join(",")}` : void 0; + const dbAnalysisConfig = getPrimaryAnalysisConfig(config); for (const language of config.languages) { try { - const sarifFile = path16.join(sarifFolder, `${language}.sarif`); const queries = []; - if (isCodeQualityEnabled(config)) { + if (config.analysisKinds.length > 1) { queries.push(getGeneratedSuitePath(config, language)); - for (const qualityQuery of codeQualityQueries) { - queries.push(resolveQuerySuiteAlias(language, qualityQuery)); + if (isCodeQualityEnabled(config)) { + for (const qualityQuery of codeQualityQueries) { + queries.push(resolveQuerySuiteAlias(language, qualityQuery)); + } } } logger.startGroup(`Running queries for ${language}`); @@ -93595,35 +93625,24 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag, await codeql.databaseRunQueries(databasePath, queryFlags, queries); logger.debug(`Finished running queries for ${language}.`); statusReport[`analyze_builtin_queries_${language}_duration_ms`] = (/* @__PURE__ */ new Date()).getTime() - startTimeRunQueries; - logger.startGroup(`Interpreting results for ${language}`); const startTimeInterpretResults = /* @__PURE__ */ new Date(); - const analysisSummary = await runInterpretResults( + const { summary: analysisSummary, sarifFile } = await runInterpretResultsFor( + dbAnalysisConfig, language, void 0, - sarifFile, - config.debugMode, - automationDetailsId + config.debugMode ); let qualityAnalysisSummary; - if (isCodeQualityEnabled(config)) { - logger.info(`Interpreting quality results for ${language}`); - const qualityCategory = fixCodeQualityCategory( - logger, - automationDetailsId - ); - const qualitySarifFile = path16.join( - sarifFolder, - `${language}.quality.sarif` - ); - qualityAnalysisSummary = await runInterpretResults( + if (config.analysisKinds.length > 1 && isCodeQualityEnabled(config)) { + const qualityResult = await runInterpretResultsFor( + CodeQuality, language, codeQualityQueries.map( (i) => resolveQuerySuiteAlias(language, i) ), - qualitySarifFile, - config.debugMode, - qualityCategory + config.debugMode ); + qualityAnalysisSummary = qualityResult.summary; } const endTimeInterpretResults = /* @__PURE__ */ new Date(); statusReport[`interpret_results_${language}_duration_ms`] = endTimeInterpretResults.getTime() - startTimeInterpretResults.getTime(); @@ -93659,6 +93678,25 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag, } } return statusReport; + async function runInterpretResultsFor(analysis, language, queries, enableDebugLogging) { + logger.info(`Interpreting ${analysis.name} results for ${language}`); + let category = automationDetailsId; + if (dbAnalysisConfig.kind === "code-quality" /* CodeQuality */) { + category = fixCodeQualityCategory(logger, automationDetailsId); + } + const sarifFile = path16.join( + sarifFolder, + addSarifExtension(analysis, language) + ); + const summary = await runInterpretResults( + language, + queries, + sarifFile, + enableDebugLogging, + category + ); + return { summary, sarifFile }; + } async function runInterpretResults(language, queries, sarifFile, enableDebugLogging, category) { const databasePath = getCodeQLDatabasePath(config, language); return await codeql.databaseInterpretResults( @@ -95498,18 +95536,6 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo } return payloadObj; } -var CodeScanningTarget = { - name: "code scanning", - target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, - sarifPredicate: (name) => name.endsWith(".sarif") && !CodeQualityTarget.sarifPredicate(name), - sentinelPrefix: "CODEQL_UPLOAD_SARIF_" -}; -var CodeQualityTarget = { - name: "code quality", - target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, - sarifPredicate: (name) => name.endsWith(".quality.sarif"), - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" -}; async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { const sarifPaths = getSarifFilePaths( inputSarifPath, @@ -95524,7 +95550,7 @@ async function uploadFiles(inputSarifPath, checkoutPath, category, features, log uploadTarget ); } -async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget = CodeScanningTarget) { +async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { logger.startGroup(`Uploading ${uploadTarget.name} results`); logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); @@ -95695,7 +95721,7 @@ function handleProcessingResultForUnsuccessfulExecution(response, status, logger assertNever(status); } } -function validateUniqueCategory(sarif, sentinelPrefix = CodeScanningTarget.sentinelPrefix) { +function validateUniqueCategory(sarif, sentinelPrefix) { const categories = {}; for (const run2 of sarif.runs) { const id = run2?.automationDetails?.id; @@ -95945,15 +95971,17 @@ async function run() { core14.setOutput("sarif-output", import_path4.default.resolve(outputDir)); const uploadInput = getOptionalInput("upload"); if (runStats && getUploadValue(uploadInput) === "always") { - uploadResult = await uploadFiles( - outputDir, - getRequiredInput("checkout_path"), - getOptionalInput("category"), - features, - logger, - CodeScanningTarget - ); - core14.setOutput("sarif-id", uploadResult.sarifID); + if (isCodeScanningEnabled(config)) { + uploadResult = await uploadFiles( + outputDir, + getRequiredInput("checkout_path"), + getOptionalInput("category"), + features, + logger, + CodeScanning + ); + core14.setOutput("sarif-id", uploadResult.sarifID); + } if (isCodeQualityEnabled(config)) { const qualityUploadResult = await uploadFiles( outputDir, @@ -95964,7 +95992,7 @@ async function run() { ), features, logger, - CodeQualityTarget + CodeQuality ); core14.setOutput("quality-sarif-id", qualityUploadResult.sarifID); } diff --git a/lib/autobuild-action.js b/lib/autobuild-action.js index 931f34583c..bfab5e3375 100644 --- a/lib/autobuild-action.js +++ b/lib/autobuild-action.js @@ -20288,7 +20288,7 @@ var require_dist_node2 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -20296,7 +20296,7 @@ var require_dist_node2 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -20308,14 +20308,14 @@ var require_dist_node2 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -20323,12 +20323,12 @@ var require_dist_node2 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -20343,7 +20343,7 @@ var require_dist_node2 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -21028,7 +21028,7 @@ var require_dist_node6 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -21036,7 +21036,7 @@ var require_dist_node6 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -21048,14 +21048,14 @@ var require_dist_node6 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -21063,12 +21063,12 @@ var require_dist_node6 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -21083,7 +21083,7 @@ var require_dist_node6 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -31821,14 +31821,14 @@ var require_typeGuards = __commonJS({ "node_modules/@azure/core-util/dist/commonjs/typeGuards.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isDefined = isDefined; + exports2.isDefined = isDefined2; exports2.isObjectWithProperties = isObjectWithProperties; exports2.objectHasProperty = objectHasProperty; - function isDefined(thing) { + function isDefined2(thing) { return typeof thing !== "undefined" && thing !== null; } function isObjectWithProperties(thing, properties) { - if (!isDefined(thing) || typeof thing !== "object") { + if (!isDefined2(thing) || typeof thing !== "object") { return false; } for (const property of properties) { @@ -31839,7 +31839,7 @@ var require_typeGuards = __commonJS({ return true; } function objectHasProperty(thing, property) { - return isDefined(thing) && typeof thing === "object" && property in thing; + return isDefined2(thing) && typeof thing === "object" && property in thing; } } }); diff --git a/lib/init-action-post.js b/lib/init-action-post.js index 2751c1ec80..be33782791 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -20288,7 +20288,7 @@ var require_dist_node2 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -20296,7 +20296,7 @@ var require_dist_node2 = __commonJS({ } function getValues(context3, operator, key, modifier) { var value = context3[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -20308,14 +20308,14 @@ var require_dist_node2 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -20323,12 +20323,12 @@ var require_dist_node2 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -20343,7 +20343,7 @@ var require_dist_node2 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -21028,7 +21028,7 @@ var require_dist_node6 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -21036,7 +21036,7 @@ var require_dist_node6 = __commonJS({ } function getValues(context3, operator, key, modifier) { var value = context3[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -21048,14 +21048,14 @@ var require_dist_node6 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -21063,12 +21063,12 @@ var require_dist_node6 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -21083,7 +21083,7 @@ var require_dist_node6 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -37670,14 +37670,14 @@ var require_typeGuards = __commonJS({ "node_modules/@azure/core-util/dist/commonjs/typeGuards.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isDefined = isDefined; + exports2.isDefined = isDefined2; exports2.isObjectWithProperties = isObjectWithProperties; exports2.objectHasProperty = objectHasProperty; - function isDefined(thing) { + function isDefined2(thing) { return typeof thing !== "undefined" && thing !== null; } function isObjectWithProperties(thing, properties) { - if (!isDefined(thing) || typeof thing !== "object") { + if (!isDefined2(thing) || typeof thing !== "object") { return false; } for (const property of properties) { @@ -37688,7 +37688,7 @@ var require_typeGuards = __commonJS({ return true; } function objectHasProperty(thing, property) { - return isDefined(thing) && typeof thing === "object" && property in thing; + return isDefined2(thing) && typeof thing === "object" && property in thing; } } }); @@ -108759,7 +108759,7 @@ var require_dist_node16 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -108767,7 +108767,7 @@ var require_dist_node16 = __commonJS({ } function getValues(context3, operator, key, modifier) { var value = context3[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -108777,12 +108777,12 @@ var require_dist_node16 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push(encodeValue(operator, value2, isKeyOperator(operator) ? key : "")); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -108790,12 +108790,12 @@ var require_dist_node16 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -108810,7 +108810,7 @@ var require_dist_node16 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -128754,6 +128754,22 @@ var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); +var CodeScanning = { + kind: "code-scanning" /* CodeScanning */, + name: "code scanning", + target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, + sarifExtension: ".sarif", + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name), + sentinelPrefix: "CODEQL_UPLOAD_SARIF_" +}; +var CodeQuality = { + kind: "code-quality" /* CodeQuality */, + name: "code quality", + target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, + sarifExtension: ".quality.sarif", + sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" +}; // src/caching-utils.ts var core6 = __toESM(require_core()); @@ -132980,18 +132996,6 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo } return payloadObj; } -var CodeScanningTarget = { - name: "code scanning", - target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, - sarifPredicate: (name) => name.endsWith(".sarif") && !CodeQualityTarget.sarifPredicate(name), - sentinelPrefix: "CODEQL_UPLOAD_SARIF_" -}; -var CodeQualityTarget = { - name: "code quality", - target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, - sarifPredicate: (name) => name.endsWith(".quality.sarif"), - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" -}; async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { const sarifPaths = getSarifFilePaths( inputSarifPath, @@ -133006,7 +133010,7 @@ async function uploadFiles(inputSarifPath, checkoutPath, category, features, log uploadTarget ); } -async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget = CodeScanningTarget) { +async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { logger.startGroup(`Uploading ${uploadTarget.name} results`); logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); @@ -133177,7 +133181,7 @@ function handleProcessingResultForUnsuccessfulExecution(response, status, logger assertNever(status); } } -function validateUniqueCategory(sarif, sentinelPrefix = CodeScanningTarget.sentinelPrefix) { +function validateUniqueCategory(sarif, sentinelPrefix) { const categories = {}; for (const run2 of sarif.runs) { const id = run2?.automationDetails?.id; @@ -133402,7 +133406,7 @@ async function maybeUploadFailedSarif(config, repositoryNwo, features, logger) { category, features, logger, - CodeScanningTarget + CodeScanning ); await waitForProcessing( repositoryNwo, diff --git a/lib/init-action.js b/lib/init-action.js index c7db9fb5f1..e76379f64a 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -22196,7 +22196,7 @@ var require_dist_node2 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -22204,7 +22204,7 @@ var require_dist_node2 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -22216,14 +22216,14 @@ var require_dist_node2 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -22231,12 +22231,12 @@ var require_dist_node2 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -22251,7 +22251,7 @@ var require_dist_node2 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -22936,7 +22936,7 @@ var require_dist_node6 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -22944,7 +22944,7 @@ var require_dist_node6 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -22956,14 +22956,14 @@ var require_dist_node6 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -22971,12 +22971,12 @@ var require_dist_node6 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -22991,7 +22991,7 @@ var require_dist_node6 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -37670,14 +37670,14 @@ var require_typeGuards = __commonJS({ "node_modules/@azure/core-util/dist/commonjs/typeGuards.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isDefined = isDefined; + exports2.isDefined = isDefined2; exports2.isObjectWithProperties = isObjectWithProperties; exports2.objectHasProperty = objectHasProperty; - function isDefined(thing) { + function isDefined2(thing) { return typeof thing !== "undefined" && thing !== null; } function isObjectWithProperties(thing, properties) { - if (!isDefined(thing) || typeof thing !== "object") { + if (!isDefined2(thing) || typeof thing !== "object") { return false; } for (const property of properties) { @@ -37688,7 +37688,7 @@ var require_typeGuards = __commonJS({ return true; } function objectHasProperty(thing, property) { - return isDefined(thing) && typeof thing === "object" && property in thing; + return isDefined2(thing) && typeof thing === "object" && property in thing; } } }); @@ -85778,6 +85778,9 @@ async function asyncSome(array, predicate) { const results = await Promise.all(array.map(predicate)); return results.some((result) => result); } +function isDefined(value) { + return value !== void 0 && value !== null; +} // src/actions-util.ts var pkg = require_package(); @@ -86167,6 +86170,7 @@ async function parseAnalysisKinds(input) { new Set(components.map((component) => component)) ); } +var codeQualityQueries = ["code-quality"]; // src/feature-flags.ts var fs7 = __toESM(require("fs")); @@ -87578,6 +87582,9 @@ function dbLocationOrDefault(dbLocation, tempDir) { function userConfigFromActionPath(tempDir) { return path10.resolve(tempDir, "user-config-from-action.yml"); } +function hasQueryCustomisation(userConfig) { + return isDefined(userConfig["disable-default-queries"]) || isDefined(userConfig.queries) || isDefined(userConfig["query-filters"]); +} async function initConfig(inputs) { const { logger, tempDir } = inputs; if (inputs.configInput) { @@ -87603,6 +87610,17 @@ async function initConfig(inputs) { ); } const config = await initActionState(inputs, userConfig); + if (config.analysisKinds.length === 1 && isCodeQualityEnabled(config)) { + if (hasQueryCustomisation(config.computedConfig)) { + throw new ConfigurationError( + "Query customizations are unsupported, because only `code-quality` analysis is enabled." + ); + } + const queries = codeQualityQueries.map((v) => ({ uses: v })); + config.computedConfig["disable-default-queries"] = true; + config.computedConfig.queries = queries; + config.computedConfig["query-filters"] = []; + } const { overlayDatabaseMode, useOverlayDatabaseCaching } = await getOverlayDatabaseMode( inputs.codeql, inputs.repository, @@ -87836,6 +87854,9 @@ function appendExtraQueryExclusions(extraQueryExclusions, cliConfig) { } return augmentedConfig; } +function isCodeQualityEnabled(config) { + return config.analysisKinds.includes("code-quality" /* CodeQuality */); +} // src/dependency-caching.ts var os2 = __toESM(require("os")); diff --git a/lib/resolve-environment-action.js b/lib/resolve-environment-action.js index eb4c0b59f6..976a012f65 100644 --- a/lib/resolve-environment-action.js +++ b/lib/resolve-environment-action.js @@ -20288,7 +20288,7 @@ var require_dist_node2 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -20296,7 +20296,7 @@ var require_dist_node2 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -20308,14 +20308,14 @@ var require_dist_node2 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -20323,12 +20323,12 @@ var require_dist_node2 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -20343,7 +20343,7 @@ var require_dist_node2 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -21028,7 +21028,7 @@ var require_dist_node6 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -21036,7 +21036,7 @@ var require_dist_node6 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -21048,14 +21048,14 @@ var require_dist_node6 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -21063,12 +21063,12 @@ var require_dist_node6 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -21083,7 +21083,7 @@ var require_dist_node6 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -31821,14 +31821,14 @@ var require_typeGuards = __commonJS({ "node_modules/@azure/core-util/dist/commonjs/typeGuards.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isDefined = isDefined; + exports2.isDefined = isDefined2; exports2.isObjectWithProperties = isObjectWithProperties; exports2.objectHasProperty = objectHasProperty; - function isDefined(thing) { + function isDefined2(thing) { return typeof thing !== "undefined" && thing !== null; } function isObjectWithProperties(thing, properties) { - if (!isDefined(thing) || typeof thing !== "object") { + if (!isDefined2(thing) || typeof thing !== "object") { return false; } for (const property of properties) { @@ -31839,7 +31839,7 @@ var require_typeGuards = __commonJS({ return true; } function objectHasProperty(thing, property) { - return isDefined(thing) && typeof thing === "object" && property in thing; + return isDefined2(thing) && typeof thing === "object" && property in thing; } } }); diff --git a/lib/start-proxy-action-post.js b/lib/start-proxy-action-post.js index 5083c32fdd..b85291f996 100644 --- a/lib/start-proxy-action-post.js +++ b/lib/start-proxy-action-post.js @@ -20288,7 +20288,7 @@ var require_dist_node2 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -20296,7 +20296,7 @@ var require_dist_node2 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -20308,14 +20308,14 @@ var require_dist_node2 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -20323,12 +20323,12 @@ var require_dist_node2 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -20343,7 +20343,7 @@ var require_dist_node2 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -21028,7 +21028,7 @@ var require_dist_node6 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -21036,7 +21036,7 @@ var require_dist_node6 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -21048,14 +21048,14 @@ var require_dist_node6 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -21063,12 +21063,12 @@ var require_dist_node6 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -21083,7 +21083,7 @@ var require_dist_node6 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -31821,14 +31821,14 @@ var require_typeGuards = __commonJS({ "node_modules/@azure/core-util/dist/commonjs/typeGuards.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isDefined = isDefined; + exports2.isDefined = isDefined2; exports2.isObjectWithProperties = isObjectWithProperties; exports2.objectHasProperty = objectHasProperty; - function isDefined(thing) { + function isDefined2(thing) { return typeof thing !== "undefined" && thing !== null; } function isObjectWithProperties(thing, properties) { - if (!isDefined(thing) || typeof thing !== "object") { + if (!isDefined2(thing) || typeof thing !== "object") { return false; } for (const property of properties) { @@ -31839,7 +31839,7 @@ var require_typeGuards = __commonJS({ return true; } function objectHasProperty(thing, property) { - return isDefined(thing) && typeof thing === "object" && property in thing; + return isDefined2(thing) && typeof thing === "object" && property in thing; } } }); @@ -101570,7 +101570,7 @@ var require_dist_node16 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -101578,7 +101578,7 @@ var require_dist_node16 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -101588,12 +101588,12 @@ var require_dist_node16 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push(encodeValue(operator, value2, isKeyOperator(operator) ? key : "")); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -101601,12 +101601,12 @@ var require_dist_node16 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -101621,7 +101621,7 @@ var require_dist_node16 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { diff --git a/lib/start-proxy-action.js b/lib/start-proxy-action.js index 5881cacead..9670648c8e 100644 --- a/lib/start-proxy-action.js +++ b/lib/start-proxy-action.js @@ -47753,6 +47753,9 @@ async function delay(milliseconds, opts) { function getErrorMessage(error2) { return error2 instanceof Error ? error2.message : String(error2); } +function isDefined(value) { + return value !== void 0 && value !== null; +} // src/actions-util.ts var pkg = require_package(); @@ -47825,9 +47828,6 @@ var LANGUAGE_TO_REGISTRY_TYPE = { rust: "cargo_registry", go: "goproxy_server" }; -function isDefined(value) { - return value !== void 0 && value !== null; -} function getCredentials(logger, registrySecrets, registriesCredentials, languageString) { const language = languageString ? parseLanguage(languageString) : void 0; const registryTypeForLanguage = language ? LANGUAGE_TO_REGISTRY_TYPE[language] : void 0; diff --git a/lib/upload-lib.js b/lib/upload-lib.js index b23e8262ee..2483ea10e7 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -21585,7 +21585,7 @@ var require_dist_node2 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -21593,7 +21593,7 @@ var require_dist_node2 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -21605,14 +21605,14 @@ var require_dist_node2 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -21620,12 +21620,12 @@ var require_dist_node2 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -21640,7 +21640,7 @@ var require_dist_node2 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -22325,7 +22325,7 @@ var require_dist_node6 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -22333,7 +22333,7 @@ var require_dist_node6 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -22345,14 +22345,14 @@ var require_dist_node6 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -22360,12 +22360,12 @@ var require_dist_node6 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -22380,7 +22380,7 @@ var require_dist_node6 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -38967,14 +38967,14 @@ var require_typeGuards = __commonJS({ "node_modules/@azure/core-util/dist/commonjs/typeGuards.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isDefined = isDefined; + exports2.isDefined = isDefined2; exports2.isObjectWithProperties = isObjectWithProperties; exports2.objectHasProperty = objectHasProperty; - function isDefined(thing) { + function isDefined2(thing) { return typeof thing !== "undefined" && thing !== null; } function isObjectWithProperties(thing, properties) { - if (!isDefined(thing) || typeof thing !== "object") { + if (!isDefined2(thing) || typeof thing !== "object") { return false; } for (const property of properties) { @@ -38985,7 +38985,7 @@ var require_typeGuards = __commonJS({ return true; } function objectHasProperty(thing, property) { - return isDefined(thing) && typeof thing === "object" && property in thing; + return isDefined2(thing) && typeof thing === "object" && property in thing; } } }); @@ -84778,10 +84778,7 @@ var require_sarif_schema_2_1_0 = __commonJS({ // src/upload-lib.ts var upload_lib_exports = {}; __export(upload_lib_exports, { - CodeQualityTarget: () => CodeQualityTarget, - CodeScanningTarget: () => CodeScanningTarget, InvalidSarifUploadError: () => InvalidSarifUploadError, - SARIF_UPLOAD_ENDPOINT: () => SARIF_UPLOAD_ENDPOINT, buildPayload: () => buildPayload, findSarifFilesInDir: () => findSarifFilesInDir, getSarifFilePaths: () => getSarifFilePaths, @@ -92203,11 +92200,6 @@ function getAutomationID(category, analysis_key, environment) { } return computeAutomationID(analysis_key, environment); } -var SARIF_UPLOAD_ENDPOINT = /* @__PURE__ */ ((SARIF_UPLOAD_ENDPOINT2) => { - SARIF_UPLOAD_ENDPOINT2["CODE_SCANNING"] = "PUT /repos/:owner/:repo/code-scanning/analysis"; - SARIF_UPLOAD_ENDPOINT2["CODE_QUALITY"] = "PUT /repos/:owner/:repo/code-quality/analysis"; - return SARIF_UPLOAD_ENDPOINT2; -})(SARIF_UPLOAD_ENDPOINT || {}); async function uploadPayload(payload, repositoryNwo, logger, target) { logger.info("Uploading results"); if (isInTestMode()) { @@ -92376,18 +92368,6 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo } return payloadObj; } -var CodeScanningTarget = { - name: "code scanning", - target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, - sarifPredicate: (name) => name.endsWith(".sarif") && !CodeQualityTarget.sarifPredicate(name), - sentinelPrefix: "CODEQL_UPLOAD_SARIF_" -}; -var CodeQualityTarget = { - name: "code quality", - target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, - sarifPredicate: (name) => name.endsWith(".quality.sarif"), - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" -}; async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { const sarifPaths = getSarifFilePaths( inputSarifPath, @@ -92402,7 +92382,7 @@ async function uploadFiles(inputSarifPath, checkoutPath, category, features, log uploadTarget ); } -async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget = CodeScanningTarget) { +async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { logger.startGroup(`Uploading ${uploadTarget.name} results`); logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); @@ -92573,7 +92553,7 @@ function handleProcessingResultForUnsuccessfulExecution(response, status, logger assertNever(status); } } -function validateUniqueCategory(sarif, sentinelPrefix = CodeScanningTarget.sentinelPrefix) { +function validateUniqueCategory(sarif, sentinelPrefix) { const categories = {}; for (const run of sarif.runs) { const id = run?.automationDetails?.id; @@ -92630,10 +92610,7 @@ function filterAlertsByDiffRange(logger, sarif) { } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { - CodeQualityTarget, - CodeScanningTarget, InvalidSarifUploadError, - SARIF_UPLOAD_ENDPOINT, buildPayload, findSarifFilesInDir, getSarifFilePaths, diff --git a/lib/upload-sarif-action-post.js b/lib/upload-sarif-action-post.js index a704d103e7..503f515c31 100644 --- a/lib/upload-sarif-action-post.js +++ b/lib/upload-sarif-action-post.js @@ -20288,7 +20288,7 @@ var require_dist_node2 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -20296,7 +20296,7 @@ var require_dist_node2 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -20308,14 +20308,14 @@ var require_dist_node2 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -20323,12 +20323,12 @@ var require_dist_node2 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -20343,7 +20343,7 @@ var require_dist_node2 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -21028,7 +21028,7 @@ var require_dist_node6 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -21036,7 +21036,7 @@ var require_dist_node6 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -21048,14 +21048,14 @@ var require_dist_node6 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -21063,12 +21063,12 @@ var require_dist_node6 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -21083,7 +21083,7 @@ var require_dist_node6 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -35658,14 +35658,14 @@ var require_typeGuards = __commonJS({ "node_modules/@azure/core-util/dist/commonjs/typeGuards.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isDefined = isDefined; + exports2.isDefined = isDefined2; exports2.isObjectWithProperties = isObjectWithProperties; exports2.objectHasProperty = objectHasProperty; - function isDefined(thing) { + function isDefined2(thing) { return typeof thing !== "undefined" && thing !== null; } function isObjectWithProperties(thing, properties) { - if (!isDefined(thing) || typeof thing !== "object") { + if (!isDefined2(thing) || typeof thing !== "object") { return false; } for (const property of properties) { @@ -35676,7 +35676,7 @@ var require_typeGuards = __commonJS({ return true; } function objectHasProperty(thing, property) { - return isDefined(thing) && typeof thing === "object" && property in thing; + return isDefined2(thing) && typeof thing === "object" && property in thing; } } }); @@ -95692,7 +95692,7 @@ var require_dist_node16 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -95700,7 +95700,7 @@ var require_dist_node16 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -95710,12 +95710,12 @@ var require_dist_node16 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push(encodeValue(operator, value2, isKeyOperator(operator) ? key : "")); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -95723,12 +95723,12 @@ var require_dist_node16 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -95743,7 +95743,7 @@ var require_dist_node16 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 6665c2ac51..7fed9664be 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -20288,7 +20288,7 @@ var require_dist_node2 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -20296,7 +20296,7 @@ var require_dist_node2 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -20308,14 +20308,14 @@ var require_dist_node2 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -20323,12 +20323,12 @@ var require_dist_node2 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -20343,7 +20343,7 @@ var require_dist_node2 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -21028,7 +21028,7 @@ var require_dist_node6 = __commonJS({ return value; } } - function isDefined(value) { + function isDefined2(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { @@ -21036,7 +21036,7 @@ var require_dist_node6 = __commonJS({ } function getValues(context2, operator, key, modifier) { var value = context2[key], result = []; - if (isDefined(value) && value !== "") { + if (isDefined2(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { @@ -21048,14 +21048,14 @@ var require_dist_node6 = __commonJS({ } else { if (modifier === "*") { if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); @@ -21063,12 +21063,12 @@ var require_dist_node6 = __commonJS({ } else { const tmp = []; if (Array.isArray(value)) { - value.filter(isDefined).forEach(function(value2) { + value.filter(isDefined2).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { - if (isDefined(value[k])) { + if (isDefined2(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } @@ -21083,7 +21083,7 @@ var require_dist_node6 = __commonJS({ } } else { if (operator === ";") { - if (isDefined(value)) { + if (isDefined2(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { @@ -37670,14 +37670,14 @@ var require_typeGuards = __commonJS({ "node_modules/@azure/core-util/dist/commonjs/typeGuards.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isDefined = isDefined; + exports2.isDefined = isDefined2; exports2.isObjectWithProperties = isObjectWithProperties; exports2.objectHasProperty = objectHasProperty; - function isDefined(thing) { + function isDefined2(thing) { return typeof thing !== "undefined" && thing !== null; } function isObjectWithProperties(thing, properties) { - if (!isDefined(thing) || typeof thing !== "object") { + if (!isDefined2(thing) || typeof thing !== "object") { return false; } for (const property of properties) { @@ -37688,7 +37688,7 @@ var require_typeGuards = __commonJS({ return true; } function objectHasProperty(thing, property) { - return isDefined(thing) && typeof thing === "object" && property in thing; + return isDefined2(thing) && typeof thing === "object" && property in thing; } } }); @@ -88718,6 +88718,30 @@ function fixCodeQualityCategory(logger, category) { return category; } +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); +var CodeScanning = { + kind: "code-scanning" /* CodeScanning */, + name: "code scanning", + target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, + sarifExtension: ".sarif", + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name), + sentinelPrefix: "CODEQL_UPLOAD_SARIF_" +}; +var CodeQuality = { + kind: "code-quality" /* CodeQuality */, + name: "code quality", + target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, + sarifExtension: ".quality.sarif", + sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" +}; + // src/api-client.ts var core5 = __toESM(require_core()); var githubUtils = __toESM(require_utils4()); @@ -89585,14 +89609,6 @@ var fs8 = __toESM(require("fs")); var path10 = __toESM(require("path")); var semver4 = __toESM(require_semver2()); -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); - // src/caching-utils.ts var core8 = __toESM(require_core()); @@ -93053,18 +93069,6 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo } return payloadObj; } -var CodeScanningTarget = { - name: "code scanning", - target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, - sarifPredicate: (name) => name.endsWith(".sarif") && !CodeQualityTarget.sarifPredicate(name), - sentinelPrefix: "CODEQL_UPLOAD_SARIF_" -}; -var CodeQualityTarget = { - name: "code quality", - target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, - sarifPredicate: (name) => name.endsWith(".quality.sarif"), - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" -}; async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger, uploadTarget) { const sarifPaths = getSarifFilePaths( inputSarifPath, @@ -93079,7 +93083,7 @@ async function uploadFiles(inputSarifPath, checkoutPath, category, features, log uploadTarget ); } -async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget = CodeScanningTarget) { +async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger, uploadTarget) { logger.startGroup(`Uploading ${uploadTarget.name} results`); logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); const gitHubVersion = await getGitHubVersion(); @@ -93250,7 +93254,7 @@ function handleProcessingResultForUnsuccessfulExecution(response, status, logger assertNever(status); } } -function validateUniqueCategory(sarif, sentinelPrefix = CodeScanningTarget.sentinelPrefix) { +function validateUniqueCategory(sarif, sentinelPrefix) { const categories = {}; for (const run2 of sarif.runs) { const id = run2?.automationDetails?.id; @@ -93359,13 +93363,13 @@ async function run() { category, features, logger, - CodeScanningTarget + CodeScanning ); core13.setOutput("sarif-id", uploadResult.sarifID); if (fs15.lstatSync(sarifPath).isDirectory()) { const qualitySarifFiles = findSarifFilesInDir( sarifPath, - CodeQualityTarget.sarifPredicate + CodeQuality.sarifPredicate ); if (qualitySarifFiles.length !== 0) { await uploadSpecifiedFiles( @@ -93374,7 +93378,7 @@ async function run() { fixCodeQualityCategory(logger, category), features, logger, - CodeQualityTarget + CodeQuality ); } } diff --git a/pr-checks/checks/quality-queries.yml b/pr-checks/checks/quality-queries.yml index 6cf07e2474..9eb578171e 100644 --- a/pr-checks/checks/quality-queries.yml +++ b/pr-checks/checks/quality-queries.yml @@ -1,6 +1,7 @@ name: "Quality queries input" description: "Tests that queries specified in the quality-queries input are used." versions: ["linked", "nightly-latest"] +analysisKinds: ["code-scanning", "code-quality", "code-scanning,code-quality"] env: CHECK_SCRIPT: | const fs = require('fs'); @@ -29,25 +30,30 @@ steps: - uses: ./../action/init with: languages: javascript - quality-queries: code-quality + analysis-kinds: ${{ matrix.analysis-kinds }} tools: ${{ steps.prepare-test.outputs.tools-url }} - uses: ./../action/analyze with: output: "${{ runner.temp }}/results" upload-database: false - name: Upload security SARIF + if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/upload-artifact@v4 with: - name: quality-queries-${{ matrix.os }}-${{ matrix.version }}.sarif.json + name: | + quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json path: "${{ runner.temp }}/results/javascript.sarif" retention-days: 7 - name: Upload quality SARIF + if: contains(matrix.analysis-kinds, 'code-quality') uses: actions/upload-artifact@v4 with: - name: quality-queries-${{ matrix.os }}-${{ matrix.version }}.quality.sarif.json + name: | + quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json path: "${{ runner.temp }}/results/javascript.quality.sarif" retention-days: 7 - name: Check quality query does not appear in security SARIF + if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/github-script@v7 env: SARIF_PATH: "${{ runner.temp }}/results/javascript.sarif" @@ -55,6 +61,7 @@ steps: with: script: ${{ env.CHECK_SCRIPT }} - name: Check quality query appears in quality SARIF + if: contains(matrix.analysis-kinds, 'code-quality') uses: actions/github-script@v7 env: SARIF_PATH: "${{ runner.temp }}/results/javascript.quality.sarif" diff --git a/pr-checks/checks/upload-quality-sarif.yml b/pr-checks/checks/upload-quality-sarif.yml index 019654fa6e..02d2cc5636 100644 --- a/pr-checks/checks/upload-quality-sarif.yml +++ b/pr-checks/checks/upload-quality-sarif.yml @@ -8,7 +8,7 @@ steps: tools: ${{ steps.prepare-test.outputs.tools-url }} languages: cpp,csharp,java,javascript,python config-file: ${{ github.repository }}/tests/multi-language-repo/.github/codeql/custom-queries.yml@${{ github.sha }} - quality-queries: code-quality + analysis-kinds: code-scanning,code-quality - name: Build code shell: bash run: ./build.sh diff --git a/pr-checks/sync.py b/pr-checks/sync.py index beaa943985..6d23cafab5 100755 --- a/pr-checks/sync.py +++ b/pr-checks/sync.py @@ -102,6 +102,18 @@ def writeHeader(checkStream): if checkSpecification.get('useAllPlatformBundle'): useAllPlatformBundle = checkSpecification['useAllPlatformBundle'] + + if 'analysisKinds' in checkSpecification: + newMatrix = [] + for matrixInclude in matrix: + for analysisKind in checkSpecification.get('analysisKinds'): + newMatrix.append( + matrixInclude | + { 'analysis-kinds': analysisKind } + ) + matrix = newMatrix + + # Construct the workflow steps needed for this check. steps = [ { 'name': 'Check out repository', diff --git a/src/analyses.ts b/src/analyses.ts index e80cdfb20e..8d8cd1d616 100644 --- a/src/analyses.ts +++ b/src/analyses.ts @@ -41,3 +41,48 @@ export async function parseAnalysisKinds( /** The queries to use for Code Quality analyses. */ export const codeQualityQueries: string[] = ["code-quality"]; + +// Enumerates API endpoints that accept SARIF files. +export enum SARIF_UPLOAD_ENDPOINT { + CODE_SCANNING = "PUT /repos/:owner/:repo/code-scanning/analysis", + CODE_QUALITY = "PUT /repos/:owner/:repo/code-quality/analysis", +} + +// Represents configurations for different analysis kinds. +export interface AnalysisConfig { + /** The analysis kind the configuration is for. */ + kind: AnalysisKind; + /** A display friendly name for logs. */ + name: string; + /** The API endpoint to upload SARIF files to. */ + target: SARIF_UPLOAD_ENDPOINT; + /** The file extension for SARIF files generated by this kind of analysis. */ + sarifExtension: string; + /** A predicate on filenames to decide whether a SARIF file + * belongs to this kind of analysis. */ + sarifPredicate: (name: string) => boolean; + /** A prefix for environment variables used to track the uniqueness of SARIF uploads. */ + sentinelPrefix: string; +} + +// Represents the Code Scanning analysis configuration. +export const CodeScanning: AnalysisConfig = { + kind: AnalysisKind.CodeScanning, + name: "code scanning", + target: SARIF_UPLOAD_ENDPOINT.CODE_SCANNING, + sarifExtension: ".sarif", + sarifPredicate: (name) => + name.endsWith(CodeScanning.sarifExtension) && + !CodeQuality.sarifPredicate(name), + sentinelPrefix: "CODEQL_UPLOAD_SARIF_", +}; + +// Represents the Code Quality analysis configuration. +export const CodeQuality: AnalysisConfig = { + kind: AnalysisKind.CodeQuality, + name: "code quality", + target: SARIF_UPLOAD_ENDPOINT.CODE_QUALITY, + sarifExtension: ".quality.sarif", + sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", +}; diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 87af6fcca7..f93072d723 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -5,6 +5,7 @@ import { performance } from "perf_hooks"; import * as core from "@actions/core"; import * as actionsUtil from "./actions-util"; +import * as analyses from "./analyses"; import { CodeQLAnalysisError, dbIsFinalized, @@ -18,7 +19,12 @@ import { getApiDetails, getGitHubVersion } from "./api-client"; import { runAutobuild } from "./autobuild"; import { getTotalCacheSize, shouldStoreCache } from "./caching-utils"; import { getCodeQL } from "./codeql"; -import { Config, getConfig, isCodeQualityEnabled } from "./config-utils"; +import { + Config, + getConfig, + isCodeQualityEnabled, + isCodeScanningEnabled, +} from "./config-utils"; import { uploadDatabases } from "./database-upload"; import { uploadDependencyCaches } from "./dependency-caching"; import { getDiffInformedAnalysisBranches } from "./diff-informed-analysis-utils"; @@ -326,15 +332,17 @@ async function run() { core.setOutput("sarif-output", path.resolve(outputDir)); const uploadInput = actionsUtil.getOptionalInput("upload"); if (runStats && actionsUtil.getUploadValue(uploadInput) === "always") { - uploadResult = await uploadLib.uploadFiles( - outputDir, - actionsUtil.getRequiredInput("checkout_path"), - actionsUtil.getOptionalInput("category"), - features, - logger, - uploadLib.CodeScanningTarget, - ); - core.setOutput("sarif-id", uploadResult.sarifID); + if (isCodeScanningEnabled(config)) { + uploadResult = await uploadLib.uploadFiles( + outputDir, + actionsUtil.getRequiredInput("checkout_path"), + actionsUtil.getOptionalInput("category"), + features, + logger, + analyses.CodeScanning, + ); + core.setOutput("sarif-id", uploadResult.sarifID); + } if (isCodeQualityEnabled(config)) { const qualityUploadResult = await uploadLib.uploadFiles( @@ -346,7 +354,7 @@ async function run() { ), features, logger, - uploadLib.CodeQualityTarget, + analyses.CodeQuality, ); core.setOutput("quality-sarif-id", qualityUploadResult.sarifID); } diff --git a/src/analyze.test.ts b/src/analyze.test.ts index e957b73843..305d41d241 100644 --- a/src/analyze.test.ts +++ b/src/analyze.test.ts @@ -5,11 +5,13 @@ import test from "ava"; import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; +import { CodeQuality, CodeScanning } from "./analyses"; import { exportedForTesting, runQueries, defaultSuites, resolveQuerySuiteAlias, + addSarifExtension, } from "./analyze"; import { createStubCodeQL } from "./codeql"; import { Feature } from "./feature-flags"; @@ -348,3 +350,13 @@ test("resolveQuerySuiteAlias", (t) => { t.deepEqual(resolveQuerySuiteAlias(KnownLanguage.go, name), name); } }); + +test("addSarifExtension", (t) => { + for (const language of Object.values(KnownLanguage)) { + t.deepEqual(addSarifExtension(CodeScanning, language), `${language}.sarif`); + t.deepEqual( + addSarifExtension(CodeQuality, language), + `${language}.quality.sarif`, + ); + } +}); diff --git a/src/analyze.ts b/src/analyze.ts index a8ab5ca91d..153b00a1f4 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -608,6 +608,16 @@ export function resolveQuerySuiteAlias( return maybeSuite; } +/** + * Adds the appropriate file extension for the given analysis configuration to the given base filename. + */ +export function addSarifExtension( + analysis: analyses.AnalysisConfig, + base: string, +): string { + return `${base}${analysis.sarifExtension}`; +} + // Runs queries and creates sarif files in the given folder export async function runQueries( sarifFolder: string, @@ -650,15 +660,25 @@ export async function runQueries( ? `--sarif-run-property=incrementalMode=${incrementalMode.join(",")}` : undefined; + const dbAnalysisConfig = configUtils.getPrimaryAnalysisConfig(config); + for (const language of config.languages) { try { - const sarifFile = path.join(sarifFolder, `${language}.sarif`); - + // This should be empty to run only the query suite that was generated when + // the database was initialised. const queries: string[] = []; - if (configUtils.isCodeQualityEnabled(config)) { + + // If multiple analysis kinds are enabled, the database is initialised for Code Scanning. + // To avoid duplicate work, we want to run queries for all analyses at the same time. + // To do this, we invoke `run-queries` once with the generated query suite that was created + // when the database was initialised + the queries for other analysis kinds. + if (config.analysisKinds.length > 1) { queries.push(util.getGeneratedSuitePath(config, language)); - for (const qualityQuery of analyses.codeQualityQueries) { - queries.push(resolveQuerySuiteAlias(language, qualityQuery)); + + if (configUtils.isCodeQualityEnabled(config)) { + for (const qualityQuery of analyses.codeQualityQueries) { + queries.push(resolveQuerySuiteAlias(language, qualityQuery)); + } } } @@ -676,48 +696,49 @@ export async function runQueries( statusReport[`analyze_builtin_queries_${language}_duration_ms`] = new Date().getTime() - startTimeRunQueries; - logger.startGroup(`Interpreting results for ${language}`); + // There is always at least one analysis kind enabled. Running `interpret-results` + // produces the SARIF file for the analysis kind that the database was initialised with. const startTimeInterpretResults = new Date(); - const analysisSummary = await runInterpretResults( - language, - undefined, - sarifFile, - config.debugMode, - automationDetailsId, - ); + const { summary: analysisSummary, sarifFile } = + await runInterpretResultsFor( + dbAnalysisConfig, + language, + undefined, + config.debugMode, + ); + // This case is only needed if Code Quality is not the sole analysis kind. + // In this case, we will have run queries for all analysis kinds. The previous call to + // `interpret-results` will have produced a SARIF file for Code Scanning and we now + // need to produce an additional SARIF file for Code Quality. let qualityAnalysisSummary: string | undefined; - if (configUtils.isCodeQualityEnabled(config)) { - logger.info(`Interpreting quality results for ${language}`); - const qualityCategory = fixCodeQualityCategory( - logger, - automationDetailsId, - ); - const qualitySarifFile = path.join( - sarifFolder, - `${language}.quality.sarif`, - ); - qualityAnalysisSummary = await runInterpretResults( + if ( + config.analysisKinds.length > 1 && + configUtils.isCodeQualityEnabled(config) + ) { + const qualityResult = await runInterpretResultsFor( + analyses.CodeQuality, language, analyses.codeQualityQueries.map((i) => resolveQuerySuiteAlias(language, i), ), - qualitySarifFile, config.debugMode, - qualityCategory, ); + qualityAnalysisSummary = qualityResult.summary; } const endTimeInterpretResults = new Date(); statusReport[`interpret_results_${language}_duration_ms`] = endTimeInterpretResults.getTime() - startTimeInterpretResults.getTime(); logger.endGroup(); - logger.info(analysisSummary); + logger.info(analysisSummary); if (qualityAnalysisSummary) { logger.info(qualityAnalysisSummary); } if (await features.getValue(Feature.QaTelemetryEnabled)) { + // Note: QA adds the `code-quality` query suite to the `queries` input, + // so this is fine since there is no `.quality.sarif`. const perQueryAlertCounts = getPerQueryAlertCounts(sarifFile); const perQueryAlertCountEventReport: EventReport = { @@ -748,6 +769,37 @@ export async function runQueries( return statusReport; + async function runInterpretResultsFor( + analysis: analyses.AnalysisConfig, + language: Language, + queries: string[] | undefined, + enableDebugLogging: boolean, + ): Promise<{ summary: string; sarifFile: string }> { + logger.info(`Interpreting ${analysis.name} results for ${language}`); + + // If this is a Code Quality analysis, correct the category to one + // accepted by the Code Quality backend. + let category = automationDetailsId; + if (dbAnalysisConfig.kind === analyses.AnalysisKind.CodeQuality) { + category = fixCodeQualityCategory(logger, automationDetailsId); + } + + const sarifFile = path.join( + sarifFolder, + addSarifExtension(analysis, language), + ); + + const summary = await runInterpretResults( + language, + queries, + sarifFile, + enableDebugLogging, + category, + ); + + return { summary, sarifFile }; + } + async function runInterpretResults( language: Language, queries: string[] | undefined, diff --git a/src/config-utils.test.ts b/src/config-utils.test.ts index c78ba6a33d..9526a4b8a9 100644 --- a/src/config-utils.test.ts +++ b/src/config-utils.test.ts @@ -171,6 +171,63 @@ test("load empty config", async (t) => { }); }); +test("load code quality config", async (t) => { + return await withTmpDir(async (tempDir) => { + const logger = getRunnerLogger(true); + const languages = "actions"; + + const codeql = createStubCodeQL({ + async betterResolveLanguages() { + return { + extractors: { + actions: [{ extractor_root: "" }], + }, + }; + }, + }); + + const config = await configUtils.initConfig( + createTestInitConfigInputs({ + analysisKindsInput: "code-quality", + languagesInput: languages, + repository: { owner: "github", repo: "example" }, + tempDir, + codeql, + logger, + }), + ); + + // And the config we expect it to result in + const expectedConfig: configUtils.Config = { + analysisKinds: [AnalysisKind.CodeQuality], + languages: [KnownLanguage.actions], + buildMode: undefined, + originalUserInput: {}, + // This gets set because we only have `AnalysisKind.CodeQuality` + computedConfig: { + "disable-default-queries": true, + queries: [{ uses: "code-quality" }], + "query-filters": [], + }, + tempDir, + codeQLCmd: codeql.getPath(), + gitHubVersion: githubVersion, + dbLocation: path.resolve(tempDir, "codeql_databases"), + debugMode: false, + debugArtifactName: "", + debugDatabaseName: "", + trapCaches: {}, + trapCacheDownloadTime: 0, + dependencyCachingEnabled: CachingKind.None, + extraQueryExclusions: [], + overlayDatabaseMode: OverlayDatabaseMode.None, + useOverlayDatabaseCaching: false, + }; + + t.deepEqual(config, expectedConfig); + }); +}); + test("loading config saves config", async (t) => { return await withTmpDir(async (tempDir) => { const logger = getRunnerLogger(true); diff --git a/src/config-utils.ts b/src/config-utils.ts index 66e50e74d0..16144398f3 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -6,7 +6,14 @@ import * as yaml from "js-yaml"; import * as semver from "semver"; import { isAnalyzingPullRequest } from "./actions-util"; -import { AnalysisKind, parseAnalysisKinds } from "./analyses"; +import { + AnalysisConfig, + AnalysisKind, + CodeQuality, + codeQualityQueries, + CodeScanning, + parseAnalysisKinds, +} from "./analyses"; import * as api from "./api-client"; import { CachingKind, getCachingKind } from "./caching-utils"; import { type CodeQL } from "./codeql"; @@ -28,6 +35,7 @@ import { BuildMode, codeQlVersionAtLeast, cloneObject, + isDefined, } from "./util"; // Property names from the user-supplied config file. @@ -1074,6 +1082,19 @@ function userConfigFromActionPath(tempDir: string): string { return path.resolve(tempDir, "user-config-from-action.yml"); } +/** + * Checks whether the given `UserConfig` contains any query customisations. + * + * @returns Returns `true` if the `UserConfig` customises which queries are run. + */ +function hasQueryCustomisation(userConfig: UserConfig): boolean { + return ( + isDefined(userConfig["disable-default-queries"]) || + isDefined(userConfig.queries) || + isDefined(userConfig["query-filters"]) + ); +} + /** * Load and return the config. * @@ -1110,6 +1131,25 @@ export async function initConfig(inputs: InitConfigInputs): Promise { const config = await initActionState(inputs, userConfig); + // If Code Quality analysis is the only enabled analysis kind, then we will initialise + // the database for Code Quality. That entails disabling the default queries and only + // running quality queries. We do not currently support query customisations in that case. + if (config.analysisKinds.length === 1 && isCodeQualityEnabled(config)) { + // Warn if any query customisations are present in the computed configuration. + if (hasQueryCustomisation(config.computedConfig)) { + throw new ConfigurationError( + "Query customizations are unsupported, because only `code-quality` analysis is enabled.", + ); + } + + const queries = codeQualityQueries.map((v) => ({ uses: v })); + + // Set the query customisation options for Code Quality only analysis. + config.computedConfig["disable-default-queries"] = true; + config.computedConfig.queries = queries; + config.computedConfig["query-filters"] = []; + } + // The choice of overlay database mode depends on the selection of languages // and queries, which in turn depends on the user config and the augmentation // properties. So we need to calculate the overlay database mode after the @@ -1509,9 +1549,41 @@ export function appendExtraQueryExclusions( return augmentedConfig; } +/** + * Returns `true` if Code Scanning analysis is enabled, or `false` if not. + */ +export function isCodeScanningEnabled(config: Config): boolean { + return config.analysisKinds.includes(AnalysisKind.CodeScanning); +} + /** * Returns `true` if Code Quality analysis is enabled, or `false` if not. */ export function isCodeQualityEnabled(config: Config): boolean { return config.analysisKinds.includes(AnalysisKind.CodeQuality); } + +/** + * Returns the primary analysis kind that the Action is initialised with. This is + * always `AnalysisKind.CodeScanning` unless `AnalysisKind.CodeScanning` is not enabled. + * + * @returns Returns `AnalysisKind.CodeScanning` if `AnalysisKind.CodeScanning` is enabled; + * otherwise `AnalysisKind.CodeQuality`. + */ +export function getPrimaryAnalysisKind(config: Config): AnalysisKind { + return isCodeScanningEnabled(config) + ? AnalysisKind.CodeScanning + : AnalysisKind.CodeQuality; +} + +/** + * Returns the primary analysis configuration that the Action is initialised with. This is + * always `CodeScanning` unless `CodeScanning` is not enabled. + * + * @returns Returns `CodeScanning` if `AnalysisKind.CodeScanning` is enabled; otherwise `CodeQuality`. + */ +export function getPrimaryAnalysisConfig(config: Config): AnalysisConfig { + return getPrimaryAnalysisKind(config) === AnalysisKind.CodeScanning + ? CodeScanning + : CodeQuality; +} diff --git a/src/init-action-post-helper.ts b/src/init-action-post-helper.ts index b04e62c290..0d21bd3b66 100644 --- a/src/init-action-post-helper.ts +++ b/src/init-action-post-helper.ts @@ -4,6 +4,7 @@ import * as core from "@actions/core"; import * as github from "@actions/github"; import * as actionsUtil from "./actions-util"; +import { CodeScanning } from "./analyses"; import { getApiClient } from "./api-client"; import { CodeQL, getCodeQL } from "./codeql"; import { Config } from "./config-utils"; @@ -104,7 +105,7 @@ async function maybeUploadFailedSarif( category, features, logger, - uploadLib.CodeScanningTarget, + CodeScanning, ); await uploadLib.waitForProcessing( repositoryNwo, diff --git a/src/start-proxy.ts b/src/start-proxy.ts index d74884bfd4..08da182918 100644 --- a/src/start-proxy.ts +++ b/src/start-proxy.ts @@ -2,7 +2,7 @@ import * as core from "@actions/core"; import { KnownLanguage } from "./languages"; import { Logger } from "./logging"; -import { ConfigurationError } from "./util"; +import { ConfigurationError, isDefined } from "./util"; export type Credential = { type: string; @@ -65,15 +65,6 @@ const LANGUAGE_TO_REGISTRY_TYPE: Partial> = { go: "goproxy_server", } as const; -/** - * Checks that `value` is neither `undefined` nor `null`. - * @param value The value to test. - * @returns Narrows the type of `value` to exclude `undefined` and `null`. - */ -function isDefined(value: T | null | undefined): value is T { - return value !== undefined && value !== null; -} - // getCredentials returns registry credentials from action inputs. // It prefers `registries_credentials` over `registry_secrets`. // If neither is set, it returns an empty array. diff --git a/src/upload-lib.test.ts b/src/upload-lib.test.ts index 96f132b210..bfa5e9844c 100644 --- a/src/upload-lib.test.ts +++ b/src/upload-lib.test.ts @@ -3,6 +3,7 @@ import * as path from "path"; import test from "ava"; +import { CodeQuality, CodeScanning } from "./analyses"; import { getRunnerLogger, Logger } from "./logging"; import { setupTests } from "./testing-utils"; import * as uploadLib from "./upload-lib"; @@ -128,7 +129,7 @@ test("finding SARIF files", async (t) => { const sarifFiles = uploadLib.findSarifFilesInDir( tmpDir, - uploadLib.CodeScanningTarget.sarifPredicate, + CodeScanning.sarifPredicate, ); t.deepEqual(sarifFiles, [ @@ -140,7 +141,7 @@ test("finding SARIF files", async (t) => { const qualitySarifFiles = uploadLib.findSarifFilesInDir( tmpDir, - uploadLib.CodeQualityTarget.sarifPredicate, + CodeQuality.sarifPredicate, ); t.deepEqual(qualitySarifFiles, [ @@ -211,109 +212,237 @@ test("populateRunAutomationDetails", (t) => { }); test("validateUniqueCategory when empty", (t) => { - t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif())); - t.throws(() => uploadLib.validateUniqueCategory(createMockSarif())); + t.notThrows(() => + uploadLib.validateUniqueCategory( + createMockSarif(), + CodeScanning.sentinelPrefix, + ), + ); + t.throws(() => + uploadLib.validateUniqueCategory( + createMockSarif(), + CodeScanning.sentinelPrefix, + ), + ); }); test("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("abc"), + CodeScanning.sentinelPrefix, + ), + ); + t.throws(() => + uploadLib.validateUniqueCategory( + createMockSarif("abc"), + CodeScanning.sentinelPrefix, + ), + ); + t.throws(() => + uploadLib.validateUniqueCategory( + createMockSarif("AbC"), + CodeScanning.sentinelPrefix, + ), + ); - t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif("def"))); - t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("def"))); + t.notThrows(() => + uploadLib.validateUniqueCategory( + createMockSarif("def"), + CodeScanning.sentinelPrefix, + ), + ); + t.throws(() => + uploadLib.validateUniqueCategory( + createMockSarif("def"), + CodeScanning.sentinelPrefix, + ), + ); // Our category sanitization is not perfect. Here are some examples // of where we see false clashes t.notThrows(() => - uploadLib.validateUniqueCategory(createMockSarif("abc/def")), + uploadLib.validateUniqueCategory( + createMockSarif("abc/def"), + CodeScanning.sentinelPrefix, + ), + ); + t.throws(() => + uploadLib.validateUniqueCategory( + createMockSarif("abc@def"), + CodeScanning.sentinelPrefix, + ), + ); + t.throws(() => + uploadLib.validateUniqueCategory( + createMockSarif("abc_def"), + CodeScanning.sentinelPrefix, + ), + ); + t.throws(() => + uploadLib.validateUniqueCategory( + createMockSarif("abc def"), + CodeScanning.sentinelPrefix, + ), ); - 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")), + uploadLib.validateUniqueCategory( + createMockSarif("abc_ def"), + CodeScanning.sentinelPrefix, + ), ); }); test("validateUniqueCategory for tool name", (t) => { t.notThrows(() => - uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc")), + uploadLib.validateUniqueCategory( + createMockSarif(undefined, "abc"), + CodeScanning.sentinelPrefix, + ), ); t.throws(() => - uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc")), + uploadLib.validateUniqueCategory( + createMockSarif(undefined, "abc"), + CodeScanning.sentinelPrefix, + ), ); t.throws(() => - uploadLib.validateUniqueCategory(createMockSarif(undefined, "AbC")), + uploadLib.validateUniqueCategory( + createMockSarif(undefined, "AbC"), + CodeScanning.sentinelPrefix, + ), ); t.notThrows(() => - uploadLib.validateUniqueCategory(createMockSarif(undefined, "def")), + uploadLib.validateUniqueCategory( + createMockSarif(undefined, "def"), + CodeScanning.sentinelPrefix, + ), ); t.throws(() => - uploadLib.validateUniqueCategory(createMockSarif(undefined, "def")), + uploadLib.validateUniqueCategory( + createMockSarif(undefined, "def"), + CodeScanning.sentinelPrefix, + ), ); // Our category sanitization is not perfect. Here are some examples // of where we see false clashes t.notThrows(() => - uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc/def")), + uploadLib.validateUniqueCategory( + createMockSarif(undefined, "abc/def"), + CodeScanning.sentinelPrefix, + ), ); t.throws(() => - uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc@def")), + uploadLib.validateUniqueCategory( + createMockSarif(undefined, "abc@def"), + CodeScanning.sentinelPrefix, + ), ); t.throws(() => - uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc_def")), + uploadLib.validateUniqueCategory( + createMockSarif(undefined, "abc_def"), + CodeScanning.sentinelPrefix, + ), ); t.throws(() => - uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc def")), + uploadLib.validateUniqueCategory( + createMockSarif(undefined, "abc def"), + CodeScanning.sentinelPrefix, + ), ); // this one is fine t.notThrows(() => - uploadLib.validateUniqueCategory(createMockSarif("abc_ def")), + uploadLib.validateUniqueCategory( + createMockSarif("abc_ def"), + CodeScanning.sentinelPrefix, + ), ); }); test("validateUniqueCategory for automation details id and tool name", (t) => { t.notThrows(() => - uploadLib.validateUniqueCategory(createMockSarif("abc", "abc")), + uploadLib.validateUniqueCategory( + createMockSarif("abc", "abc"), + CodeScanning.sentinelPrefix, + ), ); t.throws(() => - uploadLib.validateUniqueCategory(createMockSarif("abc", "abc")), + uploadLib.validateUniqueCategory( + createMockSarif("abc", "abc"), + CodeScanning.sentinelPrefix, + ), ); t.notThrows(() => - uploadLib.validateUniqueCategory(createMockSarif("abc_", "def")), + uploadLib.validateUniqueCategory( + createMockSarif("abc_", "def"), + CodeScanning.sentinelPrefix, + ), ); t.throws(() => - uploadLib.validateUniqueCategory(createMockSarif("abc_", "def")), + uploadLib.validateUniqueCategory( + createMockSarif("abc_", "def"), + CodeScanning.sentinelPrefix, + ), ); t.notThrows(() => - uploadLib.validateUniqueCategory(createMockSarif("ghi", "_jkl")), + uploadLib.validateUniqueCategory( + createMockSarif("ghi", "_jkl"), + CodeScanning.sentinelPrefix, + ), ); t.throws(() => - uploadLib.validateUniqueCategory(createMockSarif("ghi", "_jkl")), + uploadLib.validateUniqueCategory( + createMockSarif("ghi", "_jkl"), + CodeScanning.sentinelPrefix, + ), ); // 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"), + CodeScanning.sentinelPrefix, + ), + ); + t.throws(() => + uploadLib.validateUniqueCategory( + createMockSarif("abc", "_"), + CodeScanning.sentinelPrefix, + ), + ); t.notThrows(() => - uploadLib.validateUniqueCategory(createMockSarif("abc", "def__")), + uploadLib.validateUniqueCategory( + createMockSarif("abc", "def__"), + CodeScanning.sentinelPrefix, + ), + ); + t.throws(() => + uploadLib.validateUniqueCategory( + createMockSarif("abc_def"), + CodeScanning.sentinelPrefix, + ), ); - t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc_def"))); t.notThrows(() => - uploadLib.validateUniqueCategory(createMockSarif("mno_", "pqr")), + uploadLib.validateUniqueCategory( + createMockSarif("mno_", "pqr"), + CodeScanning.sentinelPrefix, + ), ); t.throws(() => - uploadLib.validateUniqueCategory(createMockSarif("mno", "_pqr")), + uploadLib.validateUniqueCategory( + createMockSarif("mno", "_pqr"), + CodeScanning.sentinelPrefix, + ), ); }); @@ -323,19 +452,30 @@ test("validateUniqueCategory for multiple runs", (t) => { // duplicate categories are allowed within the same sarif file const multiSarif = { runs: [sarif1.runs[0], sarif1.runs[0], sarif2.runs[0]] }; - t.notThrows(() => uploadLib.validateUniqueCategory(multiSarif)); + t.notThrows(() => + uploadLib.validateUniqueCategory(multiSarif, CodeScanning.sentinelPrefix), + ); // should throw if there are duplicate categories in separate validations - t.throws(() => uploadLib.validateUniqueCategory(sarif1)); - t.throws(() => uploadLib.validateUniqueCategory(sarif2)); + t.throws(() => + uploadLib.validateUniqueCategory(sarif1, CodeScanning.sentinelPrefix), + ); + t.throws(() => + uploadLib.validateUniqueCategory(sarif2, CodeScanning.sentinelPrefix), + ); }); test("validateUniqueCategory with different prefixes", (t) => { - t.notThrows(() => uploadLib.validateUniqueCategory(createMockSarif())); t.notThrows(() => uploadLib.validateUniqueCategory( createMockSarif(), - uploadLib.CodeQualityTarget.sentinelPrefix, + CodeScanning.sentinelPrefix, + ), + ); + t.notThrows(() => + uploadLib.validateUniqueCategory( + createMockSarif(), + CodeQuality.sentinelPrefix, ), ); }); diff --git a/src/upload-lib.ts b/src/upload-lib.ts index e87dad839f..8939e16944 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -8,6 +8,7 @@ import { OctokitResponse } from "@octokit/types"; import * as jsonschema from "jsonschema"; import * as actionsUtil from "./actions-util"; +import * as analyses from "./analyses"; import * as api from "./api-client"; import { getGitHubVersion, wrapApiConfigurationError } from "./api-client"; import { CodeQL, getCodeQL } from "./codeql"; @@ -345,19 +346,13 @@ function getAutomationID( return api.computeAutomationID(analysis_key, environment); } -// Enumerates API endpoints that accept SARIF files. -export enum SARIF_UPLOAD_ENDPOINT { - CODE_SCANNING = "PUT /repos/:owner/:repo/code-scanning/analysis", - CODE_QUALITY = "PUT /repos/:owner/:repo/code-quality/analysis", -} - // Upload the given payload. // If the request fails then this will retry a small number of times. async function uploadPayload( payload: any, repositoryNwo: RepositoryNwo, logger: Logger, - target: SARIF_UPLOAD_ENDPOINT, + target: analyses.SARIF_UPLOAD_ENDPOINT, ): Promise { logger.info("Uploading results"); @@ -616,31 +611,6 @@ export function buildPayload( return payloadObj; } -// Represents configurations for different services that we can upload SARIF to. -export interface UploadTarget { - name: string; - target: SARIF_UPLOAD_ENDPOINT; - sarifPredicate: (name: string) => boolean; - sentinelPrefix: string; -} - -// Represents the Code Scanning upload target. -export const CodeScanningTarget: UploadTarget = { - name: "code scanning", - target: SARIF_UPLOAD_ENDPOINT.CODE_SCANNING, - sarifPredicate: (name) => - name.endsWith(".sarif") && !CodeQualityTarget.sarifPredicate(name), - sentinelPrefix: "CODEQL_UPLOAD_SARIF_", -}; - -// Represents the Code Quality upload target. -export const CodeQualityTarget: UploadTarget = { - name: "code quality", - target: SARIF_UPLOAD_ENDPOINT.CODE_QUALITY, - sarifPredicate: (name) => name.endsWith(".quality.sarif"), - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", -}; - /** * Uploads a single SARIF file or a directory of SARIF files depending on what `inputSarifPath` refers * to. @@ -651,7 +621,7 @@ export async function uploadFiles( category: string | undefined, features: FeatureEnablement, logger: Logger, - uploadTarget: UploadTarget, + uploadTarget: analyses.AnalysisConfig, ): Promise { const sarifPaths = getSarifFilePaths( inputSarifPath, @@ -677,7 +647,7 @@ export async function uploadSpecifiedFiles( category: string | undefined, features: FeatureEnablement, logger: Logger, - uploadTarget: UploadTarget = CodeScanningTarget, + uploadTarget: analyses.AnalysisConfig, ): Promise { logger.startGroup(`Uploading ${uploadTarget.name} results`); logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`); @@ -943,7 +913,7 @@ function handleProcessingResultForUnsuccessfulExecution( export function validateUniqueCategory( sarif: SarifFile, - sentinelPrefix: string = CodeScanningTarget.sentinelPrefix, + sentinelPrefix: string, ): void { // duplicate categories are allowed in the same sarif file // but not across multiple sarif files diff --git a/src/upload-sarif-action.ts b/src/upload-sarif-action.ts index 25e884ea0f..a193e242a6 100644 --- a/src/upload-sarif-action.ts +++ b/src/upload-sarif-action.ts @@ -4,6 +4,7 @@ import * as core from "@actions/core"; import * as actionsUtil from "./actions-util"; import { getActionVersion, getTemporaryDirectory } from "./actions-util"; +import * as analyses from "./analyses"; import { getGitHubVersion } from "./api-client"; import { Features } from "./feature-flags"; import { Logger, getActionsLogger } from "./logging"; @@ -95,7 +96,7 @@ async function run() { category, features, logger, - upload_lib.CodeScanningTarget, + analyses.CodeScanning, ); core.setOutput("sarif-id", uploadResult.sarifID); @@ -105,7 +106,7 @@ async function run() { if (fs.lstatSync(sarifPath).isDirectory()) { const qualitySarifFiles = upload_lib.findSarifFilesInDir( sarifPath, - upload_lib.CodeQualityTarget.sarifPredicate, + analyses.CodeQuality.sarifPredicate, ); if (qualitySarifFiles.length !== 0) { @@ -115,7 +116,7 @@ async function run() { actionsUtil.fixCodeQualityCategory(logger, category), features, logger, - upload_lib.CodeQualityTarget, + analyses.CodeQuality, ); } } diff --git a/src/util.ts b/src/util.ts index 1ac24ad124..5ef037636f 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1278,3 +1278,12 @@ export async function asyncSome( const results = await Promise.all(array.map(predicate)); return results.some((result) => result); } + +/** + * Checks that `value` is neither `undefined` nor `null`. + * @param value The value to test. + * @returns Narrows the type of `value` to exclude `undefined` and `null`. + */ +export function isDefined(value: T | null | undefined): value is T { + return value !== undefined && value !== null; +}