@nikhil_telkar/codeshield 0.0.0-stage → 0.1.1

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 (103) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +239 -2
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +237 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/engine/fileWalker.d.ts +15 -0
  8. package/dist/engine/fileWalker.d.ts.map +1 -0
  9. package/dist/engine/fileWalker.js +170 -0
  10. package/dist/engine/fileWalker.js.map +1 -0
  11. package/dist/engine/index.d.ts +4 -0
  12. package/dist/engine/index.d.ts.map +1 -0
  13. package/dist/engine/index.js +4 -0
  14. package/dist/engine/index.js.map +1 -0
  15. package/dist/engine/projectDetector.d.ts +10 -0
  16. package/dist/engine/projectDetector.d.ts.map +1 -0
  17. package/dist/engine/projectDetector.js +44 -0
  18. package/dist/engine/projectDetector.js.map +1 -0
  19. package/dist/engine/runner.d.ts +8 -0
  20. package/dist/engine/runner.d.ts.map +1 -0
  21. package/dist/engine/runner.js +87 -0
  22. package/dist/engine/runner.js.map +1 -0
  23. package/dist/fix/fixer.d.ts +17 -0
  24. package/dist/fix/fixer.d.ts.map +1 -0
  25. package/dist/fix/fixer.js +190 -0
  26. package/dist/fix/fixer.js.map +1 -0
  27. package/dist/fix/history.d.ts +23 -0
  28. package/dist/fix/history.d.ts.map +1 -0
  29. package/dist/fix/history.js +107 -0
  30. package/dist/fix/history.js.map +1 -0
  31. package/dist/fix/index.d.ts +3 -0
  32. package/dist/fix/index.d.ts.map +1 -0
  33. package/dist/fix/index.js +3 -0
  34. package/dist/fix/index.js.map +1 -0
  35. package/dist/index.d.ts +8 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +8 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/report/colors.d.ts +21 -0
  40. package/dist/report/colors.d.ts.map +1 -0
  41. package/dist/report/colors.js +70 -0
  42. package/dist/report/colors.js.map +1 -0
  43. package/dist/report/index.d.ts +15 -0
  44. package/dist/report/index.d.ts.map +1 -0
  45. package/dist/report/index.js +39 -0
  46. package/dist/report/index.js.map +1 -0
  47. package/dist/report/sarif.d.ts +44 -0
  48. package/dist/report/sarif.d.ts.map +1 -0
  49. package/dist/report/sarif.js +69 -0
  50. package/dist/report/sarif.js.map +1 -0
  51. package/dist/report/score.d.ts +14 -0
  52. package/dist/report/score.d.ts.map +1 -0
  53. package/dist/report/score.js +62 -0
  54. package/dist/report/score.js.map +1 -0
  55. package/dist/report/terminal.d.ts +10 -0
  56. package/dist/report/terminal.d.ts.map +1 -0
  57. package/dist/report/terminal.js +77 -0
  58. package/dist/report/terminal.js.map +1 -0
  59. package/dist/scanners/code.d.ts +22 -0
  60. package/dist/scanners/code.d.ts.map +1 -0
  61. package/dist/scanners/code.js +319 -0
  62. package/dist/scanners/code.js.map +1 -0
  63. package/dist/scanners/dependencies.d.ts +10 -0
  64. package/dist/scanners/dependencies.d.ts.map +1 -0
  65. package/dist/scanners/dependencies.js +240 -0
  66. package/dist/scanners/dependencies.js.map +1 -0
  67. package/dist/scanners/env.d.ts +7 -0
  68. package/dist/scanners/env.d.ts.map +1 -0
  69. package/dist/scanners/env.js +195 -0
  70. package/dist/scanners/env.js.map +1 -0
  71. package/dist/scanners/helper.d.ts +27 -0
  72. package/dist/scanners/helper.d.ts.map +1 -0
  73. package/dist/scanners/helper.js +50 -0
  74. package/dist/scanners/helper.js.map +1 -0
  75. package/dist/scanners/index.d.ts +6 -0
  76. package/dist/scanners/index.d.ts.map +1 -0
  77. package/dist/scanners/index.js +6 -0
  78. package/dist/scanners/index.js.map +1 -0
  79. package/dist/scanners/secrets.d.ts +19 -0
  80. package/dist/scanners/secrets.d.ts.map +1 -0
  81. package/dist/scanners/secrets.js +213 -0
  82. package/dist/scanners/secrets.js.map +1 -0
  83. package/dist/types.d.ts +43 -0
  84. package/dist/types.d.ts.map +1 -0
  85. package/dist/types.js +2 -0
  86. package/dist/types.js.map +1 -0
  87. package/dist/utils/constants.d.ts +9 -0
  88. package/dist/utils/constants.d.ts.map +1 -0
  89. package/dist/utils/constants.js +54 -0
  90. package/dist/utils/constants.js.map +1 -0
  91. package/dist/utils/levenshtein.d.ts +2 -0
  92. package/dist/utils/levenshtein.d.ts.map +1 -0
  93. package/dist/utils/levenshtein.js +35 -0
  94. package/dist/utils/levenshtein.js.map +1 -0
  95. package/dist/utils/registry.d.ts +18 -0
  96. package/dist/utils/registry.d.ts.map +1 -0
  97. package/dist/utils/registry.js +106 -0
  98. package/dist/utils/registry.js.map +1 -0
  99. package/dist/utils/sanitize.d.ts +3 -0
  100. package/dist/utils/sanitize.d.ts.map +1 -0
  101. package/dist/utils/sanitize.js +10 -0
  102. package/dist/utils/sanitize.js.map +1 -0
  103. package/package.json +59 -4
