bareloop 0.6.0 → 0.8.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.
@@ -62,4 +62,54 @@ export function redactSecrets(raw: unknown): string;
62
62
  * @param {(code: string, path: string, detail?: string) => void} red
63
63
  */
64
64
  export function sweepSecretLiterals(root: any, red: (code: string, path: string, detail?: string) => void): void;
65
+ /**
66
+ * F49 — a heuristic reject for the catastrophic-backtracking footgun: an
67
+ * unbounded quantifier applied to a group whose body itself repeats unboundedly
68
+ * (`(a+)+`, `(\d*)*`, `([a-z]+){1,}`) — including through a redundant wrapping
69
+ * group (`((a+))+`, `(?:(a+))*`), which is the SAME exponential class as `(a+)+`
70
+ * and is caught by propagating the inner repeat up through the wrapper. Such a
71
+ * pattern can hang `RegExp.test` for seconds on a short crafted body, and THREE
72
+ * fields feed it to an evaluator with NO timeout — one per document:
73
+ * - the AGENT's `artifact-written.pattern`, run by `evalExits` (F49, the
74
+ * original site). Self-DoS only: the agent authors both the pattern and
75
+ * (via the worker) the artifact, so a hang burns only its own run's
76
+ * wall-clock, and there is no arbiter compromise — it cannot escape the
77
+ * fence, forge a green, or leak a secret.
78
+ * - the OPERATOR's `judged.pattern` (`runClose`) and `gapKeep` (`boundGap`),
79
+ * compiled and run against close output in BARELOOP'S OWN PROCESS. These
80
+ * are worse than an operator self-DoS, and the reason is F67's lesson: the
81
+ * regex blocks the MAIN EVENT LOOP, so the in-process stall fuse — a timer
82
+ * in that same loop — cannot fire. The run dies to the OUTSIDE watchdog and
83
+ * is read as a model stall, so a bad regex in a SIGNED spec presents as a
84
+ * provider problem. MEASURED: `boundGap(stream, '(a+)+$')` on a 40-char
85
+ * body does not finish in 20s.
86
+ * So the reject targets the dominant exponential class and fails it as a
87
+ * mechanical gap at the validation gate, before any tokens burn. A full ReDoS
88
+ * analyzer needs a real regex engine (an external native dep we do not take for
89
+ * a LOW issue); exotic overlapping-alternation blowup is out of scope by
90
+ * decision (PARKED to the close-authoring rung — PRD v1.55).
91
+ *
92
+ * SCOPE IS ASYMMETRIC, both directions named on purpose:
93
+ * - false NEGATIVE: overlapping-alternation blowup (`(a|ab)+`-class) is not
94
+ * detected — there is no inner QUANTIFIER to find, so the shape scan cannot
95
+ * see it; the blowup comes from overlapping alternation BRANCHES under a
96
+ * repeat. A genuine limit of the approach, not a bug in it. Widening the
97
+ * detector changes which SIGNED specs are admissible, which is
98
+ * arbiter-adjacent — parked, not chased (PRD v1.55).
99
+ * - false POSITIVE: a group whose repetitions are disambiguated by a literal
100
+ * anchor/delimiter (`(?:^- .+$\n?)+`, `(?:CHANGELOG:.+\n)+`) is FLAGGED even
101
+ * though a real engine runs it linearly — the scan sees the nested-quantifier
102
+ * SHAPE, not the disambiguation. Rejecting it is the FAIL-SAFE direction (it
103
+ * never admits an unsafe pattern), and the cost is bounded: the plan drafter
104
+ * gets a mechanical gap and rewrites (drop the outer `+`, or match once).
105
+ * Detecting "safe because anchored" needs the same real engine we declined,
106
+ * and guessing it wrong would ADMIT an exponential pattern — so the shape
107
+ * reject stands, and the over-rejection is a named, accepted limitation.
108
+ *
109
+ * The input is guaranteed to compile as a RegExp (checked first by the caller),
110
+ * so this scan assumes valid, balanced JS regex syntax.
111
+ * @param {string} src a compiled regex source string
112
+ * @returns {boolean} true iff a nested unbounded quantifier is present
113
+ */
114
+ export function hasNestedQuantifier(src: string): boolean;
65
115
  export const SECRET_PATTERNS: RegExp[];