safe-pkg 1.0.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 +304 -0
- package/dist/.DS_Store +0 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.js +135 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/parser.d.ts +5 -0
- package/dist/cli/parser.js +61 -0
- package/dist/cli/parser.js.map +1 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loadConfig.d.ts +5 -0
- package/dist/config/loadConfig.js +49 -0
- package/dist/config/loadConfig.js.map +1 -0
- package/dist/detector/detectPackageManager.d.ts +14 -0
- package/dist/detector/detectPackageManager.js +68 -0
- package/dist/detector/detectPackageManager.js.map +1 -0
- package/dist/detector/index.d.ts +1 -0
- package/dist/detector/index.js +3 -0
- package/dist/detector/index.js.map +1 -0
- package/dist/executor/index.d.ts +1 -0
- package/dist/executor/index.js +3 -0
- package/dist/executor/index.js.map +1 -0
- package/dist/executor/runCommand.d.ts +9 -0
- package/dist/executor/runCommand.js +61 -0
- package/dist/executor/runCommand.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/aiAnalyzer.d.ts +6 -0
- package/dist/scanner/aiAnalyzer.js +92 -0
- package/dist/scanner/aiAnalyzer.js.map +1 -0
- package/dist/scanner/analyzePackage.d.ts +5 -0
- package/dist/scanner/analyzePackage.js +155 -0
- package/dist/scanner/analyzePackage.js.map +1 -0
- package/dist/scanner/auditAnalyzer.d.ts +11 -0
- package/dist/scanner/auditAnalyzer.js +113 -0
- package/dist/scanner/auditAnalyzer.js.map +1 -0
- package/dist/scanner/heuristicAnalyzer.d.ts +5 -0
- package/dist/scanner/heuristicAnalyzer.js +228 -0
- package/dist/scanner/heuristicAnalyzer.js.map +1 -0
- package/dist/scanner/index.d.ts +6 -0
- package/dist/scanner/index.js +8 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/metadataAnalyzer.d.ts +5 -0
- package/dist/scanner/metadataAnalyzer.js +136 -0
- package/dist/scanner/metadataAnalyzer.js.map +1 -0
- package/dist/scanner/scriptAnalyzer.d.ts +5 -0
- package/dist/scanner/scriptAnalyzer.js +187 -0
- package/dist/scanner/scriptAnalyzer.js.map +1 -0
- package/dist/scanner-project/batchAnalyze.d.ts +1 -0
- package/dist/scanner-project/batchAnalyze.js +4 -0
- package/dist/scanner-project/batchAnalyze.js.map +1 -0
- package/dist/scanner-project/index.d.ts +4 -0
- package/dist/scanner-project/index.js +6 -0
- package/dist/scanner-project/index.js.map +1 -0
- package/dist/scanner-project/readDependencies.d.ts +5 -0
- package/dist/scanner-project/readDependencies.js +28 -0
- package/dist/scanner-project/readDependencies.js.map +1 -0
- package/dist/scanner-project/scanNodeModules.d.ts +1 -0
- package/dist/scanner-project/scanNodeModules.js +4 -0
- package/dist/scanner-project/scanNodeModules.js.map +1 -0
- package/dist/scanner-project/scanProject.d.ts +5 -0
- package/dist/scanner-project/scanProject.js +69 -0
- package/dist/scanner-project/scanProject.js.map +1 -0
- package/dist/test.d.ts +6 -0
- package/dist/test.js +153 -0
- package/dist/test.js.map +1 -0
- package/dist/types.d.ts +133 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +6 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/logger.d.ts +24 -0
- package/dist/ui/logger.js +39 -0
- package/dist/ui/logger.js.map +1 -0
- package/dist/ui/promptUser.d.ts +12 -0
- package/dist/ui/promptUser.js +50 -0
- package/dist/ui/promptUser.js.map +1 -0
- package/dist/ui/riskReporter.d.ts +5 -0
- package/dist/ui/riskReporter.js +157 -0
- package/dist/ui/riskReporter.js.map +1 -0
- package/dist/ui/scanReporter.d.ts +1 -0
- package/dist/ui/scanReporter.js +4 -0
- package/dist/ui/scanReporter.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { execa } from "execa";
|
|
4
|
+
/**
|
|
5
|
+
* Detect package manager from lock files in the given directory
|
|
6
|
+
* Priority: pnpm > yarn > npm
|
|
7
|
+
*/
|
|
8
|
+
export async function detectPackageManager(cwd = process.cwd()) {
|
|
9
|
+
// Check for lock files
|
|
10
|
+
const lockFileMap = [
|
|
11
|
+
{ file: "pnpm-lock.yaml", manager: "pnpm" },
|
|
12
|
+
{ file: "yarn.lock", manager: "yarn" },
|
|
13
|
+
{ file: "package-lock.json", manager: "npm" },
|
|
14
|
+
];
|
|
15
|
+
for (const { file, manager } of lockFileMap) {
|
|
16
|
+
if (existsSync(join(cwd, file))) {
|
|
17
|
+
return manager;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Fallback: check which package manager binary is available
|
|
21
|
+
const availableManager = await detectAvailablePackageManager();
|
|
22
|
+
if (availableManager) {
|
|
23
|
+
return availableManager;
|
|
24
|
+
}
|
|
25
|
+
// Final fallback: npm (most commonly available)
|
|
26
|
+
return "npm";
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check which package manager binaries are available on the system
|
|
30
|
+
*/
|
|
31
|
+
async function detectAvailablePackageManager() {
|
|
32
|
+
const managers = ["pnpm", "yarn", "npm"];
|
|
33
|
+
for (const manager of managers) {
|
|
34
|
+
try {
|
|
35
|
+
await execa("which", [manager]);
|
|
36
|
+
return manager;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Binary not found, continue to next
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Check if a specific package manager is available
|
|
46
|
+
*/
|
|
47
|
+
export async function isPackageManagerAvailable(manager) {
|
|
48
|
+
try {
|
|
49
|
+
await execa("which", [manager]);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get the version of a package manager
|
|
58
|
+
*/
|
|
59
|
+
export async function getPackageManagerVersion(manager) {
|
|
60
|
+
try {
|
|
61
|
+
const { stdout } = await execa(manager, ["--version"]);
|
|
62
|
+
return stdout.trim();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=detectPackageManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectPackageManager.js","sourceRoot":"","sources":["../../src/detector/detectPackageManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAG9B;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACzC,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,uBAAuB;IACvB,MAAM,WAAW,GAAqD;QACrE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE;QAC3C,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE;QACtC,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE;KAC7C,CAAC;IAEF,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,WAAW,EAAE,CAAC;QAC7C,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;YACjC,OAAO,OAAO,CAAC;QAChB,CAAC;IACF,CAAC;IAED,4DAA4D;IAC5D,MAAM,gBAAgB,GAAG,MAAM,6BAA6B,EAAE,CAAC;IAC/D,IAAI,gBAAgB,EAAE,CAAC;QACtB,OAAO,gBAAgB,CAAC;IACzB,CAAC;IAED,gDAAgD;IAChD,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,6BAA6B;IAC3C,MAAM,QAAQ,GAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAE3D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAChC,IAAI,CAAC;YACJ,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YAChC,OAAO,OAAO,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACR,qCAAqC;QACtC,CAAC;IACF,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC9C,OAAuB;IAEvB,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC7C,OAAuB;IAEvB,IAAI,CAAC;QACJ,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QACvD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { detectPackageManager, isPackageManagerAvailable, getPackageManagerVersion, } from "./detectPackageManager.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detector/index.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,OAAO,EACN,oBAAoB,EACpB,yBAAyB,EACzB,wBAAwB,GACxB,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./runCommand.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/executor/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PackageManager } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Execute package manager install command
|
|
4
|
+
*/
|
|
5
|
+
export declare function runInstallCommand(packageManager: PackageManager, packages: string[], options?: Record<string, unknown>): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Execute arbitrary package manager command
|
|
8
|
+
*/
|
|
9
|
+
export declare function runPackageManagerCommand(packageManager: PackageManager, args: string[]): Promise<void>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
import { logError, logStep, logSuccess } from "../ui/logger.js";
|
|
3
|
+
/**
|
|
4
|
+
* Execute package manager install command
|
|
5
|
+
*/
|
|
6
|
+
export async function runInstallCommand(packageManager, packages, options = {}) {
|
|
7
|
+
const args = [];
|
|
8
|
+
// Build command arguments based on package manager
|
|
9
|
+
if (packageManager === "npm") {
|
|
10
|
+
args.push("install");
|
|
11
|
+
if (options.saveDev)
|
|
12
|
+
args.push("--save-dev");
|
|
13
|
+
if (options.global)
|
|
14
|
+
args.push("--global");
|
|
15
|
+
}
|
|
16
|
+
else if (packageManager === "yarn") {
|
|
17
|
+
args.push("add");
|
|
18
|
+
if (options.saveDev)
|
|
19
|
+
args.push("--dev");
|
|
20
|
+
if (options.global)
|
|
21
|
+
args.push("global");
|
|
22
|
+
}
|
|
23
|
+
else if (packageManager === "pnpm") {
|
|
24
|
+
args.push("add");
|
|
25
|
+
if (options.saveDev)
|
|
26
|
+
args.push("--save-dev");
|
|
27
|
+
if (options.global)
|
|
28
|
+
args.push("--global");
|
|
29
|
+
}
|
|
30
|
+
// Add package names
|
|
31
|
+
args.push(...packages);
|
|
32
|
+
logStep(`Running: ${packageManager} ${args.join(" ")}`);
|
|
33
|
+
try {
|
|
34
|
+
// Run package manager command
|
|
35
|
+
await execa(packageManager, args, {
|
|
36
|
+
stdio: "inherit",
|
|
37
|
+
cwd: process.cwd(),
|
|
38
|
+
});
|
|
39
|
+
logSuccess(`Successfully installed ${packages.length} package(s)`);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
logError(`Installation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Execute arbitrary package manager command
|
|
48
|
+
*/
|
|
49
|
+
export async function runPackageManagerCommand(packageManager, args) {
|
|
50
|
+
try {
|
|
51
|
+
await execa(packageManager, args, {
|
|
52
|
+
stdio: "inherit",
|
|
53
|
+
cwd: process.cwd(),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
logError(`Command failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=runCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runCommand.js","sourceRoot":"","sources":["../../src/executor/runCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEhE;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACtC,cAA8B,EAC9B,QAAkB,EAClB,UAAmC,EAAE;IAErC,MAAM,IAAI,GAAa,EAAE,CAAC;IAE1B,mDAAmD;IACnD,IAAI,cAAc,KAAK,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrB,IAAI,OAAO,CAAC,OAAO;YAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC;SAAM,IAAI,cAAc,KAAK,MAAM,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,IAAI,OAAO,CAAC,OAAO;YAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;SAAM,IAAI,cAAc,KAAK,MAAM,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,IAAI,OAAO,CAAC,OAAO;YAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC;IAED,oBAAoB;IACpB,IAAI,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;IAEvB,OAAO,CAAC,YAAY,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAExD,IAAI,CAAC;QACJ,8BAA8B;QAC9B,MAAM,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE;YACjC,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;SAClB,CAAC,CAAC;QAEH,UAAU,CAAC,0BAA0B,QAAQ,CAAC,MAAM,aAAa,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,QAAQ,CACP,wBAAwB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAChF,CAAC;QACF,MAAM,KAAK,CAAC;IACb,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC7C,cAA8B,EAC9B,IAAc;IAEd,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE;YACjC,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;SAClB,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,QAAQ,CACP,mBAAmB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC3E,CAAC;QACF,MAAM,KAAK,CAAC;IACb,CAAC;AACF,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./cli/index.js";
|
|
3
|
+
export * from "./config/index.js";
|
|
4
|
+
export * from "./detector/index.js";
|
|
5
|
+
export * from "./scanner/index.js";
|
|
6
|
+
export * from "./scanner-project/index.js";
|
|
7
|
+
export * from "./executor/index.js";
|
|
8
|
+
export * from "./ui/index.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Export all types
|
|
2
|
+
export * from "./types.js";
|
|
3
|
+
// Export module interfaces (implementations will be added in later phases)
|
|
4
|
+
export * from "./cli/index.js";
|
|
5
|
+
export * from "./config/index.js";
|
|
6
|
+
export * from "./detector/index.js";
|
|
7
|
+
export * from "./scanner/index.js";
|
|
8
|
+
export * from "./scanner-project/index.js";
|
|
9
|
+
export * from "./executor/index.js";
|
|
10
|
+
export * from "./ui/index.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,cAAc,YAAY,CAAC;AAE3B,2EAA2E;AAC3E,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RiskReport } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Enhance risk report with AI insights using Anthropic Claude
|
|
4
|
+
* This is optional and only runs if API key is provided
|
|
5
|
+
*/
|
|
6
|
+
export declare function enhanceWithAI(report: RiskReport, apiKey: string): Promise<RiskReport>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhance risk report with AI insights using Anthropic Claude
|
|
3
|
+
* This is optional and only runs if API key is provided
|
|
4
|
+
*/
|
|
5
|
+
export async function enhanceWithAI(report, apiKey) {
|
|
6
|
+
try {
|
|
7
|
+
// Dynamically import Anthropic SDK (optional dependency)
|
|
8
|
+
const { default: Anthropic } = await import("@anthropic-ai/sdk");
|
|
9
|
+
const client = new Anthropic({
|
|
10
|
+
apiKey,
|
|
11
|
+
});
|
|
12
|
+
// Prepare analysis summary for Claude
|
|
13
|
+
const analysisContext = prepareAnalysisContext(report);
|
|
14
|
+
// Call Claude API
|
|
15
|
+
const message = await client.messages.create({
|
|
16
|
+
model: "claude-3-5-sonnet-20241022",
|
|
17
|
+
max_tokens: 500,
|
|
18
|
+
messages: [
|
|
19
|
+
{
|
|
20
|
+
role: "user",
|
|
21
|
+
content: `You are a security expert analyzing an npm package. Here's the automated analysis:
|
|
22
|
+
|
|
23
|
+
Package: ${report.packageName}
|
|
24
|
+
Risk Score: ${report.riskScore}/10
|
|
25
|
+
Risk Level: ${report.riskLevel}
|
|
26
|
+
|
|
27
|
+
Analysis Results:
|
|
28
|
+
${analysisContext}
|
|
29
|
+
|
|
30
|
+
Provide a brief security assessment (2-3 sentences) explaining:
|
|
31
|
+
1. The main security concerns or why it's safe
|
|
32
|
+
2. Any additional context a developer should know
|
|
33
|
+
3. Your recommendation
|
|
34
|
+
|
|
35
|
+
Be concise and focus on actionable insights.`,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
// Extract AI insights from response
|
|
40
|
+
const aiInsights = message.content[0]?.type === "text" ? message.content[0].text : "";
|
|
41
|
+
// Return enhanced report
|
|
42
|
+
return {
|
|
43
|
+
...report,
|
|
44
|
+
analyzers: {
|
|
45
|
+
...report.analyzers,
|
|
46
|
+
aiInsights,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
// If AI enhancement fails, return original report
|
|
52
|
+
// This ensures the tool still works without AI
|
|
53
|
+
return report;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Prepare analysis context for AI
|
|
58
|
+
*/
|
|
59
|
+
function prepareAnalysisContext(report) {
|
|
60
|
+
const parts = [];
|
|
61
|
+
// Audit results
|
|
62
|
+
if (report.analyzers.audit) {
|
|
63
|
+
const audit = report.analyzers.audit;
|
|
64
|
+
parts.push(`- Vulnerabilities: ${audit.vulnerabilityCount} total (${audit.criticalCount} critical, ${audit.highCount} high)`);
|
|
65
|
+
}
|
|
66
|
+
// Metadata results
|
|
67
|
+
if (report.analyzers.metadata) {
|
|
68
|
+
const meta = report.analyzers.metadata;
|
|
69
|
+
parts.push(`- Downloads: ${meta.downloads.toLocaleString()}/week, ${meta.packageAge} days old`);
|
|
70
|
+
parts.push(`- Maintainers: ${meta.maintainerCount}, License: ${meta.hasLicense ? "Yes" : "No"}`);
|
|
71
|
+
}
|
|
72
|
+
// Script results
|
|
73
|
+
if (report.analyzers.script) {
|
|
74
|
+
const script = report.analyzers.script;
|
|
75
|
+
if (script.hasSuspiciousScripts) {
|
|
76
|
+
parts.push(`- Suspicious scripts detected: ${script.suspiciousScripts.join(", ")}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Heuristic results
|
|
80
|
+
if (report.analyzers.heuristic) {
|
|
81
|
+
const heuristic = report.analyzers.heuristic;
|
|
82
|
+
if (heuristic.suspiciousPatterns.length > 0) {
|
|
83
|
+
parts.push(`- Pattern warnings: ${heuristic.suspiciousPatterns.join(", ")}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Warnings
|
|
87
|
+
if (report.warnings.length > 0) {
|
|
88
|
+
parts.push(`- Warnings: ${report.warnings.map((w) => w.message).join("; ")}`);
|
|
89
|
+
}
|
|
90
|
+
return parts.join("\n");
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=aiAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiAnalyzer.js","sourceRoot":"","sources":["../../src/scanner/aiAnalyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { enhanceWithAI } from "./aiAnalyzer.js";
|
|
2
|
+
import { analyzeWithAudit } from "./auditAnalyzer.js";
|
|
3
|
+
import { analyzeHeuristics } from "./heuristicAnalyzer.js";
|
|
4
|
+
import { analyzeMetadata } from "./metadataAnalyzer.js";
|
|
5
|
+
import { analyzeScripts } from "./scriptAnalyzer.js";
|
|
6
|
+
/**
|
|
7
|
+
* Main orchestrator that runs all analysis layers and combines results
|
|
8
|
+
*/
|
|
9
|
+
export async function analyzePackage(packageName, config) {
|
|
10
|
+
// Run all analyzers in parallel for performance
|
|
11
|
+
const [auditResult, metadataResult, scriptResult] = await Promise.all([
|
|
12
|
+
analyzeWithAudit(packageName).catch(() => null), // Gracefully handle failures
|
|
13
|
+
analyzeMetadata(packageName).catch(() => null),
|
|
14
|
+
analyzeScripts(packageName).catch(() => null),
|
|
15
|
+
]);
|
|
16
|
+
// Heuristic analyzer is synchronous
|
|
17
|
+
const heuristicResult = analyzeHeuristics(packageName);
|
|
18
|
+
// Calculate weighted risk score
|
|
19
|
+
// Weights: audit=40%, metadata=25%, scripts=25%, heuristics=10%
|
|
20
|
+
let totalScore = 0;
|
|
21
|
+
let totalWeight = 0;
|
|
22
|
+
if (auditResult) {
|
|
23
|
+
// Only count audit if there's actual package data
|
|
24
|
+
// If no vulnerabilities but also no package, don't count it as "safe"
|
|
25
|
+
if (auditResult.vulnerabilityCount > 0 ||
|
|
26
|
+
(metadataResult?.downloads ?? 0) > 0) {
|
|
27
|
+
totalScore += auditResult.riskScore * 0.4;
|
|
28
|
+
totalWeight += 0.4;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (metadataResult) {
|
|
32
|
+
totalScore += metadataResult.riskScore * 0.25;
|
|
33
|
+
totalWeight += 0.25;
|
|
34
|
+
}
|
|
35
|
+
if (scriptResult) {
|
|
36
|
+
// Only count scripts if the package appears to exist
|
|
37
|
+
if (scriptResult.hasSuspiciousScripts ||
|
|
38
|
+
(metadataResult?.downloads ?? 0) > 0) {
|
|
39
|
+
totalScore += scriptResult.riskScore * 0.25;
|
|
40
|
+
totalWeight += 0.25;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (heuristicResult) {
|
|
44
|
+
totalScore += heuristicResult.riskScore * 0.1;
|
|
45
|
+
totalWeight += 0.1;
|
|
46
|
+
}
|
|
47
|
+
// Normalize score based on available analyzers
|
|
48
|
+
// If metadata shows a risky package (high score, low downloads), ensure minimum risk
|
|
49
|
+
const normalizedScore = totalWeight > 0 ? Math.round(totalScore / totalWeight) : 5;
|
|
50
|
+
// Apply minimum risk for packages with concerning metadata
|
|
51
|
+
let riskScore = normalizedScore;
|
|
52
|
+
if (metadataResult &&
|
|
53
|
+
metadataResult.riskScore >= 7 &&
|
|
54
|
+
(metadataResult.downloads < 100 || metadataResult.maintainerCount === 0)) {
|
|
55
|
+
// Ensure packages with terrible metadata get at least medium risk
|
|
56
|
+
riskScore = Math.max(riskScore, 6);
|
|
57
|
+
}
|
|
58
|
+
// Determine risk level
|
|
59
|
+
const riskLevel = getRiskLevel(riskScore);
|
|
60
|
+
// Collect all warnings
|
|
61
|
+
const warnings = [];
|
|
62
|
+
if (auditResult && auditResult.vulnerabilityCount > 0) {
|
|
63
|
+
warnings.push({
|
|
64
|
+
severity: "critical",
|
|
65
|
+
message: `Found ${auditResult.vulnerabilityCount} vulnerabilities (${auditResult.criticalCount} critical, ${auditResult.highCount} high)`,
|
|
66
|
+
source: "audit",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (metadataResult) {
|
|
70
|
+
if (metadataResult.downloads < 100) {
|
|
71
|
+
warnings.push({
|
|
72
|
+
severity: "medium",
|
|
73
|
+
message: `Low weekly downloads (${metadataResult.downloads})`,
|
|
74
|
+
source: "metadata",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (metadataResult.maintainerCount === 0) {
|
|
78
|
+
warnings.push({
|
|
79
|
+
severity: "high",
|
|
80
|
+
message: "Package has no maintainers",
|
|
81
|
+
source: "metadata",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (!metadataResult.hasLicense) {
|
|
85
|
+
warnings.push({
|
|
86
|
+
severity: "medium",
|
|
87
|
+
message: "Package has no license",
|
|
88
|
+
source: "metadata",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (scriptResult?.hasSuspiciousScripts) {
|
|
93
|
+
warnings.push({
|
|
94
|
+
severity: "high",
|
|
95
|
+
message: `Suspicious scripts detected: ${scriptResult.suspiciousScripts.join(", ")}`,
|
|
96
|
+
source: "script",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (heuristicResult && heuristicResult.suspiciousPatterns.length > 0) {
|
|
100
|
+
warnings.push({
|
|
101
|
+
severity: "medium",
|
|
102
|
+
message: `Pattern warnings: ${heuristicResult.suspiciousPatterns.join(", ")}`,
|
|
103
|
+
source: "heuristic",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Determine recommendation
|
|
107
|
+
const recommendation = getRecommendation(riskLevel, warnings.length);
|
|
108
|
+
// Build initial report
|
|
109
|
+
let report = {
|
|
110
|
+
packageName,
|
|
111
|
+
version: metadataResult?.version ?? "unknown",
|
|
112
|
+
riskScore,
|
|
113
|
+
riskLevel,
|
|
114
|
+
warnings,
|
|
115
|
+
recommendation,
|
|
116
|
+
analyzers: {
|
|
117
|
+
audit: auditResult ?? undefined,
|
|
118
|
+
metadata: metadataResult ?? undefined,
|
|
119
|
+
script: scriptResult ?? undefined,
|
|
120
|
+
heuristic: heuristicResult ?? undefined,
|
|
121
|
+
},
|
|
122
|
+
analyzedAt: new Date(),
|
|
123
|
+
};
|
|
124
|
+
// Optional AI enhancement
|
|
125
|
+
if (config.anthropicApiKey) {
|
|
126
|
+
report = await enhanceWithAI(report, config.anthropicApiKey);
|
|
127
|
+
}
|
|
128
|
+
return report;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Map risk score to risk level
|
|
132
|
+
*/
|
|
133
|
+
function getRiskLevel(score) {
|
|
134
|
+
if (score >= 7)
|
|
135
|
+
return "dangerous";
|
|
136
|
+
if (score >= 4)
|
|
137
|
+
return "caution";
|
|
138
|
+
return "safe";
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Generate recommendation based on risk level and warnings
|
|
142
|
+
*/
|
|
143
|
+
function getRecommendation(level, warningCount) {
|
|
144
|
+
if (level === "dangerous") {
|
|
145
|
+
return "❌ DO NOT INSTALL - Critical security risks detected";
|
|
146
|
+
}
|
|
147
|
+
if (level === "caution") {
|
|
148
|
+
return "⚠️ PROCEED WITH CAUTION - Review security warnings carefully";
|
|
149
|
+
}
|
|
150
|
+
if (warningCount > 0) {
|
|
151
|
+
return "✓ MOSTLY SAFE - Minor concerns detected";
|
|
152
|
+
}
|
|
153
|
+
return "✅ SAFE - No significant security concerns detected";
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=analyzePackage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzePackage.js","sourceRoot":"","sources":["../../src/scanner/analyzePackage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AuditResult } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Analyze a package using npm audit
|
|
4
|
+
* Note: This creates a temporary package.json to audit a specific package
|
|
5
|
+
*/
|
|
6
|
+
export declare function analyzeWithAudit(packageName: string): Promise<AuditResult>;
|
|
7
|
+
/**
|
|
8
|
+
* Analyze a specific package by creating a temporary audit
|
|
9
|
+
* This is more accurate for checking a package before installation
|
|
10
|
+
*/
|
|
11
|
+
export declare function analyzePackageAudit(packageName: string, version?: string): Promise<AuditResult>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
/**
|
|
3
|
+
* Analyze a package using npm audit
|
|
4
|
+
* Note: This creates a temporary package.json to audit a specific package
|
|
5
|
+
*/
|
|
6
|
+
export async function analyzeWithAudit(packageName) {
|
|
7
|
+
try {
|
|
8
|
+
// Try to run npm audit on the package
|
|
9
|
+
// We'll audit in the current context or create a minimal check
|
|
10
|
+
const { stdout } = await execa("npm", ["audit", "--json"], {
|
|
11
|
+
reject: false, // Don't throw on non-zero exit (audit returns exit code 1 if vulnerabilities found)
|
|
12
|
+
});
|
|
13
|
+
const auditData = JSON.parse(stdout);
|
|
14
|
+
return parseAuditOutput(auditData, packageName);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
// If audit fails, return empty result
|
|
18
|
+
return createEmptyAuditResult();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Parse npm audit JSON output
|
|
23
|
+
*/
|
|
24
|
+
function parseAuditOutput(auditData, packageName) {
|
|
25
|
+
if (!auditData || typeof auditData !== "object") {
|
|
26
|
+
return createEmptyAuditResult();
|
|
27
|
+
}
|
|
28
|
+
// npm audit JSON format has vulnerabilities object
|
|
29
|
+
const vulnerabilities = auditData.vulnerabilities || {};
|
|
30
|
+
const metadata = auditData.metadata || {};
|
|
31
|
+
// Count vulnerabilities by severity
|
|
32
|
+
const vulnerabilitiesArray = [];
|
|
33
|
+
let criticalCount = 0;
|
|
34
|
+
let highCount = 0;
|
|
35
|
+
let moderateCount = 0;
|
|
36
|
+
let lowCount = 0;
|
|
37
|
+
// Parse vulnerabilities
|
|
38
|
+
for (const [vulnName, vulnData] of Object.entries(vulnerabilities)) {
|
|
39
|
+
const severity = (vulnData.severity || "moderate").toLowerCase();
|
|
40
|
+
// Count by severity
|
|
41
|
+
if (severity === "critical")
|
|
42
|
+
criticalCount++;
|
|
43
|
+
else if (severity === "high")
|
|
44
|
+
highCount++;
|
|
45
|
+
else if (severity === "moderate")
|
|
46
|
+
moderateCount++;
|
|
47
|
+
else if (severity === "low")
|
|
48
|
+
lowCount++;
|
|
49
|
+
// Extract via information
|
|
50
|
+
const via = Array.isArray(vulnData.via)
|
|
51
|
+
? vulnData.via
|
|
52
|
+
.map((v) => (typeof v === "string" ? v : v.title || ""))
|
|
53
|
+
.filter(Boolean)
|
|
54
|
+
.join(", ")
|
|
55
|
+
: "Unknown";
|
|
56
|
+
vulnerabilitiesArray.push({
|
|
57
|
+
name: vulnName,
|
|
58
|
+
severity: severity,
|
|
59
|
+
via,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const vulnerabilityCount = criticalCount + highCount + moderateCount + lowCount;
|
|
63
|
+
// Calculate risk score based on vulnerability counts
|
|
64
|
+
// Critical = 10, High = 5, Moderate = 2, Low = 1
|
|
65
|
+
const riskScore = Math.min(10, criticalCount * 10 + highCount * 5 + moderateCount * 2 + lowCount * 1);
|
|
66
|
+
return {
|
|
67
|
+
vulnerabilityCount,
|
|
68
|
+
criticalCount,
|
|
69
|
+
highCount,
|
|
70
|
+
moderateCount,
|
|
71
|
+
lowCount,
|
|
72
|
+
vulnerabilities: vulnerabilitiesArray,
|
|
73
|
+
riskScore,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create an empty audit result (no vulnerabilities found)
|
|
78
|
+
*/
|
|
79
|
+
function createEmptyAuditResult() {
|
|
80
|
+
return {
|
|
81
|
+
vulnerabilityCount: 0,
|
|
82
|
+
criticalCount: 0,
|
|
83
|
+
highCount: 0,
|
|
84
|
+
moderateCount: 0,
|
|
85
|
+
lowCount: 0,
|
|
86
|
+
vulnerabilities: [],
|
|
87
|
+
riskScore: 0,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Analyze a specific package by creating a temporary audit
|
|
92
|
+
* This is more accurate for checking a package before installation
|
|
93
|
+
*/
|
|
94
|
+
export async function analyzePackageAudit(packageName, version = "latest") {
|
|
95
|
+
try {
|
|
96
|
+
// Get package info to check for known vulnerabilities
|
|
97
|
+
// We can use npm view to get vulnerability information
|
|
98
|
+
const { stdout } = await execa("npm", [
|
|
99
|
+
"view",
|
|
100
|
+
`${packageName}@${version}`,
|
|
101
|
+
"--json",
|
|
102
|
+
]);
|
|
103
|
+
const packageData = JSON.parse(stdout);
|
|
104
|
+
// Check if the package has any known security issues
|
|
105
|
+
// This is a simplified check - in production, you'd want to cross-reference with vulnerability databases
|
|
106
|
+
return createEmptyAuditResult();
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
// Package not found or other error
|
|
110
|
+
return createEmptyAuditResult();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=auditAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditAnalyzer.js","sourceRoot":"","sources":["../../src/scanner/auditAnalyzer.ts"],"names":[],"mappings":"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"}
|