@eurekadevsecops/radar 1.10.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "1.10.0"
2
+ ".": "2.0.0"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.0](https://github.com/EurekaDevSecOps/radarctl/compare/v1.11.0...v2.0.0) (2026-03-04)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * **scan:** Exit codes have changed. When vulnerabilities are found, instead of returning exit codes in the range 8-15, Radar CLI now only returns 8.
9
+
10
+ ### Improvements
11
+
12
+ * **scan:** Add THRESHOLD option ([#67](https://github.com/EurekaDevSecOps/radarctl/issues/67)) ([47a0b7b](https://github.com/EurekaDevSecOps/radarctl/commit/47a0b7bdc2b9f59d13cc6d35d6b1367b00b4ebc3))
13
+ * **scans:** Display link to scan in Eureka dashboard ([#68](https://github.com/EurekaDevSecOps/radarctl/issues/68)) ([0b33b79](https://github.com/EurekaDevSecOps/radarctl/commit/0b33b79420a6589b33b1dc4370e4733bf872eaae))
14
+
15
+ ## [1.11.0](https://github.com/EurekaDevSecOps/radarctl/compare/v1.10.0...v1.11.0) (2026-02-27)
16
+
17
+
18
+ ### Improvements
19
+
20
+ * Add support for Veracode Pipeline (SAST) scanner ([#2](https://github.com/EurekaDevSecOps/radarctl/issues/2)) ([bf7f04b](https://github.com/EurekaDevSecOps/radarctl/commit/bf7f04b4fd8bfc5fd3e13b25365809209db80cec))
21
+
3
22
  ## [1.10.0](https://github.com/EurekaDevSecOps/radarctl/compare/v1.9.8...v1.10.0) (2026-02-25)
4
23
 
5
24
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eurekadevsecops/radar",
3
- "version": "1.10.0",
3
+ "version": "2.0.0",
4
4
  "description": "Radar is an open-source orchestrator of security scanners.",
5
5
  "homepage": "https://www.eurekadevsecops.com/radar",
6
6
  "keywords": [
@@ -0,0 +1,5 @@
1
+ name = "veracode-sast"
2
+ title = "Veracode SAST"
3
+ description = "Identify application security findings in source code. Requires Veracode API key."
4
+ categories = [ "SAST" ]
5
+ cmd = "${assets}/run.sh ${target} ${assets} ${output}"
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+
3
+ # Parameters:
4
+ # $1 - Path to the source code folder that should be scanned
5
+ # $2 - Path to the assets folder
6
+ # $3 - Path to the output folder where scan results should be stored
7
+
8
+ # Requirements:
9
+ #
10
+ # Environment variables VERACODE_API_KEY_ID and VERACODE_API_KEY_SECRET must be set:
11
+ # [Veracode Platform](https://docs.veracode.com/r/c_api_credentials3#generate-api-credentials).
12
+ #
13
+ # EXAMPLE:
14
+ # export VERACODE_API_KEY_ID=123456789
15
+ # export VERACODE_API_KEY_SECRET=REDACTED
16
+ # radar scan /path/to/repo
17
+ # (Prefer setting these via your CI/secret manager; avoid typing real secrets into shell history.)
18
+ #
19
+ # Optional:
20
+ #
21
+ # (A) The repo has already been packaged for Veracode as per https://docs.veracode.com/r/compilation_packaging
22
+ # and stored into a ZIP file somewhere within the repo. Set the environment variable VERACODE_ZIPFILE to the
23
+ # path/to/repo/veracode-package.zip file, relative to the root folder of the repo.
24
+ #
25
+ # -or-
26
+ #
27
+ # (B) Set the environment variable VERACODE_PACKAGE_CMD to the command that can create the Veracode package ZIP.
28
+ # We will run the command from the root of the repo. It should create veracode-package.zip and save it into
29
+ # the root folder of the repo. We will submit this ZIP to Veracode Pipeline SAST scanner for a scan.
30
+ #
31
+ # Examples:
32
+ # export VERACODE_PACKAGE_CMD="zip -qr veracode-package.zip lib"
33
+ # export VERACODE_PACKAGE_CMD="npm run build && zip -qr veracode-package.zip dist"
34
+ # export VERACODE_PACKAGE_CMD="make && zip -qr veracode-package.zip out"
35
+ #
36
+ # -or-
37
+ #
38
+ # (C) Your project does not need a build step. Omit both VERACODE_ZIPFILE and VERACODE_PACKAGE_CMD. We will
39
+ # automatically ZIP up the repo, excluding any files referenced in .gitignore, and submit to Veracode Pipeline
40
+ # SAST scanner for a scan. This is the default action if you don't set VERACODE_ZIPFILE and VERACODE_PACKAGE_CMD.
41
+ # This is appropriate for interpreted languages (Javascript, Python, etc) that don't need to be compiled.
42
+
43
+ set -e
44
+
45
+ if [ "$#" -ne 3 ]; then
46
+ echo "Usage: $0 <source_dir> <assets_dir> <output_dir>" >&2
47
+ exit 1
48
+ fi
49
+
50
+ # Expand relative paths
51
+ if ! APP_DIR="$(cd -- "$1" && pwd)"; then
52
+ echo "Error: source directory not found: $1" >&2
53
+ exit 1
54
+ fi
55
+
56
+ if ! CFG_DIR="$(cd -- "$2" && pwd)"; then
57
+ echo "Error: assets directory not found: $2" >&2
58
+ exit 1
59
+ fi
60
+
61
+ if ! OUT_DIR="$(cd -- "$3" && pwd)"; then
62
+ echo "Error: output directory not found: $3" >&2
63
+ exit 1
64
+ fi
65
+
66
+ # The ghcr.io/eurekadevsecops/radar-veracode-sast image is currently published for linux/amd64 only.
67
+ # On non-amd64 hosts (e.g., Apple Silicon), Docker will use emulation which may be slower.
68
+ docker run --platform linux/amd64 --rm \
69
+ -v "${APP_DIR}":/opt/eureka/radar/temp/repo \
70
+ -v "${CFG_DIR}":/opt/eureka/radar/temp/input \
71
+ -v "${OUT_DIR}":/opt/eureka/radar/temp/output \
72
+ -e VERACODE_API_KEY_ID="${VERACODE_API_KEY_ID}" \
73
+ -e VERACODE_API_KEY_SECRET="${VERACODE_API_KEY_SECRET}" \
74
+ -e VERACODE_ZIPFILE="${VERACODE_ZIPFILE}" \
75
+ -e VERACODE_PACKAGE_CMD="${VERACODE_PACKAGE_CMD}" \
76
+ ghcr.io/eurekadevsecops/radar-veracode-sast 2>&1
@@ -6,6 +6,18 @@ const SARIF = require('../util/sarif')
6
6
  const runner = require('../util/runner')
7
7
  const { DateTime } = require('luxon')
8
8
 
9
+ function is_error(threshold) {
10
+ return is_warning(threshold) || threshold === 'high' || threshold === 'error'
11
+ }
12
+
13
+ function is_warning(threshold) {
14
+ return is_note(threshold) || threshold === 'moderate' || threshold === 'warning'
15
+ }
16
+
17
+ function is_note(threshold) {
18
+ return threshold === 'low' || threshold === 'note'
19
+ }
20
+
9
21
  module.exports = {
10
22
  summary: 'scan for vulnerabilities',
11
23
  args: {
@@ -22,11 +34,12 @@ module.exports = {
22
34
  { name: 'DEBUG', short: 'd', long: 'debug', type: 'boolean', description: 'log detailed debug info to stdout' },
23
35
  { name: 'ESCALATE', short: 'e', long: 'escalate', type: 'string', description: 'severities to treat as high/error' },
24
36
  { name: 'FORMAT', short: 'f', long: 'format', type: 'string', description: 'severity format' },
37
+ { name: 'ID', short: 'i', long: 'id', type: 'string', description: 'scan ID to associate results with' },
25
38
  { name: 'LOCAL', short: 'l', long: 'local', type: 'boolean', description: 'local scan (no upload of findings to Eureka)' },
26
39
  { name: 'OUTPUT', short: 'o', long: 'output', type: 'string', description: 'output SARIF file' },
27
40
  { name: 'QUIET', short: 'q', long: 'quiet', type: 'boolean', description: 'suppress stdout logging' },
28
41
  { name: 'SCANNERS', short: 's', long: 'scanners', type: 'string', description: 'list of scanners to use' },
29
- { name: 'SCAN_ID', short: 'sid', long: 'scan-id', type: 'string', description: 'existing scan ID to associate results with' }
42
+ { name: 'THRESHOLD', short: 't', long: 'threshold', type: 'string', description: 'severity threshold for non-zero exit code' }
30
43
  ],
31
44
  description: `
32
45
  Scans a target for vulnerabilities. Defaults to displaying findings on stdout.
@@ -72,36 +85,33 @@ module.exports = {
72
85
  Radar CLI from uploading scan findings even when you have 'EUREKA_AGENT_TOKEN' set,
73
86
  you can pass the LOCAL option on the command line.
74
87
 
88
+ Use the THRESHOLD option to return a non-zero exit code for severities at or
89
+ above the threshold. For example, setting THRESHOLD to "high" would result in
90
+ a non-zero exit code only if high or critical vulnerabilities were found by the
91
+ scan. Available values are low, moderate, high, and critical - or note, warning,
92
+ and error if using the SARIF native severity levels.
93
+
75
94
  Exit codes:
76
- 0 - Clean and successful scan. No errors, warnings, or notes.
95
+ 0 - Clean and successful scan. No vulnerabilities.
77
96
  1 - Bad command, arguments, or options. Scan not completed.
78
- 8-15 - Scan completed with errors, warnings, or notes.
79
- 9 - Scan completed with errors (no warnings or notes).
80
- 10 - Scan completed with warnings (no errors or notes).
81
- 11 - Scan completed with errors and warnings (no notes).
82
- 12 - Scan completed with notes (no errors or warnings).
83
- 13 - Scan completed with errors and notes (no warnings).
84
- 14 - Scan completed with warnings and notes (no errors).
85
- 15 - Scan completed with errors, warnings, and notes.
97
+ 8 - Scan completed with vulnerabilities (>= THRESHOLD severity, if set).
86
98
  >= 16 - Scan aborted due to unexpected error.
87
99
  `,
88
100
  examples: [
89
101
  '$ radar scan ' + '(scan current working directory)'.grey,
90
102
  '$ radar scan . ' + '(scan current working directory)'.grey,
103
+ '$ radar scan /my/repo/dir ' + '(scan target directory)'.grey,
91
104
  '$ radar scan --local ' + '(run a local scan / no uploads to Eureka)'.grey,
92
105
  '$ radar scan -d' + '(turn debug mode on)'.grey,
93
106
  '$ radar scan --debug' + '(turn debug mode on)'.grey,
94
- '$ radar scan /my/repo/dir ' + '(scan target directory)'.grey,
95
107
  '$ radar scan --output=scan.sarif ' + '(save findings in a file)'.grey,
96
108
  '$ radar scan -o scan.sarif /my/repo/dir ' + '(short versions of options)'.grey,
97
109
  '$ radar scan -s depscan,opengrep ' + '(use only given scanners)'.grey,
98
110
  '$ radar scan -c sca,sast ' + '(use all scanners from given categories)'.grey,
99
111
  '$ radar scan -c sca,sast -s all ' + '(use all scanners from given categories)'.grey,
100
112
  '$ radar scan -c sast -s opengrep ' + '(use only the opengrep scanner)'.grey,
101
- '$ radar scan -f security ' + '(displays findings as high, moderate, and low)'.grey,
102
- '$ radar scan -f sarif ' + '(displays findings as error, warning, and note)'.grey,
103
- '$ radar scan -e moderate,low ' + '(treat lower severities as high)'.grey,
104
- '$ radar scan -f sarif -e warning,note ' + '(treat lower severities as errors)'.grey
113
+ '$ radar scan -e moderate,low ' + '(treat moderate and low severities as high)'.grey,
114
+ '$ radar scan -t moderate ' + '(non-zero exit code for severities moderate and higher)'.grey,
105
115
  ],
106
116
  run: async (toolbox, args, globals) => {
107
117
  const { log, scanners: availableScanners, categories: availableCategories, telemetry, git } = toolbox
@@ -135,6 +145,10 @@ module.exports = {
135
145
  if (args.FORMAT === 'security' && severity !== 'moderate' && severity !== 'low') throw new Error(`Severity to escalate must be 'moderate' or 'low'`)
136
146
  if (args.FORMAT === 'sarif' && severity !== 'warning' && severity !== 'note') throw new Error(`Severity to escalate must be 'warning' or 'note'`)
137
147
  })
148
+ if (args.THRESHOLD) {
149
+ if (args.FORMAT === 'security' && !['critical', 'high', 'moderate', 'low'].includes(args.THRESHOLD)) throw new Error(`THRESHOLD must be one of 'critical', 'high', 'moderate' or 'low'`)
150
+ if (args.FORMAT === 'sarif' && !['error', 'warning', 'note'].includes(args.THRESHOLD)) throw new Error(`THRESHOLD must be one of 'error', 'warning' or 'note'`)
151
+ }
138
152
 
139
153
  // Derive scan parameters.
140
154
  const target = args.TARGET // target to scan
@@ -166,16 +180,17 @@ module.exports = {
166
180
  if (metadata.type === 'error') throw new Error(`${metadata.error.code}: ${metadata.error.details}`)
167
181
 
168
182
  // Send telemetry: scan started.
169
- let scanID = args.SCAN_ID ?? undefined
183
+ let scanID = args.ID ?? undefined
184
+ let scanURL = undefined
170
185
  const timestamp = DateTime.now().toISO()
171
186
 
172
187
  if (telemetry.enabled && !args.LOCAL) {
173
- // TODO: Should pass scanID to the server; not read it from the server.
174
188
  try {
175
189
  const res = await telemetry.send(`scans/started`, {}, { scanners: scanners.map((s) => s.name), scanID, metadata, timestamp })
176
190
  if (!res.ok) throw new Error(`[${res.status}] ${res.statusText}: ${await res.text()}`)
177
191
  const data = await res.json()
178
192
  scanID = data.scan_id
193
+ scanURL = data.scan_url
179
194
  }
180
195
  catch (error) {
181
196
  log(`WARNING: Telemetry will be skipped for this scan run: ${error.message}\n`)
@@ -250,15 +265,24 @@ module.exports = {
250
265
  SARIF.visualizations.display_totals(summary, args.FORMAT, log, telemetry.enabled && scanID && !args.LOCAL)
251
266
  }
252
267
 
268
+ // Display link to scan results in the dashboard.
269
+ if (telemetry.enabled && scanURL && !args.QUIET) {
270
+ log(`View scan findings in the Eureka dashboard: ${scanURL}`)
271
+ }
272
+
253
273
  // Determine the correct exit code.
254
274
  let exitCode = 0
255
275
  if (!summary.errors.length && !summary.warnings.length && !summary.notes.length) {
276
+ // No vulnerabilities.
256
277
  exitCode = 0
278
+ } else if (args.THRESHOLD) {
279
+ // Set the exit code to 8 if there are any vulnerabilities with severities at or above the given threshold.
280
+ if (is_error(args.THRESHOLD) && summary.errors.length > 0) exitCode = 0x8
281
+ if (is_warning(args.THRESHOLD) && summary.warnings.length > 0) exitCode = 0x8
282
+ if (is_note(args.THRESHOLD) && summary.notes.length > 0) exitCode = 0x8
257
283
  } else {
284
+ // Set the exit code to 8 if there are any vulnerabilities.
258
285
  exitCode = 0x8
259
- if (summary.errors.length > 0) exitCode |= 0x1
260
- if (summary.warnings.length > 0) exitCode |= 0x2
261
- if (summary.notes.length > 0) exitCode |= 0x4
262
286
  }
263
287
 
264
288
  // Display the exit code.
Binary file