@cybedefend/vibedefend 1.4.2 → 1.4.3
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/README.md +3 -1
- package/dist/clients/claude-code.js +4 -1
- package/dist/clients/claude-code.js.map +1 -1
- package/dist/clients/codex.js +4 -2
- package/dist/clients/codex.js.map +1 -1
- package/dist/hook-runner.js +938 -672
- package/dist/hooks/runtime/emit.js +25 -12
- package/dist/hooks/runtime/emit.js.map +1 -1
- package/dist/hooks/runtime/fetch-rules.js +38 -12
- package/dist/hooks/runtime/fetch-rules.js.map +1 -1
- package/dist/hooks/runtime/session-start.js +5 -1
- package/dist/hooks/runtime/session-start.js.map +1 -1
- package/dist/hooks/runtime/shell-writes.js +311 -0
- package/dist/hooks/runtime/shell-writes.js.map +1 -0
- package/dist/hooks/runtime/sniff.js +84 -5
- package/dist/hooks/runtime/sniff.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which clients need the `hookSpecificOutput.additionalContext` envelope for
|
|
3
|
+
* a given event. Everything not listed here keeps its plain-markdown (or
|
|
4
|
+
* Cursor's own) shape, which is the contract that already works for it.
|
|
5
|
+
*
|
|
6
|
+
* SessionStart deliberately does NOT list claude-code: its plain stdout is
|
|
7
|
+
* delivered by contract today and works — leave it alone (BACK-173 §2).
|
|
8
|
+
*/
|
|
9
|
+
const ENVELOPE_CLIENTS = {
|
|
10
|
+
SessionStart: new Set(['codex']),
|
|
11
|
+
PreToolUse: new Set(['claude-code', 'codex']),
|
|
12
|
+
};
|
|
1
13
|
export function emit(body, client) {
|
|
2
14
|
if (!body)
|
|
3
15
|
return;
|
|
@@ -15,29 +27,30 @@ export function emit(body, client) {
|
|
|
15
27
|
process.stdout.write('\n');
|
|
16
28
|
}
|
|
17
29
|
/**
|
|
18
|
-
*
|
|
30
|
+
* Model-context emission for a given hook event.
|
|
19
31
|
*
|
|
20
|
-
* For
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
32
|
+
* For the clients listed in `ENVELOPE_CLIENTS[hookEventName]`: writes ONE
|
|
33
|
+
* JSON object `{ hookSpecificOutput: { hookEventName, additionalContext } }`
|
|
34
|
+
* so the body lands in the model's context. Callers MUST call this once per
|
|
35
|
+
* hook run — two JSON objects concatenated on stdout are not valid JSON and
|
|
36
|
+
* the agent drops both (see fetch-rules, which accumulates the business and
|
|
37
|
+
* security blocks before emitting).
|
|
24
38
|
*
|
|
25
39
|
* For every other client: delegates to `emit`, which preserves Cursor's
|
|
26
|
-
* permission-allow envelope and
|
|
27
|
-
*
|
|
28
|
-
* SessionStart equivalents.
|
|
40
|
+
* permission-allow envelope and the plain-markdown shape that already works
|
|
41
|
+
* for the remaining client/event pairs.
|
|
29
42
|
*/
|
|
30
|
-
export function emitContext(body, client) {
|
|
43
|
+
export function emitContext(body, client, hookEventName) {
|
|
31
44
|
if (!body)
|
|
32
45
|
return;
|
|
33
|
-
if (client
|
|
46
|
+
if (ENVELOPE_CLIENTS[hookEventName].has(client)) {
|
|
34
47
|
const payload = JSON.stringify({
|
|
35
48
|
hookSpecificOutput: {
|
|
36
|
-
hookEventName
|
|
49
|
+
hookEventName,
|
|
37
50
|
additionalContext: body,
|
|
38
51
|
},
|
|
39
52
|
});
|
|
40
|
-
process.stdout.write(payload);
|
|
53
|
+
process.stdout.write(payload + '\n');
|
|
41
54
|
return;
|
|
42
55
|
}
|
|
43
56
|
emit(body, client);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit.js","sourceRoot":"","sources":["../../../src/hooks/runtime/emit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"emit.js","sourceRoot":"","sources":["../../../src/hooks/runtime/emit.ts"],"names":[],"mappings":"AA0CA;;;;;;;GAOG;AACH,MAAM,gBAAgB,GAAoD;IACxE,YAAY,EAAE,IAAI,GAAG,CAAW,CAAC,OAAO,CAAC,CAAC;IAC1C,UAAU,EAAE,IAAI,GAAG,CAAW,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;CACxD,CAAC;AAEF,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,MAAgB;IACjD,IAAI,CAAC,IAAI;QAAE,OAAO;IAElB,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;YAC7B,UAAU,EAAE,OAAO;YACnB,aAAa,EAAE,IAAI;SACpB,CAAC,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,qCAAqC;IACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CACzB,IAAY,EACZ,MAAgB,EAChB,aAA+B;IAE/B,IAAI,CAAC,IAAI;QAAE,OAAO;IAElB,IAAI,gBAAgB,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;YAC7B,kBAAkB,EAAE;gBAClB,aAAa;gBACb,iBAAiB,EAAE,IAAI;aACxB;SACF,CAAC,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,QAAQ,CACtB,IAAY,EACZ,MAAgB,EAChB,MAAe;IAEf,IAAI,CAAC,IAAI;QAAE,OAAO;IAElB,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC;YACb,QAAQ,EAAE,OAAO;YACjB,MAAM,EAAE,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;SAChD,CAAC,CACH,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACrB,CAAC"}
|
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PreToolUse hook — fetch business rules before
|
|
2
|
+
* PreToolUse hook — fetch business rules before a file is written.
|
|
3
3
|
*
|
|
4
4
|
* Triggered by every agent on every tool call (Cursor and Claude Code
|
|
5
|
-
* honour matchers
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* honour matchers; VS Code ignores matchers, so we self-filter; Windsurf
|
|
6
|
+
* has its own pre_write_code event; Codex uses apply_patch). We early-exit
|
|
7
|
+
* unless the tool name is in our interested set.
|
|
8
|
+
*
|
|
9
|
+
* `Bash` is in that set (BACK-173 follow-up): a shell command that writes
|
|
10
|
+
* files — `cat > f <<EOF`, `sed -i`, `tee`, `cp`… — fetches the rules for
|
|
11
|
+
* every file it targets, exactly like the edit tools. Without it an agent
|
|
12
|
+
* writing through the shell bypassed rules injection entirely, which is the
|
|
13
|
+
* common path in practice. A read-only shell command has no targets and
|
|
14
|
+
* exits silently (see `sniff` + `shell-writes`).
|
|
9
15
|
*/
|
|
10
16
|
import { sniff } from './sniff.js';
|
|
11
17
|
import { resolveProjectIdWithApi, resolveToken, } from './resolve.js';
|
|
12
18
|
import { fetchBusinessRules, fetchSecurityRules } from './api.js';
|
|
13
|
-
import {
|
|
19
|
+
import { emitContext } from './emit.js';
|
|
14
20
|
import { loadRuntimeConfig, readStdinJson } from './config.js';
|
|
21
|
+
/**
|
|
22
|
+
* Production emitter: the rules body must reach the MODEL, and on Claude
|
|
23
|
+
* Code / Codex a PreToolUse hook's plain stdout never does (BACK-173) — it
|
|
24
|
+
* has to travel in a `hookSpecificOutput.additionalContext` envelope whose
|
|
25
|
+
* `hookEventName` names THIS hook.
|
|
26
|
+
*/
|
|
27
|
+
function emitPreToolUseContext(body, client) {
|
|
28
|
+
emitContext(body, client, 'PreToolUse');
|
|
29
|
+
}
|
|
15
30
|
const INTERESTED_TOOLS = new Set([
|
|
16
31
|
'Edit',
|
|
17
32
|
'Write',
|
|
18
33
|
'MultiEdit',
|
|
19
34
|
'apply_patch',
|
|
35
|
+
'Bash',
|
|
20
36
|
]);
|
|
21
37
|
export async function fetchRulesHook(deps = {}) {
|
|
22
38
|
const readStdin = deps.readStdin ?? readStdinJson;
|
|
@@ -25,7 +41,7 @@ export async function fetchRulesHook(deps = {}) {
|
|
|
25
41
|
const resolveTok = deps.resolveTokenFn ?? resolveToken;
|
|
26
42
|
const fetchRules = deps.fetchRulesFn ?? fetchBusinessRules;
|
|
27
43
|
const fetchSecRules = deps.fetchSecurityRulesFn ?? fetchSecurityRules;
|
|
28
|
-
const emitFn = deps.emitFn ??
|
|
44
|
+
const emitFn = deps.emitFn ?? emitPreToolUseContext;
|
|
29
45
|
const stdin = await readStdin();
|
|
30
46
|
const event = sniff(stdin);
|
|
31
47
|
// Self-filter: ignore tool calls we don't care about. Crucial for
|
|
@@ -48,11 +64,15 @@ export async function fetchRulesHook(deps = {}) {
|
|
|
48
64
|
if (!token)
|
|
49
65
|
return;
|
|
50
66
|
const intent = buildIntent(event);
|
|
67
|
+
// Edit tools write one file; a shell command may write several — fetch
|
|
68
|
+
// for all of them and label the callout with the whole list.
|
|
69
|
+
const files = event.filePaths.length > 0 ? event.filePaths : [event.filePath];
|
|
70
|
+
const fileLabel = files.join(', ');
|
|
51
71
|
const fetchOpts = {
|
|
52
72
|
apiBase,
|
|
53
73
|
projectId,
|
|
54
74
|
token,
|
|
55
|
-
files
|
|
75
|
+
files,
|
|
56
76
|
intent,
|
|
57
77
|
topK: 5,
|
|
58
78
|
};
|
|
@@ -62,17 +82,23 @@ export async function fetchRulesHook(deps = {}) {
|
|
|
62
82
|
fetchRules(fetchOpts),
|
|
63
83
|
fetchSecRules(fetchOpts),
|
|
64
84
|
]);
|
|
85
|
+
// Accumulate, then emit ONCE. On Claude Code / Codex the emitter writes a
|
|
86
|
+
// JSON envelope; two envelopes concatenated on stdout are not JSON and the
|
|
87
|
+
// agent drops both — so both blocks ride in a single body (BACK-173 §1).
|
|
88
|
+
const blocks = [];
|
|
65
89
|
if (businessResult) {
|
|
66
|
-
const body = composeBody(businessResult.markdown, businessResult.total,
|
|
90
|
+
const body = composeBody(businessResult.markdown, businessResult.total, fileLabel);
|
|
67
91
|
if (body)
|
|
68
|
-
|
|
92
|
+
blocks.push(body);
|
|
69
93
|
}
|
|
70
94
|
if (securityResult &&
|
|
71
95
|
securityResult.total > 0 &&
|
|
72
96
|
securityResult.markdown &&
|
|
73
97
|
securityResult.markdown.length > 0) {
|
|
74
|
-
|
|
98
|
+
blocks.push(composeSecurityBody(securityResult.markdown, securityResult.total, fileLabel));
|
|
75
99
|
}
|
|
100
|
+
if (blocks.length > 0)
|
|
101
|
+
emitFn(blocks.join('\n'), event.client);
|
|
76
102
|
}
|
|
77
103
|
/** Build the retrieval `intent` string from the event content. */
|
|
78
104
|
function buildIntent(event) {
|
|
@@ -104,7 +130,7 @@ function visibleCalloutTemplate(kind, total, filePath) {
|
|
|
104
130
|
return [
|
|
105
131
|
'---',
|
|
106
132
|
'',
|
|
107
|
-
`**🛡️ REQUIRED USER-VISIBLE MARKER** — you MUST include this exact block as the FIRST paragraph of your next assistant reply, BEFORE the
|
|
133
|
+
`**🛡️ REQUIRED USER-VISIBLE MARKER** — you MUST include this exact block as the FIRST paragraph of your next assistant reply, BEFORE the tool call that writes the file. Do not paraphrase, do not skip — without it, the user cannot see CybeDefend is influencing the change.`,
|
|
108
134
|
'',
|
|
109
135
|
`> 🛡️ **CybeDefend ${kind} Rules** — ${total} rule${total === 1 ? '' : 's'} for \`${filePath}\``,
|
|
110
136
|
`> - **<rule-title>** [<severity> · <category>] — applies because <one-sentence reason>`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-rules.js","sourceRoot":"","sources":["../../../src/hooks/runtime/fetch-rules.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fetch-rules.js","sourceRoot":"","sources":["../../../src/hooks/runtime/fetch-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,10 @@ import { emitContext } from './emit.js';
|
|
|
15
15
|
import { loadRuntimeConfig, readStdinJson } from './config.js';
|
|
16
16
|
import { selfUpdateCheck } from './self-update-check.js';
|
|
17
17
|
import { pkg } from '../../version.js';
|
|
18
|
+
/** Production emitter — the envelope's `hookEventName` must name THIS hook. */
|
|
19
|
+
function emitSessionStartContext(body, client) {
|
|
20
|
+
emitContext(body, client, 'SessionStart');
|
|
21
|
+
}
|
|
18
22
|
export async function sessionStartHook(deps = {}) {
|
|
19
23
|
const readStdin = deps.readStdin ?? readStdinJson;
|
|
20
24
|
const loadConfig = deps.loadConfig ?? loadRuntimeConfig;
|
|
@@ -25,7 +29,7 @@ export async function sessionStartHook(deps = {}) {
|
|
|
25
29
|
// SessionStart context goes through `emitContext`, not `emit`, so the
|
|
26
30
|
// body lands inside Codex's `additionalContext` JSON envelope (and as
|
|
27
31
|
// plain markdown for everyone else). See emit.ts for the rationale.
|
|
28
|
-
const emitFn = deps.emitFn ??
|
|
32
|
+
const emitFn = deps.emitFn ?? emitSessionStartContext;
|
|
29
33
|
const stdin = await readStdin();
|
|
30
34
|
const event = sniff(stdin);
|
|
31
35
|
const config = loadConfig();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-start.js","sourceRoot":"","sources":["../../../src/hooks/runtime/session-start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,YAAY,GAEb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"session-start.js","sourceRoot":"","sources":["../../../src/hooks/runtime/session-start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,YAAY,GAEb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAoBvC,+EAA+E;AAC/E,SAAS,uBAAuB,CAAC,IAAY,EAAE,MAAgB;IAC7D,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAyB,EAAE;IAE3B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,aAAa,CAAC;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,iBAAiB,CAAC;IACxD,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,uBAAuB,CAAC;IACtE,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,IAAI,YAAY,CAAC;IACvD,MAAM,cAAc,GAAG,IAAI,CAAC,gBAAgB,IAAI,mBAAmB,CAAC;IACpE,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,IAAI,eAAe,CAAC;IACpE,sEAAsE;IACtE,sEAAsE;IACtE,oEAAoE;IACpE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,uBAAuB,CAAC;IAEtD,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM;QAAE,OAAO;IAEpB,qEAAqE;IACrE,gEAAgE;IAChE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;IACrE,IAAI,CAAC,SAAS;QAAE,OAAO;IAEvB,MAAM,OAAO,GACX,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,aAAa,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;IAE5E,oEAAoE;IACpE,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,GAAG,EAAE,CAAC;QAC3C,MAAM,CACJ,oDAAoD,KAAK,CAAC,MAAM,iBAAiB,SAAS,IAAI,EAC9F,KAAK,CAAC,MAAM,CACb,CAAC;QACF,OAAO;IACT,CAAC;IAED,2EAA2E;IAC3E,uEAAuE;IACvE,mEAAmE;IACnE,uEAAuE;IACvE,oEAAoE;IACpE,sEAAsE;IACtE,4DAA4D;IAC5D,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QACnE,IAAI,MAAM;YAAE,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IACnC,CAAC;IAED,MAAM,KAAK,GAAa;QACtB,iCAAiC;QACjC,gBAAgB,SAAS,eAAe,KAAK,CAAC,MAAM,GAAG;KACxD,CAAC;IACF,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,0BAA0B,KAAK,IAAI,CAAC,CAAC;IAClD,CAAC;IACD,KAAK,CAAC,IAAI,CACR,gFAAgF,EAChF,mFAAmF,CACpF,CAAC;IAEF,iEAAiE;IACjE,oEAAoE;IACpE,qEAAqE;IACrE,kEAAkE;IAClE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,oEAAoE;QACpE,oEAAoE;QACpE,iEAAiE;QACjE,KAAK,CAAC,IAAI,CACR,8EAA8E,EAC9E,gFAAgF,EAChF,mEAAmE,CACpE,CAAC;IACJ,CAAC;SAAM,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CACR,sFAAsF,CACvF,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CACR,mCAAmC,KAAK,+BAA+B,EACvE,2EAA2E,EAC3E,gFAAgF,EAChF,8CAA8C,CAC/C,CAAC;IACJ,CAAC;IAED,6DAA6D;IAC7D,0EAA0E;IAC1E,uEAAuE;IACvE,wEAAwE;IACxE,sEAAsE;IACtE,0EAA0E;IAC1E,6EAA6E;IAC7E,EAAE;IACF,sEAAsE;IACtE,0EAA0E;IAC1E,mEAAmE;IACnE,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE7E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,IAAI,wBAAwB,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/C,KAAK,CAAC,IAAI,CACR,wEAAwE,EACxE,uEAAuE,EACvE,wEAAwE,EACxE,wEAAwE,EACxE,gEAAgE,CACjE,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,8CAA8C;QAC9C,KAAK,CAAC,IAAI,CACR,sEAAsE,EACtE,2DAA2D,EAC3D,yEAAyE,EACzE,+BAA+B,CAChC,CAAC;IACJ,CAAC;IAED,0EAA0E;IAC1E,sEAAsE;IACtE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;YACrC,uEAAuE;YACvE,oEAAoE;YACpE,sEAAsE;YACtE,sEAAsE;YACtE,gBAAgB,EAAE,GAAG,CAAC,OAAO;YAC7B,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU;YACnC,wEAAwE;YACxE,kEAAkE;YAClE,wDAAwD;YACxD,YAAY,EAAE,MAAM,CAAC,YAAY;SAClC,CAAC,CAAC;QACH,IAAI,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;IAC5D,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which files does a shell command WRITE?
|
|
3
|
+
*
|
|
4
|
+
* BACK-173 follow-up. The `fetch-rules` hook injected business/security rules
|
|
5
|
+
* only for the agent's file-edit tools (Edit / Write / MultiEdit /
|
|
6
|
+
* apply_patch). An agent that writes through the shell — `cat > f <<EOF`,
|
|
7
|
+
* `sed -i`, `tee`, `cp` — never triggered it, so the rules for the files it
|
|
8
|
+
* was actually changing were never fetched. In the field that is the
|
|
9
|
+
* common case, not the exception: control arms of the evaluation study did
|
|
10
|
+
* every write through the shell.
|
|
11
|
+
*
|
|
12
|
+
* This module turns a shell command string into the list of paths it will
|
|
13
|
+
* write to, so the Bash / shell PreToolUse envelope can drive the same
|
|
14
|
+
* rules fetch as a file-edit tool. It is deliberately a RECALL-oriented
|
|
15
|
+
* heuristic: a false positive costs one extra rules lookup, a false
|
|
16
|
+
* negative is a silent bypass.
|
|
17
|
+
*
|
|
18
|
+
* Covered:
|
|
19
|
+
* - output redirections `>`, `>>`, `&>`, `N>` (heredoc bodies are stripped
|
|
20
|
+
* first so a `>` inside the data does not count);
|
|
21
|
+
* - `tee [-a] file...`;
|
|
22
|
+
* - in-place `sed -i` / `sed -i.bak` / `sed -i ''` (macOS) and `perl -pi`;
|
|
23
|
+
* - `cp` / `mv` / `install` destination;
|
|
24
|
+
* - `dd of=`;
|
|
25
|
+
* - `bash|sh|zsh -c '<inner command>'` — recursed once.
|
|
26
|
+
*
|
|
27
|
+
* Not covered (documented limits): inline interpreters (`python -c`,
|
|
28
|
+
* `node -e`), `git apply` / `patch` (targets live inside the patch text),
|
|
29
|
+
* and commands behind `xargs` / `find -exec`.
|
|
30
|
+
*
|
|
31
|
+
* Pure string in, string[] out. Uses `shell-quote`, the same tokenizer the
|
|
32
|
+
* Action Guards preprocessor relies on, so quoting and operators are parsed
|
|
33
|
+
* once, consistently.
|
|
34
|
+
*/
|
|
35
|
+
import { parse as shellParse } from 'shell-quote';
|
|
36
|
+
/** Operators that end a simple command. `|` included: `a | tee f` is two commands. */
|
|
37
|
+
const SEGMENT_OPS = new Set([';', '&&', '||', '|', '|&', '&', '(', ')']);
|
|
38
|
+
/** Interpreters whose `-c` argument is itself a shell command. */
|
|
39
|
+
const SHELL_INTERPRETERS = new Set(['bash', 'sh', 'zsh', 'dash', 'ksh']);
|
|
40
|
+
/** Wrappers that prefix a command without changing what it writes. */
|
|
41
|
+
const TRANSPARENT_PREFIXES = new Set(['sudo', 'doas', 'nohup', 'command', 'time', 'nice', 'env']);
|
|
42
|
+
const HEREDOC_OPEN = /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/;
|
|
43
|
+
function isOp(tok, op) {
|
|
44
|
+
return typeof tok === 'object' && 'op' in tok && (op === undefined || tok.op === op);
|
|
45
|
+
}
|
|
46
|
+
function tokenText(tok) {
|
|
47
|
+
if (typeof tok === 'string')
|
|
48
|
+
return tok;
|
|
49
|
+
if (typeof tok === 'object' && 'pattern' in tok)
|
|
50
|
+
return tok.pattern;
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Remove heredoc BODIES (`<<EOF` … `EOF`) so their content is never parsed
|
|
55
|
+
* as shell. The opener line is kept intact — `cat > f <<'EOF'` and
|
|
56
|
+
* `cat <<EOF > f` both keep their redirect target.
|
|
57
|
+
*/
|
|
58
|
+
export function stripHeredocBodies(command) {
|
|
59
|
+
const lines = command.split('\n');
|
|
60
|
+
const out = [];
|
|
61
|
+
let i = 0;
|
|
62
|
+
while (i < lines.length) {
|
|
63
|
+
const line = lines[i];
|
|
64
|
+
out.push(line);
|
|
65
|
+
const m = HEREDOC_OPEN.exec(line);
|
|
66
|
+
i++;
|
|
67
|
+
if (!m)
|
|
68
|
+
continue;
|
|
69
|
+
const delimiter = m[2];
|
|
70
|
+
// Skip body lines up to and including the terminator. An unterminated
|
|
71
|
+
// heredoc swallows the rest of the command — that is what the shell
|
|
72
|
+
// would do too.
|
|
73
|
+
while (i < lines.length) {
|
|
74
|
+
const body = lines[i];
|
|
75
|
+
i++;
|
|
76
|
+
if (body.trim() === delimiter)
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return out.join('\n');
|
|
81
|
+
}
|
|
82
|
+
function isNoiseTarget(target) {
|
|
83
|
+
if (target.length === 0)
|
|
84
|
+
return true;
|
|
85
|
+
if (target === '-')
|
|
86
|
+
return true;
|
|
87
|
+
if (target.startsWith('/dev/'))
|
|
88
|
+
return true;
|
|
89
|
+
if (/^&?\d+$/.test(target))
|
|
90
|
+
return true; // fd numbers (`>&2`, `2>&1`)
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
/** Targets of a single simple command (no operators), from its argv. */
|
|
94
|
+
function targetsFromArgv(argv, depth) {
|
|
95
|
+
// Peel `VAR=value` assignments and transparent wrappers.
|
|
96
|
+
let i = 0;
|
|
97
|
+
while (i < argv.length) {
|
|
98
|
+
const tok = argv[i];
|
|
99
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(tok)) {
|
|
100
|
+
i++;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (TRANSPARENT_PREFIXES.has(tok)) {
|
|
104
|
+
i++;
|
|
105
|
+
// `env -u VAR cmd`, `env VAR=x cmd`: drop env's own options too.
|
|
106
|
+
if (tok === 'env') {
|
|
107
|
+
while (i < argv.length && (argv[i].startsWith('-') || /^[A-Za-z_][A-Za-z0-9_]*=/.test(argv[i]))) {
|
|
108
|
+
if (argv[i] === '-u' || argv[i] === '--unset')
|
|
109
|
+
i++;
|
|
110
|
+
i++;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
const cmd = argv[i] ?? '';
|
|
118
|
+
const args = argv.slice(i + 1);
|
|
119
|
+
const base = cmd.split('/').pop() ?? cmd;
|
|
120
|
+
if (SHELL_INTERPRETERS.has(base)) {
|
|
121
|
+
const c = args.indexOf('-c');
|
|
122
|
+
if (c >= 0 && typeof args[c + 1] === 'string' && depth < 1) {
|
|
123
|
+
return extractShellWriteTargetsAt(args[c + 1], depth + 1);
|
|
124
|
+
}
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
if (base === 'tee') {
|
|
128
|
+
return args.filter((a) => !a.startsWith('-') && !isNoiseTarget(a));
|
|
129
|
+
}
|
|
130
|
+
if (base === 'sed' || base === 'gsed') {
|
|
131
|
+
return sedTargets(args);
|
|
132
|
+
}
|
|
133
|
+
if (base === 'perl') {
|
|
134
|
+
return perlTargets(args);
|
|
135
|
+
}
|
|
136
|
+
if (base === 'cp' || base === 'mv' || base === 'install') {
|
|
137
|
+
const positional = args.filter((a) => !a.startsWith('-') || a === '-');
|
|
138
|
+
if (positional.length >= 2) {
|
|
139
|
+
const tFlag = args.findIndex((a) => a === '-t' || a === '--target-directory');
|
|
140
|
+
if (tFlag >= 0 && args[tFlag + 1])
|
|
141
|
+
return [args[tFlag + 1]];
|
|
142
|
+
return [positional[positional.length - 1]];
|
|
143
|
+
}
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
if (base === 'dd') {
|
|
147
|
+
return args.filter((a) => a.startsWith('of=')).map((a) => a.slice(3)).filter((a) => !isNoiseTarget(a));
|
|
148
|
+
}
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* `sed`: only in-place edits write. GNU `-i[SUFFIX]` / `--in-place[=SUFFIX]`,
|
|
153
|
+
* BSD/macOS `-i ''` (empty suffix as a separate token) and `-i .bak`.
|
|
154
|
+
* Files are the positional args once the script (`-e`, `-f`, or the first
|
|
155
|
+
* bare arg) is accounted for.
|
|
156
|
+
*/
|
|
157
|
+
function sedTargets(args) {
|
|
158
|
+
let inPlace = false;
|
|
159
|
+
let scriptGiven = false;
|
|
160
|
+
const files = [];
|
|
161
|
+
let i = 0;
|
|
162
|
+
while (i < args.length) {
|
|
163
|
+
const a = args[i];
|
|
164
|
+
if (a === '--') {
|
|
165
|
+
files.push(...args.slice(i + 1).filter((f) => f.length > 0));
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
if (a === '-i' || a === '--in-place') {
|
|
169
|
+
inPlace = true;
|
|
170
|
+
// BSD sed: the suffix is the NEXT token (possibly '').
|
|
171
|
+
const next = args[i + 1];
|
|
172
|
+
if (typeof next === 'string' && (next === '' || /^\.[A-Za-z0-9_-]+$/.test(next)))
|
|
173
|
+
i++;
|
|
174
|
+
i++;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (/^-i/.test(a) || a.startsWith('--in-place=')) {
|
|
178
|
+
inPlace = true;
|
|
179
|
+
i++;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (a === '-e' || a === '--expression' || a === '-f' || a === '--file') {
|
|
183
|
+
scriptGiven = true;
|
|
184
|
+
i += 2;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (a.startsWith('--expression=') || a.startsWith('--file=')) {
|
|
188
|
+
scriptGiven = true;
|
|
189
|
+
i++;
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (a.startsWith('-') && a.length > 1) {
|
|
193
|
+
// Combined short flags such as `-ni`, `-Ei`, `-E`.
|
|
194
|
+
if (/^-[A-Za-z]*i/.test(a))
|
|
195
|
+
inPlace = true;
|
|
196
|
+
i++;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (!scriptGiven) {
|
|
200
|
+
scriptGiven = true; // first bare arg is the script
|
|
201
|
+
i++;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (a.length > 0)
|
|
205
|
+
files.push(a);
|
|
206
|
+
i++;
|
|
207
|
+
}
|
|
208
|
+
return inPlace ? files : [];
|
|
209
|
+
}
|
|
210
|
+
/** `perl -pi -e '...' files` / `perl -i.bak -pe '...' files`. */
|
|
211
|
+
function perlTargets(args) {
|
|
212
|
+
let inPlace = false;
|
|
213
|
+
const files = [];
|
|
214
|
+
let i = 0;
|
|
215
|
+
while (i < args.length) {
|
|
216
|
+
const a = args[i];
|
|
217
|
+
if (a === '-e' || a === '-E') {
|
|
218
|
+
i += 2;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (a.startsWith('-')) {
|
|
222
|
+
// Clusters may carry digits: `-0pi` (slurp mode, observed on Codex),
|
|
223
|
+
// `-00pe`. The `i` anywhere in the cluster means in-place.
|
|
224
|
+
if (/^-[A-Za-z0-9]*i/.test(a))
|
|
225
|
+
inPlace = true;
|
|
226
|
+
// `-pe '...'`, `-ne '...'`: the e is inside the cluster, script follows.
|
|
227
|
+
if (/e$/.test(a) && !/^-i/.test(a))
|
|
228
|
+
i++;
|
|
229
|
+
i++;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
files.push(a);
|
|
233
|
+
i++;
|
|
234
|
+
}
|
|
235
|
+
return inPlace ? files : [];
|
|
236
|
+
}
|
|
237
|
+
function extractShellWriteTargetsAt(command, depth) {
|
|
238
|
+
let tokens;
|
|
239
|
+
try {
|
|
240
|
+
tokens = shellParse(stripHeredocBodies(command), (key) => `$${key}`);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
const targets = [];
|
|
246
|
+
let argv = [];
|
|
247
|
+
const flush = () => {
|
|
248
|
+
if (argv.length > 0)
|
|
249
|
+
targets.push(...targetsFromArgv(argv, depth));
|
|
250
|
+
argv = [];
|
|
251
|
+
};
|
|
252
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
253
|
+
const tok = tokens[i];
|
|
254
|
+
if (isOp(tok)) {
|
|
255
|
+
// `&>` arrives as `&` immediately followed by `>` — that is a redirect,
|
|
256
|
+
// not a background operator.
|
|
257
|
+
if (tok.op === '&' && isOp(tokens[i + 1], '>'))
|
|
258
|
+
continue;
|
|
259
|
+
if (tok.op === '>' || tok.op === '>>') {
|
|
260
|
+
const next = tokens[i + 1];
|
|
261
|
+
const text = next === undefined ? null : tokenText(next);
|
|
262
|
+
if (text !== null) {
|
|
263
|
+
if (!isNoiseTarget(text))
|
|
264
|
+
targets.push(text);
|
|
265
|
+
i++;
|
|
266
|
+
}
|
|
267
|
+
// A lone fd number before the redirect (`2> err`) is not an argument.
|
|
268
|
+
if (/^\d+$/.test(argv[argv.length - 1] ?? ''))
|
|
269
|
+
argv.pop();
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if (tok.op === '>&') {
|
|
273
|
+
i++; // skip the fd
|
|
274
|
+
if (/^\d+$/.test(argv[argv.length - 1] ?? ''))
|
|
275
|
+
argv.pop();
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (tok.op === '<') {
|
|
279
|
+
// `<file` input redirect or half of a stripped `<<`: skip the operand
|
|
280
|
+
// only when it is a real input file (`<<` leaves the delimiter word).
|
|
281
|
+
const next = tokens[i + 1];
|
|
282
|
+
if (!isOp(next, '<') && !isOp(tokens[i - 1], '<'))
|
|
283
|
+
i++;
|
|
284
|
+
else if (isOp(tokens[i - 1], '<'))
|
|
285
|
+
i++; // heredoc delimiter word
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (SEGMENT_OPS.has(tok.op)) {
|
|
289
|
+
flush();
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
const text = tokenText(tok);
|
|
295
|
+
if (text !== null)
|
|
296
|
+
argv.push(text);
|
|
297
|
+
}
|
|
298
|
+
flush();
|
|
299
|
+
return Array.from(new Set(targets));
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Paths a shell command writes to, in order of appearance, de-duplicated.
|
|
303
|
+
* Relative paths are returned as-is — the caller resolves them against the
|
|
304
|
+
* agent's cwd.
|
|
305
|
+
*/
|
|
306
|
+
export function extractShellWriteTargets(command) {
|
|
307
|
+
if (typeof command !== 'string' || command.trim().length === 0)
|
|
308
|
+
return [];
|
|
309
|
+
return extractShellWriteTargetsAt(command, 0);
|
|
310
|
+
}
|
|
311
|
+
//# sourceMappingURL=shell-writes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-writes.js","sourceRoot":"","sources":["../../../src/hooks/runtime/shell-writes.ts"],"names":[],"mappings":"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"}
|