diff --git a/.github/workflows/__quality-queries.yml b/.github/workflows/__analysis-kinds.yml similarity index 83% rename from .github/workflows/__quality-queries.yml rename to .github/workflows/__analysis-kinds.yml index fdbe0e812a..b36a0bceb3 100644 --- a/.github/workflows/__quality-queries.yml +++ b/.github/workflows/__analysis-kinds.yml @@ -3,7 +3,7 @@ # pr-checks/sync.sh # to regenerate this file. -name: PR Check - Quality queries input +name: PR Check - Analysis kinds env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GO111MODULE: auto @@ -29,9 +29,9 @@ defaults: shell: bash concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' || false }} - group: quality-queries-${{github.ref}} + group: analysis-kinds-${{github.ref}} jobs: - quality-queries: + analysis-kinds: strategy: fail-fast: false matrix: @@ -45,6 +45,9 @@ jobs: - os: ubuntu-latest version: linked analysis-kinds: code-scanning,code-quality + - os: ubuntu-latest + version: linked + analysis-kinds: csra - os: ubuntu-latest version: nightly-latest analysis-kinds: code-scanning @@ -54,7 +57,10 @@ jobs: - os: ubuntu-latest version: nightly-latest analysis-kinds: code-scanning,code-quality - name: Quality queries input + - os: ubuntu-latest + version: nightly-latest + analysis-kinds: csra + name: Analysis kinds if: github.triggering_actor != 'dependabot[bot]' permissions: contents: read @@ -81,30 +87,24 @@ jobs: output: ${{ runner.temp }}/results upload-database: false post-processed-sarif-path: ${{ runner.temp }}/post-processed - - name: Upload security SARIF - if: contains(matrix.analysis-kinds, 'code-scanning') - uses: actions/upload-artifact@v6 - with: - 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') + + - name: Upload SARIF files uses: actions/upload-artifact@v6 with: name: | - quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json - path: ${{ runner.temp }}/results/javascript.quality.sarif + analysis-kinds-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }} + path: ${{ runner.temp }}/results/*.sarif retention-days: 7 + - name: Upload post-processed SARIF uses: actions/upload-artifact@v6 with: name: | - post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json + post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }} path: ${{ runner.temp }}/post-processed retention-days: 7 if-no-files-found: error + - name: Check quality query does not appear in security SARIF if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/github-script@v8 @@ -121,7 +121,16 @@ jobs: EXPECT_PRESENT: 'true' with: script: ${{ env.CHECK_SCRIPT }} + - name: Check quality query does not appear in CSRA SARIF + if: contains(matrix.analysis-kinds, 'csra') + uses: actions/github-script@v8 + env: + SARIF_PATH: ${{ runner.temp }}/results/javascript.csra.sarif + EXPECT_PRESENT: 'false' + with: + script: ${{ env.CHECK_SCRIPT }} env: + CODEQL_ACTION_CSRA_ASSESSMENT_ID: 1 CHECK_SCRIPT: | const fs = require('fs'); diff --git a/lib/analyze-action-post.js b/lib/analyze-action-post.js index d097d992d3..bceaf258f3 100644 --- a/lib/analyze-action-post.js +++ b/lib/analyze-action-post.js @@ -161224,6 +161224,7 @@ var path3 = __toESM(require("path")); var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); diff --git a/lib/analyze-action.js b/lib/analyze-action.js index c0288403bf..a22217bb28 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -106485,6 +106485,7 @@ function fixCodeQualityCategory(logger, category) { var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); @@ -106494,9 +106495,10 @@ var 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), + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !CSRA.sarifPredicate(name), fixCategory: (_, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_SARIF_" + sentinelPrefix: "CODEQL_UPLOAD_SARIF_", + transformPayload: (payload) => payload }; var CodeQuality = { kind: "code-quality" /* CodeQuality */, @@ -106505,7 +106507,25 @@ var CodeQuality = { sarifExtension: ".quality.sarif", sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), fixCategory: fixCodeQualityCategory, - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", + transformPayload: (payload) => payload +}; +function addAssessmentId(payload) { + const assessmentId = parseInt( + getRequiredEnvParam("CODEQL_ACTION_CSRA_ASSESSMENT_ID"), + 10 + ); + return { sarif: payload.sarif, assessment_id: assessmentId }; +} +var CSRA = { + kind: "csra" /* CSRA */, + name: "csra", + target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* CSRA */, + sarifExtension: ".csra.sarif", + sarifPredicate: (name) => name.endsWith(CSRA.sarifExtension), + fixCategory: fixCodeQualityCategory, + sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", + transformPayload: addAssessmentId }; function getAnalysisConfig(kind) { switch (kind) { @@ -106513,9 +106533,15 @@ function getAnalysisConfig(kind) { return CodeScanning; case "code-quality" /* CodeQuality */: return CodeQuality; + case "csra" /* CSRA */: + return CSRA; } } -var SarifScanOrder = [CodeQuality, CodeScanning]; +var SarifScanOrder = [ + CSRA, + CodeQuality, + CodeScanning +]; // src/analyze.ts var fs12 = __toESM(require("fs")); @@ -108416,10 +108442,13 @@ function isCodeQualityEnabled(config) { return config.analysisKinds.includes("code-quality" /* CodeQuality */); } function getPrimaryAnalysisKind(config) { + if (config.analysisKinds.length === 1) { + return config.analysisKinds[0]; + } return isCodeScanningEnabled(config) ? "code-scanning" /* CodeScanning */ : "code-quality" /* CodeQuality */; } function getPrimaryAnalysisConfig(config) { - return getPrimaryAnalysisKind(config) === "code-scanning" /* CodeScanning */ ? CodeScanning : CodeQuality; + return getAnalysisConfig(getPrimaryAnalysisKind(config)); } // src/setup-codeql.ts @@ -110530,10 +110559,7 @@ async function runQueries(sarifFolder, memoryFlag, threadsFlag, diffRangePackDir return statusReport; async function runInterpretResultsFor(analysis, language, queries, enableDebugLogging) { logger.info(`Interpreting ${analysis.name} results for ${language}`); - let category = automationDetailsId; - if (analysis.kind === "code-quality" /* CodeQuality */) { - category = analysis.fixCategory(logger, automationDetailsId); - } + const category = analysis.fixCategory(logger, automationDetailsId); const sarifFile = path12.join( sarifFolder, addSarifExtension(analysis, language) @@ -112518,18 +112544,20 @@ async function uploadPostProcessedFiles(logger, checkoutPath, uploadTarget, post logger.debug(`Compressing serialized SARIF`); const zippedSarif = import_zlib.default.gzipSync(sarifPayload).toString("base64"); const checkoutURI = url.pathToFileURL(checkoutPath).href; - const payload = buildPayload( - await getCommitOid(checkoutPath), - await getRef(), - postProcessingResults.analysisKey, - getRequiredEnvParam("GITHUB_WORKFLOW"), - zippedSarif, - getWorkflowRunID(), - getWorkflowRunAttempt(), - checkoutURI, - postProcessingResults.environment, - toolNames, - await determineBaseBranchHeadCommitOid() + const payload = uploadTarget.transformPayload( + buildPayload( + await getCommitOid(checkoutPath), + await getRef(), + postProcessingResults.analysisKey, + getRequiredEnvParam("GITHUB_WORKFLOW"), + zippedSarif, + getWorkflowRunID(), + getWorkflowRunAttempt(), + checkoutURI, + postProcessingResults.environment, + toolNames, + await determineBaseBranchHeadCommitOid() + ) ); const rawUploadSizeBytes = sarifPayload.length; logger.debug(`Raw upload size: ${rawUploadSizeBytes} bytes`); diff --git a/lib/autobuild-action.js b/lib/autobuild-action.js index 416cc22720..9aa58f4170 100644 --- a/lib/autobuild-action.js +++ b/lib/autobuild-action.js @@ -103629,6 +103629,7 @@ var path4 = __toESM(require("path")); var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); diff --git a/lib/init-action-post.js b/lib/init-action-post.js index 44e368f8a4..e19a9678c3 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -164545,6 +164545,7 @@ var path6 = __toESM(require("path")); var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); @@ -164553,9 +164554,10 @@ var 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), + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !CSRA.sarifPredicate(name), fixCategory: (_2, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_SARIF_" + sentinelPrefix: "CODEQL_UPLOAD_SARIF_", + transformPayload: (payload) => payload }; var CodeQuality = { kind: "code-quality" /* CodeQuality */, @@ -164564,7 +164566,25 @@ var CodeQuality = { sarifExtension: ".quality.sarif", sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), fixCategory: fixCodeQualityCategory, - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", + transformPayload: (payload) => payload +}; +function addAssessmentId(payload) { + const assessmentId = parseInt( + getRequiredEnvParam("CODEQL_ACTION_CSRA_ASSESSMENT_ID"), + 10 + ); + return { sarif: payload.sarif, assessment_id: assessmentId }; +} +var CSRA = { + kind: "csra" /* CSRA */, + name: "csra", + target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* CSRA */, + sarifExtension: ".csra.sarif", + sarifPredicate: (name) => name.endsWith(CSRA.sarifExtension), + fixCategory: fixCodeQualityCategory, + sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", + transformPayload: addAssessmentId }; // src/config/db-config.ts @@ -169131,18 +169151,20 @@ async function uploadPostProcessedFiles(logger, checkoutPath, uploadTarget, post logger.debug(`Compressing serialized SARIF`); const zippedSarif = import_zlib.default.gzipSync(sarifPayload).toString("base64"); const checkoutURI = url.pathToFileURL(checkoutPath).href; - const payload = buildPayload( - await getCommitOid(checkoutPath), - await getRef(), - postProcessingResults.analysisKey, - getRequiredEnvParam("GITHUB_WORKFLOW"), - zippedSarif, - getWorkflowRunID(), - getWorkflowRunAttempt(), - checkoutURI, - postProcessingResults.environment, - toolNames, - await determineBaseBranchHeadCommitOid() + const payload = uploadTarget.transformPayload( + buildPayload( + await getCommitOid(checkoutPath), + await getRef(), + postProcessingResults.analysisKey, + getRequiredEnvParam("GITHUB_WORKFLOW"), + zippedSarif, + getWorkflowRunID(), + getWorkflowRunAttempt(), + checkoutURI, + postProcessingResults.environment, + toolNames, + await determineBaseBranchHeadCommitOid() + ) ); const rawUploadSizeBytes = sarifPayload.length; logger.debug(`Raw upload size: ${rawUploadSizeBytes} bytes`); diff --git a/lib/init-action.js b/lib/init-action.js index 8607b23914..6bf9880a5b 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -103833,8 +103833,14 @@ function isAnalyzingPullRequest() { var AnalysisKind = /* @__PURE__ */ ((AnalysisKind3) => { AnalysisKind3["CodeScanning"] = "code-scanning"; AnalysisKind3["CodeQuality"] = "code-quality"; + AnalysisKind3["CSRA"] = "csra"; return AnalysisKind3; })(AnalysisKind || {}); +var compatibilityMatrix = { + ["code-scanning" /* CodeScanning */]: /* @__PURE__ */ new Set(["code-quality" /* CodeQuality */]), + ["code-quality" /* CodeQuality */]: /* @__PURE__ */ new Set(["code-scanning" /* CodeScanning */]), + ["csra" /* CSRA */]: /* @__PURE__ */ new Set() +}; var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); async function parseAnalysisKinds(input) { const components = input.split(","); @@ -103857,7 +103863,7 @@ async function getAnalysisKinds(logger, skipCache = false) { if (!skipCache && cachedAnalysisKinds !== void 0) { return cachedAnalysisKinds; } - cachedAnalysisKinds = await parseAnalysisKinds( + const analysisKinds = await parseAnalysisKinds( getRequiredInput("analysis-kinds") ); const qualityQueriesInput = getOptionalInput("quality-queries"); @@ -103866,9 +103872,20 @@ async function getAnalysisKinds(logger, skipCache = false) { "The `quality-queries` input is deprecated and will be removed in a future version of the CodeQL Action. Use the `analysis-kinds` input to configure different analysis kinds instead." ); } - if (!cachedAnalysisKinds.includes("code-quality" /* CodeQuality */) && qualityQueriesInput !== void 0) { - cachedAnalysisKinds.push("code-quality" /* CodeQuality */); + if (!analysisKinds.includes("code-quality" /* CodeQuality */) && qualityQueriesInput !== void 0) { + analysisKinds.push("code-quality" /* CodeQuality */); + } + for (const analysisKind of analysisKinds) { + for (const otherAnalysisKind of analysisKinds) { + if (analysisKind === otherAnalysisKind) continue; + if (!compatibilityMatrix[analysisKind].has(otherAnalysisKind)) { + throw new ConfigurationError( + `${otherAnalysisKind} cannot be enabled at the same time as ${analysisKind}` + ); + } + } } + cachedAnalysisKinds = analysisKinds; return cachedAnalysisKinds; } var codeQualityQueries = ["code-quality"]; diff --git a/lib/resolve-environment-action.js b/lib/resolve-environment-action.js index a841072511..d2c4da143b 100644 --- a/lib/resolve-environment-action.js +++ b/lib/resolve-environment-action.js @@ -103628,6 +103628,7 @@ var path3 = __toESM(require("path")); var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); diff --git a/lib/setup-codeql-action.js b/lib/setup-codeql-action.js index c01ec64f56..ddc06f431d 100644 --- a/lib/setup-codeql-action.js +++ b/lib/setup-codeql-action.js @@ -104553,6 +104553,7 @@ function wrapCliConfigurationError(cliError) { var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); diff --git a/lib/start-proxy-action-post.js b/lib/start-proxy-action-post.js index c29841a85b..adccec31bc 100644 --- a/lib/start-proxy-action-post.js +++ b/lib/start-proxy-action-post.js @@ -160859,6 +160859,7 @@ var path = __toESM(require("path")); var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); diff --git a/lib/start-proxy-action.js b/lib/start-proxy-action.js index 072924405e..7baced5b4b 100644 --- a/lib/start-proxy-action.js +++ b/lib/start-proxy-action.js @@ -121161,6 +121161,7 @@ var core9 = __toESM(require_core()); var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); diff --git a/lib/upload-lib.js b/lib/upload-lib.js index 0fa50e3967..53c52c2198 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -106141,6 +106141,7 @@ function fixCodeQualityCategory(logger, category) { var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); @@ -106149,9 +106150,10 @@ var 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), + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !CSRA.sarifPredicate(name), fixCategory: (_, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_SARIF_" + sentinelPrefix: "CODEQL_UPLOAD_SARIF_", + transformPayload: (payload) => payload }; var CodeQuality = { kind: "code-quality" /* CodeQuality */, @@ -106160,9 +106162,31 @@ var CodeQuality = { sarifExtension: ".quality.sarif", sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), fixCategory: fixCodeQualityCategory, - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", + transformPayload: (payload) => payload }; -var SarifScanOrder = [CodeQuality, CodeScanning]; +function addAssessmentId(payload) { + const assessmentId = parseInt( + getRequiredEnvParam("CODEQL_ACTION_CSRA_ASSESSMENT_ID"), + 10 + ); + return { sarif: payload.sarif, assessment_id: assessmentId }; +} +var CSRA = { + kind: "csra" /* CSRA */, + name: "csra", + target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* CSRA */, + sarifExtension: ".csra.sarif", + sarifPredicate: (name) => name.endsWith(CSRA.sarifExtension), + fixCategory: fixCodeQualityCategory, + sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", + transformPayload: addAssessmentId +}; +var SarifScanOrder = [ + CSRA, + CodeQuality, + CodeScanning +]; // src/api-client.ts var core5 = __toESM(require_core()); @@ -110447,18 +110471,20 @@ async function uploadPostProcessedFiles(logger, checkoutPath, uploadTarget, post logger.debug(`Compressing serialized SARIF`); const zippedSarif = import_zlib.default.gzipSync(sarifPayload).toString("base64"); const checkoutURI = url.pathToFileURL(checkoutPath).href; - const payload = buildPayload( - await getCommitOid(checkoutPath), - await getRef(), - postProcessingResults.analysisKey, - getRequiredEnvParam("GITHUB_WORKFLOW"), - zippedSarif, - getWorkflowRunID(), - getWorkflowRunAttempt(), - checkoutURI, - postProcessingResults.environment, - toolNames, - await determineBaseBranchHeadCommitOid() + const payload = uploadTarget.transformPayload( + buildPayload( + await getCommitOid(checkoutPath), + await getRef(), + postProcessingResults.analysisKey, + getRequiredEnvParam("GITHUB_WORKFLOW"), + zippedSarif, + getWorkflowRunID(), + getWorkflowRunAttempt(), + checkoutURI, + postProcessingResults.environment, + toolNames, + await determineBaseBranchHeadCommitOid() + ) ); const rawUploadSizeBytes = sarifPayload.length; logger.debug(`Raw upload size: ${rawUploadSizeBytes} bytes`); diff --git a/lib/upload-sarif-action-post.js b/lib/upload-sarif-action-post.js index a733e8c04b..04f5016943 100644 --- a/lib/upload-sarif-action-post.js +++ b/lib/upload-sarif-action-post.js @@ -160866,6 +160866,7 @@ var io5 = __toESM(require_io()); var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index edc7840847..c8994877d0 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -106179,6 +106179,7 @@ function fixCodeQualityCategory(logger, category) { var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { AnalysisKind2["CodeScanning"] = "code-scanning"; AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["CSRA"] = "csra"; return AnalysisKind2; })(AnalysisKind || {}); var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); @@ -106187,9 +106188,10 @@ var 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), + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !CSRA.sarifPredicate(name), fixCategory: (_, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_SARIF_" + sentinelPrefix: "CODEQL_UPLOAD_SARIF_", + transformPayload: (payload) => payload }; var CodeQuality = { kind: "code-quality" /* CodeQuality */, @@ -106198,7 +106200,25 @@ var CodeQuality = { sarifExtension: ".quality.sarif", sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), fixCategory: fixCodeQualityCategory, - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_" + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", + transformPayload: (payload) => payload +}; +function addAssessmentId(payload) { + const assessmentId = parseInt( + getRequiredEnvParam("CODEQL_ACTION_CSRA_ASSESSMENT_ID"), + 10 + ); + return { sarif: payload.sarif, assessment_id: assessmentId }; +} +var CSRA = { + kind: "csra" /* CSRA */, + name: "csra", + target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* CSRA */, + sarifExtension: ".csra.sarif", + sarifPredicate: (name) => name.endsWith(CSRA.sarifExtension), + fixCategory: fixCodeQualityCategory, + sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", + transformPayload: addAssessmentId }; function getAnalysisConfig(kind) { switch (kind) { @@ -106206,9 +106226,15 @@ function getAnalysisConfig(kind) { return CodeScanning; case "code-quality" /* CodeQuality */: return CodeQuality; + case "csra" /* CSRA */: + return CSRA; } } -var SarifScanOrder = [CodeQuality, CodeScanning]; +var SarifScanOrder = [ + CSRA, + CodeQuality, + CodeScanning +]; // src/api-client.ts var core5 = __toESM(require_core()); @@ -110955,18 +110981,20 @@ async function uploadPostProcessedFiles(logger, checkoutPath, uploadTarget, post logger.debug(`Compressing serialized SARIF`); const zippedSarif = import_zlib.default.gzipSync(sarifPayload).toString("base64"); const checkoutURI = url.pathToFileURL(checkoutPath).href; - const payload = buildPayload( - await getCommitOid(checkoutPath), - await getRef(), - postProcessingResults.analysisKey, - getRequiredEnvParam("GITHUB_WORKFLOW"), - zippedSarif, - getWorkflowRunID(), - getWorkflowRunAttempt(), - checkoutURI, - postProcessingResults.environment, - toolNames, - await determineBaseBranchHeadCommitOid() + const payload = uploadTarget.transformPayload( + buildPayload( + await getCommitOid(checkoutPath), + await getRef(), + postProcessingResults.analysisKey, + getRequiredEnvParam("GITHUB_WORKFLOW"), + zippedSarif, + getWorkflowRunID(), + getWorkflowRunAttempt(), + checkoutURI, + postProcessingResults.environment, + toolNames, + await determineBaseBranchHeadCommitOid() + ) ); const rawUploadSizeBytes = sarifPayload.length; logger.debug(`Raw upload size: ${rawUploadSizeBytes} bytes`); diff --git a/pr-checks/checks/quality-queries.yml b/pr-checks/checks/analysis-kinds.yml similarity index 75% rename from pr-checks/checks/quality-queries.yml rename to pr-checks/checks/analysis-kinds.yml index 353abbb774..18483e6e1b 100644 --- a/pr-checks/checks/quality-queries.yml +++ b/pr-checks/checks/analysis-kinds.yml @@ -1,8 +1,9 @@ -name: "Quality queries input" -description: "Tests that queries specified in the quality-queries input are used." +name: "Analysis kinds" +description: "Tests basic functionality for different `analysis-kinds` inputs." versions: ["linked", "nightly-latest"] -analysisKinds: ["code-scanning", "code-quality", "code-scanning,code-quality"] +analysisKinds: ["code-scanning", "code-quality", "code-scanning,code-quality", "csra"] env: + CODEQL_ACTION_CSRA_ASSESSMENT_ID: 1 CHECK_SCRIPT: | const fs = require('fs'); @@ -37,30 +38,24 @@ steps: output: "${{ runner.temp }}/results" upload-database: false post-processed-sarif-path: "${{ runner.temp }}/post-processed" - - name: Upload security SARIF - if: contains(matrix.analysis-kinds, 'code-scanning') - uses: actions/upload-artifact@v6 - with: - 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') + + - name: Upload SARIF files uses: actions/upload-artifact@v6 with: name: | - quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json - path: "${{ runner.temp }}/results/javascript.quality.sarif" + analysis-kinds-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }} + path: "${{ runner.temp }}/results/*.sarif" retention-days: 7 + - name: Upload post-processed SARIF uses: actions/upload-artifact@v6 with: name: | - post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json + post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }} path: "${{ runner.temp }}/post-processed" retention-days: 7 if-no-files-found: error + - name: Check quality query does not appear in security SARIF if: contains(matrix.analysis-kinds, 'code-scanning') uses: actions/github-script@v8 @@ -77,3 +72,11 @@ steps: EXPECT_PRESENT: "true" with: script: ${{ env.CHECK_SCRIPT }} + - name: Check quality query does not appear in CSRA SARIF + if: contains(matrix.analysis-kinds, 'csra') + uses: actions/github-script@v8 + env: + SARIF_PATH: "${{ runner.temp }}/results/javascript.csra.sarif" + EXPECT_PRESENT: "false" + with: + script: ${{ env.CHECK_SCRIPT }} diff --git a/src/analyses.test.ts b/src/analyses.test.ts index 9178ffbd5a..b4a24f4ff3 100644 --- a/src/analyses.test.ts +++ b/src/analyses.test.ts @@ -1,9 +1,14 @@ +import path from "path"; + import test from "ava"; import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; import { AnalysisKind, + CodeScanning, + compatibilityMatrix, + getAnalysisConfig, getAnalysisKinds, parseAnalysisKinds, supportedAnalysisKinds, @@ -67,3 +72,49 @@ test("getAnalysisKinds - throws if `analysis-kinds` input is invalid", async (t) requiredInputStub.withArgs("analysis-kinds").returns("no-such-thing"); await t.throwsAsync(getAnalysisKinds(getRunnerLogger(true), true)); }); + +// Test the compatibility matrix by looping through all analysis kinds. +const analysisKinds = Object.values(AnalysisKind); +for (let i = 0; i < analysisKinds.length; i++) { + const analysisKind = analysisKinds[i]; + + for (let j = i + 1; j < analysisKinds.length; j++) { + const otherAnalysis = analysisKinds[j]; + + if (analysisKind === otherAnalysis) continue; + if (compatibilityMatrix[analysisKind].has(otherAnalysis)) { + test(`getAnalysisKinds - allows ${analysisKind} with ${otherAnalysis}`, async (t) => { + const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); + requiredInputStub + .withArgs("analysis-kinds") + .returns([analysisKind, otherAnalysis].join(",")); + const result = await getAnalysisKinds(getRunnerLogger(true), true); + t.is(result.length, 2); + }); + } else { + test(`getAnalysisKinds - throws if ${analysisKind} is enabled with ${otherAnalysis}`, async (t) => { + const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); + requiredInputStub + .withArgs("analysis-kinds") + .returns([analysisKind, otherAnalysis].join(",")); + await t.throwsAsync(getAnalysisKinds(getRunnerLogger(true), true), { + instanceOf: ConfigurationError, + message: `${otherAnalysis} cannot be enabled at the same time as ${analysisKind}`, + }); + }); + } + } +} + +test("Code Scanning configuration does not accept other SARIF extensions", (t) => { + for (const analysisKind of supportedAnalysisKinds) { + if (analysisKind === AnalysisKind.CodeScanning) continue; + + const analysis = getAnalysisConfig(analysisKind); + const sarifPath = path.join("path", "to", `file${analysis.sarifExtension}`); + + // The Code Scanning configuration's `sarifPredicate` should not accept a path which + // ends in a different configuration's `sarifExtension`. + t.false(CodeScanning.sarifPredicate(sarifPath)); + } +}); diff --git a/src/analyses.ts b/src/analyses.ts index 4f91ab07c0..ce7f101582 100644 --- a/src/analyses.ts +++ b/src/analyses.ts @@ -4,13 +4,28 @@ import { getRequiredInput, } from "./actions-util"; import { Logger } from "./logging"; -import { ConfigurationError } from "./util"; +import { + AssessmentPayload, + BasePayload, + UploadPayload, +} from "./upload-lib/types"; +import { ConfigurationError, getRequiredEnvParam } from "./util"; export enum AnalysisKind { CodeScanning = "code-scanning", CodeQuality = "code-quality", + CSRA = "csra", } +export type CompatibilityMatrix = Record>; + +/** A mapping from analysis kinds to other analysis kinds which can be enabled concurrently. */ +export const compatibilityMatrix: CompatibilityMatrix = { + [AnalysisKind.CodeScanning]: new Set([AnalysisKind.CodeQuality]), + [AnalysisKind.CodeQuality]: new Set([AnalysisKind.CodeScanning]), + [AnalysisKind.CSRA]: new Set(), +}; + // Exported for testing. A set of all known analysis kinds. export const supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); @@ -67,7 +82,7 @@ export async function getAnalysisKinds( return cachedAnalysisKinds; } - cachedAnalysisKinds = await parseAnalysisKinds( + const analysisKinds = await parseAnalysisKinds( getRequiredInput("analysis-kinds"), ); @@ -85,12 +100,27 @@ export async function getAnalysisKinds( // if an input to `quality-queries` was specified. We should remove this once // `quality-queries` is no longer used. if ( - !cachedAnalysisKinds.includes(AnalysisKind.CodeQuality) && + !analysisKinds.includes(AnalysisKind.CodeQuality) && qualityQueriesInput !== undefined ) { - cachedAnalysisKinds.push(AnalysisKind.CodeQuality); + analysisKinds.push(AnalysisKind.CodeQuality); + } + + // Check that all enabled analysis kinds are compatible with each other. + for (const analysisKind of analysisKinds) { + for (const otherAnalysisKind of analysisKinds) { + if (analysisKind === otherAnalysisKind) continue; + + if (!compatibilityMatrix[analysisKind].has(otherAnalysisKind)) { + throw new ConfigurationError( + `${otherAnalysisKind} cannot be enabled at the same time as ${analysisKind}`, + ); + } + } } + // Cache the analysis kinds and return them. + cachedAnalysisKinds = analysisKinds; return cachedAnalysisKinds; } @@ -101,6 +131,7 @@ export const codeQualityQueries: string[] = ["code-quality"]; enum SARIF_UPLOAD_ENDPOINT { CODE_SCANNING = "PUT /repos/:owner/:repo/code-scanning/analysis", CODE_QUALITY = "PUT /repos/:owner/:repo/code-quality/analysis", + CSRA = "PUT /repos/:owner/:repo/code-scanning/risk-assessment", } // Represents configurations for different analysis kinds. @@ -120,6 +151,8 @@ export interface AnalysisConfig { fixCategory: (logger: Logger, category?: string) => string | undefined; /** A prefix for environment variables used to track the uniqueness of SARIF uploads. */ sentinelPrefix: string; + /** Transforms the upload payload in an analysis-specific way. */ + transformPayload: (payload: UploadPayload) => BasePayload; } // Represents the Code Scanning analysis configuration. @@ -130,9 +163,11 @@ export const CodeScanning: AnalysisConfig = { sarifExtension: ".sarif", sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && - !CodeQuality.sarifPredicate(name), + !CodeQuality.sarifPredicate(name) && + !CSRA.sarifPredicate(name), fixCategory: (_, category) => category, sentinelPrefix: "CODEQL_UPLOAD_SARIF_", + transformPayload: (payload) => payload, }; // Represents the Code Quality analysis configuration. @@ -144,6 +179,30 @@ export const CodeQuality: AnalysisConfig = { sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), fixCategory: fixCodeQualityCategory, sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", + transformPayload: (payload) => payload, +}; + +/** + * Retrieves the CSRA assessment id from an environment variable and adds it to the payload. + * @param payload The base payload. + */ +function addAssessmentId(payload: UploadPayload): AssessmentPayload { + const assessmentId = parseInt( + getRequiredEnvParam("CODEQL_ACTION_CSRA_ASSESSMENT_ID"), + 10, + ); + return { sarif: payload.sarif, assessment_id: assessmentId }; +} + +export const CSRA: AnalysisConfig = { + kind: AnalysisKind.CSRA, + name: "csra", + target: SARIF_UPLOAD_ENDPOINT.CSRA, + sarifExtension: ".csra.sarif", + sarifPredicate: (name) => name.endsWith(CSRA.sarifExtension), + fixCategory: fixCodeQualityCategory, + sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", + transformPayload: addAssessmentId, }; /** @@ -160,6 +219,8 @@ export function getAnalysisConfig(kind: AnalysisKind): AnalysisConfig { return CodeScanning; case AnalysisKind.CodeQuality: return CodeQuality; + case AnalysisKind.CSRA: + return CSRA; } } @@ -167,4 +228,8 @@ export function getAnalysisConfig(kind: AnalysisKind): AnalysisConfig { // we want to scan a folder containing SARIF files in an order that finds the more // specific extensions first. This constant defines an array in the order of analyis // configurations with more specific extensions to less specific extensions. -export const SarifScanOrder = [CodeQuality, CodeScanning]; +export const SarifScanOrder: AnalysisConfig[] = [ + CSRA, + CodeQuality, + CodeScanning, +]; diff --git a/src/analyze.test.ts b/src/analyze.test.ts index 27fe4a6f47..c5aec6e4fe 100644 --- a/src/analyze.test.ts +++ b/src/analyze.test.ts @@ -4,7 +4,7 @@ import * as path from "path"; import test from "ava"; import * as sinon from "sinon"; -import { CodeQuality, CodeScanning } from "./analyses"; +import { CodeQuality, CodeScanning, CSRA } from "./analyses"; import { runQueries, defaultSuites, @@ -155,5 +155,6 @@ test("addSarifExtension", (t) => { addSarifExtension(CodeQuality, language), `${language}.quality.sarif`, ); + t.is(addSarifExtension(CSRA, language), `${language}.csra.sarif`); } }); diff --git a/src/analyze.ts b/src/analyze.ts index bb38415047..352efd9756 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -549,12 +549,9 @@ export async function runQueries( ): 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 (analysis.kind === analyses.AnalysisKind.CodeQuality) { - category = analysis.fixCategory(logger, automationDetailsId); - } + // Apply the analysis configuration's `fixCategory` function to adjust the category if needed. + // This is a no-op for Code Scanning. + const category = analysis.fixCategory(logger, automationDetailsId); const sarifFile = path.join( sarifFolder, diff --git a/src/config-utils.test.ts b/src/config-utils.test.ts index 276a7a344b..d0583f1674 100644 --- a/src/config-utils.test.ts +++ b/src/config-utils.test.ts @@ -7,7 +7,7 @@ import * as yaml from "js-yaml"; import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; -import { AnalysisKind } from "./analyses"; +import { AnalysisKind, supportedAnalysisKinds } from "./analyses"; import * as api from "./api-client"; import { CachingKind } from "./caching-utils"; import { createStubCodeQL } from "./codeql"; @@ -1829,3 +1829,22 @@ test("hasActionsWorkflows doesn't throw if workflows folder doesn't exist", asyn t.notThrows(() => configUtils.hasActionsWorkflows(tmpDir)); }); }); + +test("getPrimaryAnalysisConfig - single analysis kind", (t) => { + // If only one analysis kind is configured, we expect to get the matching configuration. + for (const analysisKind of supportedAnalysisKinds) { + const singleKind = createTestConfig({ analysisKinds: [analysisKind] }); + t.is(configUtils.getPrimaryAnalysisConfig(singleKind).kind, analysisKind); + } +}); + +test("getPrimaryAnalysisConfig - Code Scanning + Code Quality", (t) => { + // For CS+CQ, we expect to get the Code Scanning configuration. + const codeScanningAndCodeQuality = createTestConfig({ + analysisKinds: [AnalysisKind.CodeScanning, AnalysisKind.CodeQuality], + }); + t.is( + configUtils.getPrimaryAnalysisConfig(codeScanningAndCodeQuality).kind, + AnalysisKind.CodeScanning, + ); +}); diff --git a/src/config-utils.ts b/src/config-utils.ts index e52070b47f..c35bad33bd 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -12,9 +12,8 @@ import { import { AnalysisConfig, AnalysisKind, - CodeQuality, codeQualityQueries, - CodeScanning, + getAnalysisConfig, } from "./analyses"; import * as api from "./api-client"; import { CachingKind, getCachingKind } from "./caching-utils"; @@ -1389,28 +1388,27 @@ export function isCodeQualityEnabled(config: Config): boolean { } /** - * Returns the primary analysis kind that the Action is initialised with. This is - * always `AnalysisKind.CodeScanning` unless `AnalysisKind.CodeScanning` is not enabled. + * Returns the primary analysis kind that the Action is initialised with. If there is only + * one analysis kind, then that is returned. * - * @returns Returns `AnalysisKind.CodeScanning` if `AnalysisKind.CodeScanning` is enabled; - * otherwise `AnalysisKind.CodeQuality`. + * The special case is Code Scanning + Code Quality, which can be enabled at the same time. + * In that case, this function returns Code Scanning. */ function getPrimaryAnalysisKind(config: Config): AnalysisKind { + if (config.analysisKinds.length === 1) { + return config.analysisKinds[0]; + } + 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`. + * Returns the primary analysis configuration that the Action is initialised with. */ export function getPrimaryAnalysisConfig(config: Config): AnalysisConfig { - return getPrimaryAnalysisKind(config) === AnalysisKind.CodeScanning - ? CodeScanning - : CodeQuality; + return getAnalysisConfig(getPrimaryAnalysisKind(config)); } /** Logs the Git version as a telemetry diagnostic. */ diff --git a/src/upload-lib.test.ts b/src/upload-lib.test.ts index 7a5be6382f..5b6c0db5f2 100644 --- a/src/upload-lib.test.ts +++ b/src/upload-lib.test.ts @@ -12,6 +12,7 @@ import * as api from "./api-client"; import { getRunnerLogger, Logger } from "./logging"; import { setupTests } from "./testing-utils"; import * as uploadLib from "./upload-lib"; +import { UploadPayload } from "./upload-lib/types"; import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util"; setupTests(test); @@ -128,11 +129,21 @@ test("finding SARIF files", async (t) => { "file", ); - // add some `.quality.sarif` files that should be ignored, unless we look for them specifically - fs.writeFileSync(path.join(tmpDir, "a.quality.sarif"), ""); - fs.writeFileSync(path.join(tmpDir, "dir1", "b.quality.sarif"), ""); + // add some non-Code Scanning files that should be ignored, unless we look for them specifically + for (const analysisKind of analyses.supportedAnalysisKinds) { + if (analysisKind === AnalysisKind.CodeScanning) continue; - const expectedSarifFiles = [ + const analysis = analyses.getAnalysisConfig(analysisKind); + + fs.writeFileSync(path.join(tmpDir, `a${analysis.sarifExtension}`), ""); + fs.writeFileSync( + path.join(tmpDir, "dir1", `b${analysis.sarifExtension}`), + "", + ); + } + + const expectedSarifFiles: Partial> = {}; + expectedSarifFiles[AnalysisKind.CodeScanning] = [ path.join(tmpDir, "a.sarif"), path.join(tmpDir, "b.sarif"), path.join(tmpDir, "dir1", "d.sarif"), @@ -143,18 +154,24 @@ test("finding SARIF files", async (t) => { CodeScanning.sarifPredicate, ); - t.deepEqual(sarifFiles, expectedSarifFiles); + t.deepEqual(sarifFiles, expectedSarifFiles[AnalysisKind.CodeScanning]); - const expectedQualitySarifFiles = [ - path.join(tmpDir, "a.quality.sarif"), - path.join(tmpDir, "dir1", "b.quality.sarif"), - ]; - const qualitySarifFiles = uploadLib.findSarifFilesInDir( - tmpDir, - CodeQuality.sarifPredicate, - ); + for (const analysisKind of analyses.supportedAnalysisKinds) { + if (analysisKind === AnalysisKind.CodeScanning) continue; + + const analysis = analyses.getAnalysisConfig(analysisKind); - t.deepEqual(qualitySarifFiles, expectedQualitySarifFiles); + expectedSarifFiles[analysisKind] = [ + path.join(tmpDir, `a${analysis.sarifExtension}`), + path.join(tmpDir, "dir1", `b${analysis.sarifExtension}`), + ]; + const foundSarifFiles = uploadLib.findSarifFilesInDir( + tmpDir, + analysis.sarifPredicate, + ); + + t.deepEqual(foundSarifFiles, expectedSarifFiles[analysisKind]); + } const groupedSarifFiles = await uploadLib.getGroupedSarifFilePaths( getRunnerLogger(true), @@ -162,16 +179,31 @@ test("finding SARIF files", async (t) => { ); t.not(groupedSarifFiles, undefined); - t.not(groupedSarifFiles[AnalysisKind.CodeScanning], undefined); - t.not(groupedSarifFiles[AnalysisKind.CodeQuality], undefined); - t.deepEqual( - groupedSarifFiles[AnalysisKind.CodeScanning], - expectedSarifFiles, - ); - t.deepEqual( - groupedSarifFiles[AnalysisKind.CodeQuality], - expectedQualitySarifFiles, + for (const analysisKind of analyses.supportedAnalysisKinds) { + t.not(groupedSarifFiles[analysisKind], undefined); + t.deepEqual( + groupedSarifFiles[analysisKind], + expectedSarifFiles[analysisKind], + ); + } + }); +}); + +test("getGroupedSarifFilePaths - CSRA", async (t) => { + await withTmpDir(async (tmpDir) => { + const sarifPath = path.join(tmpDir, "a.csra.sarif"); + fs.writeFileSync(sarifPath, ""); + + const groupedSarifFiles = await uploadLib.getGroupedSarifFilePaths( + getRunnerLogger(true), + sarifPath, ); + + t.not(groupedSarifFiles, undefined); + t.is(groupedSarifFiles[AnalysisKind.CodeScanning], undefined); + t.is(groupedSarifFiles[AnalysisKind.CodeQuality], undefined); + t.not(groupedSarifFiles[AnalysisKind.CSRA], undefined); + t.deepEqual(groupedSarifFiles[AnalysisKind.CSRA], [sarifPath]); }); }); @@ -188,6 +220,7 @@ test("getGroupedSarifFilePaths - Code Quality file", async (t) => { t.not(groupedSarifFiles, undefined); t.is(groupedSarifFiles[AnalysisKind.CodeScanning], undefined); t.not(groupedSarifFiles[AnalysisKind.CodeQuality], undefined); + t.is(groupedSarifFiles[AnalysisKind.CSRA], undefined); t.deepEqual(groupedSarifFiles[AnalysisKind.CodeQuality], [sarifPath]); }); }); @@ -205,6 +238,7 @@ test("getGroupedSarifFilePaths - Code Scanning file", async (t) => { t.not(groupedSarifFiles, undefined); t.not(groupedSarifFiles[AnalysisKind.CodeScanning], undefined); t.is(groupedSarifFiles[AnalysisKind.CodeQuality], undefined); + t.is(groupedSarifFiles[AnalysisKind.CSRA], undefined); t.deepEqual(groupedSarifFiles[AnalysisKind.CodeScanning], [sarifPath]); }); }); @@ -222,6 +256,7 @@ test("getGroupedSarifFilePaths - Other file", async (t) => { t.not(groupedSarifFiles, undefined); t.not(groupedSarifFiles[AnalysisKind.CodeScanning], undefined); t.is(groupedSarifFiles[AnalysisKind.CodeQuality], undefined); + t.is(groupedSarifFiles[AnalysisKind.CSRA], undefined); t.deepEqual(groupedSarifFiles[AnalysisKind.CodeScanning], [sarifPath]); }); }); @@ -875,7 +910,15 @@ function createMockSarif(id?: string, tool?: string) { function uploadPayloadFixtures(analysis: analyses.AnalysisConfig) { const mockData = { - payload: { sarif: "base64data", commit_sha: "abc123" }, + payload: { + commit_oid: "abc123", + ref: "ref", + sarif: "base64data", + workflow_run_id: 1, + workflow_run_attempt: 1, + checkout_uri: "uri", + tool_names: ["codeql"], + } satisfies UploadPayload, owner: "test-owner", repo: "test-repo", response: { diff --git a/src/upload-lib.ts b/src/upload-lib.ts index ac02745207..43039c596f 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -21,6 +21,7 @@ import * as gitUtils from "./git-utils"; import { initCodeQL } from "./init"; import { Logger } from "./logging"; import { getRepositoryNwo, RepositoryNwo } from "./repository"; +import { BasePayload, UploadPayload } from "./upload-lib/types"; import * as util from "./util"; import { ConfigurationError, @@ -326,7 +327,7 @@ function getAutomationID( * This is exported for testing purposes only. */ export async function uploadPayload( - payload: any, + payload: BasePayload, repositoryNwo: RepositoryNwo, logger: Logger, analysis: analyses.AnalysisConfig, @@ -618,8 +619,8 @@ export function buildPayload( environment: string | undefined, toolNames: string[], mergeBaseCommitOid: string | undefined, -) { - const payloadObj = { +): UploadPayload { + const payloadObj: UploadPayload = { commit_oid: commitOid, ref, analysis_key: analysisKey, @@ -847,18 +848,20 @@ export async function uploadPostProcessedFiles( const zippedSarif = zlib.gzipSync(sarifPayload).toString("base64"); const checkoutURI = url.pathToFileURL(checkoutPath).href; - const payload = buildPayload( - await gitUtils.getCommitOid(checkoutPath), - await gitUtils.getRef(), - postProcessingResults.analysisKey, - util.getRequiredEnvParam("GITHUB_WORKFLOW"), - zippedSarif, - actionsUtil.getWorkflowRunID(), - actionsUtil.getWorkflowRunAttempt(), - checkoutURI, - postProcessingResults.environment, - toolNames, - await gitUtils.determineBaseBranchHeadCommitOid(), + const payload = uploadTarget.transformPayload( + buildPayload( + await gitUtils.getCommitOid(checkoutPath), + await gitUtils.getRef(), + postProcessingResults.analysisKey, + util.getRequiredEnvParam("GITHUB_WORKFLOW"), + zippedSarif, + actionsUtil.getWorkflowRunID(), + actionsUtil.getWorkflowRunAttempt(), + checkoutURI, + postProcessingResults.environment, + toolNames, + await gitUtils.determineBaseBranchHeadCommitOid(), + ), ); // Log some useful debug info about the info diff --git a/src/upload-lib/types.ts b/src/upload-lib/types.ts new file mode 100644 index 0000000000..64480a4fc4 --- /dev/null +++ b/src/upload-lib/types.ts @@ -0,0 +1,22 @@ +export interface BasePayload { + sarif: string; +} + +export interface UploadPayload extends BasePayload { + commit_oid: string; + ref: string; + analysis_key?: string; + analysis_name?: string; + workflow_run_id: number; + workflow_run_attempt: number; + checkout_uri: string; + environment?: string; + started_at?: string; + tool_names: string[]; + base_ref?: string; + base_sha?: string; +} + +export interface AssessmentPayload extends BasePayload { + assessment_id: number; +}