toolip 1.0.6 → 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.
Files changed (139) hide show
  1. package/dist/src/commands/alternatives.d.ts +2 -0
  2. package/dist/src/commands/alternatives.js +17 -0
  3. package/dist/src/commands/alternatives.js.map +1 -0
  4. package/dist/src/commands/compare.d.ts +2 -0
  5. package/dist/src/commands/compare.js +19 -0
  6. package/dist/src/commands/compare.js.map +1 -0
  7. package/dist/src/commands/doctor.d.ts +2 -0
  8. package/dist/src/commands/doctor.js +42 -0
  9. package/dist/src/commands/doctor.js.map +1 -0
  10. package/dist/src/commands/git-audit.d.ts +2 -0
  11. package/dist/src/commands/git-audit.js +37 -0
  12. package/dist/src/commands/git-audit.js.map +1 -0
  13. package/dist/src/commands/hook.d.ts +2 -0
  14. package/dist/src/commands/hook.js +16 -0
  15. package/dist/src/commands/hook.js.map +1 -0
  16. package/dist/src/commands/inspect.d.ts +2 -0
  17. package/dist/src/commands/inspect.js +24 -0
  18. package/dist/src/commands/inspect.js.map +1 -0
  19. package/dist/src/commands/learn.d.ts +2 -0
  20. package/dist/src/commands/learn.js +42 -0
  21. package/dist/src/commands/learn.js.map +1 -0
  22. package/dist/src/commands/licenses.d.ts +2 -0
  23. package/dist/src/commands/licenses.js +40 -0
  24. package/dist/src/commands/licenses.js.map +1 -0
  25. package/dist/src/commands/pre-commit.d.ts +2 -0
  26. package/dist/src/commands/pre-commit.js +37 -0
  27. package/dist/src/commands/pre-commit.js.map +1 -0
  28. package/dist/src/commands/profile.d.ts +2 -0
  29. package/dist/src/commands/profile.js +18 -0
  30. package/dist/src/commands/profile.js.map +1 -0
  31. package/dist/src/commands/scan.d.ts +2 -0
  32. package/dist/src/commands/scan.js +48 -0
  33. package/dist/src/commands/scan.js.map +1 -0
  34. package/dist/src/commands/score.d.ts +2 -0
  35. package/dist/src/commands/score.js +24 -0
  36. package/dist/src/commands/score.js.map +1 -0
  37. package/dist/src/commands/self-test.d.ts +2 -0
  38. package/dist/src/commands/self-test.js +63 -0
  39. package/dist/src/commands/self-test.js.map +1 -0
  40. package/dist/src/commands/tree.d.ts +2 -0
  41. package/dist/src/commands/tree.js +21 -0
  42. package/dist/src/commands/tree.js.map +1 -0
  43. package/dist/src/commands/vault.d.ts +2 -0
  44. package/dist/src/commands/vault.js +86 -0
  45. package/dist/src/commands/vault.js.map +1 -0
  46. package/dist/src/config/version.d.ts +6 -0
  47. package/dist/src/config/version.js +29 -0
  48. package/dist/src/config/version.js.map +1 -0
  49. package/dist/src/core/alternatives.d.ts +8 -0
  50. package/dist/src/core/alternatives.js +35 -0
  51. package/dist/src/core/alternatives.js.map +1 -0
  52. package/dist/src/core/analyze-package.d.ts +2 -0
  53. package/dist/src/core/analyze-package.js +49 -0
  54. package/dist/src/core/analyze-package.js.map +1 -0
  55. package/dist/src/core/compare-packages.d.ts +7 -0
  56. package/dist/src/core/compare-packages.js +19 -0
  57. package/dist/src/core/compare-packages.js.map +1 -0
  58. package/dist/src/core/dependency-scan.d.ts +17 -0
  59. package/dist/src/core/dependency-scan.js +70 -0
  60. package/dist/src/core/dependency-scan.js.map +1 -0
  61. package/dist/src/core/dependency-tree.d.ts +16 -0
  62. package/dist/src/core/dependency-tree.js +19 -0
  63. package/dist/src/core/dependency-tree.js.map +1 -0
  64. package/dist/src/core/dependency-types.d.ts +17 -0
  65. package/dist/src/core/dependency-types.js +2 -0
  66. package/dist/src/core/dependency-types.js.map +1 -0
  67. package/dist/src/core/file-walker.d.ts +6 -0
  68. package/dist/src/core/file-walker.js +27 -0
  69. package/dist/src/core/file-walker.js.map +1 -0
  70. package/dist/src/core/git-audit.d.ts +12 -0
  71. package/dist/src/core/git-audit.js +111 -0
  72. package/dist/src/core/git-audit.js.map +1 -0
  73. package/dist/src/core/hooks.d.ts +1 -0
  74. package/dist/src/core/hooks.js +14 -0
  75. package/dist/src/core/hooks.js.map +1 -0
  76. package/dist/src/core/learn.d.ts +11 -0
  77. package/dist/src/core/learn.js +163 -0
  78. package/dist/src/core/learn.js.map +1 -0
  79. package/dist/src/core/license-analysis.d.ts +18 -0
  80. package/dist/src/core/license-analysis.js +98 -0
  81. package/dist/src/core/license-analysis.js.map +1 -0
  82. package/dist/src/core/load-toolip-ignore.d.ts +5 -0
  83. package/dist/src/core/load-toolip-ignore.js +35 -0
  84. package/dist/src/core/load-toolip-ignore.js.map +1 -0
  85. package/dist/src/core/npm-registry.d.ts +3 -0
  86. package/dist/src/core/npm-registry.js +5 -0
  87. package/dist/src/core/npm-registry.js.map +1 -0
  88. package/dist/src/core/pre-commit.d.ts +11 -0
  89. package/dist/src/core/pre-commit.js +22 -0
  90. package/dist/src/core/pre-commit.js.map +1 -0
  91. package/dist/src/core/profile-project.d.ts +23 -0
  92. package/dist/src/core/profile-project.js +119 -0
  93. package/dist/src/core/profile-project.js.map +1 -0
  94. package/dist/src/core/read-dependencies.d.ts +2 -0
  95. package/dist/src/core/read-dependencies.js +24 -0
  96. package/dist/src/core/read-dependencies.js.map +1 -0
  97. package/dist/src/core/report-writer.d.ts +5 -0
  98. package/dist/src/core/report-writer.js +61 -0
  99. package/dist/src/core/report-writer.js.map +1 -0
  100. package/dist/src/core/report.d.ts +34 -0
  101. package/dist/src/core/report.js +26 -0
  102. package/dist/src/core/report.js.map +1 -0
  103. package/dist/src/core/risk-score.d.ts +5 -0
  104. package/dist/src/core/risk-score.js +14 -0
  105. package/dist/src/core/risk-score.js.map +1 -0
  106. package/dist/src/core/scanner-context.d.ts +12 -0
  107. package/dist/src/core/scanner-context.js +27 -0
  108. package/dist/src/core/scanner-context.js.map +1 -0
  109. package/dist/src/core/score.d.ts +13 -0
  110. package/dist/src/core/score.js +44 -0
  111. package/dist/src/core/score.js.map +1 -0
  112. package/dist/src/core/security-doctor.d.ts +12 -0
  113. package/dist/src/core/security-doctor.js +144 -0
  114. package/dist/src/core/security-doctor.js.map +1 -0
  115. package/dist/src/core/security-patterns.d.ts +14 -0
  116. package/dist/src/core/security-patterns.js +139 -0
  117. package/dist/src/core/security-patterns.js.map +1 -0
  118. package/dist/src/core/typosquat.d.ts +6 -0
  119. package/dist/src/core/typosquat.js +50 -0
  120. package/dist/src/core/typosquat.js.map +1 -0
  121. package/dist/src/core/vault.d.ts +48 -0
  122. package/dist/src/core/vault.js +127 -0
  123. package/dist/src/core/vault.js.map +1 -0
  124. package/dist/src/errors/toolip-error.d.ts +8 -0
  125. package/dist/src/errors/toolip-error.js +11 -0
  126. package/dist/src/errors/toolip-error.js.map +1 -0
  127. package/dist/src/index.d.ts +2 -0
  128. package/dist/src/index.js +51 -0
  129. package/dist/src/index.js.map +1 -0
  130. package/dist/src/utils/error-handler.d.ts +1 -0
  131. package/dist/src/utils/error-handler.js +24 -0
  132. package/dist/src/utils/error-handler.js.map +1 -0
  133. package/dist/src/utils/output.d.ts +6 -0
  134. package/dist/src/utils/output.js +72 -0
  135. package/dist/src/utils/output.js.map +1 -0
  136. package/dist/src/utils/package-output.d.ts +4 -0
  137. package/dist/src/utils/package-output.js +40 -0
  138. package/dist/src/utils/package-output.js.map +1 -0
  139. package/package.json +9 -6
