Skip to content

Commit 334513c

Browse files
authored
feat: support image scan in cli (#278)
* feat: support image scan in cli Signed-off-by: Ruben Romero Montes <rromerom@redhat.com> * fix: trigger IT only after Tests or manually Signed-off-by: Ruben Romero Montes <rromerom@redhat.com> --------- Signed-off-by: Ruben Romero Montes <rromerom@redhat.com>
1 parent f9025c1 commit 334513c

3 files changed

Lines changed: 113 additions & 10 deletions

File tree

.github/workflows/integration.yml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,19 @@ on:
88
types:
99
- completed
1010
workflow_dispatch:
11-
pull_request:
12-
branches:
13-
- main
1411

1512
concurrency:
1613
group: ${{ github.workflow }}-${{ github.ref }}
1714
cancel-in-progress: true
1815

1916
jobs:
2017
call-shared:
21-
# Only run if the test workflow succeeded, or if triggered directly
18+
# Only run if the test workflow succeeded, or if triggered manually
2219
if: |
2320
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') ||
24-
github.event_name == 'workflow_dispatch' ||
25-
github.event_name == 'pull_request'
21+
github.event_name == 'workflow_dispatch'
2622
uses: trustification/exhort-integration-tests/.github/workflows/integration.yml@main
2723
with:
2824
language: javascript
29-
repo-url: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
30-
commit-sha: ${{ github.event.pull_request.head.sha || github.sha }}
25+
repo-url: ${{ github.repository }}
26+
commit-sha: ${{ github.event.workflow_run && github.event.workflow_run.head_sha || github.sha }}

README.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ let stackAnalysis = await exhort.stackAnalysis('/path/to/pom.xml')
2525
let stackAnalysisHtml = await exhort.stackAnalysis('/path/to/pom.xml', true)
2626
// Get component analysis in JSON format
2727
let componentAnalysis = await exhort.componentAnalysis('/path/to/pom.xml')
28+
// Get image analysis in JSON format
29+
let imageAnalysis = await exhort.imageAnalysis(['docker.io/library/node:18'])
30+
// Get image analysis in HTML format (string)
31+
let imageAnalysisHtml = await exhort.imageAnalysis(['docker.io/library/node:18'], true)
32+
// Analyze multiple images
33+
let multipleImagesAnalysis = await exhort.imageAnalysis(['docker.io/library/node:18', 'docker.io/library/python:3.9'])
34+
// Specify architecture using ^^ notation (e.g., httpd:2.4.49^^amd64)
35+
let imageAnalysisWithArch = await exhort.imageAnalysis(['httpd:2.4.49^^amd64'])
2836
```
2937
</li>
3038
</ul>
@@ -68,11 +76,12 @@ Use as CLI Script
6876
```shell
6977
$ npx @trustify-da/trustify-da-javascript-client help
7078

71-
Usage: trustify-da-javascript-client {component|stack}
79+
Usage: trustify-da-javascript-client {component|stack|image|validate-token}
7280

7381
Commands:
7482
trustify-da-javascript-client stack </path/to/manifest> [--html|--summary] produce stack report for manifest path
7583
trustify-da-javascript-client component <path/to/manifest> [--summary] produce component report for a manifest type and content
84+
trustify-da-javascript-client image <image-refs..> [--html|--summary] produce image analysis report for OCI image references
7685

7786
Options:
7887
--help Show help [boolean]
@@ -91,6 +100,22 @@ $ npx @trustify-da/trustify-da-javascript-client stack /path/to/pom.xml --html
91100

92101
# get component analysis
93102
$ npx @trustify-da/trustify-da-javascript-client component /path/to/pom.xml
103+
104+
# get image analysis in json format
105+
$ npx @trustify-da/trustify-da-javascript-client image docker.io/library/node:18
106+
107+
# get image analysis in json format (summary only)
108+
# Note: summary returns an object with imageRef as key
109+
$ npx @trustify-da/trustify-da-javascript-client image docker.io/library/node:18 --summary
110+
111+
# get image analysis in html format
112+
$ npx @trustify-da/trustify-da-javascript-client image docker.io/library/node:18 --html
113+
114+
# analyze multiple images
115+
$ npx @trustify-da/trustify-da-javascript-client image docker.io/library/node:18 docker.io/library/python:3.9
116+
117+
# specify architecture using ^^ notation (e.g., httpd:2.4.49^^amd64)
118+
$ npx @trustify-da/trustify-da-javascript-client image httpd:2.4.49^^amd64
94119
```
95120
</li>
96121

@@ -113,6 +138,22 @@ $ trustify-da-javascript-client stack /path/to/pom.xml --html
113138

114139
# get component analysis
115140
$ trustify-da-javascript-client component /path/to/pom.xml
141+
142+
# get image analysis in json format
143+
$ trustify-da-javascript-client image docker.io/library/node:18
144+
145+
# get image analysis in json format (summary only)
146+
# Note: summary returns an object with imageRef as key
147+
$ trustify-da-javascript-client image docker.io/library/node:18 --summary
148+
149+
# get image analysis in html format
150+
$ trustify-da-javascript-client image docker.io/library/node:18 --html
151+
152+
# analyze multiple images
153+
$ trustify-da-javascript-client image docker.io/library/node:18 docker.io/library/python:3.9
154+
155+
# specify architecture using ^^ notation (e.g., httpd:2.4.49^^amd64)
156+
$ trustify-da-javascript-client image httpd:2.4.49^^amd64
116157
```
117158
</li>
118159
</ul>
@@ -288,6 +329,13 @@ let stackAnalysisHtml = await exhort.stackAnalysis('/path/to/pom.xml', true, opt
288329

289330
// Get component analysis in JSON format
290331
let componentAnalysis = await exhort.componentAnalysis('/path/to/pom.xml', options)
332+
333+
// Get image analysis in JSON format
334+
let imageAnalysis = await exhort.imageAnalysis(['docker.io/library/node:18'], false, options)
335+
// Get image analysis in HTML format in string
336+
let imageAnalysisHtml = await exhort.imageAnalysis(['docker.io/library/node:18'], true, options)
337+
// Specify architecture using ^^ notation (e.g., httpd:2.4.49^^amd64)
338+
let imageAnalysisWithArch = await exhort.imageAnalysis(['httpd:2.4.49^^amd64'], false, options)
291339
```
292340
**_Environment variables takes precedence._**
293341
</p>

src/cli.js

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,64 @@ const validateToken = {
5555
}
5656
}
5757

58+
// command for image analysis takes OCI image references
59+
const image = {
60+
command: 'image <image-refs..>',
61+
desc: 'produce image analysis report for OCI image references',
62+
builder: yargs => yargs.positional(
63+
'image-refs',
64+
{
65+
desc: 'OCI image references to analyze (one or more)',
66+
type: 'string',
67+
array: true,
68+
}
69+
).options({
70+
html: {
71+
alias: 'r',
72+
desc: 'Get the report as HTML instead of JSON',
73+
type: 'boolean',
74+
conflicts: 'summary'
75+
},
76+
summary: {
77+
alias: 's',
78+
desc: 'For JSON report, get only the \'summary\'',
79+
type: 'boolean',
80+
conflicts: 'html'
81+
}
82+
}),
83+
handler: async args => {
84+
let imageRefs = args['image-refs']
85+
if (!Array.isArray(imageRefs)) {
86+
imageRefs = [imageRefs]
87+
}
88+
let html = args['html']
89+
let summary = args['summary']
90+
let res = await exhort.imageAnalysis(imageRefs, html)
91+
if(summary && !html) {
92+
let summaries = {}
93+
for (let [imageRef, report] of Object.entries(res)) {
94+
for (let provider in report.providers) {
95+
if (report.providers[provider].sources !== undefined) {
96+
for (let source in report.providers[provider].sources) {
97+
if (report.providers[provider].sources[source].summary) {
98+
if (!summaries[imageRef]) {
99+
summaries[imageRef] = {};
100+
}
101+
if (!summaries[imageRef][provider]) {
102+
summaries[imageRef][provider] = {};
103+
}
104+
summaries[imageRef][provider][source] = report.providers[provider].sources[source].summary
105+
}
106+
}
107+
}
108+
}
109+
}
110+
res = summaries
111+
}
112+
console.log(html ? res : JSON.stringify(res, null, 2))
113+
}
114+
}
115+
58116
// command for stack analysis takes a manifest path
59117
const stack = {
60118
command: 'stack </path/to/manifest> [--html|--summary]',
@@ -112,9 +170,10 @@ const stack = {
112170

113171
// parse and invoke the command
114172
yargs(hideBin(process.argv))
115-
.usage(`Usage: ${process.argv[0].includes("node") ? path.parse(process.argv[1]).base : path.parse(process.argv[0]).base} {component|stack|validate-token}`)
173+
.usage(`Usage: ${process.argv[0].includes("node") ? path.parse(process.argv[1]).base : path.parse(process.argv[0]).base} {component|stack|image|validate-token}`)
116174
.command(stack)
117175
.command(component)
176+
.command(image)
118177
.command(validateToken)
119178
.scriptName('')
120179
.version(false)

0 commit comments

Comments
 (0)