sublyzer-snapshot 0.3.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/LICENSE +21 -0
- package/README.md +306 -0
- package/dist/api/sublyzer.d.ts +29 -0
- package/dist/api/sublyzer.d.ts.map +1 -0
- package/dist/api/sublyzer.js +61 -0
- package/dist/api/sublyzer.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +199 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/ci.d.ts +9 -0
- package/dist/commands/ci.d.ts.map +1 -0
- package/dist/commands/ci.js +65 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/compare.d.ts +7 -0
- package/dist/commands/compare.d.ts.map +1 -0
- package/dist/commands/compare.js +60 -0
- package/dist/commands/compare.js.map +1 -0
- package/dist/commands/doctor.d.ts +13 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +100 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +88 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/open.d.ts +2 -0
- package/dist/commands/open.d.ts.map +1 -0
- package/dist/commands/open.js +16 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/pull.d.ts +9 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +34 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/report.d.ts +8 -0
- package/dist/commands/report.d.ts.map +1 -0
- package/dist/commands/report.js +47 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/run.d.ts +21 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +96 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +52 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +58 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +13 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +12 -0
- package/dist/constants.js.map +1 -0
- package/dist/detect/git.d.ts +9 -0
- package/dist/detect/git.d.ts.map +1 -0
- package/dist/detect/git.js +25 -0
- package/dist/detect/git.js.map +1 -0
- package/dist/detect/meta.d.ts +8 -0
- package/dist/detect/meta.d.ts.map +1 -0
- package/dist/detect/meta.js +42 -0
- package/dist/detect/meta.js.map +1 -0
- package/dist/detect/routes.d.ts +2 -0
- package/dist/detect/routes.d.ts.map +1 -0
- package/dist/detect/routes.js +104 -0
- package/dist/detect/routes.js.map +1 -0
- package/dist/detect/stack.d.ts +15 -0
- package/dist/detect/stack.d.ts.map +1 -0
- package/dist/detect/stack.js +114 -0
- package/dist/detect/stack.js.map +1 -0
- package/dist/detect/workspaces.d.ts +6 -0
- package/dist/detect/workspaces.d.ts.map +1 -0
- package/dist/detect/workspaces.js +54 -0
- package/dist/detect/workspaces.js.map +1 -0
- package/dist/report/markdown.d.ts +5 -0
- package/dist/report/markdown.d.ts.map +1 -0
- package/dist/report/markdown.js +81 -0
- package/dist/report/markdown.js.map +1 -0
- package/dist/scan/audit.d.ts +16 -0
- package/dist/scan/audit.d.ts.map +1 -0
- package/dist/scan/audit.js +53 -0
- package/dist/scan/audit.js.map +1 -0
- package/dist/scan/health-score.d.ts +13 -0
- package/dist/scan/health-score.d.ts.map +1 -0
- package/dist/scan/health-score.js +60 -0
- package/dist/scan/health-score.js.map +1 -0
- package/dist/scan/history.d.ts +21 -0
- package/dist/scan/history.d.ts.map +1 -0
- package/dist/scan/history.js +82 -0
- package/dist/scan/history.js.map +1 -0
- package/dist/scan/outdated.d.ts +15 -0
- package/dist/scan/outdated.d.ts.map +1 -0
- package/dist/scan/outdated.js +54 -0
- package/dist/scan/outdated.js.map +1 -0
- package/dist/scan/policy.d.ts +5 -0
- package/dist/scan/policy.d.ts.map +1 -0
- package/dist/scan/policy.js +20 -0
- package/dist/scan/policy.js.map +1 -0
- package/dist/scan/snapshot.d.ts +47 -0
- package/dist/scan/snapshot.d.ts.map +1 -0
- package/dist/scan/snapshot.js +176 -0
- package/dist/scan/snapshot.js.map +1 -0
- package/dist/utils/gitignore.d.ts +3 -0
- package/dist/utils/gitignore.d.ts.map +1 -0
- package/dist/utils/gitignore.js +34 -0
- package/dist/utils/gitignore.js.map +1 -0
- package/dist/utils/log.d.ts +6 -0
- package/dist/utils/log.d.ts.map +1 -0
- package/dist/utils/log.js +17 -0
- package/dist/utils/log.js.map +1 -0
- package/dist/utils/prompt.d.ts +4 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +35 -0
- package/dist/utils/prompt.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
const VERSION_KEYS = [
|
|
4
|
+
'next',
|
|
5
|
+
'react',
|
|
6
|
+
'react-dom',
|
|
7
|
+
'vue',
|
|
8
|
+
'nuxt',
|
|
9
|
+
'@nestjs/core',
|
|
10
|
+
'express',
|
|
11
|
+
'fastify',
|
|
12
|
+
'@remix-run/react',
|
|
13
|
+
'@sveltejs/kit',
|
|
14
|
+
'typescript',
|
|
15
|
+
];
|
|
16
|
+
function readPackageJson(root) {
|
|
17
|
+
const file = path.join(root, 'package.json');
|
|
18
|
+
if (!fs.existsSync(file))
|
|
19
|
+
return null;
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function allDeps(pkg) {
|
|
28
|
+
if (!pkg)
|
|
29
|
+
return {};
|
|
30
|
+
return { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
31
|
+
}
|
|
32
|
+
function exists(root, rel) {
|
|
33
|
+
return fs.existsSync(path.join(root, rel));
|
|
34
|
+
}
|
|
35
|
+
function frameworkVersions(deps) {
|
|
36
|
+
const out = {};
|
|
37
|
+
for (const key of VERSION_KEYS) {
|
|
38
|
+
if (deps[key])
|
|
39
|
+
out[key] = deps[key];
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
export function detectStack(root = process.cwd()) {
|
|
44
|
+
const pkg = readPackageJson(root);
|
|
45
|
+
const deps = allDeps(pkg);
|
|
46
|
+
const hints = [];
|
|
47
|
+
const versions = frameworkVersions(deps);
|
|
48
|
+
if (deps.next) {
|
|
49
|
+
hints.push('package.json → next');
|
|
50
|
+
if (exists(root, 'app') || exists(root, 'pages'))
|
|
51
|
+
hints.push('app/ or pages/ directory');
|
|
52
|
+
return { id: 'nextjs', label: 'Next.js', confidence: 'high', hints, frameworkVersions: versions };
|
|
53
|
+
}
|
|
54
|
+
if (deps.nuxt || deps['nuxt3']) {
|
|
55
|
+
hints.push('package.json → nuxt');
|
|
56
|
+
return { id: 'nuxt', label: 'Nuxt', confidence: 'high', hints, frameworkVersions: versions };
|
|
57
|
+
}
|
|
58
|
+
if (deps['@sveltejs/kit']) {
|
|
59
|
+
hints.push('package.json → @sveltejs/kit');
|
|
60
|
+
return { id: 'sveltekit', label: 'SvelteKit', confidence: 'high', hints, frameworkVersions: versions };
|
|
61
|
+
}
|
|
62
|
+
if (deps['@nestjs/core']) {
|
|
63
|
+
hints.push('package.json → @nestjs/core');
|
|
64
|
+
if (exists(root, 'nest-cli.json'))
|
|
65
|
+
hints.push('nest-cli.json');
|
|
66
|
+
return { id: 'nestjs', label: 'NestJS', confidence: 'high', hints, frameworkVersions: versions };
|
|
67
|
+
}
|
|
68
|
+
if (deps.fastify) {
|
|
69
|
+
hints.push('package.json → fastify');
|
|
70
|
+
return { id: 'fastify', label: 'Fastify', confidence: 'high', hints, frameworkVersions: versions };
|
|
71
|
+
}
|
|
72
|
+
if (deps.express) {
|
|
73
|
+
hints.push('package.json → express');
|
|
74
|
+
return { id: 'express', label: 'Express', confidence: 'high', hints, frameworkVersions: versions };
|
|
75
|
+
}
|
|
76
|
+
if (deps['@remix-run/react'] || deps['@remix-run/node']) {
|
|
77
|
+
hints.push('package.json → remix');
|
|
78
|
+
return { id: 'remix', label: 'Remix', confidence: 'high', hints, frameworkVersions: versions };
|
|
79
|
+
}
|
|
80
|
+
if (deps.react && !deps.next) {
|
|
81
|
+
hints.push('package.json → react');
|
|
82
|
+
return { id: 'react', label: 'React', confidence: 'medium', hints, frameworkVersions: versions };
|
|
83
|
+
}
|
|
84
|
+
if (deps.vue) {
|
|
85
|
+
hints.push('package.json → vue');
|
|
86
|
+
return { id: 'vue', label: 'Vue', confidence: 'medium', hints, frameworkVersions: versions };
|
|
87
|
+
}
|
|
88
|
+
if (pkg?.name)
|
|
89
|
+
hints.push(`package.json name: ${pkg.name}`);
|
|
90
|
+
if (exists(root, 'package.json')) {
|
|
91
|
+
return { id: 'node', label: 'Node.js', confidence: 'low', hints, frameworkVersions: versions };
|
|
92
|
+
}
|
|
93
|
+
return { id: 'unknown', label: 'Unknown', confidence: 'low', hints: ['No package.json found'], frameworkVersions: versions };
|
|
94
|
+
}
|
|
95
|
+
export function readProjectName(root = process.cwd()) {
|
|
96
|
+
const pkg = readPackageJson(root);
|
|
97
|
+
if (pkg?.name)
|
|
98
|
+
return pkg.name;
|
|
99
|
+
return path.basename(root);
|
|
100
|
+
}
|
|
101
|
+
export function listDependencies(root = process.cwd()) {
|
|
102
|
+
const pkg = readPackageJson(root);
|
|
103
|
+
if (!pkg)
|
|
104
|
+
return [];
|
|
105
|
+
const out = [];
|
|
106
|
+
for (const [name, version] of Object.entries(pkg.dependencies || {})) {
|
|
107
|
+
out.push({ name, version, dev: false });
|
|
108
|
+
}
|
|
109
|
+
for (const [name, version] of Object.entries(pkg.devDependencies || {})) {
|
|
110
|
+
out.push({ name, version, dev: true });
|
|
111
|
+
}
|
|
112
|
+
return out.sort((a, b) => a.name.localeCompare(b.name));
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=stack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack.js","sourceRoot":"","sources":["../../src/detect/stack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../src/detect/workspaces.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACvC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAmCF,wBAAgB,gBAAgB,CAAC,IAAI,SAAgB,GAAG,aAAa,CAgBpE"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
function readPackageJson(root) {
|
|
4
|
+
const file = path.join(root, 'package.json');
|
|
5
|
+
if (!fs.existsSync(file))
|
|
6
|
+
return null;
|
|
7
|
+
try {
|
|
8
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function expandWorkspaceGlobs(root, patterns) {
|
|
15
|
+
const found = new Set();
|
|
16
|
+
for (const pattern of patterns) {
|
|
17
|
+
const base = pattern.replace(/\*.*$/, '').replace(/\/$/, '');
|
|
18
|
+
const dir = path.join(root, base);
|
|
19
|
+
if (fs.existsSync(path.join(dir, 'package.json'))) {
|
|
20
|
+
found.add(base || '.');
|
|
21
|
+
}
|
|
22
|
+
if (pattern.includes('*') && fs.existsSync(dir)) {
|
|
23
|
+
try {
|
|
24
|
+
for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
25
|
+
if (!ent.isDirectory())
|
|
26
|
+
continue;
|
|
27
|
+
const rel = path.join(base, ent.name).replace(/\\/g, '/');
|
|
28
|
+
if (fs.existsSync(path.join(root, rel, 'package.json')))
|
|
29
|
+
found.add(rel);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
/* ignore */
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return [...found].sort();
|
|
38
|
+
}
|
|
39
|
+
export function detectWorkspaces(root = process.cwd()) {
|
|
40
|
+
if (fs.existsSync(path.join(root, 'pnpm-workspace.yaml'))) {
|
|
41
|
+
const pkgs = expandWorkspaceGlobs(root, ['packages/*', 'apps/*', 'projects/*']);
|
|
42
|
+
return { type: 'pnpm', packages: pkgs.length ? pkgs : ['.'] };
|
|
43
|
+
}
|
|
44
|
+
const pkg = readPackageJson(root);
|
|
45
|
+
const workspaces = pkg?.workspaces;
|
|
46
|
+
if (Array.isArray(workspaces)) {
|
|
47
|
+
return { type: 'npm', packages: expandWorkspaceGlobs(root, workspaces) };
|
|
48
|
+
}
|
|
49
|
+
if (workspaces && typeof workspaces === 'object' && Array.isArray(workspaces.packages)) {
|
|
50
|
+
return { type: 'npm', packages: expandWorkspaceGlobs(root, workspaces.packages) };
|
|
51
|
+
}
|
|
52
|
+
return { type: 'none', packages: ['.'] };
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=workspaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../src/detect/workspaces.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SnapshotDiff } from '../scan/history.js';
|
|
2
|
+
import { type HealthScore } from '../scan/health-score.js';
|
|
3
|
+
import type { ProjectSnapshot } from '../scan/snapshot.js';
|
|
4
|
+
export declare function renderMarkdownReport(snapshot: ProjectSnapshot, health: HealthScore, diff?: SnapshotDiff | null, dashboardUrl?: string): string;
|
|
5
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/report/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,WAAW,EACnB,IAAI,CAAC,EAAE,YAAY,GAAG,IAAI,EAC1B,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAsFR"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export function renderMarkdownReport(snapshot, health, diff, dashboardUrl) {
|
|
2
|
+
const lines = [];
|
|
3
|
+
const s = snapshot.summary;
|
|
4
|
+
lines.push(`# Sublyzer Snapshot — ${snapshot.projectName}`);
|
|
5
|
+
lines.push('');
|
|
6
|
+
lines.push(`**Generated:** ${snapshot.scannedAt} `);
|
|
7
|
+
lines.push(`**Stack:** ${snapshot.stack.label} `);
|
|
8
|
+
lines.push(`**Health:** ${health.score}/100 (grade ${health.grade}) `);
|
|
9
|
+
if (dashboardUrl)
|
|
10
|
+
lines.push(`**Dashboard:** ${dashboardUrl} `);
|
|
11
|
+
lines.push('');
|
|
12
|
+
lines.push('## Summary');
|
|
13
|
+
lines.push('');
|
|
14
|
+
lines.push('| Metric | Value |');
|
|
15
|
+
lines.push('|--------|-------|');
|
|
16
|
+
lines.push(`| Routes | ${s.routeCount} |`);
|
|
17
|
+
lines.push(`| Dependencies | ${s.productionDeps} prod / ${s.devDeps} dev |`);
|
|
18
|
+
lines.push(`| Vulnerabilities | ${s.vulnerablePackages} (C:${s.criticalVulns} H:${s.highVulns}) |`);
|
|
19
|
+
if (snapshot.outdated?.ran) {
|
|
20
|
+
lines.push(`| Outdated packages | ${snapshot.outdated.total} (${snapshot.outdated.majorCount} major) |`);
|
|
21
|
+
}
|
|
22
|
+
if (snapshot.git.available) {
|
|
23
|
+
lines.push(`| Git | \`${snapshot.git.branch}@${snapshot.git.commit}\`${snapshot.git.dirty ? ' *(dirty)*' : ''} |`);
|
|
24
|
+
}
|
|
25
|
+
lines.push('');
|
|
26
|
+
if (health.factors.length) {
|
|
27
|
+
lines.push('## Health factors');
|
|
28
|
+
lines.push('');
|
|
29
|
+
for (const f of health.factors) {
|
|
30
|
+
const sign = f.impact >= 0 ? '+' : '';
|
|
31
|
+
lines.push(`- ${f.label} (${sign}${f.impact})`);
|
|
32
|
+
}
|
|
33
|
+
lines.push('');
|
|
34
|
+
}
|
|
35
|
+
if (diff && diff.previousAt) {
|
|
36
|
+
lines.push('## Changes since last scan');
|
|
37
|
+
lines.push('');
|
|
38
|
+
lines.push(`Previous scan: ${diff.previousAt}`);
|
|
39
|
+
lines.push('');
|
|
40
|
+
if (diff.healthDelta != null) {
|
|
41
|
+
const arrow = diff.healthDelta >= 0 ? '↑' : '↓';
|
|
42
|
+
lines.push(`- Health score: ${arrow} ${Math.abs(diff.healthDelta)} points`);
|
|
43
|
+
}
|
|
44
|
+
if (diff.vulnDelta.total !== 0) {
|
|
45
|
+
lines.push(`- Vulnerabilities: ${diff.vulnDelta.total >= 0 ? '+' : ''}${diff.vulnDelta.total}`);
|
|
46
|
+
}
|
|
47
|
+
if (diff.routesAdded.length) {
|
|
48
|
+
lines.push(`- Routes added (${diff.routesAdded.length}): ${diff.routesAdded.slice(0, 10).join(', ')}`);
|
|
49
|
+
}
|
|
50
|
+
if (diff.routesRemoved.length) {
|
|
51
|
+
lines.push(`- Routes removed (${diff.routesRemoved.length}): ${diff.routesRemoved.slice(0, 10).join(', ')}`);
|
|
52
|
+
}
|
|
53
|
+
lines.push('');
|
|
54
|
+
}
|
|
55
|
+
if (snapshot.audit.advisories.length) {
|
|
56
|
+
lines.push('## Top vulnerabilities');
|
|
57
|
+
lines.push('');
|
|
58
|
+
lines.push('| Severity | Package | Title |');
|
|
59
|
+
lines.push('|----------|---------|-------|');
|
|
60
|
+
for (const a of snapshot.audit.advisories.slice(0, 10)) {
|
|
61
|
+
lines.push(`| ${a.severity} | ${a.name} | ${a.title.replace(/\|/g, '/')} |`);
|
|
62
|
+
}
|
|
63
|
+
lines.push('');
|
|
64
|
+
}
|
|
65
|
+
if (snapshot.routes.length) {
|
|
66
|
+
lines.push('## Routes');
|
|
67
|
+
lines.push('');
|
|
68
|
+
for (const r of snapshot.routes.slice(0, 50)) {
|
|
69
|
+
lines.push(`- \`${r}\``);
|
|
70
|
+
}
|
|
71
|
+
if (snapshot.routes.length > 50) {
|
|
72
|
+
lines.push(`- … +${snapshot.routes.length - 50} more`);
|
|
73
|
+
}
|
|
74
|
+
lines.push('');
|
|
75
|
+
}
|
|
76
|
+
lines.push('---');
|
|
77
|
+
lines.push('*Generated by [sublyzer-snapshot](https://github.com/sublyzer-one/sublyzer-snapshot)*');
|
|
78
|
+
lines.push('');
|
|
79
|
+
return lines.join('\n');
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/report/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type AuditSummary = {
|
|
2
|
+
ran: boolean;
|
|
3
|
+
total: number;
|
|
4
|
+
critical: number;
|
|
5
|
+
high: number;
|
|
6
|
+
moderate: number;
|
|
7
|
+
low: number;
|
|
8
|
+
advisories: {
|
|
9
|
+
name: string;
|
|
10
|
+
severity: string;
|
|
11
|
+
title: string;
|
|
12
|
+
}[];
|
|
13
|
+
error?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function runNpmAudit(root?: string): AuditSummary;
|
|
16
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/scan/audit.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,SAAgB,GAAG,YAAY,CAwD9D"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
export function runNpmAudit(root = process.cwd()) {
|
|
3
|
+
const empty = {
|
|
4
|
+
ran: false,
|
|
5
|
+
total: 0,
|
|
6
|
+
critical: 0,
|
|
7
|
+
high: 0,
|
|
8
|
+
moderate: 0,
|
|
9
|
+
low: 0,
|
|
10
|
+
advisories: [],
|
|
11
|
+
};
|
|
12
|
+
const res = spawnSync(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['audit', '--json'], {
|
|
13
|
+
cwd: root,
|
|
14
|
+
encoding: 'utf8',
|
|
15
|
+
timeout: 120_000,
|
|
16
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
17
|
+
});
|
|
18
|
+
const stdout = res.stdout || '';
|
|
19
|
+
if (!stdout.trim()) {
|
|
20
|
+
return { ...empty, error: res.stderr?.slice(0, 200) || 'npm audit produced no output' };
|
|
21
|
+
}
|
|
22
|
+
let parsed;
|
|
23
|
+
try {
|
|
24
|
+
parsed = JSON.parse(stdout);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return { ...empty, error: 'Failed to parse npm audit JSON' };
|
|
28
|
+
}
|
|
29
|
+
const meta = parsed.metadata?.vulnerabilities || {};
|
|
30
|
+
const advisories = [];
|
|
31
|
+
const vulns = parsed.vulnerabilities || parsed.advisories || {};
|
|
32
|
+
if (typeof vulns === 'object') {
|
|
33
|
+
for (const [name, entry] of Object.entries(vulns)) {
|
|
34
|
+
const severity = String(entry?.severity || entry?.via?.[0]?.severity || 'unknown').toLowerCase();
|
|
35
|
+
const title = String(entry?.via?.[0]?.title || entry?.title || name).slice(0, 200);
|
|
36
|
+
advisories.push({ name, severity, title });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
advisories.sort((a, b) => {
|
|
40
|
+
const rank = (s) => ({ critical: 0, high: 1, moderate: 2, low: 3 }[s] ?? 4);
|
|
41
|
+
return rank(a.severity) - rank(b.severity);
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
ran: true,
|
|
45
|
+
total: Number(meta.total ?? advisories.length) || advisories.length,
|
|
46
|
+
critical: Number(meta.critical ?? 0),
|
|
47
|
+
high: Number(meta.high ?? 0),
|
|
48
|
+
moderate: Number(meta.moderate ?? 0),
|
|
49
|
+
low: Number(meta.low ?? 0),
|
|
50
|
+
advisories: advisories.slice(0, 25),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/scan/audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ProjectSnapshot } from './snapshot.js';
|
|
2
|
+
export type HealthGrade = 'A' | 'B' | 'C' | 'D' | 'F';
|
|
3
|
+
export type HealthScore = {
|
|
4
|
+
score: number;
|
|
5
|
+
grade: HealthGrade;
|
|
6
|
+
factors: {
|
|
7
|
+
label: string;
|
|
8
|
+
impact: number;
|
|
9
|
+
}[];
|
|
10
|
+
};
|
|
11
|
+
export declare function computeHealthScore(snapshot: ProjectSnapshot): HealthScore;
|
|
12
|
+
export declare function formatHealthBar(score: number): string;
|
|
13
|
+
//# sourceMappingURL=health-score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-score.d.ts","sourceRoot":"","sources":["../../src/scan/health-score.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,MAAM,WAAW,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEtD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC9C,CAAC;AAUF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,eAAe,GAAG,WAAW,CAiDzE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIrD"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
function gradeFromScore(score) {
|
|
2
|
+
if (score >= 90)
|
|
3
|
+
return 'A';
|
|
4
|
+
if (score >= 80)
|
|
5
|
+
return 'B';
|
|
6
|
+
if (score >= 70)
|
|
7
|
+
return 'C';
|
|
8
|
+
if (score >= 60)
|
|
9
|
+
return 'D';
|
|
10
|
+
return 'F';
|
|
11
|
+
}
|
|
12
|
+
export function computeHealthScore(snapshot) {
|
|
13
|
+
let score = 100;
|
|
14
|
+
const factors = [];
|
|
15
|
+
const s = snapshot.summary;
|
|
16
|
+
if (s.criticalVulns > 0) {
|
|
17
|
+
const impact = Math.min(50, s.criticalVulns * 25);
|
|
18
|
+
score -= impact;
|
|
19
|
+
factors.push({ label: `${s.criticalVulns} critical CVE(s)`, impact: -impact });
|
|
20
|
+
}
|
|
21
|
+
if (s.highVulns > 0) {
|
|
22
|
+
const impact = Math.min(30, s.highVulns * 10);
|
|
23
|
+
score -= impact;
|
|
24
|
+
factors.push({ label: `${s.highVulns} high CVE(s)`, impact: -impact });
|
|
25
|
+
}
|
|
26
|
+
if (snapshot.audit.moderate > 0) {
|
|
27
|
+
const impact = Math.min(15, snapshot.audit.moderate * 3);
|
|
28
|
+
score -= impact;
|
|
29
|
+
factors.push({ label: `${snapshot.audit.moderate} moderate CVE(s)`, impact: -impact });
|
|
30
|
+
}
|
|
31
|
+
const webStacks = new Set(['nextjs', 'nestjs', 'express', 'fastify', 'remix', 'nuxt', 'sveltekit', 'react']);
|
|
32
|
+
if (webStacks.has(snapshot.stack.id) && s.routeCount === 0) {
|
|
33
|
+
score -= 8;
|
|
34
|
+
factors.push({ label: 'No routes detected', impact: -8 });
|
|
35
|
+
}
|
|
36
|
+
if (snapshot.git.available && snapshot.git.dirty) {
|
|
37
|
+
score -= 3;
|
|
38
|
+
factors.push({ label: 'Uncommitted changes (dirty git)', impact: -3 });
|
|
39
|
+
}
|
|
40
|
+
if (snapshot.env.found.length === 0 && snapshot.dependencyCount > 0) {
|
|
41
|
+
score -= 2;
|
|
42
|
+
factors.push({ label: 'No .env.example found', impact: -2 });
|
|
43
|
+
}
|
|
44
|
+
if (snapshot.outdated?.majorCount && snapshot.outdated.majorCount > 0) {
|
|
45
|
+
const impact = Math.min(12, snapshot.outdated.majorCount * 3);
|
|
46
|
+
score -= impact;
|
|
47
|
+
factors.push({ label: `${snapshot.outdated.majorCount} major outdated package(s)`, impact: -impact });
|
|
48
|
+
}
|
|
49
|
+
if (snapshot.workspaces?.packages && snapshot.workspaces.packages.length > 1) {
|
|
50
|
+
factors.push({ label: `Monorepo (${snapshot.workspaces.packages.length} packages)`, impact: 0 });
|
|
51
|
+
}
|
|
52
|
+
score = Math.max(0, Math.min(100, Math.round(score)));
|
|
53
|
+
return { score, grade: gradeFromScore(score), factors };
|
|
54
|
+
}
|
|
55
|
+
export function formatHealthBar(score) {
|
|
56
|
+
const filled = Math.round(score / 10);
|
|
57
|
+
const bar = '█'.repeat(filled) + '░'.repeat(10 - filled);
|
|
58
|
+
return `[${bar}] ${score}/100`;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=health-score.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-score.js","sourceRoot":"","sources":["../../src/scan/health-score.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ProjectSnapshot } from './snapshot.js';
|
|
2
|
+
export declare function lastSnapshotPath(root: string): string;
|
|
3
|
+
export declare function historyDir(root: string): string;
|
|
4
|
+
export declare function saveScanHistory(snapshot: ProjectSnapshot, root?: string): void;
|
|
5
|
+
export declare function loadLastSnapshot(root?: string): ProjectSnapshot | null;
|
|
6
|
+
export declare function loadPreviousSnapshot(root?: string): ProjectSnapshot | null;
|
|
7
|
+
export type SnapshotDiff = {
|
|
8
|
+
routesAdded: string[];
|
|
9
|
+
routesRemoved: string[];
|
|
10
|
+
vulnDelta: {
|
|
11
|
+
critical: number;
|
|
12
|
+
high: number;
|
|
13
|
+
total: number;
|
|
14
|
+
};
|
|
15
|
+
depDelta: number;
|
|
16
|
+
healthDelta: number | null;
|
|
17
|
+
previousAt: string | null;
|
|
18
|
+
currentAt: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function diffSnapshots(previous: ProjectSnapshot | null, current: ProjectSnapshot, healthDelta?: number | null): SnapshotDiff;
|
|
21
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/scan/history.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAMrD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,SAAgB,GAAG,IAAI,CAyBrF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,SAAgB,GAAG,eAAe,GAAG,IAAI,CAQ7E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,SAAgB,GAAG,eAAe,GAAG,IAAI,CAcjF;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,eAAe,GAAG,IAAI,EAChC,OAAO,EAAE,eAAe,EACxB,WAAW,GAAE,MAAM,GAAG,IAAW,GAChC,YAAY,CAiBd"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { CONFIG_DIR, HISTORY_DIR, LAST_SNAPSHOT_FILE, MAX_HISTORY_FILES, } from '../constants.js';
|
|
4
|
+
function sublyzerDir(root) {
|
|
5
|
+
return path.join(root, CONFIG_DIR);
|
|
6
|
+
}
|
|
7
|
+
export function lastSnapshotPath(root) {
|
|
8
|
+
return path.join(sublyzerDir(root), LAST_SNAPSHOT_FILE);
|
|
9
|
+
}
|
|
10
|
+
export function historyDir(root) {
|
|
11
|
+
return path.join(sublyzerDir(root), HISTORY_DIR);
|
|
12
|
+
}
|
|
13
|
+
export function saveScanHistory(snapshot, root = process.cwd()) {
|
|
14
|
+
const dir = sublyzerDir(root);
|
|
15
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
16
|
+
const payload = JSON.stringify(snapshot, null, 2);
|
|
17
|
+
fs.writeFileSync(lastSnapshotPath(root), `${payload}\n`, 'utf8');
|
|
18
|
+
const hist = historyDir(root);
|
|
19
|
+
fs.mkdirSync(hist, { recursive: true });
|
|
20
|
+
const stamp = snapshot.scannedAt.replace(/[:.]/g, '-');
|
|
21
|
+
fs.writeFileSync(path.join(hist, `${stamp}.json`), `${payload}\n`, 'utf8');
|
|
22
|
+
const files = fs
|
|
23
|
+
.readdirSync(hist)
|
|
24
|
+
.filter((f) => f.endsWith('.json'))
|
|
25
|
+
.sort()
|
|
26
|
+
.reverse();
|
|
27
|
+
for (const old of files.slice(MAX_HISTORY_FILES)) {
|
|
28
|
+
try {
|
|
29
|
+
fs.unlinkSync(path.join(hist, old));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
/* ignore */
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function loadLastSnapshot(root = process.cwd()) {
|
|
37
|
+
const file = lastSnapshotPath(root);
|
|
38
|
+
if (!fs.existsSync(file))
|
|
39
|
+
return null;
|
|
40
|
+
try {
|
|
41
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function loadPreviousSnapshot(root = process.cwd()) {
|
|
48
|
+
const hist = historyDir(root);
|
|
49
|
+
if (!fs.existsSync(hist))
|
|
50
|
+
return null;
|
|
51
|
+
const files = fs
|
|
52
|
+
.readdirSync(hist)
|
|
53
|
+
.filter((f) => f.endsWith('.json'))
|
|
54
|
+
.sort()
|
|
55
|
+
.reverse();
|
|
56
|
+
if (files.length < 2)
|
|
57
|
+
return null;
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(fs.readFileSync(path.join(hist, files[1]), 'utf8'));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function diffSnapshots(previous, current, healthDelta = null) {
|
|
66
|
+
const prevRoutes = new Set(previous?.routes || []);
|
|
67
|
+
const curRoutes = new Set(current.routes);
|
|
68
|
+
return {
|
|
69
|
+
routesAdded: current.routes.filter((r) => !prevRoutes.has(r)),
|
|
70
|
+
routesRemoved: (previous?.routes || []).filter((r) => !curRoutes.has(r)),
|
|
71
|
+
vulnDelta: {
|
|
72
|
+
critical: current.summary.criticalVulns - (previous?.summary.criticalVulns ?? 0),
|
|
73
|
+
high: current.summary.highVulns - (previous?.summary.highVulns ?? 0),
|
|
74
|
+
total: current.summary.vulnerablePackages - (previous?.summary.vulnerablePackages ?? 0),
|
|
75
|
+
},
|
|
76
|
+
depDelta: current.dependencyCount - (previous?.dependencyCount ?? 0),
|
|
77
|
+
healthDelta,
|
|
78
|
+
previousAt: previous?.scannedAt ?? null,
|
|
79
|
+
currentAt: current.scannedAt,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/scan/history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type OutdatedSummary = {
|
|
2
|
+
ran: boolean;
|
|
3
|
+
total: number;
|
|
4
|
+
majorCount: number;
|
|
5
|
+
packages: {
|
|
6
|
+
name: string;
|
|
7
|
+
current: string;
|
|
8
|
+
wanted: string;
|
|
9
|
+
latest: string;
|
|
10
|
+
kind: 'major' | 'minor' | 'patch';
|
|
11
|
+
}[];
|
|
12
|
+
error?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function runNpmOutdated(root?: string): OutdatedSummary;
|
|
15
|
+
//# sourceMappingURL=outdated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outdated.d.ts","sourceRoot":"","sources":["../../src/scan/outdated.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAA;KAAE,EAAE,CAAC;IACjH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAUF,wBAAgB,cAAc,CAAC,IAAI,SAAgB,GAAG,eAAe,CA8CpE"}
|