cve-scanner 0.0.0 → 0.0.2

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 (140) hide show
  1. package/README.md +96 -45
  2. package/assets/gradle-init/list-dependencies.init.gradle +20 -0
  3. package/data/dataset.hash +1 -0
  4. package/data/dataset.json +288056 -0
  5. package/dist/ai/AiAssistant.d.ts +11 -0
  6. package/dist/ai/AiAssistant.js +34 -0
  7. package/dist/ai/AiAssistant.js.map +1 -0
  8. package/dist/ai/ProjectManifestReader.d.ts +8 -0
  9. package/dist/ai/ProjectManifestReader.js +34 -0
  10. package/dist/ai/ProjectManifestReader.js.map +1 -0
  11. package/dist/ai/ProjectManifestReader.test.d.ts +1 -0
  12. package/dist/ai/ProjectManifestReader.test.js +59 -0
  13. package/dist/ai/ProjectManifestReader.test.js.map +1 -0
  14. package/dist/ai/PromptBuilder.d.ts +5 -0
  15. package/dist/ai/PromptBuilder.js +42 -0
  16. package/dist/ai/PromptBuilder.js.map +1 -0
  17. package/dist/ai/PromptBuilder.test.d.ts +1 -0
  18. package/dist/ai/PromptBuilder.test.js +66 -0
  19. package/dist/ai/PromptBuilder.test.js.map +1 -0
  20. package/dist/cmd/cve-scanner.d.ts +2 -0
  21. package/dist/cmd/cve-scanner.js +60 -0
  22. package/dist/cmd/cve-scanner.js.map +1 -0
  23. package/dist/core/CommandRunner.d.ts +6 -0
  24. package/dist/core/CommandRunner.js +16 -0
  25. package/dist/core/CommandRunner.js.map +1 -0
  26. package/dist/core/DatasetLoader.d.ts +14 -0
  27. package/dist/core/DatasetLoader.js +44 -0
  28. package/dist/core/DatasetLoader.js.map +1 -0
  29. package/dist/core/DatasetLoader.test.d.ts +1 -0
  30. package/dist/core/DatasetLoader.test.js +41 -0
  31. package/dist/core/DatasetLoader.test.js.map +1 -0
  32. package/dist/core/ProjectRootDiscovery.d.ts +9 -0
  33. package/dist/core/ProjectRootDiscovery.js +62 -0
  34. package/dist/core/ProjectRootDiscovery.js.map +1 -0
  35. package/dist/core/ProjectRootDiscovery.test.d.ts +1 -0
  36. package/dist/core/ProjectRootDiscovery.test.js +47 -0
  37. package/dist/core/ProjectRootDiscovery.test.js.map +1 -0
  38. package/dist/core/Scanner.d.ts +19 -0
  39. package/dist/core/Scanner.js +66 -0
  40. package/dist/core/Scanner.js.map +1 -0
  41. package/dist/core/Scanner.test.d.ts +1 -0
  42. package/dist/core/Scanner.test.js +157 -0
  43. package/dist/core/Scanner.test.js.map +1 -0
  44. package/dist/core/VersionComparator.d.ts +6 -0
  45. package/dist/core/VersionComparator.js +35 -0
  46. package/dist/core/VersionComparator.js.map +1 -0
  47. package/dist/core/VersionComparator.test.d.ts +1 -0
  48. package/dist/core/VersionComparator.test.js +21 -0
  49. package/dist/core/VersionComparator.test.js.map +1 -0
  50. package/dist/core/cpe.d.ts +9 -0
  51. package/dist/core/cpe.js +32 -0
  52. package/dist/core/cpe.js.map +1 -0
  53. package/dist/core/cpe.test.d.ts +1 -0
  54. package/dist/core/cpe.test.js +25 -0
  55. package/dist/core/cpe.test.js.map +1 -0
  56. package/dist/core/types.d.ts +57 -0
  57. package/dist/core/types.js +3 -0
  58. package/dist/core/types.js.map +1 -0
  59. package/dist/ecosystems/enrichment/CveListCache.d.ts +13 -0
  60. package/dist/ecosystems/enrichment/CveListCache.js +88 -0
  61. package/dist/ecosystems/enrichment/CveListCache.js.map +1 -0
  62. package/dist/ecosystems/enrichment/CveListCache.test.d.ts +1 -0
  63. package/dist/ecosystems/enrichment/CveListCache.test.js +49 -0
  64. package/dist/ecosystems/enrichment/CveListCache.test.js.map +1 -0
  65. package/dist/ecosystems/enrichment/CveOrgDatasetReader.d.ts +12 -0
  66. package/dist/ecosystems/enrichment/CveOrgDatasetReader.js +59 -0
  67. package/dist/ecosystems/enrichment/CveOrgDatasetReader.js.map +1 -0
  68. package/dist/ecosystems/enrichment/CveOrgDatasetReader.test.d.ts +1 -0
  69. package/dist/ecosystems/enrichment/CveOrgDatasetReader.test.js +48 -0
  70. package/dist/ecosystems/enrichment/CveOrgDatasetReader.test.js.map +1 -0
  71. package/dist/ecosystems/enrichment/ZipExtractor.d.ts +18 -0
  72. package/dist/ecosystems/enrichment/ZipExtractor.js +105 -0
  73. package/dist/ecosystems/enrichment/ZipExtractor.js.map +1 -0
  74. package/dist/ecosystems/enrichment/ZipExtractor.test.d.ts +1 -0
  75. package/dist/ecosystems/enrichment/ZipExtractor.test.js +36 -0
  76. package/dist/ecosystems/enrichment/ZipExtractor.test.js.map +1 -0
  77. package/dist/ecosystems/java/GradleDependencyDetector.d.ts +9 -0
  78. package/dist/ecosystems/java/GradleDependencyDetector.js +33 -0
  79. package/dist/ecosystems/java/GradleDependencyDetector.js.map +1 -0
  80. package/dist/ecosystems/java/MavenDependencyDetector.d.ts +9 -0
  81. package/dist/ecosystems/java/MavenDependencyDetector.js +39 -0
  82. package/dist/ecosystems/java/MavenDependencyDetector.js.map +1 -0
  83. package/dist/ecosystems/java/parsers/gradleDependencyOutputParser.d.ts +12 -0
  84. package/dist/ecosystems/java/parsers/gradleDependencyOutputParser.js +32 -0
  85. package/dist/ecosystems/java/parsers/gradleDependencyOutputParser.js.map +1 -0
  86. package/dist/ecosystems/java/parsers/gradleDependencyOutputParser.test.d.ts +1 -0
  87. package/dist/ecosystems/java/parsers/gradleDependencyOutputParser.test.js +36 -0
  88. package/dist/ecosystems/java/parsers/gradleDependencyOutputParser.test.js.map +1 -0
  89. package/dist/ecosystems/java/parsers/mavenDependencyListParser.d.ts +11 -0
  90. package/dist/ecosystems/java/parsers/mavenDependencyListParser.js +31 -0
  91. package/dist/ecosystems/java/parsers/mavenDependencyListParser.js.map +1 -0
  92. package/dist/ecosystems/java/parsers/mavenDependencyListParser.test.d.ts +1 -0
  93. package/dist/ecosystems/java/parsers/mavenDependencyListParser.test.js +37 -0
  94. package/dist/ecosystems/java/parsers/mavenDependencyListParser.test.js.map +1 -0
  95. package/dist/ecosystems/java/resolveExecutable.d.ts +8 -0
  96. package/dist/ecosystems/java/resolveExecutable.js +22 -0
  97. package/dist/ecosystems/java/resolveExecutable.js.map +1 -0
  98. package/dist/ecosystems/java/resolveExecutable.test.d.ts +1 -0
  99. package/dist/ecosystems/java/resolveExecutable.test.js +42 -0
  100. package/dist/ecosystems/java/resolveExecutable.test.js.map +1 -0
  101. package/dist/ecosystems/npm/NpmDetector.d.ts +6 -0
  102. package/dist/ecosystems/npm/NpmDetector.js +31 -0
  103. package/dist/ecosystems/npm/NpmDetector.js.map +1 -0
  104. package/dist/ecosystems/npm/PackageLockParser.d.ts +11 -0
  105. package/dist/ecosystems/npm/PackageLockParser.js +65 -0
  106. package/dist/ecosystems/npm/PackageLockParser.js.map +1 -0
  107. package/dist/ecosystems/npm/PackageLockParser.test.d.ts +1 -0
  108. package/dist/ecosystems/npm/PackageLockParser.test.js +59 -0
  109. package/dist/ecosystems/npm/PackageLockParser.test.js.map +1 -0
  110. package/dist/lib/CveScannerApi.d.ts +13 -0
  111. package/dist/lib/CveScannerApi.js +55 -0
  112. package/dist/lib/CveScannerApi.js.map +1 -0
  113. package/dist/lib/report.d.ts +4 -0
  114. package/dist/lib/report.js +47 -0
  115. package/dist/lib/report.js.map +1 -0
  116. package/dist/pipeline/dedupeEntries.d.ts +8 -0
  117. package/dist/pipeline/dedupeEntries.js +20 -0
  118. package/dist/pipeline/dedupeEntries.js.map +1 -0
  119. package/dist/pipeline/dedupeEntries.test.d.ts +1 -0
  120. package/dist/pipeline/dedupeEntries.test.js +27 -0
  121. package/dist/pipeline/dedupeEntries.test.js.map +1 -0
  122. package/dist/pipeline/hashDataset.d.ts +7 -0
  123. package/dist/pipeline/hashDataset.js +13 -0
  124. package/dist/pipeline/hashDataset.js.map +1 -0
  125. package/dist/pipeline/hashDataset.test.d.ts +1 -0
  126. package/dist/pipeline/hashDataset.test.js +28 -0
  127. package/dist/pipeline/hashDataset.test.js.map +1 -0
  128. package/dist/pipeline/mapSeverityToScore.d.ts +9 -0
  129. package/dist/pipeline/mapSeverityToScore.js +26 -0
  130. package/dist/pipeline/mapSeverityToScore.js.map +1 -0
  131. package/dist/pipeline/mapSeverityToScore.test.d.ts +1 -0
  132. package/dist/pipeline/mapSeverityToScore.test.js +20 -0
  133. package/dist/pipeline/mapSeverityToScore.test.js.map +1 -0
  134. package/dist/pipeline/parseOsvRecord.d.ts +37 -0
  135. package/dist/pipeline/parseOsvRecord.js +88 -0
  136. package/dist/pipeline/parseOsvRecord.js.map +1 -0
  137. package/dist/pipeline/parseOsvRecord.test.d.ts +1 -0
  138. package/dist/pipeline/parseOsvRecord.test.js +220 -0
  139. package/dist/pipeline/parseOsvRecord.test.js.map +1 -0
  140. package/package.json +37 -6
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_fs_1 = require("node:fs");
8
+ const node_os_1 = require("node:os");
9
+ const node_path_1 = require("node:path");
10
+ const node_test_1 = require("node:test");
11
+ const ProjectRootDiscovery_1 = require("./ProjectRootDiscovery");
12
+ function makeScanDir() {
13
+ return (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'cve-scanner-roots-'));
14
+ }
15
+ (0, node_test_1.test)('finds the scan dir itself when it has a manifest', () => {
16
+ const dir = makeScanDir();
17
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, 'package-lock.json'), '{}');
18
+ strict_1.default.deepEqual((0, ProjectRootDiscovery_1.findProjectRoots)(dir), [dir]);
19
+ });
20
+ (0, node_test_1.test)('discovers independent sub-projects in a monorepo with no root manifest', () => {
21
+ const dir = makeScanDir();
22
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(dir, 'backend'), { recursive: true });
23
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(dir, 'frontend'), { recursive: true });
24
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, 'backend', 'pom.xml'), '<project/>');
25
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, 'frontend', 'package-lock.json'), '{}');
26
+ strict_1.default.deepEqual((0, ProjectRootDiscovery_1.findProjectRoots)(dir).sort(), [(0, node_path_1.join)(dir, 'backend'), (0, node_path_1.join)(dir, 'frontend')].sort());
27
+ });
28
+ (0, node_test_1.test)('does not descend into a directory once it qualifies as a root', () => {
29
+ const dir = makeScanDir();
30
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(dir, 'nested-module'), { recursive: true });
31
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, 'pom.xml'), '<project/>');
32
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, 'nested-module', 'pom.xml'), '<project/>');
33
+ strict_1.default.deepEqual((0, ProjectRootDiscovery_1.findProjectRoots)(dir), [dir]);
34
+ });
35
+ (0, node_test_1.test)('skips noise directories like node_modules and .git', () => {
36
+ const dir = makeScanDir();
37
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(dir, 'node_modules', 'some-lib'), { recursive: true });
38
+ (0, node_fs_1.mkdirSync)((0, node_path_1.join)(dir, '.git'), { recursive: true });
39
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, 'node_modules', 'some-lib', 'package-lock.json'), '{}');
40
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, '.git', 'pom.xml'), '<project/>');
41
+ strict_1.default.deepEqual((0, ProjectRootDiscovery_1.findProjectRoots)(dir), []);
42
+ });
43
+ (0, node_test_1.test)('returns an empty list when no manifest exists anywhere', () => {
44
+ const dir = makeScanDir();
45
+ strict_1.default.deepEqual((0, ProjectRootDiscovery_1.findProjectRoots)(dir), []);
46
+ });
47
+ //# sourceMappingURL=ProjectRootDiscovery.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectRootDiscovery.test.js","sourceRoot":"","sources":["../../src/core/ProjectRootDiscovery.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { DatasetLoader } from './DatasetLoader';
2
+ import { Detector, Finding, ScanOptions } from './types';
3
+ export type ProjectRootFinder = (scanDir: string) => string[];
4
+ export declare class Scanner {
5
+ private detectors;
6
+ private dataset;
7
+ private findRoots;
8
+ constructor(detectors: Detector[], dataset: DatasetLoader, findRoots?: ProjectRootFinder);
9
+ scan(options: ScanOptions): Promise<Finding[]>;
10
+ /**
11
+ * Runs every applicable detector in every independent project root found
12
+ * under `options.scanDir` (a monorepo of unrelated projects yields more
13
+ * than one root) — see specs/35-project-discovery.md.
14
+ */
15
+ private detectArtifacts;
16
+ private detectArtifactsInRoot;
17
+ private match;
18
+ private isAffected;
19
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Scanner = void 0;
4
+ const ProjectRootDiscovery_1 = require("./ProjectRootDiscovery");
5
+ const VersionComparator_1 = require("./VersionComparator");
6
+ class Scanner {
7
+ constructor(detectors, dataset, findRoots = ProjectRootDiscovery_1.findProjectRoots) {
8
+ this.detectors = detectors;
9
+ this.dataset = dataset;
10
+ this.findRoots = findRoots;
11
+ }
12
+ async scan(options) {
13
+ const artifacts = await this.detectArtifacts(options);
14
+ return artifacts.flatMap((artifact) => this.match(artifact));
15
+ }
16
+ /**
17
+ * Runs every applicable detector in every independent project root found
18
+ * under `options.scanDir` (a monorepo of unrelated projects yields more
19
+ * than one root) — see specs/35-project-discovery.md.
20
+ */
21
+ async detectArtifacts(options) {
22
+ const roots = this.findRoots(options.scanDir);
23
+ const perRoot = await Promise.all(roots.map((root) => this.detectArtifactsInRoot({ ...options, scanDir: root })));
24
+ return perRoot.flat();
25
+ }
26
+ async detectArtifactsInRoot(options) {
27
+ const applicable = await Promise.all(this.detectors.map(async (detector) => (await detector.isApplicable(options)) ? detector : undefined));
28
+ const results = await Promise.all(applicable
29
+ .filter((d) => d !== undefined)
30
+ .map((d) => d.detect(options)));
31
+ return results.flat();
32
+ }
33
+ match(artifact) {
34
+ const entries = this.dataset.findEntries(artifact.ecosystem, artifact.coordinate);
35
+ return entries
36
+ .filter((entry) => this.isAffected(artifact.version, entry))
37
+ .flatMap((entry) => entry.cves.map((cve) => ({ artifact, cve })));
38
+ }
39
+ isAffected(version, entry) {
40
+ if (entry.versionExact !== undefined) {
41
+ return (0, VersionComparator_1.compareVersions)(version, entry.versionExact) === 0;
42
+ }
43
+ if (entry.versionStartIncluding !== undefined &&
44
+ (0, VersionComparator_1.compareVersions)(version, entry.versionStartIncluding) < 0) {
45
+ return false;
46
+ }
47
+ if (entry.versionStartExcluding !== undefined &&
48
+ (0, VersionComparator_1.compareVersions)(version, entry.versionStartExcluding) <= 0) {
49
+ return false;
50
+ }
51
+ if (entry.versionEndIncluding !== undefined &&
52
+ (0, VersionComparator_1.compareVersions)(version, entry.versionEndIncluding) > 0) {
53
+ return false;
54
+ }
55
+ if (entry.versionEndExcluding !== undefined &&
56
+ (0, VersionComparator_1.compareVersions)(version, entry.versionEndExcluding) >= 0) {
57
+ return false;
58
+ }
59
+ return (entry.versionStartIncluding !== undefined ||
60
+ entry.versionStartExcluding !== undefined ||
61
+ entry.versionEndIncluding !== undefined ||
62
+ entry.versionEndExcluding !== undefined);
63
+ }
64
+ }
65
+ exports.Scanner = Scanner;
66
+ //# sourceMappingURL=Scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Scanner.js","sourceRoot":"","sources":["../../src/core/Scanner.ts"],"names":[],"mappings":";;;AACA,iEAA0D;AAC1D,2DAAsD;AAWtD;IACE,YACU,SAAqB,EACrB,OAAsB,EACtB,SAAS,GAAsB,uCAAgB;yBAF/C,SAAS;uBACT,OAAO;yBACP,SAAS;IAChB,CAAC;IAEJ,KAAK,CAAC,IAAI,CAAC,OAAoB;QAC7B,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACtD,OAAO,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,eAAe,CAC3B,OAAoB;QAEpB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACjB,IAAI,CAAC,qBAAqB,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAC1D,CACF,CAAC;QACF,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAEO,KAAK,CAAC,qBAAqB,CACjC,OAAoB;QAEpB,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAClC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CACpC,CAAC,MAAM,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAC9D,CACF,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,UAAU;aACP,MAAM,CAAC,CAAC,CAAC,EAAiB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC;aAC7C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CACjC,CAAC;QACF,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAEO,KAAK,CAAC,QAA0B;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CACtC,QAAQ,CAAC,SAAS,EAClB,QAAQ,CAAC,UAAU,CACpB,CAAC;QACF,OAAO,OAAO;aACX,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;aAC3D,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;IAEO,UAAU,CAAC,OAAe,EAAE,KAAsB;QACxD,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACrC,OAAO,IAAA,mCAAe,EAAC,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAC5D,CAAC;QAED,IACE,KAAK,CAAC,qBAAqB,KAAK,SAAS;YACzC,IAAA,mCAAe,EAAC,OAAO,EAAE,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,EACzD,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IACE,KAAK,CAAC,qBAAqB,KAAK,SAAS;YACzC,IAAA,mCAAe,EAAC,OAAO,EAAE,KAAK,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAC1D,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IACE,KAAK,CAAC,mBAAmB,KAAK,SAAS;YACvC,IAAA,mCAAe,EAAC,OAAO,EAAE,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,EACvD,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IACE,KAAK,CAAC,mBAAmB,KAAK,SAAS;YACvC,IAAA,mCAAe,EAAC,OAAO,EAAE,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC,EACxD,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,CACL,KAAK,CAAC,qBAAqB,KAAK,SAAS;YACzC,KAAK,CAAC,qBAAqB,KAAK,SAAS;YACzC,KAAK,CAAC,mBAAmB,KAAK,SAAS;YACvC,KAAK,CAAC,mBAAmB,KAAK,SAAS,CACxC,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_test_1 = require("node:test");
8
+ const DatasetLoader_1 = require("./DatasetLoader");
9
+ const Scanner_1 = require("./Scanner");
10
+ const SINGLE_ROOT = (scanDir) => [scanDir];
11
+ function fakeDetector(artifacts) {
12
+ return {
13
+ ecosystem: artifacts[0]?.ecosystem ?? 'npm',
14
+ isApplicable: async () => true,
15
+ detect: async () => artifacts,
16
+ };
17
+ }
18
+ const dataset = {
19
+ generatedAt: '2026-01-01T00:00:00.000Z',
20
+ entries: [
21
+ {
22
+ ecosystem: 'maven',
23
+ cpe: 'cpe:2.3:a:com.example:lib:*:*:*:*:*:*:*:*',
24
+ versionEndExcluding: '2.0.0',
25
+ cves: [{ id: 'CVE-1', score: 8, title: 'range bound' }],
26
+ },
27
+ {
28
+ ecosystem: 'npm',
29
+ cpe: 'cpe:2.3:a:left-pad:left-pad:*:*:*:*:*:*:*:*',
30
+ versionExact: '1.0.0',
31
+ cves: [{ id: 'CVE-2', score: 5, title: 'exact match' }],
32
+ },
33
+ ],
34
+ };
35
+ (0, node_test_1.test)('matches an artifact whose version falls within a bounded range', async () => {
36
+ const scanner = new Scanner_1.Scanner([
37
+ fakeDetector([
38
+ {
39
+ ecosystem: 'maven',
40
+ coordinate: 'com.example:lib',
41
+ version: '1.5.0',
42
+ source: 'test',
43
+ projectRoot: '/irrelevant',
44
+ },
45
+ ]),
46
+ ], new DatasetLoader_1.DatasetLoader(dataset), SINGLE_ROOT);
47
+ const findings = await scanner.scan({ scanDir: '/irrelevant' });
48
+ strict_1.default.equal(findings.length, 1);
49
+ strict_1.default.equal(findings[0].cve.id, 'CVE-1');
50
+ });
51
+ (0, node_test_1.test)('does not match an artifact whose version is outside the range', async () => {
52
+ const scanner = new Scanner_1.Scanner([
53
+ fakeDetector([
54
+ {
55
+ ecosystem: 'maven',
56
+ coordinate: 'com.example:lib',
57
+ version: '2.0.0',
58
+ source: 'test',
59
+ projectRoot: '/irrelevant',
60
+ },
61
+ ]),
62
+ ], new DatasetLoader_1.DatasetLoader(dataset), SINGLE_ROOT);
63
+ strict_1.default.deepEqual(await scanner.scan({ scanDir: '/irrelevant' }), []);
64
+ });
65
+ (0, node_test_1.test)('matches an exact-version entry only on that exact version', async () => {
66
+ const matching = new Scanner_1.Scanner([
67
+ fakeDetector([
68
+ {
69
+ ecosystem: 'npm',
70
+ coordinate: 'left-pad',
71
+ version: '1.0.0',
72
+ source: 'test',
73
+ projectRoot: '/irrelevant',
74
+ },
75
+ ]),
76
+ ], new DatasetLoader_1.DatasetLoader(dataset), SINGLE_ROOT);
77
+ strict_1.default.equal((await matching.scan({ scanDir: '/irrelevant' }))[0].cve.id, 'CVE-2');
78
+ const nonMatching = new Scanner_1.Scanner([
79
+ fakeDetector([
80
+ {
81
+ ecosystem: 'npm',
82
+ coordinate: 'left-pad',
83
+ version: '1.0.1',
84
+ source: 'test',
85
+ projectRoot: '/irrelevant',
86
+ },
87
+ ]),
88
+ ], new DatasetLoader_1.DatasetLoader(dataset), SINGLE_ROOT);
89
+ strict_1.default.deepEqual(await nonMatching.scan({ scanDir: '/irrelevant' }), []);
90
+ });
91
+ (0, node_test_1.test)('merges results across multiple applicable detectors', async () => {
92
+ const scanner = new Scanner_1.Scanner([
93
+ fakeDetector([
94
+ {
95
+ ecosystem: 'maven',
96
+ coordinate: 'com.example:lib',
97
+ version: '1.0.0',
98
+ source: 'test',
99
+ projectRoot: '/irrelevant',
100
+ },
101
+ ]),
102
+ fakeDetector([
103
+ {
104
+ ecosystem: 'npm',
105
+ coordinate: 'left-pad',
106
+ version: '1.0.0',
107
+ source: 'test',
108
+ projectRoot: '/irrelevant',
109
+ },
110
+ ]),
111
+ ], new DatasetLoader_1.DatasetLoader(dataset), SINGLE_ROOT);
112
+ const findings = await scanner.scan({ scanDir: '/irrelevant' });
113
+ strict_1.default.deepEqual(findings.map((f) => f.cve.id).sort(), ['CVE-1', 'CVE-2']);
114
+ });
115
+ (0, node_test_1.test)('merges results across multiple discovered project roots in a monorepo', async () => {
116
+ // A detector that only "sees" its own project's artifact, keyed by the root it was invoked with.
117
+ const detector = {
118
+ ecosystem: 'npm',
119
+ isApplicable: async () => true,
120
+ detect: async (options) => {
121
+ if (options.scanDir === '/monorepo/backend') {
122
+ return [
123
+ {
124
+ ecosystem: 'maven',
125
+ coordinate: 'com.example:lib',
126
+ version: '1.0.0',
127
+ source: 'test',
128
+ projectRoot: options.scanDir,
129
+ },
130
+ ];
131
+ }
132
+ if (options.scanDir === '/monorepo/frontend') {
133
+ return [
134
+ {
135
+ ecosystem: 'npm',
136
+ coordinate: 'left-pad',
137
+ version: '1.0.0',
138
+ source: 'test',
139
+ projectRoot: options.scanDir,
140
+ },
141
+ ];
142
+ }
143
+ return [];
144
+ },
145
+ };
146
+ const scanner = new Scanner_1.Scanner([detector], new DatasetLoader_1.DatasetLoader(dataset), () => [
147
+ '/monorepo/backend',
148
+ '/monorepo/frontend',
149
+ ]);
150
+ const findings = await scanner.scan({ scanDir: '/monorepo' });
151
+ strict_1.default.deepEqual(findings.map((f) => f.cve.id).sort(), ['CVE-1', 'CVE-2']);
152
+ strict_1.default.deepEqual(findings.map((f) => f.artifact.projectRoot).sort(), [
153
+ '/monorepo/backend',
154
+ '/monorepo/frontend',
155
+ ]);
156
+ });
157
+ //# sourceMappingURL=Scanner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Scanner.test.js","sourceRoot":"","sources":["../../src/core/Scanner.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Minimal, dependency-free version ordering: not a full semver implementation,
3
+ * just consistent enough to compare the start/end bounds in a VulnerableEntry
4
+ * against a detected artifact's version. See specs/20-data-format.md.
5
+ */
6
+ export declare function compareVersions(a: string, b: string): number;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.compareVersions = compareVersions;
4
+ function segments(version) {
5
+ return version.split(/[.-]/).filter((s) => s.length > 0);
6
+ }
7
+ /**
8
+ * Minimal, dependency-free version ordering: not a full semver implementation,
9
+ * just consistent enough to compare the start/end bounds in a VulnerableEntry
10
+ * against a detected artifact's version. See specs/20-data-format.md.
11
+ */
12
+ function compareVersions(a, b) {
13
+ const segA = segments(a);
14
+ const segB = segments(b);
15
+ const len = Math.max(segA.length, segB.length);
16
+ for (let i = 0; i < len; i++) {
17
+ if (i >= segA.length)
18
+ return -1;
19
+ if (i >= segB.length)
20
+ return 1;
21
+ const sa = segA[i];
22
+ const sb = segB[i];
23
+ const na = Number(sa);
24
+ const nb = Number(sb);
25
+ if (!Number.isNaN(na) && !Number.isNaN(nb)) {
26
+ if (na !== nb)
27
+ return na < nb ? -1 : 1;
28
+ }
29
+ else if (sa !== sb) {
30
+ return sa < sb ? -1 : 1;
31
+ }
32
+ }
33
+ return 0;
34
+ }
35
+ //# sourceMappingURL=VersionComparator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VersionComparator.js","sourceRoot":"","sources":["../../src/core/VersionComparator.ts"],"names":[],"mappings":";;;AAAA,SAAS,QAAQ,CAAC,OAAe;IAC/B,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,yBAAgC,CAAS,EAAE,CAAS;IAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAE/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,CAAC;QAE/B,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACtB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QAEtB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3C,IAAI,EAAE,KAAK,EAAE;gBAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;aAAM,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACrB,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_test_1 = require("node:test");
8
+ const VersionComparator_1 = require("./VersionComparator");
9
+ (0, node_test_1.test)('compares numeric segments numerically', () => {
10
+ strict_1.default.equal((0, VersionComparator_1.compareVersions)('2.9.8', '2.9.9'), -1);
11
+ strict_1.default.equal((0, VersionComparator_1.compareVersions)('2.10.0', '2.9.9'), 1);
12
+ strict_1.default.equal((0, VersionComparator_1.compareVersions)('1.0.0', '1.0.0'), 0);
13
+ });
14
+ (0, node_test_1.test)('a version with fewer segments is less than one with more', () => {
15
+ strict_1.default.equal((0, VersionComparator_1.compareVersions)('1.2', '1.2.1'), -1);
16
+ strict_1.default.equal((0, VersionComparator_1.compareVersions)('1.2.1', '1.2'), 1);
17
+ });
18
+ (0, node_test_1.test)('treats hyphenated qualifiers as extra segments', () => {
19
+ strict_1.default.equal((0, VersionComparator_1.compareVersions)('2.15.0', '2.0'), 1);
20
+ });
21
+ //# sourceMappingURL=VersionComparator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VersionComparator.test.js","sourceRoot":"","sources":["../../src/core/VersionComparator.test.ts"],"names":[],"mappings":";;;;;AAAA,gEAAwC;AACxC,yCAAiC;AACjC,2DAAsD;AAEtD,IAAA,gBAAI,EAAC,uCAAuC,EAAE,GAAG,EAAE;IACjD,gBAAM,CAAC,KAAK,CAAC,IAAA,mCAAe,EAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpD,gBAAM,CAAC,KAAK,CAAC,IAAA,mCAAe,EAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,gBAAM,CAAC,KAAK,CAAC,IAAA,mCAAe,EAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,0DAA0D,EAAE,GAAG,EAAE;IACpE,gBAAM,CAAC,KAAK,CAAC,IAAA,mCAAe,EAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAClD,gBAAM,CAAC,KAAK,CAAC,IAAA,mCAAe,EAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,gDAAgD,EAAE,GAAG,EAAE;IAC1D,gBAAM,CAAC,KAAK,CAAC,IAAA,mCAAe,EAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { Ecosystem } from './types';
2
+ /**
3
+ * "maven" and "gradle" detected artifacts are matched against the same pool
4
+ * of entries (both consume the same Maven Central coordinate space) — only
5
+ * "maven" is ever used as a storage/lookup key. See specs/20-data-format.md.
6
+ */
7
+ export declare function datasetEcosystem(ecosystem: Ecosystem): 'maven' | 'npm';
8
+ export declare function buildCpe(ecosystem: Ecosystem, coordinate: string): string;
9
+ export declare function vendorProductFromCpe(cpe: string): string;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.datasetEcosystem = datasetEcosystem;
4
+ exports.buildCpe = buildCpe;
5
+ exports.vendorProductFromCpe = vendorProductFromCpe;
6
+ /**
7
+ * "maven" and "gradle" detected artifacts are matched against the same pool
8
+ * of entries (both consume the same Maven Central coordinate space) — only
9
+ * "maven" is ever used as a storage/lookup key. See specs/20-data-format.md.
10
+ */
11
+ function datasetEcosystem(ecosystem) {
12
+ return ecosystem === 'npm' ? 'npm' : 'maven';
13
+ }
14
+ /**
15
+ * `coordinate` is "groupId:artifactId" for maven/gradle, or just the package
16
+ * name for npm (which has no vendor/product split).
17
+ */
18
+ function vendorProduct(ecosystem, coordinate) {
19
+ if (datasetEcosystem(ecosystem) === 'npm')
20
+ return [coordinate, coordinate];
21
+ const [vendor, product] = coordinate.split(':');
22
+ return [vendor, product];
23
+ }
24
+ function buildCpe(ecosystem, coordinate) {
25
+ const [vendor, product] = vendorProduct(ecosystem, coordinate);
26
+ return `cpe:2.3:a:${vendor.toLowerCase()}:${product.toLowerCase()}:*:*:*:*:*:*:*:*`;
27
+ }
28
+ function vendorProductFromCpe(cpe) {
29
+ const parts = cpe.split(':');
30
+ return `${parts[3]}:${parts[4]}`;
31
+ }
32
+ //# sourceMappingURL=cpe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cpe.js","sourceRoot":"","sources":["../../src/core/cpe.ts"],"names":[],"mappings":";;;;;AAEA;;;;GAIG;AACH,0BAAiC,SAAoB;IACnD,OAAO,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CACpB,SAAoB,EACpB,UAAkB;IAElB,IAAI,gBAAgB,CAAC,SAAS,CAAC,KAAK,KAAK;QAAE,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAC3E,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChD,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC3B,CAAC;AAED,kBAAyB,SAAoB,EAAE,UAAkB;IAC/D,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC/D,OAAO,aAAa,MAAM,CAAC,WAAW,EAAE,IAAI,OAAO,CAAC,WAAW,EAAE,kBAAkB,CAAC;AACtF,CAAC;AAED,8BAAqC,GAAW;IAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_test_1 = require("node:test");
8
+ const cpe_1 = require("./cpe");
9
+ (0, node_test_1.test)('maven/gradle coordinates split into vendor:product directly', () => {
10
+ strict_1.default.equal((0, cpe_1.buildCpe)('maven', 'com.example:lib'), 'cpe:2.3:a:com.example:lib:*:*:*:*:*:*:*:*');
11
+ strict_1.default.equal((0, cpe_1.buildCpe)('gradle', 'com.example:lib'), 'cpe:2.3:a:com.example:lib:*:*:*:*:*:*:*:*');
12
+ });
13
+ (0, node_test_1.test)('npm coordinates use the package name as both vendor and product', () => {
14
+ strict_1.default.equal((0, cpe_1.buildCpe)('npm', 'lodash'), 'cpe:2.3:a:lodash:lodash:*:*:*:*:*:*:*:*');
15
+ });
16
+ (0, node_test_1.test)('vendorProductFromCpe is the inverse of buildCpe', () => {
17
+ const cpe = (0, cpe_1.buildCpe)('maven', 'com.example:lib');
18
+ strict_1.default.equal((0, cpe_1.vendorProductFromCpe)(cpe), 'com.example:lib');
19
+ });
20
+ (0, node_test_1.test)('gradle aliases to maven for dataset lookup purposes', () => {
21
+ strict_1.default.equal((0, cpe_1.datasetEcosystem)('gradle'), 'maven');
22
+ strict_1.default.equal((0, cpe_1.datasetEcosystem)('maven'), 'maven');
23
+ strict_1.default.equal((0, cpe_1.datasetEcosystem)('npm'), 'npm');
24
+ });
25
+ //# sourceMappingURL=cpe.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cpe.test.js","sourceRoot":"","sources":["../../src/core/cpe.test.ts"],"names":[],"mappings":";;;;;AAAA,gEAAwC;AACxC,yCAAiC;AACjC,+BAAyE;AAEzE,IAAA,gBAAI,EAAC,6DAA6D,EAAE,GAAG,EAAE;IACvE,gBAAM,CAAC,KAAK,CACV,IAAA,cAAQ,EAAC,OAAO,EAAE,iBAAiB,CAAC,EACpC,2CAA2C,CAC5C,CAAC;IACF,gBAAM,CAAC,KAAK,CACV,IAAA,cAAQ,EAAC,QAAQ,EAAE,iBAAiB,CAAC,EACrC,2CAA2C,CAC5C,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,iEAAiE,EAAE,GAAG,EAAE;IAC3E,gBAAM,CAAC,KAAK,CACV,IAAA,cAAQ,EAAC,KAAK,EAAE,QAAQ,CAAC,EACzB,yCAAyC,CAC1C,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,iDAAiD,EAAE,GAAG,EAAE;IAC3D,MAAM,GAAG,GAAG,IAAA,cAAQ,EAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;IACjD,gBAAM,CAAC,KAAK,CAAC,IAAA,0BAAoB,EAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC,CAAC;AAC7D,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,qDAAqD,EAAE,GAAG,EAAE;IAC/D,gBAAM,CAAC,KAAK,CAAC,IAAA,sBAAgB,EAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;IAClD,gBAAM,CAAC,KAAK,CAAC,IAAA,sBAAgB,EAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IACjD,gBAAM,CAAC,KAAK,CAAC,IAAA,sBAAgB,EAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,57 @@
1
+ export type Ecosystem = 'maven' | 'gradle' | 'npm';
2
+ export interface ScanOptions {
3
+ scanDir: string;
4
+ cveDataDir?: string;
5
+ }
6
+ export interface DetectedArtifact {
7
+ ecosystem: Ecosystem;
8
+ coordinate: string;
9
+ version: string;
10
+ source: string;
11
+ projectRoot: string;
12
+ }
13
+ export interface Detector {
14
+ readonly ecosystem: Ecosystem;
15
+ isApplicable(options: ScanOptions): Promise<boolean>;
16
+ detect(options: ScanOptions): Promise<DetectedArtifact[]>;
17
+ }
18
+ export interface Cve {
19
+ id: string;
20
+ score: number;
21
+ title: string;
22
+ }
23
+ export interface VulnerableEntry {
24
+ ecosystem: Ecosystem;
25
+ cpe: string;
26
+ versionStartIncluding?: string;
27
+ versionStartExcluding?: string;
28
+ versionEndIncluding?: string;
29
+ versionEndExcluding?: string;
30
+ versionExact?: string;
31
+ cves: Cve[];
32
+ }
33
+ export interface VulnerabilityDataset {
34
+ generatedAt: string;
35
+ entries: VulnerableEntry[];
36
+ }
37
+ export interface CveEnrichment {
38
+ description: string;
39
+ cvssVector?: string;
40
+ cwe?: string[];
41
+ references: string[];
42
+ }
43
+ export interface ProjectManifest {
44
+ fileName: string;
45
+ content: string;
46
+ }
47
+ export interface Finding {
48
+ artifact: DetectedArtifact;
49
+ cve: Cve;
50
+ enrichment?: CveEnrichment;
51
+ projectManifest?: ProjectManifest;
52
+ aiAnalysis?: string;
53
+ }
54
+ export interface ScanResult {
55
+ datasetGeneratedAt: string;
56
+ findings: Finding[];
57
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ export declare function cacheRootDir(): string;
2
+ /**
3
+ * Pure (given the marker's mtime as input): is the cache under `cacheRoot`
4
+ * still within the 12-hour TTL? See specs/80-cve-enrichment.md.
5
+ */
6
+ export declare function isCacheFresh(cacheRoot: string, now?: number): boolean;
7
+ /**
8
+ * Downloads and extracts the full CVE List (https://github.com/CVEProject/cvelistV5)
9
+ * into a 12-hour-TTL local cache, reusing it across runs when still fresh.
10
+ * Returns the directory to use as --cve-data-dir (the one containing cves/).
11
+ * See specs/80-cve-enrichment.md.
12
+ */
13
+ export declare function ensureCveListCache(): Promise<string>;