@bookedsolid/rea 0.32.0 → 0.34.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/hook.js +49 -0
- package/dist/hooks/_lib/payload.d.ts +38 -0
- package/dist/hooks/_lib/payload.js +79 -0
- package/dist/hooks/_lib/segments.d.ts +127 -0
- package/dist/hooks/_lib/segments.js +628 -16
- package/dist/hooks/architecture-review-gate/index.d.ts +58 -0
- package/dist/hooks/architecture-review-gate/index.js +250 -0
- package/dist/hooks/changeset-security-gate/index.d.ts +71 -0
- package/dist/hooks/changeset-security-gate/index.js +330 -0
- package/dist/hooks/dangerous-bash-interceptor/index.d.ts +103 -0
- package/dist/hooks/dangerous-bash-interceptor/index.js +669 -0
- package/dist/hooks/dependency-audit-gate/index.d.ts +91 -0
- package/dist/hooks/dependency-audit-gate/index.js +294 -0
- package/dist/hooks/env-file-protection/index.d.ts +55 -0
- package/dist/hooks/env-file-protection/index.js +159 -0
- package/dist/hooks/local-review-gate/index.d.ts +145 -0
- package/dist/hooks/local-review-gate/index.js +374 -0
- package/dist/hooks/secret-scanner/index.d.ts +143 -0
- package/dist/hooks/secret-scanner/index.js +404 -0
- package/hooks/architecture-review-gate.sh +92 -77
- package/hooks/changeset-security-gate.sh +114 -149
- package/hooks/dangerous-bash-interceptor.sh +168 -386
- package/hooks/dependency-audit-gate.sh +115 -156
- package/hooks/env-file-protection.sh +130 -97
- package/hooks/local-review-gate.sh +523 -410
- package/hooks/secret-scanner.sh +210 -200
- package/package.json +1 -1
- package/templates/architecture-review-gate.dogfood-staged.sh +116 -0
- package/templates/changeset-security-gate.dogfood-staged.sh +137 -0
- package/templates/dangerous-bash-interceptor.dogfood-staged.sh +196 -0
- package/templates/dependency-audit-gate.dogfood-staged.sh +138 -0
- package/templates/env-file-protection.dogfood-staged.sh +157 -0
- package/templates/local-review-gate.dogfood-staged.sh +573 -0
- package/templates/secret-scanner.dogfood-staged.sh +240 -0
package/dist/cli/hook.js
CHANGED
|
@@ -39,6 +39,13 @@ import { checkHalt, formatHaltBanner } from '../hooks/_lib/halt-check.js';
|
|
|
39
39
|
import { runHookPrIssueLinkGate } from '../hooks/pr-issue-link-gate/index.js';
|
|
40
40
|
import { runHookSecurityDisclosureGate } from '../hooks/security-disclosure-gate/index.js';
|
|
41
41
|
import { runHookAttributionAdvisory } from '../hooks/attribution-advisory/index.js';
|
|
42
|
+
import { runHookEnvFileProtection } from '../hooks/env-file-protection/index.js';
|
|
43
|
+
import { runHookDependencyAuditGate } from '../hooks/dependency-audit-gate/index.js';
|
|
44
|
+
import { runHookChangesetSecurityGate } from '../hooks/changeset-security-gate/index.js';
|
|
45
|
+
import { runHookArchitectureReviewGate } from '../hooks/architecture-review-gate/index.js';
|
|
46
|
+
import { runHookDangerousBashInterceptor } from '../hooks/dangerous-bash-interceptor/index.js';
|
|
47
|
+
import { runHookLocalReviewGate } from '../hooks/local-review-gate/index.js';
|
|
48
|
+
import { runHookSecretScanner } from '../hooks/secret-scanner/index.js';
|
|
42
49
|
import { loadPolicy } from '../policy/loader.js';
|
|
43
50
|
import { appendAuditRecord, InvocationStatus, Tier } from '../audit/append.js';
|
|
44
51
|
import { CODEX_REVIEW_TOOL_NAME, CODEX_REVIEW_SERVER_NAME, } from '../audit/codex-event.js';
|
|
@@ -973,6 +980,48 @@ export function registerHookCommand(program) {
|
|
|
973
980
|
.action(async () => {
|
|
974
981
|
await runHookAttributionAdvisory();
|
|
975
982
|
});
|
|
983
|
+
hook
|
|
984
|
+
.command('env-file-protection')
|
|
985
|
+
.description('Node-binary port of `hooks/env-file-protection.sh` (0.33.0). Reads a Claude Code PreToolUse Bash payload from stdin; when the command sources, cps, or reads a `.env*`/`.envrc` file via text-reading utilities (cat/head/tail/grep/sed/awk/etc.), exits 2 with banner. Same-segment co-occurrence required for the utility-vs-filename match so multi-segment commands do not false-positive.')
|
|
986
|
+
.action(async () => {
|
|
987
|
+
await runHookEnvFileProtection();
|
|
988
|
+
});
|
|
989
|
+
hook
|
|
990
|
+
.command('dependency-audit-gate')
|
|
991
|
+
.description('Node-binary port of `hooks/dependency-audit-gate.sh` (0.33.0). Reads a Claude Code PreToolUse Bash payload from stdin; when the command is `(npm|pnpm|yarn) (install|i|add) <pkg>`, verifies each named package exists on the npm registry via `npm view <pkg> name` (5s timeout, capped at 5 packages/command). Exit 2 with multi-line banner on any missing package, otherwise exit 0.')
|
|
992
|
+
.action(async () => {
|
|
993
|
+
await runHookDependencyAuditGate();
|
|
994
|
+
});
|
|
995
|
+
hook
|
|
996
|
+
.command('changeset-security-gate')
|
|
997
|
+
.description('Node-binary port of `hooks/changeset-security-gate.sh` (0.33.0). Reads a Claude Code PreToolUse Write/Edit/MultiEdit/NotebookEdit payload from stdin; for writes targeting `.changeset/*.md`, blocks GHSA/CVE pre-disclosure and validates frontmatter (`---`-delimited block with `<pkg>: (patch|minor|major)` + non-empty description). MultiEdit short-circuits frontmatter validation because fragments are not full files. Block emissions use the Claude Code JSON-on-stdout protocol.')
|
|
998
|
+
.action(async () => {
|
|
999
|
+
await runHookChangesetSecurityGate();
|
|
1000
|
+
});
|
|
1001
|
+
hook
|
|
1002
|
+
.command('architecture-review-gate')
|
|
1003
|
+
.description('Node-binary port of `hooks/architecture-review-gate.sh` (0.33.0). PostToolUse Write/Edit advisory. Reads `policy.architecture_review.patterns` and prints an advisory banner to stderr when the just-written file matches a configured prefix. ALWAYS exits 0 unless HALT (exit 2). Path normalization handles Windows backslashes + URL-encoding; empty/unset patterns short-circuit silently.')
|
|
1004
|
+
.action(async () => {
|
|
1005
|
+
await runHookArchitectureReviewGate();
|
|
1006
|
+
});
|
|
1007
|
+
hook
|
|
1008
|
+
.command('dangerous-bash-interceptor')
|
|
1009
|
+
.description('Node-binary port of `hooks/dangerous-bash-interceptor.sh` (0.34.0). PreToolUse Bash gate that blocks destructive commands. Catalog of 17 HIGH (H1-H17) + 1 MEDIUM (M1) rules: force-push, --no-verify, HUSKY=0, rm -rf broad targets, curl|sh pipe-RCE, REA_BYPASS, alias/function-with-bypass, psql DROP, context_protection delegate enforcement. Exit 2 on HIGH match, 0 on MEDIUM-only advisory or pass-through.')
|
|
1010
|
+
.action(async () => {
|
|
1011
|
+
await runHookDangerousBashInterceptor();
|
|
1012
|
+
});
|
|
1013
|
+
hook
|
|
1014
|
+
.command('local-review-gate')
|
|
1015
|
+
.description('Node-binary port of `hooks/local-review-gate.sh` (0.34.0). PreToolUse Bash gate refusing `git push` (and optionally `git commit`) until a recent `rea.local_review` audit entry covers HEAD. Honors `policy.review.local_review.{mode=off|enforced, refuse_at=push|commit|both, bypass_env_var}`. Mode=off short-circuits silently; bypass var (default REA_SKIP_LOCAL_REVIEW) accepts process-env (global) or per-segment inline `VAR="<reason>" git push` shapes. CTO directive 2026-05-05 enforcement.')
|
|
1016
|
+
.action(async () => {
|
|
1017
|
+
await runHookLocalReviewGate();
|
|
1018
|
+
});
|
|
1019
|
+
hook
|
|
1020
|
+
.command('secret-scanner')
|
|
1021
|
+
.description('Node-binary port of `hooks/secret-scanner.sh` (0.34.0). PreToolUse Write/Edit/MultiEdit/NotebookEdit pre-write credential gate. Catalog of 12 HIGH + 5 MEDIUM patterns (AWS, Anthropic, GitHub, Stripe live/test, Supabase JWT, generic SECRET=, private-key armor, DB connection strings). awk-style line filter strips shell comments and `process.env.VAR` RHS assignments; `is_placeholder` filter drops `<your_key>`/`test_token`/`aaaaaaa` shapes. HIGH match → exit 2; MEDIUM-only → exit 0 with advisory. Suffix-excludes `.env.example`/`.env.sample`.')
|
|
1022
|
+
.action(async () => {
|
|
1023
|
+
await runHookSecretScanner();
|
|
1024
|
+
});
|
|
976
1025
|
hook
|
|
977
1026
|
.command('policy-get')
|
|
978
1027
|
.description('Read a value from `.rea/policy.yaml` via the canonical YAML parser. Used by bash-tier hooks (`hooks/_lib/policy-read.sh::policy_nested_scalar`) so inline AND block YAML forms agree at a single source of truth. Default scalar mode: prints raw value or empty. With `--json`: emits JSON (scalar or object/array; missing path → `null`). Unparseable YAML → empty / null, exit 1.')
|
|
@@ -68,6 +68,44 @@ export declare class TypePayloadError extends Error {
|
|
|
68
68
|
* non-string type.
|
|
69
69
|
*/
|
|
70
70
|
export declare function parseHookPayload(raw: string | Buffer): HookPayload;
|
|
71
|
+
/**
|
|
72
|
+
* Result of a write-tier hook payload extraction. Covers all four
|
|
73
|
+
* write-class tools (Write, Edit, MultiEdit, NotebookEdit).
|
|
74
|
+
*/
|
|
75
|
+
export interface WriteHookPayload {
|
|
76
|
+
/** `tool_name` from the payload, or `''` when absent. */
|
|
77
|
+
toolName: string;
|
|
78
|
+
/**
|
|
79
|
+
* `tool_input.file_path` (Write/Edit/MultiEdit) OR
|
|
80
|
+
* `tool_input.notebook_path` (NotebookEdit), or `''` when absent.
|
|
81
|
+
*/
|
|
82
|
+
filePath: string;
|
|
83
|
+
/**
|
|
84
|
+
* Concatenated content payload. Resolution order matches
|
|
85
|
+
* `hooks/_lib/payload-read.sh::extract_write_content`:
|
|
86
|
+
*
|
|
87
|
+
* 1. `tool_input.content` (Write)
|
|
88
|
+
* 2. `tool_input.new_string` (Edit)
|
|
89
|
+
* 3. `tool_input.edits[].new_string` joined (MultiEdit, `\n`)
|
|
90
|
+
* 4. `tool_input.new_source` (NotebookEdit cell)
|
|
91
|
+
*
|
|
92
|
+
* Returns `''` when none of these are present. Defensive coercion:
|
|
93
|
+
* a non-string `new_string`, non-array `edits`, or non-string
|
|
94
|
+
* fragments fail closed (treated as missing) rather than throwing —
|
|
95
|
+
* mirrors the bash hook's `.tool_input.new_string // ""` + the
|
|
96
|
+
* type-guard branches added in 0.16.0.
|
|
97
|
+
*/
|
|
98
|
+
content: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Parse a Claude Code Write/Edit/MultiEdit/NotebookEdit stdin payload.
|
|
102
|
+
*
|
|
103
|
+
* Same fail-closed posture as `parseHookPayload`: malformed JSON →
|
|
104
|
+
* throws `MalformedPayloadError`; type-mismatched fields → throws
|
|
105
|
+
* `TypePayloadError`. Callers fail-closed on these for blocking-tier
|
|
106
|
+
* gates (changeset-security-gate refuses on uncertainty).
|
|
107
|
+
*/
|
|
108
|
+
export declare function parseWriteHookPayload(raw: string | Buffer): WriteHookPayload;
|
|
71
109
|
/**
|
|
72
110
|
* Read all of stdin into a string with a soft byte cap and a hard
|
|
73
111
|
* timeout. Mirrors the `readStdinWithTimeout` helper in
|
|
@@ -104,6 +104,85 @@ export function parseHookPayload(raw) {
|
|
|
104
104
|
}
|
|
105
105
|
return { toolName, command };
|
|
106
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Parse a Claude Code Write/Edit/MultiEdit/NotebookEdit stdin payload.
|
|
109
|
+
*
|
|
110
|
+
* Same fail-closed posture as `parseHookPayload`: malformed JSON →
|
|
111
|
+
* throws `MalformedPayloadError`; type-mismatched fields → throws
|
|
112
|
+
* `TypePayloadError`. Callers fail-closed on these for blocking-tier
|
|
113
|
+
* gates (changeset-security-gate refuses on uncertainty).
|
|
114
|
+
*/
|
|
115
|
+
export function parseWriteHookPayload(raw) {
|
|
116
|
+
const text = typeof raw === 'string' ? raw : raw.toString('utf8');
|
|
117
|
+
if (text.trim().length === 0) {
|
|
118
|
+
return { toolName: '', filePath: '', content: '' };
|
|
119
|
+
}
|
|
120
|
+
let parsed;
|
|
121
|
+
try {
|
|
122
|
+
parsed = JSON.parse(text);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
126
|
+
throw new MalformedPayloadError(`hook payload is not valid JSON: ${detail}`);
|
|
127
|
+
}
|
|
128
|
+
if (parsed === null) {
|
|
129
|
+
return { toolName: '', filePath: '', content: '' };
|
|
130
|
+
}
|
|
131
|
+
if (typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
132
|
+
throw new MalformedPayloadError(`hook payload top-level is ${Array.isArray(parsed) ? 'array' : typeof parsed}, expected object`);
|
|
133
|
+
}
|
|
134
|
+
const toolName = typeof parsed.tool_name === 'string' ? parsed.tool_name : '';
|
|
135
|
+
const ti = parsed.tool_input;
|
|
136
|
+
let filePath = '';
|
|
137
|
+
let content = '';
|
|
138
|
+
if (ti !== undefined && ti !== null) {
|
|
139
|
+
if (typeof ti !== 'object') {
|
|
140
|
+
throw new TypePayloadError(`hook payload tool_input is ${typeof ti}, expected object`);
|
|
141
|
+
}
|
|
142
|
+
// file_path or notebook_path. Both are optional; either string or absent.
|
|
143
|
+
if (ti.file_path !== undefined) {
|
|
144
|
+
if (typeof ti.file_path !== 'string') {
|
|
145
|
+
throw new TypePayloadError(`hook payload tool_input.file_path is ${typeof ti.file_path}, expected string`);
|
|
146
|
+
}
|
|
147
|
+
filePath = ti.file_path;
|
|
148
|
+
}
|
|
149
|
+
else if (ti.notebook_path !== undefined) {
|
|
150
|
+
if (typeof ti.notebook_path !== 'string') {
|
|
151
|
+
throw new TypePayloadError(`hook payload tool_input.notebook_path is ${typeof ti.notebook_path}, expected string`);
|
|
152
|
+
}
|
|
153
|
+
filePath = ti.notebook_path;
|
|
154
|
+
}
|
|
155
|
+
// Content extraction — same priority order as the bash hook.
|
|
156
|
+
if (typeof ti.content === 'string' && ti.content.length > 0) {
|
|
157
|
+
content = ti.content;
|
|
158
|
+
}
|
|
159
|
+
else if (typeof ti.new_string === 'string' && ti.new_string.length > 0) {
|
|
160
|
+
content = ti.new_string;
|
|
161
|
+
}
|
|
162
|
+
else if (Array.isArray(ti.edits) && ti.edits.length > 0) {
|
|
163
|
+
// Defensive: non-string `new_string` fragments collapse to ''
|
|
164
|
+
// (matches the bash helper's `// ""` + `tostring`). The
|
|
165
|
+
// concatenation order is bash hook's `join("\n")`.
|
|
166
|
+
const parts = [];
|
|
167
|
+
for (const edit of ti.edits) {
|
|
168
|
+
if (edit === null || typeof edit !== 'object')
|
|
169
|
+
continue;
|
|
170
|
+
const e = edit;
|
|
171
|
+
if (typeof e.new_string === 'string') {
|
|
172
|
+
parts.push(e.new_string);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
parts.push('');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
content = parts.join('\n');
|
|
179
|
+
}
|
|
180
|
+
else if (typeof ti.new_source === 'string' && ti.new_source.length > 0) {
|
|
181
|
+
content = ti.new_source;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return { toolName, filePath, content };
|
|
185
|
+
}
|
|
107
186
|
/**
|
|
108
187
|
* Read all of stdin into a string with a soft byte cap and a hard
|
|
109
188
|
* timeout. Mirrors the `readStdinWithTimeout` helper in
|
|
@@ -69,6 +69,14 @@ export interface CommandSegment {
|
|
|
69
69
|
* Split `cmd` into segments using the quote-aware masking → split →
|
|
70
70
|
* unmask pipeline. Returns an array of `{ raw, head }` tuples in the
|
|
71
71
|
* order they appeared in the original command.
|
|
72
|
+
*
|
|
73
|
+
* 0.33.0 — nested-shell unwrapping was added on top of the original
|
|
74
|
+
* 0.32.0 splitter. When a segment's head is `bash -c|-lc|--c PAYLOAD`
|
|
75
|
+
* or `sh -c|-lc|--c PAYLOAD` (any combination of `-l` and `-c` flags),
|
|
76
|
+
* the PAYLOAD inside the quoted arg becomes additional segments
|
|
77
|
+
* appended after the wrapper segment. Mirrors the bash counterpart's
|
|
78
|
+
* `_rea_unwrap_nested_shells` (helix-017 #3 fix). Recurses up to
|
|
79
|
+
* `MAX_NESTED_DEPTH` levels.
|
|
72
80
|
*/
|
|
73
81
|
export declare function splitSegments(cmd: string): CommandSegment[];
|
|
74
82
|
/**
|
|
@@ -98,3 +106,122 @@ export declare function anySegmentStartsWith(cmd: string, regexSource: string):
|
|
|
98
106
|
* Case-INSENSITIVE, extended regex. Same posture as the bash helper.
|
|
99
107
|
*/
|
|
100
108
|
export declare function anySegmentMatches(cmd: string, regexSource: string): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Returns true if any single segment's RAW text contains matches for
|
|
111
|
+
* BOTH `regexA` AND `regexB`. Mirrors `any_segment_matches_both` from
|
|
112
|
+
* the bash counterpart — used by `env-file-protection` to require that
|
|
113
|
+
* a text-reading utility AND an `.env*` filename co-occur within the
|
|
114
|
+
* same shell segment (a multi-segment construction like
|
|
115
|
+
* `echo "log: cat .env stuff" ; touch foo.env` must NOT fire because
|
|
116
|
+
* the utility and filename live in different segments).
|
|
117
|
+
*
|
|
118
|
+
* Case-INSENSITIVE, extended regex on both patterns. Same posture as
|
|
119
|
+
* the bash helper.
|
|
120
|
+
*
|
|
121
|
+
* 0.33.0 port. The bash helper was introduced in 0.16.2 to fix the
|
|
122
|
+
* helix-017 P2 false-positive class where two independent booleans
|
|
123
|
+
* (any-utility OR any-env) were AND'd across segments.
|
|
124
|
+
*/
|
|
125
|
+
export declare function anySegmentMatchesBoth(cmd: string, regexA: string, regexB: string): boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Returns true if any segment's RAW text (env-var prefixes intact, only
|
|
128
|
+
* leading whitespace trimmed) matches the regex source. Mirrors
|
|
129
|
+
* `any_segment_raw_matches` in the bash counterpart — used by checks
|
|
130
|
+
* where the env-prefix itself IS the signal (`HUSKY=0 git`, `REA_BYPASS=`,
|
|
131
|
+
* `alias … = HUSKY=0`).
|
|
132
|
+
*
|
|
133
|
+
* 0.34.0 port — dangerous-bash-interceptor (H10, H15, H16) and
|
|
134
|
+
* local-review-gate (env-prefix git push detection) call into this.
|
|
135
|
+
* Note: callers anchor with `^` in the regex source when they want
|
|
136
|
+
* "starts at segment head"; we do not prepend `^` here.
|
|
137
|
+
*/
|
|
138
|
+
export declare function anySegmentRawMatches(cmd: string, regexSource: string): boolean;
|
|
139
|
+
/**
|
|
140
|
+
* Returns true if any segment's RAW text contains a match for the
|
|
141
|
+
* regex source. Mirrors `any_segment_matches` in the bash counterpart —
|
|
142
|
+
* used by content-scan style checks. The regex matches anywhere in the
|
|
143
|
+
* segment (not anchored). Useful for `(psql|pgcli)[^|&;]*DROP[[:space:]]+(TABLE|…)`
|
|
144
|
+
* style patterns that must match across the whole segment but only
|
|
145
|
+
* within a single segment (a heredoc body in segment N or commit
|
|
146
|
+
* message in segment 1 must NOT poison segment N+1).
|
|
147
|
+
*
|
|
148
|
+
* 0.34.0 port — dangerous-bash-interceptor H6 calls into this.
|
|
149
|
+
*/
|
|
150
|
+
export declare function anySegmentContains(cmd: string, regexSource: string): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Iterate over every segment of `cmd` and invoke `callback(raw, head)`
|
|
153
|
+
* for each. Mirrors `for_each_segment` in the bash counterpart —
|
|
154
|
+
* dangerous-bash-interceptor H1 uses this to walk each push segment
|
|
155
|
+
* independently (since one segment may include `--force-with-lease`
|
|
156
|
+
* while another carries an unsafe `--force`).
|
|
157
|
+
*
|
|
158
|
+
* The callback receives the raw segment (env-prefix preserved) and the
|
|
159
|
+
* prefix-stripped head. Return value is ignored.
|
|
160
|
+
*
|
|
161
|
+
* 0.34.0 port.
|
|
162
|
+
*/
|
|
163
|
+
export declare function forEachSegment(cmd: string, callback: (raw: string, head: string) => void): void;
|
|
164
|
+
/**
|
|
165
|
+
* Quote-aware mask of in-quote separators. Mirrors `quote_masked_cmd`
|
|
166
|
+
* in the bash counterpart — produces a string where in-quote `|` / `;`
|
|
167
|
+
* / `&` characters are replaced with multi-byte sentinels so a caller's
|
|
168
|
+
* regex can match real (unquoted) instances of those bytes without
|
|
169
|
+
* false-positiving on quoted commit-message bodies (`git commit -m
|
|
170
|
+
* "curl|sh later"`).
|
|
171
|
+
*
|
|
172
|
+
* 0.34.0 port — dangerous-bash-interceptor H12 (`curl|sh` detection)
|
|
173
|
+
* uses this to scan the WHOLE command (not split into segments)
|
|
174
|
+
* without quoted-mention false positives.
|
|
175
|
+
*
|
|
176
|
+
* Implementation uses the same sentinel-byte alphabet the bash helper
|
|
177
|
+
* uses. Sentinels are public so callers can `.test()` against the
|
|
178
|
+
* masked output without accidentally tripping on them.
|
|
179
|
+
*/
|
|
180
|
+
export declare const INQUOTE_PIPE_SENTINEL = "__REA_INQUOTE_PIPE_a8f2c1__";
|
|
181
|
+
export declare const INQUOTE_SEMI_SENTINEL = "__REA_INQUOTE_SC_a8f2c1__";
|
|
182
|
+
export declare const INQUOTE_AMP_SENTINEL = "__REA_INQUOTE_AMP_a8f2c1__";
|
|
183
|
+
export declare function quoteMaskedCmd(cmd: string): string;
|
|
184
|
+
/**
|
|
185
|
+
* Walk the nested-shell unwrap chain and emit `cmd` PLUS each inner
|
|
186
|
+
* payload as a separate string. Mirrors `_rea_unwrap_nested_shells`
|
|
187
|
+
* in the bash counterpart.
|
|
188
|
+
*
|
|
189
|
+
* Used by dangerous-bash-interceptor H12 (`curl|sh` detection) so a
|
|
190
|
+
* payload like `zsh -c "curl https://x | sh"` is scanned for the pipe
|
|
191
|
+
* shape even though the literal `|` is inside quotes at the outer
|
|
192
|
+
* level. The H12 check then runs `quoteMaskedCmd` against each
|
|
193
|
+
* emitted line independently.
|
|
194
|
+
*
|
|
195
|
+
* Depth-bounded at MAX_NESTED_DEPTH (8) — same as `splitSegments`.
|
|
196
|
+
*
|
|
197
|
+
* 0.34.0 port.
|
|
198
|
+
*/
|
|
199
|
+
export declare function unwrapNestedShells(cmd: string): string[];
|
|
200
|
+
/**
|
|
201
|
+
* Return every segment of `cmd` whose prefix-stripped head matches the
|
|
202
|
+
* head-anchored regex source. Mirrors `find_all_segments_starting_with`
|
|
203
|
+
* in the bash counterpart.
|
|
204
|
+
*
|
|
205
|
+
* Returns each match as `{ raw, head }` so callers (local-review-gate's
|
|
206
|
+
* round-25 P1-B sweep) can validate per-segment bypass against the
|
|
207
|
+
* raw (env-prefix-intact) form.
|
|
208
|
+
*
|
|
209
|
+
* Case-INSENSITIVE. Empty array on no matches.
|
|
210
|
+
*
|
|
211
|
+
* 0.34.0 port.
|
|
212
|
+
*/
|
|
213
|
+
export declare function findAllSegmentsStartingWith(cmd: string, regexSource: string): CommandSegment[];
|
|
214
|
+
/**
|
|
215
|
+
* Return every segment of `cmd` whose RAW text (env-prefix intact,
|
|
216
|
+
* leading whitespace trimmed) matches the regex source. Mirrors
|
|
217
|
+
* `find_all_segments_raw_matches` in the bash counterpart.
|
|
218
|
+
*
|
|
219
|
+
* Companion to `findAllSegmentsStartingWith` for the env-prefix shapes
|
|
220
|
+
* the prefix-stripper bails on (quoted-value env-vars like
|
|
221
|
+
* `REA_SKIP="urgent fix"`).
|
|
222
|
+
*
|
|
223
|
+
* Case-INSENSITIVE. Empty array on no matches.
|
|
224
|
+
*
|
|
225
|
+
* 0.34.0 port.
|
|
226
|
+
*/
|
|
227
|
+
export declare function findAllSegmentsRawMatches(cmd: string, regexSource: string): CommandSegment[];
|