@oops-catcher/core 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/dist/config/loader.d.ts +5 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +37 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +117 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +54 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/engine/fingerprint.d.ts +2 -0
- package/dist/engine/fingerprint.d.ts.map +1 -0
- package/dist/engine/fingerprint.js +5 -0
- package/dist/engine/fingerprint.js.map +1 -0
- package/dist/engine/line.d.ts +2 -0
- package/dist/engine/line.d.ts.map +1 -0
- package/dist/engine/line.js +11 -0
- package/dist/engine/line.js.map +1 -0
- package/dist/engine/scan.d.ts +13 -0
- package/dist/engine/scan.d.ts.map +1 -0
- package/dist/engine/scan.js +57 -0
- package/dist/engine/scan.js.map +1 -0
- package/dist/engine/walker.d.ts +8 -0
- package/dist/engine/walker.d.ts.map +1 -0
- package/dist/engine/walker.js +42 -0
- package/dist/engine/walker.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/output/formatters.d.ts +4 -0
- package/dist/output/formatters.d.ts.map +1 -0
- package/dist/output/formatters.js +35 -0
- package/dist/output/formatters.js.map +1 -0
- package/dist/output/redact.d.ts +4 -0
- package/dist/output/redact.d.ts.map +1 -0
- package/dist/output/redact.js +14 -0
- package/dist/output/redact.js.map +1 -0
- package/dist/rules/ai_artifacts_v1.d.ts +3 -0
- package/dist/rules/ai_artifacts_v1.d.ts.map +1 -0
- package/dist/rules/ai_artifacts_v1.js +76 -0
- package/dist/rules/ai_artifacts_v1.js.map +1 -0
- package/dist/rules/containers_v1.d.ts +3 -0
- package/dist/rules/containers_v1.d.ts.map +1 -0
- package/dist/rules/containers_v1.js +392 -0
- package/dist/rules/containers_v1.js.map +1 -0
- package/dist/rules/registry.d.ts +4 -0
- package/dist/rules/registry.d.ts.map +1 -0
- package/dist/rules/registry.js +12 -0
- package/dist/rules/registry.js.map +1 -0
- package/dist/rules/secrets_v1.d.ts +9 -0
- package/dist/rules/secrets_v1.d.ts.map +1 -0
- package/dist/rules/secrets_v1.js +283 -0
- package/dist/rules/secrets_v1.js.map +1 -0
- package/dist/rules/types.d.ts +19 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +2 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/types.d.ts +41 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { lineForIndex } from '../engine/line.js';
|
|
2
|
+
import { redactExcerpt } from '../output/redact.js';
|
|
3
|
+
import { stableFingerprint } from '../engine/fingerprint.js';
|
|
4
|
+
const PRIVATE_KEY_BLOCK = /-----BEGIN (RSA|EC|OPENSSH|PGP|DSA) PRIVATE KEY-----/g;
|
|
5
|
+
const GITHUB_TOKEN = /(ghp_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{22,})/g;
|
|
6
|
+
const AWS_ACCESS_KEY = /\b(AKIA[0-9A-Z]{16})\b/g;
|
|
7
|
+
const AWS_SECRET_KEY = /(?:aws[_\-.]?secret[_\-.]?(?:access[_\-.]?)?key|AWS_SECRET_ACCESS_KEY)\s*[=:]\s*["']?([A-Za-z0-9/+=]{40})["']?/gi;
|
|
8
|
+
const STRIPE_LIVE_KEY = /\b(sk_live_[0-9a-zA-Z]{24,})\b/g;
|
|
9
|
+
const SLACK_TOKEN = /\b(xox[aboprs]-[0-9A-Za-z\-]{10,})\b/g;
|
|
10
|
+
const HIGH_ENTROPY_STRING = /["']([A-Za-z0-9+/=_\-]{20,})["']/g;
|
|
11
|
+
const SECRETS_FILE_BASENAMES = new Set([
|
|
12
|
+
'.env',
|
|
13
|
+
'credentials.json',
|
|
14
|
+
'id_rsa',
|
|
15
|
+
'id_ed25519',
|
|
16
|
+
'id_ecdsa',
|
|
17
|
+
'id_dsa',
|
|
18
|
+
]);
|
|
19
|
+
function isSecretsFilePath(filePath) {
|
|
20
|
+
const base = filePath.split('/').pop() ?? filePath;
|
|
21
|
+
if (SECRETS_FILE_BASENAMES.has(base))
|
|
22
|
+
return true;
|
|
23
|
+
if (base.startsWith('.env.'))
|
|
24
|
+
return true;
|
|
25
|
+
if (base.endsWith('.pem'))
|
|
26
|
+
return true;
|
|
27
|
+
if (base.startsWith('secrets.'))
|
|
28
|
+
return true;
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
function shannonEntropy(s) {
|
|
32
|
+
const freq = {};
|
|
33
|
+
for (const c of s)
|
|
34
|
+
freq[c] = (freq[c] ?? 0) + 1;
|
|
35
|
+
const len = s.length;
|
|
36
|
+
return Object.values(freq).reduce((h, count) => {
|
|
37
|
+
const p = count / len;
|
|
38
|
+
return h - p * Math.log2(p);
|
|
39
|
+
}, 0);
|
|
40
|
+
}
|
|
41
|
+
function looksLikeUrl(s) {
|
|
42
|
+
return s.startsWith('http') || s.startsWith('ftp');
|
|
43
|
+
}
|
|
44
|
+
export const secretsV1Rules = [
|
|
45
|
+
{
|
|
46
|
+
id: 'SEC001',
|
|
47
|
+
title: 'Private key block detected',
|
|
48
|
+
defaultSeverity: 'critical',
|
|
49
|
+
appliesTo: () => true,
|
|
50
|
+
run: (ctx) => {
|
|
51
|
+
const findings = [];
|
|
52
|
+
for (const match of ctx.content.matchAll(PRIVATE_KEY_BLOCK)) {
|
|
53
|
+
const index = match.index ?? 0;
|
|
54
|
+
const line = lineForIndex(ctx.content, index);
|
|
55
|
+
const matched = match[0];
|
|
56
|
+
const redactedExcerpt = redactExcerpt(matched, ctx.config.output.redact);
|
|
57
|
+
findings.push({
|
|
58
|
+
ruleId: 'SEC001',
|
|
59
|
+
severity: 'critical',
|
|
60
|
+
path: ctx.path,
|
|
61
|
+
line,
|
|
62
|
+
message: 'Private key block detected',
|
|
63
|
+
why: 'Private keys should not be committed to source control.',
|
|
64
|
+
fix: 'Remove the key from the repo and rotate it immediately.',
|
|
65
|
+
redactedExcerpt,
|
|
66
|
+
fingerprint: stableFingerprint(`SEC001:${ctx.path}:${line}:${matched.slice(0, 16)}`),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return findings;
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: 'SEC002',
|
|
74
|
+
title: 'AWS credentials detected',
|
|
75
|
+
defaultSeverity: 'critical',
|
|
76
|
+
appliesTo: () => true,
|
|
77
|
+
run: (ctx) => {
|
|
78
|
+
const findings = [];
|
|
79
|
+
for (const match of ctx.content.matchAll(AWS_ACCESS_KEY)) {
|
|
80
|
+
const index = match.index ?? 0;
|
|
81
|
+
const line = lineForIndex(ctx.content, index);
|
|
82
|
+
const matched = match[1];
|
|
83
|
+
if (!matched)
|
|
84
|
+
continue;
|
|
85
|
+
findings.push({
|
|
86
|
+
ruleId: 'SEC002',
|
|
87
|
+
severity: 'critical',
|
|
88
|
+
path: ctx.path,
|
|
89
|
+
line,
|
|
90
|
+
message: 'AWS access key ID detected',
|
|
91
|
+
why: 'AWS access keys grant account access and must not be committed.',
|
|
92
|
+
fix: 'Remove the key and rotate it in the AWS console immediately.',
|
|
93
|
+
redactedExcerpt: redactExcerpt(matched, ctx.config.output.redact),
|
|
94
|
+
fingerprint: stableFingerprint(`SEC002:${ctx.path}:${line}:${matched.slice(0, 8)}`),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
for (const match of ctx.content.matchAll(AWS_SECRET_KEY)) {
|
|
98
|
+
const index = match.index ?? 0;
|
|
99
|
+
const line = lineForIndex(ctx.content, index);
|
|
100
|
+
const matched = match[1];
|
|
101
|
+
if (!matched)
|
|
102
|
+
continue;
|
|
103
|
+
findings.push({
|
|
104
|
+
ruleId: 'SEC002',
|
|
105
|
+
severity: 'critical',
|
|
106
|
+
path: ctx.path,
|
|
107
|
+
line,
|
|
108
|
+
message: 'AWS secret access key detected',
|
|
109
|
+
why: 'AWS secret keys grant full account access and must not be committed.',
|
|
110
|
+
fix: 'Remove the key and rotate it in the AWS console immediately.',
|
|
111
|
+
redactedExcerpt: redactExcerpt(matched, ctx.config.output.redact),
|
|
112
|
+
fingerprint: stableFingerprint(`SEC002:${ctx.path}:${line}:${matched.slice(0, 8)}`),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return findings;
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: 'SEC003',
|
|
120
|
+
title: 'GitHub token detected',
|
|
121
|
+
defaultSeverity: 'critical',
|
|
122
|
+
appliesTo: () => true,
|
|
123
|
+
run: (ctx) => {
|
|
124
|
+
const findings = [];
|
|
125
|
+
for (const match of ctx.content.matchAll(GITHUB_TOKEN)) {
|
|
126
|
+
const index = match.index ?? 0;
|
|
127
|
+
const line = lineForIndex(ctx.content, index);
|
|
128
|
+
const matched = match[0];
|
|
129
|
+
const redactedExcerpt = redactExcerpt(matched, ctx.config.output.redact);
|
|
130
|
+
findings.push({
|
|
131
|
+
ruleId: 'SEC003',
|
|
132
|
+
severity: 'critical',
|
|
133
|
+
path: ctx.path,
|
|
134
|
+
line,
|
|
135
|
+
message: 'GitHub token detected',
|
|
136
|
+
why: 'Tokens provide API access and should be stored in a secret manager.',
|
|
137
|
+
fix: 'Remove the token and rotate it in GitHub immediately.',
|
|
138
|
+
redactedExcerpt,
|
|
139
|
+
fingerprint: stableFingerprint(`SEC003:${ctx.path}:${line}:${matched.slice(0, 16)}`),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
return findings;
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
id: 'SEC004',
|
|
147
|
+
title: 'Stripe live secret key detected',
|
|
148
|
+
defaultSeverity: 'critical',
|
|
149
|
+
appliesTo: () => true,
|
|
150
|
+
run: (ctx) => {
|
|
151
|
+
const findings = [];
|
|
152
|
+
for (const match of ctx.content.matchAll(STRIPE_LIVE_KEY)) {
|
|
153
|
+
const index = match.index ?? 0;
|
|
154
|
+
const line = lineForIndex(ctx.content, index);
|
|
155
|
+
const matched = match[1];
|
|
156
|
+
if (!matched)
|
|
157
|
+
continue;
|
|
158
|
+
findings.push({
|
|
159
|
+
ruleId: 'SEC004',
|
|
160
|
+
severity: 'critical',
|
|
161
|
+
path: ctx.path,
|
|
162
|
+
line,
|
|
163
|
+
message: 'Stripe live secret key detected',
|
|
164
|
+
why: 'Live Stripe keys can charge real cards and must not be committed.',
|
|
165
|
+
fix: 'Remove the key and rotate it in the Stripe dashboard immediately.',
|
|
166
|
+
redactedExcerpt: redactExcerpt(matched, ctx.config.output.redact),
|
|
167
|
+
fingerprint: stableFingerprint(`SEC004:${ctx.path}:${line}:${matched.slice(0, 12)}`),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return findings;
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: 'SEC005',
|
|
175
|
+
title: 'Slack token detected',
|
|
176
|
+
defaultSeverity: 'critical',
|
|
177
|
+
appliesTo: () => true,
|
|
178
|
+
run: (ctx) => {
|
|
179
|
+
const findings = [];
|
|
180
|
+
for (const match of ctx.content.matchAll(SLACK_TOKEN)) {
|
|
181
|
+
const index = match.index ?? 0;
|
|
182
|
+
const line = lineForIndex(ctx.content, index);
|
|
183
|
+
const matched = match[1];
|
|
184
|
+
if (!matched)
|
|
185
|
+
continue;
|
|
186
|
+
findings.push({
|
|
187
|
+
ruleId: 'SEC005',
|
|
188
|
+
severity: 'critical',
|
|
189
|
+
path: ctx.path,
|
|
190
|
+
line,
|
|
191
|
+
message: 'Slack token detected',
|
|
192
|
+
why: 'Slack tokens grant API access and must not be committed.',
|
|
193
|
+
fix: 'Remove the token and rotate it in the Slack app dashboard.',
|
|
194
|
+
redactedExcerpt: redactExcerpt(matched, ctx.config.output.redact),
|
|
195
|
+
fingerprint: stableFingerprint(`SEC005:${ctx.path}:${line}:${matched.slice(0, 12)}`),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return findings;
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: 'SEC006',
|
|
203
|
+
title: 'GCP service account key detected',
|
|
204
|
+
defaultSeverity: 'critical',
|
|
205
|
+
appliesTo: (path) => path.endsWith('.json'),
|
|
206
|
+
run: (ctx) => {
|
|
207
|
+
try {
|
|
208
|
+
const parsed = JSON.parse(ctx.content);
|
|
209
|
+
if (parsed['type'] === 'service_account' &&
|
|
210
|
+
typeof parsed['private_key'] === 'string' &&
|
|
211
|
+
parsed['private_key'].length > 0) {
|
|
212
|
+
return [
|
|
213
|
+
{
|
|
214
|
+
ruleId: 'SEC006',
|
|
215
|
+
severity: 'critical',
|
|
216
|
+
path: ctx.path,
|
|
217
|
+
message: 'GCP service account key file detected',
|
|
218
|
+
why: 'Service account keys grant cloud access and must not be committed.',
|
|
219
|
+
fix: 'Remove the file, revoke the key in GCP IAM, and use Workload Identity instead.',
|
|
220
|
+
fingerprint: stableFingerprint(`SEC006:${ctx.path}`),
|
|
221
|
+
},
|
|
222
|
+
];
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// Not valid JSON
|
|
227
|
+
}
|
|
228
|
+
return [];
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
id: 'SEC007',
|
|
233
|
+
title: 'Secrets file tracked',
|
|
234
|
+
defaultSeverity: 'warning',
|
|
235
|
+
appliesTo: (path) => isSecretsFilePath(path),
|
|
236
|
+
run: (ctx) => [
|
|
237
|
+
{
|
|
238
|
+
ruleId: 'SEC007',
|
|
239
|
+
severity: 'warning',
|
|
240
|
+
path: ctx.path,
|
|
241
|
+
message: `Secrets file tracked in repository: ${ctx.path.split('/').pop()}`,
|
|
242
|
+
why: 'Files like .env and private key files should never be committed.',
|
|
243
|
+
fix: 'Remove the file from the repository and add it to .gitignore.',
|
|
244
|
+
fingerprint: stableFingerprint(`SEC007:${ctx.path}`),
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
id: 'SEC050',
|
|
250
|
+
title: 'High-entropy token heuristic',
|
|
251
|
+
defaultSeverity: 'warning',
|
|
252
|
+
appliesTo: () => true,
|
|
253
|
+
run: (ctx) => {
|
|
254
|
+
const findings = [];
|
|
255
|
+
for (const match of ctx.content.matchAll(HIGH_ENTROPY_STRING)) {
|
|
256
|
+
const candidate = match[1];
|
|
257
|
+
if (!candidate)
|
|
258
|
+
continue;
|
|
259
|
+
if (looksLikeUrl(candidate))
|
|
260
|
+
continue;
|
|
261
|
+
if (shannonEntropy(candidate) >= 4.5) {
|
|
262
|
+
const index = match.index ?? 0;
|
|
263
|
+
const line = lineForIndex(ctx.content, index);
|
|
264
|
+
findings.push({
|
|
265
|
+
ruleId: 'SEC050',
|
|
266
|
+
severity: 'warning',
|
|
267
|
+
path: ctx.path,
|
|
268
|
+
line,
|
|
269
|
+
message: 'High-entropy string detected (possible secret)',
|
|
270
|
+
why: 'Randomly-generated tokens often indicate embedded secrets.',
|
|
271
|
+
fix: 'Move to a secret manager or environment variable.',
|
|
272
|
+
redactedExcerpt: redactExcerpt(candidate, ctx.config.output.redact),
|
|
273
|
+
fingerprint: stableFingerprint(`SEC050:${ctx.path}:${line}:${candidate.slice(0, 8)}`),
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return findings;
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
];
|
|
281
|
+
// Export patterns for reuse in AI artifacts rule
|
|
282
|
+
export { PRIVATE_KEY_BLOCK, GITHUB_TOKEN, AWS_ACCESS_KEY, STRIPE_LIVE_KEY, SLACK_TOKEN };
|
|
283
|
+
//# sourceMappingURL=secrets_v1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets_v1.js","sourceRoot":"","sources":["../../src/rules/secrets_v1.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Finding, OopsConfig } from '../types.js';
|
|
2
|
+
export type RuleContext = {
|
|
3
|
+
cwd: string;
|
|
4
|
+
path: string;
|
|
5
|
+
content: string;
|
|
6
|
+
config: OopsConfig;
|
|
7
|
+
};
|
|
8
|
+
export type Rule = {
|
|
9
|
+
id: string;
|
|
10
|
+
title: string;
|
|
11
|
+
defaultSeverity: 'critical' | 'warning' | 'info';
|
|
12
|
+
appliesTo: (path: string) => boolean;
|
|
13
|
+
run: (ctx: RuleContext) => Finding[];
|
|
14
|
+
};
|
|
15
|
+
export type Ruleset = {
|
|
16
|
+
id: string;
|
|
17
|
+
rules: Rule[];
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/rules/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;IACjD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACrC,GAAG,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,EAAE,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,IAAI,EAAE,CAAC;CACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/rules/types.ts"],"names":[],"mappings":""}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type Severity = 'critical' | 'warning' | 'info';
|
|
2
|
+
export type Finding = {
|
|
3
|
+
ruleId: string;
|
|
4
|
+
severity: Severity;
|
|
5
|
+
path: string;
|
|
6
|
+
line?: number;
|
|
7
|
+
message: string;
|
|
8
|
+
why: string;
|
|
9
|
+
fix: string;
|
|
10
|
+
redactedExcerpt?: string;
|
|
11
|
+
fingerprint: string;
|
|
12
|
+
};
|
|
13
|
+
export type RedactConfig = {
|
|
14
|
+
showPrefix: number;
|
|
15
|
+
showSuffix: number;
|
|
16
|
+
};
|
|
17
|
+
export type OutputFormat = 'text' | 'json';
|
|
18
|
+
export type OopsConfig = {
|
|
19
|
+
version: 1;
|
|
20
|
+
include: string[];
|
|
21
|
+
exclude: string[];
|
|
22
|
+
rulesets: string[];
|
|
23
|
+
rules: {
|
|
24
|
+
disable: string[];
|
|
25
|
+
severity_overrides: Record<string, Severity>;
|
|
26
|
+
};
|
|
27
|
+
output: {
|
|
28
|
+
format: OutputFormat;
|
|
29
|
+
failOn: Severity;
|
|
30
|
+
redact: RedactConfig;
|
|
31
|
+
};
|
|
32
|
+
baseline: {
|
|
33
|
+
mode: 'off' | 'use' | 'update';
|
|
34
|
+
file: string;
|
|
35
|
+
};
|
|
36
|
+
allowlist: {
|
|
37
|
+
paths: string[];
|
|
38
|
+
rules: Record<string, string[]>;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvD,MAAM,MAAM,OAAO,GAAG;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;AAE3C,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE;QACL,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;KAC9C,CAAC;IACF,MAAM,EAAE;QACN,MAAM,EAAE,YAAY,CAAC;QACrB,MAAM,EAAE,QAAQ,CAAC;QACjB,MAAM,EAAE,YAAY,CAAC;KACtB,CAAC;IACF,QAAQ,EAAE;QACR,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;QAC/B,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,SAAS,EAAE;QACT,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;KACjC,CAAC;CACH,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oops-catcher/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core scan engine for oops-catcher — rules, redaction, and formatters",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/auntiemoi-commits/oops-catcher.git"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"fast-glob": "^3.3.2",
|
|
30
|
+
"js-yaml": "^4.1.0",
|
|
31
|
+
"zod": "^3.23.8"
|
|
32
|
+
}
|
|
33
|
+
}
|