@ash-technologia/fathom 0.1.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/CHANGELOG.md +62 -0
- package/LICENSE +21 -0
- package/README.md +725 -0
- package/dist/analyzers/architecture/graph.d.ts +29 -0
- package/dist/analyzers/architecture/graph.d.ts.map +1 -0
- package/dist/analyzers/architecture/graph.js +347 -0
- package/dist/analyzers/architecture/graph.js.map +1 -0
- package/dist/analyzers/architecture/imports.d.ts +24 -0
- package/dist/analyzers/architecture/imports.d.ts.map +1 -0
- package/dist/analyzers/architecture/imports.js +155 -0
- package/dist/analyzers/architecture/imports.js.map +1 -0
- package/dist/analyzers/architecture/index.d.ts +13 -0
- package/dist/analyzers/architecture/index.d.ts.map +1 -0
- package/dist/analyzers/architecture/index.js +217 -0
- package/dist/analyzers/architecture/index.js.map +1 -0
- package/dist/analyzers/architecture/types.d.ts +65 -0
- package/dist/analyzers/architecture/types.d.ts.map +1 -0
- package/dist/analyzers/architecture/types.js +2 -0
- package/dist/analyzers/architecture/types.js.map +1 -0
- package/dist/analyzers/cicd/index.d.ts +11 -0
- package/dist/analyzers/cicd/index.d.ts.map +1 -0
- package/dist/analyzers/cicd/index.js +157 -0
- package/dist/analyzers/cicd/index.js.map +1 -0
- package/dist/analyzers/dependencies/index.d.ts +11 -0
- package/dist/analyzers/dependencies/index.d.ts.map +1 -0
- package/dist/analyzers/dependencies/index.js +403 -0
- package/dist/analyzers/dependencies/index.js.map +1 -0
- package/dist/analyzers/dependencies/lockfiles.d.ts +19 -0
- package/dist/analyzers/dependencies/lockfiles.d.ts.map +1 -0
- package/dist/analyzers/dependencies/lockfiles.js +172 -0
- package/dist/analyzers/dependencies/lockfiles.js.map +1 -0
- package/dist/analyzers/dependencies/online.d.ts +19 -0
- package/dist/analyzers/dependencies/online.d.ts.map +1 -0
- package/dist/analyzers/dependencies/online.js +116 -0
- package/dist/analyzers/dependencies/online.js.map +1 -0
- package/dist/analyzers/dependencies/types.d.ts +49 -0
- package/dist/analyzers/dependencies/types.d.ts.map +1 -0
- package/dist/analyzers/dependencies/types.js +2 -0
- package/dist/analyzers/dependencies/types.js.map +1 -0
- package/dist/analyzers/documentation/index.d.ts +11 -0
- package/dist/analyzers/documentation/index.d.ts.map +1 -0
- package/dist/analyzers/documentation/index.js +166 -0
- package/dist/analyzers/documentation/index.js.map +1 -0
- package/dist/analyzers/git/index.d.ts +11 -0
- package/dist/analyzers/git/index.d.ts.map +1 -0
- package/dist/analyzers/git/index.js +180 -0
- package/dist/analyzers/git/index.js.map +1 -0
- package/dist/analyzers/project/index.d.ts +11 -0
- package/dist/analyzers/project/index.d.ts.map +1 -0
- package/dist/analyzers/project/index.js +95 -0
- package/dist/analyzers/project/index.js.map +1 -0
- package/dist/analyzers/quality/index.d.ts +11 -0
- package/dist/analyzers/quality/index.d.ts.map +1 -0
- package/dist/analyzers/quality/index.js +198 -0
- package/dist/analyzers/quality/index.js.map +1 -0
- package/dist/analyzers/security/index.d.ts +11 -0
- package/dist/analyzers/security/index.d.ts.map +1 -0
- package/dist/analyzers/security/index.js +236 -0
- package/dist/analyzers/security/index.js.map +1 -0
- package/dist/analyzers/testing/index.d.ts +11 -0
- package/dist/analyzers/testing/index.d.ts.map +1 -0
- package/dist/analyzers/testing/index.js +134 -0
- package/dist/analyzers/testing/index.js.map +1 -0
- package/dist/baseline/baseline.d.ts +20 -0
- package/dist/baseline/baseline.d.ts.map +1 -0
- package/dist/baseline/baseline.js +134 -0
- package/dist/baseline/baseline.js.map +1 -0
- package/dist/baseline/compare.d.ts +14 -0
- package/dist/baseline/compare.d.ts.map +1 -0
- package/dist/baseline/compare.js +113 -0
- package/dist/baseline/compare.js.map +1 -0
- package/dist/baseline/types.d.ts +25 -0
- package/dist/baseline/types.d.ts.map +1 -0
- package/dist/baseline/types.js +2 -0
- package/dist/baseline/types.js.map +1 -0
- package/dist/cli/commands.d.ts +39 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +277 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +29 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/options.d.ts +55 -0
- package/dist/cli/options.d.ts.map +1 -0
- package/dist/cli/options.js +258 -0
- package/dist/cli/options.js.map +1 -0
- package/dist/core/analyzer.d.ts +33 -0
- package/dist/core/analyzer.d.ts.map +1 -0
- package/dist/core/analyzer.js +19 -0
- package/dist/core/analyzer.js.map +1 -0
- package/dist/core/context.d.ts +90 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +159 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/errors.d.ts +74 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +109 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/findings.d.ts +59 -0
- package/dist/core/findings.d.ts.map +1 -0
- package/dist/core/findings.js +34 -0
- package/dist/core/findings.js.map +1 -0
- package/dist/core/orchestrator.d.ts +44 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +160 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/result.d.ts +169 -0
- package/dist/core/result.d.ts.map +1 -0
- package/dist/core/result.js +2 -0
- package/dist/core/result.js.map +1 -0
- package/dist/detectors/framework.d.ts +22 -0
- package/dist/detectors/framework.d.ts.map +1 -0
- package/dist/detectors/framework.js +147 -0
- package/dist/detectors/framework.js.map +1 -0
- package/dist/detectors/language.d.ts +13 -0
- package/dist/detectors/language.d.ts.map +1 -0
- package/dist/detectors/language.js +100 -0
- package/dist/detectors/language.js.map +1 -0
- package/dist/detectors/package-manager.d.ts +17 -0
- package/dist/detectors/package-manager.d.ts.map +1 -0
- package/dist/detectors/package-manager.js +67 -0
- package/dist/detectors/package-manager.js.map +1 -0
- package/dist/detectors/project-type.d.ts +20 -0
- package/dist/detectors/project-type.d.ts.map +1 -0
- package/dist/detectors/project-type.js +48 -0
- package/dist/detectors/project-type.js.map +1 -0
- package/dist/diff/analyzer.d.ts +16 -0
- package/dist/diff/analyzer.d.ts.map +1 -0
- package/dist/diff/analyzer.js +296 -0
- package/dist/diff/analyzer.js.map +1 -0
- package/dist/diff/git-diff.d.ts +44 -0
- package/dist/diff/git-diff.d.ts.map +1 -0
- package/dist/diff/git-diff.js +256 -0
- package/dist/diff/git-diff.js.map +1 -0
- package/dist/diff/types.d.ts +75 -0
- package/dist/diff/types.d.ts.map +1 -0
- package/dist/diff/types.js +2 -0
- package/dist/diff/types.js.map +1 -0
- package/dist/integrations/github/context.d.ts +22 -0
- package/dist/integrations/github/context.d.ts.map +1 -0
- package/dist/integrations/github/context.js +115 -0
- package/dist/integrations/github/context.js.map +1 -0
- package/dist/integrations/github/types.d.ts +30 -0
- package/dist/integrations/github/types.d.ts.map +1 -0
- package/dist/integrations/github/types.js +2 -0
- package/dist/integrations/github/types.js.map +1 -0
- package/dist/plugins/context.d.ts +13 -0
- package/dist/plugins/context.d.ts.map +1 -0
- package/dist/plugins/context.js +102 -0
- package/dist/plugins/context.js.map +1 -0
- package/dist/plugins/examples/react.d.ts +8 -0
- package/dist/plugins/examples/react.d.ts.map +1 -0
- package/dist/plugins/examples/react.js +129 -0
- package/dist/plugins/examples/react.js.map +1 -0
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +4 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/registry.d.ts +45 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +236 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/types.d.ts +148 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +2 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/reporters/html.d.ts +11 -0
- package/dist/reporters/html.d.ts.map +1 -0
- package/dist/reporters/html.js +1352 -0
- package/dist/reporters/html.js.map +1 -0
- package/dist/reporters/json.d.ts +10 -0
- package/dist/reporters/json.d.ts.map +1 -0
- package/dist/reporters/json.js +11 -0
- package/dist/reporters/json.js.map +1 -0
- package/dist/reporters/markdown.d.ts +7 -0
- package/dist/reporters/markdown.d.ts.map +1 -0
- package/dist/reporters/markdown.js +74 -0
- package/dist/reporters/markdown.js.map +1 -0
- package/dist/reporters/sarif.d.ts +133 -0
- package/dist/reporters/sarif.d.ts.map +1 -0
- package/dist/reporters/sarif.js +268 -0
- package/dist/reporters/sarif.js.map +1 -0
- package/dist/reporters/terminal.d.ts +17 -0
- package/dist/reporters/terminal.d.ts.map +1 -0
- package/dist/reporters/terminal.js +423 -0
- package/dist/reporters/terminal.js.map +1 -0
- package/dist/rules/categories.d.ts +8 -0
- package/dist/rules/categories.d.ts.map +1 -0
- package/dist/rules/categories.js +23 -0
- package/dist/rules/categories.js.map +1 -0
- package/dist/rules/definitions.d.ts +25 -0
- package/dist/rules/definitions.d.ts.map +1 -0
- package/dist/rules/definitions.js +429 -0
- package/dist/rules/definitions.js.map +1 -0
- package/dist/rules/registry.d.ts +36 -0
- package/dist/rules/registry.d.ts.map +1 -0
- package/dist/rules/registry.js +64 -0
- package/dist/rules/registry.js.map +1 -0
- package/dist/rules/severity.d.ts +13 -0
- package/dist/rules/severity.d.ts.map +1 -0
- package/dist/rules/severity.js +15 -0
- package/dist/rules/severity.js.map +1 -0
- package/dist/scoring/confidence.d.ts +12 -0
- package/dist/scoring/confidence.d.ts.map +1 -0
- package/dist/scoring/confidence.js +22 -0
- package/dist/scoring/confidence.js.map +1 -0
- package/dist/scoring/score.d.ts +27 -0
- package/dist/scoring/score.d.ts.map +1 -0
- package/dist/scoring/score.js +81 -0
- package/dist/scoring/score.js.map +1 -0
- package/dist/scoring/weights.d.ts +11 -0
- package/dist/scoring/weights.d.ts.map +1 -0
- package/dist/scoring/weights.js +26 -0
- package/dist/scoring/weights.js.map +1 -0
- package/dist/utils/filesystem.d.ts +65 -0
- package/dist/utils/filesystem.d.ts.map +1 -0
- package/dist/utils/filesystem.js +299 -0
- package/dist/utils/filesystem.js.map +1 -0
- package/dist/utils/git.d.ts +47 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +125 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +25 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/paths.d.ts +30 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +48 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/timing.d.ts +12 -0
- package/dist/utils/timing.d.ts.map +1 -0
- package/dist/utils/timing.js +19 -0
- package/dist/utils/timing.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { createFindingId } from '../../core/findings.js';
|
|
3
|
+
import { createTimer } from '../../utils/timing.js';
|
|
4
|
+
import { readFileSafe } from '../../utils/filesystem.js';
|
|
5
|
+
import { extractRawSpecifiers } from '../architecture/imports.js';
|
|
6
|
+
import { parsePackageLockJson, parseYarnLock, parsePnpmLock, } from './lockfiles.js';
|
|
7
|
+
import { queryVulnerabilitiesOnline, checkOutdatedOnline } from './online.js';
|
|
8
|
+
/** Maps lockfile names to their expected package manager */
|
|
9
|
+
const LOCKFILE_TO_PM = {
|
|
10
|
+
'package-lock.json': 'npm',
|
|
11
|
+
'yarn.lock': 'yarn',
|
|
12
|
+
'pnpm-lock.yaml': 'pnpm',
|
|
13
|
+
};
|
|
14
|
+
/** Maps manifests to expected lockfiles */
|
|
15
|
+
const MANIFEST_TO_LOCKFILES = {
|
|
16
|
+
'package.json': ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml'],
|
|
17
|
+
Pipfile: ['Pipfile.lock'],
|
|
18
|
+
'pyproject.toml': ['poetry.lock'],
|
|
19
|
+
'Cargo.toml': ['Cargo.lock'],
|
|
20
|
+
'go.mod': ['go.sum'],
|
|
21
|
+
'composer.json': ['composer.lock'],
|
|
22
|
+
Gemfile: ['Gemfile.lock'],
|
|
23
|
+
};
|
|
24
|
+
/** Known build-time, CLI, or polyfill packages that are legitimately not directly imported in source code */
|
|
25
|
+
const RUNTIME_IGNORED_PACKAGES = new Set([
|
|
26
|
+
'tslib',
|
|
27
|
+
'core-js',
|
|
28
|
+
'dotenv',
|
|
29
|
+
'cross-env',
|
|
30
|
+
'concurrently',
|
|
31
|
+
'nodemon',
|
|
32
|
+
'husky',
|
|
33
|
+
'lint-staged',
|
|
34
|
+
'typescript',
|
|
35
|
+
'ts-node',
|
|
36
|
+
'tsx',
|
|
37
|
+
'vite',
|
|
38
|
+
'webpack',
|
|
39
|
+
'rollup',
|
|
40
|
+
'esbuild',
|
|
41
|
+
'eslint',
|
|
42
|
+
'prettier',
|
|
43
|
+
'vitest',
|
|
44
|
+
'jest',
|
|
45
|
+
]);
|
|
46
|
+
export class DependencyAnalyzer {
|
|
47
|
+
id = 'dependencies';
|
|
48
|
+
name = 'Dependencies';
|
|
49
|
+
category = 'dependencies';
|
|
50
|
+
description = 'Checks package manifests, lockfiles, duplicate versions, suspicious configurations, and dependency health.';
|
|
51
|
+
async analyze(context) {
|
|
52
|
+
const elapsed = createTimer();
|
|
53
|
+
const findings = [];
|
|
54
|
+
const warnings = [];
|
|
55
|
+
const rootFileSet = new Set(context.rootFilenames);
|
|
56
|
+
// 1. DEP-001: Manifest detection
|
|
57
|
+
const manifests = Object.keys(MANIFEST_TO_LOCKFILES).filter((m) => rootFileSet.has(m));
|
|
58
|
+
if (manifests.length === 0) {
|
|
59
|
+
findings.push({
|
|
60
|
+
id: createFindingId('DEP-001'),
|
|
61
|
+
ruleId: 'DEP-001',
|
|
62
|
+
category: 'dependencies',
|
|
63
|
+
severity: 'info',
|
|
64
|
+
title: 'No package manifest detected',
|
|
65
|
+
description: 'No recognised package manifest (package.json, pyproject.toml, Cargo.toml, go.mod, etc.) was found.',
|
|
66
|
+
recommendation: 'If this project has dependencies, add the appropriate manifest for your ecosystem.',
|
|
67
|
+
confidence: 0.8,
|
|
68
|
+
autoFixable: false,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// 2. DEP-002 + DEP-003: Lockfile detection
|
|
72
|
+
const lockfilesFound = context.manifests.lockfiles;
|
|
73
|
+
let directCount = 0;
|
|
74
|
+
let devCount = 0;
|
|
75
|
+
if (lockfilesFound.length > 0) {
|
|
76
|
+
findings.push({
|
|
77
|
+
id: createFindingId('DEP-002'),
|
|
78
|
+
ruleId: 'DEP-002',
|
|
79
|
+
category: 'dependencies',
|
|
80
|
+
severity: 'info',
|
|
81
|
+
title: `Lockfile detected: ${lockfilesFound.join(', ')}`,
|
|
82
|
+
description: `Found lockfile(s): ${lockfilesFound.join(', ')}. Ensures deterministic installs.`,
|
|
83
|
+
recommendation: 'Keep lockfiles committed and synchronised with package manifests.',
|
|
84
|
+
confidence: 0.99,
|
|
85
|
+
autoFixable: false,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
for (const manifest of manifests) {
|
|
89
|
+
const expectedLockfiles = MANIFEST_TO_LOCKFILES[manifest] ?? [];
|
|
90
|
+
const hasLockfile = expectedLockfiles.some((lf) => rootFileSet.has(lf));
|
|
91
|
+
if (!hasLockfile) {
|
|
92
|
+
findings.push({
|
|
93
|
+
id: createFindingId('DEP-003', manifest),
|
|
94
|
+
ruleId: 'DEP-003',
|
|
95
|
+
category: 'dependencies',
|
|
96
|
+
severity: 'medium',
|
|
97
|
+
title: `No lockfile found for ${manifest}`,
|
|
98
|
+
description: 'A lockfile ensures reproducible installs across environments.',
|
|
99
|
+
recommendation: `Run your package manager to generate a lockfile (e.g., \`npm install\`, \`poetry lock\`).`,
|
|
100
|
+
confidence: 0.95,
|
|
101
|
+
location: { file: manifest },
|
|
102
|
+
autoFixable: false,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// 3. DEP-004: Package manager mismatch (multiple Node.js lockfiles)
|
|
107
|
+
const nodeLockfiles = lockfilesFound.filter((lf) => Object.keys(LOCKFILE_TO_PM).includes(lf));
|
|
108
|
+
if (nodeLockfiles.length > 1) {
|
|
109
|
+
findings.push({
|
|
110
|
+
id: createFindingId('DEP-004'),
|
|
111
|
+
ruleId: 'DEP-004',
|
|
112
|
+
category: 'dependencies',
|
|
113
|
+
severity: 'low',
|
|
114
|
+
title: 'Multiple lockfiles detected',
|
|
115
|
+
description: `Found multiple lockfiles: ${nodeLockfiles.join(', ')}. This may indicate conflicting package managers.`,
|
|
116
|
+
recommendation: "Choose one package manager and remove the others' lockfiles.",
|
|
117
|
+
confidence: 0.9,
|
|
118
|
+
evidence: nodeLockfiles.join(', '),
|
|
119
|
+
autoFixable: false,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// 4. Parse lockfiles for transitive packages and duplicates (DEP-008)
|
|
123
|
+
let transitiveCount = 0;
|
|
124
|
+
const duplicatesMap = new Map();
|
|
125
|
+
const resolvedPackages = [];
|
|
126
|
+
for (const lf of lockfilesFound) {
|
|
127
|
+
const fileEntry = context.files.find((f) => f.relativePath === lf);
|
|
128
|
+
const absPath = fileEntry ? fileEntry.absolutePath : path.join(context.root, lf);
|
|
129
|
+
const content = await readFileSafe(absPath);
|
|
130
|
+
if (!content)
|
|
131
|
+
continue;
|
|
132
|
+
let parsed = null;
|
|
133
|
+
if (lf === 'package-lock.json')
|
|
134
|
+
parsed = parsePackageLockJson(content);
|
|
135
|
+
else if (lf === 'yarn.lock')
|
|
136
|
+
parsed = parseYarnLock(content);
|
|
137
|
+
else if (lf === 'pnpm-lock.yaml')
|
|
138
|
+
parsed = parsePnpmLock(content);
|
|
139
|
+
if (parsed) {
|
|
140
|
+
transitiveCount = Math.max(transitiveCount, parsed.transitiveCount);
|
|
141
|
+
for (const [name, versions] of parsed.packages) {
|
|
142
|
+
let verSet = duplicatesMap.get(name);
|
|
143
|
+
if (!verSet) {
|
|
144
|
+
verSet = new Set();
|
|
145
|
+
duplicatesMap.set(name, verSet);
|
|
146
|
+
}
|
|
147
|
+
for (const ver of versions) {
|
|
148
|
+
verSet.add(ver);
|
|
149
|
+
resolvedPackages.push({ name, version: ver });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const duplicatePackages = [];
|
|
155
|
+
for (const [name, versions] of duplicatesMap.entries()) {
|
|
156
|
+
if (versions.size > 1) {
|
|
157
|
+
const sorted = [...versions].sort();
|
|
158
|
+
duplicatePackages.push({ name, versions: sorted });
|
|
159
|
+
findings.push({
|
|
160
|
+
id: createFindingId('DEP-008', name),
|
|
161
|
+
ruleId: 'DEP-008',
|
|
162
|
+
category: 'dependencies',
|
|
163
|
+
severity: 'low',
|
|
164
|
+
title: `Duplicate dependency versions: ${name}`,
|
|
165
|
+
description: `Package "${name}" resolves to multiple distinct versions in lockfiles: ${sorted.join(', ')}.`,
|
|
166
|
+
recommendation: 'Deduplicate versions using package manager dedupe (e.g. `npm dedupe`) or align version constraints.',
|
|
167
|
+
confidence: 0.9,
|
|
168
|
+
evidence: sorted.join(', '),
|
|
169
|
+
autoFixable: false,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
duplicatePackages.sort((a, b) => a.name.localeCompare(b.name));
|
|
174
|
+
// 5. DEP-005 & Suspicious Configuration (DEP-006) from package.json
|
|
175
|
+
const suspiciousConfigs = [];
|
|
176
|
+
const directDepsList = [];
|
|
177
|
+
const declaredProdDeps = new Set();
|
|
178
|
+
if (context.manifests.packageJson) {
|
|
179
|
+
const pkgJson = context.manifests.packageJson;
|
|
180
|
+
const deps = pkgJson.dependencies ?? {};
|
|
181
|
+
const devDeps = pkgJson.devDependencies ?? {};
|
|
182
|
+
directCount = Object.keys(deps).length;
|
|
183
|
+
devCount = Object.keys(devDeps).length;
|
|
184
|
+
const totalDeclared = directCount + devCount;
|
|
185
|
+
if (totalDeclared > 0) {
|
|
186
|
+
findings.push({
|
|
187
|
+
id: createFindingId('DEP-005'),
|
|
188
|
+
ruleId: 'DEP-005',
|
|
189
|
+
category: 'dependencies',
|
|
190
|
+
severity: 'info',
|
|
191
|
+
title: `Dependencies declared: ${totalDeclared}`,
|
|
192
|
+
description: `Project declares ${directCount} dependencies and ${devCount} devDependencies.`,
|
|
193
|
+
recommendation: 'Audit dependencies regularly for security updates and unused packages.',
|
|
194
|
+
confidence: 0.95,
|
|
195
|
+
autoFixable: false,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
// Check duplicate between dependencies and devDependencies
|
|
199
|
+
for (const depName of Object.keys(deps)) {
|
|
200
|
+
declaredProdDeps.add(depName);
|
|
201
|
+
directDepsList.push({ name: depName, currentVersion: deps[depName] ?? '' });
|
|
202
|
+
if (devDeps[depName] !== undefined) {
|
|
203
|
+
const reason = `Package "${depName}" is declared in both dependencies and devDependencies.`;
|
|
204
|
+
suspiciousConfigs.push({
|
|
205
|
+
name: depName,
|
|
206
|
+
versionSpec: `dependencies: ${deps[depName]} | devDependencies: ${devDeps[depName]}`,
|
|
207
|
+
reason,
|
|
208
|
+
manifestPath: 'package.json',
|
|
209
|
+
});
|
|
210
|
+
findings.push({
|
|
211
|
+
id: createFindingId('DEP-006', `${depName}-duplicate`),
|
|
212
|
+
ruleId: 'DEP-006',
|
|
213
|
+
category: 'dependencies',
|
|
214
|
+
severity: 'low',
|
|
215
|
+
title: `Conflicting dependency declaration: ${depName}`,
|
|
216
|
+
description: reason,
|
|
217
|
+
recommendation: 'Remove the duplicate entry from devDependencies if it is required at runtime, or vice versa.',
|
|
218
|
+
confidence: 0.95,
|
|
219
|
+
location: { file: 'package.json' },
|
|
220
|
+
autoFixable: false,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Check wildcards and unpinned Git/URL specs
|
|
225
|
+
const allSpecs = [
|
|
226
|
+
...Object.entries(deps).map(([name, spec]) => ({ name, spec })),
|
|
227
|
+
...Object.entries(devDeps).map(([name, spec]) => ({ name, spec })),
|
|
228
|
+
];
|
|
229
|
+
for (const { name, spec } of allSpecs) {
|
|
230
|
+
let reason = '';
|
|
231
|
+
if (spec === '*' || spec === 'latest' || spec === 'x.x' || spec === '>0.0.0') {
|
|
232
|
+
reason = `Unpinned wildcard version specifier "${spec}". Can introduce breaking changes or untrusted updates.`;
|
|
233
|
+
}
|
|
234
|
+
else if (spec.startsWith('git:') ||
|
|
235
|
+
spec.startsWith('git+https:') ||
|
|
236
|
+
spec.startsWith('http:')) {
|
|
237
|
+
if (!spec.includes('#')) {
|
|
238
|
+
reason = `Unpinned Git or HTTP repository reference "${spec}".`;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else if (spec.startsWith('file:..')) {
|
|
242
|
+
reason = `External local filesystem reference "${spec}". May fail in isolated build environments.`;
|
|
243
|
+
}
|
|
244
|
+
if (reason) {
|
|
245
|
+
suspiciousConfigs.push({
|
|
246
|
+
name,
|
|
247
|
+
versionSpec: spec,
|
|
248
|
+
reason,
|
|
249
|
+
manifestPath: 'package.json',
|
|
250
|
+
});
|
|
251
|
+
findings.push({
|
|
252
|
+
id: createFindingId('DEP-006', name),
|
|
253
|
+
ruleId: 'DEP-006',
|
|
254
|
+
category: 'dependencies',
|
|
255
|
+
severity: 'low',
|
|
256
|
+
title: `Suspicious dependency specifier: ${name}@${spec}`,
|
|
257
|
+
description: reason,
|
|
258
|
+
recommendation: 'Pin dependencies with standard semantic version ranges (e.g. `^1.2.0` or `~1.2.0`).',
|
|
259
|
+
confidence: 0.9,
|
|
260
|
+
location: { file: 'package.json' },
|
|
261
|
+
autoFixable: false,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// 6. Unused Dependencies (DEP-010, Confident detection)
|
|
267
|
+
const unusedDeps = [];
|
|
268
|
+
if (declaredProdDeps.size > 0 && context.files.filter((f) => f.isSource).length >= 3) {
|
|
269
|
+
// Collect all external imports from source files
|
|
270
|
+
const importedPackages = new Set();
|
|
271
|
+
for (const file of context.files) {
|
|
272
|
+
if (!file.isSource)
|
|
273
|
+
continue;
|
|
274
|
+
if (file.sizeBytes > 1024 * 1024)
|
|
275
|
+
continue;
|
|
276
|
+
const content = await readFileSafe(file.absolutePath);
|
|
277
|
+
if (!content)
|
|
278
|
+
continue;
|
|
279
|
+
const specifiers = extractRawSpecifiers(content, file.extension);
|
|
280
|
+
for (const spec of specifiers) {
|
|
281
|
+
if (spec.startsWith('.') || spec.startsWith('/'))
|
|
282
|
+
continue;
|
|
283
|
+
// Extract base package name (e.g. '@tanstack/react-query' -> '@tanstack/react-query', 'lodash/map' -> 'lodash')
|
|
284
|
+
const parts = spec.split('/');
|
|
285
|
+
const pkgName = spec.startsWith('@') ? `${parts[0]}/${parts[1]}` : parts[0];
|
|
286
|
+
if (pkgName)
|
|
287
|
+
importedPackages.add(pkgName);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
for (const depName of declaredProdDeps) {
|
|
291
|
+
if (depName.startsWith('@types/'))
|
|
292
|
+
continue;
|
|
293
|
+
if (RUNTIME_IGNORED_PACKAGES.has(depName))
|
|
294
|
+
continue;
|
|
295
|
+
if (!importedPackages.has(depName)) {
|
|
296
|
+
unusedDeps.push({
|
|
297
|
+
name: depName,
|
|
298
|
+
manifestPath: 'package.json',
|
|
299
|
+
confidence: 0.85,
|
|
300
|
+
});
|
|
301
|
+
findings.push({
|
|
302
|
+
id: createFindingId('DEP-010', depName),
|
|
303
|
+
ruleId: 'DEP-010',
|
|
304
|
+
category: 'dependencies',
|
|
305
|
+
severity: 'info',
|
|
306
|
+
title: `Unused production dependency: ${depName}`,
|
|
307
|
+
description: `Package "${depName}" is declared in dependencies but no import references were found across source files.`,
|
|
308
|
+
recommendation: 'If this package is no longer needed, remove it with your package manager or move it to devDependencies.',
|
|
309
|
+
confidence: 0.85,
|
|
310
|
+
location: { file: 'package.json' },
|
|
311
|
+
autoFixable: false,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// 7. Online Analysis: Vulnerabilities (DEP-007) and Outdated (DEP-009)
|
|
317
|
+
let vulnerabilities = [];
|
|
318
|
+
let outdated = [];
|
|
319
|
+
if (context.online) {
|
|
320
|
+
// Query vulnerabilities via OSV
|
|
321
|
+
const packagesToQuery = resolvedPackages.length > 0
|
|
322
|
+
? resolvedPackages
|
|
323
|
+
: directDepsList.map((d) => ({
|
|
324
|
+
name: d.name,
|
|
325
|
+
version: d.currentVersion.replace(/^[\^~>=<v\s]+/, ''),
|
|
326
|
+
}));
|
|
327
|
+
vulnerabilities = await queryVulnerabilitiesOnline(packagesToQuery);
|
|
328
|
+
for (const vuln of vulnerabilities) {
|
|
329
|
+
const vulnFinding = {
|
|
330
|
+
id: createFindingId('DEP-007', `${vuln.packageName}-${vuln.id}`),
|
|
331
|
+
ruleId: 'DEP-007',
|
|
332
|
+
category: 'dependencies',
|
|
333
|
+
severity: vuln.severity,
|
|
334
|
+
title: `Known vulnerability: ${vuln.packageName} (${vuln.id})`,
|
|
335
|
+
description: vuln.title,
|
|
336
|
+
recommendation: `Upgrade ${vuln.packageName} to a patched release. Advisory details: ${vuln.url ?? 'https://osv.dev'}`,
|
|
337
|
+
confidence: 0.95,
|
|
338
|
+
autoFixable: false,
|
|
339
|
+
};
|
|
340
|
+
if (vuln.url)
|
|
341
|
+
vulnFinding.references = [vuln.url];
|
|
342
|
+
findings.push(vulnFinding);
|
|
343
|
+
}
|
|
344
|
+
// Query outdated packages via registry
|
|
345
|
+
if (directDepsList.length > 0) {
|
|
346
|
+
outdated = await checkOutdatedOnline(directDepsList);
|
|
347
|
+
for (const out of outdated) {
|
|
348
|
+
findings.push({
|
|
349
|
+
id: createFindingId('DEP-009', out.packageName),
|
|
350
|
+
ruleId: 'DEP-009',
|
|
351
|
+
category: 'dependencies',
|
|
352
|
+
severity: 'low',
|
|
353
|
+
title: `Outdated dependency: ${out.packageName} (${out.currentVersion} → ${out.latestVersion})`,
|
|
354
|
+
description: `Package "${out.packageName}" is running version ${out.currentVersion}, while latest release is ${out.latestVersion}.`,
|
|
355
|
+
recommendation: `Review release notes and upgrade ${out.packageName} to ${out.latestVersion}.`,
|
|
356
|
+
confidence: 0.9,
|
|
357
|
+
autoFixable: false,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
const summary = {
|
|
363
|
+
manifests,
|
|
364
|
+
lockfiles: lockfilesFound,
|
|
365
|
+
directCount,
|
|
366
|
+
devCount,
|
|
367
|
+
transitiveCount,
|
|
368
|
+
duplicates: duplicatePackages,
|
|
369
|
+
suspicious: suspiciousConfigs,
|
|
370
|
+
unused: unusedDeps,
|
|
371
|
+
vulnerabilities,
|
|
372
|
+
outdated,
|
|
373
|
+
isOnline: Boolean(context.online),
|
|
374
|
+
};
|
|
375
|
+
const metrics = {
|
|
376
|
+
manifestsFound: manifests,
|
|
377
|
+
lockfilesFound: lockfilesFound,
|
|
378
|
+
directCount,
|
|
379
|
+
devCount,
|
|
380
|
+
transitiveCount,
|
|
381
|
+
dependencyCount: directCount + devCount,
|
|
382
|
+
duplicateCount: duplicatePackages.length,
|
|
383
|
+
suspiciousCount: suspiciousConfigs.length,
|
|
384
|
+
unusedCount: unusedDeps.length,
|
|
385
|
+
vulnerabilityCount: vulnerabilities.length,
|
|
386
|
+
outdatedCount: outdated.length,
|
|
387
|
+
isOnline: Boolean(context.online),
|
|
388
|
+
hasMissingLockfile: manifests.some((m) => !(MANIFEST_TO_LOCKFILES[m] ?? []).some((lf) => rootFileSet.has(lf))),
|
|
389
|
+
summary: JSON.stringify(summary),
|
|
390
|
+
};
|
|
391
|
+
return {
|
|
392
|
+
analyzerId: this.id,
|
|
393
|
+
analyzerName: this.name,
|
|
394
|
+
category: this.category,
|
|
395
|
+
status: 'success',
|
|
396
|
+
findings,
|
|
397
|
+
metrics,
|
|
398
|
+
durationMs: elapsed(),
|
|
399
|
+
warnings,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyzers/dependencies/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DuplicatePackage } from './types.js';
|
|
2
|
+
export interface ParsedLockfile {
|
|
3
|
+
transitiveCount: number;
|
|
4
|
+
packages: Map<string, Set<string>>;
|
|
5
|
+
duplicates: DuplicatePackage[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Statically parses a package-lock.json file (supporting v1, v2, and v3 schemas).
|
|
9
|
+
*/
|
|
10
|
+
export declare function parsePackageLockJson(content: string): ParsedLockfile;
|
|
11
|
+
/**
|
|
12
|
+
* Statically parses a yarn.lock file without executing yarn.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseYarnLock(content: string): ParsedLockfile;
|
|
15
|
+
/**
|
|
16
|
+
* Statically parses a pnpm-lock.yaml file without executing pnpm.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parsePnpmLock(content: string): ParsedLockfile;
|
|
19
|
+
//# sourceMappingURL=lockfiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfiles.d.ts","sourceRoot":"","sources":["../../../src/analyzers/dependencies/lockfiles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACnC,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAgFpE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAoD7D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAwC7D"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Statically parses a package-lock.json file (supporting v1, v2, and v3 schemas).
|
|
3
|
+
*/
|
|
4
|
+
export function parsePackageLockJson(content) {
|
|
5
|
+
const packages = new Map();
|
|
6
|
+
try {
|
|
7
|
+
const data = JSON.parse(content);
|
|
8
|
+
// v2 & v3 schemas: "packages" object
|
|
9
|
+
const rawPackages = data['packages'];
|
|
10
|
+
if (rawPackages && typeof rawPackages === 'object' && !Array.isArray(rawPackages)) {
|
|
11
|
+
const pkgsObj = rawPackages;
|
|
12
|
+
for (const [pkgPath, pkgInfo] of Object.entries(pkgsObj)) {
|
|
13
|
+
if (!pkgPath || pkgPath === '')
|
|
14
|
+
continue; // Skip root package definition
|
|
15
|
+
if (!pkgInfo || typeof pkgInfo.version !== 'string')
|
|
16
|
+
continue;
|
|
17
|
+
// Extract package name from "node_modules/..."
|
|
18
|
+
const match = /node_modules\/((?:@[^/]+\/)?[^/]+)$/.exec(pkgPath);
|
|
19
|
+
if (match?.[1]) {
|
|
20
|
+
const name = match[1];
|
|
21
|
+
const ver = pkgInfo.version;
|
|
22
|
+
let verSet = packages.get(name);
|
|
23
|
+
if (!verSet) {
|
|
24
|
+
verSet = new Set();
|
|
25
|
+
packages.set(name, verSet);
|
|
26
|
+
}
|
|
27
|
+
verSet.add(ver);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const rawDeps = data['dependencies'];
|
|
33
|
+
if (rawDeps && typeof rawDeps === 'object' && !Array.isArray(rawDeps)) {
|
|
34
|
+
// v1 schema: nested "dependencies"
|
|
35
|
+
function walkV1(depsObj) {
|
|
36
|
+
for (const [name, info] of Object.entries(depsObj)) {
|
|
37
|
+
if (!info || typeof info !== 'object')
|
|
38
|
+
continue;
|
|
39
|
+
const typedInfo = info;
|
|
40
|
+
if (typeof typedInfo.version === 'string') {
|
|
41
|
+
let verSet = packages.get(name);
|
|
42
|
+
if (!verSet) {
|
|
43
|
+
verSet = new Set();
|
|
44
|
+
packages.set(name, verSet);
|
|
45
|
+
}
|
|
46
|
+
verSet.add(typedInfo.version);
|
|
47
|
+
}
|
|
48
|
+
const childDeps = typedInfo.dependencies;
|
|
49
|
+
if (childDeps && typeof childDeps === 'object') {
|
|
50
|
+
walkV1(childDeps);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
walkV1(rawDeps);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return {
|
|
60
|
+
transitiveCount: 0,
|
|
61
|
+
packages,
|
|
62
|
+
duplicates: [],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const duplicates = [];
|
|
66
|
+
for (const [name, versions] of packages.entries()) {
|
|
67
|
+
if (versions.size > 1) {
|
|
68
|
+
duplicates.push({
|
|
69
|
+
name,
|
|
70
|
+
versions: [...versions].sort(),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
duplicates.sort((a, b) => a.name.localeCompare(b.name));
|
|
75
|
+
return {
|
|
76
|
+
transitiveCount: packages.size,
|
|
77
|
+
packages,
|
|
78
|
+
duplicates,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Statically parses a yarn.lock file without executing yarn.
|
|
83
|
+
*/
|
|
84
|
+
export function parseYarnLock(content) {
|
|
85
|
+
const packages = new Map();
|
|
86
|
+
const lines = content.split(/\r?\n/);
|
|
87
|
+
let currentHeader = null;
|
|
88
|
+
for (const rawLine of lines) {
|
|
89
|
+
const line = rawLine.trimEnd();
|
|
90
|
+
if (!line || line.startsWith('#'))
|
|
91
|
+
continue;
|
|
92
|
+
if (!line.startsWith(' ') && line.endsWith(':')) {
|
|
93
|
+
currentHeader = line.slice(0, -1).trim();
|
|
94
|
+
}
|
|
95
|
+
else if (currentHeader && line.trim().startsWith('version ')) {
|
|
96
|
+
const verMatch = /version\s+["']?([^"']+)["']?/.exec(line.trim());
|
|
97
|
+
const version = verMatch?.[1];
|
|
98
|
+
if (version) {
|
|
99
|
+
const firstSpec = currentHeader
|
|
100
|
+
.split(',')[0]
|
|
101
|
+
?.trim()
|
|
102
|
+
.replace(/^["']|["']$/g, '') ?? '';
|
|
103
|
+
const atIdx = firstSpec.lastIndexOf('@');
|
|
104
|
+
if (atIdx > 0) {
|
|
105
|
+
const name = firstSpec.slice(0, atIdx);
|
|
106
|
+
let verSet = packages.get(name);
|
|
107
|
+
if (!verSet) {
|
|
108
|
+
verSet = new Set();
|
|
109
|
+
packages.set(name, verSet);
|
|
110
|
+
}
|
|
111
|
+
verSet.add(version);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
currentHeader = null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const duplicates = [];
|
|
118
|
+
for (const [name, versions] of packages.entries()) {
|
|
119
|
+
if (versions.size > 1) {
|
|
120
|
+
duplicates.push({
|
|
121
|
+
name,
|
|
122
|
+
versions: [...versions].sort(),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
duplicates.sort((a, b) => a.name.localeCompare(b.name));
|
|
127
|
+
return {
|
|
128
|
+
transitiveCount: packages.size,
|
|
129
|
+
packages,
|
|
130
|
+
duplicates,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Statically parses a pnpm-lock.yaml file without executing pnpm.
|
|
135
|
+
*/
|
|
136
|
+
export function parsePnpmLock(content) {
|
|
137
|
+
const packages = new Map();
|
|
138
|
+
// Matches pnpm packages block lines like:
|
|
139
|
+
// /@types/node@20.1.0:
|
|
140
|
+
// /lodash@4.17.21:
|
|
141
|
+
// lodash@4.17.21:
|
|
142
|
+
const lineRegex = /^\s*['"]?(?:\/)?((?:@[^/@]+\/)?[^/@]+)@([^('"\s:]+)/gm;
|
|
143
|
+
let match;
|
|
144
|
+
while ((match = lineRegex.exec(content)) !== null) {
|
|
145
|
+
const name = match[1];
|
|
146
|
+
const version = match[2];
|
|
147
|
+
if (name && version) {
|
|
148
|
+
let verSet = packages.get(name);
|
|
149
|
+
if (!verSet) {
|
|
150
|
+
verSet = new Set();
|
|
151
|
+
packages.set(name, verSet);
|
|
152
|
+
}
|
|
153
|
+
verSet.add(version);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const duplicates = [];
|
|
157
|
+
for (const [name, versions] of packages.entries()) {
|
|
158
|
+
if (versions.size > 1) {
|
|
159
|
+
duplicates.push({
|
|
160
|
+
name,
|
|
161
|
+
versions: [...versions].sort(),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
duplicates.sort((a, b) => a.name.localeCompare(b.name));
|
|
166
|
+
return {
|
|
167
|
+
transitiveCount: packages.size,
|
|
168
|
+
packages,
|
|
169
|
+
duplicates,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=lockfiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfiles.js","sourceRoot":"","sources":["../../../src/analyzers/dependencies/lockfiles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { VulnerabilityAdvisory, OutdatedDependency } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Queries the public Open Source Vulnerabilities (OSV) API in batch mode.
|
|
4
|
+
* Strictly respects timeouts and offline failures. Never transmits repository source code or tokens.
|
|
5
|
+
*/
|
|
6
|
+
export declare function queryVulnerabilitiesOnline(packages: Array<{
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
ecosystem?: string;
|
|
10
|
+
}>): Promise<VulnerabilityAdvisory[]>;
|
|
11
|
+
/**
|
|
12
|
+
* Checks for latest versions of direct dependencies against npm registry.
|
|
13
|
+
* Limited to first 25 packages with 2.5s individual timeout.
|
|
14
|
+
*/
|
|
15
|
+
export declare function checkOutdatedOnline(directDeps: Array<{
|
|
16
|
+
name: string;
|
|
17
|
+
currentVersion: string;
|
|
18
|
+
}>): Promise<OutdatedDependency[]>;
|
|
19
|
+
//# sourceMappingURL=online.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"online.d.ts","sourceRoot":"","sources":["../../../src/analyzers/dependencies/online.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA2B5E;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACrE,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAgElC;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC,GAC1D,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAgD/B"}
|