2020-08-11 12:43:27 +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 ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
const commander _1 = require ( "commander" ) ;
2020-08-25 16:19:15 +01:00
const fs = _ _importStar ( require ( "fs" ) ) ;
const os = _ _importStar ( require ( "os" ) ) ;
2020-08-11 12:43:27 +01:00
const path = _ _importStar ( require ( "path" ) ) ;
2020-08-25 16:19:15 +01:00
const analyze _1 = require ( "./analyze" ) ;
const autobuild _1 = require ( "./autobuild" ) ;
const codeql _1 = require ( "./codeql" ) ;
2020-08-27 14:04:09 +01:00
const config _utils _1 = require ( "./config-utils" ) ;
2020-08-25 16:19:15 +01:00
const init _1 = require ( "./init" ) ;
const languages _1 = require ( "./languages" ) ;
2020-08-11 12:43:27 +01:00
const logging _1 = require ( "./logging" ) ;
const repository _1 = require ( "./repository" ) ;
const upload _lib = _ _importStar ( require ( "./upload-lib" ) ) ;
2020-09-01 14:13:10 +01:00
const util _1 = require ( "./util" ) ;
2020-08-11 12:43:27 +01:00
const program = new commander _1 . Command ( ) ;
program . version ( '0.0.1' ) ;
2020-08-25 16:19:15 +01:00
function parseGithubUrl ( inputUrl ) {
2020-08-11 12:43:27 +01:00
try {
const url = new URL ( inputUrl ) ;
// 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-08-25 16:19:15 +01:00
return 'https://github.com' ;
2020-08-11 12:43:27 +01:00
}
2020-08-25 16:19:15 +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' ) ) ;
2020-08-11 12:43:27 +01:00
}
return url . toString ( ) ;
}
catch ( e ) {
throw new Error ( ` " ${ inputUrl } " is not a valid URL ` ) ;
}
}
2020-08-25 16:19:15 +01:00
function getTempDir ( userInput ) {
2020-08-28 09:27:28 +01:00
const tempDir = path . join ( userInput || process . cwd ( ) , 'codeql-runner' ) ;
2020-08-25 16:19:15 +01:00
if ( ! fs . existsSync ( tempDir ) ) {
fs . mkdirSync ( tempDir , { recursive : true } ) ;
}
return tempDir ;
}
2020-08-27 13:39:07 +01:00
function getToolsDir ( userInput ) {
const toolsDir = userInput || path . join ( os . homedir ( ) , 'codeql-runner-tools' ) ;
2020-08-25 16:19:15 +01:00
if ( ! fs . existsSync ( toolsDir ) ) {
fs . mkdirSync ( toolsDir , { recursive : true } ) ;
}
return toolsDir ;
}
2020-08-28 17:22:26 +01:00
const codeqlEnvJsonFilename = 'codeql-env.json' ;
// Imports the environment from codeqlEnvJsonFilename if not already present
function importTracerEnvironment ( config ) {
if ( ! ( 'ODASA_TRACER_CONFIGURATION' in process . env ) ) {
const jsonEnvFile = path . join ( config . tempDir , codeqlEnvJsonFilename ) ;
const env = JSON . parse ( fs . readFileSync ( jsonEnvFile ) . toString ( 'utf-8' ) ) ;
Object . keys ( env ) . forEach ( key => process . env [ key ] = env [ key ] ) ;
2020-08-27 14:22:16 +01:00
}
}
2020-09-02 18:00:46 +01:00
// Allow the user to specify refs in full refs/heads/branch format
// or just the short branch name and prepend "refs/heads/" to it.
function parseRef ( userInput ) {
if ( userInput . startsWith ( 'refs/' ) ) {
return userInput ;
}
else {
return 'refs/heads/' + userInput ;
}
}
2020-08-25 16:19:15 +01:00
program
. command ( 'init' )
. description ( 'Initializes CodeQL' )
2020-08-28 09:35:16 +01:00
. requiredOption ( '--repository <repository>' , 'Repository name. (Required)' )
. requiredOption ( '--github-url <url>' , 'URL of GitHub instance. (Required)' )
. requiredOption ( '--github-auth <auth>' , 'GitHub Apps token or personal access token. (Required)' )
. option ( '--languages <languages>' , 'Comma-separated list of languages to analyze. Otherwise detects and analyzes all supported languages from the repo.' )
. option ( '--queries <queries>' , 'Comma-separated list of additional queries to run. This overrides the same setting in a configuration file.' )
. option ( '--config-file <file>' , 'Path to config file.' )
2020-08-25 16:19:15 +01:00
. option ( '--codeql-path <path>' , 'Path to a copy of the CodeQL CLI executable to use. Otherwise downloads a copy.' )
2020-08-28 09:35:16 +01:00
. option ( '--temp-dir <dir>' , 'Directory to use for temporary files. Default is "./codeql-runner".' )
. option ( '--tools-dir <dir>' , 'Directory to use for CodeQL tools and other files to store between runs. Default is a subdirectory of the home directory.' )
. option ( '--checkout-path <path>' , 'Checkout path. Default is the current working directory.' )
2020-08-27 14:26:44 +01:00
. option ( '--debug' , 'Print more verbose output' , false )
2020-08-25 16:19:15 +01:00
. action ( async ( cmd ) => {
2020-08-27 14:26:44 +01:00
const logger = logging _1 . getRunnerLogger ( cmd . debug ) ;
2020-08-25 16:19:15 +01:00
try {
const tempDir = getTempDir ( cmd . tempDir ) ;
2020-08-27 13:39:07 +01:00
const toolsDir = getToolsDir ( cmd . toolsDir ) ;
2020-08-25 16:19:15 +01:00
// Wipe the temp dir
2020-08-27 16:45:41 +01:00
logger . info ( ` Cleaning temp directory ${ tempDir } ` ) ;
2020-08-25 16:19:15 +01:00
fs . rmdirSync ( tempDir , { recursive : true } ) ;
fs . mkdirSync ( tempDir , { recursive : true } ) ;
let codeql ;
if ( cmd . codeqlPath !== undefined ) {
codeql = codeql _1 . getCodeQL ( cmd . codeqlPath ) ;
}
else {
codeql = await init _1 . initCodeQL ( undefined , cmd . githubAuth , parseGithubUrl ( cmd . githubUrl ) , tempDir , toolsDir , 'runner' , logger ) ;
}
2020-08-27 10:46:26 +01:00
const config = await init _1 . initConfig ( cmd . languages , cmd . queries , cmd . configFile , repository _1 . parseRepositoryNwo ( cmd . repository ) , tempDir , toolsDir , codeql , cmd . checkoutPath || process . cwd ( ) , cmd . githubAuth , parseGithubUrl ( cmd . githubUrl ) , logger ) ;
2020-08-26 13:20:46 +01:00
const tracerConfig = await init _1 . runInit ( codeql , config ) ;
2020-08-27 16:34:09 +01:00
if ( tracerConfig === undefined ) {
return ;
}
2020-08-28 17:22:26 +01:00
// Always output a json file of the env that can be consumed programatically
const jsonEnvFile = path . join ( config . tempDir , codeqlEnvJsonFilename ) ;
fs . writeFileSync ( jsonEnvFile , JSON . stringify ( tracerConfig . env ) ) ;
2020-08-27 16:34:09 +01:00
if ( process . platform === 'win32' ) {
const batEnvFile = path . join ( config . tempDir , 'codeql-env.bat' ) ;
const batEnvFileContents = Object . entries ( tracerConfig . env )
. map ( ( [ key , value ] ) => ` Set ${ key } = ${ value } ` )
. join ( '\n' ) ;
fs . writeFileSync ( batEnvFile , batEnvFileContents ) ;
const powershellEnvFile = path . join ( config . tempDir , 'codeql-env.sh' ) ;
const powershellEnvFileContents = Object . entries ( tracerConfig . env )
. map ( ( [ key , value ] ) => ` $ env: ${ key } =" ${ value } " ` )
. join ( '\n' ) ;
fs . writeFileSync ( powershellEnvFile , powershellEnvFileContents ) ;
2020-08-28 17:22:26 +01:00
logger . info ( ` \n CodeQL environment output to " ${ jsonEnvFile } ", " ${ batEnvFileContents } " and " ${ powershellEnvFile } ". ` +
2020-08-27 16:34:09 +01:00
` Please export these variables to future processes so the build can be traced. ` +
` If using cmd/batch run "call ${ batEnvFileContents } " ` +
` or if using PowerShell run "cat ${ powershellEnvFile } | Invoke-Expression". ` ) ;
}
else {
// Assume that anything that's not windows is using a unix-style shell
2020-08-28 17:22:26 +01:00
const shEnvFile = path . join ( config . tempDir , 'codeql-env.sh' ) ;
const shEnvFileContents = Object . entries ( tracerConfig . env )
2020-08-27 16:34:09 +01:00
// Some vars contain ${LIB} that we do not want to be expanded when executing this script
. map ( ( [ key , value ] ) => ` export ${ key } =" ${ value . replace ( '$' , '\\$' ) } " ` )
. join ( '\n' ) ;
2020-08-28 17:22:26 +01:00
fs . writeFileSync ( shEnvFile , shEnvFileContents ) ;
logger . info ( ` \n CodeQL environment output to " ${ jsonEnvFile } " and " ${ shEnvFile } ". ` +
2020-08-27 16:34:09 +01:00
` Please export these variables to future processes so the build can be traced, ` +
2020-08-28 17:22:26 +01:00
` for example by running ". ${ shEnvFile } ". ` ) ;
2020-08-26 13:20:46 +01:00
}
2020-08-25 16:19:15 +01:00
}
catch ( e ) {
logger . error ( 'Init failed' ) ;
logger . error ( e ) ;
process . exitCode = 1 ;
}
} ) ;
program
. command ( 'autobuild' )
. description ( 'Attempts to automatically build code' )
2020-08-28 09:35:16 +01:00
. option ( '--language <language>' , 'The language to build. Otherwise will detect the dominant compiled language.' )
. option ( '--temp-dir <dir>' , 'Directory to use for temporary files. Default is "./codeql-runner".' )
2020-08-27 14:26:44 +01:00
. option ( '--debug' , 'Print more verbose output' , false )
2020-08-25 16:19:15 +01:00
. action ( async ( cmd ) => {
2020-08-27 14:26:44 +01:00
const logger = logging _1 . getRunnerLogger ( cmd . debug ) ;
2020-08-25 16:19:15 +01:00
try {
2020-08-27 14:04:09 +01:00
const config = await config _utils _1 . getConfig ( getTempDir ( cmd . tempDir ) , logger ) ;
2020-08-28 09:43:25 +01:00
if ( config === undefined ) {
throw new Error ( "Config file could not be found at expected location. " +
"Was the 'init' command run with the same '--temp-dir' argument as this command." ) ;
}
2020-08-28 17:22:26 +01:00
importTracerEnvironment ( config ) ;
2020-08-27 14:04:09 +01:00
let language = undefined ;
if ( cmd . language !== undefined ) {
language = languages _1 . parseLanguage ( cmd . language ) ;
if ( language === undefined || ! config . languages . includes ( language ) ) {
throw new Error ( ` " ${ cmd . language } " is not a recognised language. ` +
` Known languages in this project are ${ config . languages . join ( ', ' ) } . ` ) ;
}
}
else {
language = autobuild _1 . determineAutobuildLanguage ( config , logger ) ;
}
if ( language !== undefined ) {
await autobuild _1 . runAutobuild ( language , config , logger ) ;
2020-08-25 16:19:15 +01:00
}
}
catch ( e ) {
logger . error ( 'Autobuild failed' ) ;
logger . error ( e ) ;
process . exitCode = 1 ;
}
} ) ;
program
. command ( 'analyze' )
. description ( 'Finishes extracting code and runs CodeQL queries' )
2020-08-28 09:35:16 +01:00
. requiredOption ( '--repository <repository>' , 'Repository name. (Required)' )
. requiredOption ( '--commit <commit>' , 'SHA of commit that was analyzed. (Required)' )
. requiredOption ( '--ref <ref>' , 'Name of ref that was analyzed. (Required)' )
. requiredOption ( '--github-url <url>' , 'URL of GitHub instance. (Required)' )
. requiredOption ( '--github-auth <auth>' , 'GitHub Apps token or personal access token. (Required)' )
. option ( '--checkout-path <path>' , 'Checkout path. Default is the current working directory.' )
. option ( '--no-upload' , 'Do not upload results after analysis.' , false )
. option ( '--output-dir <dir>' , 'Directory to output SARIF files to. Default is in the temp directory.' )
2020-09-01 14:13:10 +01:00
. option ( '--ram <ram>' , 'Amount of memory to use when running queries. Default is to use all available memory.' )
. option ( '--threads <threads>' , 'Number of threads to use when running queries. ' +
'Default is to use all available cores.' )
2020-08-28 09:35:16 +01:00
. option ( '--temp-dir <dir>' , 'Directory to use for temporary files. Default is "./codeql-runner".' )
2020-08-27 14:26:44 +01:00
. option ( '--debug' , 'Print more verbose output' , false )
2020-08-25 16:19:15 +01:00
. action ( async ( cmd ) => {
2020-08-27 14:26:44 +01:00
const logger = logging _1 . getRunnerLogger ( cmd . debug ) ;
2020-08-25 16:19:15 +01:00
try {
const tempDir = getTempDir ( cmd . tempDir ) ;
const outputDir = cmd . outputDir || path . join ( tempDir , 'codeql-sarif' ) ;
2020-08-27 14:04:09 +01:00
const config = await config _utils _1 . getConfig ( getTempDir ( cmd . tempDir ) , logger ) ;
2020-08-28 09:43:25 +01:00
if ( config === undefined ) {
throw new Error ( "Config file could not be found at expected location. " +
"Was the 'init' command run with the same '--temp-dir' argument as this command." ) ;
}
2020-09-02 18:00:46 +01:00
await analyze _1 . runAnalyze ( repository _1 . parseRepositoryNwo ( cmd . repository ) , cmd . commit , parseRef ( cmd . ref ) , undefined , undefined , undefined , cmd . checkoutPath || process . cwd ( ) , undefined , cmd . githubAuth , parseGithubUrl ( cmd . githubUrl ) , cmd . upload , 'runner' , outputDir , util _1 . getMemoryFlag ( cmd . ram ) , util _1 . getThreadsFlag ( cmd . threads , logger ) , config , logger ) ;
2020-08-25 16:19:15 +01:00
}
catch ( e ) {
2020-08-27 16:34:09 +01:00
logger . error ( 'Analyze failed' ) ;
2020-08-25 16:19:15 +01:00
logger . error ( e ) ;
process . exitCode = 1 ;
}
} ) ;
2020-08-11 12:43:27 +01:00
program
. command ( 'upload' )
. description ( 'Uploads a SARIF file, or all SARIF files from a directory, to code scanning' )
2020-08-28 09:35:16 +01:00
. requiredOption ( '--sarif-file <file>' , 'SARIF file to upload, or a directory containing multiple SARIF files. (Required)' )
. requiredOption ( '--repository <repository>' , 'Repository name. (Required)' )
. requiredOption ( '--commit <commit>' , 'SHA of commit that was analyzed. (Required)' )
. requiredOption ( '--ref <ref>' , 'Name of ref that was analyzed. (Required)' )
. requiredOption ( '--github-url <url>' , 'URL of GitHub instance. (Required)' )
. requiredOption ( '--github-auth <auth>' , 'GitHub Apps token or personal access token. (Required)' )
. option ( '--checkout-path <path>' , 'Checkout path. Default is the current working directory.' )
2020-08-27 14:26:44 +01:00
. option ( '--debug' , 'Print more verbose output' , false )
2020-08-11 12:43:27 +01:00
. action ( async ( cmd ) => {
2020-08-27 14:26:44 +01:00
const logger = logging _1 . getRunnerLogger ( cmd . debug ) ;
2020-08-11 12:43:27 +01:00
try {
2020-09-02 18:00:46 +01:00
await upload _lib . upload ( cmd . sarifFile , repository _1 . parseRepositoryNwo ( cmd . repository ) , cmd . commit , parseRef ( cmd . ref ) , undefined , undefined , undefined , cmd . checkoutPath || process . cwd ( ) , undefined , cmd . githubAuth , parseGithubUrl ( cmd . githubUrl ) , 'runner' , logger ) ;
2020-08-11 12:43:27 +01:00
}
catch ( e ) {
2020-08-12 18:00:01 +01:00
logger . error ( 'Upload failed' ) ;
2020-08-11 12:43:27 +01:00
logger . error ( e ) ;
2020-08-12 18:00:01 +01:00
process . exitCode = 1 ;
2020-08-11 12:43:27 +01:00
}
} ) ;
program . parse ( process . argv ) ;
2020-08-24 14:21:03 +01:00
//# sourceMappingURL=runner.js.map