Skip to content

refactor: move ActionInputs to a class #59

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
326 changes: 194 additions & 132 deletions dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

17 changes: 7 additions & 10 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as core from '@actions/core';
import fs from 'fs';
import { generateSARIFReport } from './src/sarif';
import { cliScannerName, cliScannerResult, cliScannerURL, composeFlags, executeScan, numericPriorityForSeverity, pullScanner, ScanExecutionResult, vmMode } from './src/scanner';
import { ActionInputs, defaultSecureEndpoint, parseActionInputs, printOptions, validateInput } from './src/action';
import { cliScannerName, cliScannerResult, cliScannerURL, executeScan, numericPriorityForSeverity, pullScanner, ScanExecutionResult, vmMode } from './src/scanner';
import { ActionInputs, defaultSecureEndpoint } from './src/action';
import { generateSummary } from './src/summary';
import { Report } from './src/report';

Expand All @@ -20,10 +20,9 @@ function writeReport(reportData: string) {
export async function run() {

try {
let opts = parseActionInputs();
validateInput(opts)
printOptions(opts);
let scanFlags = composeFlags(opts); // FIXME(fede) this also modifies the opts.cliScannerURL, which is something we don't want
let opts = ActionInputs.parseActionInputs();
opts.printOptions();
let scanFlags = opts.composeFlags();

let scanResult: ScanExecutionResult;
// Download CLI Scanner from 'cliScannerURL'
Expand All @@ -35,7 +34,8 @@ export async function run() {
retCode = scanResult.ReturnCode;
if (retCode == 0 || retCode == 1) {
// Transform Scan Results to other formats such as SARIF
if (opts.mode && opts.mode == vmMode) {

if (opts.mode == vmMode) {
await processScanResult(scanResult, opts);
}
} else {
Expand Down Expand Up @@ -103,11 +103,8 @@ export async function processScanResult(result: ScanExecutionResult, opts: Actio
}

export {
parseActionInputs,
validateInput,
cliScannerURL,
defaultSecureEndpoint,
composeFlags,
pullScanner,
cliScannerName,
executeScan,
Expand Down
271 changes: 211 additions & 60 deletions src/action.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as core from '@actions/core';
import { cliScannerURL, iacMode, vmMode } from './scanner';
import { cliScannerResult, cliScannerURL, ComposeFlags, iacMode, scannerURLForVersion, vmMode } from './scanner';

export const defaultSecureEndpoint = "https://secure.sysdig.com/"

export interface ActionInputs {
interface ActionInputParameters {
cliScannerURL: string;
cliScannerVersion: string;
registryUser: string;
Expand All @@ -29,89 +29,240 @@ export interface ActionInputs {
iacScanPath: string;
}

export function parseActionInputs() : ActionInputs {
return {
cliScannerURL: core.getInput('cli-scanner-url') || cliScannerURL,
cliScannerVersion: core.getInput('cli-scanner-version'),
registryUser: core.getInput('registry-user'),
registryPassword: core.getInput('registry-password'),
stopOnFailedPolicyEval: core.getInput('stop-on-failed-policy-eval') == 'true',
stopOnProcessingError: core.getInput('stop-on-processing-error') == 'true',
standalone: core.getInput('standalone') == 'true',
dbPath: core.getInput('db-path'),
skipUpload: core.getInput('skip-upload') == 'true',
skipSummary: core.getInput('skip-summary') == 'true',
usePolicies: core.getInput('use-policies'),
overridePullString: core.getInput('override-pullstring'),
imageTag: core.getInput('image-tag'),
sysdigSecureToken: core.getInput('sysdig-secure-token'),
sysdigSecureURL: core.getInput('sysdig-secure-url') || defaultSecureEndpoint,
sysdigSkipTLS: core.getInput('sysdig-skip-tls') == 'true',
severityAtLeast: core.getInput('severity-at-least') || undefined,
groupByPackage: core.getInput('group-by-package') == 'true',
extraParameters: core.getInput('extra-parameters'),
mode: core.getInput('mode') || vmMode,
recursive: core.getInput('recursive') == 'true',
minimumSeverity: core.getInput('minimum-severity'),
iacScanPath: core.getInput('iac-scan-path') || './'
export class ActionInputs {
private readonly _params: ActionInputParameters;
public get params(): ActionInputParameters {
return this._params;
}
private constructor(params: ActionInputParameters) {
ActionInputs.validateInputs(params);
this._params = params;
}
}

export function validateInput(opts: ActionInputs) {
if (!opts.standalone && !opts.sysdigSecureToken) {
core.setFailed("Sysdig Secure Token is required for standard execution, please set your token or remove the standalone input.");
throw new Error("Sysdig Secure Token is required for standard execution, please set your token or remove the standalone input.");
static from(any: any): ActionInputs {
return new ActionInputs(any as ActionInputParameters);
}

if (opts.mode && opts.mode == vmMode && !opts.imageTag) {
core.setFailed("image-tag is required for VM mode.");
throw new Error("image-tag is required for VM mode.");
static fromJSON(jsonContents: string): ActionInputs {
return ActionInputs.from(JSON.parse(jsonContents))
}

if (opts.mode && opts.mode == iacMode && opts.iacScanPath == "") {
core.setFailed("iac-scan-path can't be empty, please specify the path you want to scan your manifest resources.");
throw new Error("iac-scan-path can't be empty, please specify the path you want to scan your manifest resources.");
static parseActionInputs(): ActionInputs {
return ActionInputs.overridingParsedActionInputs({});
}
}

export function printOptions(opts: ActionInputs) {
if (opts.standalone) {
core.info(`[!] Running in Standalone Mode.`);
static overridingParsedActionInputs(overrides: { [key: string]: any }) {

const params: ActionInputParameters = {
cliScannerURL: core.getInput('cli-scanner-url') || cliScannerURL,
cliScannerVersion: core.getInput('cli-scanner-version'),
registryUser: core.getInput('registry-user'),
registryPassword: core.getInput('registry-password'),
stopOnFailedPolicyEval: core.getInput('stop-on-failed-policy-eval') == 'true',
stopOnProcessingError: core.getInput('stop-on-processing-error') == 'true',
standalone: core.getInput('standalone') == 'true',
dbPath: core.getInput('db-path'),
skipUpload: core.getInput('skip-upload') == 'true',
skipSummary: core.getInput('skip-summary') == 'true',
usePolicies: core.getInput('use-policies'),
overridePullString: core.getInput('override-pullstring'),
imageTag: core.getInput('image-tag'),
sysdigSecureToken: core.getInput('sysdig-secure-token'),
sysdigSecureURL: core.getInput('sysdig-secure-url') || defaultSecureEndpoint,
sysdigSkipTLS: core.getInput('sysdig-skip-tls') == 'true',
severityAtLeast: core.getInput('severity-at-least') || undefined,
groupByPackage: core.getInput('group-by-package') == 'true',
extraParameters: core.getInput('extra-parameters'),
mode: core.getInput('mode') || vmMode,
recursive: core.getInput('recursive') == 'true',
minimumSeverity: core.getInput('minimum-severity'),
iacScanPath: core.getInput('iac-scan-path') || './',
};

const overridenParams = {
...params,
...overrides,
};


return ActionInputs.from(overridenParams);
}

if (opts.sysdigSecureURL) {
core.info('Sysdig Secure URL: ' + opts.sysdigSecureURL);
get cliScannerURL(): string {
return this.params.cliScannerURL
}

if (opts.registryUser && opts.registryPassword) {
core.info(`Using specified Registry credentials.`);
get mode() {
return this.params.mode || vmMode;
}

core.info(`Stop on Failed Policy Evaluation: ${opts.stopOnFailedPolicyEval}`);
get stopOnProcessingError() {
return this.params.stopOnProcessingError
}

core.info(`Stop on Processing Error: ${opts.stopOnProcessingError}`);
get standalone() {
return this.params.standalone
}

if (opts.skipUpload) {
core.info(`Skipping scan results upload to Sysdig Secure...`);
get stopOnFailedPolicyEval() {
return this.params.stopOnFailedPolicyEval
}

if (opts.dbPath) {
core.info(`DB Path: ${opts.dbPath}`);
get skipSummary() {
return this.params.skipSummary
}

core.info(`Sysdig skip TLS: ${opts.sysdigSkipTLS}`);
get groupByPackage(): boolean {
return this.params.groupByPackage
}

if (opts.severityAtLeast) {
core.info(`Severity level: ${opts.severityAtLeast}`);
get severityAtLeast() {
return this.params.severityAtLeast
}

core.info('Analyzing image: ' + opts.imageTag);
get imageTag() {
return this.params.imageTag
}

if (opts.overridePullString) {
core.info(` * Image PullString will be overwritten as ${opts.overridePullString}`);
get overridePullString() {
return this.params.overridePullString
}

if (opts.skipSummary) {
core.info("This run will NOT generate a SUMMARY.");
private static validateInputs(params: ActionInputParameters) {
if (!params.standalone && !params.sysdigSecureToken) {
core.setFailed("Sysdig Secure Token is required for standard execution, please set your token or remove the standalone input.");
throw new Error("Sysdig Secure Token is required for standard execution, please set your token or remove the standalone input.");
}

if (params.mode && params.mode == vmMode && !params.imageTag) {
core.setFailed("image-tag is required for VM mode.");
throw new Error("image-tag is required for VM mode.");
}

if (params.mode && params.mode == iacMode && params.iacScanPath == "") {
core.setFailed("iac-scan-path can't be empty, please specify the path you want to scan your manifest resources.");
throw new Error("iac-scan-path can't be empty, please specify the path you want to scan your manifest resources.");
}
}

// FIXME(fede) this also modifies the opts.cliScannerURL, which is something we don't want
public composeFlags(): ComposeFlags {
if (this.params.cliScannerVersion && this.params.cliScannerURL == cliScannerURL) {
this.params.cliScannerURL = scannerURLForVersion(this.params.cliScannerVersion)
}

let envvars: { [key: string]: string } = {}
envvars['SECURE_API_TOKEN'] = this.params.sysdigSecureToken || "";

let flags = ""

if (this.params.registryUser) {
envvars['REGISTRY_USER'] = this.params.registryUser;
}

if (this.params.registryPassword) {
envvars['REGISTRY_PASSWORD'] = this.params.registryPassword;
}

if (this.params.standalone) {
flags += " --standalone";
}

if (this.params.sysdigSecureURL) {
flags += ` --apiurl ${this.params.sysdigSecureURL}`;
}

if (this.params.dbPath) {
flags += ` --dbpath=${this.params.dbPath}`;
}

if (this.params.skipUpload) {
flags += ' --skipupload';
}

if (this.params.usePolicies) {
flags += ` --policy=${this.params.usePolicies}`;
}

if (this.params.sysdigSkipTLS) {
flags += ` --skiptlsverify`;
}

if (this.params.overridePullString) {
flags += ` --override-pullstring=${this.params.overridePullString}`;
}

if (this.params.extraParameters) {
flags += ` ${this.params.extraParameters}`;
}

if (this.params.mode && this.params.mode == iacMode) {
flags += ` --iac`;
}

if (this.params.recursive && this.params.mode == iacMode) {
flags += ` -r`;
}

if (this.params.minimumSeverity && this.params.mode == iacMode) {
flags += ` -f=${this.params.minimumSeverity}`;
}

if (this.params.mode && this.params.mode == vmMode) {
flags += ` --json-scan-result=${cliScannerResult}`
flags += ` ${this.params.imageTag}`;
}

if (this.params.mode && this.params.mode == iacMode) {
flags += ` ${this.params.iacScanPath}`;
}

return {
envvars: envvars,
flags: flags
}
}

public printOptions() {
if (this.params.standalone) {
core.info(`[!] Running in Standalone Mode.`);
}

if (this.params.sysdigSecureURL) {
core.info('Sysdig Secure URL: ' + this.params.sysdigSecureURL);
}

if (this.params.registryUser && this.params.registryPassword) {
core.info(`Using specified Registry credentials.`);
}

core.info(`Stop on Failed Policy Evaluation: ${this.params.stopOnFailedPolicyEval}`);

core.info(`Stop on Processing Error: ${this.params.stopOnProcessingError}`);

if (this.params.skipUpload) {
core.info(`Skipping scan results upload to Sysdig Secure...`);
}

if (this.params.dbPath) {
core.info(`DB Path: ${this.params.dbPath}`);
}

core.info(`Sysdig skip TLS: ${this.params.sysdigSkipTLS}`);

if (this.params.severityAtLeast) {
core.info(`Severity level: ${this.params.severityAtLeast}`);
}

core.info('Analyzing image: ' + this.params.imageTag);

if (this.params.overridePullString) {
core.info(` * Image PullString will be overwritten as ${this.params.overridePullString}`);
}

if (this.params.skipSummary) {
core.info("This run will NOT generate a SUMMARY.");
}
}
}

6 changes: 3 additions & 3 deletions src/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export interface Metadata {
size: number
os: string
architecture: string
labels?: {[key: string]: string}
labels?: { [key: string]: string }
layersCount: number
createdAt: string
}
Expand Down Expand Up @@ -77,7 +77,7 @@ export interface Vuln {
exploitable: boolean
fixedInVersion?: string
publishDateByVendor: PublishDateByVendor
annotations?: {[key: string]: string}
annotations?: { [key: string]: string }
acceptedRisks?: AcceptedRisk[]
}

Expand Down Expand Up @@ -126,7 +126,7 @@ export interface Vulns {
negligible?: number
}

export interface RunningVulns {}
export interface RunningVulns { }

export interface BaseImage {
pullstrings: string[]
Expand Down
Loading
Loading