@@ -0,0 +1,61 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ export function detectReportFormat(outputPath) {
4
+ const extension = path.extname(outputPath).toLowerCase();
5
+ if (extension === '.md' || extension === '.markdown') {
6
+ return 'md';
7
+ }
8
+ return 'json';
9
+ }
10
+ export async function writeReport(outputPath, report) {
11
+ const format = detectReportFormat(outputPath);
12
+ if (format === 'md') {
13
+ await writeFile(outputPath, renderMarkdownReport(report), 'utf8');
14
+ return;
15
+ }
16
+ await writeFile(outputPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
17
+ }
18
+ export function renderMarkdownReport(report) {
19
+ const findings = report.findings.length
20
+ ? report.findings
21
+ .map((finding) => {
22
+ const fileLine = finding.file ? `\n- File: \`${finding.file}\`` : '';
23
+ const evidenceLine = finding.evidence ? `\n- Evidence: \`${finding.evidence}\`` : '';
24
+ return `### ${finding.title}
25
+
26
+ - ID: \`${finding.id}\`
27
+ - Severity: **${finding.severity.toUpperCase()}**
28
+ - Category: ${finding.category}${fileLine}${evidenceLine}
29
+
30
+ ${finding.message}
31
+
32
+ **Recommendation:** ${finding.recommendation}
33
+ `;
34
+ })
35
+ .join('\n')
36
+ : 'No findings were detected.';
37
+ return `# Toolip Report
38
+
39
+ Generated: ${report.generatedAt}
40
+
41
+ Root: \`${report.root}\`
42
+
43
+ Command: \`${report.command}\`
44
+
45
+ ## Summary
46
+
47
+ | Severity | Count |
48
+ |---|---:|
49
+ | Critical | ${report.summary.critical} |
50
+ | High | ${report.summary.high} |
51
+ | Medium | ${report.summary.medium} |
52
+ | Low | ${report.summary.low} |
53
+ | Info | ${report.summary.info} |
54
+ | Total | ${report.summary.totalFindings} |
55
+
56
+ ## Findings
57
+
58
+ ${findings}
59
+ `;
60
+ }
61
+ //# sourceMappingURL=report-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-writer.js","sourceRoot":"","sources":["../../../src/core/report-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,IAAI,MAAM,WAAW,CAAC;AAK7B,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;IAEzD,IAAI,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAkB,EAAE,MAAoB;IACxE,MAAM,MAAM,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAE9C,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,MAAM,SAAS,CAAC,UAAU,EAAE,oBAAoB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;QAClE,OAAO;IACT,CAAC;IAED,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAoB;IACvD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM;QACrC,CAAC,CAAC,MAAM,CAAC,QAAQ;aACZ,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YACf,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,mBAAmB,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAErF,OAAO,OAAO,OAAO,CAAC,KAAK;;UAE3B,OAAO,CAAC,EAAE;gBACJ,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE;cAChC,OAAO,CAAC,QAAQ,GAAG,QAAQ,GAAG,YAAY;;EAEtD,OAAO,CAAC,OAAO;;sBAEK,OAAO,CAAC,cAAc;CAC3C,CAAC;QACM,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC;QACf,CAAC,CAAC,4BAA4B,CAAC;IAEjC,OAAO;;aAEI,MAAM,CAAC,WAAW;;UAErB,MAAM,CAAC,IAAI;;aAER,MAAM,CAAC,OAAO;;;;;;eAMZ,MAAM,CAAC,OAAO,CAAC,QAAQ;WAC3B,MAAM,CAAC,OAAO,CAAC,IAAI;aACjB,MAAM,CAAC,OAAO,CAAC,MAAM;UACxB,MAAM,CAAC,OAAO,CAAC,GAAG;WACjB,MAAM,CAAC,OAAO,CAAC,IAAI;YAClB,MAAM,CAAC,OAAO,CAAC,aAAa;;;;EAItC,QAAQ;CACT,CAAC;AACF,CAAC"}
@@ -0,0 +1,34 @@
1
+ export type FindingSeverity = 'info' | 'low' | 'medium' | 'high' | 'critical';
2
+ export type ToolipFinding = {
3
+ id: string;
4
+ title: string;
5
+ severity: FindingSeverity;
6
+ category: string;
7
+ message: string;
8
+ recommendation: string;
9
+ file?: string;
10
+ evidence?: string;
11
+ };
12
+ export type ToolipReport = {
13
+ tool: 'toolip';
14
+ version: string;
15
+ command: string;
16
+ generatedAt: string;
17
+ root: string;
18
+ summary: {
19
+ totalFindings: number;
20
+ critical: number;
21
+ high: number;
22
+ medium: number;
23
+ low: number;
24
+ info: number;
25
+ };
26
+ findings: ToolipFinding[];
27
+ };
28
+ export declare function createReport(input: {
29
+ version: string;
30
+ command: string;
31
+ root: string;
32
+ findings: ToolipFinding[];
33
+ }): ToolipReport;
34
+ export declare function summarizeFindings(findings: ToolipFinding[]): ToolipReport['summary'];
@@ -0,0 +1,26 @@
1
+ export function createReport(input) {
2
+ return {
3
+ tool: 'toolip',
4
+ version: input.version,
5
+ command: input.command,
6
+ generatedAt: new Date().toISOString(),
7
+ root: input.root,
8
+ summary: summarizeFindings(input.findings),
9
+ findings: input.findings
10
+ };
11
+ }
12
+ export function summarizeFindings(findings) {
13
+ return findings.reduce((summary, finding) => {
14
+ summary.totalFindings += 1;
15
+ summary[finding.severity] += 1;
16
+ return summary;
17
+ }, {
18
+ totalFindings: 0,
19
+ critical: 0,
20
+ high: 0,
21
+ medium: 0,
22
+ low: 0,
23
+ info: 0
24
+ });
25
+ }
26
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/core/report.ts"],"names":[],"mappings":"AA8BA,MAAM,UAAU,YAAY,CAAC,KAK5B;IACC,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,QAAQ,CAAC;QAC1C,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAyB;IACzD,OAAO,QAAQ,CAAC,MAAM,CACpB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;QACnB,OAAO,CAAC,aAAa,IAAI,CAAC,CAAC;QAC3B,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC,EACD;QACE,aAAa,EAAE,CAAC;QAChB,QAAQ,EAAE,CAAC;QACX,IAAI,EAAE,CAAC;QACP,MAAM,EAAE,CAAC;QACT,GAAG,EAAE,CAAC;QACN,IAAI,EAAE,CAAC;KACR,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function calculateRiskScore(input: {
2
+ deprecated: boolean;
3
+ maintainers: number;
4
+ ageInDays: number | null;
5
+ }): number;
@@ -0,0 +1,14 @@
1
+ export function calculateRiskScore(input) {
2
+ let score = 0;
3
+ if (input.deprecated)
4
+ score += 40;
5
+ if (input.maintainers === 0)
6
+ score += 30;
7
+ else if (input.maintainers === 1)
8
+ score += 15;
9
+ if (input.ageInDays !== null && input.ageInDays > 730) {
10
+ score += 20;
11
+ }
12
+ return Math.min(score, 100);
13
+ }
14
+ //# sourceMappingURL=risk-score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk-score.js","sourceRoot":"","sources":["../../../src/core/risk-score.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,KAIlC;IACC,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,IAAI,KAAK,CAAC,UAAU;QAAE,KAAK,IAAI,EAAE,CAAC;IAElC,IAAI,KAAK,CAAC,WAAW,KAAK,CAAC;QAAE,KAAK,IAAI,EAAE,CAAC;SACpC,IAAI,KAAK,CAAC,WAAW,KAAK,CAAC;QAAE,KAAK,IAAI,EAAE,CAAC;IAE9C,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,IAAI,KAAK,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC;QACtD,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { type ProjectFile } from './file-walker.js';
2
+ import { type ProjectProfile } from './profile-project.js';
3
+ export type ScannerContext = {
4
+ root: string;
5
+ profile: ProjectProfile;
6
+ files: ProjectFile[];
7
+ summary: {
8
+ totalFiles: number;
9
+ extensions: Record<string, number>;
10
+ };
11
+ };
12
+ export declare function createScannerContext(root: string): Promise<ScannerContext>;
@@ -0,0 +1,27 @@
1
+ import path from 'node:path';
2
+ import { walkProjectFiles } from './file-walker.js';
3
+ import { profileProject } from './profile-project.js';
4
+ function summarizeExtensions(files) {
5
+ return files.reduce((summary, file) => {
6
+ const key = file.extension || 'none';
7
+ summary[key] = (summary[key] ?? 0) + 1;
8
+ return summary;
9
+ }, {});
10
+ }
11
+ export async function createScannerContext(root) {
12
+ const absoluteRoot = path.resolve(root);
13
+ const [profile, files] = await Promise.all([
14
+ profileProject(absoluteRoot),
15
+ walkProjectFiles(absoluteRoot)
16
+ ]);
17
+ return {
18
+ root: absoluteRoot,
19
+ profile,
20
+ files,
21
+ summary: {
22
+ totalFiles: files.length,
23
+ extensions: summarizeExtensions(files)
24
+ }
25
+ };
26
+ }
27
+ //# sourceMappingURL=scanner-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner-context.js","sourceRoot":"","sources":["../../../src/core/scanner-context.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAoB,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,cAAc,EAAuB,MAAM,sBAAsB,CAAC;AAY3E,SAAS,mBAAmB,CAAC,KAAoB;IAC/C,OAAO,KAAK,CAAC,MAAM,CAAyB,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE;QAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACvC,OAAO,OAAO,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAY;IACrD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACzC,cAAc,CAAC,YAAY,CAAC;QAC5B,gBAAgB,CAAC,YAAY,CAAC;KAC/B,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,OAAO;QACP,KAAK;QACL,OAAO,EAAE;YACP,UAAU,EAAE,KAAK,CAAC,MAAM;YACxB,UAAU,EAAE,mBAAmB,CAAC,KAAK,CAAC;SACvC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { ToolipFinding } from './report.js';
2
+ export type ScoreGrade = 'A' | 'B' | 'C' | 'D' | 'F';
3
+ export type ToolipScore = {
4
+ dependencyHealth: number;
5
+ secretHygiene: number;
6
+ configurationSecurity: number;
7
+ gitSafety: number;
8
+ overall: number;
9
+ grade: ScoreGrade;
10
+ };
11
+ export declare function calculateScore(input?: Partial<Omit<ToolipScore, 'overall' | 'grade'>>): ToolipScore;
12
+ export declare function calculateDependencyHealth(findings: ToolipFinding[]): number;
13
+ export declare function gradeScore(score: number): ScoreGrade;
@@ -0,0 +1,44 @@
1
+ export function calculateScore(input) {
2
+ const dependencyHealth = clamp(input?.dependencyHealth ?? 100);
3
+ const secretHygiene = clamp(input?.secretHygiene ?? 100);
4
+ const configurationSecurity = clamp(input?.configurationSecurity ?? 100);
5
+ const gitSafety = clamp(input?.gitSafety ?? 100);
6
+ const overall = Math.round((dependencyHealth + secretHygiene + configurationSecurity + gitSafety) / 4);
7
+ return {
8
+ dependencyHealth,
9
+ secretHygiene,
10
+ configurationSecurity,
11
+ gitSafety,
12
+ overall,
13
+ grade: gradeScore(overall)
14
+ };
15
+ }
16
+ export function calculateDependencyHealth(findings) {
17
+ const penalty = findings.reduce((total, finding) => {
18
+ if (finding.severity === 'critical')
19
+ return total + 35;
20
+ if (finding.severity === 'high')
21
+ return total + 25;
22
+ if (finding.severity === 'medium')
23
+ return total + 12;
24
+ if (finding.severity === 'low')
25
+ return total + 5;
26
+ return total + 0;
27
+ }, 0);
28
+ return clamp(100 - penalty);
29
+ }
30
+ function clamp(value) {
31
+ return Math.max(0, Math.min(100, Math.round(value)));
32
+ }
33
+ export function gradeScore(score) {
34
+ if (score >= 90)
35
+ return 'A';
36
+ if (score >= 80)
37
+ return 'B';
38
+ if (score >= 70)
39
+ return 'C';
40
+ if (score >= 60)
41
+ return 'D';
42
+ return 'F';
43
+ }
44
+ //# sourceMappingURL=score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../../src/core/score.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,cAAc,CAAC,KAAuD;IACpF,MAAM,gBAAgB,GAAG,KAAK,CAAC,KAAK,EAAE,gBAAgB,IAAI,GAAG,CAAC,CAAC;IAC/D,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,EAAE,aAAa,IAAI,GAAG,CAAC,CAAC;IACzD,MAAM,qBAAqB,GAAG,KAAK,CAAC,KAAK,EAAE,qBAAqB,IAAI,GAAG,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,EAAE,SAAS,IAAI,GAAG,CAAC,CAAC;IAEjD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CACxB,CAAC,gBAAgB,GAAG,aAAa,GAAG,qBAAqB,GAAG,SAAS,CAAC,GAAG,CAAC,CAC3E,CAAC;IAEF,OAAO;QACL,gBAAgB;QAChB,aAAa;QACb,qBAAqB;QACrB,SAAS;QACT,OAAO;QACP,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC;KAC3B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAAyB;IACjE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACjD,IAAI,OAAO,CAAC,QAAQ,KAAK,UAAU;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACvD,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACnD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACrD,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK;YAAE,OAAO,KAAK,GAAG,CAAC,CAAC;QACjD,OAAO,KAAK,GAAG,CAAC,CAAC;IACnB,CAAC,EAAE,CAAC,CAAC,CAAC;IAEN,OAAO,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,KAAK,CAAC,KAAa;IAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ToolipFinding } from './report.js';
2
+ export type SecurityDoctorResult = {
3
+ findings: ToolipFinding[];
4
+ summary: {
5
+ filesScanned: number;
6
+ secrets: number;
7
+ dangerousCode: number;
8
+ configuration: number;
9
+ headers: number;
10
+ };
11
+ };
12
+ export declare function runSecurityDoctor(root: string): Promise<SecurityDoctorResult>;
@@ -0,0 +1,144 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { createScannerContext } from './scanner-context.js';
3
+ import { configSecurityPatterns, dangerousCodePatterns, secretPatterns, securityHeaderNames } from './security-patterns.js';
4
+ const secretScanExtensions = new Set([
5
+ 'js',
6
+ 'jsx',
7
+ 'ts',
8
+ 'tsx',
9
+ 'mjs',
10
+ 'cjs',
11
+ 'json',
12
+ 'yml',
13
+ 'yaml',
14
+ 'env',
15
+ 'txt',
16
+ 'pem',
17
+ 'key'
18
+ ]);
19
+ const codeExtensions = new Set([
20
+ 'js',
21
+ 'jsx',
22
+ 'ts',
23
+ 'tsx',
24
+ 'mjs',
25
+ 'cjs'
26
+ ]);
27
+ export async function runSecurityDoctor(root) {
28
+ const context = await createScannerContext(root);
29
+ const findings = [];
30
+ for (const file of context.files) {
31
+ if (!shouldScanSecrets(file.relativePath, file.extension)) {
32
+ continue;
33
+ }
34
+ let content = '';
35
+ try {
36
+ content = await readFile(file.absolutePath, 'utf8');
37
+ }
38
+ catch {
39
+ continue;
40
+ }
41
+ findings.push(...scanContent(file.relativePath, content, secretPatterns));
42
+ if (codeExtensions.has(file.extension)) {
43
+ findings.push(...scanContent(file.relativePath, content, dangerousCodePatterns));
44
+ findings.push(...scanContent(file.relativePath, content, configSecurityPatterns));
45
+ }
46
+ }
47
+ findings.push(...detectMissingSecurityHeaders(context.files.map((file) => file.relativePath)));
48
+ return {
49
+ findings,
50
+ summary: {
51
+ filesScanned: context.files.length,
52
+ secrets: findings.filter((finding) => finding.category === 'secrets').length,
53
+ dangerousCode: findings.filter((finding) => finding.category === 'dangerous-code').length,
54
+ configuration: findings.filter((finding) => finding.category === 'configuration').length,
55
+ headers: findings.filter((finding) => finding.category === 'security-headers').length
56
+ }
57
+ };
58
+ }
59
+ function shouldScanSecrets(relativePath, extension) {
60
+ if (relativePath.endsWith('.d.ts'))
61
+ return false;
62
+ if (relativePath.endsWith('.map'))
63
+ return false;
64
+ if (relativePath.startsWith('dist/'))
65
+ return false;
66
+ if (relativePath.endsWith('.env'))
67
+ return true;
68
+ if (relativePath.includes('.env.'))
69
+ return true;
70
+ return secretScanExtensions.has(extension);
71
+ }
72
+ function scanContent(relativePath, content, patterns) {
73
+ const findings = [];
74
+ for (const pattern of patterns) {
75
+ pattern.regex.lastIndex = 0;
76
+ const match = pattern.regex.exec(content);
77
+ pattern.regex.lastIndex = 0;
78
+ if (!match) {
79
+ continue;
80
+ }
81
+ findings.push({
82
+ id: `${pattern.id}-${relativePath
83
+ .toUpperCase()
84
+ .replaceAll(/[^A-Z0-9]/g, '-')}`,
85
+ title: formatTitle(pattern, relativePath),
86
+ severity: resolveSeverity(pattern, relativePath),
87
+ category: pattern.category,
88
+ message: formatMessage(pattern, relativePath),
89
+ recommendation: pattern.recommendation,
90
+ file: relativePath,
91
+ evidence: redactEvidence(match[0])
92
+ });
93
+ }
94
+ return findings;
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
+ }
120
+ function redactEvidence(value) {
121
+ if (value.length <= 16) {
122
+ return value;
123
+ }
124
+ return `${value.slice(0, 8)}...[redacted]...${value.slice(-4)}`;
125
+ }
126
+ function detectMissingSecurityHeaders(relativePaths) {
127
+ const possibleServerFiles = relativePaths.filter((file) => !file.startsWith('dist/') &&
128
+ /server|app|main|index|middleware/i.test(file) &&
129
+ /\.(js|ts|jsx|tsx|mjs|cjs)$/.test(file));
130
+ if (possibleServerFiles.length === 0) {
131
+ return [];
132
+ }
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
+ }));
143
+ }
144
+ //# sourceMappingURL=security-doctor.js.map
@@ -0,0 +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,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;IACN,KAAK;IACL,MAAM;IACN,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;CACN,CAAC,CAAC;AAEH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,KAAK;IACL,KAAK;IACL,KAAK;CACN,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAY;IAEZ,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1D,SAAS;QACX,CAAC;QAED,IAAI,OAAO,GAAG,EAAE,CAAC;QAEjB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,QAAQ,CAAC,IAAI,CACX,GAAG,WAAW,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,EAAE,cAAc,CAAC,CAC3D,CAAC;QAEF,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,QAAQ,CAAC,IAAI,CACX,GAAG,WAAW,CACZ,IAAI,CAAC,YAAY,EACjB,OAAO,EACP,qBAAqB,CACtB,CACF,CAAC;YAEF,QAAQ,CAAC,IAAI,CACX,GAAG,WAAW,CACZ,IAAI,CAAC,YAAY,EACjB,OAAO,EACP,sBAAsB,CACvB,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,IAAI,CACX,GAAG,4BAA4B,CAC7B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAC/C,CACF,CAAC;IAEF,OAAO;QACL,QAAQ;QACR,OAAO,EAAE;YACP,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;YAClC,OAAO,EAAE,QAAQ,CAAC,MAAM,CACtB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAC5C,CAAC,MAAM;YACR,aAAa,EAAE,QAAQ,CAAC,MAAM,CAC5B,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,gBAAgB,CACnD,CAAC,MAAM;YACR,aAAa,EAAE,QAAQ,CAAC,MAAM,CAC5B,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,eAAe,CAClD,CAAC,MAAM;YACR,OAAO,EAAE,QAAQ,CAAC,MAAM,CACtB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,kBAAkB,CACrD,CAAC,MAAM;SACT;KACF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CACxB,YAAoB,EACpB,SAAiB;IAEjB,IAAI,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACjD,IAAI,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,IAAI,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAEhD,OAAO,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,WAAW,CAClB,YAAoB,EACpB,OAAe,EACf,QAA2B;IAE3B,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1C,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;QAE5B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,SAAS;QACX,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC;YACZ,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,YAAY;iBAC9B,WAAW,EAAE;iBACb,UAAU,CAAC,YAAY,EAAE,GAAG,CAAC,EAAE;YAClC,KAAK,EAAE,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC;YACzC,QAAQ,EAAE,eAAe,CAAC,OAAO,EAAE,YAAY,CAAC;YAChD,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC;YAC7C,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACnC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,UAAU,CAAC,YAAoB;IACtC,OAAO,CACL,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC;QACjC,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC;QAChC,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC;QACpC,8BAA8B,CAAC,IAAI,CAAC,YAAY,CAAC,CAClD,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CACtB,OAAwB,EACxB,YAAoB;IAEpB,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,OAAO,CAAC,QAAQ,CAAC;AAC1B,CAAC;AAED,SAAS,WAAW,CAClB,OAAwB,EACxB,YAAoB;IAEpB,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/D,OAAO,2BAA2B,OAAO,CAAC,KAAK,EAAE,CAAC;IACpD,CAAC;IAED,OAAO,OAAO,CAAC,KAAK,CAAC;AACvB,CAAC;AAED,SAAS,aAAa,CACpB,OAAwB,EACxB,YAAoB;IAEpB,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/D,OAAO,GAAG,OAAO,CAAC,OAAO,+GAA+G,CAAC;IAC3I,CAAC;IAED,OAAO,OAAO,CAAC,OAAO,CAAC;AACzB,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,mBAAmB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAClE,CAAC;AAED,SAAS,4BAA4B,CACnC,aAAuB;IAEvB,MAAM,mBAAmB,GAAG,aAAa,CAAC,MAAM,CAC9C,CAAC,IAAI,EAAE,EAAE,CACP,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QACzB,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC9C,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,CAC1C,CAAC;IAEF,IAAI,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,mBAAmB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC1C,EAAE,EAAE,wBAAwB,MAAM;aAC/B,WAAW,EAAE;aACb,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE;QACzB,KAAK,EAAE,2BAA2B,MAAM,EAAE;QAC1C,QAAQ,EAAE,MAAM;QAChB,QAAQ,EAAE,kBAAkB;QAC5B,OAAO,EAAE,gDAAgD,MAAM,yCAAyC;QACxG,cAAc,EACZ,oFAAoF;KACvF,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { ToolipFinding } from './report.js';
2
+ export type SecurityPattern = {
3
+ id: string;
4
+ title: string;
5
+ category: string;
6
+ severity: ToolipFinding['severity'];
7
+ regex: RegExp;
8
+ message: string;
9
+ recommendation: string;
10
+ };
11
+ export declare const secretPatterns: SecurityPattern[];
12
+ export declare const dangerousCodePatterns: SecurityPattern[];
13
+ export declare const configSecurityPatterns: SecurityPattern[];
14
+ export declare const securityHeaderNames: string[];
@@ -0,0 +1,139 @@
1
+ export const secretPatterns = [
2
+ {
3
+ id: 'TOOLIP-SECRET-GITHUB-TOKEN',
4
+ title: 'GitHub token detected',
5
+ category: 'secrets',
6
+ severity: 'critical',
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, remove it from Git history, and store its replacement securely.'
10
+ },
11
+ {
12
+ id: 'TOOLIP-SECRET-AWS-ACCESS-KEY',
13
+ title: 'AWS access key detected',
14
+ category: 'secrets',
15
+ severity: 'critical',
16
+ regex: /\bAKIA[0-9A-Z]{16}\b/g,
17
+ message: 'An AWS access key-like value was found.',
18
+ recommendation: 'Rotate the credential immediately and audit its usage.'
19
+ },
20
+ {
21
+ id: 'TOOLIP-SECRET-PRIVATE-KEY',
22
+ title: 'Private key detected',
23
+ category: 'secrets',
24
+ severity: 'critical',
25
+ regex: /-----BEGIN (RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----/g,
26
+ message: 'Private key material was found.',
27
+ recommendation: 'Remove the key from the repository and rotate affected credentials.'
28
+ },
29
+ {
30
+ id: 'TOOLIP-SECRET-NPM-TOKEN',
31
+ title: 'npm token detected',
32
+ category: 'secrets',
33
+ severity: 'critical',
34
+ regex: /\bnpm_[A-Za-z0-9]{20,}\b/g,
35
+ message: 'An npm token-like value was found.',
36
+ recommendation: 'Rotate the token and store its replacement securely.'
37
+ },
38
+ {
39
+ id: 'TOOLIP-SECRET-HARDCODED-PASSWORD',
40
+ title: 'Hardcoded password detected',
41
+ category: 'secrets',
42
+ severity: 'high',
43
+ regex: /\b(password|passwd|pwd)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
44
+ message: 'A hardcoded password-like assignment was found.',
45
+ recommendation: 'Move passwords into environment variables or an encrypted secret manager.'
46
+ },
47
+ {
48
+ id: 'TOOLIP-SECRET-JWT-SECRET',
49
+ title: 'Hardcoded JWT secret detected',
50
+ category: 'secrets',
51
+ severity: 'high',
52
+ regex: /\b(jwtSecret|JWT_SECRET|jwt_secret)\s*[:=]\s*['"][^'"]{8,}['"]/g,
53
+ message: 'A hardcoded JWT secret was found.',
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.'
64
+ }
65
+ ];
66
+ export const dangerousCodePatterns = [
67
+ {
68
+ id: 'TOOLIP-DANGEROUS-EVAL',
69
+ title: 'Dangerous eval usage',
70
+ category: 'dangerous-code',
71
+ severity: 'high',
72
+ regex: /\beval\s*\(/g,
73
+ message: 'eval() can execute arbitrary code and introduce injection risk.',
74
+ recommendation: 'Replace eval() with explicit parsing or safe control flow.'
75
+ },
76
+ {
77
+ id: 'TOOLIP-DANGEROUS-NEW-FUNCTION',
78
+ title: 'Dangerous Function constructor usage',
79
+ category: 'dangerous-code',
80
+ severity: 'high',
81
+ regex: /\bnew\s+Function\s*\(/g,
82
+ message: 'The Function constructor executes dynamic code.',
83
+ recommendation: 'Avoid runtime code generation and use explicit functions.'
84
+ },
85
+ {
86
+ id: 'TOOLIP-DANGEROUS-CHILD-PROCESS-EXEC',
87
+ title: 'Unsafe child_process exec usage',
88
+ category: 'dangerous-code',
89
+ severity: 'high',
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.'
93
+ },
94
+ {
95
+ id: 'TOOLIP-DANGEROUS-EXECSYNC',
96
+ title: 'Unsafe execSync usage',
97
+ category: 'dangerous-code',
98
+ severity: 'high',
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.'
102
+ }
103
+ ];
104
+ export const configSecurityPatterns = [
105
+ {
106
+ id: 'TOOLIP-CONFIG-OPEN-CORS',
107
+ title: 'Open CORS policy detected',
108
+ category: 'configuration',
109
+ severity: 'medium',
110
+ regex: /\borigin\s*:\s*['"]\*['"]/g,
111
+ message: 'CORS origin is configured as "*".',
112
+ recommendation: 'Restrict allowed origins to trusted domains.'
113
+ },
114
+ {
115
+ id: 'TOOLIP-CONFIG-WEAK-JWT-SECRET',
116
+ title: 'Weak JWT secret detected',
117
+ category: 'configuration',
118
+ severity: 'high',
119
+ regex: /\b(jwtSecret|JWT_SECRET|jwt_secret)\s*[:=]\s*['"](secret|changeme|password|123456|devsecret)['"]/gi,
120
+ message: 'A weak JWT secret was detected.',
121
+ recommendation: 'Use a long, random, high-entropy secret.'
122
+ },
123
+ {
124
+ id: 'TOOLIP-CONFIG-LONG-JWT-EXPIRY',
125
+ title: 'Long-lived JWT expiry detected',
126
+ category: 'configuration',
127
+ severity: 'medium',
128
+ regex: /\b(expiresIn|JWT_EXPIRES_IN)\s*[:=]\s*['"](?:365d|999d|1000d|never|10y)['"]/gi,
129
+ message: 'A long-lived JWT expiry was detected.',
130
+ recommendation: 'Use short-lived access tokens and refresh-token rotation.'
131
+ }
132
+ ];
133
+ export const securityHeaderNames = [
134
+ 'content-security-policy',
135
+ 'strict-transport-security',
136
+ 'x-frame-options',
137
+ 'x-content-type-options'
138
+ ];
139
+ //# sourceMappingURL=security-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-patterns.js","sourceRoot":"","sources":["../../../src/core/security-patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type TyposquatResult = {
2
+ input: string;
3
+ suspected: boolean;
4
+ suggestions: string[];
5
+ };
6
+ export declare function detectTyposquat(input: string): TyposquatResult;
@@ -0,0 +1,50 @@
1
+ const popularPackages = [
2
+ 'express',
3
+ 'fastify',
4
+ 'react',
5
+ 'vue',
6
+ 'axios',
7
+ 'got',
8
+ 'lodash',
9
+ 'typescript',
10
+ 'commander',
11
+ 'chalk',
12
+ 'zod',
13
+ 'prisma',
14
+ 'vite',
15
+ 'next',
16
+ 'nestjs'
17
+ ];
18
+ export function detectTyposquat(input) {
19
+ const normalized = input.trim().toLowerCase();
20
+ const suggestions = popularPackages
21
+ .map((candidate) => ({
22
+ candidate,
23
+ distance: levenshtein(normalized, candidate)
24
+ }))
25
+ .filter((item) => item.distance > 0 && item.distance <= 2)
26
+ .sort((a, b) => a.distance - b.distance)
27
+ .map((item) => item.candidate);
28
+ return {
29
+ input,
30
+ suspected: suggestions.length > 0,
31
+ suggestions
32
+ };
33
+ }
34
+ function levenshtein(a, b) {
35
+ const matrix = Array.from({ length: a.length + 1 }, (_, row) => Array.from({ length: b.length + 1 }, (_, col) => {
36
+ if (row === 0)
37
+ return col;
38
+ if (col === 0)
39
+ return row;
40
+ return 0;
41
+ }));
42
+ for (let row = 1; row <= a.length; row += 1) {
43
+ for (let col = 1; col <= b.length; col += 1) {
44
+ const cost = a[row - 1] === b[col - 1] ? 0 : 1;
45
+ matrix[row][col] = Math.min(matrix[row - 1][col] + 1, matrix[row][col - 1] + 1, matrix[row - 1][col - 1] + cost);
46
+ }
47
+ }
48
+ return matrix[a.length][b.length];
49
+ }
50
+ //# sourceMappingURL=typosquat.js.map