node-protect 1.0.0 → 1.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/dist/cli.js CHANGED
@@ -9,11 +9,9 @@ const chalk_1 = __importDefault(require("chalk"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const index_1 = require("./index");
11
11
  const program = new commander_1.Command();
12
+ program.name('node-protect').description('CLI to check for project security risks (OWASP Top 10)').version('1.0.0');
12
13
  program
13
- .name('node-protect')
14
- .description('CLI to check for project security risks (OWASP Top 10)')
15
- .version('1.0.0');
16
- program.command('scan')
14
+ .command('scan')
17
15
  .argument('[path]', 'Path to project to scan', '.')
18
16
  .option('-t, --type <type>', 'Type of scan: full, secrets, dependencies, code', 'full')
19
17
  .action(async (projectPath, options) => {
@@ -25,8 +23,7 @@ program.command('scan')
25
23
  // CLI handles its own printing/exit logic, so we disable internal logging
26
24
  const results = await (0, index_1.protect)(resolvedPath, { types, log: false });
27
25
  // Use the shared printReport function
28
- const { printReport } = require('./index');
29
- printReport(results);
26
+ (0, index_1.printReport)(results);
30
27
  if (results.length > 0) {
31
28
  console.log(chalk_1.default.yellow('\n⚠️ Security issues found. Please review the report above.'));
32
29
  // process.exit(1); // User requested warning only mode
package/dist/config.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadConfig = loadConfig;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const path_1 = __importDefault(require("path"));
9
+ async function loadConfig(projectPath) {
10
+ const configPath = path_1.default.join(projectPath, '.protectrc');
11
+ try {
12
+ const content = await promises_1.default.readFile(configPath, 'utf-8');
13
+ return JSON.parse(content);
14
+ }
15
+ catch (error) {
16
+ // Return empty config if file doesn't exist or is invalid
17
+ return {};
18
+ }
19
+ }
package/dist/index.js CHANGED
@@ -12,24 +12,26 @@ const codeScanner_1 = require("./scanners/codeScanner");
12
12
  exports.scanners = {
13
13
  DependencyAuditor: dependencyAuditor_1.DependencyAuditor,
14
14
  SecretScanner: secretScanner_1.SecretScanner,
15
- CodeScanner: codeScanner_1.CodeScanner
15
+ CodeScanner: codeScanner_1.CodeScanner,
16
16
  };
17
+ const config_1 = require("./config");
17
18
  async function protect(projectPath = process.cwd(), options = {}) {
18
19
  const { log = true, types = ['full'] } = options;
19
20
  try {
21
+ const config = await (0, config_1.loadConfig)(projectPath);
20
22
  const results = [];
21
23
  const runAll = types.includes('full');
22
24
  if (runAll || types.includes('dependencies')) {
23
25
  const auditor = new dependencyAuditor_1.DependencyAuditor();
24
- results.push(...await auditor.scan(projectPath));
26
+ results.push(...(await auditor.scan(projectPath)));
25
27
  }
26
28
  if (runAll || types.includes('secrets')) {
27
- const secretScanner = new secretScanner_1.SecretScanner();
28
- results.push(...await secretScanner.scan(projectPath));
29
+ const secretScanner = new secretScanner_1.SecretScanner(config);
30
+ results.push(...(await secretScanner.scan(projectPath)));
29
31
  }
30
32
  if (runAll || types.includes('code')) {
31
- const codeScanner = new codeScanner_1.CodeScanner();
32
- results.push(...await codeScanner.scan(projectPath));
33
+ const codeScanner = new codeScanner_1.CodeScanner(config);
34
+ results.push(...(await codeScanner.scan(projectPath)));
33
35
  }
34
36
  if (log) {
35
37
  printReport(results);
@@ -43,7 +45,7 @@ async function protect(projectPath = process.cwd(), options = {}) {
43
45
  if (log) {
44
46
  console.error(chalk_1.default.red('Security scan failed:'), error);
45
47
  }
46
- // If logging is off, we rethrow so consumer can handle it.
48
+ // If logging is off, we rethrow so consumer can handle it.
47
49
  // If logging is on, we suppress it to allow app flow to continue (as per request "not call then and catche")
48
50
  if (!log)
49
51
  throw error;
package/dist/rules.js ADDED
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SECRET_RULES = exports.CODE_RULES = void 0;
4
+ exports.CODE_RULES = [
5
+ // A01:2021-Broken Access Control
6
+ {
7
+ name: 'Permissive CORS',
8
+ regex: /Access-Control-Allow-Origin\s*:\s*\*/i,
9
+ category: 'A01:2021-Broken Access Control',
10
+ severity: 'HIGH',
11
+ remediation: 'Restrict CORS origin to specific domains.',
12
+ },
13
+ {
14
+ name: 'Hardcoded Role Check',
15
+ regex: /if\s*\(\s*user\.role\s*===\s*['"]admin['"]\s*\)/,
16
+ category: 'A01:2021-Broken Access Control',
17
+ severity: 'MEDIUM',
18
+ remediation: 'Use a centralized permission system (RBAC/ABAC).',
19
+ },
20
+ // A02:2021-Cryptographic Failures
21
+ {
22
+ name: 'Weak Hash (MD5)',
23
+ regex: /createHash\(['"]md5['"]\)/,
24
+ category: 'A02:2021-Cryptographic Failures',
25
+ severity: 'MEDIUM',
26
+ remediation: 'Use SHA-256 or stronger.',
27
+ },
28
+ {
29
+ name: 'Weak Hash (SHA1)',
30
+ regex: /createHash\(['"]sha1['"]\)/,
31
+ category: 'A02:2021-Cryptographic Failures',
32
+ severity: 'MEDIUM',
33
+ remediation: 'Use SHA-256 or stronger.',
34
+ },
35
+ {
36
+ name: 'Hardcoded IV',
37
+ regex: /createDecipheriv\([^,]+,\s*[^,]+,\s*['"]\w+['"]\)/,
38
+ category: 'A02:2021-Cryptographic Failures',
39
+ severity: 'HIGH',
40
+ remediation: 'Use a random IV.',
41
+ },
42
+ // A03:2021-Injection
43
+ {
44
+ name: 'Eval Usage',
45
+ regex: /eval\s*\(/,
46
+ category: 'A03:2021-Injection',
47
+ severity: 'HIGH',
48
+ remediation: 'Avoid using eval().',
49
+ },
50
+ {
51
+ name: 'InnerHTML Usage',
52
+ regex: /\.innerHTML\s*=/,
53
+ category: 'A03:2021-Injection',
54
+ severity: 'MEDIUM',
55
+ remediation: 'Use textContent or a sanitizer library.',
56
+ },
57
+ {
58
+ name: 'Unsafe SQL Interpolation',
59
+ regex: /query\s*\(\s*['"]select.*?\$\{/i,
60
+ category: 'A03:2021-Injection',
61
+ severity: 'HIGH',
62
+ remediation: 'Use parameterized queries.',
63
+ },
64
+ // A04:2021-Insecure Design
65
+ {
66
+ name: 'X-Powered-By Header',
67
+ regex: /res\.setHeader\(['"]X-Powered-By['"]/,
68
+ category: 'A04:2021-Insecure Design',
69
+ severity: 'LOW',
70
+ remediation: 'Disable X-Powered-By header to avoid leaking stack details.',
71
+ },
72
+ {
73
+ name: 'Disable X-Powered-By (Missing)',
74
+ regex: /app\.disable\(['"]x-powered-by['"]\)/,
75
+ category: 'A04:2021-Insecure Design',
76
+ severity: 'INFO',
77
+ remediation: 'Ensure you disable x-powered-by in Express.',
78
+ },
79
+ // A05:2021-Security Misconfiguration
80
+ {
81
+ name: 'Debug Mode Enabled',
82
+ regex: /DEBUG\s*=\s*true/i,
83
+ category: 'A05:2021-Security Misconfiguration',
84
+ severity: 'MEDIUM',
85
+ remediation: 'Ensure debug mode is disabled in production.',
86
+ },
87
+ {
88
+ name: 'Hardcoded Port 80',
89
+ regex: /\.listen\(\s*80\s*\)/,
90
+ category: 'A05:2021-Security Misconfiguration',
91
+ severity: 'LOW',
92
+ remediation: 'Use environment variables for ports and avoid privileged ports.',
93
+ },
94
+ // A08:2021-Software and Data Integrity Failures
95
+ {
96
+ name: 'Missing SRI',
97
+ regex: /<script\s+src=['"]https?:\/\/[^'"]+['"](?!.*integrity)/,
98
+ category: 'A08:2021-Software and Data Integrity Failures',
99
+ severity: 'MEDIUM',
100
+ remediation: 'Use Subresource Integrity (SRI) for external scripts.',
101
+ },
102
+ // A09:2021-Security Logging and Monitoring Failures
103
+ {
104
+ name: 'Console Log Usage',
105
+ regex: /console\.log\s*\(/,
106
+ category: 'A09:2021-Security Logging and Monitoring Failures',
107
+ severity: 'LOW',
108
+ remediation: 'Use a structured logger (like winston/pino) to ensure logs are centralized.',
109
+ },
110
+ {
111
+ name: 'Empty Catch Block',
112
+ regex: /catch\s*\(\s*\w+\s*\)\s*\{\s*\}/,
113
+ category: 'A09:2021-Security Logging and Monitoring Failures',
114
+ severity: 'MEDIUM',
115
+ remediation: 'Log all errors.',
116
+ },
117
+ // A10:2021-Server-Side Request Forgery (SSRF)
118
+ {
119
+ name: 'Unsafe Fetch with Request Data',
120
+ regex: /fetch\s*\(\s*req\.(query|body|params)/,
121
+ category: 'A10:2021-SSRF',
122
+ severity: 'HIGH',
123
+ remediation: 'Validate user input before using it in fetch/axios URLs.',
124
+ },
125
+ {
126
+ name: 'Unsafe Axios with Request Data',
127
+ regex: /axios\.(get|post|put)\s*\(\s*req\.(query|body|params)/,
128
+ category: 'A10:2021-SSRF',
129
+ severity: 'HIGH',
130
+ remediation: 'Validate user input before using it in fetch/axios URLs.',
131
+ },
132
+ ];
133
+ exports.SECRET_RULES = [
134
+ {
135
+ name: 'AWS Access Key',
136
+ regex: /AKIA[0-9A-Z]{16}/,
137
+ category: 'A07:2021-Identification and Authentication Failures',
138
+ severity: 'HIGH',
139
+ remediation: 'Store secrets in environment variables or a secure vault. Do not commit them to repo.',
140
+ },
141
+ {
142
+ name: 'Private Key',
143
+ regex: /-----BEGIN PRIVATE KEY-----/,
144
+ category: 'A07:2021-Identification and Authentication Failures',
145
+ severity: 'CRITICAL',
146
+ remediation: 'Store secrets in environment variables or a secure vault. Do not commit them to repo.',
147
+ },
148
+ {
149
+ name: 'Generic API Key',
150
+ regex: /api_key\s*[:=]\s*['"][a-zA-Z0-9_-]{20,}['"]/,
151
+ category: 'A07:2021-Identification and Authentication Failures',
152
+ severity: 'HIGH',
153
+ remediation: 'Store secrets in environment variables or a secure vault. Do not commit them to repo.',
154
+ },
155
+ {
156
+ name: 'Generic Password',
157
+ regex: /password\s*[:=]\s*['"][a-zA-Z0-9_\-!@#$%^&*]{6,}['"]/,
158
+ category: 'A07:2021-Identification and Authentication Failures',
159
+ severity: 'MEDIUM',
160
+ remediation: 'Store secrets in environment variables or a secure vault. Do not commit them to repo.',
161
+ },
162
+ ];
@@ -7,41 +7,22 @@ exports.CodeScanner = void 0;
7
7
  const promises_1 = __importDefault(require("fs/promises"));
8
8
  const glob_1 = require("glob");
9
9
  const path_1 = __importDefault(require("path"));
10
+ const rules_1 = require("../rules");
10
11
  class CodeScanner {
11
- patterns = [
12
- // A01:2021-Broken Access Control
13
- { name: 'Permissive CORS', regex: /Access-Control-Allow-Origin\s*:\s*\*/i, category: 'A01:2021-Broken Access Control', severity: 'HIGH', remediation: 'Restrict CORS origin to specific domains.' },
14
- { name: 'Hardcoded Role Check', regex: /if\s*\(\s*user\.role\s*===\s*['"]admin['"]\s*\)/, category: 'A01:2021-Broken Access Control', severity: 'MEDIUM', remediation: 'Use a centralized permission system (RBAC/ABAC).' },
15
- // A02:2021-Cryptographic Failures
16
- { name: 'Weak Hash (MD5)', regex: /createHash\(['"]md5['"]\)/, category: 'A02:2021-Cryptographic Failures', severity: 'MEDIUM', remediation: 'Use SHA-256 or stronger.' },
17
- { name: 'Weak Hash (SHA1)', regex: /createHash\(['"]sha1['"]\)/, category: 'A02:2021-Cryptographic Failures', severity: 'MEDIUM', remediation: 'Use SHA-256 or stronger.' },
18
- { name: 'Hardcoded IV', regex: /createDecipheriv\([^,]+,\s*[^,]+,\s*['"]\w+['"]\)/, category: 'A02:2021-Cryptographic Failures', severity: 'HIGH', remediation: 'Use a random IV.' },
19
- // A03:2021-Injection
20
- { name: 'Eval Usage', regex: /eval\s*\(/, category: 'A03:2021-Injection', severity: 'HIGH', remediation: 'Avoid using eval().' },
21
- { name: 'InnerHTML Usage', regex: /\.innerHTML\s*=/, category: 'A03:2021-Injection', severity: 'MEDIUM', remediation: 'Use textContent or a sanitizer library.' },
22
- { name: 'Unsafe SQL Interpolation', regex: /query\s*\(\s*['"]select.*?\$\{/i, category: 'A03:2021-Injection', severity: 'HIGH', remediation: 'Use parameterized queries.' },
23
- // A04:2021-Insecure Design
24
- { name: 'X-Powered-By Header', regex: /res\.setHeader\(['"]X-Powered-By['"]/, category: 'A04:2021-Insecure Design', severity: 'LOW', remediation: 'Disable X-Powered-By header to avoid leaking stack details.' },
25
- { name: 'Disable X-Powered-By (Missing)', regex: /app\.disable\(['"]x-powered-by['"]\)/, category: 'A04:2021-Insecure Design', severity: 'INFO', remediation: 'Ensure you disable x-powered-by in Express.' },
26
- // A05:2021-Security Misconfiguration
27
- { name: 'Debug Mode Enabled', regex: /DEBUG\s*=\s*true/i, category: 'A05:2021-Security Misconfiguration', severity: 'MEDIUM', remediation: 'Ensure debug mode is disabled in production.' },
28
- { name: 'Hardcoded Port 80', regex: /\.listen\(\s*80\s*\)/, category: 'A05:2021-Security Misconfiguration', severity: 'LOW', remediation: 'Use environment variables for ports and avoid privileged ports.' },
29
- // A08:2021-Software and Data Integrity Failures
30
- // This is hard to regex in code, usually checks for lockfiles usage or SRI in HTML
31
- { name: 'Missing SRI', regex: /<script\s+src=['"]https?:\/\/[^'"]+['"](?!.*integrity)/, category: 'A08:2021-Software and Data Integrity Failures', severity: 'MEDIUM', remediation: 'Use Subresource Integrity (SRI) for external scripts.' },
32
- // A09:2021-Security Logging and Monitoring Failures
33
- { name: 'Console Log Usage', regex: /console\.log\s*\(/, category: 'A09:2021-Security Logging and Monitoring Failures', severity: 'LOW', remediation: 'Use a structured logger (like winston/pino) to ensure logs are centralized.' },
34
- { name: 'Empty Catch Block', regex: /catch\s*\(\s*\w+\s*\)\s*\{\s*\}/, category: 'A09:2021-Security Logging and Monitoring Failures', severity: 'MEDIUM', remediation: 'Log all errors.' },
35
- // A10:2021-Server-Side Request Forgery (SSRF)
36
- { name: 'Unsafe Fetch with Request Data', regex: /fetch\s*\(\s*req\.(query|body|params)/, category: 'A10:2021-SSRF', severity: 'HIGH', remediation: 'Validate user input before using it in fetch/axios URLs.' },
37
- { name: 'Unsafe Axios with Request Data', regex: /axios\.(get|post|put)\s*\(\s*req\.(query|body|params)/, category: 'A10:2021-SSRF', severity: 'HIGH', remediation: 'Validate user input before using it in fetch/axios URLs.' },
38
- ];
12
+ config;
13
+ constructor(config) {
14
+ this.config = config;
15
+ }
39
16
  async scan(projectPath) {
40
17
  const results = [];
18
+ const ignorePatterns = ['node_modules/**', 'dist/**', '.git/**', '**/*.test.ts', '**/*.spec.ts'];
19
+ if (this.config?.ignore) {
20
+ ignorePatterns.push(...this.config.ignore);
21
+ }
41
22
  const files = await (0, glob_1.glob)('**/*.{ts,js}', {
42
23
  cwd: projectPath,
43
- ignore: ['node_modules/**', 'dist/**', '.git/**', '**/*.test.ts', '**/*.spec.ts'],
44
- nodir: true
24
+ ignore: ignorePatterns,
25
+ nodir: true,
45
26
  });
46
27
  for (const file of files) {
47
28
  const fullPath = path_1.default.join(projectPath, file);
@@ -50,22 +31,22 @@ class CodeScanner {
50
31
  const lines = content.split('\n');
51
32
  for (let i = 0; i < lines.length; i++) {
52
33
  const line = lines[i];
53
- for (const pattern of this.patterns) {
54
- if (pattern.regex.test(line)) {
34
+ for (const rule of rules_1.CODE_RULES) {
35
+ if (rule.regex.test(line)) {
55
36
  results.push({
56
- category: pattern.category,
57
- severity: pattern.severity,
58
- description: `Potential Security Issue: ${pattern.name}`,
37
+ category: rule.category,
38
+ severity: rule.severity,
39
+ description: `Potential Security Issue: ${rule.name}`,
59
40
  file: file,
60
41
  line: i + 1,
61
42
  snippet: line.trim(),
62
- remediation: pattern.remediation
43
+ remediation: rule.remediation || '',
63
44
  });
64
45
  }
65
46
  }
66
47
  }
67
48
  }
68
- catch (err) {
49
+ catch (_err) {
69
50
  // Ignore read errors
70
51
  }
71
52
  }
@@ -6,19 +6,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.DependencyAuditor = void 0;
7
7
  const child_process_1 = require("child_process");
8
8
  const util_1 = __importDefault(require("util"));
9
+ const promises_1 = __importDefault(require("fs/promises"));
10
+ const path_1 = __importDefault(require("path"));
9
11
  const execPromise = util_1.default.promisify(child_process_1.exec);
10
12
  class DependencyAuditor {
11
13
  async scan(projectPath) {
14
+ let command = 'npm audit --json';
12
15
  try {
13
- // npm audit usually returns non-zero exit code if vulnerabilities are found
14
- // so we catch the error to process the output
15
- await execPromise('npm audit --json', { cwd: projectPath });
16
- return []; // No vulnerabilities found
16
+ const hasPnpmLock = await this.fileExists(projectPath, 'pnpm-lock.yaml');
17
+ const hasPackageLock = await this.fileExists(projectPath, 'package-lock.json');
18
+ if (hasPnpmLock && !hasPackageLock) {
19
+ command = 'pnpm audit --json';
20
+ }
21
+ await execPromise(command, { cwd: projectPath });
22
+ return [];
17
23
  }
18
24
  catch (error) {
19
- // If it's a real error (not just vulnerabilities found), rethrow
20
25
  if (!error.stdout) {
21
- console.error("Error running npm audit:", error);
26
+ // If checking lockfiles failed, default to npm and swallow errors if it fails early
27
+ // console.error(`Error running ${command}:`, error);
22
28
  return [];
23
29
  }
24
30
  try {
@@ -26,11 +32,20 @@ class DependencyAuditor {
26
32
  return this.parseAuditReport(auditReport);
27
33
  }
28
34
  catch (parseError) {
29
- console.error("Failed to parse npm audit output", parseError);
35
+ // console.error(`Failed to parse ${command} output`, parseError);
30
36
  return [];
31
37
  }
32
38
  }
33
39
  }
40
+ async fileExists(dir, file) {
41
+ try {
42
+ await promises_1.default.access(path_1.default.join(dir, file));
43
+ return true;
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ }
34
49
  parseAuditReport(report) {
35
50
  const results = [];
36
51
  // Check for errors in report (npm audit sometimes returns error structure)
@@ -42,11 +57,11 @@ class DependencyAuditor {
42
57
  const vulnerability = detail;
43
58
  if (vulnerability.severity) {
44
59
  results.push({
45
- category: "A06:2021-Vulnerable and Outdated Components",
60
+ category: 'A06:2021-Vulnerable and Outdated Components',
46
61
  severity: vulnerability.severity.toUpperCase(),
47
62
  description: `Package '${name}' has a ${vulnerability.severity} vulnerability.`,
48
63
  file: 'package.json',
49
- remediation: vulnerability.fixAvailable ? "Run 'npm audit fix'" : "Update dependency manually"
64
+ remediation: vulnerability.fixAvailable ? "Run 'npm audit fix'" : 'Update dependency manually',
50
65
  });
51
66
  }
52
67
  }
@@ -7,19 +7,22 @@ exports.SecretScanner = void 0;
7
7
  const promises_1 = __importDefault(require("fs/promises"));
8
8
  const glob_1 = require("glob");
9
9
  const path_1 = __importDefault(require("path"));
10
+ const rules_1 = require("../rules");
10
11
  class SecretScanner {
11
- patterns = [
12
- { name: 'AWS Access Key', regex: /AKIA[0-9A-Z]{16}/, severity: 'HIGH' },
13
- { name: 'Private Key', regex: /-----BEGIN PRIVATE KEY-----/, severity: 'CRITICAL' },
14
- { name: 'Generic API Key', regex: /api_key\s*[:=]\s*['"][a-zA-Z0-9_\-]{20,}['"]/, severity: 'HIGH' },
15
- { name: 'Generic Password', regex: /password\s*[:=]\s*['"][a-zA-Z0-9_\-!@#$%^&*]{6,}['"]/, severity: 'MEDIUM' },
16
- ];
12
+ config;
13
+ constructor(config) {
14
+ this.config = config;
15
+ }
17
16
  async scan(projectPath) {
18
17
  const results = [];
18
+ const ignorePatterns = ['node_modules/**', 'dist/**', '.git/**'];
19
+ if (this.config?.ignore) {
20
+ ignorePatterns.push(...this.config.ignore);
21
+ }
19
22
  const files = await (0, glob_1.glob)('**/*.{ts,js,json,env,txt,yml,yaml}', {
20
23
  cwd: projectPath,
21
- ignore: ['node_modules/**', 'dist/**', '.git/**'],
22
- nodir: true
24
+ ignore: ignorePatterns,
25
+ nodir: true,
23
26
  });
24
27
  for (const file of files) {
25
28
  const fullPath = path_1.default.join(projectPath, file);
@@ -28,22 +31,22 @@ class SecretScanner {
28
31
  const lines = content.split('\n');
29
32
  for (let i = 0; i < lines.length; i++) {
30
33
  const line = lines[i];
31
- for (const pattern of this.patterns) {
32
- if (pattern.regex.test(line)) {
34
+ for (const rule of rules_1.SECRET_RULES) {
35
+ if (rule.regex.test(line)) {
33
36
  results.push({
34
- category: "A07:2021-Identification and Authentication Failures",
35
- severity: pattern.severity,
36
- description: `Potential ${pattern.name} found`,
37
+ category: rule.category,
38
+ severity: rule.severity,
39
+ description: `Potential ${rule.name} found`,
37
40
  file: file,
38
41
  line: i + 1,
39
42
  snippet: line.trim().substring(0, 100), // Truncate lengthy lines
40
- remediation: "Store secrets in environment variables or a secure vault. Do not commit them to repo."
43
+ remediation: rule.remediation || '',
41
44
  });
42
45
  }
43
46
  }
44
47
  }
45
48
  }
46
- catch (err) {
49
+ catch (_err) {
47
50
  // Ignore read errors
48
51
  }
49
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-protect",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Security scanner for Node.js projects checking for OWASP Top 10 risks",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,7 +13,9 @@
13
13
  "scripts": {
14
14
  "build": "tsc",
15
15
  "prepublishOnly": "npm run build",
16
- "test": "jest"
16
+ "test": "jest",
17
+ "lint": "eslint 'src/**/*.ts' 'tests/**/*.ts'",
18
+ "format": "prettier --write 'src/**/*.ts' 'tests/**/*.ts'"
17
19
  },
18
20
  "keywords": [
19
21
  "security",
@@ -30,11 +32,19 @@
30
32
  "glob": "^13.0.0"
31
33
  },
32
34
  "devDependencies": {
35
+ "@eslint/js": "^9.39.2",
33
36
  "@types/jest": "^30.0.0",
34
37
  "@types/node": "^25.0.10",
38
+ "@typescript-eslint/eslint-plugin": "^8.54.0",
39
+ "@typescript-eslint/parser": "^8.54.0",
40
+ "eslint": "^9.39.2",
41
+ "eslint-config-prettier": "^10.1.8",
42
+ "eslint-plugin-prettier": "^5.5.5",
35
43
  "jest": "^30.2.0",
36
- "listr2": "^10.1.0",
44
+ "prettier": "^3.8.1",
45
+ "ts-jest": "^29.4.6",
37
46
  "ts-node": "^10.9.2",
38
- "typescript": "^5.9.3"
47
+ "typescript": "^5.9.3",
48
+ "typescript-eslint": "^8.54.0"
39
49
  }
40
- }
50
+ }