@aimarket/warden 0.23.0 → 0.24.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/CHANGELOG.md +31 -0
- package/README-es.md +19 -9
- package/README-fr.md +19 -9
- package/README-ru.md +19 -9
- package/README-zh.md +18 -9
- package/README.md +20 -10
- package/codex-hooks/hooks.json +17 -0
- package/codex-hooks/requirements.toml +38 -0
- package/codex-hooks/scripts/codex-hook.mjs +15 -0
- package/codex-hooks/scripts/flow-guard-answer.mjs +228 -0
- package/codex-hooks/scripts/flow-guard-classify.mjs +224 -0
- package/codex-hooks/scripts/flow-guard-codex.mjs +222 -0
- package/codex-hooks/scripts/flow-guard-constraints.mjs +69 -0
- package/codex-hooks/scripts/flow-guard-decode.mjs +149 -0
- package/codex-hooks/scripts/flow-guard-destinations.mjs +158 -0
- package/codex-hooks/scripts/flow-guard-fingerprints.mjs +180 -0
- package/codex-hooks/scripts/flow-guard-fragments.mjs +122 -0
- package/codex-hooks/scripts/flow-guard-instructions.mjs +36 -0
- package/codex-hooks/scripts/flow-guard-labels.mjs +55 -0
- package/codex-hooks/scripts/flow-guard-leak.mjs +135 -0
- package/codex-hooks/scripts/flow-guard-paths.mjs +80 -0
- package/codex-hooks/scripts/flow-guard-policy.mjs +179 -0
- package/codex-hooks/scripts/flow-guard-post.mjs +131 -0
- package/codex-hooks/scripts/flow-guard-pre.mjs +339 -0
- package/codex-hooks/scripts/flow-guard-screen.mjs +558 -0
- package/codex-hooks/scripts/flow-guard-state.mjs +129 -0
- package/codex-hooks/scripts/flow-guard-text.mjs +46 -0
- package/codex-hooks/scripts/flow-guard-types.mjs +2 -0
- package/codex-hooks/scripts/flow-guard-unattended.mjs +22 -0
- package/codex-hooks/scripts/flow-guard.mjs +103 -0
- package/dist/flow-guard-codex.d.ts +32 -0
- package/dist/flow-guard-codex.d.ts.map +1 -0
- package/dist/flow-guard-codex.js +222 -0
- package/dist/flow-guard-codex.js.map +1 -0
- package/dist/flow-guard-paths.d.ts.map +1 -1
- package/dist/flow-guard-paths.js +6 -1
- package/dist/flow-guard-paths.js.map +1 -1
- package/dist/flow-guard-unattended.d.ts +27 -0
- package/dist/flow-guard-unattended.d.ts.map +1 -0
- package/dist/flow-guard-unattended.js +22 -0
- package/dist/flow-guard-unattended.js.map +1 -0
- package/dist/opencode-plugin.d.ts +3 -9
- package/dist/opencode-plugin.d.ts.map +1 -1
- package/dist/opencode-plugin.js +3 -18
- package/dist/opencode-plugin.js.map +1 -1
- package/docs/codex.es.md +260 -0
- package/docs/codex.fr.md +262 -0
- package/docs/codex.md +251 -0
- package/docs/codex.ru.md +254 -0
- package/docs/codex.zh.md +232 -0
- package/docs/flow-guard.es.md +1 -1
- package/docs/flow-guard.fr.md +1 -1
- package/docs/flow-guard.md +1 -1
- package/docs/flow-guard.ru.md +1 -1
- package/docs/flow-guard.zh.md +1 -1
- package/docs/opencode.md +33 -1
- package/docs/scan.es.md +2 -2
- package/docs/scan.fr.md +2 -2
- package/docs/scan.md +2 -2
- package/docs/scan.ru.md +2 -2
- package/docs/scan.zh.md +2 -2
- package/package.json +10 -2
- package/scripts/codex-live-check.sh +109 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// GENERATED from src/flow-guard-state.ts by scripts/sync-flow-guard.mjs. Do not edit; run npm run build.
|
|
2
|
+
/** Flow guard: per-session state under a lock, fingerprint files and the session log. */
|
|
3
|
+
import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { flowPaths, stateDir, sessionKey } from './flow-guard-paths.mjs';
|
|
5
|
+
import { MAX_TEXT } from './flow-guard-text.mjs';
|
|
6
|
+
import { secretPattern } from './flow-guard-fingerprints.mjs';
|
|
7
|
+
import { MAX_FRAGMENT_INDEX, MAX_FRAGMENT_SEEN, SHORT_SIZES } from './flow-guard-fragments.mjs';
|
|
8
|
+
const MAX_SOURCES = 20;
|
|
9
|
+
const MAX_PRIVATE = 50;
|
|
10
|
+
const MAX_FP_BYTES = 32 * 1_048_576;
|
|
11
|
+
export const EMPTY = { v: 1, untrusted: [], private: [], notified: false, full: false };
|
|
12
|
+
export function readFlowState(path) {
|
|
13
|
+
try {
|
|
14
|
+
const s = JSON.parse(readFileSync(path, 'utf8'));
|
|
15
|
+
if (!s || s.v !== 1 || !Array.isArray(s.untrusted) || !Array.isArray(s.private))
|
|
16
|
+
throw new Error('invalid flow state');
|
|
17
|
+
if (s.credentialRead !== undefined && s.credentialRead !== true || s.credentialGrants !== undefined && (!Array.isArray(s.credentialGrants) || s.credentialGrants.length > 32 || !s.credentialGrants.every(v => typeof v === 'string' && /^[0-9a-f]{64}$/.test(v))))
|
|
18
|
+
throw new Error('invalid credential egress state');
|
|
19
|
+
if (s.answerReview !== undefined) {
|
|
20
|
+
const review = s.answerReview;
|
|
21
|
+
if (!review || !Number.isSafeInteger(review.turn) || review.turn < 1 || typeof review.discloseInstruction !== 'boolean' || !Array.isArray(review.sources) || review.sources.length > 4 ||
|
|
22
|
+
!review.sources.every(source => typeof source === 'string' && /^source-[0-9a-f]{16}$/.test(source)) || review.factsSha256 !== undefined && (typeof review.factsSha256 !== 'string' || !/^[0-9a-f]{64}$/.test(review.factsSha256)))
|
|
23
|
+
throw new Error('invalid answer review state');
|
|
24
|
+
if (review.constraintViolations !== undefined && (!Number.isSafeInteger(review.constraintViolations) || review.constraintViolations < 0 || review.constraintViolations > 2064))
|
|
25
|
+
throw new Error('invalid answer review constraints');
|
|
26
|
+
}
|
|
27
|
+
if (s.fragments !== undefined) {
|
|
28
|
+
const f = s.fragments;
|
|
29
|
+
if (!f || ![1, 2].includes(f.v))
|
|
30
|
+
throw new Error('invalid fragment state');
|
|
31
|
+
const valid = (r) => {
|
|
32
|
+
if (!r || typeof r.group !== 'string' || !/^[0-9a-f]{32}$/.test(r.group) || typeof r.hash !== 'string' || !/^[0-9a-f]{32}$/.test(r.hash) ||
|
|
33
|
+
!Number.isSafeInteger(r.offset) || r.offset < 0 || r.offset > MAX_TEXT || r.edge !== undefined && r.edge !== true)
|
|
34
|
+
return false;
|
|
35
|
+
if (f.v === 1)
|
|
36
|
+
return r.size === undefined || Number.isSafeInteger(r.size) && r.size >= 1 && r.size <= 64;
|
|
37
|
+
return typeof r.size === 'number' && Number.isSafeInteger(r.size) && (r.edge ? r.size >= 5 && r.size <= 64 : SHORT_SIZES.includes(r.size));
|
|
38
|
+
};
|
|
39
|
+
if (!Array.isArray(f.index) || f.index.length > MAX_FRAGMENT_INDEX || !f.index.every(valid) ||
|
|
40
|
+
!Array.isArray(f.seen) || f.seen.length > MAX_FRAGMENT_SEEN || !f.seen.every(valid) || f.full !== undefined && f.full !== true)
|
|
41
|
+
throw new Error('invalid fragment state');
|
|
42
|
+
}
|
|
43
|
+
return s;
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
if (err.code === 'ENOENT')
|
|
47
|
+
return { ...EMPTY, untrusted: [], private: [] };
|
|
48
|
+
throw new Error('flow state cannot be read safely');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function withLock(path, action) {
|
|
52
|
+
const lock = `${path}.lock`;
|
|
53
|
+
let fd;
|
|
54
|
+
const deadline = Date.now() + 3000;
|
|
55
|
+
while (fd === undefined) {
|
|
56
|
+
try {
|
|
57
|
+
fd = openSync(lock, 'wx', 0o600);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
if (err.code !== 'EEXIST')
|
|
61
|
+
throw err;
|
|
62
|
+
// A lock older than 10 s is a crashed hook: take it over rather than wedge the session.
|
|
63
|
+
try {
|
|
64
|
+
if (Date.now() - statSync(lock).mtimeMs > 10_000)
|
|
65
|
+
unlinkSync(lock);
|
|
66
|
+
}
|
|
67
|
+
catch { /* raced */ }
|
|
68
|
+
if (Date.now() > deadline)
|
|
69
|
+
throw new Error('flow state is locked');
|
|
70
|
+
const until = Date.now() + 15;
|
|
71
|
+
while (Date.now() < until) { /* short spin; hooks are short-lived */ }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
return action();
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
closeSync(fd);
|
|
79
|
+
try {
|
|
80
|
+
unlinkSync(lock);
|
|
81
|
+
}
|
|
82
|
+
catch { /* gone */ }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function writeAtomic(path, value) {
|
|
86
|
+
const temp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
87
|
+
writeFileSync(temp, JSON.stringify(value), { mode: 0o600 });
|
|
88
|
+
renameSync(temp, path);
|
|
89
|
+
}
|
|
90
|
+
export function updateFlowState(path, change) {
|
|
91
|
+
return withLock(path, () => {
|
|
92
|
+
const s = readFlowState(path);
|
|
93
|
+
change(s);
|
|
94
|
+
s.untrusted = s.untrusted.slice(-MAX_SOURCES);
|
|
95
|
+
s.private = s.private.slice(-MAX_PRIVATE);
|
|
96
|
+
writeAtomic(path, s);
|
|
97
|
+
return s;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
export function appendFp(path, fps) {
|
|
101
|
+
if (!fps.length)
|
|
102
|
+
return true;
|
|
103
|
+
let size = 0;
|
|
104
|
+
try {
|
|
105
|
+
size = statSync(path).size;
|
|
106
|
+
}
|
|
107
|
+
catch { /* new */ }
|
|
108
|
+
if (size > MAX_FP_BYTES)
|
|
109
|
+
return false;
|
|
110
|
+
appendFileSync(path, fps.join('\n') + '\n', { mode: 0o600 });
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
export function log(paths, entry) {
|
|
114
|
+
try {
|
|
115
|
+
mkdirSync(paths.dir, { recursive: true, mode: 0o700 });
|
|
116
|
+
appendFileSync(paths.log, JSON.stringify({ at: new Date().toISOString(), ...entry }) + '\n', { mode: 0o600 });
|
|
117
|
+
}
|
|
118
|
+
catch { /* best effort */ }
|
|
119
|
+
}
|
|
120
|
+
export function safeToolName(name) {
|
|
121
|
+
return /^[A-Za-z0-9_.:-]{1,100}$/.test(name) && !secretPattern([name]) ? name : '[unrecognized tool name]';
|
|
122
|
+
}
|
|
123
|
+
/** Display correlation only, never a pin or authority. No server-authored words. */
|
|
124
|
+
export function warningSourceId(name) {
|
|
125
|
+
return `source-${sessionKey(name).slice(0, 16)}`;
|
|
126
|
+
}
|
|
127
|
+
export function flowStateExists(sessionId, env = process.env) {
|
|
128
|
+
return existsSync(flowPaths(stateDir(env), sessionId).state);
|
|
129
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// GENERATED from src/flow-guard-text.ts by scripts/sync-flow-guard.mjs. Do not edit; run npm run build.
|
|
2
|
+
/** Flow guard: the text a call carries or a result returns, and the hosts named in it. */
|
|
3
|
+
export const MAX_TEXT = 1_048_576;
|
|
4
|
+
export function strings(value, out = [], budget = { left: MAX_TEXT }) {
|
|
5
|
+
if (budget.left <= 0)
|
|
6
|
+
return out;
|
|
7
|
+
if (typeof value === 'string') {
|
|
8
|
+
out.push(value.slice(0, budget.left));
|
|
9
|
+
budget.left -= value.length;
|
|
10
|
+
}
|
|
11
|
+
else if (Array.isArray(value)) {
|
|
12
|
+
// Explicit numeric arrays are another spelling of character codes. Never stringify arbitrary objects.
|
|
13
|
+
if (value.length >= 5 && value.length <= 4096 && value.every(v => typeof v === 'number' && Number.isSafeInteger(v)))
|
|
14
|
+
strings(value.join(' '), out, budget);
|
|
15
|
+
else
|
|
16
|
+
for (const v of value)
|
|
17
|
+
strings(v, out, budget);
|
|
18
|
+
}
|
|
19
|
+
else if (value && typeof value === 'object') {
|
|
20
|
+
const o = value;
|
|
21
|
+
for (const [key, v] of Object.entries(o)) {
|
|
22
|
+
if (budget.omitBinary && key === 'data' && (o.type === 'image' || o.type === 'audio'))
|
|
23
|
+
continue;
|
|
24
|
+
strings(v, out, budget);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
// MCP binary blocks are not text. Their base64 must not exhaust the text budget before a screen's labels,
|
|
30
|
+
// titles or JSON text blocks are read. Arguments still use strings() without this exemption: an outgoing
|
|
31
|
+
// credential disguised as an image's data is still a credential leaving the session.
|
|
32
|
+
export function responseStrings(value) {
|
|
33
|
+
return strings(value, [], { left: MAX_TEXT, omitBinary: true });
|
|
34
|
+
}
|
|
35
|
+
const URL_RE = /\b(?:https?|ftp|wss?):\/\/[^\s<>"']+/gi;
|
|
36
|
+
export function hostsIn(texts) {
|
|
37
|
+
const hosts = new Set();
|
|
38
|
+
for (const t of texts)
|
|
39
|
+
for (const m of t.matchAll(URL_RE)) {
|
|
40
|
+
try {
|
|
41
|
+
hosts.add(new URL(m[0]).hostname.toLowerCase().replace(/\.$/, ''));
|
|
42
|
+
}
|
|
43
|
+
catch { /* an invalid URL grants no host permission */ }
|
|
44
|
+
}
|
|
45
|
+
return [...hosts];
|
|
46
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// GENERATED from src/flow-guard-unattended.ts by scripts/sync-flow-guard.mjs. Do not edit; run npm run build.
|
|
2
|
+
/** Reasons that are about data, never only about an action. */
|
|
3
|
+
export const DATA_REASONS = new Set(['protected_settings', 'secret', 'secret_fragment',
|
|
4
|
+
'paste_after_secret', 'payload_incomplete', 'secret_tracking', 'personal_data', 'private_text', 'credential_egress',
|
|
5
|
+
'secret_to_file']);
|
|
6
|
+
/** Whether an unattended run must refuse this decision. */
|
|
7
|
+
export function refuses(decision, detail, block) {
|
|
8
|
+
if (decision.permissionDecision === 'deny' || block === 'all')
|
|
9
|
+
return true;
|
|
10
|
+
return !!detail.sensitive || (detail.reason !== undefined && DATA_REASONS.has(detail.reason));
|
|
11
|
+
}
|
|
12
|
+
/** `data` or `all` from an environment value; anything else is undefined. */
|
|
13
|
+
export function blockMode(value) {
|
|
14
|
+
return value === 'all' || value === 'data' ? value : undefined;
|
|
15
|
+
}
|
|
16
|
+
/** File paths an apply_patch text adds, updates, moves or deletes. */
|
|
17
|
+
export function patchFiles(patch) {
|
|
18
|
+
const out = [];
|
|
19
|
+
for (const m of patch.matchAll(/^\*\*\* (?:Add|Update|Delete) File: (.+)$|^\*\*\* Move to: (.+)$/gm))
|
|
20
|
+
out.push((m[1] ?? m[2]).trim());
|
|
21
|
+
return [...new Set(out)];
|
|
22
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// GENERATED from src/flow-guard.ts by scripts/sync-flow-guard.mjs. Do not edit; run npm run build.
|
|
2
|
+
/**
|
|
3
|
+
* Flow guard: break the "lethal trifecta" inside a running Claude Code session.
|
|
4
|
+
*
|
|
5
|
+
* Detecting injected instructions is a guess; the same sentence can be reworded,
|
|
6
|
+
* translated or hidden in data. What can be enforced is the combination that makes an
|
|
7
|
+
* injection costly: in one session the agent (1) reads text written by someone else,
|
|
8
|
+
* (2) reads the user's private data and (3) sends something off the machine. Text that
|
|
9
|
+
* arrives through (1) can then tell the model to read with (2) and send with (3).
|
|
10
|
+
*
|
|
11
|
+
* The guard watches every tool call through Claude Code's hooks and keeps per-session
|
|
12
|
+
* state. Once outside text is in the context ("tainted"), and private data has been read,
|
|
13
|
+
* a call that can send data out asks the user first (or is denied, by mode). Independently,
|
|
14
|
+
* a call that carries text the session read from private files is caught by fingerprint:
|
|
15
|
+
* secrets are denied outright, other private text asks. A tool call that would change the
|
|
16
|
+
* guard's own policy or Claude Code's hook settings never passes silently.
|
|
17
|
+
*
|
|
18
|
+
* It does not read the model's mind and does not need to recognise an attack. What it
|
|
19
|
+
* cannot see: prompts submitted before installation, text the model already holds from before the hook was
|
|
20
|
+
* installed, and harm that needs no outbound or destructive call (a wrong answer). For that last one the
|
|
21
|
+
* Stop hook can only tell the user which outside text the answer drew on.
|
|
22
|
+
*
|
|
23
|
+
* Dependency-free on purpose (node: built-ins only): the Claude Code plugin runs a copy of
|
|
24
|
+
* the compiled files on every tool call (claude-plugin/scripts/flow-guard*.mjs; a test keeps
|
|
25
|
+
* each copy identical to its dist/flow-guard*.js).
|
|
26
|
+
*
|
|
27
|
+
* This file is the public API and the hook entry point. The parts are flow-guard-*.ts: the shared
|
|
28
|
+
* types, state paths, operator policy, text extraction, call classification, screen tools,
|
|
29
|
+
* destinations, fingerprints, decoding, credential fragments, leak checks, session state, the
|
|
30
|
+
* PreToolUse and PostToolUse hooks, the prompt and Stop hooks (answer), and the flow-labels report.
|
|
31
|
+
*/
|
|
32
|
+
import { readFileSync } from 'node:fs';
|
|
33
|
+
import { flowPre } from './flow-guard-pre.mjs';
|
|
34
|
+
import { flowPost } from './flow-guard-post.mjs';
|
|
35
|
+
import { flowPrompt, flowStop } from './flow-guard-answer.mjs';
|
|
36
|
+
export { stateDir, flowPaths, isSecretPath, isProtectedPath } from './flow-guard-paths.mjs';
|
|
37
|
+
export { DEFAULT_POLICY, loadPolicy, readPinnedTaskManifest, publicRequestDigest, hostMatches } from './flow-guard-policy.mjs';
|
|
38
|
+
export { hostsIn } from './flow-guard-text.mjs';
|
|
39
|
+
export { classifyShell, classifyCall, resultTaints } from './flow-guard-classify.mjs';
|
|
40
|
+
export { screenFromResult, screenCall, screenObservation, screenTargetEvidence, screenTargetStamp, screenResponseEvidence, screenResponseStamp, screenSecretRead } from './flow-guard-screen.mjs';
|
|
41
|
+
export { destinations, keepsDestination, resolvedContacts, namedByUser } from './flow-guard-destinations.mjs';
|
|
42
|
+
export { normalizeText, fingerprints, withoutRecordIds, piiTokens, secretPattern, secretValues, secretTokens, tokenFingerprints, tokenWindows } from './flow-guard-fingerprints.mjs';
|
|
43
|
+
export { spelledCandidates, characterCodeCandidates, natoCandidates, scanCandidates, candidates } from './flow-guard-decode.mjs';
|
|
44
|
+
export { fragmentFingerprints, checkFragments } from './flow-guard-fragments.mjs';
|
|
45
|
+
export { checkLeak, checkStream } from './flow-guard-leak.mjs';
|
|
46
|
+
export { readFlowState, updateFlowState, flowStateExists } from './flow-guard-state.mjs';
|
|
47
|
+
export { flowPre, flowApproval, flowScreenValidation } from './flow-guard-pre.mjs';
|
|
48
|
+
export { flowPost } from './flow-guard-post.mjs';
|
|
49
|
+
export { ownWords, flowPrompt, instructionText, lastAnswer, flowStop } from './flow-guard-answer.mjs';
|
|
50
|
+
export { checkAnswerConstraints } from './flow-guard-constraints.mjs';
|
|
51
|
+
export { unlabeledTools, flowLabelsReport } from './flow-guard-labels.mjs';
|
|
52
|
+
/** Hook runner shared by the CLI and the plugin script: `pre`, `post`, `prompt` or `stop`, hook JSON on stdin, decision JSON on stdout. */
|
|
53
|
+
export function runFlowHook(event, stdin, env = process.env) {
|
|
54
|
+
let input;
|
|
55
|
+
try {
|
|
56
|
+
input = JSON.parse(stdin || '{}');
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
62
|
+
return undefined;
|
|
63
|
+
if (event === 'pre') {
|
|
64
|
+
const d = flowPre(input, env);
|
|
65
|
+
return d ? JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', ...d } }) : undefined;
|
|
66
|
+
}
|
|
67
|
+
if (event === 'prompt') {
|
|
68
|
+
flowPrompt(input, env);
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
if (event === 'stop') {
|
|
72
|
+
const o = flowStop(input, env);
|
|
73
|
+
return o ? JSON.stringify(o) : undefined;
|
|
74
|
+
}
|
|
75
|
+
if (event === 'post') {
|
|
76
|
+
const o = flowPost(input, env);
|
|
77
|
+
if (!o)
|
|
78
|
+
return undefined;
|
|
79
|
+
return JSON.stringify({ ...(o.systemMessage ? { systemMessage: o.systemMessage } : {}), ...(o.additionalContext ? { hookSpecificOutput: { hookEventName: 'PostToolUse', additionalContext: o.additionalContext } } : {}) });
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
export function flowGuardMain(argv = process.argv.slice(2)) {
|
|
84
|
+
const event = argv[0] || '';
|
|
85
|
+
let stdin = '';
|
|
86
|
+
try {
|
|
87
|
+
stdin = readFileSync(0, 'utf8');
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const out = runFlowHook(event, stdin);
|
|
94
|
+
if (out)
|
|
95
|
+
process.stdout.write(out + '\n');
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
// Never interpret corrupt/unreadable state as permission to execute a tool.
|
|
99
|
+
process.stderr.write(`warden flow guard: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
100
|
+
if (event === 'pre')
|
|
101
|
+
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: 'WARDEN flow guard could not safely check this call. Repair the guard state before retrying.' } }) + '\n');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type UnattendedBlockMode } from './flow-guard-unattended.js';
|
|
2
|
+
export type CodexBlockMode = UnattendedBlockMode;
|
|
3
|
+
export interface CodexGuardCall {
|
|
4
|
+
name: string;
|
|
5
|
+
input: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
/** The shell text of a Codex command: a string, or an argv where `bash -lc "<script>"` means its script. */
|
|
8
|
+
export declare function commandText(value: unknown): string;
|
|
9
|
+
/** One Codex tool call in the guard's (Claude Code) vocabulary: zero, one or, for a multi-file patch, several calls. */
|
|
10
|
+
export declare function codexGuardCalls(toolName: string, rawInput: unknown): CodexGuardCall[];
|
|
11
|
+
/** The guard's session id for a Codex session: namespaced, so it never shares state with a Claude Code session. */
|
|
12
|
+
export declare function codexSession(input: Record<string, unknown>): string;
|
|
13
|
+
export interface CodexHookOptions {
|
|
14
|
+
block?: CodexBlockMode;
|
|
15
|
+
env?: NodeJS.ProcessEnv;
|
|
16
|
+
}
|
|
17
|
+
/** PreToolUse: a deny, or undefined to let the call run. Never `ask` (Codex runs the call on `ask`). */
|
|
18
|
+
export declare function codexPre(input: Record<string, unknown>, options?: CodexHookOptions): object | undefined;
|
|
19
|
+
/** PostToolUse: records what the result brought in. A failure marks the session so that later calls are denied. */
|
|
20
|
+
export declare function codexPost(input: Record<string, unknown>, options?: CodexHookOptions): object | undefined;
|
|
21
|
+
/** UserPromptSubmit: the destinations the user's own message names. */
|
|
22
|
+
export declare function codexPrompt(input: Record<string, unknown>, options?: CodexHookOptions): undefined;
|
|
23
|
+
/** Stop: the guard's note on the answer. `decision: block` makes Codex continue once with the reason as the prompt. */
|
|
24
|
+
export declare function codexStop(input: Record<string, unknown>, options?: CodexHookOptions): object | undefined;
|
|
25
|
+
declare const EVENTS: readonly ['pre-tool-use', 'post-tool-use', 'user-prompt-submit', 'stop'];
|
|
26
|
+
export type CodexHookEvent = typeof EVENTS[number];
|
|
27
|
+
/** One hook run: the stdout line, or undefined. Throws only on bad input; the caller turns that into a deny. */
|
|
28
|
+
export declare function runCodexHook(event: CodexHookEvent, stdin: string, options?: CodexHookOptions): string | undefined;
|
|
29
|
+
/** `codex-hook.mjs <event>` reads the Codex hook JSON on stdin. Fails closed for PreToolUse. */
|
|
30
|
+
export declare function codexHookMain(argv?: string[], options?: CodexHookOptions): number;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=flow-guard-codex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-guard-codex.d.ts","sourceRoot":"","sources":["../src/flow-guard-codex.ts"],"names":[],"mappings":"AAiCA,OAAO,EAAkC,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEtG,MAAM,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAEjD,MAAM,WAAW,cAAc;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE;AAgBhF,4GAA4G;AAC5G,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQlD;AAED,wHAAwH;AACxH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,cAAc,EAAE,CAwBrF;AAED,mHAAmH;AACnH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAGnE;AAUD,MAAM,WAAW,gBAAgB;IAAG,KAAK,CAAC,EAAE,cAAc,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE;AAYrF,wGAAwG;AACxG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,GAAG,SAAS,CAoB3G;AAED,mHAAmH;AACnH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,GAAG,SAAS,CAkB5G;AAQD,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS,CAKrG;AAED,uHAAuH;AACvH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,GAAG,SAAS,CAI5G;AAED,QAAA,MAAM,MAAM,YAAI,cAAc,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,CAAU,CAAC;AACxF,MAAM,MAAM,cAAc,GAAG,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;AAEnD,gHAAgH;AAChH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,GAAG,SAAS,CAQrH;AAED,gGAAgG;AAChG,wBAAgB,aAAa,CAAC,IAAI,GAAE,MAAM,EAA0B,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAwB5G"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WARDEN flow guard for OpenAI Codex (CLI, desktop app, `codex exec`, a Multica runtime): the checks of the Claude
|
|
3
|
+
* Code plugin, through Codex's command hooks (`hooks.json`, `[hooks]` in `config.toml` or `requirements.toml`).
|
|
4
|
+
*
|
|
5
|
+
* Codex hooks speak nearly the Claude Code hook protocol: the same events, `tool_name`/`tool_input`/`tool_response`,
|
|
6
|
+
* `hookSpecificOutput.permissionDecision`. Three differences decide this adapter:
|
|
7
|
+
*
|
|
8
|
+
* - **No `ask`.** Codex does not support `permissionDecision: "ask"` in PreToolUse: the hook run counts as failed and
|
|
9
|
+
* THE TOOL CALL CONTINUES. Passing the Claude Code decision through would let every questioned call run. Every
|
|
10
|
+
* `ask` therefore becomes `deny` or a logged pass, by `block` (see flow-guard-unattended.ts); this adapter never
|
|
11
|
+
* prints `ask`.
|
|
12
|
+
* - **A failed hook does not stop the call.** An exception in a hook, or output Codex cannot parse, lets the tool
|
|
13
|
+
* run. Every path of PreToolUse that is not a clean "no decision" prints a deny, and a PostToolUse that could not
|
|
14
|
+
* record its result marks the session, so every later call of that session is denied.
|
|
15
|
+
* - **Tool names.** Shell and unified exec arrive as `Bash` with `tool_input.command`; edits as `apply_patch` with the
|
|
16
|
+
* patch in `tool_input.command`; MCP tools as `mcp__<server>__<tool>`; other local tools by their own name.
|
|
17
|
+
* Subagent hooks carry the parent's `session_id`, so a session tree shares one guard state without extra work.
|
|
18
|
+
*
|
|
19
|
+
* Codex's own session ids are namespaced (`codex:<id>`) so they never share state with a Claude Code session.
|
|
20
|
+
* Hosted tools (Codex's own web search) run no local hook: what they bring in is not recorded. Turn web search off
|
|
21
|
+
* for a guarded agent (`web_search = "disabled"`) or accept that gap.
|
|
22
|
+
*
|
|
23
|
+
* Node built-ins and flow-guard parts only: `codex-plugin/scripts` holds copies that run without the package.
|
|
24
|
+
*/
|
|
25
|
+
import { createHash } from 'node:crypto';
|
|
26
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
import { flowPaths, stateDir } from './flow-guard-paths.js';
|
|
29
|
+
import { flowPost } from './flow-guard-post.js';
|
|
30
|
+
import { flowPrompt, flowStop } from './flow-guard-answer.js';
|
|
31
|
+
import { flowPre } from './flow-guard-pre.js';
|
|
32
|
+
import { log } from './flow-guard-state.js';
|
|
33
|
+
import { blockMode, patchFiles, refuses } from './flow-guard-unattended.js';
|
|
34
|
+
/** Local tools that only change Codex's own session state: no data in, no data out. */
|
|
35
|
+
const IGNORED = new Set(['update_plan', 'request_user_input', 'list_mcp_resources', 'list_mcp_resource_templates']);
|
|
36
|
+
const SHELLS = /^(?:\/(?:usr\/)?bin\/)?(?:ba|z|da|k)?sh$/;
|
|
37
|
+
// A PostToolUse input carries the whole tool result (a large file read); too small a cap would skip fingerprinting it.
|
|
38
|
+
const STDIN_BYTES = 16 * 1_048_576;
|
|
39
|
+
function obj(v) {
|
|
40
|
+
return v && typeof v === 'object' && !Array.isArray(v) ? v : {};
|
|
41
|
+
}
|
|
42
|
+
function str(v) {
|
|
43
|
+
return typeof v === 'string' ? v : undefined;
|
|
44
|
+
}
|
|
45
|
+
/** The shell text of a Codex command: a string, or an argv where `bash -lc "<script>"` means its script. */
|
|
46
|
+
export function commandText(value) {
|
|
47
|
+
if (typeof value === 'string')
|
|
48
|
+
return value;
|
|
49
|
+
if (!Array.isArray(value) || !value.every(v => typeof v === 'string'))
|
|
50
|
+
return value === undefined ? '' : JSON.stringify(value);
|
|
51
|
+
const argv = value;
|
|
52
|
+
const flag = argv.findIndex((a, i) => i > 0 && /^-[a-z]*c[a-z]*$/.test(a));
|
|
53
|
+
if (argv.length >= 3 && SHELLS.test(argv[0]) && flag > 0 && flag === argv.length - 2)
|
|
54
|
+
return argv[argv.length - 1];
|
|
55
|
+
// Quote each word, so a word with a space stays one word for the guard's shell parser.
|
|
56
|
+
return argv.map(a => /^[A-Za-z0-9_@%+=:,./-]+$/.test(a) ? a : `'${a.replace(/'/g, `'\\''`)}'`).join(' ');
|
|
57
|
+
}
|
|
58
|
+
/** One Codex tool call in the guard's (Claude Code) vocabulary: zero, one or, for a multi-file patch, several calls. */
|
|
59
|
+
export function codexGuardCalls(toolName, rawInput) {
|
|
60
|
+
const a = obj(rawInput);
|
|
61
|
+
if (IGNORED.has(toolName))
|
|
62
|
+
return [];
|
|
63
|
+
if (toolName.startsWith('mcp__'))
|
|
64
|
+
return [{ name: toolName, input: a }];
|
|
65
|
+
switch (toolName) {
|
|
66
|
+
case 'Bash':
|
|
67
|
+
case 'shell':
|
|
68
|
+
case 'exec_command':
|
|
69
|
+
case 'local_shell':
|
|
70
|
+
case 'unified_exec':
|
|
71
|
+
return [{ name: 'Bash', input: { command: commandText(a.command ?? a.cmd) } }];
|
|
72
|
+
case 'apply_patch':
|
|
73
|
+
case 'Edit':
|
|
74
|
+
case 'Write': {
|
|
75
|
+
const text = str(a.command) ?? str(a.patch) ?? str(a.input) ?? (typeof rawInput === 'string' ? rawInput : '');
|
|
76
|
+
const files = patchFiles(text);
|
|
77
|
+
// An unparsable patch is still a write of its whole text somewhere.
|
|
78
|
+
return (files.length ? files : ['']).map(f => ({ name: 'Write', input: { file_path: f, content: text } }));
|
|
79
|
+
}
|
|
80
|
+
case 'view_image': {
|
|
81
|
+
const path = str(a.path) ?? str(a.file_path);
|
|
82
|
+
return [{ name: 'Read', input: path ? { file_path: path } : {} }];
|
|
83
|
+
}
|
|
84
|
+
case 'write_stdin':
|
|
85
|
+
// Input to a running command: its text is what that command receives.
|
|
86
|
+
return [{ name: 'Bash', input: { command: str(a.chars) ?? str(a.input) ?? '' } }];
|
|
87
|
+
}
|
|
88
|
+
// Anything else (spawn_agent, a plugin's tool) is an unlabelled tool: its result is outside text, and it sends
|
|
89
|
+
// when its name or arguments say so.
|
|
90
|
+
return [{ name: `mcp__codex__${toolName.replace(/[^A-Za-z0-9_-]/g, '_')}`, input: a }];
|
|
91
|
+
}
|
|
92
|
+
/** The guard's session id for a Codex session: namespaced, so it never shares state with a Claude Code session. */
|
|
93
|
+
export function codexSession(input) {
|
|
94
|
+
const id = str(input.session_id);
|
|
95
|
+
return id ? `codex:${id}` : '';
|
|
96
|
+
}
|
|
97
|
+
function brokenPath(env, sessionId) {
|
|
98
|
+
return join(stateDir(env), 'codex', 'broken', createHash('sha256').update(sessionId).digest('hex'));
|
|
99
|
+
}
|
|
100
|
+
function deny(reason) {
|
|
101
|
+
return { hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason } };
|
|
102
|
+
}
|
|
103
|
+
function settings(options) {
|
|
104
|
+
const env = options.env ?? process.env;
|
|
105
|
+
return { env, block: options.block ?? blockMode(env.WARDEN_CODEX_BLOCK) ?? 'data' };
|
|
106
|
+
}
|
|
107
|
+
function hookInput(input, call, sessionId) {
|
|
108
|
+
return { session_id: sessionId, tool_name: call.name, tool_input: call.input, cwd: str(input.cwd) || process.cwd(),
|
|
109
|
+
...(input.tool_response !== undefined ? { tool_response: input.tool_response } : {}) };
|
|
110
|
+
}
|
|
111
|
+
/** PreToolUse: a deny, or undefined to let the call run. Never `ask` (Codex runs the call on `ask`). */
|
|
112
|
+
export function codexPre(input, options = {}) {
|
|
113
|
+
const { env, block } = settings(options);
|
|
114
|
+
const sessionId = codexSession(input);
|
|
115
|
+
const tool = str(input.tool_name) ?? '';
|
|
116
|
+
if (!sessionId || !tool)
|
|
117
|
+
return deny('WARDEN flow guard got a Codex hook input without a session or tool name. Refused.');
|
|
118
|
+
if (existsSync(brokenPath(env, sessionId))) {
|
|
119
|
+
return deny('WARDEN flow guard could not record an earlier result of this session, so it cannot judge this call. Refused; start a new session.');
|
|
120
|
+
}
|
|
121
|
+
for (const call of codexGuardCalls(tool, input.tool_input)) {
|
|
122
|
+
const detail = {};
|
|
123
|
+
const decision = flowPre(hookInput(input, call, sessionId), env, 'hook', detail);
|
|
124
|
+
if (!decision)
|
|
125
|
+
continue;
|
|
126
|
+
const refused = refuses(decision, detail, block);
|
|
127
|
+
log(flowPaths(stateDir(env), sessionId), { event: 'codex', tool: call.name, decision: decision.permissionDecision,
|
|
128
|
+
reason: detail.reason, sensitive: !!detail.sensitive, resolution: refused ? 'refused' : 'allowed_unattended', block });
|
|
129
|
+
if (refused) {
|
|
130
|
+
return deny(`${decision.permissionDecisionReason}\nRefused by the WARDEN flow guard (Codex, block=${block}). Do not retry this call in another form; report what was refused.`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
/** PostToolUse: records what the result brought in. A failure marks the session so that later calls are denied. */
|
|
136
|
+
export function codexPost(input, options = {}) {
|
|
137
|
+
const { env } = settings(options);
|
|
138
|
+
const sessionId = codexSession(input);
|
|
139
|
+
const tool = str(input.tool_name) ?? '';
|
|
140
|
+
if (!sessionId || !tool)
|
|
141
|
+
return undefined;
|
|
142
|
+
const warnings = [];
|
|
143
|
+
for (const call of codexGuardCalls(tool, input.tool_input)) {
|
|
144
|
+
let post;
|
|
145
|
+
try {
|
|
146
|
+
post = flowPost(hookInput(input, call, sessionId), env);
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
markBroken(env, sessionId);
|
|
150
|
+
log(flowPaths(stateDir(env), sessionId), { event: 'codex', tool: call.name, resolution: 'record_failed', error: err instanceof Error ? err.name : 'error' });
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const warning = post?.additionalContext || post?.systemMessage;
|
|
154
|
+
if (warning && !warnings.includes(warning))
|
|
155
|
+
warnings.push(warning);
|
|
156
|
+
}
|
|
157
|
+
return warnings.length ? { hookSpecificOutput: { hookEventName: 'PostToolUse', additionalContext: `[WARDEN] ${warnings.join('\n')}` } } : undefined;
|
|
158
|
+
}
|
|
159
|
+
function markBroken(env, sessionId) {
|
|
160
|
+
const path = brokenPath(env, sessionId);
|
|
161
|
+
mkdirSync(join(stateDir(env), 'codex', 'broken'), { recursive: true, mode: 0o700 });
|
|
162
|
+
writeFileSync(path, new Date().toISOString() + '\n', { mode: 0o600 });
|
|
163
|
+
}
|
|
164
|
+
/** UserPromptSubmit: the destinations the user's own message names. */
|
|
165
|
+
export function codexPrompt(input, options = {}) {
|
|
166
|
+
const { env } = settings(options);
|
|
167
|
+
const sessionId = codexSession(input);
|
|
168
|
+
if (sessionId)
|
|
169
|
+
flowPrompt({ ...input, session_id: sessionId }, env);
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
/** Stop: the guard's note on the answer. `decision: block` makes Codex continue once with the reason as the prompt. */
|
|
173
|
+
export function codexStop(input, options = {}) {
|
|
174
|
+
const { env } = settings(options);
|
|
175
|
+
const sessionId = codexSession(input);
|
|
176
|
+
return sessionId ? flowStop({ ...input, session_id: sessionId }, env) : undefined;
|
|
177
|
+
}
|
|
178
|
+
const EVENTS = ['pre-tool-use', 'post-tool-use', 'user-prompt-submit', 'stop'];
|
|
179
|
+
/** One hook run: the stdout line, or undefined. Throws only on bad input; the caller turns that into a deny. */
|
|
180
|
+
export function runCodexHook(event, stdin, options = {}) {
|
|
181
|
+
if (Buffer.byteLength(stdin) > STDIN_BYTES)
|
|
182
|
+
throw new Error('hook input too large');
|
|
183
|
+
const parsed = JSON.parse(stdin || '{}');
|
|
184
|
+
const input = obj(parsed);
|
|
185
|
+
if (input !== parsed)
|
|
186
|
+
throw new Error('hook input is not an object');
|
|
187
|
+
const out = event === 'pre-tool-use' ? codexPre(input, options) : event === 'post-tool-use' ? codexPost(input, options)
|
|
188
|
+
: event === 'user-prompt-submit' ? codexPrompt(input, options) : codexStop(input, options);
|
|
189
|
+
return out ? JSON.stringify(out) : undefined;
|
|
190
|
+
}
|
|
191
|
+
/** `codex-hook.mjs <event>` reads the Codex hook JSON on stdin. Fails closed for PreToolUse. */
|
|
192
|
+
export function codexHookMain(argv = process.argv.slice(2), options = {}) {
|
|
193
|
+
const event = argv[0];
|
|
194
|
+
if (!EVENTS.includes(event)) {
|
|
195
|
+
process.stderr.write(`Usage: codex-hook.mjs ${EVENTS.join('|')} (Codex command hook; reads the hook JSON on stdin)\n`);
|
|
196
|
+
// Codex reads a deny from stdout; a misconfigured PreToolUse hook must not let calls through.
|
|
197
|
+
process.stdout.write(JSON.stringify(deny('WARDEN Codex hook is misconfigured (unknown event). Refused.')) + '\n');
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
let stdin = '';
|
|
201
|
+
try {
|
|
202
|
+
stdin = readFileSync(0, 'utf8');
|
|
203
|
+
const out = runCodexHook(event, stdin, options);
|
|
204
|
+
if (out)
|
|
205
|
+
process.stdout.write(out + '\n');
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
process.stderr.write(`warden codex hook ${event}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
209
|
+
if (event === 'pre-tool-use')
|
|
210
|
+
process.stdout.write(JSON.stringify(deny('WARDEN flow guard could not safely check this call. Repair the guard state before retrying.')) + '\n');
|
|
211
|
+
if (event === 'post-tool-use') {
|
|
212
|
+
try {
|
|
213
|
+
const sessionId = codexSession(obj(JSON.parse(stdin || '{}')));
|
|
214
|
+
if (sessionId)
|
|
215
|
+
markBroken(options.env ?? process.env, sessionId);
|
|
216
|
+
}
|
|
217
|
+
catch { /* the input itself is unreadable: nothing to mark */ }
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return 0;
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=flow-guard-codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-guard-codex.js","sourceRoot":"","sources":["../src/flow-guard-codex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAA4B,MAAM,4BAA4B,CAAC;AAMtG,uFAAuF;AACvF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,6BAA6B,CAAC,CAAC,CAAC;AACpH,MAAM,MAAM,GAAG,0CAA0C,CAAC;AAC1D,uHAAuH;AACvH,MAAM,WAAW,GAAG,EAAE,GAAG,SAAS,CAAC;AAEnC,SAAS,GAAG,CAAC,CAAU;IACrB,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAA4B,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7F,CAAC;AAED,SAAS,GAAG,CAAC,CAAU;IACrB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/C,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QAAE,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/H,MAAM,IAAI,GAAG,KAAiB,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;IACrH,uFAAuF;IACvF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3G,CAAC;AAED,wHAAwH;AACxH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,QAAiB;IACjE,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACxE,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,MAAM,CAAC;QAAC,KAAK,OAAO,CAAC;QAAC,KAAK,cAAc,CAAC;QAAC,KAAK,aAAa,CAAC;QAAC,KAAK,cAAc;YACrF,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QACjF,KAAK,aAAa,CAAC;QAAC,KAAK,MAAM,CAAC;QAAC,KAAK,OAAO,EAAE,CAAC;YAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9G,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;YAC/B,oEAAoE;YACpE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC7G,CAAC;QACD,KAAK,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC7C,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,KAAK,aAAa;YAChB,sEAAsE;YACtE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,+GAA+G;IAC/G,qCAAqC;IACrC,OAAO,CAAC,EAAE,IAAI,EAAE,eAAe,QAAQ,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,YAAY,CAAC,KAA8B;IACzD,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACjC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACjC,CAAC;AAED,SAAS,UAAU,CAAC,GAAsB,EAAE,SAAiB;IAC3D,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACtG,CAAC;AAED,SAAS,IAAI,CAAC,MAAc;IAC1B,OAAO,EAAE,kBAAkB,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,EAAE,wBAAwB,EAAE,MAAM,EAAE,EAAE,CAAC;AAC/H,CAAC;AAID,SAAS,QAAQ,CAAC,OAAyB;IACzC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,MAAM,EAAE,CAAC;AACtF,CAAC;AAED,SAAS,SAAS,CAAC,KAA8B,EAAE,IAAoB,EAAE,SAAiB;IACxF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE;QAChH,GAAG,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC3F,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,QAAQ,CAAC,KAA8B,EAAE,OAAO,GAAqB,EAAE;IACrF,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC,mFAAmF,CAAC,CAAC;IAC1H,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC,mIAAmI,CAAC,CAAC;IACnJ,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACjF,IAAI,CAAC,QAAQ;YAAE,SAAS;QACxB,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACjD,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,kBAAkB;YAC/G,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,oBAAoB,EAAE,KAAK,EAAE,CAAC,CAAC;QACzH,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC,GAAG,QAAQ,CAAC,wBAAwB,oDAAoD,KAAK,qEAAqE,CAAC,CAAC;QAClL,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,SAAS,CAAC,KAA8B,EAAE,OAAO,GAAqB,EAAE;IACtF,MAAM,EAAE,GAAG,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3D,IAAI,IAAI,CAAC;QACT,IAAI,CAAC;YAAC,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;QAAC,CAAC;QAChE,OAAO,GAAG,EAAE,CAAC;YACX,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC3B,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7J,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,EAAE,iBAAiB,IAAI,IAAI,EAAE,aAAa,CAAC;QAC/D,IAAI,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACtJ,CAAC;AAED,SAAS,UAAU,CAAC,GAAsB,EAAE,SAAiB;IAC3D,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACxC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACpF,aAAa,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,WAAW,CAAC,KAA8B,EAAE,OAAO,GAAqB,EAAE;IACxF,MAAM,EAAE,GAAG,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,SAAS;QAAE,UAAU,CAAC,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,GAAG,CAAC,CAAC;IACpE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,uHAAuH;AACvH,MAAM,UAAU,SAAS,CAAC,KAA8B,EAAE,OAAO,GAAqB,EAAE;IACtF,MAAM,EAAE,GAAG,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACtC,OAAO,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACpF,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,cAAc,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,CAAU,CAAC;AAGxF,gHAAgH;AAChH,MAAM,UAAU,YAAY,CAAC,KAAqB,EAAE,KAAa,EAAE,OAAO,GAAqB,EAAE;IAC/F,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACpF,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,IAAI,KAAK,KAAK,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACrE,MAAM,GAAG,GAAG,KAAK,KAAK,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC;QACrH,CAAC,CAAC,KAAK,KAAK,oBAAoB,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC7F,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/C,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,aAAa,CAAC,IAAI,GAAa,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,GAAqB,EAAE;IAClG,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAmB,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;QACxH,8FAA8F;QAC9F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAClH,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,CAAC;QACH,KAAK,GAAG,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAChC,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChD,IAAI,GAAG;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,KAAK,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1G,IAAI,KAAK,KAAK,cAAc;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,6FAA6F,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC/K,IAAI,KAAK,KAAK,eAAe,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC/D,IAAI,SAAS;oBAAE,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACnE,CAAC;YAAC,MAAM,CAAC,CAAC,qDAAqD,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-guard-paths.d.ts","sourceRoot":"","sources":["../src/flow-guard-paths.ts"],"names":[],"mappings":"AAMA,wBAAgB,QAAQ,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAErE;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAG7C,GAAG;IAAQ,KAAK;IAA6B,EAAE;IAA2B,MAAM;IAAkC,GAAG;IAA+B,GAAG;IAA+B,IAAI;IAAgC,GAAG;EACvO;AAMD,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGtD;AAGD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK9C;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAIhF;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAG7D;AAGD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,eAAO,MAAM,YAAY,QAAmI,CAAC;AAE7J,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"flow-guard-paths.d.ts","sourceRoot":"","sources":["../src/flow-guard-paths.ts"],"names":[],"mappings":"AAMA,wBAAgB,QAAQ,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAErE;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAG7C,GAAG;IAAQ,KAAK;IAA6B,EAAE;IAA2B,MAAM;IAAkC,GAAG;IAA+B,GAAG;IAA+B,IAAI;IAAgC,GAAG;EACvO;AAMD,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGtD;AAGD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK9C;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAIhF;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAG7D;AAGD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,eAAO,MAAM,YAAY,QAAmI,CAAC;AAE7J,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAqBxG"}
|
package/dist/flow-guard-paths.js
CHANGED
|
@@ -39,7 +39,7 @@ export function inside(child, parent) {
|
|
|
39
39
|
const p = parent.endsWith(sep) ? parent : parent + sep;
|
|
40
40
|
return child === parent || child.startsWith(p);
|
|
41
41
|
}
|
|
42
|
-
const SECRET_PATH = /(^|\/)(\.ssh|\.aws|\.gnupg|\.kube|\.docker|\.config\/gh|\.config\/gcloud|\.azure|\.password-store|keychains?)(\/|$)|(^|\/)(\.netrc|\.npmrc|\.pypirc|\.git-credentials|\.pgpass|id_(rsa|dsa|ecdsa|ed25519)[^/]*|[^/]*\.(pem|key|p12|pfx|kdbx|keystore|jks)|\.env(\.[^/]*)?|credentials?(\.[^/]*)?|secrets?(\.[^/]*)?)$|(^|\/)\.local\/share\/opencode\/auth\.json$|(^|\/)\.multica\/config\.json$/i;
|
|
42
|
+
const SECRET_PATH = /(^|\/)(\.ssh|\.aws|\.gnupg|\.kube|\.docker|\.config\/gh|\.config\/gcloud|\.azure|\.password-store|keychains?)(\/|$)|(^|\/)(\.netrc|\.npmrc|\.pypirc|\.git-credentials|\.pgpass|id_(rsa|dsa|ecdsa|ed25519)[^/]*|[^/]*\.(pem|key|p12|pfx|kdbx|keystore|jks)|\.env(\.[^/]*)?|credentials?(\.[^/]*)?|secrets?(\.[^/]*)?)$|(^|\/)\.local\/share\/opencode\/auth\.json$|(^|\/)\.multica\/config\.json$|(^|\/)\.codex\/auth\.json$/i;
|
|
43
43
|
export function isSecretPath(path) {
|
|
44
44
|
return SECRET_PATH.test(path.replace(/\\/g, '/'));
|
|
45
45
|
}
|
|
@@ -67,6 +67,11 @@ export function isProtectedPath(path, cwd, env = process.env) {
|
|
|
67
67
|
// OpenCode: its config and plugin folders load (or drop) the guard itself, globally and per project.
|
|
68
68
|
if (/(^|\/)\.config\/opencode(\/|$)/.test(p) || /(^|\/)\.opencode(\/|$)/.test(p) || /(^|\/)opencode\.jsonc?$/.test(p))
|
|
69
69
|
return true;
|
|
70
|
+
// Codex: user, project and system config layers load (or drop) its hooks, the guard among them.
|
|
71
|
+
if (/(^|\/)\.codex(\/|$)/.test(p) || inside(p, '/etc/codex'))
|
|
72
|
+
return true;
|
|
73
|
+
if (env.CODEX_HOME && inside(p, physicalPath(resolve(env.CODEX_HOME)).replace(/\\/g, '/')))
|
|
74
|
+
return true;
|
|
70
75
|
if (/(^|\/)warden\.lock\.json$/.test(p) && inside(p, cwd.replace(/\\/g, '/')))
|
|
71
76
|
return true;
|
|
72
77
|
return false;
|