Skip to content

Commit

Permalink
Feat/add iac support (#44)
Browse files Browse the repository at this point in the history
* feat: add support for IaC

* feat: add function to validate inputs with new modes, checking inputs for standalone execution

* feat: change parameters format, push dist

* feat: removing hard-coded image-tag requirement from index.js

* feat: add spaces for cmd build

* feat: add spaces for cmd build

* feat: change execution order for scan vm vs iac

* feat: push npm ci results

* feat: refactor unit tests to handle mode, configure json to only show up for vm mode

* fix: flag handling for non vm scenario

* feat: make output analysis conditional based on mode

* chore: set default mode to vm

* chore: add new fields for IaC scanning in README.md

* chore: remove dist from .gitignore

* chore: change step name and put disclaimer for VM
  • Loading branch information
IgorEulalio authored Apr 9, 2024
1 parent 8ee2f00 commit ed29e02
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 20 deletions.
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@ URL to `sysdig-cli-scanner` binary download. The action will detect the runner O

For more info about the Sysdig CLI Scanner download visit [the official documentation](https://docs.sysdig.com/en/docs/installation/sysdig-secure/install-vulnerability-cli-scanner/).

### `mode`

Mode of operation. Can be "vm" or "iac". Default is **vm**.

### `cli-scanner-version`

Custom sysdig-cli-scanner version to download. It is set to `1.8.1` by default.

> Please note that the Action has only been tested with `1.8.x` versions and it is not guaranteed that it will work as expected with other versions.
> If using iac mode, minimum required version is 1.9.0.
> Please note that for VM mode the Action has only been tested with `1.8.x` versions and it is not guaranteed that it will work as expected with other versions.
### `registry-user`

Expand Down Expand Up @@ -101,6 +106,18 @@ Skip TLS verification when calling Sysdig Secure endpoints.

Additional parameters to be added to the CLI Scanner. Note that these may not be supported with the current Action.

### `recursive`

Recursively scan all folders within the folder specified in the iacScanPath

### `minimum-severity`

Minimum severity to fail when scanning in IaC mode

### `iac-scan-path`

Path to the IaC files to scan

## SARIF Report

The action generates a SARIF report that can be uploaded using the `codeql-action/upload-sarif` action.
Expand Down Expand Up @@ -168,6 +185,20 @@ The `if: success() || failure()` option makes sure the SARIF report is uploaded
sysdig-secure-token: ${{ secrets.SYSDIG_SECURE_TOKEN }}
```

### Scan infrastructure using IaC scan

```yaml
...
- name: Scan infrastructure
uses: sysdiglabs/scan-action@v4
with:
sysdig-secure-token: ${{ secrets.SYSDIG_SECURE_TOKEN }}
cli-scanner-version: 1.9.0
mode: iac
iac-scan-path: ./terraform
```

### Fail pipeline when Policy Evaluation is failed or scanner fails to run


Expand Down
20 changes: 18 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ inputs:
default: "false"
required: false
image-tag:
description: Tag of the image to analyse.
required: true
description: Tag of the image to analyse. (Required if not in IaC mode.)
required: false
sysdig-secure-token:
description: API token for Sysdig Scanning auth. (Required if not in Standalone mode.)
required: false
Expand All @@ -68,6 +68,22 @@ inputs:
extra-parameters:
description: Additional parameters added to the secure-inline-scan container execution.
required: false
mode:
description: 'Mode of operation. Can be "vm" or "iac".'
required: false
default: vm
recursive:
description: 'Recursively scan all folders within the folder specified in the iacScanPath.'
required: false
default: "false"
minimum-severity:
description: 'Minimum severity to fail when scanning in IaC mode'
required: false
default: "high"
iac-scan-path:
description: 'Path to the IaC files to scan.'
required: false
default: "./"
outputs:
scanReport:
description: Path to a JSON file containing the report results, failed evaluation gates, and found vulnerabilities.
Expand Down
56 changes: 51 additions & 5 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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

Large diffs are not rendered by default.

56 changes: 51 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const os = require('os');

const toolVersion = `${version}`;
const dottedQuadToolVersion = `${version}.0`;
const vmMode = "vm"
const iacMode = "iac"

function getRunArch() {
let arch = "unknown";
Expand Down Expand Up @@ -82,13 +84,17 @@ function parseActionInputs() {
skipSummary: core.getInput('skip-summary') == 'true',
usePolicies: core.getInput('use-policies'),
overridePullString: core.getInput('override-pullstring'),
imageTag: core.getInput('image-tag', { required: true }),
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') || 'any',
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') || './'
}
}

Expand Down Expand Up @@ -139,7 +145,7 @@ function composeFlags(opts) {
let envvars = {}
envvars['SECURE_API_TOKEN'] = opts.sysdigSecureToken || "";

let flags = ` --json-scan-result=${cliScannerResult}`;
let flags = ""

if (opts.registryUser) {
envvars['REGISTRY_USER'] = opts.registryUser;
Expand Down Expand Up @@ -181,7 +187,26 @@ function composeFlags(opts) {
flags += ` ${opts.extraParameters}`;
}

flags += ` ${opts.imageTag || ""}`;
if (opts.mode && opts.mode == iacMode) {
flags += ` --iac`;
}

if (opts.recursive) {
flags += ` -r`;
}

if (opts.minimumSeverity) {
flags += ` -f=${opts.minimumSeverity}`;
}

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

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

return {
envvars: envvars,
Expand All @@ -194,10 +219,28 @@ function writeReport(reportData) {
core.setOutput("scanReport", "./report.json");
}

function validateInput(opts) {
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.");
}

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.");
}

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.");
}
}

async function run() {

try {
let opts = parseActionInputs();
validateInput(opts)
printOptions(opts);
let scanFlags = composeFlags(opts);

Expand All @@ -216,7 +259,9 @@ async function run() {
retCode = scanResult.ReturnCode;
if (retCode == 0 || retCode == 1) {
// Transform Scan Results to other formats such as SARIF
await processScanResult(scanResult, opts);
if (opts.mode && opts.mode == vmMode) {
await processScanResult(scanResult, opts);
}
} else {
core.error("Terminating scan. Scanner couldn't be executed.")
}
Expand Down Expand Up @@ -332,7 +377,7 @@ async function executeScan(envvars, flags) {

let start = performance.now();
let cmd = `./${cliScannerName} ${flags}`;
core.debug("Executing: " + cmd);
core.info("Executing: " + cmd);
let retCode = await exec.exec(cmd, null, scanOptions);
core.info("Image analysis took " + Math.round(performance.now() - start) + " milliseconds.");

Expand Down Expand Up @@ -816,6 +861,7 @@ module.exports = {
executeScan,
processScanResult,
run,
validateInput,
cliScannerName,
cliScannerResult,
cliScannerVersion,
Expand Down
Loading

0 comments on commit ed29e02

Please sign in to comment.