@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.
Files changed (69) hide show
  1. package/README.md +201 -110
  2. package/bin/dev.js +1 -4
  3. package/bin/main.js +3 -3
  4. package/bin/run.js +1 -1
  5. package/dist/api/gql-operations.d.ts +2 -0
  6. package/dist/api/gql-operations.js +36 -0
  7. package/dist/api/nes.client.d.ts +12 -0
  8. package/dist/api/nes.client.js +84 -0
  9. package/dist/commands/scan/eol.d.ts +18 -19
  10. package/dist/commands/scan/eol.js +214 -142
  11. package/dist/config/constants.d.ts +9 -3
  12. package/dist/config/constants.js +19 -3
  13. package/dist/hooks/finally/finally.d.ts +3 -0
  14. package/dist/hooks/finally/finally.js +18 -0
  15. package/dist/hooks/{npm-update-notifier.js → init/00_npm-update-notifier.js} +3 -3
  16. package/dist/hooks/init/01_initialize_amplitude.d.ts +3 -0
  17. package/dist/hooks/init/01_initialize_amplitude.js +15 -0
  18. package/dist/service/analytics.svc.d.ts +27 -0
  19. package/dist/service/analytics.svc.js +112 -0
  20. package/dist/service/{eol/cdx.svc.d.ts → cdx.svc.d.ts} +8 -16
  21. package/dist/service/{eol/cdx.svc.js → cdx.svc.js} +17 -7
  22. package/dist/service/display.svc.d.ts +30 -0
  23. package/dist/service/display.svc.js +87 -0
  24. package/dist/service/file.svc.d.ts +30 -0
  25. package/dist/service/file.svc.js +115 -0
  26. package/dist/service/log.svc.d.ts +1 -0
  27. package/dist/service/log.svc.js +9 -0
  28. package/dist/service/{eol/sbom.worker.js → sbom.worker.js} +2 -1
  29. package/dist/utils/strip-typename.d.ts +1 -0
  30. package/dist/utils/strip-typename.js +15 -0
  31. package/package.json +33 -22
  32. package/dist/api/client.d.ts +0 -12
  33. package/dist/api/client.js +0 -43
  34. package/dist/api/nes/nes.client.d.ts +0 -23
  35. package/dist/api/nes/nes.client.js +0 -107
  36. package/dist/api/queries/nes/sbom.d.ts +0 -3
  37. package/dist/api/queries/nes/sbom.js +0 -35
  38. package/dist/api/queries/nes/telemetry.d.ts +0 -2
  39. package/dist/api/queries/nes/telemetry.js +0 -24
  40. package/dist/api/types/hd-cli.types.d.ts +0 -30
  41. package/dist/api/types/hd-cli.types.js +0 -10
  42. package/dist/api/types/nes.types.d.ts +0 -53
  43. package/dist/api/types/nes.types.js +0 -1
  44. package/dist/commands/report/committers.d.ts +0 -23
  45. package/dist/commands/report/committers.js +0 -146
  46. package/dist/commands/report/purls.d.ts +0 -15
  47. package/dist/commands/report/purls.js +0 -84
  48. package/dist/commands/scan/sbom.d.ts +0 -21
  49. package/dist/commands/scan/sbom.js +0 -159
  50. package/dist/service/committers.svc.d.ts +0 -70
  51. package/dist/service/committers.svc.js +0 -196
  52. package/dist/service/eol/eol.svc.d.ts +0 -14
  53. package/dist/service/eol/eol.svc.js +0 -49
  54. package/dist/service/error.svc.d.ts +0 -8
  55. package/dist/service/error.svc.js +0 -28
  56. package/dist/service/nes/nes.svc.d.ts +0 -5
  57. package/dist/service/nes/nes.svc.js +0 -27
  58. package/dist/service/purls.svc.d.ts +0 -23
  59. package/dist/service/purls.svc.js +0 -99
  60. package/dist/ui/date.ui.d.ts +0 -1
  61. package/dist/ui/date.ui.js +0 -15
  62. package/dist/ui/eol.ui.d.ts +0 -15
  63. package/dist/ui/eol.ui.js +0 -134
  64. package/dist/ui/shared.ui.d.ts +0 -6
  65. package/dist/ui/shared.ui.js +0 -16
  66. /package/dist/hooks/{npm-update-notifier.d.ts → init/00_npm-update-notifier.d.ts} +0 -0
  67. /package/dist/hooks/{prerun.d.ts → prerun/prerun.d.ts} +0 -0
  68. /package/dist/hooks/{prerun.js → prerun/prerun.js} +0 -0
  69. /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
