@securecode-ai/mcp 0.2.1 → 0.3.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 (52) hide show
  1. package/dist/dependency/depCache.d.ts +22 -0
  2. package/dist/dependency/depCache.js +115 -0
  3. package/dist/dependency/depCache.js.map +1 -0
  4. package/dist/dependency/dependencyChecker.d.ts +48 -0
  5. package/dist/dependency/dependencyChecker.js +196 -0
  6. package/dist/dependency/dependencyChecker.js.map +1 -0
  7. package/dist/dependency/finding.d.ts +42 -0
  8. package/dist/dependency/finding.js +13 -0
  9. package/dist/dependency/finding.js.map +1 -0
  10. package/dist/dependency/licensePolicy.d.ts +56 -0
  11. package/dist/dependency/licensePolicy.js +109 -0
  12. package/dist/dependency/licensePolicy.js.map +1 -0
  13. package/dist/dependency/minSafeVersion.d.ts +32 -0
  14. package/dist/dependency/minSafeVersion.js +125 -0
  15. package/dist/dependency/minSafeVersion.js.map +1 -0
  16. package/dist/dependency/osvClient.d.ts +45 -0
  17. package/dist/dependency/osvClient.js +452 -0
  18. package/dist/dependency/osvClient.js.map +1 -0
  19. package/dist/dependency/parsers/npm.d.ts +13 -0
  20. package/dist/dependency/parsers/npm.js +160 -0
  21. package/dist/dependency/parsers/npm.js.map +1 -0
  22. package/dist/dependency/parsers/pipfile.d.ts +8 -0
  23. package/dist/dependency/parsers/pipfile.js +110 -0
  24. package/dist/dependency/parsers/pipfile.js.map +1 -0
  25. package/dist/dependency/parsers/pnpm.d.ts +11 -0
  26. package/dist/dependency/parsers/pnpm.js +148 -0
  27. package/dist/dependency/parsers/pnpm.js.map +1 -0
  28. package/dist/dependency/parsers/requirements.d.ts +24 -0
  29. package/dist/dependency/parsers/requirements.js +153 -0
  30. package/dist/dependency/parsers/requirements.js.map +1 -0
  31. package/dist/dependency/parsers/yarn.d.ts +10 -0
  32. package/dist/dependency/parsers/yarn.js +153 -0
  33. package/dist/dependency/parsers/yarn.js.map +1 -0
  34. package/dist/dependency/resolver.d.ts +28 -0
  35. package/dist/dependency/resolver.js +159 -0
  36. package/dist/dependency/resolver.js.map +1 -0
  37. package/dist/dependency/types.d.ts +85 -0
  38. package/dist/dependency/types.js +11 -0
  39. package/dist/dependency/types.js.map +1 -0
  40. package/dist/mcp/server.js +2 -0
  41. package/dist/mcp/server.js.map +1 -1
  42. package/dist/mcp/tools.js +8 -0
  43. package/dist/mcp/tools.js.map +1 -1
  44. package/dist/project-map/sinkFinder.js +41 -0
  45. package/dist/project-map/sinkFinder.js.map +1 -1
  46. package/dist/project-map/sinkRegistry.d.ts +8 -0
  47. package/dist/project-map/sinkRegistry.js +145 -0
  48. package/dist/project-map/sinkRegistry.js.map +1 -1
  49. package/dist/tools/scanDependencies.d.ts +11 -0
  50. package/dist/tools/scanDependencies.js +37 -0
  51. package/dist/tools/scanDependencies.js.map +1 -0
  52. package/package.json +9 -2
