@bookedsolid/rea 0.35.0 → 0.37.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/cli/doctor.js +45 -36
- package/dist/hooks/_lib/segments.js +67 -7
- package/dist/hooks/secret-scanner/index.js +64 -2
- package/hooks/_lib/policy-reader.sh +948 -0
- package/hooks/attribution-advisory.sh +125 -66
- package/hooks/blocked-paths-bash-gate.sh +12 -12
- package/hooks/blocked-paths-enforcer.sh +11 -11
- package/hooks/local-review-gate.sh +111 -81
- package/hooks/protected-paths-bash-gate.sh +11 -15
- package/hooks/settings-protection.sh +11 -14
- package/package.json +3 -2
- package/scripts/lint-awk-shim-quotes.mjs +386 -0
- package/templates/_lib_policy-reader.dogfood-staged.sh +948 -0
- package/templates/attribution-advisory.dogfood-staged.sh +125 -66
- package/templates/blocked-paths-bash-gate.dogfood-staged.sh +12 -12
- package/templates/blocked-paths-enforcer.dogfood-staged.sh +11 -11
- package/templates/local-review-gate.dogfood-staged.sh +111 -81
- package/templates/protected-paths-bash-gate.dogfood-staged.sh +11 -15
- package/templates/settings-protection.dogfood-staged.sh +11 -14
package/dist/cli/doctor.js
CHANGED
|
@@ -169,22 +169,19 @@ export const EXPECTED_HOOKS = [
|
|
|
169
169
|
'blocked-paths-enforcer.sh',
|
|
170
170
|
'changeset-security-gate.sh',
|
|
171
171
|
'dangerous-bash-interceptor.sh',
|
|
172
|
-
// 0.
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
// hard-`fail`
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
// runtime and never blocks a tool call. See `git blame` on the 0.29.0
|
|
186
|
-
// round-2 P2 comment on `checkDelegationHookRegistered` for the prior
|
|
187
|
-
// application of this exact discipline.
|
|
172
|
+
// 0.36.0 — `delegation-advisory.sh` PROMOTED to EXPECTED_HOOKS (charter
|
|
173
|
+
// follow-through from 0.31.0). Originally held out in 0.31.0 to give
|
|
174
|
+
// consumers an upgrade-lag window: adding a brand-new hook to
|
|
175
|
+
// EXPECTED_HOOKS would have hard-`fail`ed `checkHooksInstalled` on
|
|
176
|
+
// every pre-0.31.0 install the instant they bumped the rea binary, a
|
|
177
|
+
// regression that turns a green doctor red purely from upgrade lag.
|
|
178
|
+
// After 4 releases of propagation (0.32, 0.33, 0.34, 0.35), the lag
|
|
179
|
+
// window has closed — consumers running `rea upgrade` since 0.31.0
|
|
180
|
+
// have laid the hook down. Same ratchet `delegation-capture.sh` went
|
|
181
|
+
// through 0.29.0 → 0.30.0. Promotion happens in lockstep with
|
|
182
|
+
// `checkDelegationAdvisoryHookRegistered` flipping `warn` → `fail`
|
|
183
|
+
// (see that function for the matching commentary).
|
|
184
|
+
'delegation-advisory.sh',
|
|
188
185
|
// 0.29.0 — delegation-telemetry MVP. The PreToolUse hook on
|
|
189
186
|
// matcher `Agent|Skill` emits a `rea.delegation_signal` audit record
|
|
190
187
|
// on every subagent / skill dispatch. Observational only — fails
|
|
@@ -1126,14 +1123,25 @@ export function checkDelegationHookRegistered(baseDir) {
|
|
|
1126
1123
|
*/
|
|
1127
1124
|
export function checkDelegationAdvisoryHookRegistered(baseDir) {
|
|
1128
1125
|
const label = 'delegation-advisory hook registered';
|
|
1129
|
-
|
|
1126
|
+
// 0.36.0 — promoted from `warn` (advisory in 0.31.0) to `fail` (hard)
|
|
1127
|
+
// per the staged-rollout ratchet. After 4 releases of upgrade-lag
|
|
1128
|
+
// propagation (0.32, 0.33, 0.34, 0.35), consumer installs that have
|
|
1129
|
+
// run `rea upgrade` since 0.31.0 already carry the PostToolUse
|
|
1130
|
+
// `Bash|Edit|Write|MultiEdit|NotebookEdit` group. Any install that
|
|
1131
|
+
// still lacks it after that window is genuinely missing the nudge
|
|
1132
|
+
// and `fail` is the proportionate signal. Companion change:
|
|
1133
|
+
// `delegation-advisory.sh` joined `EXPECTED_HOOKS` in the same
|
|
1134
|
+
// commit, so `checkHooksInstalled` also covers the file-presence +
|
|
1135
|
+
// executability checks now (this function still does both directly
|
|
1136
|
+
// as defense-in-depth, mirroring `checkDelegationHookRegistered`).
|
|
1137
|
+
const REFUSE = 'fail';
|
|
1130
1138
|
const MATCHER = 'Bash|Edit|Write|MultiEdit|NotebookEdit';
|
|
1131
1139
|
const settingsPath = path.join(baseDir, '.claude', 'settings.json');
|
|
1132
1140
|
if (!fs.existsSync(settingsPath)) {
|
|
1133
1141
|
return {
|
|
1134
1142
|
label,
|
|
1135
|
-
status:
|
|
1136
|
-
detail: `missing: ${settingsPath} — run \`rea upgrade\` or \`rea init
|
|
1143
|
+
status: REFUSE,
|
|
1144
|
+
detail: `missing: ${settingsPath} — run \`rea upgrade\` or \`rea init\``,
|
|
1137
1145
|
};
|
|
1138
1146
|
}
|
|
1139
1147
|
let parsed;
|
|
@@ -1143,7 +1151,7 @@ export function checkDelegationAdvisoryHookRegistered(baseDir) {
|
|
|
1143
1151
|
catch (e) {
|
|
1144
1152
|
return {
|
|
1145
1153
|
label,
|
|
1146
|
-
status:
|
|
1154
|
+
status: REFUSE,
|
|
1147
1155
|
detail: e instanceof Error ? e.message : String(e),
|
|
1148
1156
|
};
|
|
1149
1157
|
}
|
|
@@ -1152,9 +1160,9 @@ export function checkDelegationAdvisoryHookRegistered(baseDir) {
|
|
|
1152
1160
|
if (group === undefined) {
|
|
1153
1161
|
return {
|
|
1154
1162
|
label,
|
|
1155
|
-
status:
|
|
1163
|
+
status: REFUSE,
|
|
1156
1164
|
detail: `no PostToolUse group with matcher "${MATCHER}" found in .claude/settings.json — ` +
|
|
1157
|
-
'run `rea upgrade` to install
|
|
1165
|
+
'run `rea upgrade` to install. ' +
|
|
1158
1166
|
'NOTE: the matcher INCLUDES Bash — the delegation nudge counts every write-class ' +
|
|
1159
1167
|
'tool call, not just file edits.',
|
|
1160
1168
|
};
|
|
@@ -1163,16 +1171,16 @@ export function checkDelegationAdvisoryHookRegistered(baseDir) {
|
|
|
1163
1171
|
if (!cmds.some((c) => c.includes('delegation-advisory.sh'))) {
|
|
1164
1172
|
return {
|
|
1165
1173
|
label,
|
|
1166
|
-
status:
|
|
1174
|
+
status: REFUSE,
|
|
1167
1175
|
detail: `${MATCHER} matcher exists but no delegation-advisory.sh command found in its hooks list`,
|
|
1168
1176
|
};
|
|
1169
1177
|
}
|
|
1170
|
-
//
|
|
1171
|
-
// hook file it points at actually exists AND is
|
|
1172
|
-
//
|
|
1173
|
-
//
|
|
1174
|
-
//
|
|
1175
|
-
//
|
|
1178
|
+
// 0.31.0 round-2/3 P2: the registration string is present — now
|
|
1179
|
+
// confirm the hook file it points at actually exists AND is
|
|
1180
|
+
// executable. Kept after the 0.36.0 EXPECTED_HOOKS promotion as
|
|
1181
|
+
// defense-in-depth (the same `0o111` check `checkHooksInstalled`
|
|
1182
|
+
// does, scoped to this hook so the failure message can name the
|
|
1183
|
+
// exact remediation rather than a generic "missing X" enumeration).
|
|
1176
1184
|
const hookFile = path.join(baseDir, '.claude', 'hooks', 'delegation-advisory.sh');
|
|
1177
1185
|
let hookStat;
|
|
1178
1186
|
try {
|
|
@@ -1181,19 +1189,19 @@ export function checkDelegationAdvisoryHookRegistered(baseDir) {
|
|
|
1181
1189
|
catch {
|
|
1182
1190
|
return {
|
|
1183
1191
|
label,
|
|
1184
|
-
status:
|
|
1192
|
+
status: REFUSE,
|
|
1185
1193
|
detail: `${MATCHER} matcher references delegation-advisory.sh but the hook file is missing: ` +
|
|
1186
|
-
`${hookFile} — run \`rea upgrade\` to lay it down
|
|
1194
|
+
`${hookFile} — run \`rea upgrade\` to lay it down. ` +
|
|
1187
1195
|
'Without the file every matching PostToolUse dispatch shells out to a nonexistent path.',
|
|
1188
1196
|
};
|
|
1189
1197
|
}
|
|
1190
1198
|
if ((hookStat.mode & 0o111) === 0) {
|
|
1191
1199
|
return {
|
|
1192
1200
|
label,
|
|
1193
|
-
status:
|
|
1201
|
+
status: REFUSE,
|
|
1194
1202
|
detail: `${MATCHER} matcher references delegation-advisory.sh but the hook file is not executable ` +
|
|
1195
1203
|
`(mode=${(hookStat.mode & 0o777).toString(8)}): ${hookFile} — ` +
|
|
1196
|
-
'run `rea upgrade` or `chmod +x` it
|
|
1204
|
+
'run `rea upgrade` or `chmod +x` it. ' +
|
|
1197
1205
|
'A non-executable hook cannot be launched by Claude Code from settings.json.',
|
|
1198
1206
|
};
|
|
1199
1207
|
}
|
|
@@ -1469,9 +1477,10 @@ export function collectChecks(baseDir, codexProbeState, prePushState, options =
|
|
|
1469
1477
|
checkDelegationHookRegistered(baseDir),
|
|
1470
1478
|
// 0.31.0 — delegation-telemetry completion. The PostToolUse
|
|
1471
1479
|
// `Bash|Edit|Write|MultiEdit|NotebookEdit` matcher group drives
|
|
1472
|
-
// the delegation-advisory nudge hook.
|
|
1473
|
-
//
|
|
1474
|
-
// through in 0.29.0.
|
|
1480
|
+
// the delegation-advisory nudge hook. 0.36.0 — promoted warn →
|
|
1481
|
+
// fail (same upgrade-lag ratchet checkDelegationHookRegistered
|
|
1482
|
+
// went through in 0.29.0 → 0.30.0, after 4 release cycles of
|
|
1483
|
+
// propagation).
|
|
1475
1484
|
checkDelegationAdvisoryHookRegistered(baseDir),
|
|
1476
1485
|
];
|
|
1477
1486
|
// Non-git escape hatch: when `.git/` is absent, both git-hook checks are
|
|
@@ -467,6 +467,50 @@ function splitSegmentsRecursive(cmd, depth) {
|
|
|
467
467
|
}
|
|
468
468
|
return out;
|
|
469
469
|
}
|
|
470
|
+
/**
|
|
471
|
+
* Test whether a flag token is a `-c`-class introducer.
|
|
472
|
+
*
|
|
473
|
+
* Bash accepts `-c` combined with any other short single-char flags in
|
|
474
|
+
* a single short-flag bundle: `-c`, `-lc`, `-lic`, `-cli`, `-lci`,
|
|
475
|
+
* `-cil`, `-ilc`, etc. The bash cmd-segments.sh `WRAP` regex lists
|
|
476
|
+
* a non-exhaustive defensive subset (`c|lc|lic|ic|cl|cli|li|il`) but
|
|
477
|
+
* bash itself accepts ANY short-flag bundle that contains a `c`.
|
|
478
|
+
*
|
|
479
|
+
* The TS detector mirrors bash semantics: a SHORT-flag bundle
|
|
480
|
+
* (`-letters`, single leading `-`) whose letter set contains `c` is
|
|
481
|
+
* an introducer. The separated `--c` long-flag form is also
|
|
482
|
+
* recognized for parity with the bash WRAP regex's `--c` alternation.
|
|
483
|
+
*
|
|
484
|
+
* Long flags (`--rcfile`, `--noprofile`, `--login`, `--init-file`)
|
|
485
|
+
* are NOT introducers regardless of whether they contain the letter
|
|
486
|
+
* `c` — bash's long-options namespace is disjoint from the `-c`
|
|
487
|
+
* payload-execute semantics.
|
|
488
|
+
*
|
|
489
|
+
* 0.36.0 audit-trail:
|
|
490
|
+
* - Charter item 4 / 0.34.0 codex round-7 P2 #1: pre-fix the test
|
|
491
|
+
* was `/c/i.test(flag.replace(/^--?/, ''))` which over-matched on
|
|
492
|
+
* every flag with a `c` in its name (`--rcfile`, `--noprofile`).
|
|
493
|
+
* - 0.36.0 codex round-1 P1: the first fix attempt used an explicit
|
|
494
|
+
* allowlist `Set` mirroring the bash WRAP regex's explicit
|
|
495
|
+
* alternation, which was a NARROWING vs the pre-fix behavior —
|
|
496
|
+
* valid combined-flag forms like `-lci`, `-cil`, `-ilc` were not
|
|
497
|
+
* in the allowlist and stopped unwrapping, reopening a bypass
|
|
498
|
+
* surface against env-file-protection / dependency-audit-gate /
|
|
499
|
+
* dangerous-bash matchers. This function restores parity with
|
|
500
|
+
* bash itself: any short-flag bundle containing `c` qualifies.
|
|
501
|
+
*/
|
|
502
|
+
function isCDashIntroducer(flag) {
|
|
503
|
+
// Separated long-flag form (rare but bash accepts it).
|
|
504
|
+
if (flag === '--c')
|
|
505
|
+
return true;
|
|
506
|
+
// Short-flag bundle: single leading `-`, then one-or-more letters.
|
|
507
|
+
// The bundle is a `-c` introducer iff it contains the letter `c`
|
|
508
|
+
// (any position, any other-letters mix).
|
|
509
|
+
const m = /^-([A-Za-z]+)$/.exec(flag);
|
|
510
|
+
if (m === null)
|
|
511
|
+
return false;
|
|
512
|
+
return /c/i.test(m[1] ?? '');
|
|
513
|
+
}
|
|
470
514
|
/**
|
|
471
515
|
* Recognize a nested-shell wrapper segment and return the unquoted
|
|
472
516
|
* payload string. Returns `null` when the segment is not a wrapper.
|
|
@@ -554,15 +598,29 @@ function extractNestedShellPayload(head) {
|
|
|
554
598
|
return null;
|
|
555
599
|
const flag = flagMatch[0] ?? '';
|
|
556
600
|
cursor += flag.length;
|
|
557
|
-
// Recognized flag-token shapes:
|
|
558
|
-
// `-c` `-l
|
|
559
|
-
//
|
|
560
|
-
//
|
|
601
|
+
// Recognized flag-token shapes (parity with cmd-segments.sh WRAP):
|
|
602
|
+
// - pre-flags (no `-c` yet): `-l`, `-i`, `-e`, `-li`, `-il`,
|
|
603
|
+
// `--noprofile`, `--rcfile`, `--login` (etc.)
|
|
604
|
+
// - `-c`-class introducer: exactly `-c`, `-lc`, `-lic`, `-cl`,
|
|
605
|
+
// `-cli`, `-li`, `-il`, `-ic` (the bash WRAP regex's
|
|
606
|
+
// `-(c|lc|lic|ic|cl|cli|li|il)` set), OR separated `--c`.
|
|
607
|
+
//
|
|
608
|
+
// 0.36.0 audit-trail (charter item 4 / 0.34.0 codex round-7 P2 #1):
|
|
609
|
+
// pre-fix the test `/c/i.test(flag.replace(/^--?/, ''))` treated
|
|
610
|
+
// ANY flag containing the letter `c` as a `-c` introducer. This
|
|
611
|
+
// false-positived on benign flags like `--rcfile`, `--noprofile`
|
|
612
|
+
// (with `c` in the name), causing the walker to "commit" to a -c
|
|
613
|
+
// unwrap, advance past the flag, and then either fail to find a
|
|
614
|
+
// quoted payload or unwrap something that was never a shell-payload
|
|
615
|
+
// body. Net effect: over-trigger of nested-shell unwrap, with
|
|
616
|
+
// downstream advisory matchers seeing payloads that weren't ever
|
|
617
|
+
// shell-payloads. Fix restricts the introducer set to the exact
|
|
618
|
+
// WRAP-regex shapes; any other flag shape continues the flag walk
|
|
619
|
+
// (still valid — pre-flags before `-c` are accepted) but does NOT
|
|
620
|
+
// mark `sawCFlag = true`.
|
|
561
621
|
if (!/^--?[A-Za-z]+$/.test(flag))
|
|
562
622
|
return null;
|
|
563
|
-
|
|
564
|
-
// `--c` also counts (rare but bash accepts).
|
|
565
|
-
if (/c/i.test(flag.replace(/^--?/, ''))) {
|
|
623
|
+
if (isCDashIntroducer(flag)) {
|
|
566
624
|
sawCFlag = true;
|
|
567
625
|
// Continue the loop — the payload is the NEXT non-flag token.
|
|
568
626
|
// (Bash's argv parser stops walking flags as soon as it sees -c,
|
|
@@ -570,6 +628,8 @@ function extractNestedShellPayload(head) {
|
|
|
570
628
|
// safety; the bash WRAP regex similarly tolerates trailing
|
|
571
629
|
// flag-like tokens before the quoted body.)
|
|
572
630
|
}
|
|
631
|
+
// Else: a pre-flag (e.g. `-l`, `--rcfile`, `--noprofile`) — keep
|
|
632
|
+
// walking; if a later token IS in `CDASH_INTRODUCERS` we'll fire.
|
|
573
633
|
}
|
|
574
634
|
if (!sawCFlag)
|
|
575
635
|
return null;
|
|
@@ -127,7 +127,22 @@ const SECRET_PATTERNS = [
|
|
|
127
127
|
{
|
|
128
128
|
severity: 'HIGH',
|
|
129
129
|
label: 'Supabase service role key (JWT)',
|
|
130
|
-
|
|
130
|
+
// 0.36.0 audit-trail (charter item 5 / 0.34.0 codex round-7 P2 #2):
|
|
131
|
+
// restore byte-parity with the pre-0.34.0 bash body. The bash hook
|
|
132
|
+
// required a quote introducer (`["']`, no `?`); only quoted
|
|
133
|
+
// assignments matched HIGH. Pre-fix this TS regex made the quote
|
|
134
|
+
// OPTIONAL (`["']?`), which upgraded an unquoted `.env` line like
|
|
135
|
+
// `SUPABASE_SERVICE_ROLE_KEY=eyJ...` from MEDIUM advisory (matched
|
|
136
|
+
// by the lower-down `.env credential assignment` pattern) to HIGH
|
|
137
|
+
// blocking. That over-blocks legitimate `.env` files committed to
|
|
138
|
+
// public repos and breaks parity with consumers still on the bash
|
|
139
|
+
// body. Fix: drop the `?` so the quote is required, matching bash
|
|
140
|
+
// exactly. Unquoted assignments continue to fire MEDIUM via the
|
|
141
|
+
// `.env credential assignment` pattern below (line ~190); the only
|
|
142
|
+
// change is that they no longer ALSO fire HIGH here. The `[\"']`
|
|
143
|
+
// character class accepts both single and double quotes
|
|
144
|
+
// (mirroring the bash `["\'"'"']` literal).
|
|
145
|
+
regex: /SUPABASE_SERVICE_ROLE_KEY\s*=\s*["']eyJ[A-Za-z0-9._-]{50,}/g,
|
|
131
146
|
},
|
|
132
147
|
// ── MEDIUM severity (advisory) ───────────────────────────────────
|
|
133
148
|
{
|
|
@@ -153,10 +168,57 @@ const SECRET_PATTERNS = [
|
|
|
153
168
|
label: 'Hardcoded DB connection string with password',
|
|
154
169
|
regex: /postgresql:\/\/[^:]+:[^@]{8,}@/g,
|
|
155
170
|
},
|
|
171
|
+
{
|
|
172
|
+
severity: 'MEDIUM',
|
|
173
|
+
label: 'Supabase service role key (JWT, unquoted non-.env shape)',
|
|
174
|
+
// 0.36.0 codex round-2 P1 → round-3 P3 → round-4 P1 evolution.
|
|
175
|
+
//
|
|
176
|
+
// Background:
|
|
177
|
+
// - Round 1: 0.34.0-introduced HIGH regex had `["']?` (quote
|
|
178
|
+
// optional) which over-blocked unquoted .env lines vs the
|
|
179
|
+
// pre-0.34.0 bash baseline. Charter item 5 dropped the `?`.
|
|
180
|
+
// - Round 2 P1: dropping the `?` left a gap for unquoted forms
|
|
181
|
+
// outside `^FOO=` shape (`export FOO=…` etc.) that ALSO
|
|
182
|
+
// existed in the bash baseline. Added an unquoted-anywhere
|
|
183
|
+
// MEDIUM rule to close it.
|
|
184
|
+
// - Round 3 P3: unquoted-anywhere double-fired with the broader
|
|
185
|
+
// `.env credential assignment` MEDIUM on plain `^FOO=` lines.
|
|
186
|
+
// Narrowed to only fire on 5 specific shell-keyword prefixes
|
|
187
|
+
// (`export`, `readonly`, `declare`, `local`, `typeset`).
|
|
188
|
+
// - Round 4 P1: too narrow — left other unquoted shapes
|
|
189
|
+
// (Dockerfile `ENV FOO=…`, k8s manifests, ad-hoc shell
|
|
190
|
+
// `FOO=…; bar`) entirely unscanned.
|
|
191
|
+
//
|
|
192
|
+
// Round-4 resolution: fire on any unquoted assignment that is
|
|
193
|
+
// NOT at the start of a line (`^`). The `.env credential
|
|
194
|
+
// assignment` MEDIUM pattern owns `^FOO=…`; this rule owns
|
|
195
|
+
// everything else (`ENV FOO=…`, `export FOO=…`, `; FOO=…`,
|
|
196
|
+
// template-string `${FOO=…}`, etc.). Implemented via a
|
|
197
|
+
// multi-line regex with a look-behind for "anything except a
|
|
198
|
+
// line start". JS regex doesn't support a direct "not at line
|
|
199
|
+
// start" assertion, so we require at least one non-newline char
|
|
200
|
+
// before `SUPABASE_SERVICE_ROLE_KEY` on the same line.
|
|
201
|
+
//
|
|
202
|
+
// The `(?!["'])` look-ahead refuses when the value starts with
|
|
203
|
+
// a quote so the same secret isn't double-reported by the HIGH
|
|
204
|
+
// pattern above. Result: each secret produces exactly one
|
|
205
|
+
// MEDIUM finding regardless of shape, and the HIGH rule keeps
|
|
206
|
+
// exclusive ownership of quoted forms.
|
|
207
|
+
regex: /(?<=[^\n\r])\bSUPABASE_SERVICE_ROLE_KEY\s*=\s*(?!["'])eyJ[A-Za-z0-9._-]{50,}/gm,
|
|
208
|
+
},
|
|
156
209
|
{
|
|
157
210
|
severity: 'MEDIUM',
|
|
158
211
|
label: 'Supabase anon key in non-client context',
|
|
159
|
-
|
|
212
|
+
// 0.36.0 audit-trail (charter item 5 / 0.34.0 codex round-7 P2 #2,
|
|
213
|
+
// sibling fix): same parity restoration as the SUPABASE_SERVICE_ROLE_KEY
|
|
214
|
+
// pattern above — bash hook required a quote introducer, TS pattern
|
|
215
|
+
// had it optional via `?`. Removed for byte-parity. Unquoted .env
|
|
216
|
+
// forms continue to be advisory via the broader `.env credential
|
|
217
|
+
// assignment` MEDIUM pattern (where SUPABASE_ANON_KEY is NOT one of
|
|
218
|
+
// the named keys — anon-key prose in unquoted .env is acceptable
|
|
219
|
+
// since anon keys are public; only QUOTED-in-source matches stay
|
|
220
|
+
// an advisory MEDIUM here).
|
|
221
|
+
regex: /SUPABASE_ANON_KEY\s*=\s*["']eyJ[A-Za-z0-9._-]{50,}/g,
|
|
160
222
|
},
|
|
161
223
|
];
|
|
162
224
|
/**
|