2020-09-15 14:00:25 +01:00
"use strict" ;
2021-07-27 17:59:59 +01:00
var _ _createBinding = ( this && this . _ _createBinding ) || ( Object . create ? ( function ( o , m , k , k2 ) {
if ( k2 === undefined ) k2 = k ;
Object . defineProperty ( o , k2 , { enumerable : true , get : function ( ) { return m [ k ] ; } } ) ;
} ) : ( function ( o , m , k , k2 ) {
if ( k2 === undefined ) k2 = k ;
o [ k2 ] = m [ k ] ;
} ) ) ;
var _ _setModuleDefault = ( this && this . _ _setModuleDefault ) || ( Object . create ? ( function ( o , v ) {
Object . defineProperty ( o , "default" , { enumerable : true , value : v } ) ;
} ) : function ( o , v ) {
o [ "default" ] = v ;
} ) ;
2020-09-15 14:00:25 +01:00
var _ _importStar = ( this && this . _ _importStar ) || function ( mod ) {
if ( mod && mod . _ _esModule ) return mod ;
var result = { } ;
2021-07-27 17:59:59 +01:00
if ( mod != null ) for ( var k in mod ) if ( k !== "default" && Object . prototype . hasOwnProperty . call ( mod , k ) ) _ _createBinding ( result , mod , k ) ;
_ _setModuleDefault ( result , mod ) ;
2020-09-15 14:00:25 +01:00
return result ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
2022-09-07 09:45:19 +02:00
exports . printDebugLogs = exports . isAnalyzingDefaultBranch = exports . getRelativeScriptPath = exports . isRunningLocalAction = exports . workflowEventName = exports . sendStatusReport = exports . createStatusReportBase = exports . getActionsStatus = exports . getRef = exports . computeAutomationID = exports . getAutomationID = exports . getAnalysisKey = exports . getWorkflowRunID = exports . getWorkflow = exports . formatWorkflowCause = exports . formatWorkflowErrors = exports . validateWorkflow = exports . getWorkflowErrors = exports . WorkflowErrors = exports . patternIsSuperset = exports . determineMergeBaseCommitOid = exports . getCommitOid = exports . getTemporaryDirectory = exports . getOptionalInput = exports . getRequiredInput = void 0 ;
2020-11-24 09:51:00 +00:00
const fs = _ _importStar ( require ( "fs" ) ) ;
2022-03-03 13:06:02 -08:00
const os = _ _importStar ( require ( "os" ) ) ;
2020-11-12 14:18:58 +00:00
const path = _ _importStar ( require ( "path" ) ) ;
2020-09-15 14:00:25 +01:00
const core = _ _importStar ( require ( "@actions/core" ) ) ;
2020-11-20 11:35:59 +01:00
const toolrunner = _ _importStar ( require ( "@actions/exec/lib/toolrunner" ) ) ;
2020-11-18 21:14:45 +00:00
const safeWhich = _ _importStar ( require ( "@chrisgavin/safe-which" ) ) ;
2020-11-24 09:51:00 +00:00
const yaml = _ _importStar ( require ( "js-yaml" ) ) ;
2020-09-15 14:00:25 +01:00
const api = _ _importStar ( require ( "./api-client" ) ) ;
const sharedEnv = _ _importStar ( require ( "./shared-environment" ) ) ;
const util _1 = require ( "./util" ) ;
2022-03-17 10:07:29 -07:00
// eslint-disable-next-line import/no-commonjs
const pkg = require ( "../package.json" ) ;
2021-06-01 14:49:07 -07:00
/**
* The utils in this module are meant to be run inside of the action only.
* Code paths from the runner should not enter this module.
*/
2020-09-15 18:42:23 +01:00
/**
* Wrapper around core.getInput for inputs that always have a value.
* Also see getOptionalInput.
*
* This allows us to get stronger type checking of required/optional inputs
* and make behaviour more consistent between actions and the runner.
*/
function getRequiredInput ( name ) {
return core . getInput ( name , { required : true } ) ;
}
exports . getRequiredInput = getRequiredInput ;
/**
* Wrapper around core.getInput that converts empty inputs to undefined.
* Also see getRequiredInput.
*
* This allows us to get stronger type checking of required/optional inputs
* and make behaviour more consistent between actions and the runner.
*/
2022-01-25 22:37:02 -05:00
const getOptionalInput = function ( name ) {
2020-09-15 18:42:23 +01:00
const value = core . getInput ( name ) ;
return value . length > 0 ? value : undefined ;
2022-01-25 22:37:02 -05:00
} ;
2020-09-15 18:42:23 +01:00
exports . getOptionalInput = getOptionalInput ;
2021-06-03 11:18:25 -07:00
function getTemporaryDirectory ( ) {
const value = process . env [ "CODEQL_ACTION_TEMP" ] ;
return value !== undefined && value !== ""
? value
2021-09-10 13:53:13 -07:00
: ( 0 , util _1 . getRequiredEnvParam ) ( "RUNNER_TEMP" ) ;
2021-06-03 11:18:25 -07:00
}
exports . getTemporaryDirectory = getTemporaryDirectory ;
2020-09-15 14:00:25 +01:00
/**
* Gets the SHA of the commit that is currently checked out.
*/
2022-02-28 11:56:11 -08:00
const getCommitOid = async function ( checkoutPath , ref = "HEAD" ) {
2020-09-15 14:00:25 +01:00
// Try to use git to get the current commit SHA. If that fails then
// log but otherwise silently fall back to using the SHA from the environment.
// The only time these two values will differ is during analysis of a PR when
// the workflow has changed the current commit to the head commit instead of
// the merge commit, which must mean that git is available.
// Even if this does go wrong, it's not a huge problem for the alerts to
// reported on the merge commit.
try {
let commitOid = "" ;
2021-03-22 09:07:26 +00:00
await new toolrunner . ToolRunner ( await safeWhich . safeWhich ( "git" ) , [ "rev-parse" , ref ] , {
2020-09-15 14:00:25 +01:00
silent : true ,
listeners : {
stdout : ( data ) => {
commitOid += data . toString ( ) ;
} ,
stderr : ( data ) => {
process . stderr . write ( data ) ;
} ,
} ,
2022-02-28 11:56:11 -08:00
cwd : checkoutPath ,
2020-09-15 14:00:25 +01:00
} ) . exec ( ) ;
return commitOid . trim ( ) ;
}
catch ( e ) {
2022-01-25 22:37:02 -05:00
core . info ( ` Failed to call git to get current commit. Continuing with data from environment or input: ${ e } ` ) ;
2021-10-29 11:31:30 -07:00
core . info ( e . stack || "NO STACK" ) ;
2022-01-25 22:37:02 -05:00
return ( 0 , exports . getOptionalInput ) ( "sha" ) || ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_SHA" ) ;
2020-09-15 14:00:25 +01:00
}
2020-09-15 18:24:57 +01:00
} ;
2021-07-27 17:59:59 +01:00
exports . getCommitOid = getCommitOid ;
2022-02-01 15:23:02 +00:00
/**
* If the action was triggered by a pull request, determine the commit sha of the merge base.
* Returns undefined if run by other triggers or the merge base cannot be determined.
*/
const determineMergeBaseCommitOid = async function ( ) {
2022-09-07 09:45:19 +02:00
if ( workflowEventName ( ) !== "pull_request" ) {
2022-02-01 15:23:02 +00:00
return undefined ;
}
const mergeSha = ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_SHA" ) ;
2022-03-01 13:58:50 -08:00
const checkoutPath = ( 0 , exports . getOptionalInput ) ( "checkout_path" ) ;
2022-02-01 15:23:02 +00:00
try {
let commitOid = "" ;
let baseOid = "" ;
let headOid = "" ;
await new toolrunner . ToolRunner ( await safeWhich . safeWhich ( "git" ) , [ "show" , "-s" , "--format=raw" , mergeSha ] , {
silent : true ,
listeners : {
stdline : ( data ) => {
if ( data . startsWith ( "commit " ) && commitOid === "" ) {
commitOid = data . substring ( 7 ) ;
}
else if ( data . startsWith ( "parent " ) ) {
if ( baseOid === "" ) {
baseOid = data . substring ( 7 ) ;
}
else if ( headOid === "" ) {
headOid = data . substring ( 7 ) ;
}
}
} ,
stderr : ( data ) => {
process . stderr . write ( data ) ;
} ,
} ,
2022-02-28 11:56:11 -08:00
cwd : checkoutPath ,
2022-02-01 15:23:02 +00:00
} ) . exec ( ) ;
// Let's confirm our assumptions: We had a merge commit and the parsed parent data looks correct
if ( commitOid === mergeSha &&
headOid . length === 40 &&
baseOid . length === 40 ) {
return baseOid ;
}
return undefined ;
}
catch ( e ) {
core . info ( ` Failed to call git to determine merge base. Continuing with data from environment: ${ e } ` ) ;
core . info ( e . stack || "NO STACK" ) ;
return undefined ;
}
} ;
exports . determineMergeBaseCommitOid = determineMergeBaseCommitOid ;
2020-11-23 17:29:19 +00:00
function isObject ( o ) {
return o !== null && typeof o === "object" ;
}
2020-12-01 20:56:07 +00:00
const GLOB _PATTERN = new RegExp ( "(\\*\\*?)" ) ;
function escapeRegExp ( string ) {
return string . replace ( /[.*+?^${}()|[\]\\]/g , "\\$&" ) ; // $& means the whole matched string
}
function patternToRegExp ( value ) {
return new RegExp ( ` ^ ${ value
2020-12-17 19:18:09 +00:00
. toString ( )
2020-12-01 20:56:07 +00:00
. split ( GLOB _PATTERN )
. reduce ( function ( arr , cur ) {
2020-12-02 08:33:54 +00:00
if ( cur === "**" ) {
arr . push ( ".*?" ) ;
}
else if (cur === "*") {
arr.push("[^/]*?");
}
else if (cur) {
arr.push(escapeRegExp(cur));
2020-12-01 15:21:30 +00:00
}
return arr;
2020-12-01 20:56:07 +00:00
}, [])
.join("")} $ ` ) ;
2020-12-01 15:21:30 +00:00
}
2020-12-01 20:56:07 +00:00
// this function should return true if patternA is a superset of patternB
// e.g: * is a superset of main-* but main-* is not a superset of *.
2020-12-01 20:08:41 +00:00
function patternIsSuperset ( patternA , patternB ) {
2020-12-01 20:56:07 +00:00
return patternToRegExp ( patternA ) . test ( patternB ) ;
2020-12-01 17:16:33 +00:00
}
2020-12-01 20:08:41 +00:00
exports . patternIsSuperset = patternIsSuperset ;
2020-12-01 15:21:30 +00:00
function branchesToArray ( branches ) {
if ( typeof branches === "string" ) {
2020-12-01 10:42:21 +00:00
return [ branches ] ;
}
2020-12-04 15:18:22 +00:00
if ( Array . isArray ( branches ) ) {
if ( branches . length === 0 ) {
return "**" ;
}
return branches ;
2020-12-01 10:42:21 +00:00
}
2020-12-04 15:18:22 +00:00
return "**" ;
2020-12-01 10:42:21 +00:00
}
2020-11-24 17:21:25 +00:00
function toCodedErrors ( errors ) {
return Object . entries ( errors ) . reduce ( ( acc , [ key , value ] ) => {
acc [ key ] = { message : value , code : key } ;
return acc ;
} , { } ) ;
}
2021-01-22 14:07:46 +00:00
// code to send back via status report
// message to add as a warning annotation to the run
2020-11-24 17:21:25 +00:00
exports . WorkflowErrors = toCodedErrors ( {
2020-11-25 12:36:59 +00:00
MismatchedBranches : ` Please make sure that every branch in on.pull_request is also in on.push so that Code Scanning can compare pull requests against the state of the base branch. ` ,
MissingPushHook : ` Please specify an on.push hook so that Code Scanning can compare pull requests against the state of the base branch. ` ,
2020-11-25 14:23:21 +00:00
PathsSpecified : ` Using on.push.paths can prevent Code Scanning annotating new alerts in your pull requests. ` ,
PathsIgnoreSpecified : ` Using on.push.paths-ignore can prevent Code Scanning annotating new alerts in your pull requests. ` ,
2020-11-25 12:36:59 +00:00
CheckoutWrongHead : ` git checkout HEAD^2 is no longer necessary. Please remove this step as Code Scanning recommends analyzing the merge commit for best results. ` ,
2020-11-24 17:21:25 +00:00
} ) ;
2021-01-22 09:27:29 +00:00
function getWorkflowErrors ( doc ) {
2021-07-27 17:59:59 +01:00
var _a , _b , _c , _d , _e ;
2020-11-23 17:29:19 +00:00
const errors = [ ] ;
2021-01-04 12:00:15 +00:00
const jobName = process . env . GITHUB _JOB ;
if ( jobName ) {
2021-07-27 17:59:59 +01:00
const job = ( _a = doc === null || doc === void 0 ? void 0 : doc . jobs ) === null || _a === void 0 ? void 0 : _a [ jobName ] ;
const steps = job === null || job === void 0 ? void 0 : job . steps ;
2021-01-04 12:00:15 +00:00
if ( Array . isArray ( steps ) ) {
for ( const step of steps ) {
2020-12-03 13:41:55 +00:00
// this was advice that we used to give in the README
// we actually want to run the analysis on the merge commit
// to produce results that are more inline with expectations
// (i.e: this is what will happen if you merge this PR)
// and avoid some race conditions
2021-07-27 17:59:59 +01:00
if ( ( step === null || step === void 0 ? void 0 : step . run ) === "git checkout HEAD^2" ) {
2020-12-03 13:41:55 +00:00
errors . push ( exports . WorkflowErrors . CheckoutWrongHead ) ;
2021-01-04 12:00:15 +00:00
break ;
2020-12-03 13:41:55 +00:00
}
2020-11-23 17:29:19 +00:00
}
}
}
2021-01-19 15:26:28 +00:00
let missingPush = false ;
2020-11-23 17:29:19 +00:00
if ( doc . on === undefined ) {
2021-01-15 08:13:47 +00:00
// this is not a valid config
2020-11-23 17:29:19 +00:00
}
else if ( typeof doc . on === "string" ) {
2021-01-15 08:13:47 +00:00
if ( doc . on === "pull_request" ) {
2021-01-19 15:26:28 +00:00
missingPush = true ;
2020-11-23 17:29:19 +00:00
}
}
else if ( Array . isArray ( doc . on ) ) {
2021-01-13 12:28:24 +00:00
const hasPush = doc . on . includes ( "push" ) ;
const hasPullRequest = doc . on . includes ( "pull_request" ) ;
if ( hasPullRequest && ! hasPush ) {
2021-01-19 15:26:28 +00:00
missingPush = true ;
2020-11-23 17:29:19 +00:00
}
}
else if ( isObject ( doc . on ) ) {
2021-01-13 12:28:24 +00:00
const hasPush = Object . prototype . hasOwnProperty . call ( doc . on , "push" ) ;
const hasPullRequest = Object . prototype . hasOwnProperty . call ( doc . on , "pull_request" ) ;
2021-01-15 08:13:47 +00:00
if ( ! hasPush && hasPullRequest ) {
2021-01-19 15:26:28 +00:00
missingPush = true ;
2020-11-23 17:29:19 +00:00
}
2021-01-13 12:28:24 +00:00
if ( hasPush && hasPullRequest ) {
2021-07-27 17:59:59 +01:00
const paths = ( _b = doc . on . push ) === null || _b === void 0 ? void 0 : _b . paths ;
2020-11-25 14:23:21 +00:00
// if you specify paths or paths-ignore you can end up with commits that have no baseline
// if they didn't change any files
// currently we cannot go back through the history and find the most recent baseline
2020-11-23 17:29:19 +00:00
if ( Array . isArray ( paths ) && paths . length > 0 ) {
2020-11-24 17:21:25 +00:00
errors . push ( exports . WorkflowErrors . PathsSpecified ) ;
2020-11-23 17:29:19 +00:00
}
2021-07-27 17:59:59 +01:00
const pathsIgnore = ( _c = doc . on . push ) === null || _c === void 0 ? void 0 : _c [ "paths-ignore" ] ;
2020-11-25 14:23:21 +00:00
if ( Array . isArray ( pathsIgnore ) && pathsIgnore . length > 0 ) {
errors . push ( exports . WorkflowErrors . PathsIgnoreSpecified ) ;
}
2020-11-23 17:29:19 +00:00
}
2021-01-15 08:13:47 +00:00
// if doc.on.pull_request is null that means 'all branches'
// if doc.on.pull_request is undefined that means 'off'
// we only want to check for mismatched branches if pull_request is on.
2021-01-13 12:28:24 +00:00
if ( doc . on . pull _request !== undefined ) {
2021-07-27 17:59:59 +01:00
const push = branchesToArray ( ( _d = doc . on . push ) === null || _d === void 0 ? void 0 : _d . branches ) ;
2021-01-13 12:28:24 +00:00
if ( push !== "**" ) {
2021-07-27 17:59:59 +01:00
const pull _request = branchesToArray ( ( _e = doc . on . pull _request ) === null || _e === void 0 ? void 0 : _e . branches ) ;
2021-01-13 12:28:24 +00:00
if ( pull _request !== "**" ) {
const difference = pull _request . filter ( ( value ) => ! push . some ( ( o ) => patternIsSuperset ( o , value ) ) ) ;
if ( difference . length > 0 ) {
// there are branches in pull_request that may not have a baseline
// because we are not building them on push
errors . push ( exports . WorkflowErrors . MismatchedBranches ) ;
}
}
else if ( push . length > 0 ) {
// push is set up to run on a subset of branches
// and you could open a PR against a branch with no baseline
2020-11-24 17:21:25 +00:00
errors . push ( exports . WorkflowErrors . MismatchedBranches ) ;
2020-11-24 12:43:08 +00:00
}
}
2020-11-23 17:29:19 +00:00
}
}
2021-01-19 15:26:28 +00:00
if ( missingPush ) {
errors . push ( exports . WorkflowErrors . MissingPushHook ) ;
2020-11-23 17:29:19 +00:00
}
return errors ;
}
2021-01-22 09:27:29 +00:00
exports . getWorkflowErrors = getWorkflowErrors ;
async function validateWorkflow ( ) {
2021-01-22 10:58:34 +00:00
let workflow ;
2020-12-01 15:41:04 +00:00
try {
2021-01-22 10:58:34 +00:00
workflow = await getWorkflow ( ) ;
}
catch ( e ) {
2021-09-10 13:53:13 -07:00
return ` error: getWorkflow() failed: ${ String ( e ) } ` ;
2021-01-22 10:58:34 +00:00
}
let workflowErrors ;
try {
workflowErrors = getWorkflowErrors ( workflow ) ;
}
catch ( e ) {
2021-09-10 13:53:13 -07:00
return ` error: getWorkflowErrors() failed: ${ String ( e ) } ` ;
2021-01-22 10:58:34 +00:00
}
if ( workflowErrors . length > 0 ) {
let message ;
2021-01-22 09:04:58 +00:00
try {
2021-01-22 10:58:34 +00:00
message = formatWorkflowErrors ( workflowErrors ) ;
2021-01-22 09:04:58 +00:00
}
catch ( e ) {
2021-09-10 13:53:13 -07:00
return ` error: formatWorkflowErrors() failed: ${ String ( e ) } ` ;
2020-12-01 15:41:04 +00:00
}
2021-01-22 10:58:34 +00:00
core . warning ( message ) ;
2020-12-01 15:41:04 +00:00
}
2021-02-01 16:32:13 +00:00
return formatWorkflowCause ( workflowErrors ) ;
2020-11-24 12:43:08 +00:00
}
2021-01-22 09:27:29 +00:00
exports . validateWorkflow = validateWorkflow ;
2020-11-24 12:43:08 +00:00
function formatWorkflowErrors ( errors ) {
2020-11-24 17:21:25 +00:00
const issuesWere = errors . length === 1 ? "issue was" : "issues were" ;
2020-11-26 15:20:38 +00:00
const errorsList = errors . map ( ( e ) => e . message ) . join ( " " ) ;
2020-11-25 13:06:51 +00:00
return ` ${ errors . length } ${ issuesWere } detected with this workflow: ${ errorsList } ` ;
2020-11-24 12:43:08 +00:00
}
exports . formatWorkflowErrors = formatWorkflowErrors ;
function formatWorkflowCause ( errors ) {
2020-11-26 15:20:38 +00:00
if ( errors . length === 0 ) {
2020-11-24 12:43:08 +00:00
return undefined ;
}
return errors . map ( ( e ) => e . code ) . join ( "," ) ;
2020-11-24 10:51:31 +00:00
}
2020-11-24 12:43:08 +00:00
exports . formatWorkflowCause = formatWorkflowCause ;
2020-11-24 09:51:00 +00:00
async function getWorkflow ( ) {
2020-11-24 09:56:10 +00:00
const relativePath = await getWorkflowPath ( ) ;
2021-09-10 13:53:13 -07:00
const absolutePath = path . join ( ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_WORKSPACE" ) , relativePath ) ;
2021-07-27 22:12:26 +01:00
return yaml . load ( fs . readFileSync ( absolutePath , "utf-8" ) ) ;
2020-11-24 09:51:00 +00:00
}
exports . getWorkflow = getWorkflow ;
2020-09-15 14:00:25 +01:00
/**
* Get the path of the currently executing workflow.
*/
async function getWorkflowPath ( ) {
2021-09-10 13:53:13 -07:00
const repo _nwo = ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_REPOSITORY" ) . split ( "/" ) ;
2020-09-15 14:00:25 +01:00
const owner = repo _nwo [ 0 ] ;
const repo = repo _nwo [ 1 ] ;
2021-09-10 13:53:13 -07:00
const run _id = Number ( ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_RUN_ID" ) ) ;
2020-09-15 14:00:25 +01:00
const apiClient = api . getActionsApiClient ( ) ;
2022-04-07 13:52:29 -07:00
const runsResponse = await apiClient . request ( "GET /repos/:owner/:repo/actions/runs/:run_id?exclude_pull_requests=true" , {
2020-09-15 14:00:25 +01:00
owner ,
repo ,
run _id ,
} ) ;
const workflowUrl = runsResponse . data . workflow _url ;
const workflowResponse = await apiClient . request ( ` GET ${ workflowUrl } ` ) ;
return workflowResponse . data . path ;
}
/**
* Get the workflow run ID.
*/
function getWorkflowRunID ( ) {
2021-09-10 13:53:13 -07:00
const workflowRunID = parseInt ( ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_RUN_ID" ) , 10 ) ;
2020-09-15 14:00:25 +01:00
if ( Number . isNaN ( workflowRunID ) ) {
throw new Error ( "GITHUB_RUN_ID must define a non NaN workflow run ID" ) ;
}
return workflowRunID ;
}
exports . getWorkflowRunID = getWorkflowRunID ;
/**
2021-02-28 01:55:55 -05:00
* Get the analysis key parameter for the current job.
2020-09-15 14:00:25 +01:00
*
* This will combine the workflow path and current job name.
* Computing this the first time requires making requests to
* the github API, but after that the result will be cached.
*/
async function getAnalysisKey ( ) {
const analysisKeyEnvVar = "CODEQL_ACTION_ANALYSIS_KEY" ;
let analysisKey = process . env [ analysisKeyEnvVar ] ;
if ( analysisKey !== undefined ) {
return analysisKey ;
}
const workflowPath = await getWorkflowPath ( ) ;
2021-09-10 13:53:13 -07:00
const jobName = ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_JOB" ) ;
2020-09-15 14:00:25 +01:00
analysisKey = ` ${ workflowPath } : ${ jobName } ` ;
core . exportVariable ( analysisKeyEnvVar , analysisKey ) ;
return analysisKey ;
}
exports . getAnalysisKey = getAnalysisKey ;
2021-05-03 19:36:32 +02:00
async function getAutomationID ( ) {
2021-05-03 19:56:04 +02:00
const analysis _key = await getAnalysisKey ( ) ;
const environment = getRequiredInput ( "matrix" ) ;
return computeAutomationID ( analysis _key , environment ) ;
}
exports . getAutomationID = getAutomationID ;
function computeAutomationID ( analysis _key , environment ) {
let automationID = ` ${ analysis _key } / ` ;
2021-05-03 19:36:32 +02:00
// the id has to be deterministic so we sort the fields
2021-05-05 15:07:47 +02:00
if ( environment !== undefined && environment !== "null" ) {
2021-05-03 19:36:32 +02:00
const environmentObject = JSON . parse ( environment ) ;
for ( const entry of Object . entries ( environmentObject ) . sort ( ) ) {
if ( typeof entry [ 1 ] === "string" ) {
automationID += ` ${ entry [ 0 ] } : ${ entry [ 1 ] } / ` ;
}
else {
// In code scanning we just handle the string values,
// the rest get converted to the empty string
automationID += ` ${ entry [ 0 ] } :/ ` ;
}
}
}
return automationID ;
}
2021-05-03 19:56:04 +02:00
exports . computeAutomationID = computeAutomationID ;
2020-09-15 14:00:25 +01:00
/**
* Get the ref currently being analyzed.
*/
2020-09-15 18:24:57 +01:00
async function getRef ( ) {
2020-09-15 14:00:25 +01:00
// Will be in the form "refs/heads/master" on a push event
// or in the form "refs/pull/N/merge" on a pull_request event
2022-01-25 22:37:02 -05:00
const refInput = ( 0 , exports . getOptionalInput ) ( "ref" ) ;
const shaInput = ( 0 , exports . getOptionalInput ) ( "sha" ) ;
2022-02-28 11:56:11 -08:00
const checkoutPath = ( 0 , exports . getOptionalInput ) ( "checkout_path" ) ||
( 0 , exports . getOptionalInput ) ( "source-root" ) ||
( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_WORKSPACE" ) ;
2022-01-25 22:37:02 -05:00
const hasRefInput = ! ! refInput ;
const hasShaInput = ! ! shaInput ;
// If one of 'ref' or 'sha' are provided, both are required
if ( ( hasRefInput || hasShaInput ) && ! ( hasRefInput && hasShaInput ) ) {
throw new Error ( "Both 'ref' and 'sha' are required if one of them is provided." ) ;
}
const ref = refInput || ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_REF" ) ;
const sha = shaInput || ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_SHA" ) ;
// If the ref is a user-provided input, we have to skip logic
// and assume that it is really where they want to upload the results.
if ( refInput ) {
return refInput ;
}
2020-09-15 18:24:57 +01:00
// For pull request refs we want to detect whether the workflow
// has run `git checkout HEAD^2` to analyze the 'head' ref rather
// than the 'merge' ref. If so, we want to convert the ref that
// we report back.
2020-09-15 14:00:25 +01:00
const pull _ref _regex = /refs\/pull\/(\d+)\/merge/ ;
2021-03-22 15:50:04 +00:00
if ( ! pull _ref _regex . test ( ref ) ) {
return ref ;
}
2022-02-28 11:56:11 -08:00
const head = await ( 0 , exports . getCommitOid ) ( checkoutPath , "HEAD" ) ;
2022-03-30 19:42:05 +01:00
// in actions/checkout@v2+ we can check if git rev-parse HEAD == GITHUB_SHA
2021-03-22 15:09:33 +00:00
// in actions/checkout@v1 this may not be true as it checks out the repository
2021-03-22 09:07:26 +00:00
// using GITHUB_REF. There is a subtle race condition where
// git rev-parse GITHUB_REF != GITHUB_SHA, so we must check
2022-09-24 23:27:01 -04:00
// git rev-parse GITHUB_REF == git rev-parse HEAD instead.
2021-03-25 12:47:36 +00:00
const hasChangedRef = sha !== head &&
2022-02-28 11:56:11 -08:00
( await ( 0 , exports . getCommitOid ) ( checkoutPath , ref . replace ( /^refs\/pull\// , "refs/remotes/pull/" ) ) ) !== head ;
2021-03-22 15:50:04 +00:00
if ( hasChangedRef ) {
2021-03-22 09:07:26 +00:00
const newRef = ref . replace ( pull _ref _regex , "refs/pull/$1/head" ) ;
2021-03-22 15:09:33 +00:00
core . debug ( ` No longer on merge commit, rewriting ref from ${ ref } to ${ newRef } . ` ) ;
2021-03-22 09:07:26 +00:00
return newRef ;
2020-09-15 14:00:25 +01:00
}
else {
return ref ;
}
}
exports . getRef = getRef ;
2022-02-17 11:47:04 -08:00
function getActionsStatus ( error , otherFailureCause ) {
if ( error || otherFailureCause ) {
return error instanceof util _1 . UserError ? "user-error" : "failure" ;
}
else {
return "success" ;
}
}
exports . getActionsStatus = getActionsStatus ;
2020-09-15 14:00:25 +01:00
/**
* Compose a StatusReport.
*
* @param actionName The name of the action, e.g. 'init', 'finish', 'upload-sarif'
* @param status The status. Must be 'success', 'failure', or 'starting'
* @param startedAt The time this action started executing.
* @param cause Cause of failure (only supply if status is 'failure')
* @param exception Exception (only supply if status is 'failure')
*/
async function createStatusReportBase ( actionName , status , actionStartedAt , cause , exception ) {
2022-01-25 22:37:02 -05:00
const commitOid = ( 0 , exports . getOptionalInput ) ( "sha" ) || process . env [ "GITHUB_SHA" ] || "" ;
2020-09-15 18:24:57 +01:00
const ref = await getRef ( ) ;
2020-09-15 14:00:25 +01:00
const workflowRunIDStr = process . env [ "GITHUB_RUN_ID" ] ;
let workflowRunID = - 1 ;
if ( workflowRunIDStr ) {
workflowRunID = parseInt ( workflowRunIDStr , 10 ) ;
}
const workflowName = process . env [ "GITHUB_WORKFLOW" ] || "" ;
const jobName = process . env [ "GITHUB_JOB" ] || "" ;
const analysis _key = await getAnalysisKey ( ) ;
let workflowStartedAt = process . env [ sharedEnv . CODEQL _WORKFLOW _STARTED _AT ] ;
if ( workflowStartedAt === undefined ) {
workflowStartedAt = actionStartedAt . toISOString ( ) ;
core . exportVariable ( sharedEnv . CODEQL _WORKFLOW _STARTED _AT , workflowStartedAt ) ;
}
2022-03-02 15:14:26 -08:00
const runnerOs = ( 0 , util _1 . getRequiredEnvParam ) ( "RUNNER_OS" ) ;
2022-03-17 10:07:29 -07:00
const codeQlCliVersion = ( 0 , util _1 . getCachedCodeQlVersion ) ( ) ;
2022-08-10 09:39:03 +01:00
const actionRef = process . env [ "GITHUB_ACTION_REF" ] ;
2020-09-15 14:00:25 +01:00
const statusReport = {
workflow _run _id : workflowRunID ,
workflow _name : workflowName ,
job _name : jobName ,
analysis _key ,
commit _oid : commitOid ,
ref ,
action _name : actionName ,
2020-11-12 14:18:58 +00:00
action _ref : actionRef ,
2020-09-15 14:00:25 +01:00
action _oid : "unknown" ,
started _at : workflowStartedAt ,
action _started _at : actionStartedAt . toISOString ( ) ,
status ,
2022-03-02 10:57:12 -08:00
runner _os : runnerOs ,
2022-03-17 10:07:29 -07:00
action _version : pkg . version ,
2020-09-15 14:00:25 +01:00
} ;
// Add optional parameters
if ( cause ) {
statusReport . cause = cause ;
}
if ( exception ) {
statusReport . exception = exception ;
}
2022-02-17 11:47:04 -08:00
if ( status === "success" ||
status === "failure" ||
status === "aborted" ||
status === "user-error" ) {
2020-09-15 14:00:25 +01:00
statusReport . completed _at = new Date ( ) . toISOString ( ) ;
}
2020-09-16 11:03:13 +01:00
const matrix = getRequiredInput ( "matrix" ) ;
2020-09-15 14:00:25 +01:00
if ( matrix ) {
statusReport . matrix _vars = matrix ;
}
2022-03-14 08:20:27 -07:00
if ( "RUNNER_ARCH" in process . env ) {
// RUNNER_ARCH is available only in GHES 3.4 and later
2022-03-14 15:44:16 -07:00
// Values other than X86, X64, ARM, or ARM64 are discarded server side
2022-03-14 08:20:27 -07:00
statusReport . runner _arch = process . env [ "RUNNER_ARCH" ] ;
}
2022-03-03 13:06:02 -08:00
if ( runnerOs === "Windows" || runnerOs === "macOS" ) {
statusReport . runner _os _release = os . release ( ) ;
}
2022-03-17 10:07:29 -07:00
if ( codeQlCliVersion !== undefined ) {
2022-03-23 11:32:03 -07:00
statusReport . codeql _version = codeQlCliVersion ;
2022-03-17 10:07:29 -07:00
}
2020-09-15 14:00:25 +01:00
return statusReport ;
}
exports . createStatusReportBase = createStatusReportBase ;
2021-03-16 19:55:55 -07:00
const GENERIC _403 _MSG = "The repo on which this action is running is not opted-in to CodeQL code scanning." ;
2022-02-02 13:51:48 +01:00
const GENERIC _404 _MSG = "Not authorized to use the CodeQL code scanning feature on this repo." ;
2021-03-16 19:55:55 -07:00
const OUT _OF _DATE _MSG = "CodeQL Action is out-of-date. Please upgrade to the latest version of codeql-action." ;
const INCOMPATIBLE _MSG = "CodeQL Action version is incompatible with the code scanning endpoint. Please update to a compatible version of codeql-action." ;
2020-09-15 14:00:25 +01:00
/**
* Send a status report to the code_scanning/analysis/status endpoint.
*
* Optionally checks the response from the API endpoint and sets the action
* as failed if the status report failed. This is only expected to be used
* when sending a 'starting' report.
*
* Returns whether sending the status report was successful of not.
*/
2020-11-19 15:49:46 +00:00
async function sendStatusReport ( statusReport ) {
2022-03-14 15:44:16 -07:00
const gitHubVersion = await api . getGitHubVersionActionsOnly ( ) ;
2022-03-14 08:20:27 -07:00
if ( ( 0 , util _1 . isGitHubGhesVersionBelow ) ( gitHubVersion , "3.2.0" ) ) {
// GHES 3.1 and earlier versions reject unexpected properties, which means
// that they will reject status reports with newly added properties.
// Inhibiting status reporting for GHES < 3.2 avoids such failures.
return true ;
}
2020-09-15 14:00:25 +01:00
const statusReportJSON = JSON . stringify ( statusReport ) ;
core . debug ( ` Sending status report: ${ statusReportJSON } ` ) ;
2022-01-31 18:46:49 -08:00
// If in test mode we don't want to upload the results
2022-04-28 19:07:04 +01:00
if ( ( 0 , util _1 . isInTestMode ) ( ) ) {
2022-01-31 18:46:49 -08:00
core . debug ( "In test mode. Status reports are not uploaded." ) ;
return true ;
}
2021-09-10 13:53:13 -07:00
const nwo = ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_REPOSITORY" ) ;
2020-09-15 14:00:25 +01:00
const [ owner , repo ] = nwo . split ( "/" ) ;
const client = api . getActionsApiClient ( ) ;
2020-11-19 12:36:40 +00:00
try {
await client . request ( "PUT /repos/:owner/:repo/code-scanning/analysis/status" , {
owner ,
repo ,
data : statusReportJSON ,
} ) ;
return true ;
}
catch ( e ) {
2021-03-16 19:55:55 -07:00
console . log ( e ) ;
2021-09-10 13:53:13 -07:00
if ( ( 0 , util _1 . isHTTPError ) ( e ) ) {
2020-11-19 12:36:40 +00:00
switch ( e . status ) {
case 403 :
2021-03-30 16:53:02 +01:00
if ( workflowIsTriggeredByPushEvent ( ) && isDependabotActor ( ) ) {
2021-03-30 13:25:12 +01:00
core . setFailed ( 'Workflows triggered by Dependabot on the "push" event run with read-only access. ' +
2021-03-30 16:53:02 +01:00
"Uploading Code Scanning results requires write access. " +
2021-03-31 11:05:30 +01:00
'To use Code Scanning with Dependabot, please ensure you are using the "pull_request" event for this workflow and avoid triggering on the "push" event for Dependabot branches. ' +
2021-03-30 16:53:02 +01:00
"See https://docs.github.com/en/code-security/secure-coding/configuring-code-scanning#scanning-on-push for more information on how to configure these events." ) ;
2021-03-30 13:25:12 +01:00
}
else {
core . setFailed ( e . message || GENERIC _403 _MSG ) ;
}
2020-11-19 12:36:40 +00:00
return false ;
case 404 :
2021-03-16 19:55:55 -07:00
core . setFailed ( GENERIC _404 _MSG ) ;
2020-11-19 12:36:40 +00:00
return false ;
case 422 :
// schema incompatibility when reporting status
2020-11-19 13:07:55 +00:00
// this means that this action version is no longer compatible with the API
2020-11-19 15:49:46 +00:00
// we still want to continue as it is likely the analysis endpoint will work
2021-09-10 13:53:13 -07:00
if ( ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_SERVER_URL" ) !== util _1 . GITHUB _DOTCOM _URL ) {
2021-03-16 19:55:55 -07:00
core . debug ( INCOMPATIBLE _MSG ) ;
2020-11-19 13:07:55 +00:00
}
else {
2021-03-16 19:55:55 -07:00
core . debug ( OUT _OF _DATE _MSG ) ;
2020-11-19 13:07:55 +00:00
}
2020-11-19 15:49:46 +00:00
return true ;
2020-11-19 12:36:40 +00:00
}
2020-09-15 14:00:25 +01:00
}
2020-11-19 12:36:40 +00:00
// something else has gone wrong and the request/response will be logged by octokit
2020-11-19 15:49:46 +00:00
// it's possible this is a transient error and we should continue scanning
2021-02-28 01:55:55 -05:00
core . error ( "An unexpected error occurred when sending code scanning status report." ) ;
2020-11-19 15:49:46 +00:00
return true ;
2020-09-15 14:00:25 +01:00
}
}
exports . sendStatusReport = sendStatusReport ;
2022-09-07 09:45:19 +02:00
function workflowEventName ( ) {
// If the original event is dynamic CODESCANNING_EVENT_NAME will contain the right info (push/pull_request)
if ( process . env [ "GITHUB_EVENT_NAME" ] === "dynamic" ) {
const value = process . env [ "CODESCANNING_EVENT_NAME" ] ;
if ( value === undefined || value . length === 0 ) {
return process . env [ "GITHUB_EVENT_NAME" ] ;
}
return value ;
}
return process . env [ "GITHUB_EVENT_NAME" ] ;
}
exports . workflowEventName = workflowEventName ;
2021-03-30 16:53:02 +01:00
// Was the workflow run triggered by a `push` event, for example as opposed to a `pull_request` event.
function workflowIsTriggeredByPushEvent ( ) {
2022-09-07 09:45:19 +02:00
return workflowEventName ( ) === "push" ;
2021-03-30 16:53:02 +01:00
}
2021-03-30 13:25:12 +01:00
// Is dependabot the actor that triggered the current workflow run.
function isDependabotActor ( ) {
return process . env [ "GITHUB_ACTOR" ] === "dependabot[bot]" ;
}
2020-11-12 14:18:58 +00:00
// Is the current action executing a local copy (i.e. we're running a workflow on the codeql-action repo itself)
// as opposed to running a remote action (i.e. when another repo references us)
function isRunningLocalAction ( ) {
const relativeScriptPath = getRelativeScriptPath ( ) ;
return ( relativeScriptPath . startsWith ( ".." ) || path . isAbsolute ( relativeScriptPath ) ) ;
}
exports . isRunningLocalAction = isRunningLocalAction ;
2020-11-20 11:35:59 +01:00
// Get the location where the action is running from.
2020-11-12 14:18:58 +00:00
// This can be used to get the actions name or tell if we're running a local action.
function getRelativeScriptPath ( ) {
2021-09-10 13:53:13 -07:00
const runnerTemp = ( 0 , util _1 . getRequiredEnvParam ) ( "RUNNER_TEMP" ) ;
2020-11-12 14:18:58 +00:00
const actionsDirectory = path . join ( path . dirname ( runnerTemp ) , "_actions" ) ;
return path . relative ( actionsDirectory , _ _filename ) ;
}
exports . getRelativeScriptPath = getRelativeScriptPath ;
2021-06-22 13:05:12 +01:00
// Reads the contents of GITHUB_EVENT_PATH as a JSON object
function getWorkflowEvent ( ) {
2021-09-10 13:53:13 -07:00
const eventJsonFile = ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_EVENT_PATH" ) ;
2021-06-22 13:05:12 +01:00
try {
return JSON . parse ( fs . readFileSync ( eventJsonFile , "utf-8" ) ) ;
}
catch ( e ) {
throw new Error ( ` Unable to read workflow event JSON from ${ eventJsonFile } : ${ e } ` ) ;
}
}
2022-08-25 10:57:08 +01:00
function removeRefsHeadsPrefix ( ref ) {
return ref . startsWith ( "refs/heads/" ) ? ref . slice ( "refs/heads/" . length ) : ref ;
}
2021-06-22 13:05:12 +01:00
// Is the version of the repository we are currently analyzing from the default branch,
// or alternatively from another branch or a pull request.
async function isAnalyzingDefaultBranch ( ) {
2021-07-27 17:59:59 +01:00
var _a ;
2021-06-22 13:05:12 +01:00
// Get the current ref and trim and refs/heads/ prefix
let currentRef = await getRef ( ) ;
2022-08-25 10:57:08 +01:00
currentRef = removeRefsHeadsPrefix ( currentRef ) ;
2021-06-22 13:05:12 +01:00
const event = getWorkflowEvent ( ) ;
2022-08-25 10:57:08 +01:00
let defaultBranch = ( _a = event === null || event === void 0 ? void 0 : event . repository ) === null || _a === void 0 ? void 0 : _a . default _branch ;
if ( process . env . GITHUB _EVENT _NAME === "schedule" ) {
defaultBranch = removeRefsHeadsPrefix ( ( 0 , util _1 . getRequiredEnvParam ) ( "GITHUB_REF" ) ) ;
}
2021-06-22 13:05:12 +01:00
return currentRef === defaultBranch ;
}
exports . isAnalyzingDefaultBranch = isAnalyzingDefaultBranch ;
2022-08-02 12:41:08 +02:00
async function printDebugLogs ( config ) {
for ( const language of config . languages ) {
const databaseDirectory = ( 0 , util _1 . getCodeQLDatabasePath ) ( config , language ) ;
const logsDirectory = path . join ( databaseDirectory , "log" ) ;
if ( ! ( 0 , util _1 . doesDirectoryExist ) ( logsDirectory ) ) {
core . info ( ` Directory ${ logsDirectory } does not exist. ` ) ;
continue ; // Skip this language database.
}
const walkLogFiles = ( dir ) => {
const entries = fs . readdirSync ( dir , { withFileTypes : true } ) ;
if ( entries . length === 0 ) {
core . info ( ` No debug logs found at directory ${ logsDirectory } . ` ) ;
}
for ( const entry of entries ) {
if ( entry . isFile ( ) ) {
2022-08-11 13:58:01 +02:00
const absolutePath = path . resolve ( dir , entry . name ) ;
core . startGroup ( ` CodeQL Debug Logs - ${ language } - ${ entry . name } from file at path ${ absolutePath } ` ) ;
process . stdout . write ( fs . readFileSync ( absolutePath ) ) ;
2022-08-02 12:41:08 +02:00
core . endGroup ( ) ;
}
else if ( entry . isDirectory ( ) ) {
walkLogFiles ( path . resolve ( dir , entry . name ) ) ;
}
}
} ;
walkLogFiles ( logsDirectory ) ;
}
}
exports . printDebugLogs = printDebugLogs ;
2020-09-15 14:00:25 +01:00
//# sourceMappingURL=actions-util.js.map