toolip 1.0.5 → 1.0.7
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/src/config/version.d.ts +1 -1
- package/dist/src/config/version.js +23 -1
- package/dist/src/config/version.js.map +1 -1
- package/dist/src/core/security-doctor.js +67 -29
- package/dist/src/core/security-doctor.js.map +1 -1
- package/dist/src/core/security-patterns.js +33 -24
- package/dist/src/core/security-patterns.js.map +1 -1
- package/package.json +9 -6
|
@@ -1,4 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
function resolvePackageVersion() {
|
|
5
|
+
let directory = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const root = path.parse(directory).root;
|
|
7
|
+
while (directory !== root) {
|
|
8
|
+
const manifestPath = path.join(directory, 'package.json');
|
|
9
|
+
try {
|
|
10
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
11
|
+
if (manifest.name === 'toolip' &&
|
|
12
|
+
typeof manifest.version === 'string') {
|
|
13
|
+
return manifest.version;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// Continue searching parent directories.
|
|
18
|
+
}
|
|
19
|
+
directory = path.dirname(directory);
|
|
20
|
+
}
|
|
21
|
+
throw new Error('Unable to resolve Toolip version from package.json.');
|
|
22
|
+
}
|
|
23
|
+
export const TOOLIP_VERSION = resolvePackageVersion();
|
|
2
24
|
export const TOOLIP_AUTHOR = {
|
|
3
25
|
name: 'Ashibuogwu Williams',
|
|
4
26
|
handle: 'wbizmo',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/config/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/config/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAOzC,SAAS,qBAAqB;IAC5B,IAAI,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;IAExC,OAAO,SAAS,KAAK,IAAI,EAAE,CAAC;QAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAE1D,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CACzB,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAChB,CAAC;YAErB,IACE,QAAQ,CAAC,IAAI,KAAK,QAAQ;gBAC1B,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,EACpC,CAAC;gBACD,OAAO,QAAQ,CAAC,OAAO,CAAC;YAC1B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,yCAAyC;QAC3C,CAAC;QAED,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,IAAI,KAAK,CACb,qDAAqD,CACtD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,EAAE,CAAC;AAEtD,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,qBAAqB;IAC3B,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,2BAA2B;CACpC,CAAC"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { createScannerContext } from './scanner-context.js';
|
|
3
3
|
import { configSecurityPatterns, dangerousCodePatterns, secretPatterns, securityHeaderNames } from './security-patterns.js';
|
|
4
|
-
const
|
|
4
|
+
const secretScanExtensions = new Set([
|
|
5
5
|
'js',
|
|
6
6
|
'jsx',
|
|
7
7
|
'ts',
|
|
8
8
|
'tsx',
|
|
9
|
+
'mjs',
|
|
10
|
+
'cjs',
|
|
9
11
|
'json',
|
|
10
12
|
'yml',
|
|
11
13
|
'yaml',
|
|
@@ -14,12 +16,21 @@ const scanExtensions = new Set([
|
|
|
14
16
|
'pem',
|
|
15
17
|
'key'
|
|
16
18
|
]);
|
|
19
|
+
const codeExtensions = new Set([
|
|
20
|
+
'js',
|
|
21
|
+
'jsx',
|
|
22
|
+
'ts',
|
|
23
|
+
'tsx',
|
|
24
|
+
'mjs',
|
|
25
|
+
'cjs'
|
|
26
|
+
]);
|
|
17
27
|
export async function runSecurityDoctor(root) {
|
|
18
28
|
const context = await createScannerContext(root);
|
|
19
29
|
const findings = [];
|
|
20
30
|
for (const file of context.files) {
|
|
21
|
-
if (!
|
|
31
|
+
if (!shouldScanSecrets(file.relativePath, file.extension)) {
|
|
22
32
|
continue;
|
|
33
|
+
}
|
|
23
34
|
let content = '';
|
|
24
35
|
try {
|
|
25
36
|
content = await readFile(file.absolutePath, 'utf8');
|
|
@@ -28,8 +39,10 @@ export async function runSecurityDoctor(root) {
|
|
|
28
39
|
continue;
|
|
29
40
|
}
|
|
30
41
|
findings.push(...scanContent(file.relativePath, content, secretPatterns));
|
|
31
|
-
|
|
32
|
-
|
|
42
|
+
if (codeExtensions.has(file.extension)) {
|
|
43
|
+
findings.push(...scanContent(file.relativePath, content, dangerousCodePatterns));
|
|
44
|
+
findings.push(...scanContent(file.relativePath, content, configSecurityPatterns));
|
|
45
|
+
}
|
|
33
46
|
}
|
|
34
47
|
findings.push(...detectMissingSecurityHeaders(context.files.map((file) => file.relativePath)));
|
|
35
48
|
return {
|
|
@@ -43,7 +56,7 @@ export async function runSecurityDoctor(root) {
|
|
|
43
56
|
}
|
|
44
57
|
};
|
|
45
58
|
}
|
|
46
|
-
function
|
|
59
|
+
function shouldScanSecrets(relativePath, extension) {
|
|
47
60
|
if (relativePath.endsWith('.d.ts'))
|
|
48
61
|
return false;
|
|
49
62
|
if (relativePath.endsWith('.map'))
|
|
@@ -54,53 +67,78 @@ function shouldScan(relativePath, extension) {
|
|
|
54
67
|
return true;
|
|
55
68
|
if (relativePath.includes('.env.'))
|
|
56
69
|
return true;
|
|
57
|
-
|
|
58
|
-
return true;
|
|
59
|
-
return false;
|
|
70
|
+
return secretScanExtensions.has(extension);
|
|
60
71
|
}
|
|
61
72
|
function scanContent(relativePath, content, patterns) {
|
|
62
73
|
const findings = [];
|
|
63
74
|
for (const pattern of patterns) {
|
|
64
75
|
pattern.regex.lastIndex = 0;
|
|
65
|
-
const
|
|
66
|
-
|
|
76
|
+
const match = pattern.regex.exec(content);
|
|
77
|
+
pattern.regex.lastIndex = 0;
|
|
78
|
+
if (!match) {
|
|
67
79
|
continue;
|
|
80
|
+
}
|
|
68
81
|
findings.push({
|
|
69
|
-
id: `${pattern.id}-${relativePath
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
id: `${pattern.id}-${relativePath
|
|
83
|
+
.toUpperCase()
|
|
84
|
+
.replaceAll(/[^A-Z0-9]/g, '-')}`,
|
|
85
|
+
title: formatTitle(pattern, relativePath),
|
|
86
|
+
severity: resolveSeverity(pattern, relativePath),
|
|
72
87
|
category: pattern.category,
|
|
73
|
-
message: pattern
|
|
88
|
+
message: formatMessage(pattern, relativePath),
|
|
74
89
|
recommendation: pattern.recommendation,
|
|
75
90
|
file: relativePath,
|
|
76
|
-
evidence: redactEvidence(
|
|
91
|
+
evidence: redactEvidence(match[0])
|
|
77
92
|
});
|
|
78
93
|
}
|
|
79
94
|
return findings;
|
|
80
95
|
}
|
|
96
|
+
function isTestFile(relativePath) {
|
|
97
|
+
return (relativePath.startsWith('tests/') ||
|
|
98
|
+
relativePath.includes('/tests/') ||
|
|
99
|
+
relativePath.includes('/__tests__/') ||
|
|
100
|
+
/\.(test|spec)\.[cm]?[jt]sx?$/.test(relativePath));
|
|
101
|
+
}
|
|
102
|
+
function resolveSeverity(pattern, relativePath) {
|
|
103
|
+
if (pattern.category === 'secrets' && isTestFile(relativePath)) {
|
|
104
|
+
return 'low';
|
|
105
|
+
}
|
|
106
|
+
return pattern.severity;
|
|
107
|
+
}
|
|
108
|
+
function formatTitle(pattern, relativePath) {
|
|
109
|
+
if (pattern.category === 'secrets' && isTestFile(relativePath)) {
|
|
110
|
+
return `Potential test fixture: ${pattern.title}`;
|
|
111
|
+
}
|
|
112
|
+
return pattern.title;
|
|
113
|
+
}
|
|
114
|
+
function formatMessage(pattern, relativePath) {
|
|
115
|
+
if (pattern.category === 'secrets' && isTestFile(relativePath)) {
|
|
116
|
+
return `${pattern.message} This match is inside a test file, so Toolip reduced its severity. Confirm that it is synthetic fixture data.`;
|
|
117
|
+
}
|
|
118
|
+
return pattern.message;
|
|
119
|
+
}
|
|
81
120
|
function redactEvidence(value) {
|
|
82
|
-
if (value.length <= 16)
|
|
121
|
+
if (value.length <= 16) {
|
|
83
122
|
return value;
|
|
123
|
+
}
|
|
84
124
|
return `${value.slice(0, 8)}...[redacted]...${value.slice(-4)}`;
|
|
85
125
|
}
|
|
86
126
|
function detectMissingSecurityHeaders(relativePaths) {
|
|
87
127
|
const possibleServerFiles = relativePaths.filter((file) => !file.startsWith('dist/') &&
|
|
88
128
|
/server|app|main|index|middleware/i.test(file) &&
|
|
89
|
-
/\.(js|ts|jsx|tsx)$/.test(file));
|
|
129
|
+
/\.(js|ts|jsx|tsx|mjs|cjs)$/.test(file));
|
|
90
130
|
if (possibleServerFiles.length === 0) {
|
|
91
131
|
return [];
|
|
92
132
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
return findings;
|
|
133
|
+
return securityHeaderNames.map((header) => ({
|
|
134
|
+
id: `TOOLIP-HEADER-VERIFY-${header
|
|
135
|
+
.toUpperCase()
|
|
136
|
+
.replaceAll('-', '_')}`,
|
|
137
|
+
title: `Verify security header: ${header}`,
|
|
138
|
+
severity: 'info',
|
|
139
|
+
category: 'security-headers',
|
|
140
|
+
message: `Toolip found server-like files. Confirm that ${header} is configured in production responses.`,
|
|
141
|
+
recommendation: 'Use Helmet or equivalent framework middleware to set secure HTTP response headers.'
|
|
142
|
+
}));
|
|
105
143
|
}
|
|
106
144
|
//# sourceMappingURL=security-doctor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-doctor.js","sourceRoot":"","sources":["../../../src/core/security-doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,cAAc,EACd,mBAAmB,EAEpB,MAAM,wBAAwB,CAAC;AAahC,MAAM,
|
|
1
|
+
{"version":3,"file":"security-doctor.js","sourceRoot":"","sources":["../../../src/core/security-doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,8 +5,8 @@ export const secretPatterns = [
|
|
|
5
5
|
category: 'secrets',
|
|
6
6
|
severity: 'critical',
|
|
7
7
|
regex: /\bgh[pousr]_[A-Za-z0-9_]{20,}\b/g,
|
|
8
|
-
message: 'A GitHub token-like secret was found
|
|
9
|
-
recommendation: 'Revoke the token
|
|
8
|
+
message: 'A GitHub token-like secret was found.',
|
|
9
|
+
recommendation: 'Revoke the token, remove it from Git history, and store its replacement securely.'
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
id: 'TOOLIP-SECRET-AWS-ACCESS-KEY',
|
|
@@ -14,8 +14,8 @@ export const secretPatterns = [
|
|
|
14
14
|
category: 'secrets',
|
|
15
15
|
severity: 'critical',
|
|
16
16
|
regex: /\bAKIA[0-9A-Z]{16}\b/g,
|
|
17
|
-
message: 'An AWS access key-like value was found
|
|
18
|
-
recommendation: 'Rotate the
|
|
17
|
+
message: 'An AWS access key-like value was found.',
|
|
18
|
+
recommendation: 'Rotate the credential immediately and audit its usage.'
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
id: 'TOOLIP-SECRET-PRIVATE-KEY',
|
|
@@ -24,7 +24,7 @@ export const secretPatterns = [
|
|
|
24
24
|
severity: 'critical',
|
|
25
25
|
regex: /-----BEGIN (RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----/g,
|
|
26
26
|
message: 'Private key material was found.',
|
|
27
|
-
recommendation: 'Remove key
|
|
27
|
+
recommendation: 'Remove the key from the repository and rotate affected credentials.'
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
id: 'TOOLIP-SECRET-NPM-TOKEN',
|
|
@@ -32,8 +32,8 @@ export const secretPatterns = [
|
|
|
32
32
|
category: 'secrets',
|
|
33
33
|
severity: 'critical',
|
|
34
34
|
regex: /\bnpm_[A-Za-z0-9]{20,}\b/g,
|
|
35
|
-
message: 'An npm token-like value was
|
|
36
|
-
recommendation: 'Rotate the token and
|
|
35
|
+
message: 'An npm token-like value was found.',
|
|
36
|
+
recommendation: 'Rotate the token and store its replacement securely.'
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
id: 'TOOLIP-SECRET-HARDCODED-PASSWORD',
|
|
@@ -42,7 +42,7 @@ export const secretPatterns = [
|
|
|
42
42
|
severity: 'high',
|
|
43
43
|
regex: /\b(password|passwd|pwd)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
|
|
44
44
|
message: 'A hardcoded password-like assignment was found.',
|
|
45
|
-
recommendation: 'Move passwords into environment variables or
|
|
45
|
+
recommendation: 'Move passwords into environment variables or an encrypted secret manager.'
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
id: 'TOOLIP-SECRET-JWT-SECRET',
|
|
@@ -51,7 +51,16 @@ export const secretPatterns = [
|
|
|
51
51
|
severity: 'high',
|
|
52
52
|
regex: /\b(jwtSecret|JWT_SECRET|jwt_secret)\s*[:=]\s*['"][^'"]{8,}['"]/g,
|
|
53
53
|
message: 'A hardcoded JWT secret was found.',
|
|
54
|
-
recommendation: '
|
|
54
|
+
recommendation: 'Load a strong random secret from a secure runtime source.'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'TOOLIP-SECRET-GENERIC-API-KEY',
|
|
58
|
+
title: 'Generic API key detected',
|
|
59
|
+
category: 'secrets',
|
|
60
|
+
severity: 'medium',
|
|
61
|
+
regex: /\b(apiKey|API_KEY|api_key)\s*[:=]\s*['"][A-Za-z0-9_-]{16,}['"]/g,
|
|
62
|
+
message: 'A hardcoded API key-like value was found.',
|
|
63
|
+
recommendation: 'Remove API keys from source code and rotate exposed credentials.'
|
|
55
64
|
}
|
|
56
65
|
];
|
|
57
66
|
export const dangerousCodePatterns = [
|
|
@@ -61,8 +70,8 @@ export const dangerousCodePatterns = [
|
|
|
61
70
|
category: 'dangerous-code',
|
|
62
71
|
severity: 'high',
|
|
63
72
|
regex: /\beval\s*\(/g,
|
|
64
|
-
message: 'eval() can execute arbitrary code.',
|
|
65
|
-
recommendation: 'Replace eval() with
|
|
73
|
+
message: 'eval() can execute arbitrary code and introduce injection risk.',
|
|
74
|
+
recommendation: 'Replace eval() with explicit parsing or safe control flow.'
|
|
66
75
|
},
|
|
67
76
|
{
|
|
68
77
|
id: 'TOOLIP-DANGEROUS-NEW-FUNCTION',
|
|
@@ -70,26 +79,26 @@ export const dangerousCodePatterns = [
|
|
|
70
79
|
category: 'dangerous-code',
|
|
71
80
|
severity: 'high',
|
|
72
81
|
regex: /\bnew\s+Function\s*\(/g,
|
|
73
|
-
message: '
|
|
74
|
-
recommendation: 'Avoid
|
|
82
|
+
message: 'The Function constructor executes dynamic code.',
|
|
83
|
+
recommendation: 'Avoid runtime code generation and use explicit functions.'
|
|
75
84
|
},
|
|
76
85
|
{
|
|
77
86
|
id: 'TOOLIP-DANGEROUS-CHILD-PROCESS-EXEC',
|
|
78
87
|
title: 'Unsafe child_process exec usage',
|
|
79
88
|
category: 'dangerous-code',
|
|
80
89
|
severity: 'high',
|
|
81
|
-
regex:
|
|
82
|
-
message: '
|
|
83
|
-
recommendation: '
|
|
90
|
+
regex: /(?:\bchild_process\s*\.\s*exec|(?<![\w.])exec)\s*\(/g,
|
|
91
|
+
message: 'Shell execution may become unsafe when untrusted input reaches the command.',
|
|
92
|
+
recommendation: 'Prefer execFile() or spawn() with argument arrays and strict validation.'
|
|
84
93
|
},
|
|
85
94
|
{
|
|
86
95
|
id: 'TOOLIP-DANGEROUS-EXECSYNC',
|
|
87
96
|
title: 'Unsafe execSync usage',
|
|
88
97
|
category: 'dangerous-code',
|
|
89
98
|
severity: 'high',
|
|
90
|
-
regex:
|
|
91
|
-
message: '
|
|
92
|
-
recommendation: 'Avoid shell execution
|
|
99
|
+
regex: /(?:\bchild_process\s*\.\s*execSync|(?<![\w.])execSync)\s*\(/g,
|
|
100
|
+
message: 'Synchronous shell execution can introduce injection and blocking risks.',
|
|
101
|
+
recommendation: 'Avoid shell execution or use safer process APIs with validated arguments.'
|
|
93
102
|
}
|
|
94
103
|
];
|
|
95
104
|
export const configSecurityPatterns = [
|
|
@@ -100,7 +109,7 @@ export const configSecurityPatterns = [
|
|
|
100
109
|
severity: 'medium',
|
|
101
110
|
regex: /\borigin\s*:\s*['"]\*['"]/g,
|
|
102
111
|
message: 'CORS origin is configured as "*".',
|
|
103
|
-
recommendation: 'Restrict origins to trusted domains.'
|
|
112
|
+
recommendation: 'Restrict allowed origins to trusted domains.'
|
|
104
113
|
},
|
|
105
114
|
{
|
|
106
115
|
id: 'TOOLIP-CONFIG-WEAK-JWT-SECRET',
|
|
@@ -108,17 +117,17 @@ export const configSecurityPatterns = [
|
|
|
108
117
|
category: 'configuration',
|
|
109
118
|
severity: 'high',
|
|
110
119
|
regex: /\b(jwtSecret|JWT_SECRET|jwt_secret)\s*[:=]\s*['"](secret|changeme|password|123456|devsecret)['"]/gi,
|
|
111
|
-
message: 'A weak JWT secret
|
|
112
|
-
recommendation: 'Use a long, random secret.'
|
|
120
|
+
message: 'A weak JWT secret was detected.',
|
|
121
|
+
recommendation: 'Use a long, random, high-entropy secret.'
|
|
113
122
|
},
|
|
114
123
|
{
|
|
115
|
-
id: 'TOOLIP-CONFIG-LONG-
|
|
124
|
+
id: 'TOOLIP-CONFIG-LONG-JWT-EXPIRY',
|
|
116
125
|
title: 'Long-lived JWT expiry detected',
|
|
117
126
|
category: 'configuration',
|
|
118
127
|
severity: 'medium',
|
|
119
128
|
regex: /\b(expiresIn|JWT_EXPIRES_IN)\s*[:=]\s*['"](?:365d|999d|1000d|never|10y)['"]/gi,
|
|
120
129
|
message: 'A long-lived JWT expiry was detected.',
|
|
121
|
-
recommendation: 'Use
|
|
130
|
+
recommendation: 'Use short-lived access tokens and refresh-token rotation.'
|
|
122
131
|
}
|
|
123
132
|
];
|
|
124
133
|
export const securityHeaderNames = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-patterns.js","sourceRoot":"","sources":["../../../src/core/security-patterns.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,cAAc,GAAsB;IAC/C;QACE,EAAE,EAAE,4BAA4B;QAChC,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,kCAAkC;QACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"security-patterns.js","sourceRoot":"","sources":["../../../src/core/security-patterns.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,cAAc,GAAsB;IAC/C;QACE,EAAE,EAAE,4BAA4B;QAChC,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,kCAAkC;QACzC,OAAO,EAAE,uCAAuC;QAChD,cAAc,EACZ,mFAAmF;KACtF;IACD;QACE,EAAE,EAAE,8BAA8B;QAClC,KAAK,EAAE,yBAAyB;QAChC,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,uBAAuB;QAC9B,OAAO,EAAE,yCAAyC;QAClD,cAAc,EACZ,wDAAwD;KAC3D;IACD;QACE,EAAE,EAAE,2BAA2B;QAC/B,KAAK,EAAE,sBAAsB;QAC7B,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,uDAAuD;QAC9D,OAAO,EAAE,iCAAiC;QAC1C,cAAc,EACZ,qEAAqE;KACxE;IACD;QACE,EAAE,EAAE,yBAAyB;QAC7B,KAAK,EAAE,oBAAoB;QAC3B,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,2BAA2B;QAClC,OAAO,EAAE,oCAAoC;QAC7C,cAAc,EACZ,sDAAsD;KACzD;IACD;QACE,EAAE,EAAE,kCAAkC;QACtC,KAAK,EAAE,6BAA6B;QACpC,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,sDAAsD;QAC7D,OAAO,EAAE,iDAAiD;QAC1D,cAAc,EACZ,2EAA2E;KAC9E;IACD;QACE,EAAE,EAAE,0BAA0B;QAC9B,KAAK,EAAE,+BAA+B;QACtC,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,iEAAiE;QACxE,OAAO,EAAE,mCAAmC;QAC5C,cAAc,EACZ,2DAA2D;KAC9D;IACD;QACE,EAAE,EAAE,+BAA+B;QACnC,KAAK,EAAE,0BAA0B;QACjC,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,iEAAiE;QACxE,OAAO,EAAE,2CAA2C;QACpD,cAAc,EACZ,kEAAkE;KACrE;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAsB;IACtD;QACE,EAAE,EAAE,uBAAuB;QAC3B,KAAK,EAAE,sBAAsB;QAC7B,QAAQ,EAAE,gBAAgB;QAC1B,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,cAAc;QACrB,OAAO,EACL,iEAAiE;QACnE,cAAc,EACZ,4DAA4D;KAC/D;IACD;QACE,EAAE,EAAE,+BAA+B;QACnC,KAAK,EAAE,sCAAsC;QAC7C,QAAQ,EAAE,gBAAgB;QAC1B,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,wBAAwB;QAC/B,OAAO,EACL,iDAAiD;QACnD,cAAc,EACZ,2DAA2D;KAC9D;IACD;QACE,EAAE,EAAE,qCAAqC;QACzC,KAAK,EAAE,iCAAiC;QACxC,QAAQ,EAAE,gBAAgB;QAC1B,QAAQ,EAAE,MAAM;QAChB,KAAK,EACH,sDAAsD;QACxD,OAAO,EACL,6EAA6E;QAC/E,cAAc,EACZ,0EAA0E;KAC7E;IACD;QACE,EAAE,EAAE,2BAA2B;QAC/B,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE,gBAAgB;QAC1B,QAAQ,EAAE,MAAM;QAChB,KAAK,EACH,8DAA8D;QAChE,OAAO,EACL,yEAAyE;QAC3E,cAAc,EACZ,2EAA2E;KAC9E;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAsB;IACvD;QACE,EAAE,EAAE,yBAAyB;QAC7B,KAAK,EAAE,2BAA2B;QAClC,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,4BAA4B;QACnC,OAAO,EAAE,mCAAmC;QAC5C,cAAc,EACZ,8CAA8C;KACjD;IACD;QACE,EAAE,EAAE,+BAA+B;QACnC,KAAK,EAAE,0BAA0B;QACjC,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE,MAAM;QAChB,KAAK,EACH,oGAAoG;QACtG,OAAO,EAAE,iCAAiC;QAC1C,cAAc,EACZ,0CAA0C;KAC7C;IACD;QACE,EAAE,EAAE,+BAA+B;QACnC,KAAK,EAAE,gCAAgC;QACvC,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE,QAAQ;QAClB,KAAK,EACH,+EAA+E;QACjF,OAAO,EAAE,uCAAuC;QAChD,cAAc,EACZ,2DAA2D;KAC9D;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,yBAAyB;IACzB,2BAA2B;IAC3B,iBAAiB;IACjB,wBAAwB;CACzB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolip",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "A TypeScript-powered developer security companion CLI for supply chain security, dependency intelligence, secret detection, security auditing, encrypted local secrets management, Git security checks, and secure development education.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"toolip": "dist/src/index.js"
|
|
8
8
|
},
|
|
9
|
-
"main": "
|
|
9
|
+
"main": "dist/src/index.js",
|
|
10
10
|
"files": [
|
|
11
11
|
"dist/src",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
+
"clean": "rm -rf dist",
|
|
16
17
|
"dev": "tsx src/index.ts",
|
|
17
18
|
"build": "tsc",
|
|
18
19
|
"start": "node dist/src/index.js",
|
|
19
20
|
"test": "vitest run",
|
|
20
21
|
"test:watch": "vitest",
|
|
21
22
|
"typecheck": "tsc --noEmit",
|
|
22
|
-
"verify": "
|
|
23
|
+
"verify:package": "node scripts/verify-package.mjs",
|
|
24
|
+
"verify": "npm run typecheck && npm test && npm run clean && npm run build && npm run verify:package",
|
|
25
|
+
"prepack": "npm run verify",
|
|
23
26
|
"pack:check": "npm pack --dry-run"
|
|
24
27
|
},
|
|
25
28
|
"keywords": [
|