@soos-io/soos-sbom 1.2.12 → 1.3.0-pre.1

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 (2) hide show
  1. package/bin/index.js +183 -193
  2. package/package.json +8 -5
package/bin/index.js CHANGED
@@ -13,211 +13,201 @@ const AnalysisService_1 = tslib_1.__importDefault(require("@soos-io/api-client/d
13
13
  const constants_1 = require("./constants");
14
14
  const utilities_2 = require("./utilities");
15
15
  const Glob = tslib_1.__importStar(require("glob"));
16
- class SOOSSBOMAnalysis {
17
- args;
18
- constructor(args) {
19
- this.args = args;
20
- }
21
- static parseArgs() {
22
- const analysisArgumentParser = AnalysisArgumentParser_1.default.create(api_client_1.IntegrationName.SoosSbom, api_client_1.IntegrationType.Script, api_client_1.ScanType.SBOM, package_json_1.version);
23
- analysisArgumentParser.addArgument("directoriesToExclude", "Listing of directories or patterns to exclude from the search for SBOM files. eg: **bin/start/**, **/start/**", {
24
- argParser: (value) => {
25
- return (0, utilities_2.removeDuplicates)(value.split(",").map((pattern) => pattern.trim()));
26
- },
27
- defaultValue: constants_1.SOOS_SBOM_CONSTANTS.DefaultDirectoriesToExclude,
28
- });
29
- analysisArgumentParser.addArgument("filesToExclude", "Listing of files or patterns patterns to exclude from the search for SBOM files. eg: **/int**.cdx.json/, **/internal.cdx.json", {
30
- argParser: (value) => {
31
- return (0, utilities_2.removeDuplicates)(value.split(",").map((pattern) => pattern.trim()));
32
- },
33
- defaultValue: [],
16
+ const parseArgs = () => {
17
+ const analysisArgumentParser = AnalysisArgumentParser_1.default.create(api_client_1.IntegrationName.SoosSbom, api_client_1.IntegrationType.Script, api_client_1.ScanType.SBOM, package_json_1.version);
18
+ analysisArgumentParser.addArgument("directoriesToExclude", "Listing of directories or patterns to exclude from the search for SBOM files. eg: **bin/start/**, **/start/**", {
19
+ argParser: (value) => {
20
+ return (0, utilities_2.removeDuplicates)(value.split(",").map((pattern) => pattern.trim()));
21
+ },
22
+ defaultValue: constants_1.SOOS_SBOM_CONSTANTS.DefaultDirectoriesToExclude,
23
+ });
24
+ analysisArgumentParser.addArgument("filesToExclude", "Listing of files or patterns patterns to exclude from the search for SBOM files. eg: **/int**.cdx.json/, **/internal.cdx.json", {
25
+ argParser: (value) => {
26
+ return (0, utilities_2.removeDuplicates)(value.split(",").map((pattern) => pattern.trim()));
27
+ },
28
+ defaultValue: [],
29
+ });
30
+ analysisArgumentParser.addArgument("sbomPath", "The SBOM file or folder to scan. When a folder is specified all SBOMs found in the folder and sub-folders will be scanned.", { useNoOptionKey: true });
31
+ analysisArgumentParser.addArgument("outputDirectory", "Absolute path where SOOS will write exported reports and SBOMs. eg Correct: /out/sbom/ | Incorrect: ./out/sbom/", {
32
+ defaultValue: process.cwd(),
33
+ });
34
+ return analysisArgumentParser.parseArguments();
35
+ };
36
+ const findSbomFilePaths = async (args) => {
37
+ const sbomPathStat = FileSystem.statSync(args.sbomPath);
38
+ if (sbomPathStat.isDirectory()) {
39
+ const searchPattern = args.sbomPath.endsWith("/") || args.sbomPath.endsWith("\\")
40
+ ? `${args.sbomPath}${constants_1.SOOS_SBOM_CONSTANTS.FilePattern}`
41
+ : `${args.sbomPath}/${constants_1.SOOS_SBOM_CONSTANTS.FilePattern}`;
42
+ let sbomFilePaths = Glob.sync(searchPattern, {
43
+ ignore: [
44
+ ...args.filesToExclude,
45
+ ...args.directoriesToExclude,
46
+ constants_1.SOOS_SBOM_CONSTANTS.SoosDirectoryToExclude,
47
+ ],
48
+ nocase: true,
34
49
  });
35
- analysisArgumentParser.addArgument("sbomPath", "The SBOM file or folder to scan. When a folder is specified all SBOMs found in the folder and sub-folders will be scanned.", { useNoOptionKey: true });
36
- analysisArgumentParser.addArgument("outputDirectory", "Absolute path where SOOS will write exported reports and SBOMs. eg Correct: /out/sbom/ | Incorrect: ./out/sbom/", {
37
- defaultValue: process.cwd(),
38
- });
39
- return analysisArgumentParser.parseArguments();
50
+ const hasMoreThanMaximumManifests = sbomFilePaths.length > constants_1.SOOS_SBOM_CONSTANTS.MaxSbomsPerScan;
51
+ if (hasMoreThanMaximumManifests) {
52
+ const filesToSkip = sbomFilePaths.slice(constants_1.SOOS_SBOM_CONSTANTS.MaxSbomsPerScan);
53
+ sbomFilePaths = sbomFilePaths.slice(0, constants_1.SOOS_SBOM_CONSTANTS.MaxSbomsPerScan);
54
+ const filesDetectedString = utilities_1.StringUtilities.pluralizeTemplate(sbomFilePaths.length, "file was", "files were");
55
+ const filesSkippedString = utilities_1.StringUtilities.pluralizeTemplate(filesToSkip.length, "file");
56
+ api_client_1.soosLogger.info(`The maximum number of SBOMs per scan is ${constants_1.SOOS_SBOM_CONSTANTS.MaxSbomsPerScan}. ${filesDetectedString} detected, and ${filesSkippedString} will be not be uploaded. \n`, `The following SBOMs will not be included in the scan: \n`, filesToSkip.map((file) => ` "${Path.parse(file).base}": "${file}"`).join("\n"));
57
+ }
58
+ return { sbomFilePaths, hasMoreThanMaximumManifests };
40
59
  }
41
- async runAnalysis() {
42
- const scanType = api_client_1.ScanType.SBOM;
43
- const soosAnalysisService = AnalysisService_1.default.create(this.args.apiKey, this.args.apiURL);
44
- let projectHash;
45
- let branchHash;
46
- let analysisId;
47
- let scanStatusUrl;
48
- let scanStatus;
49
- try {
50
- const result = await soosAnalysisService.setupScan({
51
- clientId: this.args.clientId,
52
- projectName: this.args.projectName,
53
- branchName: this.args.branchName,
54
- commitHash: this.args.commitHash,
55
- buildVersion: this.args.buildVersion,
56
- buildUri: this.args.buildURI,
57
- branchUri: this.args.branchURI,
58
- operatingEnvironment: this.args.operatingEnvironment,
59
- integrationName: this.args.integrationName,
60
- integrationType: this.args.integrationType,
61
- appVersion: this.args.appVersion,
62
- scriptVersion: this.args.scriptVersion,
63
- contributingDeveloperAudit: [
64
- {
65
- contributingDeveloperId: this.args.contributingDeveloperId,
66
- source: this.args.contributingDeveloperSource,
67
- sourceName: this.args.contributingDeveloperSourceName,
68
- },
69
- ],
60
+ return { sbomFilePaths: [args.sbomPath], hasMoreThanMaximumManifests: false };
61
+ };
62
+ const runAnalysis = async (args) => {
63
+ const scanType = api_client_1.ScanType.SBOM;
64
+ const soosAnalysisService = AnalysisService_1.default.create(args.apiKey, args.apiURL);
65
+ let projectHash;
66
+ let branchHash;
67
+ let analysisId;
68
+ let scanStatusUrl;
69
+ let scanStatus;
70
+ try {
71
+ const result = await soosAnalysisService.setupScan({
72
+ clientId: args.clientId,
73
+ projectName: args.projectName,
74
+ branchName: args.branchName,
75
+ commitHash: args.commitHash,
76
+ buildVersion: args.buildVersion,
77
+ buildUri: args.buildURI,
78
+ branchUri: args.branchURI,
79
+ operatingEnvironment: args.operatingEnvironment,
80
+ integrationName: args.integrationName,
81
+ integrationType: args.integrationType,
82
+ appVersion: args.appVersion,
83
+ scriptVersion: args.scriptVersion,
84
+ contributingDeveloperAudit: [
85
+ {
86
+ contributingDeveloperId: args.contributingDeveloperId,
87
+ source: args.contributingDeveloperSource,
88
+ sourceName: args.contributingDeveloperSourceName,
89
+ },
90
+ ],
91
+ scanType,
92
+ commandLine: process.argv.length > 2
93
+ ? (0, utilities_1.obfuscateCommandLine)((0, utilities_1.reassembleCommandLine)(process.argv.slice(2)), constants_1.SOOS_SBOM_CONSTANTS.ObfuscatedArguments.map((a) => `--${a}`))
94
+ : null,
95
+ });
96
+ projectHash = result.projectHash;
97
+ branchHash = result.branchHash;
98
+ analysisId = result.analysisId;
99
+ scanStatusUrl = result.scanStatusUrl;
100
+ const { sbomFilePaths, hasMoreThanMaximumManifests } = await findSbomFilePaths(args);
101
+ if (sbomFilePaths.length === 0) {
102
+ const noFilesMessage = `No SBOM files found. They need to match the pattern ${constants_1.SOOS_SBOM_CONSTANTS.FilePattern}. See https://kb.soos.io/getting-started-with-soos-sbom-manager for more information.`;
103
+ await soosAnalysisService.updateScanStatus({
104
+ analysisId,
105
+ clientId: args.clientId,
106
+ projectHash,
107
+ branchHash,
70
108
  scanType,
71
- commandLine: process.argv.length > 2
72
- ? (0, utilities_1.obfuscateCommandLine)((0, utilities_1.reassembleCommandLine)(process.argv.slice(2)), constants_1.SOOS_SBOM_CONSTANTS.ObfuscatedArguments.map((a) => `--${a}`))
73
- : null,
109
+ status: api_client_1.ScanStatus.NoFiles,
110
+ message: noFilesMessage,
111
+ scanStatusUrl,
74
112
  });
75
- projectHash = result.projectHash;
76
- branchHash = result.branchHash;
77
- analysisId = result.analysisId;
78
- scanStatusUrl = result.scanStatusUrl;
79
- const { sbomFilePaths, hasMoreThanMaximumManifests } = await this.findSbomFilePaths();
80
- if (sbomFilePaths.length === 0) {
81
- const noFilesMessage = `No SBOM files found. They need to match the pattern ${constants_1.SOOS_SBOM_CONSTANTS.FilePattern}. See https://kb.soos.io/getting-started-with-soos-sbom-manager for more information.`;
82
- await soosAnalysisService.updateScanStatus({
83
- analysisId,
84
- clientId: this.args.clientId,
85
- projectHash,
86
- branchHash,
87
- scanType,
88
- status: api_client_1.ScanStatus.NoFiles,
89
- message: noFilesMessage,
90
- scanStatusUrl,
91
- });
92
- api_client_1.soosLogger.error(noFilesMessage);
93
- api_client_1.soosLogger.always(`${noFilesMessage} - exit 1`);
94
- (0, process_1.exit)(1);
95
- }
96
- if (sbomFilePaths.length === 1 &&
97
- sbomFilePaths[0] === this.args.sbomPath &&
98
- !constants_1.SOOS_SBOM_CONSTANTS.FileRegex.test(sbomFilePaths[0])) {
99
- const noFilesMessage = `The file does not match the required SBOM pattern ${constants_1.SOOS_SBOM_CONSTANTS.FilePattern}. See https://kb.soos.io/getting-started-with-soos-sbom-manager for more information.`;
100
- await soosAnalysisService.updateScanStatus({
101
- analysisId,
102
- clientId: this.args.clientId,
103
- projectHash,
104
- branchHash,
105
- scanType,
106
- status: api_client_1.ScanStatus.NoFiles,
107
- message: noFilesMessage,
108
- scanStatusUrl,
109
- });
110
- api_client_1.soosLogger.error(noFilesMessage);
111
- api_client_1.soosLogger.always(`${noFilesMessage} - exit 1`);
112
- (0, process_1.exit)(1);
113
- }
114
- api_client_1.soosLogger.info("Uploading SBOM File(s)...");
115
- for (let i = 0; i < sbomFilePaths.length; i += constants_1.SOOS_SBOM_CONSTANTS.UploadBatchSize) {
116
- const sbomFilePathsBatch = sbomFilePaths.slice(i, i + constants_1.SOOS_SBOM_CONSTANTS.UploadBatchSize);
117
- const formData = await soosAnalysisService.getAnalysisFilesAsFormData(sbomFilePathsBatch, this.args.sbomPath);
118
- const manifestUploadResponse = await soosAnalysisService.analysisApiClient.uploadManifestFiles({
119
- clientId: this.args.clientId,
120
- projectHash,
121
- branchHash,
122
- analysisId,
123
- manifestFiles: formData,
124
- hasMoreThanMaximumManifests,
125
- });
126
- api_client_1.soosLogger.info(` SBOM File(s): \n`, ` ${manifestUploadResponse.message} \n`, manifestUploadResponse.manifests
127
- ?.map((m) => ` ${m.name}: ${m.statusMessage}`)
128
- .join("\n"));
129
- }
130
- await soosAnalysisService.startScan({
131
- clientId: this.args.clientId,
132
- projectHash,
113
+ api_client_1.soosLogger.error(noFilesMessage);
114
+ api_client_1.soosLogger.always(`${noFilesMessage} - exit 1`);
115
+ (0, process_1.exit)(1);
116
+ }
117
+ if (sbomFilePaths.length === 1 &&
118
+ sbomFilePaths[0] === args.sbomPath &&
119
+ !constants_1.SOOS_SBOM_CONSTANTS.FileRegex.test(sbomFilePaths[0])) {
120
+ const noFilesMessage = `The file does not match the required SBOM pattern ${constants_1.SOOS_SBOM_CONSTANTS.FilePattern}. See https://kb.soos.io/getting-started-with-soos-sbom-manager for more information.`;
121
+ await soosAnalysisService.updateScanStatus({
133
122
  analysisId,
123
+ clientId: args.clientId,
124
+ projectHash,
125
+ branchHash,
134
126
  scanType,
135
- scanUrl: result.scanUrl,
127
+ status: api_client_1.ScanStatus.NoFiles,
128
+ message: noFilesMessage,
129
+ scanStatusUrl,
136
130
  });
137
- scanStatus = await soosAnalysisService.waitForScanToFinish({
138
- scanStatusUrl: result.scanStatusUrl,
139
- scanUrl: result.scanUrl,
140
- scanType,
131
+ api_client_1.soosLogger.error(noFilesMessage);
132
+ api_client_1.soosLogger.always(`${noFilesMessage} - exit 1`);
133
+ (0, process_1.exit)(1);
134
+ }
135
+ api_client_1.soosLogger.info("Uploading SBOM File(s)...");
136
+ for (let i = 0; i < sbomFilePaths.length; i += constants_1.SOOS_SBOM_CONSTANTS.UploadBatchSize) {
137
+ const sbomFilePathsBatch = sbomFilePaths.slice(i, i + constants_1.SOOS_SBOM_CONSTANTS.UploadBatchSize);
138
+ const formData = await soosAnalysisService.getAnalysisFilesAsFormData(sbomFilePathsBatch, args.sbomPath);
139
+ const manifestUploadResponse = await soosAnalysisService.analysisApiClient.uploadManifestFiles({
140
+ clientId: args.clientId,
141
+ projectHash,
142
+ branchHash,
143
+ analysisId,
144
+ manifestFiles: formData,
145
+ hasMoreThanMaximumManifests,
141
146
  });
142
- if ((0, utilities_1.isScanDone)(scanStatus) &&
143
- this.args.exportFormat !== api_client_1.AttributionFormatEnum.Unknown &&
144
- this.args.exportFileType !== api_client_1.AttributionFileTypeEnum.Unknown) {
145
- await soosAnalysisService.generateFormattedOutput({
146
- clientId: this.args.clientId,
147
- projectHash: result.projectHash,
148
- projectName: this.args.projectName,
149
- branchHash: result.branchHash,
150
- analysisId: result.analysisId,
151
- format: this.args.exportFormat,
152
- fileType: this.args.exportFileType,
153
- includeDependentProjects: false,
154
- includeOriginalSbom: false,
155
- includeVulnerabilities: false,
156
- workingDirectory: this.args.outputDirectory,
157
- });
158
- }
159
- const exitCodeWithMessage = (0, utilities_1.getAnalysisExitCodeWithMessage)(scanStatus, this.args.integrationName, this.args.onFailure);
160
- api_client_1.soosLogger.always(`${exitCodeWithMessage.message} - exit ${exitCodeWithMessage.exitCode}`);
161
- (0, process_1.exit)(exitCodeWithMessage.exitCode);
147
+ api_client_1.soosLogger.info(` SBOM File(s): \n`, ` ${manifestUploadResponse.message} \n`, manifestUploadResponse.manifests?.map((m) => ` ${m.name}: ${m.statusMessage}`).join("\n"));
162
148
  }
163
- catch (error) {
164
- if (projectHash && branchHash && analysisId && (!scanStatus || !(0, utilities_1.isScanDone)(scanStatus))) {
165
- await soosAnalysisService.updateScanStatus({
166
- clientId: this.args.clientId,
167
- projectHash,
168
- branchHash,
169
- scanType,
170
- analysisId: analysisId,
171
- status: api_client_1.ScanStatus.Error,
172
- message: "Error while performing scan.",
173
- scanStatusUrl,
174
- });
175
- }
176
- api_client_1.soosLogger.error(error);
177
- api_client_1.soosLogger.always(`${error} - exit 1`);
178
- (0, process_1.exit)(1);
149
+ await soosAnalysisService.startScan({
150
+ clientId: args.clientId,
151
+ projectHash,
152
+ analysisId,
153
+ scanType,
154
+ scanUrl: result.scanUrl,
155
+ });
156
+ scanStatus = await soosAnalysisService.waitForScanToFinish({
157
+ scanStatusUrl: result.scanStatusUrl,
158
+ scanUrl: result.scanUrl,
159
+ scanType,
160
+ });
161
+ if ((0, utilities_1.isScanDone)(scanStatus) &&
162
+ args.exportFormat !== api_client_1.AttributionFormatEnum.Unknown &&
163
+ args.exportFileType !== api_client_1.AttributionFileTypeEnum.Unknown) {
164
+ await soosAnalysisService.generateFormattedOutput({
165
+ clientId: args.clientId,
166
+ projectHash: result.projectHash,
167
+ projectName: args.projectName,
168
+ branchHash: result.branchHash,
169
+ analysisId: result.analysisId,
170
+ format: args.exportFormat,
171
+ fileType: args.exportFileType,
172
+ includeDependentProjects: false,
173
+ includeOriginalSbom: false,
174
+ includeVulnerabilities: false,
175
+ workingDirectory: args.outputDirectory,
176
+ });
179
177
  }
178
+ const exitCodeWithMessage = (0, utilities_1.getAnalysisExitCodeWithMessage)(scanStatus, args.integrationName, args.onFailure);
179
+ api_client_1.soosLogger.always(`${exitCodeWithMessage.message} - exit ${exitCodeWithMessage.exitCode}`);
180
+ (0, process_1.exit)(exitCodeWithMessage.exitCode);
180
181
  }
181
- async findSbomFilePaths() {
182
- const sbomPathStat = await FileSystem.statSync(this.args.sbomPath);
183
- if (sbomPathStat.isDirectory()) {
184
- const searchPattern = this.args.sbomPath.endsWith("/") || this.args.sbomPath.endsWith("\\")
185
- ? `${this.args.sbomPath}${constants_1.SOOS_SBOM_CONSTANTS.FilePattern}`
186
- : `${this.args.sbomPath}/${constants_1.SOOS_SBOM_CONSTANTS.FilePattern}`;
187
- let sbomFilePaths = Glob.sync(searchPattern, {
188
- ignore: [
189
- ...this.args.filesToExclude,
190
- ...this.args.directoriesToExclude,
191
- constants_1.SOOS_SBOM_CONSTANTS.SoosDirectoryToExclude,
192
- ],
193
- nocase: true,
182
+ catch (error) {
183
+ if (projectHash && branchHash && analysisId && (!scanStatus || !(0, utilities_1.isScanDone)(scanStatus))) {
184
+ await soosAnalysisService.updateScanStatus({
185
+ clientId: args.clientId,
186
+ projectHash,
187
+ branchHash,
188
+ scanType,
189
+ analysisId: analysisId,
190
+ status: api_client_1.ScanStatus.Error,
191
+ message: "Error while performing scan.",
192
+ scanStatusUrl,
194
193
  });
195
- const hasMoreThanMaximumManifests = sbomFilePaths.length > constants_1.SOOS_SBOM_CONSTANTS.MaxSbomsPerScan;
196
- if (hasMoreThanMaximumManifests) {
197
- const filesToSkip = sbomFilePaths.slice(constants_1.SOOS_SBOM_CONSTANTS.MaxSbomsPerScan);
198
- sbomFilePaths = sbomFilePaths.slice(0, constants_1.SOOS_SBOM_CONSTANTS.MaxSbomsPerScan);
199
- const filesDetectedString = utilities_1.StringUtilities.pluralizeTemplate(sbomFilePaths.length, "file was", "files were");
200
- const filesSkippedString = utilities_1.StringUtilities.pluralizeTemplate(filesToSkip.length, "file");
201
- api_client_1.soosLogger.info(`The maximum number of SBOMs per scan is ${constants_1.SOOS_SBOM_CONSTANTS.MaxSbomsPerScan}. ${filesDetectedString} detected, and ${filesSkippedString} will be not be uploaded. \n`, `The following SBOMs will not be included in the scan: \n`, filesToSkip.map((file) => ` "${Path.parse(file).base}": "${file}"`).join("\n"));
202
- }
203
- return { sbomFilePaths, hasMoreThanMaximumManifests };
204
194
  }
205
- return { sbomFilePaths: [this.args.sbomPath], hasMoreThanMaximumManifests: false };
195
+ api_client_1.soosLogger.error(error);
196
+ api_client_1.soosLogger.always(`${error} - exit 1`);
197
+ (0, process_1.exit)(1);
206
198
  }
207
- static async createAndRun() {
208
- try {
209
- const args = this.parseArgs();
210
- api_client_1.soosLogger.setMinLogLevel(args.logLevel);
211
- api_client_1.soosLogger.always("Starting SOOS SBOM Analysis");
212
- api_client_1.soosLogger.debug(JSON.stringify((0, utilities_1.obfuscateProperties)(args, ["apiKey"]), null, 2));
213
- const soosSBOMAnalysis = new SOOSSBOMAnalysis(args);
214
- await soosSBOMAnalysis.runAnalysis();
215
- }
216
- catch (error) {
217
- api_client_1.soosLogger.error(`Error on createAndRun: ${error}`);
218
- api_client_1.soosLogger.always(`Error on createAndRun: ${error} - exit 1`);
219
- (0, process_1.exit)(1);
220
- }
199
+ };
200
+ (async () => {
201
+ try {
202
+ const args = parseArgs();
203
+ api_client_1.soosLogger.setMinLogLevel(args.logLevel);
204
+ api_client_1.soosLogger.always("Starting SOOS SBOM Analysis");
205
+ api_client_1.soosLogger.debug(JSON.stringify((0, utilities_1.obfuscateProperties)(args, ["apiKey"]), null, 2));
206
+ await runAnalysis(args);
207
+ }
208
+ catch (error) {
209
+ api_client_1.soosLogger.error(`Error on createAndRun: ${error}`);
210
+ api_client_1.soosLogger.always(`Error on createAndRun: ${error} - exit 1`);
211
+ (0, process_1.exit)(1);
221
212
  }
222
- }
223
- SOOSSBOMAnalysis.createAndRun();
213
+ })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soos-io/soos-sbom",
3
- "version": "1.2.12",
3
+ "version": "1.3.0-pre.1",
4
4
  "description": "Upload your Software Bill of Materials (SBOM) to SOOS for vulnerability analysis, license matching and more. Register for a free trial today at https://app.soos.io/register",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -42,14 +42,17 @@
42
42
  },
43
43
  "homepage": "https://github.com/soos-io/soos-sbom#readme",
44
44
  "dependencies": {
45
- "@soos-io/api-client": "1.10.1",
45
+ "@soos-io/api-client": "1.10.2",
46
46
  "tslib": "^2.6.3"
47
47
  },
48
+ "overrides": {
49
+ "minimatch": "^10.2.2"
50
+ },
48
51
  "devDependencies": {
49
- "@eslint/js": "^9.31.0",
52
+ "@eslint/js": "^9.39.3",
50
53
  "@types/node": "^24.10.1",
51
- "eslint": "^9.31.0",
52
- "globals": "^17.0.0",
54
+ "eslint": "^9.39.3",
55
+ "globals": "^17.3.0",
53
56
  "knip": "^5.47.0",
54
57
  "prettier": "^3.5.1",
55
58
  "typescript": "^5.8.3",