@nikhil_telkar/codeshield 0.0.0-stage → 0.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/LICENSE +22 -0
- package/README.md +289 -2
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +237 -0
- package/dist/cli.js.map +1 -0
- package/dist/engine/fileWalker.d.ts +15 -0
- package/dist/engine/fileWalker.d.ts.map +1 -0
- package/dist/engine/fileWalker.js +170 -0
- package/dist/engine/fileWalker.js.map +1 -0
- package/dist/engine/index.d.ts +4 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +4 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/projectDetector.d.ts +10 -0
- package/dist/engine/projectDetector.d.ts.map +1 -0
- package/dist/engine/projectDetector.js +44 -0
- package/dist/engine/projectDetector.js.map +1 -0
- package/dist/engine/runner.d.ts +8 -0
- package/dist/engine/runner.d.ts.map +1 -0
- package/dist/engine/runner.js +87 -0
- package/dist/engine/runner.js.map +1 -0
- package/dist/fix/fixer.d.ts +17 -0
- package/dist/fix/fixer.d.ts.map +1 -0
- package/dist/fix/fixer.js +190 -0
- package/dist/fix/fixer.js.map +1 -0
- package/dist/fix/history.d.ts +23 -0
- package/dist/fix/history.d.ts.map +1 -0
- package/dist/fix/history.js +107 -0
- package/dist/fix/history.js.map +1 -0
- package/dist/fix/index.d.ts +3 -0
- package/dist/fix/index.d.ts.map +1 -0
- package/dist/fix/index.js +3 -0
- package/dist/fix/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/report/colors.d.ts +21 -0
- package/dist/report/colors.d.ts.map +1 -0
- package/dist/report/colors.js +70 -0
- package/dist/report/colors.js.map +1 -0
- package/dist/report/index.d.ts +15 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +39 -0
- package/dist/report/index.js.map +1 -0
- package/dist/report/sarif.d.ts +44 -0
- package/dist/report/sarif.d.ts.map +1 -0
- package/dist/report/sarif.js +69 -0
- package/dist/report/sarif.js.map +1 -0
- package/dist/report/score.d.ts +14 -0
- package/dist/report/score.d.ts.map +1 -0
- package/dist/report/score.js +62 -0
- package/dist/report/score.js.map +1 -0
- package/dist/report/terminal.d.ts +10 -0
- package/dist/report/terminal.d.ts.map +1 -0
- package/dist/report/terminal.js +77 -0
- package/dist/report/terminal.js.map +1 -0
- package/dist/scanners/code.d.ts +22 -0
- package/dist/scanners/code.d.ts.map +1 -0
- package/dist/scanners/code.js +319 -0
- package/dist/scanners/code.js.map +1 -0
- package/dist/scanners/dependencies.d.ts +10 -0
- package/dist/scanners/dependencies.d.ts.map +1 -0
- package/dist/scanners/dependencies.js +240 -0
- package/dist/scanners/dependencies.js.map +1 -0
- package/dist/scanners/env.d.ts +7 -0
- package/dist/scanners/env.d.ts.map +1 -0
- package/dist/scanners/env.js +195 -0
- package/dist/scanners/env.js.map +1 -0
- package/dist/scanners/helper.d.ts +27 -0
- package/dist/scanners/helper.d.ts.map +1 -0
- package/dist/scanners/helper.js +50 -0
- package/dist/scanners/helper.js.map +1 -0
- package/dist/scanners/index.d.ts +6 -0
- package/dist/scanners/index.d.ts.map +1 -0
- package/dist/scanners/index.js +6 -0
- package/dist/scanners/index.js.map +1 -0
- package/dist/scanners/secrets.d.ts +19 -0
- package/dist/scanners/secrets.d.ts.map +1 -0
- package/dist/scanners/secrets.js +213 -0
- package/dist/scanners/secrets.js.map +1 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/constants.d.ts +9 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +54 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/levenshtein.d.ts +2 -0
- package/dist/utils/levenshtein.d.ts.map +1 -0
- package/dist/utils/levenshtein.js +35 -0
- package/dist/utils/levenshtein.js.map +1 -0
- package/dist/utils/registry.d.ts +18 -0
- package/dist/utils/registry.d.ts.map +1 -0
- package/dist/utils/registry.js +106 -0
- package/dist/utils/registry.js.map +1 -0
- package/dist/utils/sanitize.d.ts +3 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +10 -0
- package/dist/utils/sanitize.js.map +1 -0
- package/package.json +56 -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 @@
|
|
|
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 @@
|
|
|
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"}
|