2020-06-26 17:22:19 +01:00
"use strict" ;
var _ _importStar = ( this && this . _ _importStar ) || function ( mod ) {
if ( mod && mod . _ _esModule ) return mod ;
var result = { } ;
if ( mod != null ) for ( var k in mod ) if ( Object . hasOwnProperty . call ( mod , k ) ) result [ k ] = mod [ k ] ;
result [ "default" ] = mod ;
return result ;
} ;
2021-01-26 15:50:22 +00:00
var _ _importDefault = ( this && this . _ _importDefault ) || function ( mod ) {
return ( mod && mod . _ _esModule ) ? mod : { "default" : mod } ;
} ;
2020-06-26 17:22:19 +01:00
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
const fs = _ _importStar ( require ( "fs" ) ) ;
const path = _ _importStar ( require ( "path" ) ) ;
2020-07-10 11:54:26 +01:00
const stream = _ _importStar ( require ( "stream" ) ) ;
2020-10-01 11:03:30 +01:00
const globalutil = _ _importStar ( require ( "util" ) ) ;
2020-11-20 11:35:59 +01:00
const toolrunner = _ _importStar ( require ( "@actions/exec/lib/toolrunner" ) ) ;
2020-10-01 11:03:30 +01:00
const http = _ _importStar ( require ( "@actions/http-client" ) ) ;
2021-01-26 15:50:22 +00:00
const fast _deep _equal _1 = _ _importDefault ( require ( "fast-deep-equal" ) ) ;
2021-02-11 15:13:22 +00:00
const query _string _1 = _ _importDefault ( require ( "query-string" ) ) ;
2020-10-01 11:03:30 +01:00
const semver = _ _importStar ( require ( "semver" ) ) ;
2020-10-01 11:17:59 +01:00
const uuid _1 = require ( "uuid" ) ;
2020-09-29 14:43:37 +01:00
const actions _util _1 = require ( "./actions-util" ) ;
2020-10-01 11:03:30 +01:00
const api = _ _importStar ( require ( "./api-client" ) ) ;
const defaults = _ _importStar ( require ( "./defaults.json" ) ) ; // Referenced from codeql-action-sync-tool!
const error _matcher _1 = require ( "./error-matcher" ) ;
2021-04-22 15:04:59 +01:00
const toolcache = _ _importStar ( require ( "./toolcache" ) ) ;
2020-09-08 00:01:04 +01:00
const toolrunner _error _catcher _1 = require ( "./toolrunner-error-catcher" ) ;
2020-10-01 11:03:30 +01:00
const util = _ _importStar ( require ( "./util" ) ) ;
2020-06-26 15:33:59 +01:00
/**
2020-07-15 17:36:49 +01:00
* Stores the CodeQL object, and is populated by `setupCodeQL` or `getCodeQL`.
2020-06-26 15:33:59 +01:00
* Can be overridden in tests using `setCodeQL`.
*/
let cachedCodeQL = undefined ;
2020-08-10 12:34:11 +01:00
const CODEQL _BUNDLE _VERSION = defaults . bundleVersion ;
2020-07-10 11:54:26 +01:00
const CODEQL _DEFAULT _ACTION _REPOSITORY = "github/codeql-action" ;
2020-09-30 16:17:07 +02:00
function getCodeQLBundleName ( ) {
let platform ;
if ( process . platform === "win32" ) {
platform = "win64" ;
}
else if ( process . platform === "linux" ) {
platform = "linux64" ;
}
else if ( process . platform === "darwin" ) {
platform = "osx64" ;
}
else {
return "codeql-bundle.tar.gz" ;
}
return ` codeql-bundle- ${ platform } .tar.gz ` ;
}
2021-05-20 15:20:32 -07:00
function getCodeQLActionRepository ( logger ) {
2021-06-01 14:49:07 -07:00
if ( util . isActions ( ) ) {
2020-08-27 16:34:09 +01:00
return CODEQL _DEFAULT _ACTION _REPOSITORY ;
2020-08-25 16:19:15 +01:00
}
2021-03-16 11:59:10 +00:00
else {
return getActionsCodeQLActionRepository ( logger ) ;
}
}
2021-05-20 15:20:32 -07:00
exports . getCodeQLActionRepository = getCodeQLActionRepository ;
2021-03-16 11:59:10 +00:00
function getActionsCodeQLActionRepository ( logger ) {
2020-11-10 12:35:14 +00:00
if ( process . env [ "GITHUB_ACTION_REPOSITORY" ] !== undefined ) {
return process . env [ "GITHUB_ACTION_REPOSITORY" ] ;
}
// The Actions Runner used with GitHub Enterprise Server 2.22 did not set the GITHUB_ACTION_REPOSITORY variable.
// This fallback logic can be removed after the end-of-support for 2.22 on 2021-09-23.
2020-11-12 14:18:58 +00:00
if ( actions _util _1 . isRunningLocalAction ( ) ) {
// This handles the case where the Action does not come from an Action repository,
// e.g. our integration tests which use the Action code from the current checkout.
2020-11-10 12:35:14 +00:00
logger . info ( "The CodeQL Action is checked out locally. Using the default CodeQL Action repository." ) ;
2020-07-10 11:54:26 +01:00
return CODEQL _DEFAULT _ACTION _REPOSITORY ;
}
2020-11-10 12:35:14 +00:00
logger . info ( "GITHUB_ACTION_REPOSITORY environment variable was not set. Falling back to legacy method of finding the GitHub Action." ) ;
2020-11-12 14:18:58 +00:00
const relativeScriptPathParts = actions _util _1 . getRelativeScriptPath ( ) . split ( path . sep ) ;
2020-09-14 10:44:43 +01:00
return ` ${ relativeScriptPathParts [ 0 ] } / ${ relativeScriptPathParts [ 1 ] } ` ;
2020-07-10 11:54:26 +01:00
}
2021-05-20 15:20:32 -07:00
async function getCodeQLBundleDownloadURL ( apiDetails , variant , logger ) {
const codeQLActionRepository = getCodeQLActionRepository ( logger ) ;
2020-07-10 11:54:26 +01:00
const potentialDownloadSources = [
// This GitHub instance, and this Action.
2020-11-23 14:18:05 +00:00
[ apiDetails . url , codeQLActionRepository ] ,
2020-07-10 11:54:26 +01:00
// This GitHub instance, and the canonical Action.
2020-11-23 14:18:05 +00:00
[ apiDetails . url , CODEQL _DEFAULT _ACTION _REPOSITORY ] ,
2020-07-10 11:54:26 +01:00
// GitHub.com, and the canonical Action.
2020-08-25 16:19:15 +01:00
[ util . GITHUB _DOTCOM _URL , CODEQL _DEFAULT _ACTION _REPOSITORY ] ,
2020-07-10 11:54:26 +01:00
] ;
// We now filter out any duplicates.
// Duplicates will happen either because the GitHub instance is GitHub.com, or because the Action is not a fork.
2021-01-26 15:50:22 +00:00
const uniqueDownloadSources = potentialDownloadSources . filter ( ( source , index , self ) => {
return ! self . slice ( 0 , index ) . some ( ( other ) => fast _deep _equal _1 . default ( source , other ) ) ;
} ) ;
2020-09-30 16:17:07 +02:00
const codeQLBundleName = getCodeQLBundleName ( ) ;
2021-03-07 09:27:19 +00:00
if ( variant === util . GitHubVariant . GHAE ) {
try {
const release = await api
. getApiClient ( apiDetails )
. request ( "GET /enterprise/code-scanning/codeql-bundle/find/{tag}" , {
tag : CODEQL _BUNDLE _VERSION ,
} ) ;
const assetID = release . data . assets [ codeQLBundleName ] ;
if ( assetID !== undefined ) {
const download = await api
. getApiClient ( apiDetails )
. request ( "GET /enterprise/code-scanning/codeql-bundle/download/{asset_id}" , { asset _id : assetID } ) ;
const downloadURL = download . data . url ;
logger . info ( ` Found CodeQL bundle at GitHub AE endpoint with URL ${ downloadURL } . ` ) ;
return downloadURL ;
}
else {
logger . info ( ` Attempted to fetch bundle from GitHub AE endpoint but the bundle ${ codeQLBundleName } was not found in the assets ${ JSON . stringify ( release . data . assets ) } . ` ) ;
}
}
catch ( e ) {
logger . info ( ` Attempted to fetch bundle from GitHub AE endpoint but got error ${ e } . ` ) ;
}
}
2020-09-14 10:44:43 +01:00
for ( const downloadSource of uniqueDownloadSources ) {
const [ apiURL , repository ] = downloadSource ;
2020-07-10 11:54:26 +01:00
// If we've reached the final case, short-circuit the API check since we know the bundle exists and is public.
2020-09-14 10:44:43 +01:00
if ( apiURL === util . GITHUB _DOTCOM _URL &&
repository === CODEQL _DEFAULT _ACTION _REPOSITORY ) {
2020-07-27 10:47:45 +01:00
break ;
2020-07-10 11:54:26 +01:00
}
2020-09-14 10:44:43 +01:00
const [ repositoryOwner , repositoryName ] = repository . split ( "/" ) ;
2020-07-10 11:54:26 +01:00
try {
2020-11-30 16:33:38 +00:00
const release = await api . getApiClient ( apiDetails ) . repos . getReleaseByTag ( {
2020-07-10 11:54:26 +01:00
owner : repositoryOwner ,
repo : repositoryName ,
2020-09-14 10:44:43 +01:00
tag : CODEQL _BUNDLE _VERSION ,
2020-07-10 11:54:26 +01:00
} ) ;
2020-09-14 10:44:43 +01:00
for ( const asset of release . data . assets ) {
2020-09-30 16:17:07 +02:00
if ( asset . name === codeQLBundleName ) {
2020-08-25 16:19:15 +01:00
logger . info ( ` Found CodeQL bundle in ${ downloadSource [ 1 ] } on ${ downloadSource [ 0 ] } with URL ${ asset . url } . ` ) ;
2020-07-10 11:54:26 +01:00
return asset . url ;
}
}
}
catch ( e ) {
2020-08-25 16:19:15 +01:00
logger . info ( ` Looked for CodeQL bundle in ${ downloadSource [ 1 ] } on ${ downloadSource [ 0 ] } but got error ${ e } . ` ) ;
2020-07-10 11:54:26 +01:00
}
}
2020-09-30 16:17:07 +02:00
return ` https://github.com/ ${ CODEQL _DEFAULT _ACTION _REPOSITORY } /releases/download/ ${ CODEQL _BUNDLE _VERSION } / ${ codeQLBundleName } ` ;
2020-07-10 11:54:26 +01:00
}
2020-07-27 11:02:37 +01:00
// We have to download CodeQL manually because the toolcache doesn't support Accept headers.
// This can be removed once https://github.com/actions/toolkit/pull/530 is merged and released.
2020-08-25 16:19:15 +01:00
async function toolcacheDownloadTool ( url , headers , tempDir , logger ) {
2020-09-14 10:44:43 +01:00
const client = new http . HttpClient ( "CodeQL Action" ) ;
2020-09-29 15:03:21 +01:00
const dest = path . join ( tempDir , uuid _1 . v4 ( ) ) ;
2020-07-27 11:02:37 +01:00
const response = await client . get ( url , headers ) ;
if ( response . message . statusCode !== 200 ) {
2020-08-25 16:19:15 +01:00
logger . info ( ` Failed to download from " ${ url } ". Code( ${ response . message . statusCode } ) Message( ${ response . message . statusMessage } ) ` ) ;
throw new Error ( ` Unexpected HTTP response: ${ response . message . statusCode } ` ) ;
2020-07-27 11:02:37 +01:00
}
const pipeline = globalutil . promisify ( stream . pipeline ) ;
2020-08-07 17:46:46 +01:00
fs . mkdirSync ( path . dirname ( dest ) , { recursive : true } ) ;
2020-07-27 11:02:37 +01:00
await pipeline ( response . message , fs . createWriteStream ( dest ) ) ;
return dest ;
}
2021-05-20 15:20:32 -07:00
async function setupCodeQL ( codeqlURL , apiDetails , tempDir , toolCacheDir , variant , logger ) {
2020-06-26 17:22:19 +01:00
try {
2020-09-22 14:38:27 +01:00
// We use the special value of 'latest' to prioritize the version in the
// defaults over any pinned cached version.
const forceLatest = codeqlURL === "latest" ;
if ( forceLatest ) {
codeqlURL = undefined ;
}
2020-11-11 18:22:12 +00:00
const codeqlURLVersion = getCodeQLURLVersion ( codeqlURL || ` / ${ CODEQL _BUNDLE _VERSION } / ` ) ;
const codeqlURLSemVer = convertToSemVer ( codeqlURLVersion , logger ) ;
2020-09-22 14:38:27 +01:00
// If we find the specified version, we always use that.
2021-05-20 15:20:32 -07:00
let codeqlFolder = toolcache . find ( "CodeQL" , codeqlURLSemVer , toolCacheDir , logger ) ;
2020-09-22 14:38:27 +01:00
// If we don't find the requested version, in some cases we may allow a
// different version to save download time if the version hasn't been
// specified explicitly (in which case we always honor it).
if ( ! codeqlFolder && ! codeqlURL && ! forceLatest ) {
2021-05-20 15:20:32 -07:00
const codeqlVersions = toolcache . findAllVersions ( "CodeQL" , toolCacheDir , logger ) ;
2020-09-22 14:38:27 +01:00
if ( codeqlVersions . length === 1 ) {
2021-05-20 15:20:32 -07:00
const tmpCodeqlFolder = toolcache . find ( "CodeQL" , codeqlVersions [ 0 ] , toolCacheDir , logger ) ;
2020-09-22 14:38:27 +01:00
if ( fs . existsSync ( path . join ( tmpCodeqlFolder , "pinned-version" ) ) ) {
logger . debug ( ` CodeQL in cache overriding the default ${ CODEQL _BUNDLE _VERSION } ` ) ;
codeqlFolder = tmpCodeqlFolder ;
}
}
}
2020-06-26 17:22:19 +01:00
if ( codeqlFolder ) {
2020-08-25 16:19:15 +01:00
logger . debug ( ` CodeQL found in cache ${ codeqlFolder } ` ) ;
2020-06-26 17:22:19 +01:00
}
else {
2020-07-10 11:54:26 +01:00
if ( ! codeqlURL ) {
2021-05-20 15:20:32 -07:00
codeqlURL = await getCodeQLBundleDownloadURL ( apiDetails , variant , logger ) ;
2020-07-10 11:54:26 +01:00
}
2021-02-11 15:13:22 +00:00
const parsedCodeQLURL = new URL ( codeqlURL ) ;
const parsedQueryString = query _string _1 . default . parse ( parsedCodeQLURL . search ) ;
2020-09-14 10:44:43 +01:00
const headers = { accept : "application/octet-stream" } ;
2020-07-10 11:54:26 +01:00
// We only want to provide an authorization header if we are downloading
// from the same GitHub instance the Action is running on.
// This avoids leaking Enterprise tokens to dotcom.
2021-02-11 15:13:22 +00:00
// We also don't want to send an authorization header if there's already a token provided in the URL.
if ( codeqlURL . startsWith ( ` ${ apiDetails . url } / ` ) &&
parsedQueryString [ "token" ] === undefined ) {
2020-09-14 10:44:43 +01:00
logger . debug ( "Downloading CodeQL bundle with token." ) ;
2020-11-23 14:18:05 +00:00
headers . authorization = ` token ${ apiDetails . auth } ` ;
2020-07-10 11:54:26 +01:00
}
else {
2020-09-14 10:44:43 +01:00
logger . debug ( "Downloading CodeQL bundle without token." ) ;
2020-07-10 11:54:26 +01:00
}
2020-09-02 18:02:49 +01:00
logger . info ( ` Downloading CodeQL tools from ${ codeqlURL } . This may take a while. ` ) ;
2020-09-14 10:44:43 +01:00
const codeqlPath = await toolcacheDownloadTool ( codeqlURL , headers , tempDir , logger ) ;
2020-08-25 16:19:15 +01:00
logger . debug ( ` CodeQL bundle download to ${ codeqlPath } complete. ` ) ;
2021-05-20 15:20:32 -07:00
const codeqlExtracted = await toolcache . extractTar ( codeqlPath , tempDir , logger ) ;
codeqlFolder = await toolcache . cacheDir ( codeqlExtracted , "CodeQL" , codeqlURLSemVer , toolCacheDir , logger ) ;
2020-06-26 17:22:19 +01:00
}
2020-09-14 10:44:43 +01:00
let codeqlCmd = path . join ( codeqlFolder , "codeql" , "codeql" ) ;
if ( process . platform === "win32" ) {
2020-06-26 17:22:19 +01:00
codeqlCmd += ".exe" ;
}
2020-09-14 10:44:43 +01:00
else if ( process . platform !== "linux" && process . platform !== "darwin" ) {
throw new Error ( ` Unsupported platform: ${ process . platform } ` ) ;
2020-06-26 17:22:19 +01:00
}
2020-06-26 15:33:59 +01:00
cachedCodeQL = getCodeQLForCmd ( codeqlCmd ) ;
2020-11-11 18:22:12 +00:00
return { codeql : cachedCodeQL , toolsVersion : codeqlURLVersion } ;
2020-06-26 17:22:19 +01:00
}
catch ( e ) {
2020-08-25 16:19:15 +01:00
logger . error ( e ) ;
2020-06-26 17:22:19 +01:00
throw new Error ( "Unable to download and extract CodeQL CLI" ) ;
}
}
exports . setupCodeQL = setupCodeQL ;
2020-11-11 18:22:12 +00:00
function getCodeQLURLVersion ( url ) {
2020-06-26 17:22:19 +01:00
const match = url . match ( /\/codeql-bundle-(.*)\// ) ;
if ( match === null || match . length < 2 ) {
throw new Error ( ` Malformed tools url: ${ url } . Version could not be inferred ` ) ;
}
2020-11-11 18:22:12 +00:00
return match [ 1 ] ;
}
exports . getCodeQLURLVersion = getCodeQLURLVersion ;
function convertToSemVer ( version , logger ) {
2020-06-26 17:22:19 +01:00
if ( ! semver . valid ( version ) ) {
2020-08-25 16:19:15 +01:00
logger . debug ( ` Bundle version ${ version } is not in SemVer format. Will treat it as pre-release 0.0.0- ${ version } . ` ) ;
2020-09-14 10:44:43 +01:00
version = ` 0.0.0- ${ version } ` ;
2020-06-26 17:22:19 +01:00
}
const s = semver . clean ( version ) ;
if ( ! s ) {
2020-11-11 18:22:12 +00:00
throw new Error ( ` Bundle version ${ version } is not in SemVer format. ` ) ;
2020-06-26 17:22:19 +01:00
}
return s ;
}
2020-11-11 18:22:12 +00:00
exports . convertToSemVer = convertToSemVer ;
2020-08-19 15:54:23 +01:00
/**
* Use the CodeQL executable located at the given path.
*/
function getCodeQL ( cmd ) {
2020-06-26 15:33:59 +01:00
if ( cachedCodeQL === undefined ) {
2020-08-19 15:54:23 +01:00
cachedCodeQL = getCodeQLForCmd ( cmd ) ;
2020-06-26 15:33:59 +01:00
}
return cachedCodeQL ;
2020-06-26 17:22:19 +01:00
}
exports . getCodeQL = getCodeQL ;
2020-08-19 15:54:23 +01:00
function resolveFunction ( partialCodeql , methodName , defaultImplementation ) {
2020-09-14 10:44:43 +01:00
if ( typeof partialCodeql [ methodName ] !== "function" ) {
2020-08-19 15:54:23 +01:00
if ( defaultImplementation !== undefined ) {
return defaultImplementation ;
}
2020-06-26 15:33:59 +01:00
const dummyMethod = ( ) => {
2020-09-14 10:44:43 +01:00
throw new Error ( ` CodeQL ${ methodName } method not correctly defined ` ) ;
2020-06-26 15:33:59 +01:00
} ;
return dummyMethod ;
}
return partialCodeql [ methodName ] ;
}
2020-07-15 17:36:49 +01:00
/**
* Set the functionality for CodeQL methods. Only for use in tests.
*
* Accepts a partial object and any undefined methods will be implemented
* to immediately throw an exception indicating which method is missing.
*/
2020-06-26 15:33:59 +01:00
function setCodeQL ( partialCodeql ) {
cachedCodeQL = {
2020-09-14 10:44:43 +01:00
getPath : resolveFunction ( partialCodeql , "getPath" , ( ) => "/tmp/dummy-path" ) ,
printVersion : resolveFunction ( partialCodeql , "printVersion" ) ,
getTracerEnv : resolveFunction ( partialCodeql , "getTracerEnv" ) ,
databaseInit : resolveFunction ( partialCodeql , "databaseInit" ) ,
runAutobuild : resolveFunction ( partialCodeql , "runAutobuild" ) ,
extractScannedLanguage : resolveFunction ( partialCodeql , "extractScannedLanguage" ) ,
finalizeDatabase : resolveFunction ( partialCodeql , "finalizeDatabase" ) ,
2021-05-23 16:27:46 +02:00
resolveLanguages : resolveFunction ( partialCodeql , "resolveLanguages" ) ,
2020-09-14 10:44:43 +01:00
resolveQueries : resolveFunction ( partialCodeql , "resolveQueries" ) ,
databaseAnalyze : resolveFunction ( partialCodeql , "databaseAnalyze" ) ,
2021-05-24 17:26:13 +01:00
databaseCleanup : resolveFunction ( partialCodeql , "databaseCleanup" ) ,
2020-06-26 15:33:59 +01:00
} ;
2020-08-19 15:54:23 +01:00
return cachedCodeQL ;
2020-06-26 15:33:59 +01:00
}
exports . setCodeQL = setCodeQL ;
2020-08-19 15:54:23 +01:00
/**
* Get the cached CodeQL object. Should only be used from tests.
*
* TODO: Work out a good way for tests to get this from the test context
* instead of having to have this method.
*/
function getCachedCodeQL ( ) {
if ( cachedCodeQL === undefined ) {
// Should never happen as setCodeQL is called by testing-utils.setupTests
2020-09-14 10:44:43 +01:00
throw new Error ( "cachedCodeQL undefined" ) ;
2020-08-19 15:54:23 +01:00
}
return cachedCodeQL ;
}
exports . getCachedCodeQL = getCachedCodeQL ;
2020-06-26 17:22:19 +01:00
function getCodeQLForCmd ( cmd ) {
return {
2020-09-14 10:44:43 +01:00
getPath ( ) {
2020-08-19 15:54:23 +01:00
return cmd ;
2020-06-26 17:22:19 +01:00
} ,
2020-09-14 10:44:43 +01:00
async printVersion ( ) {
2020-11-20 11:35:59 +01:00
await new toolrunner . ToolRunner ( cmd , [ "version" , "--format=json" ] ) . exec ( ) ;
2020-06-26 17:22:19 +01:00
} ,
2020-09-14 10:44:43 +01:00
async getTracerEnv ( databasePath ) {
2020-08-27 16:34:09 +01:00
// Write tracer-env.js to a temp location.
2021-05-13 22:01:26 +02:00
// BEWARE: The name and location of this file is recognized by `codeql database
// trace-command` in order to enable special support for concatenable tracer
// configurations. Consequently the name must not be changed.
// (This warning can be removed once a different way to recognize the
// action/runner has been implemented in `codeql database trace-command`
// _and_ is present in the latest supported CLI release.)
2020-09-14 10:44:43 +01:00
const tracerEnvJs = path . resolve ( databasePath , "working" , "tracer-env.js" ) ;
2020-08-26 16:18:53 +01:00
fs . mkdirSync ( path . dirname ( tracerEnvJs ) , { recursive : true } ) ;
fs . writeFileSync ( tracerEnvJs , `
const fs = require('fs');
const env = {};
for (let entry of Object.entries(process.env)) {
const key = entry[0];
const value = entry[1];
if (typeof value !== 'undefined' && key !== '_' && !key.startsWith('JAVA_MAIN_CLASS_')) {
env[key] = value;
}
}
process.stdout.write(process.argv[2]);
fs.writeFileSync(process.argv[2], JSON.stringify(env), 'utf-8'); ` ) ;
2021-05-13 22:01:26 +02:00
// BEWARE: The name and location of this file is recognized by `codeql database
// trace-command` in order to enable special support for concatenable tracer
// configurations. Consequently the name must not be changed.
// (This warning can be removed once a different way to recognize the
// action/runner has been implemented in `codeql database trace-command`
// _and_ is present in the latest supported CLI release.)
2020-09-14 10:44:43 +01:00
const envFile = path . resolve ( databasePath , "working" , "env.tmp" ) ;
2020-11-20 11:35:59 +01:00
await new toolrunner . ToolRunner ( cmd , [
2020-09-14 10:44:43 +01:00
"database" ,
"trace-command" ,
2020-07-02 14:45:14 +01:00
databasePath ,
2020-09-14 10:44:43 +01:00
... getExtraOptionsFromEnv ( [ "database" , "trace-command" ] ) ,
2020-06-26 17:22:19 +01:00
process . execPath ,
2020-08-26 16:18:53 +01:00
tracerEnvJs ,
2020-09-14 10:44:43 +01:00
envFile ,
2020-08-28 16:37:14 +01:00
] ) . exec ( ) ;
2020-09-14 10:44:43 +01:00
return JSON . parse ( fs . readFileSync ( envFile , "utf-8" ) ) ;
2020-06-26 17:22:19 +01:00
} ,
2020-09-14 10:44:43 +01:00
async databaseInit ( databasePath , language , sourceRoot ) {
2020-11-20 11:35:59 +01:00
await new toolrunner . ToolRunner ( cmd , [
2020-09-14 10:44:43 +01:00
"database" ,
"init" ,
2020-07-02 14:45:14 +01:00
databasePath ,
2020-09-14 10:44:43 +01:00
` --language= ${ language } ` ,
` --source-root= ${ sourceRoot } ` ,
... getExtraOptionsFromEnv ( [ "database" , "init" ] ) ,
2020-08-28 16:37:14 +01:00
] ) . exec ( ) ;
2020-06-26 17:22:19 +01:00
} ,
2020-09-14 10:44:43 +01:00
async runAutobuild ( language ) {
const cmdName = process . platform === "win32" ? "autobuild.cmd" : "autobuild.sh" ;
const autobuildCmd = path . join ( path . dirname ( cmd ) , language , "tools" , cmdName ) ;
2020-07-02 14:45:14 +01:00
// Update JAVA_TOOL_OPTIONS to contain '-Dhttp.keepAlive=false'
// This is because of an issue with Azure pipelines timing out connections after 4 minutes
// and Maven not properly handling closed connections
// Otherwise long build processes will timeout when pulling down Java packages
// https://developercommunity.visualstudio.com/content/problem/292284/maven-hosted-agent-connection-timeout.html
2020-09-14 10:44:43 +01:00
const javaToolOptions = process . env [ "JAVA_TOOL_OPTIONS" ] || "" ;
process . env [ "JAVA_TOOL_OPTIONS" ] = [
... javaToolOptions . split ( /\s+/ ) ,
"-Dhttp.keepAlive=false" ,
"-Dmaven.wagon.http.pool=false" ,
] . join ( " " ) ;
2020-11-20 11:35:59 +01:00
await new toolrunner . ToolRunner ( autobuildCmd ) . exec ( ) ;
2020-07-02 14:45:14 +01:00
} ,
2020-09-14 10:44:43 +01:00
async extractScannedLanguage ( databasePath , language ) {
2020-06-26 17:22:19 +01:00
// Get extractor location
2020-09-14 10:44:43 +01:00
let extractorPath = "" ;
2020-11-20 11:35:59 +01:00
await new toolrunner . ToolRunner ( cmd , [
2020-09-14 10:44:43 +01:00
"resolve" ,
"extractor" ,
"--format=json" ,
` --language= ${ language } ` ,
... getExtraOptionsFromEnv ( [ "resolve" , "extractor" ] ) ,
2020-09-03 17:01:51 +01:00
] , {
2020-06-26 17:22:19 +01:00
silent : true ,
listeners : {
2020-09-14 10:44:43 +01:00
stdout : ( data ) => {
extractorPath += data . toString ( ) ;
} ,
stderr : ( data ) => {
process . stderr . write ( data ) ;
} ,
} ,
2020-08-28 16:37:14 +01:00
} ) . exec ( ) ;
2020-06-26 17:22:19 +01:00
// Set trace command
2020-09-14 10:44:43 +01:00
const ext = process . platform === "win32" ? ".cmd" : ".sh" ;
const traceCommand = path . resolve ( JSON . parse ( extractorPath ) , "tools" , ` autobuild ${ ext } ` ) ;
2020-06-26 17:22:19 +01:00
// Run trace command
2020-09-08 00:01:04 +01:00
await toolrunner _error _catcher _1 . toolrunnerErrorCatcher ( cmd , [
2020-09-14 10:44:43 +01:00
"database" ,
"trace-command" ,
... getExtraOptionsFromEnv ( [ "database" , "trace-command" ] ) ,
2020-07-02 14:45:14 +01:00
databasePath ,
2020-09-14 10:44:43 +01:00
"--" ,
traceCommand ,
2020-09-07 22:50:37 +01:00
] , error _matcher _1 . errorMatchers ) ;
2020-06-26 17:22:19 +01:00
} ,
2020-11-03 08:25:40 -08:00
async finalizeDatabase ( databasePath , threadsFlag ) {
2020-09-08 00:01:04 +01:00
await toolrunner _error _catcher _1 . toolrunnerErrorCatcher ( cmd , [
2020-09-14 10:44:43 +01:00
"database" ,
"finalize" ,
2020-11-03 08:25:40 -08:00
threadsFlag ,
2020-09-14 10:44:43 +01:00
... getExtraOptionsFromEnv ( [ "database" , "finalize" ] ) ,
databasePath ,
2020-09-07 22:50:37 +01:00
] , error _matcher _1 . errorMatchers ) ;
2020-06-26 17:22:19 +01:00
} ,
2021-05-23 16:27:46 +02:00
async resolveLanguages ( ) {
const codeqlArgs = [ "resolve" , "languages" , "--format=json" ] ;
let output = "" ;
await new toolrunner . ToolRunner ( cmd , codeqlArgs , {
listeners : {
stdout : ( data ) => {
output += data . toString ( ) ;
} ,
} ,
} ) . exec ( ) ;
2021-05-24 11:00:02 +02:00
try {
return JSON . parse ( output ) ;
}
catch ( e ) {
throw new Error ( ` Unexpected output from codeql resolve languages: ${ e } ` ) ;
}
2021-05-23 16:27:46 +02:00
} ,
2020-09-14 10:44:43 +01:00
async resolveQueries ( queries , extraSearchPath ) {
2020-06-26 15:33:59 +01:00
const codeqlArgs = [
2020-09-14 10:44:43 +01:00
"resolve" ,
"queries" ,
2020-06-26 17:22:19 +01:00
... queries ,
2020-09-14 10:44:43 +01:00
"--format=bylanguage" ,
... getExtraOptionsFromEnv ( [ "resolve" , "queries" ] ) ,
2020-06-26 15:33:59 +01:00
] ;
if ( extraSearchPath !== undefined ) {
2021-05-20 19:03:50 +00:00
codeqlArgs . push ( "--additional-packs" , extraSearchPath ) ;
2020-06-26 15:33:59 +01:00
}
2020-09-14 10:44:43 +01:00
let output = "" ;
2020-11-20 11:35:59 +01:00
await new toolrunner . ToolRunner ( cmd , codeqlArgs , {
2020-06-26 17:22:19 +01:00
listeners : {
stdout : ( data ) => {
output += data . toString ( ) ;
2020-09-14 10:44:43 +01:00
} ,
} ,
2020-08-28 16:37:14 +01:00
} ) . exec ( ) ;
2021-05-24 11:00:02 +02:00
try {
return JSON . parse ( output ) ;
}
catch ( e ) {
throw new Error ( ` Unexpected output from codeql resolve queries: ${ e } ` ) ;
}
2020-06-26 17:22:19 +01:00
} ,
2021-05-03 19:41:53 +02:00
async databaseAnalyze ( databasePath , sarifFile , extraSearchPath , querySuite , memoryFlag , addSnippetsFlag , threadsFlag , automationDetailsId ) {
2021-04-01 12:38:13 +01:00
const args = [
2020-09-14 10:44:43 +01:00
"database" ,
"analyze" ,
2020-09-01 14:13:10 +01:00
memoryFlag ,
threadsFlag ,
2020-07-02 14:45:14 +01:00
databasePath ,
2020-09-24 11:42:21 +02:00
"--min-disk-free=1024" ,
2020-09-14 10:44:43 +01:00
"--format=sarif-latest" ,
2020-09-24 10:56:43 +01:00
"--sarif-multicause-markdown" ,
2021-06-04 09:58:35 +01:00
"--sarif-group-rules-by-pack" ,
2020-09-14 10:44:43 +01:00
` --output= ${ sarifFile } ` ,
2020-09-10 17:18:02 +01:00
addSnippetsFlag ,
2021-05-05 18:09:10 +01:00
// Enable progress verbosity so we log each query as it's interpreted. This aids debugging
// when interpretation takes a while for one of the queries being analyzed.
"-v" ,
2020-09-14 10:44:43 +01:00
... getExtraOptionsFromEnv ( [ "database" , "analyze" ] ) ,
2021-04-01 12:38:13 +01:00
] ;
if ( extraSearchPath !== undefined ) {
2021-05-20 19:03:50 +00:00
args . push ( "--additional-packs" , extraSearchPath ) ;
2021-04-01 12:38:13 +01:00
}
2021-05-03 19:41:53 +02:00
if ( automationDetailsId !== undefined ) {
args . push ( "--sarif-category" , automationDetailsId ) ;
}
2021-04-01 12:38:13 +01:00
args . push ( querySuite ) ;
2021-05-19 16:01:06 -07:00
// capture stdout, which contains analysis summaries
let output = "" ;
await new toolrunner . ToolRunner ( cmd , args , {
listeners : {
stdout : ( data ) => {
2021-05-20 14:08:29 -07:00
output += data . toString ( "utf8" ) ;
2021-05-19 16:01:06 -07:00
} ,
} ,
} ) . exec ( ) ;
return output ;
2020-09-14 10:44:43 +01:00
} ,
2021-05-24 17:26:13 +01:00
async databaseCleanup ( databasePath , cleanupLevel ) {
const args = [
"database" ,
"cleanup" ,
databasePath ,
` --mode= ${ cleanupLevel } ` ,
] ;
await new toolrunner . ToolRunner ( cmd , args ) . exec ( ) ;
} ,
2020-06-26 17:22:19 +01:00
} ;
}
2020-08-10 09:25:14 +02:00
/**
* Gets the options for `path` of `options` as an array of extra option strings.
*/
2020-11-19 23:03:45 +01:00
function getExtraOptionsFromEnv ( paths ) {
2020-09-14 10:44:43 +01:00
const options = util . getExtraOptionsEnvParam ( ) ;
2020-11-19 23:03:45 +01:00
return getExtraOptions ( options , paths , [ ] ) ;
}
/**
* Gets `options` as an array of extra option strings.
*
* - throws an exception mentioning `pathInfo` if this conversion is impossible.
*/
function asExtraOptions ( options , pathInfo ) {
if ( options === undefined ) {
return [ ] ;
}
if ( ! Array . isArray ( options ) ) {
const msg = ` The extra options for ' ${ pathInfo . join ( "." ) } ' (' ${ JSON . stringify ( options ) } ') are not in an array. ` ;
throw new Error ( msg ) ;
}
return options . map ( ( o ) => {
const t = typeof o ;
if ( t !== "string" && t !== "number" && t !== "boolean" ) {
const msg = ` The extra option for ' ${ pathInfo . join ( "." ) } ' (' ${ JSON . stringify ( o ) } ') is not a primitive value. ` ;
throw new Error ( msg ) ;
}
return ` ${ o } ` ;
} ) ;
2020-08-10 09:25:14 +02:00
}
/**
* Gets the options for `path` of `options` as an array of extra option strings.
*
* - the special terminal step name '*' in `options` matches all path steps
* - throws an exception if this conversion is impossible.
2020-09-23 20:25:45 +08:00
*
* Exported for testing.
2020-08-10 09:25:14 +02:00
*/
2020-11-19 23:03:45 +01:00
function getExtraOptions ( options , paths , pathInfo ) {
2020-08-10 09:25:14 +02:00
var _a , _b , _c ;
2020-09-14 10:44:43 +01:00
const all = asExtraOptions ( ( _a = options ) === null || _a === void 0 ? void 0 : _a [ "*" ] , pathInfo . concat ( "*" ) ) ;
2020-11-19 23:03:45 +01:00
const specific = paths . length === 0
2020-09-14 10:44:43 +01:00
? asExtraOptions ( options , pathInfo )
2020-11-19 23:03:45 +01:00
: getExtraOptions ( ( _b = options ) === null || _b === void 0 ? void 0 : _b [ paths [ 0 ] ] , ( _c = paths ) === null || _c === void 0 ? void 0 : _c . slice ( 1 ) , pathInfo . concat ( paths [ 0 ] ) ) ;
2020-08-10 09:25:14 +02:00
return all . concat ( specific ) ;
}
exports . getExtraOptions = getExtraOptions ;
2020-06-26 17:22:19 +01:00
//# sourceMappingURL=codeql.js.map