@@ -0,0 +1,170 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { BINARY_EXTENSIONS, MAX_FILE_BYTES, MAX_FILE_COUNT, SKIP_DIRS, TEXT_EXTENSIONS, } from '../utils/constants.js';
4
+ export function walkFiles(root, options = {}) {
5
+ const resolvedRoot = path.resolve(root);
6
+ let canonicalRoot;
7
+ try {
8
+ canonicalRoot = fs.realpathSync(resolvedRoot);
9
+ }
10
+ catch {
11
+ canonicalRoot = resolvedRoot;
12
+ }
13
+ const maxFiles = options.maxFiles ?? MAX_FILE_COUNT;
14
+ const maxBytes = options.maxBytes ?? MAX_FILE_BYTES;
15
+ const onSkip = options.onSkip;
16
+ const files = [];
17
+ let filesVisited = 0;
18
+ let filesSkipped = 0;
19
+ let truncated = false;
20
+ let rootStat;
21
+ try {
22
+ rootStat = fs.statSync(resolvedRoot);
23
+ }
24
+ catch {
25
+ return { files: [], filesVisited: 0, filesSkipped: 1, truncated: false };
26
+ }
27
+ if (rootStat.isFile()) {
28
+ const ext = path.extname(resolvedRoot).toLowerCase();
29
+ const fileName = path.basename(resolvedRoot);
30
+ const isKnownDotfile = fileName === '.gitignore' || fileName === '.env' || fileName.startsWith('.env.');
31
+ if (BINARY_EXTENSIONS.has(ext)) {
32
+ onSkip?.(resolvedRoot, 'binary extension');
33
+ return { files: [], filesVisited: 0, filesSkipped: 1, truncated: false };
34
+ }
35
+ if (!isKnownDotfile && ext !== '' && !TEXT_EXTENSIONS.has(ext)) {
36
+ onSkip?.(resolvedRoot, `unknown extension (${ext})`);
37
+ return { files: [], filesVisited: 0, filesSkipped: 1, truncated: false };
38
+ }
39
+ if (rootStat.size > maxBytes) {
40
+ onSkip?.(resolvedRoot, 'file too large');
41
+ return { files: [], filesVisited: 0, filesSkipped: 1, truncated: false };
42
+ }
43
+ try {
44
+ const content = fs.readFileSync(resolvedRoot, 'utf8');
45
+ const lines = content.split(/\r?\n/);
46
+ return {
47
+ files: [{ path: resolvedRoot, relativePath: path.basename(resolvedRoot), content, lines }],
48
+ filesVisited: 1,
49
+ filesSkipped: 0,
50
+ truncated: false,
51
+ };
52
+ }
53
+ catch {
54
+ return { files: [], filesVisited: 0, filesSkipped: 1, truncated: false };
55
+ }
56
+ }
57
+ function recurse(dir) {
58
+ if (truncated)
59
+ return;
60
+ let entries;
61
+ try {
62
+ entries = fs.readdirSync(dir, { withFileTypes: true });
63
+ }
64
+ catch {
65
+ onSkip?.(dir, 'unreadable directory');
66
+ filesSkipped++;
67
+ return;
68
+ }
69
+ for (const entry of entries) {
70
+ if (truncated)
71
+ return;
72
+ const fullPath = path.join(dir, entry.name);
73
+ if (entry.isSymbolicLink()) {
74
+ let realTarget;
75
+ try {
76
+ realTarget = fs.realpathSync(fullPath);
77
+ }
78
+ catch {
79
+ onSkip?.(fullPath, 'broken symlink');
80
+ filesSkipped++;
81
+ continue;
82
+ }
83
+ const escapes = (!realTarget.startsWith(resolvedRoot + path.sep) && realTarget !== resolvedRoot) &&
84
+ (!realTarget.startsWith(canonicalRoot + path.sep) && realTarget !== canonicalRoot);
85
+ if (escapes) {
86
+ onSkip?.(fullPath, 'symlink escapes scan root');
87
+ filesSkipped++;
88
+ continue;
89
+ }
90
+ let targetStat;
91
+ try {
92
+ targetStat = fs.statSync(realTarget);
93
+ }
94
+ catch {
95
+ filesSkipped++;
96
+ continue;
97
+ }
98
+ if (targetStat.isDirectory()) {
99
+ onSkip?.(fullPath, 'symlink to directory (skipped to avoid cycle)');
100
+ filesSkipped++;
101
+ continue;
102
+ }
103
+ }
104
+ if (entry.isDirectory()) {
105
+ if (SKIP_DIRS.has(entry.name)) {
106
+ onSkip?.(fullPath, `skipped directory (${entry.name})`);
107
+ filesSkipped++;
108
+ continue;
109
+ }
110
+ recurse(fullPath);
111
+ continue;
112
+ }
113
+ if (!entry.isFile() && !entry.isSymbolicLink()) {
114
+ onSkip?.(fullPath, 'non-regular file');
115
+ filesSkipped++;
116
+ continue;
117
+ }
118
+ const ext = path.extname(entry.name).toLowerCase();
119
+ if (BINARY_EXTENSIONS.has(ext)) {
120
+ onSkip?.(fullPath, 'binary extension');
121
+ filesSkipped++;
122
+ continue;
123
+ }
124
+ const isKnownDotfile = entry.name === '.gitignore' || entry.name === '.env' || entry.name.startsWith('.env.');
125
+ if (!isKnownDotfile && ext !== '' && !TEXT_EXTENSIONS.has(ext)) {
126
+ onSkip?.(fullPath, `unknown extension (${ext})`);
127
+ filesSkipped++;
128
+ continue;
129
+ }
130
+ let stat;
131
+ try {
132
+ stat = fs.statSync(fullPath);
133
+ }
134
+ catch {
135
+ onSkip?.(fullPath, 'stat failed');
136
+ filesSkipped++;
137
+ continue;
138
+ }
139
+ if (stat.size > maxBytes) {
140
+ onSkip?.(fullPath, `file exceeds size limit (${stat.size} bytes)`);
141
+ filesSkipped++;
142
+ continue;
143
+ }
144
+ if (filesVisited >= maxFiles) {
145
+ truncated = true;
146
+ return;
147
+ }
148
+ let content;
149
+ try {
150
+ content = fs.readFileSync(fullPath, 'utf8');
151
+ }
152
+ catch {
153
+ onSkip?.(fullPath, 'read error');
154
+ filesSkipped++;
155
+ continue;
156
+ }
157
+ filesVisited++;
158
+ const relativePath = path.relative(resolvedRoot, fullPath);
159
+ files.push({
160
+ path: fullPath,
161
+ relativePath,
162
+ content,
163
+ lines: content.split(/\r?\n/),
164
+ });
165
+ }
166
+ }
167
+ recurse(resolvedRoot);
168
+ return { files, filesVisited, filesSkipped, truncated };
169
+ }
170
+ //# sourceMappingURL=fileWalker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileWalker.js","sourceRoot":"","sources":["../../src/engine/fileWalker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from './fileWalker.js';
2
+ export * from './projectDetector.js';
3
+ export * from './runner.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './fileWalker.js';
2
+ export * from './projectDetector.js';
3
+ export * from './runner.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { ProjectType } from '../types.js';
2
+ interface PackageJsonStructure {
3
+ dependencies?: Record<string, string>;
4
+ devDependencies?: Record<string, string>;
5
+ scripts?: Record<string, string>;
6
+ }
7
+ export declare function readPackageJson(root: string): PackageJsonStructure | null;
8
+ export declare function detectProjectType(root: string, existingFilePaths?: string[]): ProjectType;
9
+ export {};
10
+ //# sourceMappingURL=projectDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectDetector.d.ts","sourceRoot":"","sources":["../../src/engine/projectDetector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,UAAU,oBAAoB;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CASzE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,GAAG,WAAW,CAiCzF"}
@@ -0,0 +1,44 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ export function readPackageJson(root) {
4
+ const pkgPath = path.join(root, 'package.json');
5
+ try {
6
+ if (!fs.existsSync(pkgPath))
7
+ return null;
8
+ const raw = fs.readFileSync(pkgPath, 'utf8');
9
+ return JSON.parse(raw);
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ export function detectProjectType(root, existingFilePaths) {
16
+ const resolvedRoot = path.resolve(root);
17
+ const pkg = readPackageJson(resolvedRoot);
18
+ const deps = pkg?.dependencies ?? {};
19
+ const devDeps = pkg?.devDependencies ?? {};
20
+ const allDeps = { ...deps, ...devDeps };
21
+ if ('next' in allDeps)
22
+ return 'nextjs';
23
+ const nextConfigExists = ['next.config.js', 'next.config.mjs', 'next.config.ts'].some(cfg => fs.existsSync(path.join(resolvedRoot, cfg)));
24
+ if (nextConfigExists)
25
+ return 'nextjs';
26
+ const hasVite = 'vite' in allDeps ||
27
+ fs.existsSync(path.join(resolvedRoot, 'vite.config.js')) ||
28
+ fs.existsSync(path.join(resolvedRoot, 'vite.config.ts')) ||
29
+ fs.existsSync(path.join(resolvedRoot, 'vite.config.mjs'));
30
+ const hasReact = 'react' in allDeps;
31
+ if (hasVite && hasReact)
32
+ return 'vite-react';
33
+ if ('express' in deps)
34
+ return 'express';
35
+ const indexHtmlRoot = fs.existsSync(path.join(resolvedRoot, 'index.html'));
36
+ const indexHtmlPublic = fs.existsSync(path.join(resolvedRoot, 'public', 'index.html'));
37
+ if (indexHtmlRoot || indexHtmlPublic) {
38
+ const hasFrameworkDeps = ['vue', 'angular', 'svelte', '@angular/core'].some(d => d in allDeps);
39
+ if (!hasFrameworkDeps && !hasVite)
40
+ return 'plain-html';
41
+ }
42
+ return 'unknown';
43
+ }
44
+ //# sourceMappingURL=projectDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectDetector.js","sourceRoot":"","sources":["../../src/engine/projectDetector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AASlC,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,iBAA4B;IAC1E,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,eAAe,CAAC,YAAY,CAAC,CAAC;IAE1C,MAAM,IAAI,GAAG,GAAG,EAAE,YAAY,IAAI,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,GAAG,EAAE,eAAe,IAAI,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC;IAExC,IAAI,MAAM,IAAI,OAAO;QAAE,OAAO,QAAQ,CAAC;IAEvC,MAAM,gBAAgB,GAAG,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAC1F,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAC5C,CAAC;IACF,IAAI,gBAAgB;QAAE,OAAO,QAAQ,CAAC;IAEtC,MAAM,OAAO,GAAG,MAAM,IAAI,OAAO;QAC/B,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;QACxD,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;QACxD,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,OAAO,IAAI,OAAO,CAAC;IAEpC,IAAI,OAAO,IAAI,QAAQ;QAAE,OAAO,YAAY,CAAC;IAE7C,IAAI,SAAS,IAAI,IAAI;QAAE,OAAO,SAAS,CAAC;IAExC,MAAM,aAAa,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;IAC3E,MAAM,eAAe,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IACvF,IAAI,aAAa,IAAI,eAAe,EAAE,CAAC;QACrC,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC;QAC/F,IAAI,CAAC,gBAAgB,IAAI,CAAC,OAAO;YAAE,OAAO,YAAY,CAAC;IACzD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { RunnerOptions, ScanResult } from '../types.js';
2
+ import { type DepScanOptions } from '../scanners/dependencies.js';
3
+ export interface AsyncRunnerOptions extends RunnerOptions {
4
+ depOptions?: DepScanOptions;
5
+ }
6
+ export declare function runScan(options: RunnerOptions): ScanResult;
7
+ export declare function runScanAsync(options: AsyncRunnerOptions): Promise<ScanResult>;
8
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/engine/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,aAAa,EAAe,UAAU,EAAY,MAAM,aAAa,CAAC;AAIxF,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAEpF,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,UAAU,CAAC,EAAE,cAAc,CAAC;CAC7B;AAgCD,wBAAgB,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,UAAU,CA2B1D;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAmCnF"}
@@ -0,0 +1,87 @@
1
+ import { SEVERITY_RANK } from '../utils/constants.js';
2
+ import { walkFiles } from './fileWalker.js';
3
+ import { detectProjectType } from './projectDetector.js';
4
+ import { scanDependencies } from '../scanners/dependencies.js';
5
+ function finalizeFindings(findings, minRank) {
6
+ const filtered = findings.filter((f) => (SEVERITY_RANK[f.severity] ?? 0) >= minRank);
7
+ filtered.sort((a, b) => {
8
+ const rankDiff = (SEVERITY_RANK[b.severity] ?? 0) - (SEVERITY_RANK[a.severity] ?? 0);
9
+ if (rankDiff !== 0)
10
+ return rankDiff;
11
+ const fileDiff = a.file.localeCompare(b.file);
12
+ if (fileDiff !== 0)
13
+ return fileDiff;
14
+ return a.line - b.line;
15
+ });
16
+ return filtered;
17
+ }
18
+ function buildContext(options) {
19
+ const projectType = detectProjectType(options.root);
20
+ const walkResult = walkFiles(options.root);
21
+ const context = {
22
+ root: options.root,
23
+ projectType,
24
+ files: walkResult.files,
25
+ };
26
+ return { context, walkResult };
27
+ }
28
+ export function runScan(options) {
29
+ const startTime = Date.now();
30
+ const minSeverity = options.minSeverity ?? 'info';
31
+ const minRank = SEVERITY_RANK[minSeverity] ?? 0;
32
+ const { context, walkResult } = buildContext(options);
33
+ const findings = [];
34
+ for (const scanner of options.scanners ?? []) {
35
+ try {
36
+ const scannerFindings = scanner.scan(context);
37
+ if (Array.isArray(scannerFindings)) {
38
+ findings.push(...scannerFindings);
39
+ }
40
+ }
41
+ catch {
42
+ // scanner error handled gracefully
43
+ }
44
+ }
45
+ return {
46
+ projectType: context.projectType,
47
+ findings: finalizeFindings(findings, minRank),
48
+ filesScanned: walkResult.filesVisited,
49
+ filesSkipped: walkResult.filesSkipped,
50
+ truncated: walkResult.truncated,
51
+ durationMs: Date.now() - startTime,
52
+ };
53
+ }
54
+ export async function runScanAsync(options) {
55
+ const startTime = Date.now();
56
+ const minSeverity = options.minSeverity ?? 'info';
57
+ const minRank = SEVERITY_RANK[minSeverity] ?? 0;
58
+ const { context, walkResult } = buildContext(options);
59
+ const findings = [];
60
+ for (const scanner of options.scanners ?? []) {
61
+ try {
62
+ const scannerFindings = scanner.scan(context);
63
+ if (Array.isArray(scannerFindings)) {
64
+ findings.push(...scannerFindings);
65
+ }
66
+ }
67
+ catch {
68
+ // scanner error handled gracefully
69
+ }
70
+ }
71
+ try {
72
+ const depFindings = await scanDependencies(context, options.depOptions ?? {});
73
+ findings.push(...depFindings);
74
+ }
75
+ catch {
76
+ // dependency scanner failure must never crash the tool
77
+ }
78
+ return {
79
+ projectType: context.projectType,
80
+ findings: finalizeFindings(findings, minRank),
81
+ filesScanned: walkResult.filesVisited,
82
+ filesSkipped: walkResult.filesSkipped,
83
+ truncated: walkResult.truncated,
84
+ durationMs: Date.now() - startTime,
85
+ };
86
+ }
87
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/engine/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface PlannedFix {
2
+ id: string;
3
+ title: string;
4
+ filePath: string;
5
+ relativePath: string;
6
+ isCreation: boolean;
7
+ backupPath?: string;
8
+ diffLines: string[];
9
+ apply: () => void;
10
+ }
11
+ export declare function resolveSafePath(root: string, relativePath: string): string;
12
+ export declare function generateEnvExampleContent(envContent: string): string;
13
+ export declare function planFixes(root: string): PlannedFix[];
14
+ export declare function formatFixDiff(fixes: PlannedFix[]): string;
15
+ export declare function promptConfirmation(question: string): Promise<boolean>;
16
+ export declare function runFix(root: string, autoConfirm?: boolean): Promise<number>;
17
+ //# sourceMappingURL=fixer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixer.d.ts","sourceRoot":"","sources":["../../src/fix/fixer.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAW1E;AAED,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAmCpE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAuFpD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAsBzD;AAED,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAa3E;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CA0C/E"}
@@ -0,0 +1,190 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import * as readline from 'node:readline';
4
+ import { isEnvIgnoredByGitignore } from '../scanners/env.js';
5
+ import { sanitize } from '../utils/sanitize.js';
6
+ export function resolveSafePath(root, relativePath) {
7
+ const resolvedRoot = path.resolve(root);
8
+ const resolvedTarget = path.resolve(resolvedRoot, relativePath);
9
+ if (resolvedTarget !== resolvedRoot && !resolvedTarget.startsWith(resolvedRoot + path.sep)) {
10
+ throw new Error(`Path traversal attempt rejected: "${sanitize(relativePath)}" is outside the scan root "${sanitize(root)}"`);
11
+ }
12
+ return resolvedTarget;
13
+ }
14
+ export function generateEnvExampleContent(envContent) {
15
+ const lines = envContent.split('\n');
16
+ const result = [
17
+ '# .env.example — generated by CodeShield',
18
+ '# Replace with your actual credentials in .env (never commit .env)',
19
+ '',
20
+ ];
21
+ const SENSITIVE_KEY_RE = /(?:key|secret|token|password|passwd|pwd|auth|credential|salt|nonce|hash|private|jwt|database_url|db_url)/i;
22
+ for (const line of lines) {
23
+ const trimmed = line.trim();
24
+ if (trimmed.length === 0 || trimmed.startsWith('#')) {
25
+ result.push(line);
26
+ continue;
27
+ }
28
+ const eqIdx = line.indexOf('=');
29
+ if (eqIdx === -1) {
30
+ result.push(line);
31
+ continue;
32
+ }
33
+ const key = line.slice(0, eqIdx).trim();
34
+ const rawVal = line.slice(eqIdx + 1).trim();
35
+ if (SENSITIVE_KEY_RE.test(key) || rawVal.length > 20) {
36
+ const placeholder = `your_${key.toLowerCase()}_here`;
37
+ result.push(`${key}=${placeholder}`);
38
+ }
39
+ else {
40
+ result.push(line);
41
+ }
42
+ }
43
+ return result.join('\n') + '\n';
44
+ }
45
+ export function planFixes(root) {
46
+ const safeRoot = path.resolve(root);
47
+ const fixes = [];
48
+ const envPath = resolveSafePath(safeRoot, '.env');
49
+ const envExists = fs.existsSync(envPath);
50
+ const gitignorePath = resolveSafePath(safeRoot, '.gitignore');
51
+ const gitignoreExists = fs.existsSync(gitignorePath);
52
+ let gitignoreNeedsEnv = false;
53
+ let gitignoreNeedsCodeshield = false;
54
+ if (gitignoreExists) {
55
+ const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
56
+ gitignoreNeedsEnv = envExists && !isEnvIgnoredByGitignore('.env', gitignoreContent);
57
+ gitignoreNeedsCodeshield = !gitignoreContent.includes('.codeshield');
58
+ }
59
+ else if (envExists) {
60
+ gitignoreNeedsEnv = true;
61
+ gitignoreNeedsCodeshield = true;
62
+ }
63
+ if (gitignoreNeedsEnv || gitignoreNeedsCodeshield) {
64
+ const linesToAdd = [];
65
+ if (gitignoreNeedsEnv) {
66
+ linesToAdd.push('# CodeShield: Ignore local environment credentials', '.env', '.env.local', '.env.*.local');
67
+ }
68
+ if (gitignoreNeedsCodeshield) {
69
+ linesToAdd.push('# CodeShield: Ignore local scan history cache', '.codeshield/');
70
+ }
71
+ const diffLines = linesToAdd.map(l => `+ ${l}`);
72
+ const backupPath = gitignoreExists ? `${gitignorePath}.codeshield.bak` : undefined;
73
+ fixes.push({
74
+ id: 'FIX-GITIGNORE',
75
+ title: gitignoreExists
76
+ ? 'Add .env and .codeshield/ to .gitignore'
77
+ : 'Create .gitignore with .env and .codeshield/',
78
+ filePath: gitignorePath,
79
+ relativePath: '.gitignore',
80
+ isCreation: !gitignoreExists,
81
+ ...(backupPath ? { backupPath } : {}),
82
+ diffLines,
83
+ apply: () => {
84
+ if (gitignoreExists) {
85
+ fs.copyFileSync(gitignorePath, backupPath);
86
+ const current = fs.readFileSync(gitignorePath, 'utf8');
87
+ const prefix = current.endsWith('\n') || current.length === 0 ? '' : '\n';
88
+ fs.appendFileSync(gitignorePath, prefix + linesToAdd.join('\n') + '\n', 'utf8');
89
+ }
90
+ else {
91
+ fs.writeFileSync(gitignorePath, linesToAdd.join('\n') + '\n', 'utf8');
92
+ }
93
+ },
94
+ });
95
+ }
96
+ const envExamplePath = resolveSafePath(safeRoot, '.env.example');
97
+ const envExampleExists = fs.existsSync(envExamplePath);
98
+ if (envExists && !envExampleExists) {
99
+ const envContent = fs.readFileSync(envPath, 'utf8');
100
+ const exampleContent = generateEnvExampleContent(envContent);
101
+ const diffLines = exampleContent.trim().split('\n').map(l => `+ ${l}`);
102
+ fixes.push({
103
+ id: 'FIX-ENV-EXAMPLE',
104
+ title: 'Create .env.example template from .env',
105
+ filePath: envExamplePath,
106
+ relativePath: '.env.example',
107
+ isCreation: true,
108
+ diffLines,
109
+ apply: () => {
110
+ fs.writeFileSync(envExamplePath, exampleContent, 'utf8');
111
+ },
112
+ });
113
+ }
114
+ return fixes;
115
+ }
116
+ export function formatFixDiff(fixes) {
117
+ const lines = [
118
+ '\nCodeShield Fix Plan:',
119
+ '────────────────────────────────────────────────────────────',
120
+ ];
121
+ for (let i = 0; i < fixes.length; i++) {
122
+ const fix = fixes[i];
123
+ lines.push(`[${i + 1}] ${fix.title}`);
124
+ lines.push(` Target : ${fix.relativePath}`);
125
+ if (fix.backupPath) {
126
+ lines.push(` Backup : ${path.basename(fix.backupPath)}`);
127
+ }
128
+ lines.push(' Changes:');
129
+ for (const d of fix.diffLines) {
130
+ lines.push(` ${d}`);
131
+ }
132
+ lines.push('');
133
+ }
134
+ lines.push('────────────────────────────────────────────────────────────');
135
+ return lines.join('\n');
136
+ }
137
+ export async function promptConfirmation(question) {
138
+ const rl = readline.createInterface({
139
+ input: process.stdin,
140
+ output: process.stdout,
141
+ });
142
+ return new Promise((resolve) => {
143
+ rl.question(question, (answer) => {
144
+ rl.close();
145
+ const trimmed = answer.trim().toLowerCase();
146
+ resolve(trimmed === 'y' || trimmed === 'yes');
147
+ });
148
+ });
149
+ }
150
+ export async function runFix(root, autoConfirm = false) {
151
+ const safeRoot = path.resolve(root);
152
+ let fixes;
153
+ try {
154
+ fixes = planFixes(safeRoot);
155
+ }
156
+ catch (err) {
157
+ const msg = err instanceof Error ? err.message : String(err);
158
+ console.error(`Error planning fixes: ${sanitize(msg)}`);
159
+ return 2;
160
+ }
161
+ if (fixes.length === 0) {
162
+ console.log('\n✅ No automatic fixes needed. Codebase looks clean!');
163
+ return 0;
164
+ }
165
+ console.log(formatFixDiff(fixes));
166
+ if (!autoConfirm) {
167
+ const confirmed = await promptConfirmation('Apply these changes? [y/N]: ');
168
+ if (!confirmed) {
169
+ console.log('\nOperation cancelled. No files were modified.');
170
+ return 0;
171
+ }
172
+ }
173
+ try {
174
+ for (const fix of fixes) {
175
+ fix.apply();
176
+ console.log(`✅ Applied: ${fix.title}`);
177
+ if (fix.backupPath) {
178
+ console.log(` (Backup created at ${path.basename(fix.backupPath)})`);
179
+ }
180
+ }
181
+ console.log(`\n🎉 Successfully applied ${fixes.length} fix${fixes.length === 1 ? '' : 'es'}.\n`);
182
+ return 0;
183
+ }
184
+ catch (err) {
185
+ const msg = err instanceof Error ? err.message : String(err);
186
+ console.error(`Error applying fixes: ${sanitize(msg)}`);
187
+ return 2;
188
+ }
189
+ }
190
+ //# sourceMappingURL=fixer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixer.js","sourceRoot":"","sources":["../../src/fix/fixer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { Finding } from '../types.js';
2
+ export interface ScanSnapshot {
3
+ timestamp: number;
4
+ score: number;
5
+ grade: string;
6
+ findingsCount: number;
7
+ findingFingerprints: string[];
8
+ }
9
+ export interface HistoryComparison {
10
+ previousScore: number;
11
+ currentScore: number;
12
+ scoreDiff: number;
13
+ fixedCount: number;
14
+ newCount: number;
15
+ summaryText: string;
16
+ }
17
+ export declare function getFindingFingerprint(f: Finding): string;
18
+ export declare function getHistoryFilePath(root: string): string;
19
+ export declare function readLastScan(root: string): ScanSnapshot | null;
20
+ export declare function saveLastScan(root: string, score: number, grade: string, findings: readonly Finding[]): void;
21
+ export declare function ensureCodeshieldInGitignore(root: string): void;
22
+ export declare function compareWithLastScan(previous: ScanSnapshot, currentScore: number, currentFindings: readonly Finding[]): HistoryComparison;
23
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/fix/history.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAExD;AAKD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAa9D;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,OAAO,EAAE,GAC3B,IAAI,CAsBN;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAgB9D;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,EACtB,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,SAAS,OAAO,EAAE,GAClC,iBAAiB,CA4CnB"}