- ## TERMS
13
+ ### Terms and Data Security
14
14
 
15
- Use of this CLI is governed by the [HeroDevs End of Life Dataset Terms of Service and Data Policy](https://docs.herodevs.com/legal/end-of-life-dataset-terms).
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's scanning commands (`hd scan eol` and `hd scan sbom`) are designed to be non-invasive:
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
- * They do not install dependencies or modify package manager files (package-lock.json, yarn.lock, etc.)
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.1 linux-x64 node-v22.15.0
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.28/src/commands/help.ts)_
107
+ _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.33/src/commands/help.ts)_
68
108
 
69
- ## `hd report committers`
109
+ ## `hd scan eol`
70
110
 
71
- Generate report of committers to a git repository
111
+ Scan a given SBOM for EOL data
72
112
 
73
113
  ```
74
114
  USAGE
75
- $ hd report committers [--json] [-m <value>] [-c] [-s]
115
+ $ hd scan eol [--json] [-f <value> | -d <value>] [-s] [-o <value>] [--saveSbom] [--sbomOutput <value>] [--saveTrimmedSbom] [--hideReportUrl] [--version]
76
116
 
77
117
  FLAGS
78
- -c, --csv Output in CSV format
79
- -m, --months=<value> [default: 12] The number of months of git history to review
80
- -s, --save Save the committers report as eol.committers.<output>
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
- Generate report of committers to a git repository
132
+ Scan a given SBOM for EOL data
87
133
 
88
134
  EXAMPLES
89
- $ hd report committers
135
+ Default behavior (no command or flags specified)
90
136
 
91
- $ hd report committers --csv -s
137
+ $ hd
92
138
 
93
- $ hd report committers --json
139
+ Equivalent to
94
140
 
95
- $ hd report committers --csv
96
- ```
141
+ $ hd scan eol --dir .
97
142
 
