@maverick006/scanner-npm-audit 1.0.2 → 1.0.4

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/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { SecurityScanner } from '@maverick006/security-engine';
1
+ import { SecurityScanner, ScannerCapability } from '@maverick006/security-engine';
2
2
  import { ScanInput, ScannerResult } from '@maverick006/types';
3
3
  export declare class NpmAuditScanner implements SecurityScanner {
4
4
  name: string;
5
5
  version: string;
6
+ capabilities: ScannerCapability;
6
7
  scan(input: ScanInput): Promise<ScannerResult>;
7
8
  }
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAQ9D,qBAAa,eAAgB,YAAW,eAAe;IAC9C,IAAI,SAAe;IACnB,OAAO,SAAa;IAErB,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC;CAuDrD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,aAAa,EAAgB,MAAM,oBAAoB,CAAC;AAS5E,qBAAa,eAAgB,YAAW,eAAe;IAC9C,IAAI,SAAe;IACnB,OAAO,SAAa;IAEpB,YAAY,EAAE,iBAAiB,CAMpC;IAEI,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC;CAgHrD"}
package/dist/index.js CHANGED
@@ -34,38 +34,95 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.NpmAuditScanner = void 0;
37
+ const types_1 = require("@maverick006/types");
37
38
  const child_process_1 = require("child_process");
38
39
  const util_1 = require("util");
39
40
  const parser_1 = require("./parser");
40
41
  const path = __importStar(require("path"));
