fix(hooks): do not echo raw input from plugin-hook-bootstrap.js

Rebased onto origin/main (49128b576). Fixtures moved from
scripts/hooks/ to /tmp/ecc-pr2380-fixtures/ per reviewer feedback.

(Original commit b0e49036 was based on cc6724ee; main has since
refactored spawnShell to use a shellArgs variable and added
PowerShell .sh fallback paths. This rebase adapts the
const result = spawnSync(...) + __rawInput tagging pattern to
all three spawnSync call sites in spawnShell.)
This commit is contained in:
chs0813
2026-08-14 22:32:30 +08:00
committed by Your Name
parent c9de8f5b2b
commit a224617abb
3 changed files with 326 additions and 25 deletions
+24 -13
View File
@@ -61,12 +61,14 @@ function runTests() {
let passed = 0;
let failed = 0;
if (test('passes stdin through when required bootstrap inputs are missing', () => {
if (test('emits empty stdout and stderr warning when required bootstrap inputs are missing', () => {
const result = run([], { input: '{"ok":true}' });
assert.strictEqual(result.status, 0);
assert.strictEqual(result.stdout, '{"ok":true}');
assert.strictEqual(result.stderr, '');
// Empty stdout (not the raw input) so the harness falls back to the
// tool_use's original result -- prevents session-transcript bloat.
assert.strictEqual(result.stdout, '');
assert.ok(result.stderr.includes('missing required args'));
})) passed++; else failed++;
if (test('normalizes Windows Git Bash POSIX drive roots', () => {
@@ -143,7 +145,7 @@ process.stdout.write(JSON.stringify({
}
})) passed++; else failed++;
if (test('node mode passes original stdin when child exits cleanly without stdout', () => {
if (test('node mode emits empty stdout when child exits cleanly without stdout', () => {
const root = createTempDir();
try {
writeFile(root, path.join('scripts', 'silent.js'), 'process.exit(0);\n');
@@ -154,7 +156,10 @@ process.stdout.write(JSON.stringify({
});
assert.strictEqual(result.status, 0);
assert.strictEqual(result.stdout, 'raw-input');
// Empty stdout (not the raw input) -- the dominant source of
// session-transcript bloat pre-fix.
assert.strictEqual(result.stdout, '');
assert.ok(result.stderr.includes('emitting empty stdout'));
} finally {
cleanup(root);
}
@@ -225,7 +230,7 @@ process.exit(7);
}
})) passed++; else failed++;
if (test('shell mode fails open when no shell runtime is available', () => {
if (test('shell mode fails open with empty stdout when no shell runtime is available', () => {
const root = createTempDir();
try {
writeFile(root, path.join('scripts', 'hook.sh'), 'printf unreachable\n');
@@ -237,14 +242,16 @@ process.exit(7);
});
assert.strictEqual(result.status, 0);
assert.strictEqual(result.stdout, 'raw-input');
// Empty stdout (not the raw input) so the harness falls back to the
// tool_use's original result.
assert.strictEqual(result.stdout, '');
assert.ok(result.stderr.includes('shell runtime unavailable'));
} finally {
cleanup(root);
}
})) passed++; else failed++;
if (test('rejects target paths that escape the plugin root', () => {
if (test('rejects target paths that escape the plugin root with empty stdout', () => {
const root = createTempDir();
try {
const result = run(['node', path.join('..', 'outside.js')], {
@@ -253,14 +260,16 @@ process.exit(7);
});
assert.strictEqual(result.status, 0);
assert.strictEqual(result.stdout, 'raw-input');
// Empty stdout (not the raw input) -- the resolver throws, fallthrough
// path emits empty + stderr explanation.
assert.strictEqual(result.stdout, '');
assert.ok(result.stderr.includes('Path traversal rejected'));
} finally {
cleanup(root);
}
})) passed++; else failed++;
if (test('unknown mode fails open with stderr warning', () => {
if (test('unknown mode fails open with empty stdout and stderr warning', () => {
const root = createTempDir();
try {
const result = run(['python', 'hook.py'], {
@@ -269,7 +278,9 @@ process.exit(7);
});
assert.strictEqual(result.status, 0);
assert.strictEqual(result.stdout, 'raw-input');
// Empty stdout (not the raw input) -- unknown mode fallthrough path
// emits empty + stderr explanation.
assert.strictEqual(result.stdout, '');
assert.ok(result.stderr.includes('unknown bootstrap mode: python'));
} finally {
cleanup(root);
@@ -375,7 +386,7 @@ process.exit(7);
});
assert.strictEqual(result.status, 0);
assert.strictEqual(result.stdout, 'raw-input');
assert.strictEqual(result.stdout, '');
assert.ok(
result.stderr.includes('no bash binary found') ||
result.stderr.includes('shell runtime unavailable'),
@@ -391,4 +402,4 @@ process.exit(7);
process.exit(failed > 0 ? 1 : 0);
}
runTests();
runTests();