2020-04-28 16:46:47 +02: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 ;
2023-01-18 20:00:33 +00:00
var desc = Object . getOwnPropertyDescriptor ( m , k ) ;
if ( ! desc || ( "get" in desc ? ! m . _ _esModule : desc . writable || desc . configurable ) ) {
desc = { enumerable : true , get : function ( ) { return m [ k ] ; } } ;
}
Object . defineProperty ( o , k2 , desc ) ;
2021-07-27 17:59:59 +01:00
} ) : ( 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 ;
} ) ;
2024-12-03 18:39:38 +00:00
var _ _importStar = ( this && this . _ _importStar ) || ( function ( ) {
var ownKeys = function ( o ) {
ownKeys = Object . getOwnPropertyNames || function ( o ) {
var ar = [ ] ;
for ( var k in o ) if ( Object . prototype . hasOwnProperty . call ( o , k ) ) ar [ ar . length ] = k ;
return ar ;
} ;
return ownKeys ( o ) ;
} ;
return function ( mod ) {
if ( mod && mod . _ _esModule ) return mod ;
var result = { } ;
if ( mod != null ) for ( var k = ownKeys ( mod ) , i = 0 ; i < k . length ; i ++ ) if ( k [ i ] !== "default" ) _ _createBinding ( result , mod , k [ i ] ) ;
_ _setModuleDefault ( result , mod ) ;
return result ;
} ;
} ) ( ) ;
2021-12-08 12:00:54 -08:00
var _ _importDefault = ( this && this . _ _importDefault ) || function ( mod ) {
return ( mod && mod . _ _esModule ) ? mod : { "default" : mod } ;
} ;
2020-04-28 16:46:47 +02:00
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
2024-06-25 09:21:42 +00:00
exports . BuildMode = exports . ConfigurationError = exports . HTTPError = exports . DisallowedAPIVersionReason = exports . GitHubVariant = exports . DEFAULT _DEBUG _DATABASE _NAME = exports . DEFAULT _DEBUG _ARTIFACT _NAME = exports . GITHUB _DOTCOM _URL = void 0 ;
exports . getExtraOptionsEnvParam = getExtraOptionsEnvParam ;
exports . getToolNames = getToolNames ;
exports . withTmpDir = withTmpDir ;
exports . getMemoryFlagValueForPlatform = getMemoryFlagValueForPlatform ;
exports . getMemoryFlagValue = getMemoryFlagValue ;
exports . getMemoryFlag = getMemoryFlag ;
exports . getAddSnippetsFlag = getAddSnippetsFlag ;
exports . getThreadsFlagValue = getThreadsFlagValue ;
exports . getCgroupCpuCountFromCpus = getCgroupCpuCountFromCpus ;
exports . getThreadsFlag = getThreadsFlag ;
exports . getCodeQLDatabasePath = getCodeQLDatabasePath ;
exports . parseGitHubUrl = parseGitHubUrl ;
exports . checkGitHubVersionInRange = checkGitHubVersionInRange ;
exports . apiVersionInRange = apiVersionInRange ;
exports . assertNever = assertNever ;
exports . initializeEnvironment = initializeEnvironment ;
exports . getRequiredEnvParam = getRequiredEnvParam ;
exports . isHTTPError = isHTTPError ;
exports . cacheCodeQlVersion = cacheCodeQlVersion ;
exports . getCachedCodeQlVersion = getCachedCodeQlVersion ;
exports . codeQlVersionAtLeast = codeQlVersionAtLeast ;
exports . bundleDb = bundleDb ;
exports . delay = delay ;
exports . isGoodVersion = isGoodVersion ;
exports . isInTestMode = isInTestMode ;
2025-05-14 14:08:58 +01:00
exports . getTestingEnvironment = getTestingEnvironment ;
2024-06-25 09:21:42 +00:00
exports . doesDirectoryExist = doesDirectoryExist ;
exports . listFolder = listFolder ;
exports . tryGetFolderBytes = tryGetFolderBytes ;
exports . withTimeout = withTimeout ;
exports . checkForTimeout = checkForTimeout ;
exports . isHostedRunner = isHostedRunner ;
exports . parseMatrixInput = parseMatrixInput ;
exports . fixInvalidNotifications = fixInvalidNotifications ;
exports . fixInvalidNotificationsInFile = fixInvalidNotificationsInFile ;
exports . wrapError = wrapError ;
exports . getErrorMessage = getErrorMessage ;
exports . prettyPrintPack = prettyPrintPack ;
exports . checkDiskUsage = checkDiskUsage ;
exports . checkActionVersion = checkActionVersion ;
2024-07-31 17:56:06 -07:00
exports . cloneObject = cloneObject ;
2024-08-23 09:17:22 -07:00
exports . checkSipEnablement = checkSipEnablement ;
2024-10-02 15:45:55 +01:00
exports . cleanUpGlob = cleanUpGlob ;
2024-11-18 11:21:11 -08:00
exports . isBinaryAccessible = isBinaryAccessible ;
2020-05-05 11:59:05 +01:00
const fs = _ _importStar ( require ( "fs" ) ) ;
const os = _ _importStar ( require ( "os" ) ) ;
2020-04-28 16:46:47 +02:00
const path = _ _importStar ( require ( "path" ) ) ;
2022-09-23 11:51:06 +01:00
const util _1 = require ( "util" ) ;
2020-11-26 17:54:34 +00:00
const core = _ _importStar ( require ( "@actions/core" ) ) ;
2024-08-20 16:04:03 -07:00
const exec = _ _importStar ( require ( "@actions/exec/lib/exec" ) ) ;
2024-12-19 14:21:06 +00:00
const io = _ _importStar ( require ( "@actions/io" ) ) ;
2023-08-07 16:00:32 +01:00
const check _disk _space _1 = _ _importDefault ( require ( "check-disk-space" ) ) ;
2021-12-08 12:00:54 -08:00
const del _1 = _ _importDefault ( require ( "del" ) ) ;
2022-09-23 11:51:06 +01:00
const get _folder _size _1 = _ _importDefault ( require ( "get-folder-size" ) ) ;
2024-10-02 12:34:57 -04:00
const yaml = _ _importStar ( require ( "js-yaml" ) ) ;
2020-11-26 17:54:34 +00:00
const semver = _ _importStar ( require ( "semver" ) ) ;
2020-11-30 16:33:38 +00:00
const apiCompatibility = _ _importStar ( require ( "./api-compatibility.json" ) ) ;
2023-07-06 12:24:38 +01:00
const environment _1 = require ( "./environment" ) ;
2021-12-09 13:43:57 +00:00
/**
* Specifies bundle versions that are known to be broken
* and will not be used if found in the toolcache.
*/
const BROKEN _VERSIONS = [ "0.0.0-20211207" ] ;
2020-07-30 13:00:35 +01:00
/**
2020-08-25 16:19:15 +01:00
* The URL for github.com.
2020-07-30 13:00:35 +01:00
*/
2020-08-25 16:19:15 +01:00
exports . GITHUB _DOTCOM _URL = "https://github.com" ;
2021-10-28 14:15:22 +01:00
/**
2022-01-07 13:11:51 +00:00
* Default name of the debugging artifact.
2021-10-28 14:15:22 +01:00
*/
2022-01-07 13:11:51 +00:00
exports . DEFAULT _DEBUG _ARTIFACT _NAME = "debug-artifacts" ;
/**
* Default name of the database in the debugging artifact.
*/
exports . DEFAULT _DEBUG _DATABASE _NAME = "db" ;
2023-09-05 13:14:47 +02:00
/**
* The default fraction of the total RAM above 8 GB that should be reserved for the system.
*/
const DEFAULT _RESERVED _RAM _SCALING _FACTOR = 0.05 ;
2023-09-18 16:00:59 +01:00
/**
* The minimum amount of memory imposed by a cgroup limit that we will consider. Memory limits below
* this amount are ignored.
*/
const MINIMUM _CGROUP _MEMORY _LIMIT _BYTES = 1024 * 1024 ;
2020-08-10 09:25:14 +02:00
/**
* Get the extra options for the codeql commands.
*/
function getExtraOptionsEnvParam ( ) {
2020-09-14 10:44:43 +01:00
const varName = "CODEQL_ACTION_EXTRA_OPTIONS" ;
2020-08-10 09:25:14 +02:00
const raw = process . env [ varName ] ;
if ( raw === undefined || raw . length === 0 ) {
return { } ;
}
try {
2024-10-02 12:34:57 -04:00
return yaml . load ( raw ) ;
2020-08-10 09:25:14 +02:00
}
2023-04-06 17:04:21 +01:00
catch ( unwrappedError ) {
const error = wrapError ( unwrappedError ) ;
2024-02-08 09:20:03 -08:00
throw new ConfigurationError ( ` ${ varName } environment variable is set, but does not contain valid JSON: ${ error . message } ` ) ;
2020-08-10 09:25:14 +02:00
}
}
2020-04-28 11:29:10 -07:00
/**
* Get the array of all the tool names contained in the given sarif contents.
*
* Returns an array of unique string tool names.
*/
2022-01-12 15:26:34 -08:00
function getToolNames ( sarif ) {
2020-04-28 11:29:10 -07:00
const toolNames = { } ;
for ( const run of sarif . runs || [ ] ) {
const tool = run . tool || { } ;
const driver = tool . driver || { } ;
if ( typeof driver . name === "string" && driver . name . length > 0 ) {
toolNames [ driver . name ] = true ;
}
}
return Object . keys ( toolNames ) ;
}
2020-05-05 11:59:05 +01:00
// Creates a random temporary directory, runs the given body, and then deletes the directory.
// Mostly intended for use within tests.
async function withTmpDir ( body ) {
2020-09-14 10:44:43 +01:00
const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "codeql-action-" ) ) ;
2022-06-17 14:07:36 -07:00
const result = await body ( tmpDir ) ;
2021-12-08 12:00:54 -08:00
await ( 0 , del _1 . default ) ( tmpDir , { force : true } ) ;
2020-05-05 17:32:58 +01:00
return result ;
2020-05-05 11:59:05 +01:00
}
2021-02-16 15:04:38 -08:00
/**
* Gets an OS-specific amount of memory (in MB) to reserve for OS processes
* when the user doesn't explicitly specify a memory setting.
* This is a heuristic to avoid OOM errors (exit code 137 / SIGKILL)
* from committing too much of the available memory to CodeQL.
* @returns number
*/
2023-09-05 14:30:56 +02:00
function getSystemReservedMemoryMegaBytes ( totalMemoryMegaBytes , platform ) {
2021-02-16 15:04:38 -08:00
// Windows needs more memory for OS processes.
2023-07-21 17:35:34 +01:00
const fixedAmount = 1024 * ( platform === "win32" ? 1.5 : 1 ) ;
2023-09-05 14:30:56 +02:00
// Reserve an additional percentage of the amount of memory above 8 GB, since the amount used by
// the kernel for page tables scales with the size of physical memory.
const scaledAmount = getReservedRamScaleFactor ( ) * Math . max ( totalMemoryMegaBytes - 8 * 1024 , 0 ) ;
return fixedAmount + scaledAmount ;
2021-02-16 15:04:38 -08:00
}
2023-09-05 13:14:47 +02:00
function getReservedRamScaleFactor ( ) {
const envVar = Number . parseInt ( process . env [ environment _1 . EnvVar . SCALING _RESERVED _RAM _PERCENTAGE ] || "" , 10 ) ;
if ( envVar < 0 || envVar > 100 || Number . isNaN ( envVar ) ) {
return DEFAULT _RESERVED _RAM _SCALING _FACTOR ;
}
return envVar / 100 ;
}
2020-06-22 17:17:25 +02:00
/**
2021-10-28 15:09:59 -07:00
* Get the value of the codeql `--ram` flag as configured by the `ram` input.
* If no value was specified, the total available memory will be used minus a
* threshold reserved for the OS.
2020-06-22 17:17:25 +02:00
*
2021-10-28 15:09:59 -07:00
* @returns {number} the amount of RAM to use, in megabytes
2020-06-22 17:17:25 +02:00
*/
2023-09-05 14:30:56 +02:00
function getMemoryFlagValueForPlatform ( userInput , totalMemoryBytes , platform ) {
2020-06-22 17:17:25 +02:00
let memoryToUseMegaBytes ;
2020-09-01 14:13:10 +01:00
if ( userInput ) {
memoryToUseMegaBytes = Number ( userInput ) ;
2020-06-22 17:17:25 +02:00
if ( Number . isNaN ( memoryToUseMegaBytes ) || memoryToUseMegaBytes <= 0 ) {
2024-02-08 09:20:03 -08:00
throw new ConfigurationError ( ` Invalid RAM setting " ${ userInput } ", specified. ` ) ;
2020-06-22 17:17:25 +02:00
}
}
else {
const totalMemoryMegaBytes = totalMemoryBytes / ( 1024 * 1024 ) ;
2023-09-05 14:30:56 +02:00
const reservedMemoryMegaBytes = getSystemReservedMemoryMegaBytes ( totalMemoryMegaBytes , platform ) ;
2021-02-16 15:04:38 -08:00
memoryToUseMegaBytes = totalMemoryMegaBytes - reservedMemoryMegaBytes ;
2020-06-22 17:17:25 +02:00
}
2021-10-28 15:09:59 -07:00
return Math . floor ( memoryToUseMegaBytes ) ;
}
2023-09-15 18:09:37 +01:00
/**
2023-09-15 18:17:13 +01:00
* Get the total amount of memory available to the Action, taking into account constraints imposed
* by cgroups on Linux.
2023-09-15 18:09:37 +01:00
*/
2023-09-18 16:00:59 +01:00
function getTotalMemoryBytes ( logger ) {
const limits = [ os . totalmem ( ) ] ;
2023-09-15 18:17:13 +01:00
if ( os . platform ( ) === "linux" ) {
2023-09-18 16:00:59 +01:00
limits . push ( ... [
2023-09-15 18:23:25 +01:00
"/sys/fs/cgroup/memory/memory.limit_in_bytes" ,
"/sys/fs/cgroup/memory.max" ,
2023-09-18 16:00:59 +01:00
]
. map ( ( file ) => getCgroupMemoryLimitBytes ( file , logger ) )
. filter ( ( limit ) => limit !== undefined )
. map ( ( limit ) => limit ) ) ;
}
const limit = Math . min ( ... limits ) ;
logger . debug ( ` While resolving RAM, determined that the total memory available to the Action is ${ limit / ( 1024 * 1024 ) } MiB. ` ) ;
return limit ;
}
/**
* Gets the number of bytes of available memory specified by the cgroup limit file at the given path.
*
* May be greater than the total memory reported by the operating system if there is no cgroup limit.
*/
function getCgroupMemoryLimitBytes ( limitFile , logger ) {
if ( ! fs . existsSync ( limitFile ) ) {
logger . debug ( ` While resolving RAM, did not find a cgroup memory limit at ${ limitFile } . ` ) ;
return undefined ;
}
const limit = Number ( fs . readFileSync ( limitFile , "utf8" ) ) ;
if ( ! Number . isInteger ( limit ) ) {
logger . debug ( ` While resolving RAM, ignored the file ${ limitFile } that may contain a cgroup memory limit ` +
"as this file did not contain an integer." ) ;
return undefined ;
}
const displayLimit = ` ${ Math . floor ( limit / ( 1024 * 1024 ) ) } MiB ` ;
2023-09-27 13:56:20 +01:00
if ( limit > os . totalmem ( ) ) {
logger . debug ( ` While resolving RAM, ignored the file ${ limitFile } that may contain a cgroup memory limit as ` +
` its contents ${ displayLimit } were greater than the total amount of system memory. ` ) ;
return undefined ;
}
2023-09-18 16:00:59 +01:00
if ( limit < MINIMUM _CGROUP _MEMORY _LIMIT _BYTES ) {
logger . info ( ` While resolving RAM, ignored a cgroup limit of ${ displayLimit } in ${ limitFile } as it was below ${ MINIMUM _CGROUP _MEMORY _LIMIT _BYTES / ( 1024 * 1024 ) } MiB. ` ) ;
return undefined ;
2023-09-15 18:09:37 +01:00
}
2023-09-18 16:00:59 +01:00
logger . info ( ` While resolving RAM, found a cgroup limit of ${ displayLimit } in ${ limitFile } . ` ) ;
return limit ;
2023-09-15 18:09:37 +01:00
}
2023-07-21 17:35:34 +01:00
/**
* Get the value of the codeql `--ram` flag as configured by the `ram` input.
* If no value was specified, the total available memory will be used minus a
* threshold reserved for the OS.
*
* @returns {number} the amount of RAM to use, in megabytes
*/
2023-09-18 12:43:52 +01:00
function getMemoryFlagValue ( userInput , logger ) {
2023-09-18 16:00:59 +01:00
return getMemoryFlagValueForPlatform ( userInput , getTotalMemoryBytes ( logger ) , process . platform ) ;
2023-07-21 17:35:34 +01:00
}
2021-10-28 15:09:59 -07:00
/**
* Get the codeql `--ram` flag as configured by the `ram` input. If no value was
* specified, the total available memory will be used minus a threshold
* reserved for the OS.
*
* @returns string
*/
2023-09-18 12:43:52 +01:00
function getMemoryFlag ( userInput , logger ) {
const megabytes = getMemoryFlagValue ( userInput , logger ) ;
2023-07-07 12:13:57 +01:00
return ` --ram= ${ megabytes } ` ;
2020-06-22 17:17:25 +02:00
}
2020-09-10 17:18:02 +01:00
/**
* Get the codeql flag to specify whether to add code snippets to the sarif file.
*
* @returns string
*/
function getAddSnippetsFlag ( userInput ) {
if ( typeof userInput === "string" ) {
// have to process specifically because any non-empty string is truthy
userInput = userInput . toLowerCase ( ) === "true" ;
}
return userInput ? "--sarif-add-snippets" : "--no-sarif-add-snippets" ;
}
2020-06-22 17:17:25 +02:00
/**
2021-10-28 15:09:59 -07:00
* Get the value of the codeql `--threads` flag specified for the `threads`
* input. If no value was specified, all available threads will be used.
2020-08-13 14:25:10 +01:00
*
* The value will be capped to the number of available CPUs.
2020-06-22 17:17:25 +02:00
*
2021-10-28 15:09:59 -07:00
* @returns {number}
2020-06-22 17:17:25 +02:00
*/
2021-10-28 15:09:59 -07:00
function getThreadsFlagValue ( userInput , logger ) {
2020-08-13 14:25:10 +01:00
let numThreads ;
2024-01-23 06:50:06 -08:00
const maxThreadsCandidates = [ os . cpus ( ) . length ] ;
if ( os . platform ( ) === "linux" ) {
maxThreadsCandidates . push ( ... [ "/sys/fs/cgroup/cpuset.cpus.effective" , "/sys/fs/cgroup/cpuset.cpus" ]
. map ( ( file ) => getCgroupCpuCountFromCpus ( file , logger ) )
. filter ( ( count ) => count !== undefined && count > 0 )
. map ( ( count ) => count ) ) ;
maxThreadsCandidates . push ( ... [ "/sys/fs/cgroup/cpu.max" ]
. map ( ( file ) => getCgroupCpuCountFromCpuMax ( file , logger ) )
. filter ( ( count ) => count !== undefined && count > 0 )
. map ( ( count ) => count ) ) ;
}
const maxThreads = Math . min ( ... maxThreadsCandidates ) ;
2020-09-01 14:13:10 +01:00
if ( userInput ) {
numThreads = Number ( userInput ) ;
2020-06-22 21:39:09 +02:00
if ( Number . isNaN ( numThreads ) ) {
2024-02-08 09:20:03 -08:00
throw new ConfigurationError ( ` Invalid threads setting " ${ userInput } ", specified. ` ) ;
2020-06-22 17:17:25 +02:00
}
if ( numThreads > maxThreads ) {
2020-09-01 14:13:10 +01:00
logger . info ( ` Clamping desired number of threads ( ${ numThreads } ) to max available ( ${ maxThreads } ). ` ) ;
2020-06-22 17:17:25 +02:00
numThreads = maxThreads ;
}
2020-06-22 21:39:09 +02:00
const minThreads = - maxThreads ;
if ( numThreads < minThreads ) {
2020-09-01 14:13:10 +01:00
logger . info ( ` Clamping desired number of free threads ( ${ numThreads } ) to max available ( ${ minThreads } ). ` ) ;
2020-06-22 21:39:09 +02:00
numThreads = minThreads ;
}
2020-06-22 17:17:25 +02:00
}
2020-08-13 14:25:10 +01:00
else {
// Default to using all threads
2020-08-17 12:46:55 +01:00
numThreads = maxThreads ;
2020-08-13 14:25:10 +01:00
}
2021-10-28 15:09:59 -07:00
return numThreads ;
}
2024-01-23 06:50:06 -08:00
/**
* Gets the number of available cores specified by the cgroup cpu.max file at the given path.
* Format of file: two values, the limit and the duration (period). If the limit is "max" then
* we return undefined and do not use this file to determine CPU limits.
*/
function getCgroupCpuCountFromCpuMax ( cpuMaxFile , logger ) {
if ( ! fs . existsSync ( cpuMaxFile ) ) {
logger . debug ( ` While resolving threads, did not find a cgroup CPU file at ${ cpuMaxFile } . ` ) ;
return undefined ;
}
const cpuMaxString = fs . readFileSync ( cpuMaxFile , "utf-8" ) ;
const cpuMaxStringSplit = cpuMaxString . split ( " " ) ;
if ( cpuMaxStringSplit . length !== 2 ) {
logger . debug ( ` While resolving threads, did not use cgroup CPU file at ${ cpuMaxFile } because it contained ${ cpuMaxStringSplit . length } value(s) rather than the two expected. ` ) ;
return undefined ;
}
const cpuLimit = cpuMaxStringSplit [ 0 ] ;
if ( cpuLimit === "max" ) {
return undefined ;
}
const duration = cpuMaxStringSplit [ 1 ] ;
const cpuCount = Math . floor ( parseInt ( cpuLimit ) / parseInt ( duration ) ) ;
logger . info ( ` While resolving threads, found a cgroup CPU file with ${ cpuCount } CPUs in ${ cpuMaxFile } . ` ) ;
return cpuCount ;
}
/**
* Gets the number of available cores listed in the cgroup cpuset.cpus file at the given path.
*/
function getCgroupCpuCountFromCpus ( cpusFile , logger ) {
if ( ! fs . existsSync ( cpusFile ) ) {
logger . debug ( ` While resolving threads, did not find a cgroup CPUs file at ${ cpusFile } . ` ) ;
return undefined ;
}
let cpuCount = 0 ;
// Comma-separated numbers and ranges, for eg. 0-1,3
2024-02-15 14:31:37 +00:00
const cpusString = fs . readFileSync ( cpusFile , "utf-8" ) . trim ( ) ;
if ( cpusString . length === 0 ) {
return undefined ;
}
2024-01-23 06:50:06 -08:00
for ( const token of cpusString . split ( "," ) ) {
if ( ! token . includes ( "-" ) ) {
// Not a range
++ cpuCount ;
}
else {
const cpuStartIndex = parseInt ( token . split ( "-" ) [ 0 ] ) ;
const cpuEndIndex = parseInt ( token . split ( "-" ) [ 1 ] ) ;
cpuCount += cpuEndIndex - cpuStartIndex + 1 ;
}
}
logger . info ( ` While resolving threads, found a cgroup CPUs file with ${ cpuCount } CPUs in ${ cpusFile } . ` ) ;
return cpuCount ;
}
2021-10-28 15:09:59 -07:00
/**
* Get the codeql `--threads` flag specified for the `threads` input.
* If no value was specified, all available threads will be used.
*
* The value will be capped to the number of available CPUs.
*
* @returns string
*/
function getThreadsFlag ( userInput , logger ) {
return ` --threads= ${ getThreadsFlagValue ( userInput , logger ) } ` ;
2020-06-22 17:17:25 +02:00
}
2020-08-24 12:53:09 +01:00
/**
* Get the path where the CodeQL database for the given language lives.
*/
2021-05-17 10:35:09 +01:00
function getCodeQLDatabasePath ( config , language ) {
return path . resolve ( config . dbLocation , language ) ;
2020-08-24 12:53:09 +01:00
}
2020-09-28 18:28:46 +01:00
/**
* Parses user input of a github.com or GHES URL to a canonical form.
* Removes any API prefix or suffix if one is present.
*/
2021-02-28 01:55:55 -05:00
function parseGitHubUrl ( inputUrl ) {
2020-09-28 18:28:46 +01:00
const originalUrl = inputUrl ;
if ( inputUrl . indexOf ( "://" ) === - 1 ) {
inputUrl = ` https:// ${ inputUrl } ` ;
}
if ( ! inputUrl . startsWith ( "http://" ) && ! inputUrl . startsWith ( "https://" ) ) {
2024-02-08 09:20:03 -08:00
throw new ConfigurationError ( ` " ${ originalUrl } " is not a http or https URL ` ) ;
2020-09-28 18:28:46 +01:00
}
let url ;
try {
url = new URL ( inputUrl ) ;
}
2024-08-05 19:22:26 +01:00
catch {
2024-02-08 09:20:03 -08:00
throw new ConfigurationError ( ` " ${ originalUrl } " is not a valid URL ` ) ;
2020-09-28 18:28:46 +01:00
}
// If we detect this is trying to be to github.com
// then return with a fixed canonical URL.
if ( url . hostname === "github.com" || url . hostname === "api.github.com" ) {
2020-10-05 16:44:43 +01:00
return exports . GITHUB _DOTCOM _URL ;
2020-09-28 18:28:46 +01:00
}
// Remove the API prefix if it's present
if ( url . pathname . indexOf ( "/api/v3" ) !== - 1 ) {
url . pathname = url . pathname . substring ( 0 , url . pathname . indexOf ( "/api/v3" ) ) ;
}
// Also consider subdomain isolation on GHES
if ( url . hostname . startsWith ( "api." ) ) {
url . hostname = url . hostname . substring ( 4 ) ;
}
// Normalise path to having a trailing slash for consistency
if ( ! url . pathname . endsWith ( "/" ) ) {
url . pathname = ` ${ url . pathname } / ` ;
}
return url . toString ( ) ;
}
2020-11-26 17:54:34 +00:00
const CODEQL _ACTION _WARNED _ABOUT _VERSION _ENV _VAR = "CODEQL_ACTION_WARNED_ABOUT_VERSION" ;
let hasBeenWarnedAboutVersion = false ;
2021-02-15 09:29:10 +00:00
var GitHubVariant ;
( function ( GitHubVariant ) {
GitHubVariant [ GitHubVariant [ "DOTCOM" ] = 0 ] = "DOTCOM" ;
GitHubVariant [ GitHubVariant [ "GHES" ] = 1 ] = "GHES" ;
2024-01-08 13:28:35 +00:00
GitHubVariant [ GitHubVariant [ "GHE_DOTCOM" ] = 2 ] = "GHE_DOTCOM" ;
2023-07-13 11:17:33 +01:00
} ) ( GitHubVariant || ( exports . GitHubVariant = GitHubVariant = { } ) ) ;
2022-11-14 16:37:48 +00:00
function checkGitHubVersionInRange ( version , logger ) {
2021-02-15 09:29:10 +00:00
if ( hasBeenWarnedAboutVersion || version . type !== GitHubVariant . GHES ) {
2020-11-26 17:54:34 +00:00
return ;
}
const disallowedAPIVersionReason = apiVersionInRange ( version . version , apiCompatibility . minimumVersion , apiCompatibility . maximumVersion ) ;
if ( disallowedAPIVersionReason === DisallowedAPIVersionReason . ACTION _TOO _OLD ) {
2022-11-14 16:37:48 +00:00
logger . warning ( ` The CodeQL Action version you are using is too old to be compatible with GitHub Enterprise ${ version . version } . If you experience issues, please upgrade to a more recent version of the CodeQL Action. ` ) ;
2020-11-26 17:54:34 +00:00
}
if ( disallowedAPIVersionReason === DisallowedAPIVersionReason . ACTION _TOO _NEW ) {
2022-11-14 16:37:48 +00:00
logger . warning ( ` GitHub Enterprise ${ version . version } is too old to be compatible with this version of the CodeQL Action. If you experience issues, please upgrade to a more recent version of GitHub Enterprise or use an older version of the CodeQL Action. ` ) ;
2020-11-26 17:54:34 +00:00
}
hasBeenWarnedAboutVersion = true ;
2022-11-14 16:37:48 +00:00
core . exportVariable ( CODEQL _ACTION _WARNED _ABOUT _VERSION _ENV _VAR , true ) ;
2020-11-26 17:54:34 +00:00
}
var DisallowedAPIVersionReason ;
( function ( DisallowedAPIVersionReason ) {
DisallowedAPIVersionReason [ DisallowedAPIVersionReason [ "ACTION_TOO_OLD" ] = 0 ] = "ACTION_TOO_OLD" ;
DisallowedAPIVersionReason [ DisallowedAPIVersionReason [ "ACTION_TOO_NEW" ] = 1 ] = "ACTION_TOO_NEW" ;
2023-07-13 11:17:33 +01:00
} ) ( DisallowedAPIVersionReason || ( exports . DisallowedAPIVersionReason = DisallowedAPIVersionReason = { } ) ) ;
2020-11-26 17:54:34 +00:00
function apiVersionInRange ( version , minimumVersion , maximumVersion ) {
if ( ! semver . satisfies ( version , ` >= ${ minimumVersion } ` ) ) {
return DisallowedAPIVersionReason . ACTION _TOO _NEW ;
}
if ( ! semver . satisfies ( version , ` <= ${ maximumVersion } ` ) ) {
return DisallowedAPIVersionReason . ACTION _TOO _OLD ;
}
return undefined ;
}
2021-05-13 17:56:27 +00:00
/**
* This error is used to indicate a runtime failure of an exhaustivity check enforced at compile time.
*/
class ExhaustivityCheckingError extends Error {
constructor ( expectedExhaustiveValue ) {
super ( "Internal error: exhaustivity checking failure" ) ;
this . expectedExhaustiveValue = expectedExhaustiveValue ;
}
}
/**
* Used to perform compile-time exhaustivity checking on a value. This function will not be executed at runtime unless
* the type system has been subverted.
*/
function assertNever ( value ) {
throw new ExhaustivityCheckingError ( value ) ;
}
2021-09-15 14:49:20 +01:00
/**
* Set some initial environment variables that we can set even without
* knowing what version of CodeQL we're running.
*/
2022-11-14 16:37:48 +00:00
function initializeEnvironment ( version ) {
2023-07-06 12:24:38 +01:00
core . exportVariable ( String ( environment _1 . EnvVar . FEATURE _MULTI _LANGUAGE ) , "false" ) ;
core . exportVariable ( String ( environment _1 . EnvVar . FEATURE _SANDWICH ) , "false" ) ;
core . exportVariable ( String ( environment _1 . EnvVar . FEATURE _SARIF _COMBINE ) , "true" ) ;
core . exportVariable ( String ( environment _1 . EnvVar . FEATURE _WILL _UPLOAD ) , "true" ) ;
core . exportVariable ( String ( environment _1 . EnvVar . VERSION ) , version ) ;
2021-06-01 14:49:07 -07:00
}
/**
* Get an environment parameter, but throw an error if it is not set.
*/
function getRequiredEnvParam ( paramName ) {
const value = process . env [ paramName ] ;
if ( value === undefined || value . length === 0 ) {
throw new Error ( ` ${ paramName } environment variable must be set ` ) ;
}
return value ;
}
2021-06-22 13:05:12 +01:00
class HTTPError extends Error {
constructor ( message , status ) {
super ( message ) ;
this . status = status ;
}
}
exports . HTTPError = HTTPError ;
2022-02-17 11:47:04 -08:00
/**
* An Error class that indicates an error that occurred due to
* a misconfiguration of the action or the CodeQL CLI.
*/
2024-02-08 09:20:03 -08:00
class ConfigurationError extends Error {
2022-02-17 11:47:04 -08:00
constructor ( message ) {
super ( message ) ;
}
}
2024-02-08 09:20:03 -08:00
exports . ConfigurationError = ConfigurationError ;
2021-06-22 13:05:12 +01:00
function isHTTPError ( arg ) {
2023-01-18 20:00:33 +00:00
return arg ? . status !== undefined && Number . isInteger ( arg . status ) ;
2021-06-22 13:05:12 +01:00
}
2022-03-17 10:07:29 -07:00
let cachedCodeQlVersion = undefined ;
function cacheCodeQlVersion ( version ) {
if ( cachedCodeQlVersion !== undefined ) {
throw new Error ( "cacheCodeQlVersion() should be called only once" ) ;
}
cachedCodeQlVersion = version ;
}
function getCachedCodeQlVersion ( ) {
return cachedCodeQlVersion ;
}
2024-04-25 15:20:13 -07:00
async function codeQlVersionAtLeast ( codeql , requiredVersion ) {
2023-10-04 11:28:28 +01:00
return semver . gte ( ( await codeql . getVersion ( ) ) . version , requiredVersion ) ;
2021-08-12 16:02:19 +01:00
}
2021-10-28 14:15:22 +01:00
// Create a bundle for the given DB, if it doesn't already exist
2022-01-07 13:11:51 +00:00
async function bundleDb ( config , language , codeql , dbName ) {
2021-10-28 14:15:22 +01:00
const databasePath = getCodeQLDatabasePath ( config , language ) ;
2022-01-07 13:11:51 +00:00
const databaseBundlePath = path . resolve ( config . dbLocation , ` ${ dbName } .zip ` ) ;
2021-12-01 12:25:57 +00:00
// For a tiny bit of added safety, delete the file if it exists.
// The file is probably from an earlier call to this function, either
// as part of this action step or a previous one, but it could also be
// from somewhere else or someone trying to make the action upload a
// non-database file.
if ( fs . existsSync ( databaseBundlePath ) ) {
2021-12-08 15:37:43 -08:00
await ( 0 , del _1 . default ) ( databaseBundlePath , { force : true } ) ;
2021-12-01 12:25:57 +00:00
}
2022-01-07 13:11:51 +00:00
await codeql . databaseBundle ( databasePath , databaseBundlePath , dbName ) ;
2021-10-28 14:15:22 +01:00
return databaseBundlePath ;
}
2023-02-13 13:26:01 -08:00
/**
* @param milliseconds time to delay
* @param opts options
* @param opts.allowProcessExit if true, the timer will not prevent the process from exiting
*/
2023-11-15 13:14:19 -08:00
async function delay ( milliseconds , opts ) {
const { allowProcessExit } = opts || { } ;
2023-02-13 13:26:01 -08:00
return new Promise ( ( resolve ) => {
const timer = setTimeout ( resolve , milliseconds ) ;
if ( allowProcessExit ) {
// Immediately `unref` the timer such that it only prevents the process from exiting if the
// surrounding promise is being awaited.
timer . unref ( ) ;
}
} ) ;
2021-10-18 11:43:30 +01:00
}
2021-12-09 13:43:57 +00:00
function isGoodVersion ( versionSpec ) {
return ! BROKEN _VERSIONS . includes ( versionSpec ) ;
}
2025-05-14 14:08:58 +01:00
/**
* Returns whether we are in test mode. This is used by CodeQL Action PR checks.
2022-04-28 19:07:04 +01:00
*
* In test mode, we don't upload SARIF results or status reports to the GitHub API.
*/
function isInTestMode ( ) {
2023-07-06 12:24:38 +01:00
return process . env [ environment _1 . EnvVar . TEST _MODE ] === "true" ;
2022-04-28 19:07:04 +01:00
}
2025-05-14 14:08:58 +01:00
/**
* Get the testing environment.
*
* This is set if the CodeQL Action is running in a non-production environment.
*/
function getTestingEnvironment ( ) {
const testingEnvironment = process . env [ environment _1 . EnvVar . TESTING _ENVIRONMENT ] || "" ;
if ( testingEnvironment === "" ) {
return undefined ;
}
return testingEnvironment ;
}
/**
2022-08-01 11:42:55 +02:00
* Returns whether the path in the argument represents an existing directory.
*/
function doesDirectoryExist ( dirPath ) {
try {
const stats = fs . lstatSync ( dirPath ) ;
return stats . isDirectory ( ) ;
}
2024-08-05 19:22:26 +01:00
catch {
2022-08-01 11:42:55 +02:00
return false ;
}
}
2022-08-01 12:52:16 +02:00
/**
2022-08-11 13:58:01 +02:00
* Returns a recursive list of files in a given directory.
2022-08-01 12:52:16 +02:00
*/
function listFolder ( dir ) {
2022-08-10 14:57:57 +02:00
if ( ! doesDirectoryExist ( dir ) ) {
return [ ] ;
}
2022-08-01 12:52:16 +02:00
const entries = fs . readdirSync ( dir , { withFileTypes : true } ) ;
let files = [ ] ;
for ( const entry of entries ) {
if ( entry . isFile ( ) ) {
files . push ( path . resolve ( dir , entry . name ) ) ;
}
else if ( entry . isDirectory ( ) ) {
files = files . concat ( listFolder ( path . resolve ( dir , entry . name ) ) ) ;
}
}
return files ;
}
2022-09-23 11:51:06 +01:00
/**
* Get the size a folder in bytes. This will log any filesystem errors
* as a warning and then return undefined.
*
* @param cacheDir A directory to get the size of.
* @param logger A logger to log any errors to.
2024-11-12 15:16:18 +00:00
* @param quiet A value indicating whether to suppress warnings for errors (default: false).
* Ignored if the log level is `debug`.
2022-09-23 11:51:06 +01:00
* @returns The size in bytes of the folder, or undefined if errors occurred.
*/
2024-11-12 15:16:18 +00:00
async function tryGetFolderBytes ( cacheDir , logger , quiet = false ) {
2022-09-23 11:51:06 +01:00
try {
return await ( 0 , util _1 . promisify ) ( get _folder _size _1 . default ) ( cacheDir ) ;
}
catch ( e ) {
2024-11-12 15:16:18 +00:00
if ( ! quiet || logger . isDebug ( ) ) {
logger . warning ( ` Encountered an error while getting size of ' ${ cacheDir } ': ${ e } ` ) ;
}
2022-09-23 11:51:06 +01:00
return undefined ;
}
}
2022-11-09 17:08:44 +00:00
let hadTimeout = false ;
2022-09-30 10:44:36 +01:00
/**
* Run a promise for a given amount of time, and if it doesn't resolve within
2022-11-09 17:08:44 +00:00
* that time, call the provided callback and then return undefined. Due to the
* limitation outlined below, using this helper function is not recommended
* unless there is no other option for adding a timeout (e.g. the code that
* would need the timeout added is an external library).
2022-09-30 10:44:36 +01:00
*
2022-10-11 22:38:30 +01:00
* Important: This does NOT cancel the original promise, so that promise will
* continue in the background even after the timeout has expired. If the
* original promise hangs, then this will prevent the process terminating.
2022-11-09 17:08:44 +00:00
* If a timeout has occurred then the global hadTimeout variable will get set
* to true, and the caller is responsible for forcing the process to exit
* if this is the case by calling the `checkForTimeout` function at the end
* of execution.
2022-10-11 16:59:48 +01:00
*
2022-09-30 10:44:36 +01:00
* @param timeoutMs The timeout in milliseconds.
* @param promise The promise to run.
* @param onTimeout A callback to call if the promise times out.
* @returns The result of the promise, or undefined if the promise times out.
*/
async function withTimeout ( timeoutMs , promise , onTimeout ) {
2022-10-11 10:04:21 +01:00
let finished = false ;
const mainTask = async ( ) => {
const result = await promise ;
finished = true ;
return result ;
} ;
2023-01-19 20:25:55 +00:00
const timeoutTask = async ( ) => {
2023-02-13 13:26:01 -08:00
await delay ( timeoutMs , { allowProcessExit : true } ) ;
2023-01-19 20:25:55 +00:00
if ( ! finished ) {
// Workaround: While the promise racing below will allow the main code
// to continue, the process won't normally exit until the asynchronous
// task in the background has finished. We set this variable to force
// an exit at the end of our code when `checkForTimeout` is called.
hadTimeout = true ;
onTimeout ( ) ;
}
return undefined ;
} ;
return await Promise . race ( [ mainTask ( ) , timeoutTask ( ) ] ) ;
2022-09-30 10:44:36 +01:00
}
2022-11-09 17:08:44 +00:00
/**
* Check if the global hadTimeout variable has been set, and if so then
* exit the process to ensure any background tasks that are still running
* are killed. This should be called at the end of execution if the
* `withTimeout` function has been used.
*/
async function checkForTimeout ( ) {
if ( hadTimeout === true ) {
core . info ( "A timeout occurred, force exiting the process after 30 seconds to prevent hanging." ) ;
2024-03-12 07:27:21 -07:00
await delay ( 30_000 , { allowProcessExit : true } ) ;
2022-11-09 17:08:44 +00:00
process . exit ( ) ;
}
}
2022-10-13 14:31:54 +01:00
/**
* This function implements a heuristic to determine whether the
* runner we are on is hosted by GitHub. It does this by checking
* the name of the runner against the list of known GitHub-hosted
* runner names. It also checks for the presence of a toolcache
* directory with the name hostedtoolcache which is present on
* GitHub-hosted runners.
*
* @returns true iff the runner is hosted by GitHub
*/
function isHostedRunner ( ) {
return (
// Name of the runner on hosted Windows runners
2023-01-18 20:00:33 +00:00
process . env [ "RUNNER_NAME" ] ? . includes ( "Hosted Agent" ) ||
2022-10-13 14:31:54 +01:00
// Name of the runner on hosted POSIX runners
2023-01-18 20:00:33 +00:00
process . env [ "RUNNER_NAME" ] ? . includes ( "GitHub Actions" ) ||
2022-10-13 14:31:54 +01:00
// Segment of the path to the tool cache on all hosted runners
2023-01-18 20:00:33 +00:00
process . env [ "RUNNER_TOOL_CACHE" ] ? . includes ( "hostedtoolcache" ) ) ;
2022-10-13 14:31:54 +01:00
}
2022-11-23 13:27:16 +00:00
function parseMatrixInput ( matrixInput ) {
if ( matrixInput === undefined || matrixInput === "null" ) {
return undefined ;
}
return JSON . parse ( matrixInput ) ;
}
2023-03-24 20:01:35 +00:00
function removeDuplicateLocations ( locations ) {
const newJsonLocations = new Set ( ) ;
return locations . filter ( ( location ) => {
const jsonLocation = JSON . stringify ( location ) ;
if ( ! newJsonLocations . has ( jsonLocation ) ) {
newJsonLocations . add ( jsonLocation ) ;
return true ;
}
return false ;
} ) ;
}
function fixInvalidNotifications ( sarif , logger ) {
2023-03-27 15:59:29 +01:00
if ( ! Array . isArray ( sarif . runs ) ) {
2023-03-24 20:01:35 +00:00
return sarif ;
}
// Ensure that the array of locations for each SARIF notification contains unique locations.
// This is a workaround for a bug in the CodeQL CLI that causes duplicate locations to be
// emitted in some cases.
let numDuplicateLocationsRemoved = 0 ;
const newSarif = {
... sarif ,
runs : sarif . runs . map ( ( run ) => {
if ( run . tool ? . driver ? . name !== "CodeQL" ||
2023-03-27 15:59:29 +01:00
! Array . isArray ( run . invocations ) ) {
2023-03-24 20:01:35 +00:00
return run ;
}
return {
... run ,
invocations : run . invocations . map ( ( invocation ) => {
2023-03-27 15:59:29 +01:00
if ( ! Array . isArray ( invocation . toolExecutionNotifications ) ) {
2023-03-24 20:01:35 +00:00
return invocation ;
}
return {
... invocation ,
toolExecutionNotifications : invocation . toolExecutionNotifications . map ( ( notification ) => {
2023-03-27 15:59:29 +01:00
if ( ! Array . isArray ( notification . locations ) ) {
2023-03-24 20:01:35 +00:00
return notification ;
}
const newLocations = removeDuplicateLocations ( notification . locations ) ;
numDuplicateLocationsRemoved +=
notification . locations . length - newLocations . length ;
return {
... notification ,
locations : newLocations ,
} ;
} ) ,
} ;
} ) ,
} ;
} ) ,
} ;
if ( numDuplicateLocationsRemoved > 0 ) {
logger . info ( ` Removed ${ numDuplicateLocationsRemoved } duplicate locations from SARIF notification ` +
"objects." ) ;
}
2023-04-04 16:46:45 +01:00
else {
logger . debug ( "No duplicate locations found in SARIF notification objects." ) ;
}
2023-03-24 20:01:35 +00:00
return newSarif ;
}
2023-05-24 12:12:27 +00:00
/**
* Removes duplicates from the sarif file.
*
* When `CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX` is set to true, this will
* simply rename the input file to the output file. Otherwise, it will parse the
* input file as JSON, remove duplicate locations from the SARIF notification
* objects, and write the result to the output file.
*
* For context, see documentation of:
* `CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX`. */
2023-03-27 15:44:47 +01:00
function fixInvalidNotificationsInFile ( inputPath , outputPath , logger ) {
2023-07-06 12:24:38 +01:00
if ( process . env [ environment _1 . EnvVar . DISABLE _DUPLICATE _LOCATION _FIX ] === "true" ) {
2023-05-24 11:51:57 +00:00
logger . info ( "SARIF notification object duplicate location fix disabled by the " +
2023-07-06 12:24:38 +01:00
` ${ environment _1 . EnvVar . DISABLE _DUPLICATE _LOCATION _FIX } environment variable. ` ) ;
2023-05-24 11:51:57 +00:00
fs . renameSync ( inputPath , outputPath ) ;
}
else {
let sarif = JSON . parse ( fs . readFileSync ( inputPath , "utf8" ) ) ;
sarif = fixInvalidNotifications ( sarif , logger ) ;
fs . writeFileSync ( outputPath , JSON . stringify ( sarif ) ) ;
}
2023-03-27 15:44:47 +01:00
}
2023-04-06 17:04:21 +01:00
function wrapError ( error ) {
return error instanceof Error ? error : new Error ( String ( error ) ) ;
}
2024-09-16 22:38:35 +02:00
/**
* Returns an appropriate message for the error.
*
* If the error is an `Error` instance, this returns the error message without
* an `Error: ` prefix.
*/
2023-11-15 12:47:51 -08:00
function getErrorMessage ( error ) {
2024-09-16 22:38:35 +02:00
return error instanceof Error ? error . message : String ( error ) ;
2023-11-15 12:47:51 -08:00
}
2023-07-19 17:37:43 +01:00
function prettyPrintPack ( pack ) {
return ` ${ pack . name } ${ pack . version ? ` @ ${ pack . version } ` : "" } ${ pack . path ? ` : ${ pack . path } ` : "" } ` ;
}
2023-08-07 16:00:32 +01:00
async function checkDiskUsage ( logger ) {
2024-02-02 16:31:04 +00:00
try {
2024-08-20 16:04:03 -07:00
// We avoid running the `df` binary under the hood for macOS ARM runners with SIP disabled.
if ( process . platform === "darwin" &&
( process . arch === "arm" || process . arch === "arm64" ) &&
2024-08-23 09:17:22 -07:00
! ( await checkSipEnablement ( logger ) ) ) {
2024-08-20 16:04:03 -07:00
return undefined ;
}
2024-02-02 16:31:04 +00:00
const diskUsage = await ( 0 , check _disk _space _1 . default ) ( getRequiredEnvParam ( "GITHUB_WORKSPACE" ) ) ;
2025-02-26 15:12:53 +00:00
const mbInBytes = 1024 * 1024 ;
2024-02-02 16:31:04 +00:00
const gbInBytes = 1024 * 1024 * 1024 ;
2024-08-20 16:04:03 -07:00
if ( diskUsage . free < 2 * gbInBytes ) {
2024-02-02 16:31:04 +00:00
const message = "The Actions runner is running low on disk space " +
2025-02-26 15:12:53 +00:00
` ( ${ ( diskUsage . free / mbInBytes ) . toPrecision ( 4 ) } MB available). ` ;
2024-02-02 16:31:04 +00:00
if ( process . env [ environment _1 . EnvVar . HAS _WARNED _ABOUT _DISK _SPACE ] !== "true" ) {
logger . warning ( message ) ;
}
else {
logger . debug ( message ) ;
}
core . exportVariable ( environment _1 . EnvVar . HAS _WARNED _ABOUT _DISK _SPACE , "true" ) ;
2023-08-07 16:00:32 +01:00
}
2024-02-02 16:31:04 +00:00
return {
numAvailableBytes : diskUsage . free ,
numTotalBytes : diskUsage . size ,
} ;
}
catch ( error ) {
2024-08-20 16:04:03 -07:00
logger . warning ( ` Failed to check available disk space: ${ getErrorMessage ( error ) } ` ) ;
2024-02-02 16:31:04 +00:00
return undefined ;
2023-08-07 16:00:32 +01:00
}
}
2024-01-18 18:14:30 +00:00
/**
2024-01-19 15:03:13 +00:00
* Prompt the customer to upgrade to CodeQL Action v3, if appropriate.
2024-01-18 18:14:30 +00:00
*
2025-01-07 13:59:42 -08:00
* Check whether a customer is running v1 or v2. If they are, and we can determine that the GitHub
* instance supports v3, then log an error prompting the customer to upgrade to v3.
2024-01-18 18:14:30 +00:00
*/
function checkActionVersion ( version , githubVersion ) {
2025-01-07 13:59:42 -08:00
if ( ! semver . satisfies ( version , ">=3" ) && // do not log error if the customer is already running v3
! process . env [ environment _1 . EnvVar . LOG _VERSION _DEPRECATION ] // do not log error if we have already
2024-01-19 11:40:39 +00:00
) {
2025-01-07 13:59:42 -08:00
// Only error for versions of GHES that are compatible with CodeQL Action version 3.
2024-01-18 18:14:30 +00:00
//
// GHES 3.11 shipped without the v3 tag, but it also shipped without this warning message code.
// Therefore users who are seeing this warning message code have pulled in a new version of the
// Action, and with it the v3 tag.
if ( githubVersion . type === GitHubVariant . DOTCOM ||
githubVersion . type === GitHubVariant . GHE _DOTCOM ||
( githubVersion . type === GitHubVariant . GHES &&
semver . satisfies ( semver . coerce ( githubVersion . version ) ? ? "0.0.0" , ">=3.11" ) ) ) {
2025-01-07 13:59:42 -08:00
core . error ( "CodeQL Action major versions v1 and v2 have been deprecated. " +
2024-01-19 15:01:15 +00:00
"Please update all occurrences of the CodeQL Action in your workflow files to v3. " +
"For more information, see " +
2025-01-10 08:52:16 -08:00
"https://github.blog/changelog/2025-01-10-code-scanning-codeql-action-v2-is-now-deprecated/" ) ;
2025-01-07 13:59:42 -08:00
// set LOG_VERSION_DEPRECATION env var to prevent the warning from being logged multiple times
core . exportVariable ( environment _1 . EnvVar . LOG _VERSION _DEPRECATION , "true" ) ;
2024-01-18 18:14:30 +00:00
}
}
}
2024-04-11 20:01:39 +01:00
/**
* Supported build modes.
*
* These specify whether the CodeQL database should be created by tracing a build, and if so, how
* this build will be invoked.
*/
var BuildMode ;
( function ( BuildMode ) {
/** The database will be created without building the source root. */
BuildMode [ "None" ] = "none" ;
/** The database will be created by attempting to automatically build the source root. */
BuildMode [ "Autobuild" ] = "autobuild" ;
/** The database will be created by building the source root using manually specified build steps. */
BuildMode [ "Manual" ] = "manual" ;
} ) ( BuildMode || ( exports . BuildMode = BuildMode = { } ) ) ;
2024-07-31 17:56:06 -07:00
function cloneObject ( obj ) {
return JSON . parse ( JSON . stringify ( obj ) ) ;
}
2024-08-23 09:17:22 -07:00
// The first time this function is called, it runs `csrutil status` to determine
// whether System Integrity Protection is enabled; and saves the result in an
// environment variable. Afterwards, simply return the value of the environment
// variable.
async function checkSipEnablement ( logger ) {
if ( process . env [ environment _1 . EnvVar . IS _SIP _ENABLED ] !== undefined &&
[ "true" , "false" ] . includes ( process . env [ environment _1 . EnvVar . IS _SIP _ENABLED ] ) ) {
return process . env [ environment _1 . EnvVar . IS _SIP _ENABLED ] === "true" ;
}
2024-08-20 16:04:03 -07:00
try {
const sipStatusOutput = await exec . getExecOutput ( "csrutil status" ) ;
if ( sipStatusOutput . exitCode === 0 ) {
if ( sipStatusOutput . stdout . includes ( "System Integrity Protection status: enabled." ) ) {
2024-08-23 09:17:22 -07:00
core . exportVariable ( environment _1 . EnvVar . IS _SIP _ENABLED , "true" ) ;
2024-08-20 16:04:03 -07:00
return true ;
}
if ( sipStatusOutput . stdout . includes ( "System Integrity Protection status: disabled." ) ) {
2024-08-23 09:17:22 -07:00
core . exportVariable ( environment _1 . EnvVar . IS _SIP _ENABLED , "false" ) ;
2024-08-20 16:04:03 -07:00
return false ;
}
}
return undefined ;
}
catch ( e ) {
logger . warning ( ` Failed to determine if System Integrity Protection was enabled: ${ e } ` ) ;
return undefined ;
}
}
2024-10-02 15:45:55 +01:00
async function cleanUpGlob ( glob , name , logger ) {
logger . debug ( ` Cleaning up ${ name } . ` ) ;
try {
const deletedPaths = await ( 0 , del _1 . default ) ( glob , { force : true } ) ;
if ( deletedPaths . length === 0 ) {
logger . warning ( ` Failed to clean up ${ name } : no files found matching ${ glob } . ` ) ;
}
else if ( deletedPaths . length === 1 ) {
logger . debug ( ` Cleaned up ${ name } . ` ) ;
}
else {
logger . debug ( ` Cleaned up ${ name } ( ${ deletedPaths . length } files). ` ) ;
}
}
catch ( e ) {
logger . warning ( ` Failed to clean up ${ name } : ${ e } . ` ) ;
}
}
2024-11-18 11:21:11 -08:00
async function isBinaryAccessible ( binary , logger ) {
try {
2024-12-19 14:21:06 +00:00
await io . which ( binary , true ) ;
2024-11-18 11:21:11 -08:00
logger . debug ( ` Found ${ binary } . ` ) ;
return true ;
}
catch ( e ) {
logger . debug ( ` Could not find ${ binary } : ${ e } ` ) ;
return false ;
}
}
2020-05-13 16:31:24 +01:00
//# sourceMappingURL=util.js.map