41
- const execAsync = (0, util_1.promisify)(child_process_1.exec);
42
+ const fs = __importStar(require("fs"));
43
+ const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
42
44
  class NpmAuditScanner {
43
45
  name = 'npm-audit';
44
46
  version = 'unknown';
47
+ capabilities = {
48
+ category: 'dependencies',
49
+ detectApplicability: (repoPath) => {
50
+ const safePath = path.resolve(repoPath);
51
+ return fs.existsSync(path.join(safePath, 'package.json'));
52
+ }
53
+ };
45
54
  async scan(input) {
46
55
  const startTime = new Date();
47
56
  let rawOutput = '';
57
+ const safePath = path.resolve(input.repositoryPath);
58
+ const hasPackageJson = fs.existsSync(path.join(safePath, 'package.json'));
59
+ if (!hasPackageJson) {
60
+ const endTime = new Date();
61
+ return {
62
+ scanner: this.name,
63
+ success: true,
64
+ state: types_1.ScannerState.SKIPPED,
65
+ reason: 'Skipped: No package.json detected in repository',
66
+ findings: [],
67
+ rawOutput: 'No package.json found',
68
+ startTime,
69
+ endTime,
70
+ durationMs: endTime.getTime() - startTime.getTime()
71
+ };
72
+ }
48
73
  try {
49
- const safePath = path.resolve(input.repositoryPath);
50
- // npm audit --json outputs audit data. We run it in the repository path.
51
- // Note: this assumes package.json exists. If it doesn't, npm audit will fail, which we can catch.
52
- const { stdout } = await execAsync(`npm audit --json --prefix "${safePath}"`, {
53
- timeout: 300000,
54
- maxBuffer: 1024 * 1024 * 50
74
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
75
+ const args = ['audit', '--json'];
76
+ const { stdout } = await execFileAsync(npmCmd, args, {
77
+ cwd: safePath,
78
+ timeout: 60000,
79
+ maxBuffer: 1024 * 1024 * 50,
80
+ shell: process.platform === 'win32'
55
81
  });
56
82
  rawOutput = stdout;
57
83
  const findings = (0, parser_1.parseNpmAuditOutput)(input.scanId, rawOutput);
84
+ const endTime = new Date();
58
85
  return {
59
86
  scanner: this.name,
60
87
  success: true,
88
+ state: types_1.ScannerState.SUCCESS,
61
89
  findings,
62
90
  rawOutput,
63
91
  startTime,
64
- endTime: new Date()
92
+ endTime,
93
+ durationMs: endTime.getTime() - startTime.getTime()
65
94
  };
66
95
  }
67
96
  catch (error) {
68
- // npm audit returns exit code > 0 if vulnerabilities are found
97
+ const endTime = new Date();
98
+ const durationMs = endTime.getTime() - startTime.getTime();
99
+ if (error.code === 'ENOENT') {
100
+ return {
101
+ scanner: this.name,
102
+ success: false,
103
+ state: types_1.ScannerState.NOT_INSTALLED,
104
+ reason: 'npm executable was not found on PATH',
105
+ findings: [],
106
+ error: error.message,
107
+ startTime,
108
+ endTime,
109
+ durationMs
110
+ };
111
+ }
112
+ if (error.code === 'ETIMEDOUT') {
113
+ return {
114
+ scanner: this.name,
115
+ success: false,
116
+ state: types_1.ScannerState.TIMEOUT,
117
+ reason: 'npm-audit execution timed out',
118
+ findings: [],
119
+ error: error.message,
120
+ startTime,
121
+ endTime,
122
+ durationMs
123
+ };
124
+ }
125
+ // npm audit exits > 0 if vulnerabilities are found
69
126
  if (error.stdout && error.stdout.includes('"auditReportVersion":')) {
70
127
  try {
71
128
  rawOutput = error.stdout;
@@ -73,24 +130,28 @@ class NpmAuditScanner {
73
130
  return {
74
131
  scanner: this.name,
75
132
  success: true,
133
+ state: types_1.ScannerState.SUCCESS,
76
134
  findings,
77
135
  rawOutput,
78
136
  startTime,
79
- endTime: new Date()
137
+ endTime,
138
+ durationMs
80
139
  };
81
140
  }
82
- catch (parseError) {
141
+ catch {
83
142
  // ignore parsing error
84
143
  }
85
144
  }
86
145
  return {
87
146
  scanner: this.name,
88
147
  success: false,
148
+ state: types_1.ScannerState.FAILED,
89
149
  findings: [],
90
150
  error: error.message || 'npm audit execution failed',
91
151
  rawOutput: error.stdout || '',
92
152
  startTime,
93
- endTime: new Date()
153
+ endTime,
154
+ durationMs
94
155
  };
95
156
  }
96
157
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,iDAAqC;AACrC,+BAAiC;AACjC,qCAA+C;AAC/C,2CAA6B;AAE7B,MAAM,SAAS,GAAG,IAAA,gBAAS,EAAC,oBAAI,CAAC,CAAC;AAElC,MAAa,eAAe;IACnB,IAAI,GAAG,WAAW,CAAC;IACnB,OAAO,GAAG,SAAS,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,KAAgB;QACzB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,IAAI,SAAS,GAAG,EAAE,CAAC;QAEnB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YAEpD,yEAAyE;YACzE,kGAAkG;YAClG,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,8BAA8B,QAAQ,GAAG,EAAE;gBAC5E,OAAO,EAAE,MAAM;gBACf,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,EAAE;aAC5B,CAAC,CAAC;YAEH,SAAS,GAAG,MAAM,CAAC;YACnB,MAAM,QAAQ,GAAG,IAAA,4BAAmB,EAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YAE9D,OAAO;gBACL,OAAO,EAAE,IAAI,CAAC,IAAI;gBAClB,OAAO,EAAE,IAAI;gBACb,QAAQ;gBACR,SAAS;gBACT,SAAS;gBACT,OAAO,EAAE,IAAI,IAAI,EAAE;aACpB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,+DAA+D;YAC/D,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;gBACnE,IAAI,CAAC;oBACH,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;oBACzB,MAAM,QAAQ,GAAG,IAAA,4BAAmB,EAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;oBAC9D,OAAO;wBACL,OAAO,EAAE,IAAI,CAAC,IAAI;wBAClB,OAAO,EAAE,IAAI;wBACb,QAAQ;wBACR,SAAS;wBACT,SAAS;wBACT,OAAO,EAAE,IAAI,IAAI,EAAE;qBACpB,CAAC;gBACJ,CAAC;gBAAC,OAAO,UAAU,EAAE,CAAC;oBACpB,uBAAuB;gBACzB,CAAC;YACH,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,IAAI,CAAC,IAAI;gBAClB,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,KAAK,CAAC,OAAO,IAAI,4BAA4B;gBACpD,SAAS,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;gBAC7B,SAAS;gBACT,OAAO,EAAE,IAAI,IAAI,EAAE;aACpB,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AA3DD,0CA2DC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,23 +1,23 @@
1
- {
2
- "name": "@maverick006/scanner-npm-audit",
3
- "version": "1.0.2",
4
- "main": "dist/index.js",
5
- "types": "dist/index.d.ts",
6
- "scripts": {
7
- "build": "tsc",
8
- "clean": "rm -rf dist",
9
- "test": "jest",
10
- "typecheck": "tsc --noEmit"
11
- },
12
- "dependencies": {
13
- "@maverick006/types": "*",
14
- "@maverick006/security-engine": "*"
15
- },
16
- "devDependencies": {
17
- "typescript": "^5.0.0",
18
- "jest": "^29.5.0",
19
- "@types/jest": "^29.5.0",
20
- "ts-jest": "^29.1.0",
21
- "@types/node": "^20.0.0"
22
- }
23
- }
1
+ {
2
+ "name": "@maverick006/scanner-npm-audit",
3
+ "version": "1.0.4",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "clean": "rm -rf dist",
9
+ "test": "jest",
10
+ "typecheck": "tsc --noEmit"
11
+ },
12
+ "dependencies": {
13
+ "@maverick006/types": "*",
14
+ "@maverick006/security-engine": "*"
15
+ },
16
+ "devDependencies": {
17
+ "typescript": "^5.0.0",
18
+ "jest": "^29.5.0",
19
+ "@types/jest": "^29.5.0",
20
+ "ts-jest": "^29.1.0",
21
+ "@types/node": "^20.0.0"
22
+ }
23
+ }
package/src/index.ts CHANGED
@@ -1,43 +1,105 @@
1
- import { SecurityScanner } from '@maverick006/security-engine';
2
- import { ScanInput, ScannerResult } from '@maverick006/types';
3
- import { exec } from 'child_process';
1
+ import { SecurityScanner, ScannerCapability } from '@maverick006/security-engine';
2
+ import { ScanInput, ScannerResult, ScannerState } from '@maverick006/types';
3
+ import { execFile } from 'child_process';
4
4
  import { promisify } from 'util';
5
5
  import { parseNpmAuditOutput } from './parser';
6
6
  import * as path from 'path';
7
+ import * as fs from 'fs';
7
8
 
8
- const execAsync = promisify(exec);
9
+ const execFileAsync = promisify(execFile);
9
10
 
10
11
  export class NpmAuditScanner implements SecurityScanner {
11
12
  public name = 'npm-audit';
12
13
  public version = 'unknown';
13
14
 
15
+ public capabilities: ScannerCapability = {
16
+ category: 'dependencies',
17
+ detectApplicability: (repoPath: string) => {
18
+ const safePath = path.resolve(repoPath);
19
+ return fs.existsSync(path.join(safePath, 'package.json'));
20
+ }
21
+ };
22
+
14
23
  async scan(input: ScanInput): Promise<ScannerResult> {
15
24
  const startTime = new Date();
16
25
  let rawOutput = '';
17
26
 
27
+ const safePath = path.resolve(input.repositoryPath);
28
+ const hasPackageJson = fs.existsSync(path.join(safePath, 'package.json'));
29
+
30
+ if (!hasPackageJson) {
31
+ const endTime = new Date();
32
+ return {
33
+ scanner: this.name,
34
+ success: true,
35
+ state: ScannerState.SKIPPED,
36
+ reason: 'Skipped: No package.json detected in repository',
37
+ findings: [],
38
+ rawOutput: 'No package.json found',
39
+ startTime,
40
+ endTime,
41
+ durationMs: endTime.getTime() - startTime.getTime()
42
+ };
43
+ }
44
+
18
45
  try {
19
- const safePath = path.resolve(input.repositoryPath);
20
-
21
- // npm audit --json outputs audit data. We run it in the repository path.
22
- // Note: this assumes package.json exists. If it doesn't, npm audit will fail, which we can catch.
23
- const { stdout } = await execAsync(`npm audit --json --prefix "${safePath}"`, {
24
- timeout: 300000,
25
- maxBuffer: 1024 * 1024 * 50
46
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
47
+ const args = ['audit', '--json'];
48
+
49
+ const { stdout } = await execFileAsync(npmCmd, args, {
50
+ cwd: safePath,
51
+ timeout: 60000,
52
+ maxBuffer: 1024 * 1024 * 50,
53
+ shell: process.platform === 'win32'
26
54
  });
27
55
 
28
56
  rawOutput = stdout;
29
57
  const findings = parseNpmAuditOutput(input.scanId, rawOutput);
58
+ const endTime = new Date();
30
59
 
31
60
  return {
32
61
  scanner: this.name,
33
62
  success: true,
63
+ state: ScannerState.SUCCESS,
34
64
  findings,
35
65
  rawOutput,
36
66
  startTime,
37
- endTime: new Date()
67
+ endTime,
68
+ durationMs: endTime.getTime() - startTime.getTime()
38
69
  };
39
70
  } catch (error: any) {
40
- // npm audit returns exit code > 0 if vulnerabilities are found
71
+ const endTime = new Date();
72
+ const durationMs = endTime.getTime() - startTime.getTime();
73
+
74
+ if (error.code === 'ENOENT') {
75
+ return {
76
+ scanner: this.name,
77
+ success: false,
78
+ state: ScannerState.NOT_INSTALLED,
79
+ reason: 'npm executable was not found on PATH',
80
+ findings: [],
81
+ error: error.message,
82
+ startTime,
83
+ endTime,
84
+ durationMs
85
+ };
86
+ }
87
+
88
+ if (error.code === 'ETIMEDOUT') {
89
+ return {
90
+ scanner: this.name,
91
+ success: false,
92
+ state: ScannerState.TIMEOUT,
93
+ reason: 'npm-audit execution timed out',
94
+ findings: [],
95
+ error: error.message,
96
+ startTime,
97
+ endTime,
98
+ durationMs
99
+ };
100
+ }
101
+
102
+ // npm audit exits > 0 if vulnerabilities are found
41
103
  if (error.stdout && error.stdout.includes('"auditReportVersion":')) {
42
104
  try {
43
105
  rawOutput = error.stdout;
@@ -45,12 +107,14 @@ export class NpmAuditScanner implements SecurityScanner {
45
107
  return {
46
108
  scanner: this.name,
47
109
  success: true,
110
+ state: ScannerState.SUCCESS,
48
111
  findings,
49
112
  rawOutput,
50
113
  startTime,
51
- endTime: new Date()
114
+ endTime,
115
+ durationMs
52
116
  };
53
- } catch (parseError) {
117
+ } catch {
54
118
  // ignore parsing error
55
119
  }
56
120
  }
@@ -58,11 +122,13 @@ export class NpmAuditScanner implements SecurityScanner {
58
122
  return {
59
123
  scanner: this.name,
60
124
  success: false,
125
+ state: ScannerState.FAILED,
61
126
  findings: [],
62
127
  error: error.message || 'npm audit execution failed',
63
128
  rawOutput: error.stdout || '',
64
129
  startTime,
65
- endTime: new Date()
130
+ endTime,
131
+ durationMs
66
132
  };
67
133
  }
68
134
  }