Skip to content
Permalink
1220ae5bfd
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
Latest commit b185050 Oct 5, 2020 History
0 contributors

Users who have contributed to this file

210 lines (190 sloc) 6.02 KB
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import { Language } from "./languages";
import { Logger } from "./logging";
/**
* Are we running on actions, or not.
*/
export type Mode = "actions" | "runner";
/**
* The URL for github.com.
*/
export const GITHUB_DOTCOM_URL = "https://github.com";
/**
* Get the extra options for the codeql commands.
*/
export function getExtraOptionsEnvParam(): object {
const varName = "CODEQL_ACTION_EXTRA_OPTIONS";
const raw = process.env[varName];
if (raw === undefined || raw.length === 0) {
return {};
}
try {
return JSON.parse(raw);
} catch (e) {
throw new Error(
`${varName} environment variable is set, but does not contain valid JSON: ${e.message}`
);
}
}
export function isLocalRun(): boolean {
return (
!!process.env.CODEQL_LOCAL_RUN &&
process.env.CODEQL_LOCAL_RUN !== "false" &&
process.env.CODEQL_LOCAL_RUN !== "0"
);
}
/**
* Get the array of all the tool names contained in the given sarif contents.
*
* Returns an array of unique string tool names.
*/
export function getToolNames(sarifContents: string): string[] {
const sarif = JSON.parse(sarifContents);
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);
}
// Creates a random temporary directory, runs the given body, and then deletes the directory.
// Mostly intended for use within tests.
export async function withTmpDir<T>(
body: (tmpDir: string) => Promise<T>
): Promise<T> {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "codeql-action-"));
const realSubdir = path.join(tmpDir, "real");
fs.mkdirSync(realSubdir);
const symlinkSubdir = path.join(tmpDir, "symlink");
fs.symlinkSync(realSubdir, symlinkSubdir, "dir");
const result = await body(symlinkSubdir);
fs.rmdirSync(tmpDir, { recursive: true });
return result;
}
/**
* Get the codeql `--ram` flag as configured by the `ram` input. If no value was
* specified, the total available memory will be used minus 256 MB.
*
* @returns string
*/
export function getMemoryFlag(userInput: string | undefined): string {
let memoryToUseMegaBytes: number;
if (userInput) {
memoryToUseMegaBytes = Number(userInput);
if (Number.isNaN(memoryToUseMegaBytes) || memoryToUseMegaBytes <= 0) {
throw new Error(`Invalid RAM setting "${userInput}", specified.`);
}
} else {
const totalMemoryBytes = os.totalmem();
const totalMemoryMegaBytes = totalMemoryBytes / (1024 * 1024);
const systemReservedMemoryMegaBytes = 256;
memoryToUseMegaBytes = totalMemoryMegaBytes - systemReservedMemoryMegaBytes;
}
return `--ram=${Math.floor(memoryToUseMegaBytes)}`;
}
/**
* Get the codeql flag to specify whether to add code snippets to the sarif file.
*
* @returns string
*/
export function getAddSnippetsFlag(
userInput: string | boolean | undefined
): string {
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";
}
/**
* Get the codeql `--threads` value specified for the `threads` input.
* If not value was specified, all available threads will be used.
*
* The value will be capped to the number of available CPUs.
*
* @returns string
*/
export function getThreadsFlag(
userInput: string | undefined,
logger: Logger
): string {
let numThreads: number;
const maxThreads = os.cpus().length;
if (userInput) {
numThreads = Number(userInput);
if (Number.isNaN(numThreads)) {
throw new Error(`Invalid threads setting "${userInput}", specified.`);
}
if (numThreads > maxThreads) {
logger.info(
`Clamping desired number of threads (${numThreads}) to max available (${maxThreads}).`
);
numThreads = maxThreads;
}
const minThreads = -maxThreads;
if (numThreads < minThreads) {
logger.info(
`Clamping desired number of free threads (${numThreads}) to max available (${minThreads}).`
);
numThreads = minThreads;
}
} else {
// Default to using all threads
numThreads = maxThreads;
}
return `--threads=${numThreads}`;
}
/**
* Get the directory where CodeQL databases should be placed.
*/
export function getCodeQLDatabasesDir(tempDir: string) {
return path.resolve(tempDir, "codeql_databases");
}
/**
* Get the path where the CodeQL database for the given language lives.
*/
export function getCodeQLDatabasePath(tempDir: string, language: Language) {
return path.resolve(getCodeQLDatabasesDir(tempDir), language);
}
/**
* Parses user input of a github.com or GHES URL to a canonical form.
* Removes any API prefix or suffix if one is present.
*/
export function parseGithubUrl(inputUrl: string): string {
const originalUrl = inputUrl;
if (inputUrl.indexOf("://") === -1) {
inputUrl = `https://${inputUrl}`;
}
if (!inputUrl.startsWith("http://") && !inputUrl.startsWith("https://")) {
throw new Error(`"${originalUrl}" is not a http or https URL`);
}
let url: URL;
try {
url = new URL(inputUrl);
} catch (e) {
throw new Error(`"${originalUrl}" is not a valid URL`);
}
// 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") {
return GITHUB_DOTCOM_URL;
}
// 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();
}