@soos-io/soos-sbom 0.1.3 → 0.1.8

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  SOOS is an independent software security company, located in Winooski, VT USA, building security software for your team. [SOOS, Software security, simplified](https://soos.io).
4
4
 
5
- Use SOOS to scan your software for [vulnerabilities](https://app.soos.io/research/vulnerabilities) and [open source license](https://app.soos.io/research/licenses) issues with [SOOS Core SCA](https://soos.io/sca-product). [Generate SBOMs](https://kb.soos.io/help/generating-a-software-bill-of-materials-sbom). Govern your open source dependencies. Run the [SOOS DAST vulnerability scanner](https://soos.io/dast-product) against your web apps or APIs.
5
+ Use SOOS to scan your software for [vulnerabilities](https://app.soos.io/research/vulnerabilities) and [open source license](https://app.soos.io/research/licenses) issues with [SOOS Core SCA](https://soos.io/products/sca). [Generate and ingest SBOMs](https://soos.io/products/sbom-manager). [Export reports](https://kb.soos.io/help/soos-reports-for-export) to industry standards. Govern your open source dependencies. Run the [SOOS DAST vulnerability scanner](https://soos.io/products/dast) against your web apps or APIs. [Scan your Docker containers](https://soos.io/products/containers) for vulnerabilities. Check your source code for issues with [SAST Analysis](https://soos.io/products/sast).
6
6
 
7
7
  [Demo SOOS](https://app.soos.io/demo) or [Register for a Free Trial](https://app.soos.io/register).
8
8
 
@@ -12,31 +12,31 @@ If you maintain an Open Source project, sign up for the Free as in Beer [SOOS Co
12
12
  - [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
13
13
 
14
14
  ## Installation
15
+
16
+ ### Globally
15
17
  run `npm i -g @soos-io/soos-sbom@latest`
18
+ Then Run `soos-sbom` from any terminal and add the parameters you want.
16
19
 
17
- ## Usage
18
- Run `soos-sbom` from any terminal and add the parameters you want.
20
+ ### Locally
21
+ run `npm install --prefix ./soos @soos-io/soos-sbom`
22
+ Then run from the same terminal `node ./soos/node_modules/@soos-io/soos-sbom/bin/index.js`
19
23
 
20
- ## Parameters
24
+ ## Client Parameters
21
25
 
22
26
 
23
27
  | Argument | Default | Description |
24
28
  | ----------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
25
- | `--apiKey` | `getEnvVariable(CONSTANTS.SOOS.API_KEY_ENV_VAR)` | SOOS API Key - get yours from [SOOS Integration](https://app.soos.io/integrate/sbom). |
26
- | `--apiURL` | `"https://api.soos.io/api/"` | SOOS API URL - Intended for internal use only, do not modify. |
27
- | `--appVersion` | N/A | App Version - Intended for internal use only. |
28
- | `--branchName` | `null` | The name of the branch from the SCM System. |
29
- | `--branchURI` | `null` | The URI to the branch from the SCM System. |
30
- | `--buildURI` | `null` | URI to CI build info. |
31
- | `--buildVersion` | `null` | Version of application build artifacts. |
32
- | `--clientId` | `getEnvVariable(CONSTANTS.SOOS.CLIENT_ID_ENV_VAR)` | SOOS Client ID - get yours from [SOOS Integration](https://app.soos.io/integrate/sbom). |
33
- | `--commitHash` | `null` | The commit hash value from the SCM System. |
34
- | `--integrationName` | N/A | Integration Name - Intended for internal use only. |
35
- | `--integrationType` | N/A | Integration Type - Intended for internal use only. |
36
- | `--logLevel` | `LogLevel.INFO` | Minimum level to show logs: PASS, IGNORE, INFO, WARN, or FAIL. |
37
- | `--operatingEnvironment`| `null` | Set Operating environment for information purposes only. |
38
- | `--otherOptions` | `null` | Other Options to pass to syft. |
39
- | `--projectName` | N/A | Project Name - this is what will be displayed in the SOOS app. |
40
- | `--scriptVersion` | N/A | Script Version - Intended for internal use only. |
29
+ | `--apiKey` | | SOOS API Key - get yours from [SOOS Integration](https://app.soos.io/integrate/sbom). Uses `SOOS_API_KEY` env value if present. |
30
+ | `--branchName` | | The name of the branch from the SCM System. |
31
+ | `--branchURI` | | The URI to the branch from the SCM System. |
32
+ | `--buildURI` | | URI to CI build info. |
33
+ | `--buildVersion` | | Version of application build artifacts. |
34
+ | `--clientId` | | SOOS Client ID - get yours from [SOOS Integration](https://app.soos.io/integrate/sbom). Uses `SOOS_API_CLIENT` env value if present. |
35
+ | `--commitHash` | | The commit hash value from the SCM System. |
36
+ | `--logLevel` | `INFO` | Minimum level to show logs: PASS, IGNORE, INFO, WARN, or FAIL. |
37
+ | `--onFailure` | `continue_on_failure` | Action to perform when the scan fails. Options: fail_the_build, continue_on_failure. |
38
+ | `--operatingEnvironment`| | Set Operating environment for information purposes only. |
39
+ | `--otherOptions` | | Other Options to pass to syft. |
40
+ | `--projectName` | | Project Name - this is what will be displayed in the SOOS app. |
41
41
  | `--verbose` | `false` | Enable verbose logging. |
42
- | `sbomPath` | N/A | The SBOM File to scan, it could be the location of the file or the file itself. When location is specified only the first file found will be scanned. |
42
+ | `sbomPath` | | The SBOM File to scan, it could be the location of the file or the file itself. When location is specified only the first file found will be scanned. |
@@ -0,0 +1,3 @@
1
+ export declare const SOOS_SBOM_CONSTANTS: {
2
+ FileRegex: RegExp;
3
+ };
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SOOS_SBOM_CONSTANTS = void 0;
4
+ exports.SOOS_SBOM_CONSTANTS = {
5
+ FileRegex: /\.(cdx|spdx)\.json$/,
6
+ };
package/bin/index.js CHANGED
@@ -4,208 +4,125 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const tslib_1 = require("tslib");
5
5
  const api_client_1 = require("@soos-io/api-client");
6
6
  const utilities_1 = require("@soos-io/api-client/dist/utilities");
7
- const argparse_1 = require("argparse");
8
7
  const FileSystem = tslib_1.__importStar(require("fs"));
9
8
  const Path = tslib_1.__importStar(require("path"));
10
- const form_data_1 = tslib_1.__importDefault(require("form-data"));
11
- const constants_1 = require("./utils/constants");
12
9
  const process_1 = require("process");
13
- const SOOSAnalysisApiClient_1 = tslib_1.__importDefault(require("@soos-io/api-client/dist/api/SOOSAnalysisApiClient"));
10
+ const AnalysisArgumentParser_1 = tslib_1.__importDefault(require("@soos-io/api-client/dist/services/AnalysisArgumentParser"));
11
+ const package_json_1 = require("../package.json");
12
+ const AnalysisService_1 = tslib_1.__importDefault(require("@soos-io/api-client/dist/services/AnalysisService"));
13
+ const constants_1 = require("./constants");
14
14
  class SOOSSBOMAnalysis {
15
15
  constructor(args) {
16
16
  this.args = args;
17
17
  }
18
18
  static parseArgs() {
19
- const parser = new argparse_1.ArgumentParser({ description: "SOOS SBOM" });
20
- parser.add_argument("--apiKey", {
21
- help: "SOOS API Key - get yours from https://app.soos.io/integrate/sbom",
22
- default: (0, utilities_1.getEnvVariable)(constants_1.CONSTANTS.SOOS.API_KEY_ENV_VAR),
23
- required: false,
24
- });
25
- parser.add_argument("--apiURL", {
26
- help: "SOOS API URL - Intended for internal use only, do not modify.",
27
- default: "https://api.soos.io/api/",
28
- required: false,
29
- type: (value) => {
30
- return (0, utilities_1.ensureNonEmptyValue)(value, "apiURL");
31
- },
32
- });
33
- parser.add_argument("--appVersion", {
34
- help: "App Version - Intended for internal use only.",
35
- required: false,
36
- });
37
- parser.add_argument("--branchName", {
38
- help: "The name of the branch from the SCM System.",
39
- default: null,
40
- required: false,
41
- });
42
- parser.add_argument("--branchURI", {
43
- help: "The URI to the branch from the SCM System.",
44
- default: null,
45
- required: false,
46
- });
47
- parser.add_argument("--buildURI", {
48
- help: "URI to CI build info.",
49
- default: null,
50
- required: false,
51
- });
52
- parser.add_argument("--buildVersion", {
53
- help: "Version of application build artifacts.",
54
- default: null,
55
- required: false,
56
- });
57
- parser.add_argument("--clientId", {
58
- help: "SOOS Client ID - get yours from https://app.soos.io/integrate/sbom",
59
- default: (0, utilities_1.getEnvVariable)(constants_1.CONSTANTS.SOOS.CLIENT_ID_ENV_VAR),
60
- required: false,
61
- });
62
- parser.add_argument("--commitHash", {
63
- help: "The commit hash value from the SCM System.",
64
- default: null,
65
- required: false,
66
- });
67
- parser.add_argument("--integrationName", {
68
- help: "Integration Name - Intended for internal use only.",
69
- required: false,
70
- });
71
- parser.add_argument("--integrationType", {
72
- help: "Integration Type - Intended for internal use only.",
73
- required: false,
74
- default: constants_1.CONSTANTS.SOOS.DEFAULT_INTEGRATION_TYPE,
75
- });
76
- parser.add_argument("--logLevel", {
77
- help: "Minimum level to show logs: PASS, IGNORE, INFO, WARN or FAIL.",
78
- default: api_client_1.LogLevel.INFO,
79
- required: false,
80
- type: (value) => {
81
- return (0, utilities_1.ensureEnumValue)(api_client_1.LogLevel, value);
82
- },
83
- });
84
- parser.add_argument("--operatingEnvironment", {
85
- help: "Set Operating environment for information purposes only.",
86
- default: null,
87
- required: false,
88
- });
89
- parser.add_argument("--projectName", {
90
- help: "Project Name - this is what will be displayed in the SOOS app.",
91
- required: true,
92
- type: (value) => {
93
- return (0, utilities_1.ensureNonEmptyValue)(value, "projectName");
94
- },
95
- });
96
- parser.add_argument("--scriptVersion", {
97
- help: "Script Version - Intended for internal use only.",
98
- required: false,
99
- });
100
- parser.add_argument("--verbose", {
101
- help: "Enable verbose logging.",
102
- action: "store_true",
103
- default: false,
104
- required: false,
105
- });
106
- parser.add_argument("sbomPath", {
19
+ const analysisArgumentParser = AnalysisArgumentParser_1.default.create(api_client_1.ScanType.SBOM);
20
+ analysisArgumentParser.addBaseScanArguments(api_client_1.IntegrationName.SoosSbom, api_client_1.IntegrationType.Script, package_json_1.version);
21
+ analysisArgumentParser.argumentParser.add_argument("sbomPath", {
107
22
  help: "The SBOM File to scan, it could be the location of the file or the file itself. When location is specified only the first file found will be scanned.",
108
23
  });
109
24
  api_client_1.soosLogger.info("Parsing arguments");
110
- return parser.parse_args();
25
+ return analysisArgumentParser.parseArguments();
111
26
  }
112
27
  async runAnalysis() {
28
+ const scanType = api_client_1.ScanType.SBOM;
29
+ const soosAnalysisService = AnalysisService_1.default.create(this.args.apiKey, this.args.apiURL);
113
30
  let projectHash;
114
31
  let branchHash;
115
32
  let analysisId;
116
- const filePath = await this.findSbomFilePath();
117
- const soosAnalysisApiClient = new SOOSAnalysisApiClient_1.default(this.args.apiKey, this.args.apiURL);
33
+ let scanStatusUrl;
34
+ const sbomFilePath = await this.findSbomFilePath();
118
35
  try {
119
- api_client_1.soosLogger.info("Starting SOOS SBOM Analysis");
120
- api_client_1.soosLogger.info(`Creating scan for project '${this.args.projectName}'...`);
121
- api_client_1.soosLogger.info(`Branch Name: ${this.args.branchName}`);
122
- const result = await soosAnalysisApiClient.createScan({
36
+ const result = await soosAnalysisService.setupScan({
123
37
  clientId: this.args.clientId,
124
38
  projectName: this.args.projectName,
39
+ branchName: this.args.branchName,
125
40
  commitHash: this.args.commitHash,
126
- branch: this.args.branchName,
127
41
  buildVersion: this.args.buildVersion,
128
- buildUri: this.args.buildUri,
129
- branchUri: this.args.branchUri,
130
- integrationType: this.args.integrationType,
42
+ buildUri: this.args.buildURI,
43
+ branchUri: this.args.branchURI,
131
44
  operatingEnvironment: this.args.operatingEnvironment,
132
45
  integrationName: this.args.integrationName,
46
+ integrationType: this.args.integrationType,
133
47
  appVersion: this.args.appVersion,
134
- scriptVersion: null,
135
- contributingDeveloperAudit: undefined,
136
- scanType: api_client_1.ScanType.SBOM,
137
- toolName: null,
138
- toolVersion: null,
48
+ scriptVersion: this.args.scriptVersion,
49
+ contributingDeveloperAudit: !this.args.contributingDeveloperId ||
50
+ !this.args.contributingDeveloperSource ||
51
+ !this.args.contributingDeveloperSourceName
52
+ ? []
53
+ : [
54
+ {
55
+ contributingDeveloperId: this.args.contributingDeveloperId,
56
+ source: this.args.contributingDeveloperSource,
57
+ sourceName: this.args.contributingDeveloperSourceName,
58
+ },
59
+ ],
60
+ scanType,
61
+ toolName: undefined,
62
+ toolVersion: undefined,
139
63
  });
140
64
  projectHash = result.projectHash;
141
65
  branchHash = result.branchHash;
142
66
  analysisId = result.analysisId;
143
- api_client_1.soosLogger.info(`Project Hash: ${projectHash}`);
144
- api_client_1.soosLogger.info(`Branch Hash: ${branchHash}`);
145
- api_client_1.soosLogger.info(`Scan Id: ${analysisId}`);
146
- api_client_1.soosLogger.info("Scan created successfully.");
67
+ scanStatusUrl = result.scanStatusUrl;
147
68
  api_client_1.soosLogger.logLineSeparator();
148
- api_client_1.soosLogger.info("Uploading SBOM File");
149
- const formData = await this.getSbomAsFormData(filePath);
150
- const uploadManifestFilesResponse = await soosAnalysisApiClient.uploadManifestFiles({
69
+ api_client_1.soosLogger.info("Uploading SBOM File...");
70
+ const formData = await soosAnalysisService.getAnalysisFilesAsFormData([sbomFilePath], this.args.sbomPath);
71
+ const manifestUploadResponse = await soosAnalysisService.analysisApiClient.uploadManifestFiles({
151
72
  clientId: this.args.clientId,
152
73
  projectHash,
153
74
  branchHash,
154
75
  analysisId,
155
76
  manifestFiles: formData,
77
+ hasMoreThanMaximumManifests: false,
156
78
  });
157
- api_client_1.soosLogger.info(` SBOM Files: \n`, ` ${uploadManifestFilesResponse.message} \n`, uploadManifestFilesResponse.manifests
158
- ?.map((m) => ` ${m.name}: ${m.statusMessage}`)
159
- .join("\n"));
79
+ api_client_1.soosLogger.info(` SBOM Files: \n`, ` ${manifestUploadResponse.message} \n`, manifestUploadResponse.manifests?.map((m) => ` ${m.name}: ${m.statusMessage}`).join("\n"));
160
80
  api_client_1.soosLogger.logLineSeparator();
161
- api_client_1.soosLogger.info("Starting SBOM Analysis scan");
162
- await soosAnalysisApiClient.startScan({
81
+ await soosAnalysisService.startScan({
163
82
  clientId: this.args.clientId,
164
83
  projectHash,
165
- analysisId: analysisId,
84
+ analysisId,
85
+ scanType,
86
+ scanUrl: result.scanUrl,
87
+ });
88
+ const scanStatus = await soosAnalysisService.waitForScanToFinish({
89
+ scanStatusUrl: result.scanStatusUrl,
90
+ scanUrl: result.scanUrl,
91
+ scanType,
166
92
  });
167
- api_client_1.soosLogger.info(`Analysis scan started successfully, to see the results visit: ${result.scanUrl}`);
93
+ const exitCodeWithMessage = (0, utilities_1.getAnalysisExitCodeWithMessage)(scanStatus, this.args.integrationName, this.args.onFailure);
94
+ api_client_1.soosLogger.always(`${exitCodeWithMessage.message} - exit ${exitCodeWithMessage.exitCode}`);
95
+ (0, process_1.exit)(exitCodeWithMessage.exitCode);
168
96
  }
169
97
  catch (error) {
170
- if (projectHash && branchHash && analysisId)
171
- await soosAnalysisApiClient.updateScanStatus({
98
+ if (projectHash && branchHash && analysisId) {
99
+ await soosAnalysisService.updateScanStatus({
172
100
  clientId: this.args.clientId,
173
101
  projectHash,
174
102
  branchHash,
175
- scanType: api_client_1.ScanType.SBOM,
176
- scanId: analysisId,
103
+ scanType,
104
+ analysisId: analysisId,
177
105
  status: api_client_1.ScanStatus.Error,
178
- message: `Error while performing scan.`,
106
+ message: "Error while performing scan.",
107
+ scanStatusUrl,
179
108
  });
109
+ }
180
110
  api_client_1.soosLogger.error(error);
111
+ api_client_1.soosLogger.always(`${error} - exit 1`);
181
112
  (0, process_1.exit)(1);
182
113
  }
183
114
  }
184
- async getSbomAsFormData(filePath) {
185
- try {
186
- const fileReadStream = FileSystem.createReadStream(filePath, {
187
- encoding: api_client_1.SOOS_CONSTANTS.FileUploads.Encoding,
188
- });
189
- const formData = new form_data_1.default();
190
- formData.append("file", fileReadStream);
191
- return formData;
192
- }
193
- catch (error) {
194
- api_client_1.soosLogger.error(`Error on getSbomAsFormData: ${error}`);
195
- throw error;
196
- }
197
- }
198
115
  async findSbomFilePath() {
199
116
  const sbomPathStat = await FileSystem.statSync(this.args.sbomPath);
200
117
  if (sbomPathStat.isDirectory()) {
201
118
  const files = await FileSystem.promises.readdir(this.args.sbomPath);
202
- const sbomFile = files.find((file) => constants_1.CONSTANTS.SBOM.FILE_REGEX.test(file));
119
+ const sbomFile = files.find((file) => constants_1.SOOS_SBOM_CONSTANTS.FileRegex.test(file));
203
120
  if (!sbomFile) {
204
121
  throw new Error("No SBOM file found in the directory.");
205
122
  }
206
123
  return Path.join(this.args.sbomPath, sbomFile);
207
124
  }
208
- if (!constants_1.CONSTANTS.SBOM.FILE_REGEX.test(this.args.sbomPath)) {
125
+ if (!constants_1.SOOS_SBOM_CONSTANTS.FileRegex.test(this.args.sbomPath)) {
209
126
  throw new Error("The file does not match the required SBOM pattern.");
210
127
  }
211
128
  return this.args.sbomPath;
@@ -219,14 +136,13 @@ class SOOSSBOMAnalysis {
219
136
  api_client_1.soosLogger.setVerbose(args.verbose);
220
137
  api_client_1.soosLogger.info("Configuration read");
221
138
  api_client_1.soosLogger.verboseDebug(JSON.stringify((0, utilities_1.obfuscateProperties)(args, ["apiKey"]), null, 2));
222
- (0, utilities_1.ensureNonEmptyValue)(args.clientId, "clientId");
223
- (0, utilities_1.ensureNonEmptyValue)(args.apiKey, "apiKey");
224
139
  api_client_1.soosLogger.logLineSeparator();
225
140
  const soosSBOMAnalysis = new SOOSSBOMAnalysis(args);
226
141
  await soosSBOMAnalysis.runAnalysis();
227
142
  }
228
143
  catch (error) {
229
144
  api_client_1.soosLogger.error(`Error on createAndRun: ${error}`);
145
+ api_client_1.soosLogger.always(`Error on createAndRun: ${error} - exit 1`);
230
146
  (0, process_1.exit)(1);
231
147
  }
232
148
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@soos-io/soos-sbom",
3
- "version": "0.1.3",
4
- "description": "SOOS wrapper script to upload sboms.",
3
+ "version": "0.1.8",
4
+ "description": "SOOS wrapper script to upload SBOMs.",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
7
7
  "setup:install": "npm install",
@@ -13,23 +13,32 @@
13
13
  "format": "prettier ./src --check",
14
14
  "format:fix": "prettier ./src --write",
15
15
  "typecheck": "tsc --noEmit",
16
- "check": "npm run format && npm run typecheck && npm outdated"
16
+ "check": "npm run format && npm run typecheck && npm outdated",
17
+ "patch-api-client": "npm version patch --no-git-tag-version && npm run setup:clean && npm install @soos-io/api-client@latest --save-exact && npm install && npm run check"
17
18
  },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/soos-io/soos-sbom.git"
22
+ },
23
+ "author": "SOOS",
24
+ "license": "MIT",
25
+ "bugs": {
26
+ "url": "https://github.com/soos-io/soos-sbom/issues"
27
+ },
28
+ "homepage": "https://github.com/soos-io/soos-sbom#readme",
18
29
  "dependencies": {
19
- "@soos-io/api-client": "0.1.8",
30
+ "@soos-io/api-client": "0.2.26",
20
31
  "argparse": "^2.0.1",
32
+ "glob": "^10.3.10",
21
33
  "tslib": "^2.6.2"
22
34
  },
23
35
  "devDependencies": {
24
- "@types/argparse": "^2.0.11",
25
- "@types/glob": "^8.1.0",
26
- "@types/node": "^20.6.3",
27
- "prettier": "^2.8.8",
28
- "typescript": "^5.2.2"
36
+ "@types/argparse": "^2.0.14",
37
+ "@types/node": "^20.10.5",
38
+ "prettier": "^3.1.1",
39
+ "typescript": "^5.3.3"
29
40
  },
30
41
  "bin": {
31
42
  "soos-sbom": "bin/index.js"
32
- },
33
- "author": "SOOS",
34
- "license": "MIT"
43
+ }
35
44
  }
@@ -1,10 +0,0 @@
1
- export declare const CONSTANTS: {
2
- SBOM: {
3
- FILE_REGEX: RegExp;
4
- };
5
- SOOS: {
6
- API_KEY_ENV_VAR: string;
7
- CLIENT_ID_ENV_VAR: string;
8
- DEFAULT_INTEGRATION_TYPE: string;
9
- };
10
- };
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CONSTANTS = void 0;
4
- exports.CONSTANTS = {
5
- SBOM: {
6
- FILE_REGEX: /\.(cdx|spdx)\.json$/,
7
- },
8
- SOOS: {
9
- API_KEY_ENV_VAR: "SOOS_API_KEY",
10
- CLIENT_ID_ENV_VAR: "SOOS_CLIENT_ID",
11
- DEFAULT_INTEGRATION_TYPE: "Script",
12
- },
13
- };