@codacy/tools-trivy-0 0.3.0 → 0.5.0

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
@@ -1,8 +1,11 @@
1
1
  # @codacy/tools-trivy-0
2
2
 
3
3
  ## Table of Contents
4
+
4
5
  - [Overview](#overview)
5
6
  - [Umbrella patterns](#umbrella-patterns)
7
+ - [DB update management](#db-update-management)
8
+ - [Malicious package detection](#malicious-package-detection)
6
9
  - [Updating patterns](#updating-patterns)
7
10
  - [Updating the Trivy version](#updating-the-trivy-version)
8
11
  - [Development](#development)
@@ -14,28 +17,52 @@
14
17
 
15
18
  Security scanner using the [Trivy](https://trivy.dev/) binary. Scans for vulnerabilities in dependencies and hardcoded secrets. Uses the CLI execution strategy with two separate scan modes (vulnerability + secret).
16
19
 
17
- | Property | Value |
18
- |----------|-------|
19
- | Tool ID | `Trivy` |
20
- | Codacy UUID | `2fd7fbe0-33f9-4ab3-ab73-e9b62404e2cb` |
21
- | Strategy | CLI |
22
- | Languages | Multi-language (scans dependency manifests) |
23
- | Binary | `trivy` |
24
- | File patterns | `*` (auto-detects dependency manifests) |
25
- | Pattern count | 6 (umbrella patterns) |
20
+ | Property | Value |
21
+ | ------------- | ------------------------------------------- |
22
+ | Tool ID | `Trivy` |
23
+ | Codacy UUID | `2fd7fbe0-33f9-4ab3-ab73-e9b62404e2cb` |
24
+ | Strategy | CLI |
25
+ | Languages | Multi-language (scans dependency manifests) |
26
+ | Binary | `trivy` |
27
+ | File patterns | `*` (auto-detects dependency manifests) |
28
+ | Pattern count | 6 (umbrella patterns) |
26
29
 
27
30
  ## Umbrella patterns
28
31
 
29
32
  Trivy uses umbrella patterns rather than individual CVE patterns:
30
33
 
31
- | Pattern ID | Severity | Description |
32
- |------------|----------|-------------|
33
- | `Trivy_vulnerability_critical` | Error | Critical vulnerabilities |
34
- | `Trivy_vulnerability_high` | High | High-severity vulnerabilities |
35
- | `Trivy_vulnerability_medium` | Warning | Medium-severity vulnerabilities |
36
- | `Trivy_vulnerability_minor` | Info | Low-severity vulnerabilities |
37
- | `Trivy_secret` | Error | Hardcoded secrets |
38
- | `Trivy_malicious_packages` | Error | Malicious packages (reserved) |
34
+ | Pattern ID | Severity | Description |
35
+ | ------------------------------ | -------- | ------------------------------------ |
36
+ | `Trivy_vulnerability_critical` | Error | Critical vulnerabilities |
37
+ | `Trivy_vulnerability_high` | High | High-severity vulnerabilities |
38
+ | `Trivy_vulnerability_medium` | Warning | Medium-severity vulnerabilities |
39
+ | `Trivy_vulnerability_minor` | Info | Low-severity vulnerabilities |
40
+ | `Trivy_secret` | Error | Hardcoded secrets |
41
+ | `Trivy_malicious_packages` | Error | Malicious packages (via OSV.dev API) |
42
+
43
+ ## DB update management
44
+
45
+ The adapter reads Trivy's `metadata.json` (at `{cacheDir}/db/metadata.json`) to
46
+ determine if the vulnerability database is still fresh. The `NextUpdate` field
47
+ tells us when Trivy expects the next DB update.
48
+
49
+ | Scenario | Behavior |
50
+ | ------------------------------ | ------------------------------------------------------------------ |
51
+ | DB fresh (`now < NextUpdate`) | `--skip-db-update --skip-java-db-update` passed — no network check |
52
+ | DB stale (`now >= NextUpdate`) | Trivy checks for updates normally |
53
+ | First run (no metadata) | Trivy downloads the DB (~40MB) |
54
+ | Container mode | Always skips DB updates (DBs are pre-baked) |
55
+
56
+ ## Malicious package detection
57
+
58
+ Detects known malicious packages by querying the [OSV.dev batch API](https://api.osv.dev/v1/querybatch).
59
+ This piggybacks on the vulnerability scan output — the package list from `--list-all-pkgs`
60
+ is extracted and cross-referenced against the OpenSSF malicious packages index (`MAL-*` IDs).
61
+
62
+ - Covers 14 ecosystems: npm, PyPI, Go, RubyGems, crates.io, NuGet, Maven, Packagist, Pub, Hex, ConanCenter, CocoaPods, SwiftURL, conda
63
+ - Uses a 10-second timeout per API call
64
+ - On API failure (network error, timeout), logs a warning and skips — never blocks the core scan
65
+ - Message format: `Malicious package detected: {name}@{version} ({MAL-ID}). {summary}`
39
66
 
40
67
  ## Updating patterns
41
68
 
@@ -62,10 +89,11 @@ pnpm test # Run tests (requires trivy in PATH or auto-install)
62
89
 
63
90
  ## Notes for maintainers
64
91
 
65
- - Trivy runs **two separate scan invocations**: one for vulnerabilities (`--scanners vuln`) and one for secrets (`--scanners secret`). Which scans run depends on which umbrella patterns are enabled.
66
- - The vulnerability database is downloaded lazily on first run to `--cache-dir ~/.codacy/cache/trivy/`. Internet access is required on first use.
92
+ - Trivy runs **two separate scan invocations**: one for vulnerabilities (`--scanners vuln`) and one for secrets (`--scanners secret`). Malicious package detection piggybacks on the vuln scan output (no extra invocation). Which scans run depends on which umbrella patterns are enabled.
93
+ - The vulnerability database is downloaded lazily on first run to `--cache-dir ~/.codacy/cache/trivy/`. Internet access is required on first use. DB staleness is managed via `metadata.json` → `NextUpdate`.
67
94
  - Trivy scans **whole directories**, not individual files. Results are filtered to `ctx.targetFiles` after scanning.
68
95
  - The binary is downloaded from GitHub releases as a `.tar.gz` archive.
69
96
  - Vulnerability severity (CRITICAL/HIGH/MEDIUM/LOW) maps to the corresponding umbrella pattern.
70
97
  - Message format: `Insecure dependency {pkg}@{version} ({CVE}: {title}). Update to {fixedVersion}.`
98
+ - Malicious package detection uses the OSV.dev batch API. On failure, it degrades gracefully (warning only).
71
99
  - Config file: checks for `trivy.yaml` in the repo root.
package/dist/index.js CHANGED
@@ -92,19 +92,33 @@ var patterns_default = [
92
92
  }
93
93
  ];
94
94
 
95
+ // src/metadata.ts
96
+ var descriptor = {
97
+ id: "Trivy",
98
+ displayName: "Trivy",
99
+ preferredVersion: "0.69.3",
100
+ languages: [
101
+ "Python",
102
+ "JavaScript",
103
+ "TypeScript",
104
+ "Go",
105
+ "Java",
106
+ "Ruby",
107
+ "Rust",
108
+ "PHP",
109
+ "C#",
110
+ "Dart",
111
+ "Elixir",
112
+ "Swift"
113
+ ],
114
+ filePatterns: ["*"],
115
+ supportedOS: ["linux", "darwin"],
116
+ supportedArch: ["x64", "arm64"],
117
+ supportedRunners: ["local", "container"]
118
+ };
119
+
95
120
  // src/adapter.ts
96
121
  var TOOL_ID = "Trivy";
97
- function getLineContent(lines, lineNumber) {
98
- return lines[lineNumber - 1] ?? "";
99
- }
100
- async function readFileLines(filePath) {
101
- try {
102
- const content = await import_promises.default.readFile(filePath, "utf-8");
103
- return content.split("\n");
104
- } catch {
105
- return [];
106
- }
107
- }
108
122
  var PATTERN_META = new Map(
109
123
  patterns_default.map((p) => [
110
124
  p.id,
@@ -126,6 +140,52 @@ var PATTERN_TO_SEVERITY = {
126
140
  Trivy_vulnerability_medium: "MEDIUM",
127
141
  Trivy_vulnerability_minor: "LOW"
128
142
  };
143
+ var TRIVY_TYPE_TO_OSV_ECOSYSTEM = {
144
+ npm: "npm",
145
+ pip: "PyPI",
146
+ pipenv: "PyPI",
147
+ poetry: "PyPI",
148
+ conda: "conda",
149
+ gomod: "Go",
150
+ gem: "RubyGems",
151
+ bundler: "RubyGems",
152
+ cargo: "crates.io",
153
+ nuget: "NuGet",
154
+ pom: "Maven",
155
+ gradle: "Maven",
156
+ composer: "Packagist",
157
+ pub: "Pub",
158
+ hex: "Hex",
159
+ conan: "ConanCenter",
160
+ cocoapods: "CocoaPods",
161
+ swift: "SwiftURL"
162
+ };
163
+ var OSV_BATCH_SIZE = 1e3;
164
+ var OSV_TIMEOUT_MS = 1e4;
165
+ async function queryOsvBatch(queries) {
166
+ const allResults = [];
167
+ for (let i = 0; i < queries.length; i += OSV_BATCH_SIZE) {
168
+ const batch = queries.slice(i, i + OSV_BATCH_SIZE);
169
+ const controller = new AbortController();
170
+ const timer = setTimeout(() => controller.abort(), OSV_TIMEOUT_MS);
171
+ try {
172
+ const response = await fetch("https://api.osv.dev/v1/querybatch", {
173
+ method: "POST",
174
+ headers: { "Content-Type": "application/json" },
175
+ body: JSON.stringify({ queries: batch }),
176
+ signal: controller.signal
177
+ });
178
+ if (!response.ok) {
179
+ throw new Error(`OSV API returned HTTP ${response.status}: ${response.statusText}`);
180
+ }
181
+ const data = await response.json();
182
+ allResults.push(...data.results ?? []);
183
+ } finally {
184
+ clearTimeout(timer);
185
+ }
186
+ }
187
+ return { results: allResults };
188
+ }
129
189
  var BINARY = "trivy";
130
190
  var PLATFORM_MAP = {
131
191
  "darwin-arm64": "macOS-ARM64",
@@ -151,31 +211,29 @@ async function resolveBinaryPath(ctx) {
151
211
  if (version) return codacyBin;
152
212
  return BINARY;
153
213
  }
154
- function buildResult(startedAt, completedAt, issues, errors, filesAnalyzed) {
155
- const durationMs = completedAt.getTime() - startedAt.getTime();
156
- return {
157
- metadata: {
158
- startedAt: startedAt.toISOString(),
159
- completedAt: completedAt.toISOString(),
160
- durationMs
161
- },
162
- issues,
163
- errors,
164
- summary: {
165
- toolId: TOOL_ID,
166
- status: errors.some((e) => e.level === "error") ? "partial" : "success",
167
- issueCount: issues.length,
168
- errorCount: errors.length,
169
- durationMs,
170
- filesAnalyzed
171
- }
172
- };
173
- }
174
214
  async function ensureCacheDir(globalDir) {
175
215
  const cacheDir = import_path.default.join(globalDir, "cache", "trivy");
176
216
  await import_promises.default.mkdir(cacheDir, { recursive: true });
177
217
  return cacheDir;
178
218
  }
219
+ async function checkDbFreshness(cacheDir) {
220
+ const metadataPath = import_path.default.join(cacheDir, "db", "metadata.json");
221
+ try {
222
+ const raw = await import_promises.default.readFile(metadataPath, "utf-8");
223
+ const meta = JSON.parse(raw);
224
+ if (!meta.NextUpdate) {
225
+ return { fresh: false, error: "metadata.json missing NextUpdate field" };
226
+ }
227
+ const nextUpdateMs = Date.parse(meta.NextUpdate);
228
+ if (Number.isNaN(nextUpdateMs)) {
229
+ return { fresh: false, error: `Invalid NextUpdate timestamp: ${meta.NextUpdate}` };
230
+ }
231
+ return Date.now() < nextUpdateMs ? { fresh: true, nextUpdate: meta.NextUpdate } : { fresh: false, nextUpdate: meta.NextUpdate };
232
+ } catch (err) {
233
+ const message = err instanceof Error ? err.message : String(err);
234
+ return { fresh: false, error: message };
235
+ }
236
+ }
179
237
  async function runTrivyScan(binary, args, cwd, errors) {
180
238
  const { stdout, stderr, exitCode } = await (0, import_tooling.spawnTool)(binary, args, { cwd });
181
239
  if (exitCode !== 0) {
@@ -213,7 +271,7 @@ async function parseVulnerabilities(output, enabledPatterns, targetFilesSet, rep
213
271
  const relPath = result.Target;
214
272
  if (targetFilesSet.size > 0 && !targetFilesSet.has(relPath)) continue;
215
273
  if (!linesCache.has(relPath)) {
216
- linesCache.set(relPath, await readFileLines(import_path.default.join(repositoryRoot, relPath)));
274
+ linesCache.set(relPath, await (0, import_tooling.readFileLines)(import_path.default.join(repositoryRoot, relPath)));
217
275
  }
218
276
  const lines = linesCache.get(relPath);
219
277
  const pkgLineByID = /* @__PURE__ */ new Map();
@@ -242,7 +300,7 @@ async function parseVulnerabilities(output, enabledPatterns, targetFilesSet, rep
242
300
  line,
243
301
  column: 1,
244
302
  message: `Insecure dependency ${vuln.PkgName}@${vuln.InstalledVersion} (${vuln.VulnerabilityID}${title}). ${fix}`,
245
- lineContent: getLineContent(lines, line),
303
+ lineContent: (0, import_tooling.getLineContent)(lines, line),
246
304
  category: meta.category,
247
305
  severity: meta.severity
248
306
  });
@@ -265,7 +323,7 @@ async function parseSecrets(output, enabledPatterns, targetFilesSet, repositoryR
265
323
  const relPath = result.Target;
266
324
  if (targetFilesSet.size > 0 && !targetFilesSet.has(relPath)) continue;
267
325
  if (!linesCache.has(relPath)) {
268
- linesCache.set(relPath, await readFileLines(import_path.default.join(repositoryRoot, relPath)));
326
+ linesCache.set(relPath, await (0, import_tooling.readFileLines)(import_path.default.join(repositoryRoot, relPath)));
269
327
  }
270
328
  const lines = linesCache.get(relPath);
271
329
  for (const secret of result.Secrets) {
@@ -277,7 +335,7 @@ async function parseSecrets(output, enabledPatterns, targetFilesSet, repositoryR
277
335
  column: 1,
278
336
  endLine: secret.EndLine,
279
337
  message: `Possible hardcoded secret: ${secret.Title} (${secret.Category})`,
280
- lineContent: getLineContent(lines, secret.StartLine),
338
+ lineContent: (0, import_tooling.getLineContent)(lines, secret.StartLine),
281
339
  multilineContent: (0, import_tooling.getMultilineContent)(lines, secret.StartLine, secret.EndLine),
282
340
  category: meta.category,
283
341
  severity: meta.severity
@@ -286,30 +344,107 @@ async function parseSecrets(output, enabledPatterns, targetFilesSet, repositoryR
286
344
  }
287
345
  return issues;
288
346
  }
347
+ async function parseMaliciousPackages(output, enabledPatterns, targetFilesSet, repositoryRoot, logger) {
348
+ const issues = [];
349
+ const errors = [];
350
+ const patternId = "Trivy_malicious_packages";
351
+ if (enabledPatterns.size > 0 && !enabledPatterns.has(patternId)) {
352
+ return { issues, errors };
353
+ }
354
+ if (!output.Results) return { issues, errors };
355
+ const meta = PATTERN_META.get(patternId) ?? {
356
+ category: "Security",
357
+ severity: "Error"
358
+ };
359
+ const packages = [];
360
+ const seen = /* @__PURE__ */ new Set();
361
+ for (const result of output.Results) {
362
+ if (!result.Packages || !result.Type) continue;
363
+ const ecosystem = TRIVY_TYPE_TO_OSV_ECOSYSTEM[result.Type];
364
+ if (!ecosystem) continue;
365
+ const relPath = result.Target;
366
+ if (targetFilesSet.size > 0 && !targetFilesSet.has(relPath)) continue;
367
+ for (const pkg of result.Packages) {
368
+ const key = `${ecosystem}:${pkg.Name}:${pkg.Version}:${relPath}`;
369
+ if (seen.has(key)) continue;
370
+ seen.add(key);
371
+ const line = pkg.Locations && pkg.Locations.length > 0 && pkg.Locations[0].StartLine > 0 ? pkg.Locations[0].StartLine : 1;
372
+ packages.push({ ecosystem, name: pkg.Name, version: pkg.Version, filePath: relPath, line });
373
+ }
374
+ }
375
+ if (packages.length === 0) return { issues, errors };
376
+ const queryMap = /* @__PURE__ */ new Map();
377
+ for (const pkg of packages) {
378
+ const queryKey = `${pkg.ecosystem}:${pkg.name}:${pkg.version}`;
379
+ if (!queryMap.has(queryKey)) {
380
+ queryMap.set(queryKey, {
381
+ package: { name: pkg.name, ecosystem: pkg.ecosystem },
382
+ version: pkg.version
383
+ });
384
+ }
385
+ }
386
+ const queries = Array.from(queryMap.values());
387
+ let osvResponse;
388
+ try {
389
+ logger.debug("Querying OSV.dev for malicious packages", { packageCount: queries.length });
390
+ osvResponse = await queryOsvBatch(queries);
391
+ } catch (err) {
392
+ const message = err instanceof Error ? err.message : String(err);
393
+ logger.warn(`Malicious package check skipped: ${message}`);
394
+ errors.push({
395
+ toolId: TOOL_ID,
396
+ phase: "toolInvoke",
397
+ kind: "NetworkError",
398
+ message: `OSV.dev API call failed: ${message}. Malicious package detection skipped.`,
399
+ level: "warning"
400
+ });
401
+ return { issues, errors };
402
+ }
403
+ const maliciousByPkg = /* @__PURE__ */ new Map();
404
+ const queryList = Array.from(queryMap.keys());
405
+ for (let i = 0; i < osvResponse.results.length; i++) {
406
+ const result = osvResponse.results[i];
407
+ if (!result.vulns) continue;
408
+ const malVulns = result.vulns.filter((v) => v.id.startsWith("MAL-"));
409
+ if (malVulns.length > 0 && i < queryList.length) {
410
+ maliciousByPkg.set(queryList[i], malVulns);
411
+ }
412
+ }
413
+ if (maliciousByPkg.size === 0) {
414
+ logger.debug("No malicious packages detected");
415
+ return { issues, errors };
416
+ }
417
+ const linesCache = /* @__PURE__ */ new Map();
418
+ for (const pkg of packages) {
419
+ const queryKey = `${pkg.ecosystem}:${pkg.name}:${pkg.version}`;
420
+ const malVulns = maliciousByPkg.get(queryKey);
421
+ if (!malVulns) continue;
422
+ if (!linesCache.has(pkg.filePath)) {
423
+ linesCache.set(pkg.filePath, await (0, import_tooling.readFileLines)(import_path.default.join(repositoryRoot, pkg.filePath)));
424
+ }
425
+ const lines = linesCache.get(pkg.filePath);
426
+ for (const vuln of malVulns) {
427
+ const summary = vuln.summary ? ` ${vuln.summary}` : "";
428
+ issues.push({
429
+ filePath: pkg.filePath,
430
+ patternId,
431
+ toolId: TOOL_ID,
432
+ line: pkg.line,
433
+ column: 1,
434
+ message: `Malicious package detected: ${pkg.name}@${pkg.version} (${vuln.id}).${summary}`,
435
+ lineContent: (0, import_tooling.getLineContent)(lines, pkg.line),
436
+ category: meta.category,
437
+ severity: meta.severity
438
+ });
439
+ }
440
+ }
441
+ logger.info("Malicious package check complete", { issuesFound: issues.length });
442
+ return { issues, errors };
443
+ }
289
444
  var adapter = {
290
- id: TOOL_ID,
291
- displayName: "Trivy",
292
- preferredVersion: "0.69.3",
445
+ ...descriptor,
293
446
  compatibleVersions: ">=0.50.0",
294
447
  website: "https://trivy.dev/",
295
- languages: [
296
- "Python",
297
- "JavaScript",
298
- "TypeScript",
299
- "Go",
300
- "Java",
301
- "Ruby",
302
- "Rust",
303
- "PHP",
304
- "C#",
305
- "Dart",
306
- "Elixir",
307
- "Swift"
308
- ],
309
- filePatterns: ["*"],
310
- supportedOS: ["linux", "darwin"],
311
- supportedArch: ["x64", "arm64"],
312
- supportedRunners: ["local", "container"],
313
448
  prerequisites: [],
314
449
  /**
315
450
  * Checks whether the `trivy` binary is present and runnable.
@@ -446,13 +581,7 @@ var adapter = {
446
581
  const issues = [];
447
582
  const errors = [];
448
583
  if (ctx.targetFiles.length === 0) {
449
- return buildResult(startedAt, /* @__PURE__ */ new Date(), issues, errors, 0);
450
- }
451
- if (!(codacyConfig.useLocalConfigurationFile && codacyConfig.localConfigurationFile) && codacyConfig.patterns.length === 0) {
452
- ctx.logger.info("Skipping analysis: no local config and no patterns enabled", {
453
- toolId: TOOL_ID
454
- });
455
- return buildResult(startedAt, /* @__PURE__ */ new Date(), issues, errors, ctx.targetFiles.length);
584
+ return (0, import_tooling.buildResult)(TOOL_ID, startedAt, /* @__PURE__ */ new Date(), issues, errors, 0);
456
585
  }
457
586
  const binary = await resolveBinaryPath(ctx);
458
587
  let cacheDir;
@@ -466,14 +595,33 @@ var adapter = {
466
595
  message: `Failed to create cache directory: ${err instanceof Error ? err.message : String(err)}`,
467
596
  level: "error"
468
597
  });
469
- return buildResult(startedAt, /* @__PURE__ */ new Date(), issues, errors, ctx.targetFiles.length);
598
+ return (0, import_tooling.buildResult)(TOOL_ID, startedAt, /* @__PURE__ */ new Date(), issues, errors, ctx.targetFiles.length);
470
599
  }
471
600
  const enabledPatterns = new Set(codacyConfig.patterns.map((p) => p.patternId));
472
601
  const targetFilesSet = new Set(ctx.targetFiles);
473
602
  const vulnPatternIds = Object.values(VULN_SEVERITY_TO_PATTERN);
474
- const runVulnScan = enabledPatterns.size === 0 || vulnPatternIds.some((id) => enabledPatterns.has(id));
603
+ const runMaliciousScan = enabledPatterns.size === 0 || enabledPatterns.has("Trivy_malicious_packages");
604
+ const runVulnScan = enabledPatterns.size === 0 || vulnPatternIds.some((id) => enabledPatterns.has(id)) || runMaliciousScan;
475
605
  const runSecretScan = enabledPatterns.size === 0 || enabledPatterns.has("Trivy_secret");
476
606
  const baseArgs = ["filesystem", "--format", "json", "--cache-dir", cacheDir];
607
+ if (runVulnScan) {
608
+ if (ctx.runner === "container") {
609
+ baseArgs.push("--skip-db-update", "--skip-java-db-update");
610
+ ctx.logger.debug("Container mode: skipping DB updates");
611
+ } else {
612
+ const dbStatus = await checkDbFreshness(cacheDir);
613
+ if (dbStatus.fresh) {
614
+ baseArgs.push("--skip-db-update", "--skip-java-db-update");
615
+ ctx.logger.debug("Trivy DB is fresh, skipping update check", {
616
+ nextUpdate: dbStatus.nextUpdate
617
+ });
618
+ } else {
619
+ ctx.logger.info(
620
+ dbStatus.error?.includes("ENOENT") ? "Trivy vulnerability database not found. Downloading (~40MB)..." : "Trivy DB update due, checking for new data..."
621
+ );
622
+ }
623
+ }
624
+ }
477
625
  if (codacyConfig.useLocalConfigurationFile && codacyConfig.localConfigurationFile) {
478
626
  baseArgs.push("--config", codacyConfig.localConfigurationFile);
479
627
  }
@@ -511,6 +659,17 @@ var adapter = {
511
659
  ctx.repositoryRoot
512
660
  )
513
661
  );
662
+ if (runMaliciousScan && ctx.runner !== "container") {
663
+ const malResult = await parseMaliciousPackages(
664
+ vulnOutput,
665
+ enabledPatterns,
666
+ targetFilesSet,
667
+ ctx.repositoryRoot,
668
+ ctx.logger
669
+ );
670
+ issues.push(...malResult.issues);
671
+ errors.push(...malResult.errors);
672
+ }
514
673
  }
515
674
  }
516
675
  if (runSecretScan) {
@@ -536,7 +695,14 @@ var adapter = {
536
695
  level: "error"
537
696
  });
538
697
  }
539
- const result = buildResult(startedAt, /* @__PURE__ */ new Date(), issues, errors, ctx.targetFiles.length);
698
+ const result = (0, import_tooling.buildResult)(
699
+ TOOL_ID,
700
+ startedAt,
701
+ /* @__PURE__ */ new Date(),
702
+ issues,
703
+ errors,
704
+ ctx.targetFiles.length
705
+ );
540
706
  ctx.logger.info("Analysis complete", {
541
707
  toolId: TOOL_ID,
542
708
  issueCount: result.summary.issueCount,
@@ -0,0 +1,13 @@
1
+ import { AdapterDescriptor } from '@codacy/tooling';
2
+
3
+ /**
4
+ * Lightweight adapter descriptor for lazy loading.
5
+ *
6
+ * This module contains only plain-data metadata fields and has zero heavy
7
+ * imports (no patterns.json, no runtime utilities). The CLI imports this
8
+ * at startup for adapter registration without loading the full adapter module.
9
+ */
10
+
11
+ declare const descriptor: AdapterDescriptor;
12
+
13
+ export { descriptor };
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/metadata.ts
21
+ var metadata_exports = {};
22
+ __export(metadata_exports, {
23
+ descriptor: () => descriptor
24
+ });
25
+ module.exports = __toCommonJS(metadata_exports);
26
+ var descriptor = {
27
+ id: "Trivy",
28
+ displayName: "Trivy",
29
+ preferredVersion: "0.69.3",
30
+ languages: [
31
+ "Python",
32
+ "JavaScript",
33
+ "TypeScript",
34
+ "Go",
35
+ "Java",
36
+ "Ruby",
37
+ "Rust",
38
+ "PHP",
39
+ "C#",
40
+ "Dart",
41
+ "Elixir",
42
+ "Swift"
43
+ ],
44
+ filePatterns: ["*"],
45
+ supportedOS: ["linux", "darwin"],
46
+ supportedArch: ["x64", "arm64"],
47
+ supportedRunners: ["local", "container"]
48
+ };
49
+ // Annotate the CommonJS export names for ESM import in node:
50
+ 0 && (module.exports = {
51
+ descriptor
52
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codacy/tools-trivy-0",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Trivy adapter — CLI-mode security scanner",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,7 +8,7 @@
8
8
  "dist"
9
9
  ],
10
10
  "dependencies": {
11
- "@codacy/tooling": "0.3.0"
11
+ "@codacy/tooling": "0.5.0"
12
12
  },
13
13
  "license": "MIT",
14
14
  "author": "Codacy <support@codacy.com> (https://www.codacy.com)",
@@ -21,8 +21,18 @@
21
21
  "engines": {
22
22
  "node": ">=20.0.0"
23
23
  },
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "./metadata": {
30
+ "types": "./dist/metadata.d.ts",
31
+ "default": "./dist/metadata.js"
32
+ }
33
+ },
24
34
  "scripts": {
25
- "build": "tsup src/index.ts --format cjs --dts --clean",
35
+ "build": "tsup src/index.ts src/metadata.ts --format cjs --dts --clean",
26
36
  "test": "vitest run",
27
37
  "lint": "eslint src/",
28
38
  "clean": "rm -rf dist",