2020-08-25 16:19:15 +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-08-25 16:19:15 +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-08-25 16:19:15 +01:00
return result ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
2021-07-27 17:59:59 +01:00
exports . runCleanup = exports . runFinalize = exports . runQueries = exports . CodeQLAnalysisError = void 0 ;
2020-08-25 16:19:15 +01:00
const fs = _ _importStar ( require ( "fs" ) ) ;
const path = _ _importStar ( require ( "path" ) ) ;
2020-11-20 11:35:59 +01:00
const toolrunner = _ _importStar ( require ( "@actions/exec/lib/toolrunner" ) ) ;
2021-06-28 10:07:51 +01:00
const yaml = _ _importStar ( require ( "js-yaml" ) ) ;
2020-08-25 16:19:15 +01:00
const analysisPaths = _ _importStar ( require ( "./analysis-paths" ) ) ;
const codeql _1 = require ( "./codeql" ) ;
2021-04-16 14:52:39 -07:00
const count _loc _1 = require ( "./count-loc" ) ;
2020-08-25 16:19:15 +01:00
const languages _1 = require ( "./languages" ) ;
const sharedEnv = _ _importStar ( require ( "./shared-environment" ) ) ;
2022-02-17 15:45:00 +00:00
const tracer _config _1 = require ( "./tracer-config" ) ;
2020-08-25 16:19:15 +01:00
const util = _ _importStar ( require ( "./util" ) ) ;
2020-10-22 10:22:27 +02:00
class CodeQLAnalysisError extends Error {
constructor ( queriesStatusReport , message ) {
super ( message ) ;
this . name = "CodeQLAnalysisError" ;
this . queriesStatusReport = queriesStatusReport ;
}
}
exports . CodeQLAnalysisError = CodeQLAnalysisError ;
2020-09-11 11:07:27 +02:00
async function setupPythonExtractor ( logger ) {
const codeqlPython = process . env [ "CODEQL_PYTHON" ] ;
if ( codeqlPython === undefined || codeqlPython . length === 0 ) {
// If CODEQL_PYTHON is not set, no dependencies were installed, so we don't need to do anything
return ;
}
2020-09-23 09:27:54 +02:00
let output = "" ;
2020-09-11 11:07:27 +02:00
const options = {
listeners : {
stdout : ( data ) => {
output += data . toString ( ) ;
2020-09-23 09:27:54 +02:00
} ,
} ,
2020-09-11 11:07:27 +02:00
} ;
2020-11-20 11:35:59 +01:00
await new toolrunner . ToolRunner ( codeqlPython , [
2020-09-23 09:27:54 +02:00
"-c" ,
2020-09-23 18:06:08 +02:00
"import os; import pip; print(os.path.dirname(os.path.dirname(pip.__file__)))" ,
2020-09-23 09:27:54 +02:00
] , options ) . exec ( ) ;
logger . info ( ` Setting LGTM_INDEX_IMPORT_PATH= ${ output } ` ) ;
process . env [ "LGTM_INDEX_IMPORT_PATH" ] = output ;
output = "" ;
2020-11-20 11:35:59 +01:00
await new toolrunner . ToolRunner ( codeqlPython , [ "-c" , "import sys; print(sys.version_info[0])" ] , options ) . exec ( ) ;
2020-09-23 09:27:54 +02:00
logger . info ( ` Setting LGTM_PYTHON_SETUP_VERSION= ${ output } ` ) ;
process . env [ "LGTM_PYTHON_SETUP_VERSION" ] = output ;
2020-09-11 11:07:27 +02:00
}
2020-08-25 16:19:15 +01:00
async function createdDBForScannedLanguages ( config , logger ) {
// Insert the LGTM_INDEX_X env vars at this point so they are set when
// we extract any scanned languages.
analysisPaths . includeAndExcludeAnalysisPaths ( config ) ;
2021-09-10 13:53:13 -07:00
const codeql = await ( 0 , codeql _1 . getCodeQL ) ( config . codeQLCmd ) ;
2020-08-25 16:19:15 +01:00
for ( const language of config . languages ) {
2021-09-10 13:53:13 -07:00
if ( ( 0 , languages _1 . isScannedLanguage ) ( language ) &&
2021-06-28 10:07:51 +01:00
! dbIsFinalized ( config , language , logger ) ) {
2020-09-14 10:44:43 +01:00
logger . startGroup ( ` Extracting ${ language } ` ) ;
2020-09-11 11:07:27 +02:00
if ( language === languages _1 . Language . python ) {
await setupPythonExtractor ( logger ) ;
}
2021-05-17 10:35:09 +01:00
await codeql . extractScannedLanguage ( util . getCodeQLDatabasePath ( config , language ) , language ) ;
2020-08-25 16:19:15 +01:00
logger . endGroup ( ) ;
}
}
}
2021-06-28 10:07:51 +01:00
function dbIsFinalized ( config , language , logger ) {
const dbPath = util . getCodeQLDatabasePath ( config , language ) ;
try {
const dbInfo = yaml . load ( fs . readFileSync ( path . resolve ( dbPath , "codeql-database.yml" ) , "utf8" ) ) ;
return ! ( "inProgress" in dbInfo ) ;
}
catch ( e ) {
logger . warning ( ` Could not check whether database for ${ language } was finalized. Assuming it is not. ` ) ;
return false ;
}
}
2021-08-12 16:02:19 +01:00
async function finalizeDatabaseCreation ( config , threadsFlag , memoryFlag , logger ) {
2020-08-25 16:19:15 +01:00
await createdDBForScannedLanguages ( config , logger ) ;
2021-09-10 13:53:13 -07:00
const codeql = await ( 0 , codeql _1 . getCodeQL ) ( config . codeQLCmd ) ;
2020-08-25 16:19:15 +01:00
for ( const language of config . languages ) {
2021-06-28 10:07:51 +01:00
if ( dbIsFinalized ( config , language , logger ) ) {
logger . info ( ` There is already a finalized database for ${ language } at the location where the CodeQL Action places databases, so we did not create one. ` ) ;
}
else {
logger . startGroup ( ` Finalizing ${ language } ` ) ;
2021-08-12 16:02:19 +01:00
await codeql . finalizeDatabase ( util . getCodeQLDatabasePath ( config , language ) , threadsFlag , memoryFlag ) ;
2021-06-28 10:07:51 +01:00
logger . endGroup ( ) ;
}
2020-08-25 16:19:15 +01:00
}
}
// Runs queries and creates sarif files in the given folder
2021-05-03 19:41:53 +02:00
async function runQueries ( sarifFolder , memoryFlag , addSnippetsFlag , threadsFlag , automationDetailsId , config , logger ) {
2020-09-10 18:02:33 +01:00
const statusReport = { } ;
2021-09-28 09:25:35 +01:00
let locPromise = Promise . resolve ( { } ) ;
const cliCanCountBaseline = await cliCanCountLoC ( ) ;
const debugMode = process . env [ "INTERNAL_CODEQL_ACTION_DEBUG_LOC" ] ||
process . env [ "ACTIONS_RUNNER_DEBUG" ] ||
process . env [ "ACTIONS_STEP_DEBUG" ] ;
if ( ! cliCanCountBaseline || debugMode ) {
// count the number of lines in the background
locPromise = ( 0 , count _loc _1 . countLoc ) ( path . resolve ( ) ,
// config.paths specifies external directories. the current
// directory is included in the analysis by default. Replicate
// that here.
config . paths , config . pathsIgnore , config . languages , logger ) ;
}
2020-09-14 10:44:43 +01:00
for ( const language of config . languages ) {
2020-09-10 18:02:33 +01:00
const queries = config . queries [ language ] ;
2021-06-03 09:32:44 -07:00
const packsWithVersion = config . packs [ language ] || [ ] ;
2021-07-27 17:59:59 +01:00
const hasBuiltinQueries = ( queries === null || queries === void 0 ? void 0 : queries . builtin . length ) > 0 ;
const hasCustomQueries = ( queries === null || queries === void 0 ? void 0 : queries . custom . length ) > 0 ;
2021-06-04 13:12:49 -07:00
const hasPackWithCustomQueries = packsWithVersion . length > 0 ;
if ( ! hasBuiltinQueries && ! hasCustomQueries && ! hasPackWithCustomQueries ) {
2020-09-14 10:44:43 +01:00
throw new Error ( ` Unable to analyse ${ language } as no queries were selected for this language ` ) ;
2020-08-25 16:19:15 +01:00
}
2022-03-25 11:15:02 +00:00
const codeql = await ( 0 , codeql _1 . getCodeQL ) ( config . codeQLCmd ) ;
2020-08-25 16:19:15 +01:00
try {
2022-04-05 09:34:40 +01:00
if ( hasPackWithCustomQueries ) {
2022-01-24 09:42:57 -08:00
logger . info ( "Performing analysis with custom CodeQL Packs." ) ;
2021-06-09 13:19:49 -07:00
logger . startGroup ( ` Downloading custom packs for ${ language } ` ) ;
2022-04-29 10:54:01 -07:00
const results = await codeql . packDownload ( packsWithVersion ) ;
2021-06-04 13:44:24 -07:00
logger . info ( ` Downloaded packs: ${ results . packs
. map ( ( r ) => ` ${ r . name } @ ${ r . version || "latest" } ` )
. join ( ", " ) } ` ) ;
2021-06-09 13:19:49 -07:00
logger . endGroup ( ) ;
2021-06-04 13:44:24 -07:00
}
2021-06-09 13:19:49 -07:00
logger . startGroup ( ` Running queries for ${ language } ` ) ;
2021-06-04 14:28:55 +01:00
const querySuitePaths = [ ] ;
2021-04-01 12:38:13 +01:00
if ( queries [ "builtin" ] . length > 0 ) {
2021-05-28 18:32:53 +01:00
const startTimeBuiltIn = new Date ( ) . getTime ( ) ;
2021-06-09 12:43:17 -07:00
querySuitePaths . push ( await runQueryGroup ( language , "builtin" , createQuerySuiteContents ( queries [ "builtin" ] ) , undefined ) ) ;
2021-04-01 12:38:13 +01:00
statusReport [ ` analyze_builtin_queries_ ${ language } _duration_ms ` ] =
2021-05-28 18:32:53 +01:00
new Date ( ) . getTime ( ) - startTimeBuiltIn ;
2021-04-01 12:38:13 +01:00
}
const startTimeCustom = new Date ( ) . getTime ( ) ;
2021-06-04 14:28:55 +01:00
let ranCustom = false ;
2021-04-01 12:38:13 +01:00
for ( let i = 0 ; i < queries [ "custom" ] . length ; ++ i ) {
if ( queries [ "custom" ] [ i ] . queries . length > 0 ) {
2021-06-09 12:43:17 -07:00
querySuitePaths . push ( await runQueryGroup ( language , ` custom- ${ i } ` , createQuerySuiteContents ( queries [ "custom" ] [ i ] . queries ) , queries [ "custom" ] [ i ] . searchPath ) ) ;
2021-06-04 14:28:55 +01:00
ranCustom = true ;
2020-09-10 18:02:33 +01:00
}
}
2021-06-03 09:32:44 -07:00
if ( packsWithVersion . length > 0 ) {
2022-04-26 19:47:59 -07:00
querySuitePaths . push ( ... ( await runQueryPacks ( language , "packs" , packsWithVersion , undefined ) ) ) ;
2021-06-09 12:43:17 -07:00
ranCustom = true ;
2021-06-03 09:32:44 -07:00
}
2021-06-04 14:28:55 +01:00
if ( ranCustom ) {
2021-04-01 12:38:13 +01:00
statusReport [ ` analyze_custom_queries_ ${ language } _duration_ms ` ] =
new Date ( ) . getTime ( ) - startTimeCustom ;
}
2021-05-19 16:01:06 -07:00
logger . endGroup ( ) ;
2021-06-04 14:28:55 +01:00
logger . startGroup ( ` Interpreting results for ${ language } ` ) ;
const startTimeInterpretResults = new Date ( ) . getTime ( ) ;
const sarifFile = path . join ( sarifFolder , ` ${ language } .sarif ` ) ;
const analysisSummary = await runInterpretResults ( language , querySuitePaths , sarifFile ) ;
2021-09-28 09:25:35 +01:00
if ( ! cliCanCountBaseline )
await injectLinesOfCode ( sarifFile , language , locPromise ) ;
2021-06-04 14:28:55 +01:00
statusReport [ ` interpret_results_ ${ language } _duration_ms ` ] =
new Date ( ) . getTime ( ) - startTimeInterpretResults ;
2021-05-19 16:01:06 -07:00
logger . endGroup ( ) ;
2021-06-04 14:28:55 +01:00
logger . info ( analysisSummary ) ;
2021-09-28 09:25:35 +01:00
if ( ! cliCanCountBaseline || debugMode )
printLinesOfCodeSummary ( logger , language , await locPromise ) ;
if ( cliCanCountBaseline )
logger . info ( await runPrintLinesOfCode ( language ) ) ;
2020-08-25 16:19:15 +01:00
}
catch ( e ) {
2021-09-10 13:53:13 -07:00
logger . info ( String ( e ) ) ;
if ( e instanceof Error ) {
logger . info ( e . stack ) ;
}
2020-09-10 18:02:33 +01:00
statusReport . analyze _failure _language = language ;
2020-10-22 10:22:27 +02:00
throw new CodeQLAnalysisError ( statusReport , ` Error running analysis for ${ language } : ${ e } ` ) ;
2020-08-25 16:19:15 +01:00
}
}
2020-09-10 18:02:33 +01:00
return statusReport ;
2021-06-04 14:28:55 +01:00
async function runInterpretResults ( language , queries , sarifFile ) {
const databasePath = util . getCodeQLDatabasePath ( config , language ) ;
2021-09-10 13:53:13 -07:00
const codeql = await ( 0 , codeql _1 . getCodeQL ) ( config . codeQLCmd ) ;
2021-06-04 14:28:55 +01:00
return await codeql . databaseInterpretResults ( databasePath , queries , sarifFile , addSnippetsFlag , threadsFlag , automationDetailsId ) ;
}
2021-09-28 09:25:35 +01:00
async function cliCanCountLoC ( ) {
return await util . codeQlVersionAbove ( await ( 0 , codeql _1 . getCodeQL ) ( config . codeQLCmd ) , codeql _1 . CODEQL _VERSION _COUNTS _LINES ) ;
}
async function runPrintLinesOfCode ( language ) {
const databasePath = util . getCodeQLDatabasePath ( config , language ) ;
const codeql = await ( 0 , codeql _1 . getCodeQL ) ( config . codeQLCmd ) ;
return await codeql . databasePrintBaseline ( databasePath ) ;
}
2021-06-09 12:43:17 -07:00
async function runQueryGroup ( language , type , querySuiteContents , searchPath ) {
2021-05-17 10:35:09 +01:00
const databasePath = util . getCodeQLDatabasePath ( config , language ) ;
2021-04-01 12:38:13 +01:00
// Pass the queries to codeql using a file instead of using the command
// line to avoid command line length restrictions, particularly on windows.
const querySuitePath = ` ${ databasePath } -queries- ${ type } .qls ` ;
fs . writeFileSync ( querySuitePath , querySuiteContents ) ;
2021-06-03 09:32:44 -07:00
logger . debug ( ` Query suite file for ${ language } - ${ type } ... \n ${ querySuiteContents } ` ) ;
2021-09-10 13:53:13 -07:00
const codeql = await ( 0 , codeql _1 . getCodeQL ) ( config . codeQLCmd ) ;
2021-06-04 14:28:55 +01:00
await codeql . databaseRunQueries ( databasePath , searchPath , querySuitePath , memoryFlag , threadsFlag ) ;
logger . debug ( ` BQRS results produced for ${ language } (queries: ${ type } )" ` ) ;
return querySuitePath ;
2021-04-01 12:38:13 +01:00
}
2022-04-26 19:47:59 -07:00
async function runQueryPacks ( language , type , packs , searchPath ) {
const databasePath = util . getCodeQLDatabasePath ( config , language ) ;
// Run the queries individually instead of all at once to avoid command
// line length restrictions, particularly on windows.
for ( const pack of packs ) {
logger . debug ( ` Running query pack for ${ language } - ${ type } : ${ pack } ` ) ;
const codeql = await ( 0 , codeql _1 . getCodeQL ) ( config . codeQLCmd ) ;
await codeql . databaseRunQueries ( databasePath , searchPath , pack , memoryFlag , threadsFlag ) ;
logger . debug ( ` BQRS results produced for ${ language } (queries: ${ type } )" ` ) ;
}
return packs ;
}
2020-08-25 16:19:15 +01:00
}
2020-09-10 18:02:33 +01:00
exports . runQueries = runQueries ;
2021-06-03 09:32:44 -07:00
function createQuerySuiteContents ( queries ) {
return queries . map ( ( q ) => ` - query: ${ q } ` ) . join ( "\n" ) ;
}
2021-08-12 16:02:19 +01:00
async function runFinalize ( outputDir , threadsFlag , memoryFlag , config , logger ) {
2022-02-17 15:45:00 +00:00
const codeql = await ( 0 , codeql _1 . getCodeQL ) ( config . codeQLCmd ) ;
if ( await util . codeQlVersionAbove ( codeql , codeql _1 . CODEQL _VERSION _NEW _TRACING ) ) {
// Delete variables as specified by the end-tracing script
await ( 0 , tracer _config _1 . endTracingForCluster ) ( config ) ;
}
else {
// Delete the tracer config env var to avoid tracing ourselves
delete process . env [ sharedEnv . ODASA _TRACER _CONFIGURATION ] ;
}
2022-02-28 15:16:05 +00:00
// After switching to Node16, this entire block can be replaced with `await fs.promises.rm(outputDir, { recursive: true, force: true });`.
try {
2022-02-28 19:37:17 +00:00
await fs . promises . rmdir ( outputDir , {
recursive : true ,
maxRetries : 5 ,
retryDelay : 2000 ,
} ) ;
2022-02-28 15:16:05 +00:00
}
catch ( error ) {
if ( ( error === null || error === void 0 ? void 0 : error . code ) !== "ENOENT" ) {
throw error ;
}
}
await fs . promises . mkdir ( outputDir , { recursive : true } ) ;
2021-08-12 16:02:19 +01:00
await finalizeDatabaseCreation ( config , threadsFlag , memoryFlag , logger ) ;
2020-08-25 16:19:15 +01:00
}
2021-06-28 10:07:51 +01:00
exports . runFinalize = runFinalize ;
2021-05-24 17:26:13 +01:00
async function runCleanup ( config , cleanupLevel , logger ) {
2021-06-09 11:16:22 +01:00
logger . startGroup ( "Cleaning up databases" ) ;
2021-05-24 17:26:13 +01:00
for ( const language of config . languages ) {
2021-09-10 13:53:13 -07:00
const codeql = await ( 0 , codeql _1 . getCodeQL ) ( config . codeQLCmd ) ;
2021-05-24 17:26:13 +01:00
const databasePath = util . getCodeQLDatabasePath ( config , language ) ;
await codeql . databaseCleanup ( databasePath , cleanupLevel ) ;
}
2021-06-09 11:16:22 +01:00
logger . endGroup ( ) ;
2021-05-24 17:26:13 +01:00
}
exports . runCleanup = runCleanup ;
2021-04-16 14:52:39 -07:00
async function injectLinesOfCode ( sarifFile , language , locPromise ) {
2021-07-21 10:27:42 +01:00
var _a ;
2021-04-16 14:52:39 -07:00
const lineCounts = await locPromise ;
if ( language in lineCounts ) {
const sarif = JSON . parse ( fs . readFileSync ( sarifFile , "utf8" ) ) ;
if ( Array . isArray ( sarif . runs ) ) {
for ( const run of sarif . runs ) {
run . properties = run . properties || { } ;
run . properties . metricResults = run . properties . metricResults || [ ] ;
2021-07-21 10:27:42 +01:00
for ( const metric of run . properties . metricResults ) {
2021-08-26 13:46:22 +01:00
// Baseline is inserted when matching rule has tag lines-of-code
2021-07-21 10:27:42 +01:00
if ( metric . rule && metric . rule . toolComponent ) {
const matchingRule = run . tool . extensions [ metric . rule . toolComponent . index ] . rules [ metric . rule . index ] ;
if ( ( _a = matchingRule . properties . tags ) === null || _a === void 0 ? void 0 : _a . includes ( "lines-of-code" ) ) {
metric . baseline = lineCounts [ language ] ;
}
}
}
2021-04-16 14:52:39 -07:00
}
}
fs . writeFileSync ( sarifFile , JSON . stringify ( sarif ) ) ;
}
}
2021-05-13 17:56:27 +00:00
function printLinesOfCodeSummary ( logger , language , lineCounts ) {
if ( language in lineCounts ) {
2021-06-09 13:19:49 -07:00
logger . info ( ` Counted a baseline of ${ lineCounts [ language ] } lines of code for ${ language } . ` ) ;
2021-05-13 17:56:27 +00:00
}
}
2020-08-25 16:19:15 +01:00
//# sourceMappingURL=analyze.js.map