@@ -0,0 +1,22 @@
1
+ import { CacheStore } from './finding';
2
+ /**
3
+ * A file-backed CacheStore. Loads the cache file lazily on first `get`,
4
+ * buffers updates in memory, and flushes to disk atomically on each
5
+ * `update`. Safe for the single-threaded MCP server; not safe for
6
+ * concurrent processes writing the same file.
7
+ */
8
+ export declare class FileCacheStore implements CacheStore {
9
+ private workspaceRoot;
10
+ private cachePath;
11
+ private loaded;
12
+ private dirty;
13
+ constructor(workspaceRoot: string);
14
+ private load;
15
+ get<T>(key: string): T | undefined;
16
+ update(key: string, value: unknown): void;
17
+ /**
18
+ * Write the cache to disk atomically (.tmp + rename). Called after
19
+ * each `update` so a crash never loses more than the last entry.
20
+ */
21
+ private flush;
22
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.FileCacheStore = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ /**
40
+ * File-based NVD CVSS cache for the MCP server.
41
+ *
42
+ * The extension uses `vscode.Memento` (workspaceState) for this. The MCP
43
+ * server has no VS Code API, so we store the cache as a JSON file at
44
+ * `.securecode/nvd-cache.json` inside the workspace root.
45
+ *
46
+ * Implements the `CacheStore` interface ({ get, update }) that
47
+ * `enrichWithNvd` expects.
48
+ */
49
+ const CACHE_DIR = '.securecode';
50
+ const CACHE_FILE = 'nvd-cache.json';
51
+ const SCHEMA_VERSION = 1;
52
+ /**
53
+ * A file-backed CacheStore. Loads the cache file lazily on first `get`,
54
+ * buffers updates in memory, and flushes to disk atomically on each
55
+ * `update`. Safe for the single-threaded MCP server; not safe for
56
+ * concurrent processes writing the same file.
57
+ */
58
+ class FileCacheStore {
59
+ workspaceRoot;
60
+ cachePath;
61
+ loaded = null;
62
+ dirty = false;
63
+ constructor(workspaceRoot) {
64
+ this.workspaceRoot = workspaceRoot;
65
+ this.cachePath = path.join(workspaceRoot, CACHE_DIR, CACHE_FILE);
66
+ }
67
+ load() {
68
+ if (this.loaded)
69
+ return this.loaded;
70
+ try {
71
+ if (fs.existsSync(this.cachePath)) {
72
+ const raw = fs.readFileSync(this.cachePath, 'utf8');
73
+ const parsed = JSON.parse(raw);
74
+ if (parsed.version === SCHEMA_VERSION && parsed.entries) {
75
+ this.loaded = parsed;
76
+ return this.loaded;
77
+ }
78
+ }
79
+ }
80
+ catch { /* file corrupt or missing — start fresh */ }
81
+ this.loaded = { version: SCHEMA_VERSION, entries: {} };
82
+ return this.loaded;
83
+ }
84
+ get(key) {
85
+ const cache = this.load();
86
+ return cache.entries[key];
87
+ }
88
+ update(key, value) {
89
+ const cache = this.load();
90
+ cache.entries[key] = value;
91
+ this.dirty = true;
92
+ this.flush();
93
+ }
94
+ /**
95
+ * Write the cache to disk atomically (.tmp + rename). Called after
96
+ * each `update` so a crash never loses more than the last entry.
97
+ */
98
+ flush() {
99
+ if (!this.dirty || !this.loaded)
100
+ return;
101
+ try {
102
+ const dir = path.join(this.workspaceRoot, CACHE_DIR);
103
+ if (!fs.existsSync(dir)) {
104
+ fs.mkdirSync(dir, { recursive: true });
105
+ }
106
+ const tmp = this.cachePath + '.tmp';
107
+ fs.writeFileSync(tmp, JSON.stringify(this.loaded, null, 2), 'utf8');
108
+ fs.renameSync(tmp, this.cachePath);
109
+ this.dirty = false;
110
+ }
111
+ catch { /* best effort — cache is optional */ }
112
+ }
113
+ }
114
+ exports.FileCacheStore = FileCacheStore;
115
+ //# sourceMappingURL=depCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"depCache.js","sourceRoot":"","sources":["../../src/dependency/depCache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { ScanFinding, CacheStore } from './finding';
2
+ import { ResolvedPackage, Vulnerability } from './types';
3
+ import { LicensePolicyMode } from './licensePolicy';
4
+ export interface DependencyScanOptions {
5
+ /** Workspace root to scan recursively for lockfiles. */
6
+ workspaceRoot: string;
7
+ /** VS Code memento (workspaceState) for NVD CVSS caching. */
8
+ state: CacheStore;
9
+ /** License policy mode (off | warn | error). Default 'warn'. */
10
+ licensePolicy?: LicensePolicyMode;
11
+ /** Whether to also query GitHub Advisory via `gh` CLI. Default true (skips gracefully if gh absent). */
12
+ useGhsa?: boolean;
13
+ }
14
+ export interface DependencyScanResult {
15
+ /** ScanFinding-shaped records (source: 'dependency'), ready for the unified panel. */
16
+ findings: ScanFinding[];
17
+ /** Raw matched vulnerabilities keyed by `${ecosystem}:${name}@${version}` (for diagnostics). */
18
+ matches: Map<string, Vulnerability[]>;
19
+ /** Number of packages scanned (excluding unresolved). */
20
+ packageCount: number;
21
+ /** Number of packages marked unresolved (unpinned requirements.txt, etc.). */
22
+ unresolvedCount: number;
23
+ /** Parsed lockfile paths. */
24
+ lockfiles: string[];
25
+ /** All resolved packages (for Apply affordance lookups). */
26
+ packages: ResolvedPackage[];
27
+ /** True when GHSA enrichment was skipped because `gh` is not installed. */
28
+ ghsaSkipped?: boolean;
29
+ }
30
+ /**
31
+ * Run the full dependency vulnerability check.
32
+ *
33
+ * Pipeline:
34
+ * 1. Find lockfiles in the workspace.
35
+ * 2. Parse each one (returns the full resolved transitive tree).
36
+ * 3. Resolve + dedupe across lockfiles (npm-family collapses; pip-family collapses).
37
+ * 4. Batch-query OSV.dev (name + version only — no source code leaves the machine).
38
+ * 5. Optionally enrich with GHSA via `gh` CLI (graceful skip if absent).
39
+ * 6. Fill in missing CVSS via NVD (24h workspaceState cache).
40
+ * 7. Compute min-safe-version for each matched vulnerable package.
41
+ * 8. Run license policy check (default 'warn') against the project license.
42
+ * 9. Produce ScanFinding[] records with source: 'dependency' and a
43
+ * dependency{...} block carrying everything the Apply affordance needs.
44
+ *
45
+ * No AI calls, no API changes. OSV and NVD are the only network egress, and
46
+ * only package names + versions go to them.
47
+ */
48
+ export declare function scanDependencies(opts: DependencyScanOptions): Promise<DependencyScanResult>;
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scanDependencies = scanDependencies;
4
+ const resolver_1 = require("./resolver");
5
+ const osvClient_1 = require("./osvClient");
6
+ const minSafeVersion_1 = require("./minSafeVersion");
7
+ const licensePolicy_1 = require("./licensePolicy");
8
+ /**
9
+ * Run the full dependency vulnerability check.
10
+ *
11
+ * Pipeline:
12
+ * 1. Find lockfiles in the workspace.
13
+ * 2. Parse each one (returns the full resolved transitive tree).
14
+ * 3. Resolve + dedupe across lockfiles (npm-family collapses; pip-family collapses).
15
+ * 4. Batch-query OSV.dev (name + version only — no source code leaves the machine).
16
+ * 5. Optionally enrich with GHSA via `gh` CLI (graceful skip if absent).
17
+ * 6. Fill in missing CVSS via NVD (24h workspaceState cache).
18
+ * 7. Compute min-safe-version for each matched vulnerable package.
19
+ * 8. Run license policy check (default 'warn') against the project license.
20
+ * 9. Produce ScanFinding[] records with source: 'dependency' and a
21
+ * dependency{...} block carrying everything the Apply affordance needs.
22
+ *
23
+ * No AI calls, no API changes. OSV and NVD are the only network egress, and
24
+ * only package names + versions go to them.
25
+ */
26
+ async function scanDependencies(opts) {
27
+ const policy = opts.licensePolicy ?? 'warn';
28
+ const useGhsa = opts.useGhsa !== false;
29
+ // Map an Ecosystem to its OSV family name. npm-family collapses to 'npm',
30
+ // pip-family collapses to 'PyPI'.
31
+ const ecosystemFamilyOf = (e) => e === 'pip' || e === 'pipenv' ? 'PyPI' : 'npm';
32
+ // 1. Find lockfiles.
33
+ const found = (0, resolver_1.findLockfiles)(opts.workspaceRoot);
34
+ const lockfilePaths = [
35
+ ...found.npm, ...found.yarn, ...found.pnpm, ...found.pipenv, ...found.pip,
36
+ ];
37
+ // 2. Parse.
38
+ const parsed = lockfilePaths
39
+ .map(resolver_1.parseLockfile)
40
+ .filter((p) => p !== null);
41
+ // 3. Resolve + dedupe.
42
+ const packages = (0, resolver_1.resolveAll)(parsed);
43
+ const unresolved = packages.filter(p => p.unresolved);
44
+ const queryable = packages.filter(p => !p.unresolved);
45
+ // 4. OSV batch.
46
+ const osvMap = await (0, osvClient_1.queryOsvBatch)(queryable);
47
+ // 5. GHSA via REST API (best-effort enrichment).
48
+ // Only query packages that OSV flagged as vulnerable — GHSA is an
49
+ // enrichment source, not a primary source. This keeps the request
50
+ // count low (typically 5-30 packages) and within the 60 req/hr
51
+ // unauthenticated GitHub rate limit.
52
+ let ghsaMap = new Map();
53
+ let ghsaSkipped = false;
54
+ if (useGhsa) {
55
+ // Collect packages that OSV found vulnerabilities for.
56
+ const osvFlagged = queryable.filter(p => {
57
+ const fam = ecosystemFamilyOf(p.ecosystem);
58
+ const key = `${fam}:${p.name}@${p.version}`;
59
+ return osvMap.has(key);
60
+ });
61
+ if (osvFlagged.length > 0) {
62
+ if (await (0, osvClient_1.ghCliAvailable)()) {
63
+ try {
64
+ ghsaMap = await (0, osvClient_1.queryGhsaViaCli)(osvFlagged);
65
+ }
66
+ catch {
67
+ // ignore — OSV data already includes GHSA records most of the time.
68
+ }
69
+ }
70
+ else {
71
+ ghsaSkipped = true;
72
+ }
73
+ }
74
+ }
75
+ // 6. Merge OSV + GHSA per package key, dedupe by vuln id.
76
+ const matches = new Map();
77
+ const allKeys = new Set([...osvMap.keys(), ...ghsaMap.keys()]);
78
+ for (const key of allKeys) {
79
+ const osvList = osvMap.get(key) || [];
80
+ const ghsaList = ghsaMap.get(key) || [];
81
+ const merged = [];
82
+ const seenIds = new Set();
83
+ for (const v of [...osvList, ...ghsaList]) {
84
+ if (seenIds.has(v.id))
85
+ continue;
86
+ seenIds.add(v.id);
87
+ merged.push(v);
88
+ }
89
+ // NVD enrichment (cached).
90
+ await (0, osvClient_1.enrichWithNvd)(merged, opts.state);
91
+ matches.set(key, merged);
92
+ }
93
+ // 7. Compute min-safe-version and build vulnerability findings.
94
+ const findings = [];
95
+ // For each package with vulnerabilities, produce ONE rolled-up finding
96
+ // (not one per CVE) to keep the sidebar readable. The dependency block
97
+ // carries the worst CVE id + the min-safe-version; the message carries
98
+ // the upgrade suggestion.
99
+ // Sort: highest CVSS first so the most severe is the "rolled-up" id.
100
+ for (const pkg of queryable) {
101
+ const fam = ecosystemFamilyOf(pkg.ecosystem);
102
+ const key = `${fam}:${pkg.name}@${pkg.version}`;
103
+ const vulns = matches.get(key);
104
+ if (!vulns || vulns.length === 0)
105
+ continue;
106
+ const sortedVulns = vulns.slice().sort((a, b) => (b.cvssScore ?? 0) - (a.cvssScore ?? 0));
107
+ const worst = sortedVulns[0];
108
+ const minSafe = (0, minSafeVersion_1.computeMinSafeVersion)(pkg, sortedVulns);
109
+ const severity = (worst.cvssScore ?? 0) >= 7 ? 'ERROR' : 'WARNING';
110
+ const vulnCount = sortedVulns.length;
111
+ const cveList = sortedVulns.map(v => v.id).slice(0, 5).join(', ');
112
+ const message = minSafe
113
+ ? `${(0, minSafeVersion_1.upgradeSuggestion)(pkg, minSafe)} — ${vulnCount} vulnerable ${vulnCount === 1 ? 'advisory' : 'advisories'}: ${cveList}`
114
+ : `${pkg.name}@${pkg.version} has ${vulnCount} vulnerable ${vulnCount === 1 ? 'advisory' : 'advisories'} with NO known fix: ${cveList}`;
115
+ findings.push({
116
+ check_id: `dep.${worst.id}`,
117
+ severity,
118
+ message,
119
+ start: { line: 1, col: 1 },
120
+ end: { line: 1, col: 1 },
121
+ source: 'dependency',
122
+ dependency: {
123
+ ecosystem: pkg.ecosystem,
124
+ name: pkg.name,
125
+ installedVersion: pkg.version,
126
+ fixedVersion: minSafe,
127
+ license: pkg.license,
128
+ manifestPath: pkg.manifestPath,
129
+ unresolved: pkg.unresolved,
130
+ },
131
+ });
132
+ }
133
+ // Unresolved requirements.txt entries -> a single warning per package
134
+ // so the user knows why those weren't queried against OSV.
135
+ for (const pkg of unresolved) {
136
+ findings.push({
137
+ check_id: `dep.unresolved.${pkg.name}`,
138
+ severity: 'WARNING',
139
+ message: `Cannot resolve ${pkg.name} version from ${pkg.manifestPath || 'requirements'} (pin it with == or use a lockfile) — skipped from OSV scan`,
140
+ start: { line: 1, col: 1 },
141
+ end: { line: 1, col: 1 },
142
+ source: 'dependency',
143
+ dependency: {
144
+ ecosystem: pkg.ecosystem,
145
+ name: pkg.name,
146
+ installedVersion: pkg.version || '',
147
+ license: pkg.license,
148
+ manifestPath: pkg.manifestPath,
149
+ unresolved: true,
150
+ },
151
+ });
152
+ }
153
+ // 8. License policy.
154
+ // Use the most permissive-looking projectLicense discovered across lockfiles
155
+ // (the first one — typically package.json's). If there are multiple projects,
156
+ // license findings are produced per-package and the policy is conservative.
157
+ let projectLicense;
158
+ for (const lf of parsed) {
159
+ if (lf.projectLicense) {
160
+ projectLicense = lf.projectLicense;
161
+ break;
162
+ }
163
+ }
164
+ const licenseFindings = (0, licensePolicy_1.checkLicenses)(packages, projectLicense, policy);
165
+ for (const lf of licenseFindings) {
166
+ findings.push(licenseFindingToScanFinding(lf));
167
+ }
168
+ return {
169
+ findings,
170
+ matches,
171
+ packageCount: queryable.length,
172
+ unresolvedCount: unresolved.length,
173
+ lockfiles: lockfilePaths,
174
+ packages,
175
+ ...(ghsaSkipped ? { ghsaSkipped: true } : {}),
176
+ };
177
+ }
178
+ function licenseFindingToScanFinding(lf) {
179
+ return {
180
+ check_id: `dep.license.${lf.package.name}`,
181
+ severity: lf.severity === 'ERROR' ? 'ERROR' : 'WARNING',
182
+ message: lf.reason,
183
+ start: { line: 1, col: 1 },
184
+ end: { line: 1, col: 1 },
185
+ source: 'dependency',
186
+ dependency: {
187
+ ecosystem: lf.package.ecosystem,
188
+ name: lf.package.name,
189
+ installedVersion: lf.package.version,
190
+ license: lf.license,
191
+ manifestPath: lf.package.manifestPath,
192
+ unresolved: lf.package.unresolved,
193
+ },
194
+ };
195
+ }
196
+ //# sourceMappingURL=dependencyChecker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencyChecker.js","sourceRoot":"","sources":["../../src/dependency/dependencyChecker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Shared types for the MCP dependency scanner.
3
+ *
4
+ * ScanFinding is copied from the extension's apiClient.ts (line 74-97) to
5
+ * avoid importing that file, which drags in `axios` and `vscode` — neither
6
+ * available in the MCP server.
7
+ *
8
+ * CacheStore replaces the extension's `vscode.Memento` dependency. The MCP
9
+ * server implements this with a file-based cache (depCache.ts).
10
+ */
11
+ export interface ScanFinding {
12
+ check_id: string;
13
+ severity: 'ERROR' | 'WARNING';
14
+ message: string;
15
+ start: {
16
+ line: number;
17
+ col: number;
18
+ };
19
+ end: {
20
+ line: number;
21
+ col: number;
22
+ };
23
+ source?: 'code' | 'dependency';
24
+ dependency?: {
25
+ ecosystem: 'npm' | 'yarn' | 'pnpm' | 'pip' | 'pipenv';
26
+ name: string;
27
+ installedVersion: string;
28
+ fixedVersion?: string;
29
+ license?: string;
30
+ manifestPath?: string;
31
+ unresolved?: boolean;
32
+ };
33
+ }
34
+ /**
35
+ * Minimal cache interface — the only part of `vscode.Memento` the dependency
36
+ * checker uses (`get<T>(key)` and `update(key, value)`). The MCP server
37
+ * implements this with a file-based JSON cache (see depCache.ts).
38
+ */
39
+ export interface CacheStore {
40
+ get<T>(key: string): T | undefined;
41
+ update(key: string, value: unknown): Promise<void> | void;
42
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /**
3
+ * Shared types for the MCP dependency scanner.
4
+ *
5
+ * ScanFinding is copied from the extension's apiClient.ts (line 74-97) to
6
+ * avoid importing that file, which drags in `axios` and `vscode` — neither
7
+ * available in the MCP server.
8
+ *
9
+ * CacheStore replaces the extension's `vscode.Memento` dependency. The MCP
10
+ * server implements this with a file-based cache (depCache.ts).
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ //# sourceMappingURL=finding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding.js","sourceRoot":"","sources":["../../src/dependency/finding.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG"}
@@ -0,0 +1,56 @@
1
+ import { ResolvedPackage } from './types';
2
+ /**
3
+ * SPDX license policy.
4
+ *
5
+ * Default behavior (matching the `secureCode.licensePolicy` setting):
6
+ * - "off": no license findings are produced.
7
+ * "warn": produce a WARNING-severity finding for copyleft licenses
8
+ * (GPL/AGPL/LGPL/Mozilla/Eclipse/Commons-Clause/CC-BY-NC, etc.)
9
+ * in projects that look proprietary (no license field, or a
10
+ * non-OSI/non-copyleft license field).
11
+ * "error": same, but ERROR severity.
12
+ *
13
+ * The "looks proprietary" test is conservative: if the project's own
14
+ * `projectLicense` is missing or is a permissive/proprietary-ish license
15
+ * (MIT, ISC, Apache-2.0, BSD-*, UNLICENSED, proprietary, or absent), then
16
+ * a copyleft transitive dep is flagged. If the project itself is GPL,
17
+ * GPL deps are fine and not flagged.
18
+ */
19
+ export type LicensePolicyMode = 'off' | 'warn' | 'error';
20
+ export interface LicenseFinding {
21
+ package: ResolvedPackage;
22
+ /** SPDX license id (or the raw string if not SPDX-valid). */
23
+ license: string;
24
+ /** True when the license matches a copyleft/restrictive prefix. */
25
+ copyleft: boolean;
26
+ /** Why this package was flagged. */
27
+ reason: string;
28
+ /** Severity the caller should use. */
29
+ severity: 'ERROR' | 'WARNING' | 'INFO';
30
+ }
31
+ /**
32
+ * Project-level license classifier: does it look proprietary?
33
+ * - No license field -> yes (likely proprietary).
34
+ * - A permissive license (MIT, ISC, Apache-2.0, BSD, ...) -> yes (the
35
+ * presence of copyleft deps creates a conflict).
36
+ * - A copyleft license -> no (GPL deps in a GPL project are fine).
37
+ */
38
+ export declare function projectLooksProprietary(projectLicense: string | undefined): boolean;
39
+ /** Does a SPDX/license string match a copyleft/restrictive prefix? */
40
+ export declare function isCopyleft(license: string | undefined): boolean;
41
+ /**
42
+ * Produce license findings for copyleft dependencies under the configured policy.
43
+ *
44
+ * `projectLicense` is the project's own SPDX string (from package.json/Pipfile);
45
+ * undefined when not discoverable.
46
+ *
47
+ * Returns one LicenseFinding per copyleft package when:
48
+ * - policy !== 'off', AND
49
+ * - the project looks proprietary, AND
50
+ * - the package has a license string that matches a copyleft prefix.
51
+ *
52
+ * Packages with no license at all are NOT flagged here (we can't tell), and
53
+ * packages with non-copyleft licenses are not flagged. This is the
54
+ * GPL-in-a-commercial-project detector from the spec.
55
+ */
56
+ export declare function checkLicenses(packages: ResolvedPackage[], projectLicense: string | undefined, policy: LicensePolicyMode): LicenseFinding[];
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.projectLooksProprietary = projectLooksProprietary;
4
+ exports.isCopyleft = isCopyleft;
5
+ exports.checkLicenses = checkLicenses;
6
+ const spdxCorrect = require("spdx-correct");
7
+ /**
8
+ * Normalize a license string to a canonical SPDX id when possible.
9
+ * e.g. "GPLv3" -> "GPL-3.0-only", "Apache 2.0" -> "Apache-2.0".
10
+ * Returns the original string (trimmed) if spdx-correct can't normalize it,
11
+ * so the copyleft prefix matcher still gets a chance to flag obvious cases.
12
+ */
13
+ function normalizeSpdx(license) {
14
+ if (!license)
15
+ return undefined;
16
+ const trimmed = license.trim();
17
+ if (!trimmed)
18
+ return undefined;
19
+ try {
20
+ const corrected = spdxCorrect(trimmed);
21
+ return corrected || trimmed;
22
+ }
23
+ catch {
24
+ return trimmed;
25
+ }
26
+ }
27
+ /**
28
+ * Copyleft / restrictive SPDX identifiers (and well-known non-OSI ones)
29
+ * that we flag in proprietary-looking projects. Matched case-insensitively
30
+ * against the SPDX id's case-insensitive prefix.
31
+ */
32
+ const COPYLEFT_PREFIXES = [
33
+ 'GPL-', 'AGPL-', 'LGPL-', 'MPL-', 'EPL-', 'CDDL-', 'CPL-',
34
+ 'CC-BY-NC', 'CC-BY-SA', 'CC-BY-ND', 'COMMONS-CLAUSE',
35
+ 'BUSL-', 'SSPL-', 'RSAL-', 'JSON', 'EUPL-',
36
+ ];
37
+ /** Permissive / proprietary-looking licenses where a copyleft dep is flagged. */
38
+ const PERMISSIVE_OR_PROPRIETARY = new Set([
39
+ 'MIT', 'ISC', 'Apache-2.0', 'BSD-2-Clause', 'BSD-3-Clause', '0BSD',
40
+ 'Unlicense', 'UNLICENSED', 'SEE LICENSE IN LICENSE', 'SEE-LICENSE-IN-LICENSE',
41
+ 'PROPRIETARY', 'COMMERCIAL',
42
+ ]);
43
+ /**
44
+ * Project-level license classifier: does it look proprietary?
45
+ * - No license field -> yes (likely proprietary).
46
+ * - A permissive license (MIT, ISC, Apache-2.0, BSD, ...) -> yes (the
47
+ * presence of copyleft deps creates a conflict).
48
+ * - A copyleft license -> no (GPL deps in a GPL project are fine).
49
+ */
50
+ function projectLooksProprietary(projectLicense) {
51
+ const norm = normalizeSpdx(projectLicense);
52
+ if (!norm)
53
+ return true;
54
+ if (PERMISSIVE_OR_PROPRIETARY.has(norm.toUpperCase()))
55
+ return true;
56
+ // Copyleft-looking project license -> not proprietary.
57
+ const up = norm.toUpperCase();
58
+ if (COPYLEFT_PREFIXES.some(p => up.startsWith(p)))
59
+ return false;
60
+ // Anything else -> treat as proprietary to be safe.
61
+ return true;
62
+ }
63
+ /** Does a SPDX/license string match a copyleft/restrictive prefix? */
64
+ function isCopyleft(license) {
65
+ const norm = normalizeSpdx(license);
66
+ if (!norm)
67
+ return false;
68
+ const up = norm.toUpperCase();
69
+ return COPYLEFT_PREFIXES.some(p => up.startsWith(p));
70
+ }
71
+ /**
72
+ * Produce license findings for copyleft dependencies under the configured policy.
73
+ *
74
+ * `projectLicense` is the project's own SPDX string (from package.json/Pipfile);
75
+ * undefined when not discoverable.
76
+ *
77
+ * Returns one LicenseFinding per copyleft package when:
78
+ * - policy !== 'off', AND
79
+ * - the project looks proprietary, AND
80
+ * - the package has a license string that matches a copyleft prefix.
81
+ *
82
+ * Packages with no license at all are NOT flagged here (we can't tell), and
83
+ * packages with non-copyleft licenses are not flagged. This is the
84
+ * GPL-in-a-commercial-project detector from the spec.
85
+ */
86
+ function checkLicenses(packages, projectLicense, policy) {
87
+ if (policy === 'off')
88
+ return [];
89
+ if (!projectLooksProprietary(projectLicense))
90
+ return [];
91
+ const out = [];
92
+ const severity = policy === 'error' ? 'ERROR' : 'WARNING';
93
+ for (const p of packages) {
94
+ if (!p.license)
95
+ continue;
96
+ if (!isCopyleft(p.license))
97
+ continue;
98
+ const normalized = normalizeSpdx(p.license) || p.license;
99
+ out.push({
100
+ package: p,
101
+ license: normalized,
102
+ copyleft: true,
103
+ reason: `Copyleft license "${normalized}" on "${p.name}" conflicts with this project's ${projectLicense ? `"${projectLicense}"` : 'unspecified'} license.`,
104
+ severity,
105
+ });
106
+ }
107
+ return out;
108
+ }
109
+ //# sourceMappingURL=licensePolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"licensePolicy.js","sourceRoot":"","sources":["../../src/dependency/licensePolicy.ts"],"names":[],"mappings":"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"}