@herodevs/cli 2.0.0-beta.1 → 2.0.0-beta.11
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.
- package/README.md +201 -110
- package/bin/dev.js +1 -4
- package/bin/main.js +3 -3
- package/bin/run.js +1 -1
- package/dist/api/gql-operations.d.ts +2 -0
- package/dist/api/gql-operations.js +36 -0
- package/dist/api/nes.client.d.ts +12 -0
- package/dist/api/nes.client.js +84 -0
- package/dist/commands/scan/eol.d.ts +18 -19
- package/dist/commands/scan/eol.js +214 -142
- package/dist/config/constants.d.ts +9 -3
- package/dist/config/constants.js +19 -3
- package/dist/hooks/finally/finally.d.ts +3 -0
- package/dist/hooks/finally/finally.js +18 -0
- package/dist/hooks/{npm-update-notifier.js → init/00_npm-update-notifier.js} +3 -3
- package/dist/hooks/init/01_initialize_amplitude.d.ts +3 -0
- package/dist/hooks/init/01_initialize_amplitude.js +15 -0
- package/dist/service/analytics.svc.d.ts +27 -0
- package/dist/service/analytics.svc.js +112 -0
- package/dist/service/{eol/cdx.svc.d.ts → cdx.svc.d.ts} +8 -16
- package/dist/service/{eol/cdx.svc.js → cdx.svc.js} +17 -7
- package/dist/service/display.svc.d.ts +30 -0
- package/dist/service/display.svc.js +87 -0
- package/dist/service/file.svc.d.ts +30 -0
- package/dist/service/file.svc.js +115 -0
- package/dist/service/log.svc.d.ts +1 -0
- package/dist/service/log.svc.js +9 -0
- package/dist/service/{eol/sbom.worker.js → sbom.worker.js} +2 -1
- package/dist/utils/strip-typename.d.ts +1 -0
- package/dist/utils/strip-typename.js +15 -0
- package/package.json +33 -22
- package/dist/api/client.d.ts +0 -12
- package/dist/api/client.js +0 -43
- package/dist/api/nes/nes.client.d.ts +0 -23
- package/dist/api/nes/nes.client.js +0 -107
- package/dist/api/queries/nes/sbom.d.ts +0 -3
- package/dist/api/queries/nes/sbom.js +0 -35
- package/dist/api/queries/nes/telemetry.d.ts +0 -2
- package/dist/api/queries/nes/telemetry.js +0 -24
- package/dist/api/types/hd-cli.types.d.ts +0 -30
- package/dist/api/types/hd-cli.types.js +0 -10
- package/dist/api/types/nes.types.d.ts +0 -53
- package/dist/api/types/nes.types.js +0 -1
- package/dist/commands/report/committers.d.ts +0 -23
- package/dist/commands/report/committers.js +0 -146
- package/dist/commands/report/purls.d.ts +0 -15
- package/dist/commands/report/purls.js +0 -84
- package/dist/commands/scan/sbom.d.ts +0 -21
- package/dist/commands/scan/sbom.js +0 -159
- package/dist/service/committers.svc.d.ts +0 -70
- package/dist/service/committers.svc.js +0 -196
- package/dist/service/eol/eol.svc.d.ts +0 -14
- package/dist/service/eol/eol.svc.js +0 -49
- package/dist/service/error.svc.d.ts +0 -8
- package/dist/service/error.svc.js +0 -28
- package/dist/service/nes/nes.svc.d.ts +0 -5
- package/dist/service/nes/nes.svc.js +0 -27
- package/dist/service/purls.svc.d.ts +0 -23
- package/dist/service/purls.svc.js +0 -99
- package/dist/ui/date.ui.d.ts +0 -1
- package/dist/ui/date.ui.js +0 -15
- package/dist/ui/eol.ui.d.ts +0 -15
- package/dist/ui/eol.ui.js +0 -134
- package/dist/ui/shared.ui.d.ts +0 -6
- package/dist/ui/shared.ui.js +0 -16
- /package/dist/hooks/{npm-update-notifier.d.ts → init/00_npm-update-notifier.d.ts} +0 -0
- /package/dist/hooks/{prerun.d.ts → prerun/prerun.d.ts} +0 -0
- /package/dist/hooks/{prerun.js → prerun/prerun.js} +0 -0
- /package/dist/service/{eol/sbom.worker.d.ts → sbom.worker.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -10,27 +10,69 @@ The HeroDevs CLI
|
|
|
10
10
|
* [@herodevs/cli](#herodevscli)
|
|
11
11
|
<!-- tocstop -->
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
### Terms and Data Security
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
- [HeroDevs End of Life Dataset Terms of Service and Data Policy](https://docs.herodevs.com/legal/end-of-life-dataset-terms)
|
|
16
|
+
- [HeroDevs End of Life Dataset Data Privacy and Security](https://docs.herodevs.com/eol-ds/data-privacy-and-security)
|
|
17
|
+
|
|
18
|
+
### Prerequisites
|
|
19
|
+
|
|
20
|
+
- Install node v20 or higher: [Download Node](https://nodejs.org/en/download)
|
|
21
|
+
- The HeroDevs CLI expects that you have all required technology installed for the project that you are running the CLI against
|
|
22
|
+
- For example, if you are running the CLI against a Gradle project, the CLI expects you to have Java installed.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Installation methods
|
|
26
|
+
|
|
27
|
+
#### Node Package Execute (NPX)
|
|
28
|
+
|
|
29
|
+
With Node installed, you can run the CLI directly from the npm registry without installing it globally or locally on your system
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
npx @herodevs/cli@beta
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
#### Global NPM Installation
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
npm install -g @herodevs/cli@beta
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
#### Binary Installation
|
|
42
|
+
|
|
43
|
+
HeroDevs CLI is available as a binary installation, without requiring `npm`. To do that, you may either download and run the script manually, or use the following cURL or Wget command:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
curl -o- https://raw.githubusercontent.com/herodevs/cli/v2.0.0-beta.11/scripts/install.sh | bash
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
wget -qO- https://raw.githubusercontent.com/herodevs/cli/v2.0.0-beta.11/scripts/install.sh | bash
|
|
51
|
+
```
|
|
16
52
|
|
|
17
53
|
## Scanning Behavior
|
|
18
54
|
|
|
19
|
-
The CLI
|
|
55
|
+
The CLI is designed to be non-invasive:
|
|
56
|
+
|
|
57
|
+
* It does **not** install dependencies or modify package manager files (package-lock.json, yarn.lock, etc.)
|
|
58
|
+
* It analyzes the project in its current state
|
|
59
|
+
|
|
60
|
+
## Installing Dependencies Before Use
|
|
20
61
|
|
|
21
|
-
|
|
22
|
-
* They analyze the project in its current state
|
|
23
|
-
* If you need dependencies installed for accurate scanning, please install them manually before running the scan
|
|
62
|
+
Some projects and ecosystems require projects to have dependencies installed already, to achieve an accurate scan result. It is **highly** recommended that you install all dependencies of your project to your working directory, before running a scan on your project, to ensure scan accuracy.
|
|
24
63
|
|
|
64
|
+
### Java Users
|
|
65
|
+
|
|
66
|
+
Maven and Gradle projects should run an install and build before scanning
|
|
25
67
|
|
|
26
68
|
## Usage
|
|
27
69
|
<!-- usage -->
|
|
28
70
|
```sh-session
|
|
29
|
-
$ npm install -g @herodevs/cli
|
|
71
|
+
$ npm install -g @herodevs/cli@beta
|
|
30
72
|
$ hd COMMAND
|
|
31
73
|
running command...
|
|
32
74
|
$ hd (--version)
|
|
33
|
-
@herodevs/cli/2.0.0-beta.
|
|
75
|
+
@herodevs/cli/2.0.0-beta.10 darwin-arm64 node-v22.18.0
|
|
34
76
|
$ hd --help [COMMAND]
|
|
35
77
|
USAGE
|
|
36
78
|
$ hd COMMAND
|
|
@@ -40,11 +82,9 @@ USAGE
|
|
|
40
82
|
## Commands
|
|
41
83
|
<!-- commands -->
|
|
42
84
|
* [`hd help [COMMAND]`](#hd-help-command)
|
|
43
|
-
* [`hd report committers`](#hd-report-committers)
|
|
44
|
-
* [`hd report purls`](#hd-report-purls)
|
|
45
85
|
* [`hd scan eol`](#hd-scan-eol)
|
|
46
|
-
* [`hd scan sbom`](#hd-scan-sbom)
|
|
47
86
|
* [`hd update [CHANNEL]`](#hd-update-channel)
|
|
87
|
+
* **NOTE:** Only applies to [binary installation method](#binary-installation). NPM users should use [`npm install`](#global-npm-installation) to update to the latest version.
|
|
48
88
|
|
|
49
89
|
## `hd help [COMMAND]`
|
|
50
90
|
|
|
@@ -64,170 +104,221 @@ DESCRIPTION
|
|
|
64
104
|
Display help for hd.
|
|
65
105
|
```
|
|
66
106
|
|
|
67
|
-
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.
|
|
107
|
+
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.33/src/commands/help.ts)_
|
|
68
108
|
|
|
69
|
-
## `hd
|
|
109
|
+
## `hd scan eol`
|
|
70
110
|
|
|
71
|
-
|
|
111
|
+
Scan a given SBOM for EOL data
|
|
72
112
|
|
|
73
113
|
```
|
|
74
114
|
USAGE
|
|
75
|
-
$ hd
|
|
115
|
+
$ hd scan eol [--json] [-f <value> | -d <value>] [-s] [-o <value>] [--saveSbom] [--sbomOutput <value>] [--saveTrimmedSbom] [--hideReportUrl] [--version]
|
|
76
116
|
|
|
77
117
|
FLAGS
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
-s, --save
|
|
118
|
+
-d, --dir=<value> [default: <current directory>] The directory to scan in order to scan for EOL
|
|
119
|
+
-f, --file=<value> The file path of an existing SBOM to scan for EOL (supports CycloneDX and SPDX 2.3 formats)
|
|
120
|
+
-s, --save Save the generated report as herodevs.report.json in the scanned directory
|
|
121
|
+
-o, --output=<value> Save the generated report to a custom path (requires --save, defaults to herodevs.report.json when not provided)
|
|
122
|
+
--hideReportUrl Hide the generated web report URL for this scan
|
|
123
|
+
--saveSbom Save the generated SBOM as herodevs.sbom.json in the scanned directory
|
|
124
|
+
--sbomOutput=<value> Save the generated SBOM to a custom path (requires --saveSbom, defaults to herodevs.sbom.json when not provided)
|
|
125
|
+
--saveTrimmedSbom Save the trimmed SBOM as herodevs.sbom-trimmed.json in the scanned directory
|
|
126
|
+
--version Show CLI version.
|
|
81
127
|
|
|
82
128
|
GLOBAL FLAGS
|
|
83
129
|
--json Format output as json.
|
|
84
130
|
|
|
85
131
|
DESCRIPTION
|
|
86
|
-
|
|
132
|
+
Scan a given SBOM for EOL data
|
|
87
133
|
|
|
88
134
|
EXAMPLES
|
|
89
|
-
|
|
135
|
+
Default behavior (no command or flags specified)
|
|
90
136
|
|
|
91
|
-
|
|
137
|
+
$ hd
|
|
92
138
|
|
|
93
|
-
|
|
139
|
+
Equivalent to
|
|
94
140
|
|
|
95
|
-
|
|
96
|
-
```
|
|
141
|
+
$ hd scan eol --dir .
|
|
97
142
|
|
|
98
|
-
|
|
143
|
+
Skip SBOM generation and specify an existing file
|
|
99
144
|
|
|
100
|
-
|
|
145
|
+
$ hd scan eol --file /path/to/sbom.json
|
|
101
146
|
|
|
102
|
-
|
|
147
|
+
Save the report or SBOM to a file
|
|
103
148
|
|
|
104
|
-
|
|
105
|
-
USAGE
|
|
106
|
-
$ hd report purls [--json] [-f <value>] [-d <value>] [-s] [-c]
|
|
149
|
+
$ hd scan eol --save --saveSbom
|
|
107
150
|
|
|
108
|
-
|
|
109
|
-
-c, --csv Save output in CSV format (only applies when using --save)
|
|
110
|
-
-d, --dir=<value> The directory to scan in order to create a cyclonedx sbom
|
|
111
|
-
-f, --file=<value> The file path of an existing cyclonedx sbom to scan for EOL
|
|
112
|
-
-s, --save Save the list of purls as eol.purls.<output>
|
|
151
|
+
Save the report and SBOM to custom paths
|
|
113
152
|
|
|
114
|
-
|
|
115
|
-
--json Format output as json.
|
|
116
|
-
|
|
117
|
-
DESCRIPTION
|
|
118
|
-
Generate a list of purls from a sbom
|
|
119
|
-
|
|
120
|
-
EXAMPLES
|
|
121
|
-
$ hd report purls --json -s
|
|
153
|
+
$ hd scan eol --dir . --save --saveSbom --output ./reports/my-report.json --sbomOutput ./reports/my-sbom.json
|
|
122
154
|
|
|
123
|
-
|
|
155
|
+
Output the report in JSON format (for APIs, CI, etc.)
|
|
124
156
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
$ hd report purls --dir=./my-project --save
|
|
128
|
-
|
|
129
|
-
$ hd report purls --save --csv
|
|
157
|
+
$ hd scan eol --json
|
|
130
158
|
```
|
|
131
159
|
|
|
132
|
-
_See code: [src/commands/
|
|
160
|
+
_See code: [src/commands/scan/eol.ts](https://github.com/herodevs/cli/blob/v2.0.0-beta.10/src/commands/scan/eol.ts)_
|
|
133
161
|
|
|
134
|
-
## `hd
|
|
162
|
+
## `hd update [CHANNEL]`
|
|
163
|
+
|
|
164
|
+
update the hd CLI
|
|
135
165
|
|
|
136
|
-
|
|
166
|
+
* **NOTE:** Only applies to [binary installation method](#binary-installation). NPM users should use [`npm install`](#global-npm-installation) to update to the latest version.
|
|
137
167
|
|
|
138
168
|
```
|
|
139
169
|
USAGE
|
|
140
|
-
$ hd
|
|
170
|
+
$ hd update [CHANNEL] [--force | | [-a | -v <value> | -i]] [-b ]
|
|
141
171
|
|
|
142
172
|
FLAGS
|
|
143
|
-
-a, --
|
|
144
|
-
-
|
|
145
|
-
-
|
|
146
|
-
-
|
|
147
|
-
|
|
148
|
-
-t, --table Display the results in a table
|
|
149
|
-
|
|
150
|
-
GLOBAL FLAGS
|
|
151
|
-
--json Format output as json.
|
|
173
|
+
-a, --available See available versions.
|
|
174
|
+
-b, --verbose Show more details about the available versions.
|
|
175
|
+
-i, --interactive Interactively select version to install. This is ignored if a channel is provided.
|
|
176
|
+
-v, --version=<value> Install a specific version.
|
|
177
|
+
--force Force a re-download of the requested version.
|
|
152
178
|
|
|
153
179
|
DESCRIPTION
|
|
154
|
-
|
|
180
|
+
update the hd CLI
|
|
155
181
|
|
|
156
182
|
EXAMPLES
|
|
157
|
-
|
|
183
|
+
Update to the stable channel:
|
|
158
184
|
|
|
159
|
-
|
|
185
|
+
$ hd update stable
|
|
160
186
|
|
|
161
|
-
|
|
187
|
+
Update to a specific version:
|
|
162
188
|
|
|
163
|
-
|
|
164
|
-
```
|
|
189
|
+
$ hd update --version 1.0.0
|
|
165
190
|
|
|
166
|
-
|
|
191
|
+
Interactively select version:
|
|
167
192
|
|
|
168
|
-
|
|
193
|
+
$ hd update --interactive
|
|
169
194
|
|
|
170
|
-
|
|
195
|
+
See available versions:
|
|
171
196
|
|
|
197
|
+
$ hd update --available
|
|
172
198
|
```
|
|
173
|
-
USAGE
|
|
174
|
-
$ hd scan sbom [--json] [-f <value>] [-d <value>] [-s] [-b]
|
|
175
199
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
-d, --dir=<value> The directory to scan in order to create a cyclonedx sbom
|
|
179
|
-
-f, --file=<value> The file path of an existing cyclonedx sbom to scan for EOL
|
|
180
|
-
-s, --save Save the generated SBOM as eol.sbom.json in the scanned directory
|
|
200
|
+
_See code: [@oclif/plugin-update](https://github.com/oclif/plugin-update/blob/v4.7.8/src/commands/update.ts)_
|
|
201
|
+
<!-- commandsstop -->
|
|
181
202
|
|
|
182
|
-
|
|
183
|
-
--json Format output as json.
|
|
203
|
+
## CI/CD Usage
|
|
184
204
|
|
|
185
|
-
|
|
186
|
-
Scan a SBOM for purls
|
|
205
|
+
You can use `@herodevs/cli` in your CI/CD pipelines to automate EOL scanning.
|
|
187
206
|
|
|
188
|
-
|
|
189
|
-
$ hd scan sbom --dir=./my-project
|
|
207
|
+
### Using the Docker Image (Recommended)
|
|
190
208
|
|
|
191
|
-
|
|
192
|
-
|
|
209
|
+
We provide a Docker image that's pre-configured to run EOL scans. Based on [`cdxgen`](https://github.com/CycloneDX/cdxgen),
|
|
210
|
+
it contains build tools for most project types and will provide best results when generating an SBOM. Use these templates to generate a report and save it to your CI job artifact for analysis and processing after your scan runs.
|
|
193
211
|
|
|
194
|
-
|
|
212
|
+
#### GitHub Actions
|
|
195
213
|
|
|
196
|
-
|
|
214
|
+
```yaml
|
|
215
|
+
## .github/workflows/herodevs-eol-scan.yml
|
|
216
|
+
name: HeroDevs EOL Scan
|
|
197
217
|
|
|
198
|
-
|
|
218
|
+
on:
|
|
219
|
+
push:
|
|
220
|
+
branches: [ main ]
|
|
221
|
+
pull_request:
|
|
222
|
+
branches: [ main ]
|
|
223
|
+
|
|
224
|
+
jobs:
|
|
225
|
+
scan:
|
|
226
|
+
runs-on: ubuntu-latest
|
|
227
|
+
environment: demo
|
|
228
|
+
steps:
|
|
229
|
+
- name: Checkout repository
|
|
230
|
+
uses: actions/checkout@v4
|
|
199
231
|
|
|
232
|
+
- name: Run EOL Scan
|
|
233
|
+
run: |
|
|
234
|
+
docker run --rm \
|
|
235
|
+
-v $GITHUB_WORKSPACE:/app \
|
|
236
|
+
-w /app \
|
|
237
|
+
ghcr.io/herodevs/eol-scan --save
|
|
238
|
+
|
|
239
|
+
- name: Upload artifact
|
|
240
|
+
uses: actions/upload-artifact@v4
|
|
241
|
+
with:
|
|
242
|
+
name: my-eol-report
|
|
243
|
+
path: ./herodevs.report.json
|
|
200
244
|
```
|
|
201
|
-
USAGE
|
|
202
|
-
$ hd update [CHANNEL] [--force | | [-a | -v <value> | -i]] [-b ]
|
|
203
245
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
246
|
+
#### GitLab CI/CD
|
|
247
|
+
|
|
248
|
+
```yaml
|
|
249
|
+
eol-scan:
|
|
250
|
+
image:
|
|
251
|
+
name: "ghcr.io/herodevs/eol-scan"
|
|
252
|
+
# Entrypoint or base command must be disabled due
|
|
253
|
+
# to GitLab's execution mechanism and run manually
|
|
254
|
+
entrypoint: [""]
|
|
255
|
+
script: "npx @herodevs/cli@beta scan eol -s"
|
|
256
|
+
artifacts:
|
|
257
|
+
paths:
|
|
258
|
+
- herodevs.report.json
|
|
259
|
+
```
|
|
210
260
|
|
|
211
|
-
|
|
212
|
-
update the hd CLI
|
|
261
|
+
### Using `npx` in CI
|
|
213
262
|
|
|
214
|
-
|
|
215
|
-
Update to the stable channel:
|
|
263
|
+
You can use `npx` to run the CLI in your CI pipeline, just like you would run it locally.
|
|
216
264
|
|
|
217
|
-
|
|
265
|
+
> [!NOTE]
|
|
266
|
+
> The development environment is expected to be ready to run the app. For best results,
|
|
267
|
+
prefer [using the prebuilt image](#using-the-docker-image-recommended), but otherwise, prepare
|
|
268
|
+
all requirements before the scan step.
|
|
218
269
|
|
|
219
|
-
|
|
270
|
+
#### GitHub Actions
|
|
220
271
|
|
|
221
|
-
|
|
272
|
+
```yaml
|
|
273
|
+
## .github/workflows/herodevs-eol-scan.yml
|
|
274
|
+
name: HeroDevs EOL Scan
|
|
222
275
|
|
|
223
|
-
|
|
276
|
+
on:
|
|
277
|
+
push:
|
|
278
|
+
branches: [ main ]
|
|
279
|
+
pull_request:
|
|
280
|
+
branches: [ main ]
|
|
224
281
|
|
|
225
|
-
|
|
282
|
+
jobs:
|
|
283
|
+
scan:
|
|
284
|
+
runs-on: ubuntu-latest
|
|
285
|
+
steps:
|
|
286
|
+
- uses: actions/checkout@v4
|
|
287
|
+
- uses: actions/setup-node@v4
|
|
288
|
+
with:
|
|
289
|
+
node-version: '22'
|
|
226
290
|
|
|
227
|
-
|
|
291
|
+
- run: echo # Prepare environment, install tooling, perform setup, etc.
|
|
228
292
|
|
|
229
|
-
|
|
293
|
+
- name: Run EOL Scan
|
|
294
|
+
run: npx @herodevs/cli@beta scan eol
|
|
295
|
+
|
|
296
|
+
- name: Upload artifact
|
|
297
|
+
uses: actions/upload-artifact@v4
|
|
298
|
+
with:
|
|
299
|
+
name: my-eol-report
|
|
300
|
+
path: herodevs.report.json
|
|
230
301
|
```
|
|
231
302
|
|
|
232
|
-
|
|
233
|
-
|
|
303
|
+
#### GitLab CI/CD
|
|
304
|
+
|
|
305
|
+
```yaml
|
|
306
|
+
image: alpine
|
|
307
|
+
|
|
308
|
+
eol-scan:
|
|
309
|
+
script:
|
|
310
|
+
- echo # Prepare environment, install tooling, perform setup, etc.
|
|
311
|
+
- npx @herodevs/cli@beta scan eol -s
|
|
312
|
+
artifacts:
|
|
313
|
+
paths:
|
|
314
|
+
- herodevs.report.json
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Local Docker image scans
|
|
318
|
+
|
|
319
|
+
The same pre-configured image can be pulled locally to scan in an optimized environment. Mount your code
|
|
320
|
+
to `/app` or a specified working directory to perform the scan:
|
|
321
|
+
|
|
322
|
+
```shell
|
|
323
|
+
docker run -v "$PWD":/app ghcr.io/herodevs/eol-scan
|
|
324
|
+
```
|
package/bin/dev.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
process.env.GRAPHQL_HOST = 'https://api.dev.nes.herodevs.com';
|
|
4
|
-
process.env.EOL_REPORT_URL = 'https://eol-report-card.stage.apps.herodevs.io/reports';
|
|
5
|
-
|
|
6
3
|
import main from './main.js';
|
|
7
4
|
|
|
8
5
|
try {
|
|
9
6
|
await main(false);
|
|
10
|
-
} catch
|
|
7
|
+
} catch {
|
|
11
8
|
process.exit(1);
|
|
12
9
|
}
|
package/bin/main.js
CHANGED
|
@@ -7,9 +7,9 @@ async function main(isProduction = false) {
|
|
|
7
7
|
strict: false, // Don't validate flags
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
-
// If no arguments at all, default to scan:eol
|
|
10
|
+
// If no arguments at all, default to scan:eol
|
|
11
11
|
if (positionals.length === 0) {
|
|
12
|
-
process.argv.splice(2, 0, 'scan:eol'
|
|
12
|
+
process.argv.splice(2, 0, 'scan:eol');
|
|
13
13
|
}
|
|
14
14
|
// If only flags are provided, set scan:eol as the command for those flags
|
|
15
15
|
else if (positionals.length === 1 && positionals[0].startsWith('-')) {
|
|
@@ -21,7 +21,7 @@ async function main(isProduction = false) {
|
|
|
21
21
|
development: !isProduction,
|
|
22
22
|
dir: new URL('./dev.js', import.meta.url),
|
|
23
23
|
});
|
|
24
|
-
} catch
|
|
24
|
+
} catch {
|
|
25
25
|
process.exit(1);
|
|
26
26
|
}
|
|
27
27
|
}
|
package/bin/run.js
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { gql } from '@apollo/client/core/core.cjs';
|
|
2
|
+
export const createReportMutation = gql `
|
|
3
|
+
mutation createReport($input: CreateEolReportInput) {
|
|
4
|
+
eol {
|
|
5
|
+
createReport(input: $input) {
|
|
6
|
+
success
|
|
7
|
+
id
|
|
8
|
+
totalRecords
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
`;
|
|
13
|
+
export const getEolReportQuery = gql `
|
|
14
|
+
query GetEolReport($input: GetEolReportInput) {
|
|
15
|
+
eol {
|
|
16
|
+
report(input: $input) {
|
|
17
|
+
id
|
|
18
|
+
createdOn
|
|
19
|
+
metadata
|
|
20
|
+
components {
|
|
21
|
+
purl
|
|
22
|
+
metadata
|
|
23
|
+
nesRemediation {
|
|
24
|
+
remediations {
|
|
25
|
+
urls {
|
|
26
|
+
main
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
page
|
|
32
|
+
totalRecords
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ApolloClient } from '@apollo/client/core/index.js';
|
|
2
|
+
import type { CreateEolReportInput, EolReport } from '@herodevs/eol-shared';
|
|
3
|
+
export declare const createApollo: (uri: string) => ApolloClient<import("@apollo/client/core/index.js").NormalizedCacheObject>;
|
|
4
|
+
export declare const SbomScanner: (client: ReturnType<typeof createApollo>) => (input: CreateEolReportInput) => Promise<EolReport>;
|
|
5
|
+
export declare class NesClient {
|
|
6
|
+
startScan: ReturnType<typeof SbomScanner>;
|
|
7
|
+
constructor(url: string);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Submit a scan for a list of purls
|
|
11
|
+
*/
|
|
12
|
+
export declare function submitScan(input: CreateEolReportInput): Promise<EolReport>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client/core/index.js';
|
|
2
|
+
import { config } from "../config/constants.js";
|
|
3
|
+
import { debugLogger } from "../service/log.svc.js";
|
|
4
|
+
import { stripTypename } from "../utils/strip-typename.js";
|
|
5
|
+
import { createReportMutation, getEolReportQuery } from "./gql-operations.js";
|
|
6
|
+
export const createApollo = (uri) => new ApolloClient({
|
|
7
|
+
cache: new InMemoryCache(),
|
|
8
|
+
defaultOptions: {
|
|
9
|
+
query: { fetchPolicy: 'no-cache', errorPolicy: 'all' },
|
|
10
|
+
mutate: { errorPolicy: 'all' },
|
|
11
|
+
},
|
|
12
|
+
link: new HttpLink({
|
|
13
|
+
uri,
|
|
14
|
+
headers: {
|
|
15
|
+
'User-Agent': `hdcli/${process.env.npm_package_version ?? 'unknown'}`,
|
|
16
|
+
},
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
19
|
+
export const SbomScanner = (client) => {
|
|
20
|
+
return async (input) => {
|
|
21
|
+
const res = await client.mutate({
|
|
22
|
+
mutation: createReportMutation,
|
|
23
|
+
variables: { input },
|
|
24
|
+
});
|
|
25
|
+
if (res?.errors?.length) {
|
|
26
|
+
debugLogger('GraphQL errors in createReport: %o', res.errors);
|
|
27
|
+
throw new Error('Failed to create EOL report');
|
|
28
|
+
}
|
|
29
|
+
const result = res.data?.eol?.createReport;
|
|
30
|
+
if (!result?.success || !result.id) {
|
|
31
|
+
debugLogger('failed scan %o', result || {});
|
|
32
|
+
throw new Error('Failed to create EOL report');
|
|
33
|
+
}
|
|
34
|
+
const totalRecords = result.totalRecords || 0;
|
|
35
|
+
const totalPages = Math.ceil(totalRecords / config.pageSize);
|
|
36
|
+
const pages = Array.from({ length: totalPages }, (_, index) => client.query({
|
|
37
|
+
query: getEolReportQuery,
|
|
38
|
+
variables: {
|
|
39
|
+
input: {
|
|
40
|
+
id: result.id,
|
|
41
|
+
page: index + 1,
|
|
42
|
+
size: config.pageSize,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
}));
|
|
46
|
+
const components = [];
|
|
47
|
+
let reportMetadata = null;
|
|
48
|
+
for (let i = 0; i < pages.length; i += config.concurrentPageRequests) {
|
|
49
|
+
const batch = pages.slice(i, i + config.concurrentPageRequests);
|
|
50
|
+
const batchResponses = await Promise.all(batch);
|
|
51
|
+
for (const response of batchResponses) {
|
|
52
|
+
if (response?.errors?.length) {
|
|
53
|
+
debugLogger('GraphQL errors in getReport query: %o', response.errors);
|
|
54
|
+
throw new Error('Failed to fetch EOL report');
|
|
55
|
+
}
|
|
56
|
+
const report = response.data.eol.report;
|
|
57
|
+
reportMetadata ??= report;
|
|
58
|
+
components.push(...(report?.components ?? []));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!reportMetadata) {
|
|
62
|
+
throw new Error('Failed to fetch EOL report');
|
|
63
|
+
}
|
|
64
|
+
return stripTypename({
|
|
65
|
+
...reportMetadata,
|
|
66
|
+
components,
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
export class NesClient {
|
|
71
|
+
startScan;
|
|
72
|
+
constructor(url) {
|
|
73
|
+
this.startScan = SbomScanner(createApollo(url));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Submit a scan for a list of purls
|
|
78
|
+
*/
|
|
79
|
+
export function submitScan(input) {
|
|
80
|
+
const url = config.graphqlHost + config.graphqlPath;
|
|
81
|
+
debugLogger('Submitting scan to %s', url);
|
|
82
|
+
const client = new NesClient(url);
|
|
83
|
+
return client.startScan(input);
|
|
84
|
+
}
|
|
@@ -1,31 +1,30 @@
|
|
|
1
|
+
import type { EolReport } from '@herodevs/eol-shared';
|
|
1
2
|
import { Command } from '@oclif/core';
|
|
2
|
-
import type { InsightsEolScanComponent } from '../../api/types/nes.types.ts';
|
|
3
3
|
export default class ScanEol extends Command {
|
|
4
4
|
static description: string;
|
|
5
5
|
static enableJsonFlag: boolean;
|
|
6
|
-
static examples:
|
|
6
|
+
static examples: {
|
|
7
|
+
description: string;
|
|
8
|
+
command: string;
|
|
9
|
+
}[];
|
|
7
10
|
static flags: {
|
|
8
11
|
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
-
|
|
10
|
-
dir: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
dir: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
13
|
save: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
saveSbom: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
sbomOutput: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
saveTrimmedSbom: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
hideReportUrl: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
19
|
+
version: import("@oclif/core/interfaces").BooleanFlag<void>;
|
|
14
20
|
};
|
|
15
|
-
run(): Promise<
|
|
16
|
-
|
|
17
|
-
}>;
|
|
18
|
-
private getScan;
|
|
19
|
-
private getPurlsFromFile;
|
|
20
|
-
private printWebReportUrl;
|
|
21
|
+
run(): Promise<EolReport | undefined>;
|
|
22
|
+
private loadSbom;
|
|
21
23
|
private scanSbom;
|
|
22
|
-
private getFilteredComponents;
|
|
23
24
|
private saveReport;
|
|
25
|
+
private saveSbom;
|
|
26
|
+
private saveTrimmedSbom;
|
|
24
27
|
private displayResults;
|
|
25
|
-
private
|
|
26
|
-
private
|
|
27
|
-
private displayNoComponentsMessage;
|
|
28
|
-
private logLine;
|
|
29
|
-
private displayStatusSection;
|
|
30
|
-
private logLegend;
|
|
28
|
+
private getSbomFromScan;
|
|
29
|
+
private getSbomFromFile;
|
|
31
30
|
}
|