mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-31 04:09:51 +02:00
Merge pull request #2899 from haelyra/fix/plugin-bootstrap-prefix-classification
fix(hooks): classify platform-dependent raw prefixes
This commit is contained in:
@@ -7,7 +7,6 @@ const { spawnSync } = require('child_process');
|
||||
const { ensureAgentDataHomeEnv } = require('../lib/agent-data-home');
|
||||
|
||||
const SHELL_PROBE_TIMEOUT_MS = 2000;
|
||||
const STDOUT_PIPE_CAP_BYTES = 64 * 1024;
|
||||
|
||||
function readStdinRaw() {
|
||||
try {
|
||||
@@ -37,9 +36,8 @@ function isRawPassthrough(raw, stdout) {
|
||||
const stdoutBytes = toBuffer(stdout);
|
||||
if (rawBytes.length === 0 || stdoutBytes.length === 0) return false;
|
||||
return (
|
||||
stdoutBytes.equals(rawBytes) ||
|
||||
(stdoutBytes.length === STDOUT_PIPE_CAP_BYTES &&
|
||||
rawBytes.subarray(0, stdoutBytes.length).equals(stdoutBytes))
|
||||
stdoutBytes.length <= rawBytes.length &&
|
||||
rawBytes.subarray(0, stdoutBytes.length).equals(stdoutBytes)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -58,11 +56,11 @@ function passthrough(result) {
|
||||
// instead; the harness falls back to the tool_use's original result, the
|
||||
// same path #2240 established for bash-hook-dispatcher.
|
||||
//
|
||||
// IMPORTANT: a strict `stdout === raw` check misses the common case where
|
||||
// child processes' synchronous `process.stdout.write()` writes hit the
|
||||
// ~64 KB Node.js pipe buffer and get truncated -- stdout is then exactly
|
||||
// 65536 bytes and a strict prefix of raw. So we also detect that
|
||||
// truncation sentinel.
|
||||
// IMPORTANT: a strict `stdout === raw` check misses child processes whose
|
||||
// synchronous `process.stdout.write()` is truncated before exit. Pipe
|
||||
// capacity varies by platform and Node version (observed at 8, 16, and
|
||||
// 64 KiB), so classify any non-empty byte-exact prefix of the raw hook
|
||||
// event as passthrough instead of assuming one buffer size.
|
||||
const raw = result?.comparisonInput;
|
||||
const looksLikePassthrough = isRawPassthrough(raw, stdout);
|
||||
if (looksLikePassthrough) {
|
||||
|
||||
@@ -242,7 +242,7 @@ if (
|
||||
else failed++;
|
||||
|
||||
if (
|
||||
test('64 KiB passthrough sentinel is measured in UTF-8 bytes', () => {
|
||||
test('truncated UTF-8 prefix is classified by bytes', () => {
|
||||
const fixturePath = path.join(FIXTURE_DIR, 'multibyte-prefix-fixture.js');
|
||||
fs.writeFileSync(
|
||||
fixturePath,
|
||||
@@ -255,7 +255,7 @@ if (
|
||||
});
|
||||
assert.strictEqual(Buffer.byteLength(payload.slice(0, 32768), 'utf8'), 64 * 1024);
|
||||
assert.strictEqual(result.status, 0, result.stderr);
|
||||
assert.strictEqual(result.stdout, '', 'a 64 KiB UTF-8 prefix of raw input must be suppressed');
|
||||
assert.strictEqual(result.stdout, '', 'a UTF-8 byte prefix of raw input must be suppressed');
|
||||
assert.match(result.stderr, /returned raw input as stdout/);
|
||||
} finally {
|
||||
fs.unlinkSync(fixturePath);
|
||||
@@ -266,18 +266,23 @@ if (
|
||||
else failed++;
|
||||
|
||||
if (
|
||||
test('byte boundary does not misclassify 64K multibyte characters', () => {
|
||||
const byteBoundaryPrefix = 'é'.repeat(32768);
|
||||
const characterBoundaryPrefix = 'é'.repeat(65536);
|
||||
test('classifies platform-dependent pipe prefixes without accepting mismatches', () => {
|
||||
const raw = Buffer.from(`${'a'.repeat(64 * 1024)}tail`, 'utf8');
|
||||
|
||||
assert.strictEqual(Buffer.byteLength(byteBoundaryPrefix, 'utf8'), 64 * 1024);
|
||||
assert.strictEqual(Buffer.byteLength(characterBoundaryPrefix, 'utf8'), 128 * 1024);
|
||||
assert.strictEqual(isRawPassthrough(`${byteBoundaryPrefix}tail`, byteBoundaryPrefix), true);
|
||||
assert.strictEqual(
|
||||
isRawPassthrough(`${characterBoundaryPrefix}tail`, characterBoundaryPrefix),
|
||||
false,
|
||||
'64K JavaScript characters must not be treated as a 64 KiB byte boundary'
|
||||
);
|
||||
for (const prefixLength of [8 * 1024, 16 * 1024, 64 * 1024]) {
|
||||
assert.strictEqual(
|
||||
isRawPassthrough(raw, raw.subarray(0, prefixLength)),
|
||||
true,
|
||||
`${prefixLength}-byte raw prefix must be classified as passthrough`
|
||||
);
|
||||
}
|
||||
|
||||
const mismatchLength = 8 * 1024;
|
||||
const mismatchedPrefix = Buffer.concat([
|
||||
raw.subarray(0, mismatchLength - 1),
|
||||
Buffer.from([raw[mismatchLength - 1] ^ 1])
|
||||
]);
|
||||
assert.strictEqual(isRawPassthrough(raw, mismatchedPrefix), false);
|
||||
})
|
||||
)
|
||||
passed++;
|
||||
|
||||
Reference in New Issue
Block a user