@wrongstack/plugins 0.295.0 → 0.295.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.
- package/dist/accessibility-auditor/index.d.ts.map +1 -1
- package/dist/accessibility-auditor.js +19 -2
- package/dist/agent-handoff/index.d.ts.map +1 -1
- package/dist/agent-handoff.js +30 -1
- package/dist/auto-doc/index.d.ts.map +1 -1
- package/dist/auto-doc.js +3 -1
- package/dist/auto-i18n-extractor.js +5 -0
- package/dist/branch-guard/index.d.ts.map +1 -1
- package/dist/branch-guard.js +103 -1
- package/dist/changelog-writer/index.d.ts.map +1 -1
- package/dist/changelog-writer.js +137 -3
- package/dist/checkpoint/index.d.ts +2 -0
- package/dist/checkpoint/index.d.ts.map +1 -1
- package/dist/checkpoint.js +34 -8
- package/dist/code-metrics.js +5 -0
- package/dist/commit-validator/index.d.ts.map +1 -1
- package/dist/commit-validator.js +17 -7
- package/dist/context-pins/index.d.ts.map +1 -1
- package/dist/context-pins.js +6 -5
- package/dist/cost-tracker/index.d.ts.map +1 -1
- package/dist/cost-tracker.js +101 -1
- package/dist/cron/index.d.ts.map +1 -1
- package/dist/cron.js +1 -0
- package/dist/dead-code-detector.js +5 -0
- package/dist/dependency-vulnerability-gate/index.d.ts.map +1 -1
- package/dist/dependency-vulnerability-gate.js +43 -8
- package/dist/diff-summary/index.d.ts.map +1 -1
- package/dist/diff-summary.js +100 -1
- package/dist/doc-sync-guard.js +5 -0
- package/dist/duplicate-code-detector/index.d.ts.map +1 -1
- package/dist/duplicate-code-detector.js +102 -2
- package/dist/feature-flag-tracker/index.d.ts.map +1 -1
- package/dist/feature-flag-tracker.js +30 -4
- package/dist/file-watcher/index.d.ts.map +1 -1
- package/dist/file-watcher.js +6 -7
- package/dist/format-on-save/index.d.ts +2 -0
- package/dist/format-on-save/index.d.ts.map +1 -1
- package/dist/format-on-save.js +288 -59
- package/dist/import-organizer/index.d.ts.map +1 -1
- package/dist/import-organizer.js +140 -20
- package/dist/index.js +1265 -544
- package/dist/interface-contract-guard/index.d.ts.map +1 -1
- package/dist/interface-contract-guard.js +60 -26
- package/dist/knowledge-graph/index.d.ts.map +1 -1
- package/dist/knowledge-graph.js +7 -6
- package/dist/lint-gate/index.d.ts.map +1 -1
- package/dist/lint-gate.js +103 -1
- package/dist/loop-breaker/index.d.ts.map +1 -1
- package/dist/loop-breaker.js +15 -5
- package/dist/migration-planner.js +3 -0
- package/dist/notify-hub/index.d.ts.map +1 -1
- package/dist/notify-hub.js +41 -4
- package/dist/prompt-firewall/index.d.ts.map +1 -1
- package/dist/prompt-firewall.js +140 -11
- package/dist/refactor-suggester/index.d.ts.map +1 -1
- package/dist/refactor-suggester.js +119 -4
- package/dist/runtime/bounded-map.d.ts +86 -0
- package/dist/runtime/bounded-map.d.ts.map +1 -0
- package/dist/runtime/credential-patterns.d.ts +42 -0
- package/dist/runtime/credential-patterns.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/local-bin.d.ts +120 -0
- package/dist/runtime/local-bin.d.ts.map +1 -0
- package/dist/runtime/safe-json.d.ts +25 -0
- package/dist/runtime/safe-json.d.ts.map +1 -0
- package/dist/runtime.js +291 -22
- package/dist/schema-evolution-guard.js +5 -0
- package/dist/secret-scanner/index.d.ts.map +1 -1
- package/dist/secret-scanner.js +175 -48
- package/dist/security-hotspot-scanner/index.d.ts.map +1 -1
- package/dist/security-hotspot-scanner.js +132 -1
- package/dist/semantic-search-indexer/index.d.ts.map +1 -1
- package/dist/semantic-search-indexer.js +7 -1
- package/dist/semver-bump/index.d.ts.map +1 -1
- package/dist/semver-bump.js +21 -2
- package/dist/template-engine/index.d.ts.map +1 -1
- package/dist/template-engine.js +30 -2
- package/dist/test-coverage-gate.js +5 -0
- package/dist/test-runner-gate/index.d.ts.map +1 -1
- package/dist/test-runner-gate.js +130 -8
- package/dist/todo-listener/index.d.ts.map +1 -1
- package/dist/todo-listener.js +30 -1
- package/dist/todo-tracker/index.d.ts.map +1 -1
- package/dist/todo-tracker.js +3 -4
- package/dist/token-throttle/index.d.ts.map +1 -1
- package/dist/token-throttle.js +17 -2
- package/dist/type-gate/index.d.ts.map +1 -1
- package/dist/type-gate.js +96 -16
- package/package.json +3 -3
package/dist/secret-scanner.js
CHANGED
|
@@ -1,20 +1,44 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
var
|
|
1
|
+
// src/runtime/credential-patterns.ts
|
|
2
|
+
var CREDENTIAL_PATTERNS = [
|
|
3
3
|
// LLM provider keys
|
|
4
4
|
{
|
|
5
5
|
type: "anthropic_key",
|
|
6
6
|
regex: /(?<![A-Za-z0-9])sk-ant-api\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g
|
|
7
7
|
},
|
|
8
|
-
{ type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g },
|
|
9
|
-
// GitHub
|
|
8
|
+
{ type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?!ant)(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g },
|
|
9
|
+
// GitHub. `ghp_` is only the personal-access-token prefix — the OAuth
|
|
10
|
+
// (`gho_`), user-to-server (`ghu_`), server-to-server (`ghs_`) and
|
|
11
|
+
// refresh (`ghr_`) tokens grant the same or broader access and were
|
|
12
|
+
// previously not detected at all.
|
|
10
13
|
{ type: "github_pat", regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g },
|
|
14
|
+
{
|
|
15
|
+
type: "github_oauth_token",
|
|
16
|
+
regex: /(?<![A-Za-z0-9])gh[ousr]_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g
|
|
17
|
+
},
|
|
11
18
|
{ type: "github_pat_v2", regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g },
|
|
19
|
+
// GitLab
|
|
20
|
+
{ type: "gitlab_pat", regex: /(?<![A-Za-z0-9])glpat-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
21
|
+
{
|
|
22
|
+
type: "gitlab_runner_token",
|
|
23
|
+
regex: /(?<![A-Za-z0-9])glrt-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
24
|
+
},
|
|
25
|
+
// npm — a leaked publish token is a supply-chain compromise.
|
|
26
|
+
{ type: "npm_token", regex: /(?<![A-Za-z0-9])npm_[A-Za-z0-9]{36}(?![A-Za-z0-9])/g },
|
|
12
27
|
// AWS
|
|
13
28
|
{ type: "aws_access_key", regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g },
|
|
14
29
|
// GCP
|
|
15
30
|
{ type: "gcp_key", regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g },
|
|
16
|
-
// Slack
|
|
17
|
-
|
|
31
|
+
// Slack. `xoxe` (token-rotation) and `xapp` (app-level) were missing;
|
|
32
|
+
// both are as sensitive as the bot/user tokens already covered.
|
|
33
|
+
{
|
|
34
|
+
type: "slack_token",
|
|
35
|
+
regex: /(?<![A-Za-z0-9-])xox[abposer]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g
|
|
36
|
+
},
|
|
37
|
+
{ type: "slack_app_token", regex: /(?<![A-Za-z0-9-])xapp-\d-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g },
|
|
38
|
+
{
|
|
39
|
+
type: "slack_webhook",
|
|
40
|
+
regex: /https:\/\/hooks\.slack\.com\/services\/T[A-Za-z0-9_-]+\/B[A-Za-z0-9_-]+\/[A-Za-z0-9]{16,}/g
|
|
41
|
+
},
|
|
18
42
|
// Stripe
|
|
19
43
|
{
|
|
20
44
|
type: "stripe_key",
|
|
@@ -25,7 +49,7 @@ var BASE_PATTERNS = [
|
|
|
25
49
|
// Telegram
|
|
26
50
|
{
|
|
27
51
|
type: "telegram_bot_token",
|
|
28
|
-
regex:
|
|
52
|
+
regex: /(?:(?<![A-Za-z0-9_])|(?<=(?:^|[^A-Za-z0-9_])bot))\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
29
53
|
},
|
|
30
54
|
// JWT
|
|
31
55
|
{
|
|
@@ -35,35 +59,93 @@ var BASE_PATTERNS = [
|
|
|
35
59
|
// Private keys
|
|
36
60
|
{
|
|
37
61
|
type: "private_key",
|
|
38
|
-
regex: /(?:^|\n)
|
|
62
|
+
regex: /(?:^|\n)(?:-----BEGIN (?:RSA|EC|OPENSSH|DSA)? ?PRIVATE KEY-----[\s\S]*?-----END (?:RSA|EC|OPENSSH|DSA)? ?PRIVATE KEY-----|-----BEGIN PGP PRIVATE KEY BLOCK-----[\s\S]*?-----END PGP PRIVATE KEY BLOCK-----)(?!\S)/g
|
|
39
63
|
},
|
|
40
64
|
// AI/ML provider tokens
|
|
41
65
|
{ type: "huggingface_token", regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g },
|
|
42
66
|
{ type: "replicate_token", regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
43
67
|
{ type: "perplexity_key", regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
44
68
|
{ type: "groq_key", regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
69
|
+
// SaaS / infrastructure tokens — each grants API access on the user's
|
|
70
|
+
// account, and each was previously invisible to this gate.
|
|
71
|
+
{ type: "sendgrid_key", regex: /(?<![A-Za-z0-9])SG\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
72
|
+
{ type: "digitalocean_token", regex: /(?<![A-Za-z0-9])dop_v1_[a-f0-9]{64}(?![A-Za-z0-9])/g },
|
|
73
|
+
{ type: "doppler_token", regex: /(?<![A-Za-z0-9])dp\.(?:pt|st|sa|scim|audit)\.[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
74
|
+
{ type: "shopify_token", regex: /(?<![A-Za-z0-9])shp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}(?![A-Za-z0-9])/g },
|
|
75
|
+
{ type: "docker_pat", regex: /(?<![A-Za-z0-9])dckr_pat_[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
76
|
+
{ type: "linear_key", regex: /(?<![A-Za-z0-9])lin_api_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
77
|
+
{ type: "atlassian_token", regex: /(?<![A-Za-z0-9])ATATT3[A-Za-z0-9_\-=]{40,}(?![A-Za-z0-9_\-=])/g },
|
|
78
|
+
{ type: "square_token", regex: /(?<![A-Za-z0-9])(?:sq0(?:atp|csp)-|EAAA)[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
79
|
+
{
|
|
80
|
+
type: "azure_storage_key",
|
|
81
|
+
regex: /AccountKey=[A-Za-z0-9+/]{80,}={0,2}/g
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
type: "google_oauth_client_secret",
|
|
85
|
+
regex: /(?<![A-Za-z0-9_-])GOCSPX-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
86
|
+
},
|
|
45
87
|
// Bearer tokens
|
|
46
88
|
{
|
|
47
89
|
type: "bearer_token",
|
|
48
|
-
regex: /(
|
|
90
|
+
regex: /(?<![A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{12,512}=*(?![A-Za-z0-9._~+/-])/g
|
|
49
91
|
},
|
|
50
|
-
// Database URIs
|
|
51
|
-
{ type: "mongodb_uri", regex: /mongodb(?:\+srv)?:\/\/[^\s"'`]+/g },
|
|
52
|
-
{
|
|
53
|
-
|
|
54
|
-
|
|
92
|
+
// Database URIs. Require password-bearing user-info; credential-free values stay scannable.
|
|
93
|
+
{ type: "mongodb_uri", regex: /mongodb(?:\+srv)?:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g },
|
|
94
|
+
{
|
|
95
|
+
type: "postgres_uri",
|
|
96
|
+
// Query parsers decode percent-encoded parameter names. Recognize each
|
|
97
|
+
// encoded character in `password` so mixed forms such as `pass%77ord`
|
|
98
|
+
// cannot bypass detection while keeping the scan strictly bounded.
|
|
99
|
+
regex: /postgres(?:ql)?:\/\/(?:[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+|[^&\s?"'`#]{1,2048}\?(?:(?!(?:p|%70)(?:a|%61)(?:s|%73)(?:s|%73)(?:w|%77)(?:o|%6[fF])(?:r|%72)(?:d|%64)=)[^&\s#"'`]{1,256}&){0,32}(?:p|%70)(?:a|%61)(?:s|%73)(?:s|%73)(?:w|%77)(?:o|%6[fF])(?:r|%72)(?:d|%64)=[^&\s#"'`]{1,4096})/g
|
|
100
|
+
},
|
|
101
|
+
{ type: "mysql_uri", regex: /mysql:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g },
|
|
102
|
+
{ type: "redis_uri", regex: /redis:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g }
|
|
55
103
|
];
|
|
104
|
+
function cloneCredentialPatterns() {
|
|
105
|
+
return CREDENTIAL_PATTERNS.map((p) => ({
|
|
106
|
+
type: p.type,
|
|
107
|
+
regex: new RegExp(p.regex.source, p.regex.flags)
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/secret-scanner/index.ts
|
|
112
|
+
var BASE_PATTERNS = cloneCredentialPatterns();
|
|
56
113
|
var PATTERNS = [...BASE_PATTERNS];
|
|
57
114
|
var patternCacheKey = "";
|
|
115
|
+
var GROUP_INDEX_OF_PATTERN = [];
|
|
58
116
|
var COMBINED_REGEX = buildCombinedRegex(PATTERNS);
|
|
59
|
-
var
|
|
117
|
+
var SCAN_WINDOW_LENGTH = 1e5;
|
|
118
|
+
var SCAN_WINDOW_OVERLAP = 4096;
|
|
119
|
+
var MAX_TOTAL_SCAN_LENGTH = 8 * 1024 * 1024;
|
|
120
|
+
var TOO_LARGE_MARKER = "unscannable_oversized_input";
|
|
60
121
|
var RE_DOS_TIMEOUT_MS = 100;
|
|
122
|
+
function countCaptureGroups(source) {
|
|
123
|
+
try {
|
|
124
|
+
return new RegExp(`${source}|`).exec("").length - 1;
|
|
125
|
+
} catch {
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function patternTypeForGroups(groups) {
|
|
130
|
+
for (let i = 0; i < PATTERNS.length; i++) {
|
|
131
|
+
const at = GROUP_INDEX_OF_PATTERN[i];
|
|
132
|
+
if (at !== void 0 && groups[at] !== void 0) return PATTERNS[i].type;
|
|
133
|
+
}
|
|
134
|
+
return void 0;
|
|
135
|
+
}
|
|
61
136
|
function buildCombinedRegex(patterns) {
|
|
62
|
-
const newCacheKey = JSON.stringify(patterns.map((p) => p.type));
|
|
137
|
+
const newCacheKey = JSON.stringify(patterns.map((p) => [p.type, p.regex.source]));
|
|
63
138
|
if (newCacheKey === patternCacheKey && COMBINED_REGEX) {
|
|
64
139
|
return COMBINED_REGEX;
|
|
65
140
|
}
|
|
66
141
|
patternCacheKey = newCacheKey;
|
|
142
|
+
const offsets = [];
|
|
143
|
+
let cursor = 0;
|
|
144
|
+
for (const p of patterns) {
|
|
145
|
+
offsets.push(cursor);
|
|
146
|
+
cursor += 1 + countCaptureGroups(p.regex.source);
|
|
147
|
+
}
|
|
148
|
+
GROUP_INDEX_OF_PATTERN = offsets;
|
|
67
149
|
return new RegExp(patterns.map((p) => `(${p.regex.source})`).join("|"), "g");
|
|
68
150
|
}
|
|
69
151
|
var state = {
|
|
@@ -81,29 +163,37 @@ var state = {
|
|
|
81
163
|
/** PostToolUse hook handle so teardown can unregister. */
|
|
82
164
|
postHookUnregister: null
|
|
83
165
|
};
|
|
84
|
-
function
|
|
85
|
-
if (!text) return [];
|
|
86
|
-
if (text.length > RE_DOS_MAX_SCAN_LENGTH) return [];
|
|
87
|
-
const found = /* @__PURE__ */ new Set();
|
|
166
|
+
function scanWindow(window, found, startTime) {
|
|
88
167
|
COMBINED_REGEX.lastIndex = 0;
|
|
89
168
|
let m;
|
|
90
|
-
|
|
91
|
-
while ((m = COMBINED_REGEX.exec(text)) !== null) {
|
|
169
|
+
while ((m = COMBINED_REGEX.exec(window)) !== null) {
|
|
92
170
|
if (performance.now() - startTime > RE_DOS_TIMEOUT_MS) {
|
|
93
171
|
throw new Error(
|
|
94
|
-
`secret-scanner: ReDoS timeout \u2014 regex scan exceeded ${RE_DOS_TIMEOUT_MS}ms on ${
|
|
172
|
+
`secret-scanner: ReDoS timeout \u2014 regex scan exceeded ${RE_DOS_TIMEOUT_MS}ms on ${window.length}-char window`
|
|
95
173
|
);
|
|
96
174
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
found.add(PATTERNS[i].type);
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
175
|
+
const type = patternTypeForGroups(m.slice(1));
|
|
176
|
+
if (type !== void 0) found.add(type);
|
|
103
177
|
if (m.index === COMBINED_REGEX.lastIndex) {
|
|
104
178
|
COMBINED_REGEX.lastIndex += 1;
|
|
105
179
|
}
|
|
106
180
|
}
|
|
181
|
+
}
|
|
182
|
+
function findMatches(text) {
|
|
183
|
+
if (!text) return [];
|
|
184
|
+
const found = /* @__PURE__ */ new Set();
|
|
185
|
+
const startTime = performance.now();
|
|
186
|
+
if (text.length <= SCAN_WINDOW_LENGTH) {
|
|
187
|
+
scanWindow(text, found, startTime);
|
|
188
|
+
return Array.from(found).sort();
|
|
189
|
+
}
|
|
190
|
+
if (text.length > MAX_TOTAL_SCAN_LENGTH) {
|
|
191
|
+
return [TOO_LARGE_MARKER];
|
|
192
|
+
}
|
|
193
|
+
const stride = SCAN_WINDOW_LENGTH - SCAN_WINDOW_OVERLAP;
|
|
194
|
+
for (let offset = 0; offset < text.length; offset += stride) {
|
|
195
|
+
scanWindow(text.slice(offset, offset + SCAN_WINDOW_LENGTH), found, startTime);
|
|
196
|
+
}
|
|
107
197
|
return Array.from(found).sort();
|
|
108
198
|
}
|
|
109
199
|
function scanInput(input, depth = 0) {
|
|
@@ -129,30 +219,55 @@ function scanInput(input, depth = 0) {
|
|
|
129
219
|
}
|
|
130
220
|
return null;
|
|
131
221
|
}
|
|
222
|
+
function redactString(text) {
|
|
223
|
+
if (text.length > SCAN_WINDOW_LENGTH) {
|
|
224
|
+
return { ok: false, reason: "oversized_input" };
|
|
225
|
+
}
|
|
226
|
+
const startTime = performance.now();
|
|
227
|
+
let cursor = 0;
|
|
228
|
+
let output = "";
|
|
229
|
+
COMBINED_REGEX.lastIndex = 0;
|
|
230
|
+
let match;
|
|
231
|
+
while ((match = COMBINED_REGEX.exec(text)) !== null) {
|
|
232
|
+
if (performance.now() - startTime > RE_DOS_TIMEOUT_MS) {
|
|
233
|
+
return { ok: false, reason: "oversized_input" };
|
|
234
|
+
}
|
|
235
|
+
const type = patternTypeForGroups(match.slice(1));
|
|
236
|
+
output += text.slice(cursor, match.index);
|
|
237
|
+
output += `[REDACTED:${type ?? "unknown"}]`;
|
|
238
|
+
cursor = COMBINED_REGEX.lastIndex;
|
|
239
|
+
if (match.index === COMBINED_REGEX.lastIndex) {
|
|
240
|
+
COMBINED_REGEX.lastIndex += 1;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (cursor === 0) return { ok: true, value: text };
|
|
244
|
+
return { ok: true, value: output + text.slice(cursor) };
|
|
245
|
+
}
|
|
132
246
|
function redactInput(input, depth = 0) {
|
|
133
|
-
if (input === null || input === void 0) return input;
|
|
134
|
-
if (depth > 50) return
|
|
247
|
+
if (input === null || input === void 0) return { ok: true, value: input };
|
|
248
|
+
if (depth > 50) return { ok: false, reason: "maximum_depth_exceeded" };
|
|
135
249
|
if (typeof input === "string") {
|
|
136
|
-
return input
|
|
137
|
-
for (let i = 0; i < PATTERNS.length; i++) {
|
|
138
|
-
if (groups[i] !== void 0) {
|
|
139
|
-
return `[REDACTED:${PATTERNS[i].type}]`;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return "[REDACTED:unknown]";
|
|
143
|
-
});
|
|
250
|
+
return redactString(input);
|
|
144
251
|
}
|
|
145
252
|
if (Array.isArray(input)) {
|
|
146
|
-
|
|
253
|
+
const out = [];
|
|
254
|
+
for (const item of input) {
|
|
255
|
+
const redacted = redactInput(item, depth + 1);
|
|
256
|
+
if (!redacted.ok) return redacted;
|
|
257
|
+
out.push(redacted.value);
|
|
258
|
+
}
|
|
259
|
+
return { ok: true, value: out };
|
|
147
260
|
}
|
|
148
261
|
if (typeof input === "object") {
|
|
149
262
|
const out = {};
|
|
150
263
|
for (const [k, v] of Object.entries(input)) {
|
|
151
|
-
|
|
264
|
+
const redacted = redactInput(v, depth + 1);
|
|
265
|
+
if (!redacted.ok) return redacted;
|
|
266
|
+
out[k] = redacted.value;
|
|
152
267
|
}
|
|
153
|
-
return out;
|
|
268
|
+
return { ok: true, value: out };
|
|
154
269
|
}
|
|
155
|
-
return input;
|
|
270
|
+
return { ok: true, value: input };
|
|
156
271
|
}
|
|
157
272
|
var DEFAULTS = {
|
|
158
273
|
matcher: "bash|write|edit",
|
|
@@ -212,20 +327,21 @@ function buildHook(cfg, log) {
|
|
|
212
327
|
}
|
|
213
328
|
if (cfg.mode === "redact") {
|
|
214
329
|
const redacted = redactInput(input.toolInput);
|
|
215
|
-
if (redacted !== null && typeof redacted === "object" && !Array.isArray(redacted)) {
|
|
330
|
+
if (redacted.ok && redacted.value !== null && typeof redacted.value === "object" && !Array.isArray(redacted.value)) {
|
|
216
331
|
state.redactCount += 1;
|
|
217
332
|
log.info(`[secret-scanner] redacted ${toolName} \u2014 matched: ${summary}`);
|
|
218
333
|
return {
|
|
219
334
|
decision: "allow",
|
|
220
|
-
modifiedInput: redacted,
|
|
335
|
+
modifiedInput: redacted.value,
|
|
221
336
|
additionalContext: `secret-scanner: redacted ${matched.length} credential pattern(s) from the ${toolName} arguments before execution.`
|
|
222
337
|
};
|
|
223
338
|
}
|
|
224
339
|
state.blockCount += 1;
|
|
225
340
|
state.lastBlock = { toolName, matchedTypes: matched, when };
|
|
341
|
+
const detail = !redacted.ok ? redacted.reason === "oversized_input" ? "an input field exceeds the safe scan limit" : "the input exceeds the safe nesting depth" : "the input has a non-object shape";
|
|
226
342
|
return {
|
|
227
343
|
decision: "block",
|
|
228
|
-
reason: `secret-scanner: cannot safely redact '${toolName}'
|
|
344
|
+
reason: `secret-scanner: cannot safely redact '${toolName}' because ${detail}; refusing to run.`
|
|
229
345
|
};
|
|
230
346
|
}
|
|
231
347
|
state.allowCount += 1;
|
|
@@ -243,10 +359,21 @@ function buildPostHook(cfg, log) {
|
|
|
243
359
|
const matched = findMatches(result.content);
|
|
244
360
|
if (matched.length === 0) return;
|
|
245
361
|
const toolName = input.toolName ?? "unknown";
|
|
246
|
-
const
|
|
362
|
+
const oversized = matched.includes(TOO_LARGE_MARKER);
|
|
363
|
+
const credentialMatches = matched.filter((type) => type !== TOO_LARGE_MARKER);
|
|
364
|
+
if (oversized && credentialMatches.length === 0) {
|
|
365
|
+
log.warn(
|
|
366
|
+
`[secret-scanner] POST-TOOL UNSCANNABLE: ${toolName} output exceeds ${MAX_TOTAL_SCAN_LENGTH} characters`
|
|
367
|
+
);
|
|
368
|
+
return {
|
|
369
|
+
additionalContext: `
|
|
370
|
+
\u26A0\uFE0F secret-scanner: the output of '${toolName}' exceeds the safe scan limit and could not be inspected for plaintext credentials. Do not treat this output as verified clean; avoid echoing, storing, committing, or transmitting it until it can be reviewed in smaller bounded sections.`
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
const summary = credentialMatches.join(", ");
|
|
247
374
|
const when = (/* @__PURE__ */ new Date()).toISOString();
|
|
248
375
|
state.leakCount += 1;
|
|
249
|
-
state.lastLeak = { toolName, matchedTypes:
|
|
376
|
+
state.lastLeak = { toolName, matchedTypes: credentialMatches, when };
|
|
250
377
|
log.warn(`[secret-scanner] POST-TOOL LEAK: ${toolName} output matched ${summary}`);
|
|
251
378
|
return {
|
|
252
379
|
additionalContext: `
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security-hotspot-scanner/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security-hotspot-scanner/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAkRrD,QAAA,MAAM,MAAM,EAAE,MAkQb,CAAC;eAEa,MAAM"}
|
|
@@ -4,6 +4,137 @@ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 }
|
|
|
4
4
|
|
|
5
5
|
// src/runtime/index.ts
|
|
6
6
|
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
7
|
+
|
|
8
|
+
// src/runtime/local-bin.ts
|
|
9
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
10
|
+
|
|
11
|
+
// src/runtime/bounded-map.ts
|
|
12
|
+
var BoundedMap = class {
|
|
13
|
+
map = /* @__PURE__ */ new Map();
|
|
14
|
+
max;
|
|
15
|
+
ttlMs;
|
|
16
|
+
now;
|
|
17
|
+
/** Entries dropped to stay under `max`. Surfaced by plugin health(). */
|
|
18
|
+
evictions = 0;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
const normalizedMax = Math.floor(options.max);
|
|
21
|
+
this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
|
|
22
|
+
this.ttlMs = options.ttlMs;
|
|
23
|
+
this.now = options.now ?? Date.now;
|
|
24
|
+
}
|
|
25
|
+
expired(entry) {
|
|
26
|
+
return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
|
|
27
|
+
}
|
|
28
|
+
get(key) {
|
|
29
|
+
const entry = this.map.get(key);
|
|
30
|
+
if (entry === void 0) return void 0;
|
|
31
|
+
if (this.expired(entry)) {
|
|
32
|
+
this.map.delete(key);
|
|
33
|
+
return void 0;
|
|
34
|
+
}
|
|
35
|
+
this.map.delete(key);
|
|
36
|
+
this.map.set(key, entry);
|
|
37
|
+
return entry.value;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Read without promoting the key to most-recently-used. Use for
|
|
41
|
+
* diagnostics that must not perturb the eviction order.
|
|
42
|
+
*/
|
|
43
|
+
peek(key) {
|
|
44
|
+
const entry = this.map.get(key);
|
|
45
|
+
if (entry === void 0 || this.expired(entry)) return void 0;
|
|
46
|
+
return entry.value;
|
|
47
|
+
}
|
|
48
|
+
has(key) {
|
|
49
|
+
const entry = this.map.get(key);
|
|
50
|
+
if (entry === void 0) return false;
|
|
51
|
+
if (this.expired(entry)) {
|
|
52
|
+
this.map.delete(key);
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
set(key, value) {
|
|
58
|
+
this.map.delete(key);
|
|
59
|
+
this.map.set(key, { value, storedAt: this.now() });
|
|
60
|
+
while (this.map.size > this.max) {
|
|
61
|
+
const coldest = this.map.keys().next().value;
|
|
62
|
+
if (coldest === void 0) break;
|
|
63
|
+
this.map.delete(coldest);
|
|
64
|
+
this.evictions += 1;
|
|
65
|
+
}
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
delete(key) {
|
|
69
|
+
return this.map.delete(key);
|
|
70
|
+
}
|
|
71
|
+
clear() {
|
|
72
|
+
this.map.clear();
|
|
73
|
+
this.evictions = 0;
|
|
74
|
+
}
|
|
75
|
+
get size() {
|
|
76
|
+
return this.map.size;
|
|
77
|
+
}
|
|
78
|
+
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
79
|
+
get evictionCount() {
|
|
80
|
+
return this.evictions;
|
|
81
|
+
}
|
|
82
|
+
/** Drop every expired entry. Cheap enough to call from a status tool. */
|
|
83
|
+
prune() {
|
|
84
|
+
if (this.ttlMs === void 0) return 0;
|
|
85
|
+
let removed = 0;
|
|
86
|
+
for (const [key, entry] of this.map) {
|
|
87
|
+
if (this.expired(entry)) {
|
|
88
|
+
this.map.delete(key);
|
|
89
|
+
removed += 1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return removed;
|
|
93
|
+
}
|
|
94
|
+
/** Live (non-expired) entries, coldest first. */
|
|
95
|
+
*entries() {
|
|
96
|
+
for (const [key, entry] of this.map) {
|
|
97
|
+
if (!this.expired(entry)) yield [key, entry.value];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
[Symbol.iterator]() {
|
|
101
|
+
return this.entries();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
var BoundedSet = class {
|
|
105
|
+
inner;
|
|
106
|
+
constructor(options) {
|
|
107
|
+
this.inner = new BoundedMap(options);
|
|
108
|
+
}
|
|
109
|
+
has(value) {
|
|
110
|
+
return this.inner.has(value);
|
|
111
|
+
}
|
|
112
|
+
add(value) {
|
|
113
|
+
this.inner.set(value, true);
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
delete(value) {
|
|
117
|
+
return this.inner.delete(value);
|
|
118
|
+
}
|
|
119
|
+
clear() {
|
|
120
|
+
this.inner.clear();
|
|
121
|
+
}
|
|
122
|
+
get size() {
|
|
123
|
+
return this.inner.size;
|
|
124
|
+
}
|
|
125
|
+
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
126
|
+
get evictionCount() {
|
|
127
|
+
return this.inner.evictionCount;
|
|
128
|
+
}
|
|
129
|
+
*values() {
|
|
130
|
+
for (const [key] of this.inner) yield key;
|
|
131
|
+
}
|
|
132
|
+
[Symbol.iterator]() {
|
|
133
|
+
return this.values();
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// src/runtime/index.ts
|
|
7
138
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
8
139
|
function hasLeadingDash(arg) {
|
|
9
140
|
return arg.length > 0 && arg.startsWith("-");
|
|
@@ -30,7 +161,7 @@ var state = {
|
|
|
30
161
|
skippedCount: 0,
|
|
31
162
|
blockedCount: 0,
|
|
32
163
|
lastResult: null,
|
|
33
|
-
knownHotspots:
|
|
164
|
+
knownHotspots: new BoundedSet({ max: 5e3 }),
|
|
34
165
|
hookUnregister: null
|
|
35
166
|
};
|
|
36
167
|
var DEFAULTS = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/semantic-search-indexer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/semantic-search-indexer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAqcrD,QAAA,MAAM,MAAM,EAAE,MA6Nb,CAAC;eAEa,MAAM"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// src/semantic-search-indexer/index.ts
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
3
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { DEFAULT_WALK_IGNORE_DIRS } from "@wrongstack/core/utils";
|
|
4
5
|
var API_VERSION = "^0.1.10";
|
|
6
|
+
var escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5
7
|
var state = {
|
|
6
8
|
index: null,
|
|
7
9
|
cachedPath: null,
|
|
@@ -45,7 +47,11 @@ var DEFAULTS = {
|
|
|
45
47
|
".scss",
|
|
46
48
|
".html"
|
|
47
49
|
],
|
|
48
|
-
excludePatterns: [
|
|
50
|
+
excludePatterns: [
|
|
51
|
+
...DEFAULT_WALK_IGNORE_DIRS.map(escapeRegex),
|
|
52
|
+
"\\.wrongstack",
|
|
53
|
+
"\\.temp_files"
|
|
54
|
+
],
|
|
49
55
|
maxFileBytes: 1e6,
|
|
50
56
|
defaultLimit: 10,
|
|
51
57
|
minTokenLength: 2,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/semver-bump/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAuCrD,KAAK,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAErD,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAqGD;+DAC+D;AAC/D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAQnF;AAmBD,wBAAgB,aAAa,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,QAAQ,CAIrE;AAmED,QAAA,MAAM,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/semver-bump/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAuCrD,KAAK,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAErD,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAqGD;+DAC+D;AAC/D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAQnF;AAmBD,wBAAgB,aAAa,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,QAAQ,CAIrE;AAmED,QAAA,MAAM,MAAM,EAAE,MA0db,CAAC;eAEa,MAAM"}
|
package/dist/semver-bump.js
CHANGED
|
@@ -293,10 +293,29 @@ var plugin = {
|
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
} else {
|
|
296
|
+
const pending = [];
|
|
296
297
|
for (const manifest of changed) {
|
|
297
|
-
|
|
298
|
+
let pkgData;
|
|
299
|
+
try {
|
|
300
|
+
pkgData = JSON.parse(await readFile(manifest, "utf-8"));
|
|
301
|
+
} catch (err) {
|
|
302
|
+
return {
|
|
303
|
+
ok: false,
|
|
304
|
+
error: `cannot bump: ${manifest} is not readable as JSON (${toErrorMessage(err)}). No manifests were modified.`
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
if (!pkgData || typeof pkgData !== "object") {
|
|
308
|
+
return {
|
|
309
|
+
ok: false,
|
|
310
|
+
error: `cannot bump: ${manifest} does not contain a JSON object. No manifests were modified.`
|
|
311
|
+
};
|
|
312
|
+
}
|
|
298
313
|
pkgData.version = newVersion;
|
|
299
|
-
|
|
314
|
+
pending.push({ path: manifest, contents: `${JSON.stringify(pkgData, null, 2)}
|
|
315
|
+
` });
|
|
316
|
+
}
|
|
317
|
+
for (const { path, contents } of pending) {
|
|
318
|
+
await writeFile(path, contents, "utf-8");
|
|
300
319
|
}
|
|
301
320
|
}
|
|
302
321
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/template-engine/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/template-engine/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA+HrD,QAAA,MAAM,MAAM,EAAE,MA4Sb,CAAC;eAEa,MAAM"}
|
package/dist/template-engine.js
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
// src/template-engine/index.ts
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
-
import { isAbsolute } from "node:path";
|
|
3
|
+
import { isAbsolute as isAbsolute2 } from "node:path";
|
|
4
|
+
|
|
5
|
+
// src/runtime/index.ts
|
|
6
|
+
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
7
|
+
|
|
8
|
+
// src/runtime/local-bin.ts
|
|
9
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
10
|
+
|
|
11
|
+
// src/runtime/index.ts
|
|
12
|
+
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
13
|
+
function hasLeadingDash(arg) {
|
|
14
|
+
return arg.length > 0 && arg.startsWith("-");
|
|
15
|
+
}
|
|
16
|
+
function withinProjectPath(projectRoot, candidate) {
|
|
17
|
+
if (candidate.length === 0 || candidate.length > 4096) return false;
|
|
18
|
+
if (hasLeadingDash(candidate)) return false;
|
|
19
|
+
const resolved = isAbsolute(candidate) ? resolve(candidate) : resolve(projectRoot, candidate);
|
|
20
|
+
const rel = relative(projectRoot, resolved);
|
|
21
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
22
|
+
}
|
|
23
|
+
function withinProject(p) {
|
|
24
|
+
const cwd = process.cwd();
|
|
25
|
+
return withinProjectPath(cwd, p) || relative(cwd, p) === ".";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/template-engine/index.ts
|
|
4
29
|
var API_VERSION = "^0.1.10";
|
|
5
30
|
var templates = /* @__PURE__ */ new Map();
|
|
6
31
|
function expandTemplate(template, variables) {
|
|
@@ -47,9 +72,12 @@ function renderTemplateRaw(template, variables) {
|
|
|
47
72
|
return result;
|
|
48
73
|
}
|
|
49
74
|
function validateRelativeTemplatePath(field, value) {
|
|
50
|
-
if (
|
|
75
|
+
if (isAbsolute2(value) || value.split(/[\\/]+/).includes("..")) {
|
|
51
76
|
return `${field} must be a relative path without ".." components`;
|
|
52
77
|
}
|
|
78
|
+
if (!withinProject(value)) {
|
|
79
|
+
return `${field} must resolve inside the project directory`;
|
|
80
|
+
}
|
|
53
81
|
return null;
|
|
54
82
|
}
|
|
55
83
|
var plugin = {
|
|
@@ -3,6 +3,11 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
|
|
4
4
|
// src/runtime/index.ts
|
|
5
5
|
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
6
|
+
|
|
7
|
+
// src/runtime/local-bin.ts
|
|
8
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
9
|
+
|
|
10
|
+
// src/runtime/index.ts
|
|
6
11
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
7
12
|
function hasLeadingDash(arg) {
|
|
8
13
|
return arg.length > 0 && arg.startsWith("-");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-runner-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-runner-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAufrD,QAAA,MAAM,MAAM,EAAE,MA+Tb,CAAC;eAEa,MAAM"}
|