98
- _See code: [src/commands/report/committers.ts](https://github.com/herodevs/cli/blob/v2.0.0-beta.1/src/commands/report/committers.ts)_
143
+ Skip SBOM generation and specify an existing file
99
144
 
100
- ## `hd report purls`
145
+ $ hd scan eol --file /path/to/sbom.json
101
146
 
102
- Generate a list of purls from a sbom
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
- FLAGS
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
- GLOBAL FLAGS
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
- $ hd report purls --dir=./my-project
155
+ Output the report in JSON format (for APIs, CI, etc.)
124
156
 
125
- $ hd report purls --file=path/to/sbom.json
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/report/purls.ts](https://github.com/herodevs/cli/blob/v2.0.0-beta.1/src/commands/report/purls.ts)_
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 scan eol`
162
+ ## `hd update [CHANNEL]`
163
+
164
+ update the hd CLI
135
165
 
136
- Scan a given sbom for EOL data
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 scan eol [--json] [-f <value>] [-p <value>] [-d <value>] [-s] [-a] [-t]
170
+ $ hd update [CHANNEL] [--force | | [-a | -v <value> | -i]] [-b ]
141
171
 
142
172
  FLAGS
143
- -a, --all Show all components (default is EOL and SUPPORTED only)
144
- -d, --dir=<value> The directory to scan in order to create a cyclonedx sbom
145
- -f, --file=<value> The file path of an existing cyclonedx sbom to scan for EOL
146
- -p, --purls=<value> The file path of a list of purls to scan for EOL
147
- -s, --save Save the generated report as eol.report.json in the scanned directory
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
- Scan a given sbom for EOL data
180
+ update the hd CLI
155
181
 
156
182
  EXAMPLES
157
- $ hd scan eol --dir=./my-project
183
+ Update to the stable channel:
158
184
 
159
- $ hd scan eol --file=path/to/sbom.json
185
+ $ hd update stable
160
186
 
161
- $ hd scan eol --purls=path/to/purls.json
187
+ Update to a specific version:
162
188
 
163
- $ hd scan eol -a --dir=./my-project
164
- ```
189
+ $ hd update --version 1.0.0
165
190
 
166
- _See code: [src/commands/scan/eol.ts](https://github.com/herodevs/cli/blob/v2.0.0-beta.1/src/commands/scan/eol.ts)_
191
+ Interactively select version:
167
192
 
168
- ## `hd scan sbom`
193
+ $ hd update --interactive
169
194
 
170
- Scan a SBOM for purls
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
- FLAGS
177
- -b, --background Run the scan in the background
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
- GLOBAL FLAGS
183
- --json Format output as json.
203
+ ## CI/CD Usage
184
204
 
185
- DESCRIPTION
186
- Scan a SBOM for purls
205
+ You can use `@herodevs/cli` in your CI/CD pipelines to automate EOL scanning.
187
206
 
188
- EXAMPLES
189
- $ hd scan sbom --dir=./my-project
207
+ ### Using the Docker Image (Recommended)
190
208
 
191
- $ hd scan sbom --file=path/to/sbom.json
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
- _See code: [src/commands/scan/sbom.ts](https://github.com/herodevs/cli/blob/v2.0.0-beta.1/src/commands/scan/sbom.ts)_
212
+ #### GitHub Actions
195
213
 
196
- ## `hd update [CHANNEL]`
214
+ ```yaml
215
+ ## .github/workflows/herodevs-eol-scan.yml
216
+ name: HeroDevs EOL Scan
197
217
 
198
- update the hd CLI
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
- FLAGS
205
- -a, --available See available versions.
206
- -b, --verbose Show more details about the available versions.
207
- -i, --interactive Interactively select version to install. This is ignored if a channel is provided.
208
- -v, --version=<value> Install a specific version.
209
- --force Force a re-download of the requested version.
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
- DESCRIPTION
212
- update the hd CLI
261
+ ### Using `npx` in CI
213
262
 
214
- EXAMPLES
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
- $ hd update stable
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
- Update to a specific version:
270
+ #### GitHub Actions
220
271
 
221
- $ hd update --version 1.0.0
272
+ ```yaml
273
+ ## .github/workflows/herodevs-eol-scan.yml
274
+ name: HeroDevs EOL Scan
222
275
 
223
- Interactively select version:
276
+ on:
277
+ push:
278
+ branches: [ main ]
279
+ pull_request:
280
+ branches: [ main ]
224
281
 
225
- $ hd update --interactive
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
- See available versions:
291
+ - run: echo # Prepare environment, install tooling, perform setup, etc.
228
292
 
229
- $ hd update --available
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
- _See code: [@oclif/plugin-update](https://github.com/oclif/plugin-update/blob/v4.6.39/src/commands/update.ts)_
233
- <!-- commandsstop -->
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 (error) {
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 -t
10
+ // If no arguments at all, default to scan:eol
11
11
  if (positionals.length === 0) {
12
- process.argv.splice(2, 0, 'scan:eol', '-t');
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 (error) {
24
+ } catch {
25
25
  process.exit(1);
26
26
  }
27
27
  }
package/bin/run.js CHANGED
@@ -4,6 +4,6 @@ import main from './main.js';
4
4
 
5
5
  try {
6
6
  await main(true);
7
- } catch (error) {
7
+ } catch {
8
8
  process.exit(1);
9
9
  }
@@ -0,0 +1,2 @@
1
+ export declare const createReportMutation: import("graphql/language/ast.js").DocumentNode;
2
+ export declare const getEolReportQuery: import("graphql/language/ast.js").DocumentNode;
@@ -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: string[];
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
- purls: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
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
- all: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
- table: import("@oclif/core/interfaces").BooleanFlag<boolean>;
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
- components: InsightsEolScanComponent[];
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 displayResultsInTable;
26
- private displayTable;
27
- private displayNoComponentsMessage;
28
- private logLine;
29
- private displayStatusSection;
30
- private logLegend;
28
+ private getSbomFromScan;
29
+ private getSbomFromFile;
31
30
  }