mirror of
https://github.com/morluto/rea.git
synced 2026-11-07 05:56:19 -10:00
chore(lint): enforce buffer and cancellation regression guards
This commit is contained in:
1 parent
f2fa951c00
commit
475f09d5ca
182 files changed
+1653
-497
No files matched your search
@@ -1,7 +1,13 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["typescript", "import", "unicorn", "oxc"],
|
||||
"jsPlugins": [{ "name": "rea", "specifier": "./scripts/lint/index.mjs" }],
|
||||
"rules": {
|
||||
"rea/no-buffer-deep-equality": "error",
|
||||
"rea/cancellation-cause": "error",
|
||||
"no-async-promise-executor": "error",
|
||||
"no-unreachable": "error",
|
||||
"no-unsafe-optional-chaining": "error",
|
||||
"complexity": ["warn", 20],
|
||||
"max-depth": ["warn", 4],
|
||||
"max-lines": [
|
||||
|
||||
@@ -146,6 +146,27 @@ boundaries and architecture guards enforce their declared import and source
|
||||
rules. Passing them does not prove that two parsers agree, a wrapper is still
|
||||
needed at runtime, or cleanup has one owner.
|
||||
|
||||
The lint gate treats `no-async-promise-executor`, `no-unreachable`, and
|
||||
`no-unsafe-optional-chaining` as errors. These catch lost async executor failures,
|
||||
dead code, and unsafe uses of optional-chain results. `no-unsafe-finally` remains
|
||||
a warning because cleanup paths can deliberately throw aggregated failures;
|
||||
review whether they preserve the primary failure. Two local rules
|
||||
cover narrower observed failures: `rea/no-buffer-deep-equality` flags Vitest
|
||||
deep comparisons of Buffers from recognized constructors and file reads,
|
||||
including simple `const` aliases; `rea/cancellation-cause` requires an explicit
|
||||
cause when a directly checked caller `AbortSignal` is converted to an
|
||||
`AnalysisCancelledError`. The rules do not infer arbitrary Buffer types,
|
||||
follow indirect cancellation helpers, or prove that an explicit cause equals
|
||||
the caller's reason. Keep focused boundary and lifecycle tests for those facts.
|
||||
|
||||
Type-aware linting remains outside the routine gate: a full source, test, and
|
||||
script scan exceeded the bounded process-family memory envelope, including
|
||||
with Go runtime limits. Future scoped evaluation can consider
|
||||
`typescript/no-floating-promises`, `typescript/return-await` with
|
||||
`error-handling-correctness-only`, `typescript/no-misused-promises`, and
|
||||
`typescript/switch-exhaustiveness-check`. None replaces behavioral checks for
|
||||
source identity, omission versus unknown, or Evidence provenance.
|
||||
|
||||
Routine iterations and rebases need focused regressions and relevant checks.
|
||||
Before handing off a PR, run `npm run check` and generated-document checks when
|
||||
applicable; CI owns the full suite and coverage. Use the full local gate for
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/** Resolve the lexical binding instead of treating a matching name as an API. */
|
||||
export const findBinding = (sourceCode, identifier) => {
|
||||
for (
|
||||
let scope = sourceCode.getScope(identifier);
|
||||
scope !== null;
|
||||
scope = scope.upper
|
||||
) {
|
||||
const variable = scope.set.get(identifier.name);
|
||||
if (variable !== undefined) return variable;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
import type { RuleTester } from "oxlint/plugins-dev";
|
||||
|
||||
declare const cancellationCauseRule: Parameters<RuleTester["run"]>[1];
|
||||
export default cancellationCauseRule;
|
||||
@@ -0,0 +1,200 @@
|
||||
import { findBinding } from "./bindings.mjs";
|
||||
|
||||
/**
|
||||
* Require an explicit cancellation reason when a directly checked caller signal
|
||||
* is converted to an AnalysisCancelledError. This is deliberately syntactic:
|
||||
* internal shutdown and cancellation forwarded through other owners are outside
|
||||
* the rule.
|
||||
*/
|
||||
|
||||
const coreModule = /(?:^|\/)analysisErrorCore(?:\.js|\.ts)?$/;
|
||||
|
||||
const unwrapChain = (node) =>
|
||||
node?.type === "ChainExpression" ? node.expression : node;
|
||||
|
||||
const propertyName = (property) =>
|
||||
property.computed
|
||||
? property.property.type === "Literal"
|
||||
? property.property.value
|
||||
: undefined
|
||||
: property.property.name;
|
||||
|
||||
const annotationType = (node) => {
|
||||
const annotation = node?.typeAnnotation?.typeAnnotation;
|
||||
return annotation?.type === "TSTypeReference" &&
|
||||
annotation.typeName.type === "Identifier"
|
||||
? annotation.typeName
|
||||
: undefined;
|
||||
};
|
||||
|
||||
const soleDefinition = (variable) =>
|
||||
variable?.defs.length === 1 ? variable.defs[0] : undefined;
|
||||
|
||||
const isKnownType = (node, kind, context) => {
|
||||
const type = annotationType(node);
|
||||
if (type === undefined) return false;
|
||||
const definition = soleDefinition(findBinding(context.sourceCode, type));
|
||||
if (kind === "AbortSignal")
|
||||
return type.name === "AbortSignal" && definition === undefined;
|
||||
return (
|
||||
definition?.type === "ImportBinding" &&
|
||||
definition.parent?.type === "ImportDeclaration" &&
|
||||
/(?:^|\/)AnalysisProvider(?:\.js|\.ts)?$/.test(
|
||||
definition.parent.source.value,
|
||||
) &&
|
||||
definition.node.type === "ImportSpecifier" &&
|
||||
definition.node.imported.name === "ExecutionOptions"
|
||||
);
|
||||
};
|
||||
|
||||
const unmodified = (variable) =>
|
||||
variable !== undefined &&
|
||||
variable.references.every(
|
||||
(reference) => !reference.isWrite() || reference.init,
|
||||
);
|
||||
|
||||
const isOptionsSignal = (node, context, seen) => {
|
||||
node = unwrapChain(node);
|
||||
if (node?.type !== "MemberExpression" || propertyName(node) !== "signal")
|
||||
return false;
|
||||
return isKnownBinding(node.object, "ExecutionOptions", context, seen);
|
||||
};
|
||||
|
||||
const isKnownBinding = (node, kind, context, seen) => {
|
||||
if (node?.type !== "Identifier") return false;
|
||||
const variable = findBinding(context.sourceCode, node);
|
||||
if (!unmodified(variable) || seen.has(variable)) return false;
|
||||
seen.add(variable);
|
||||
const definition = soleDefinition(variable);
|
||||
if (definition?.type === "Parameter")
|
||||
return isKnownType(definition.name, kind, context);
|
||||
if (definition?.type !== "Variable" || definition.parent?.kind !== "const")
|
||||
return false;
|
||||
const declaration = definition.node;
|
||||
if (isKnownType(declaration.id, kind, context)) return true;
|
||||
return kind === "AbortSignal"
|
||||
? isKnownSignal(declaration.init, context, seen)
|
||||
: false;
|
||||
};
|
||||
|
||||
const isKnownSignal = (node, context, seen = new Set()) =>
|
||||
isKnownBinding(unwrapChain(node), "AbortSignal", context, seen) ||
|
||||
isOptionsSignal(node, context, seen);
|
||||
|
||||
const isAbortRead = (node, context) => {
|
||||
node = unwrapChain(node);
|
||||
return (
|
||||
node?.type === "MemberExpression" &&
|
||||
propertyName(node) === "aborted" &&
|
||||
isKnownSignal(node.object, context)
|
||||
);
|
||||
};
|
||||
|
||||
const isTrueLiteral = (node) => node?.type === "Literal" && node.value === true;
|
||||
|
||||
const positiveAbortGuard = (test, context) => {
|
||||
if (isAbortRead(test, context)) return true;
|
||||
if (
|
||||
test?.type === "BinaryExpression" &&
|
||||
(test.operator === "===" || test.operator === "==")
|
||||
)
|
||||
return (
|
||||
(isAbortRead(test.left, context) && isTrueLiteral(test.right)) ||
|
||||
(isTrueLiteral(test.left) && isAbortRead(test.right, context))
|
||||
);
|
||||
if (test?.type === "LogicalExpression" && test.operator === "&&")
|
||||
return (
|
||||
positiveAbortGuard(test.left, context) ||
|
||||
positiveAbortGuard(test.right, context)
|
||||
);
|
||||
return false;
|
||||
};
|
||||
|
||||
const isCanonicalConstructor = (node, context) => {
|
||||
if (node?.type !== "Identifier") return false;
|
||||
const definition = soleDefinition(findBinding(context.sourceCode, node));
|
||||
return (
|
||||
definition?.type === "ImportBinding" &&
|
||||
definition.parent?.type === "ImportDeclaration" &&
|
||||
coreModule.test(definition.parent.source.value) &&
|
||||
definition.node.type === "ImportSpecifier" &&
|
||||
definition.node.imported.name === "AnalysisCancelledError"
|
||||
);
|
||||
};
|
||||
|
||||
const hasExplicitCause = (node) => {
|
||||
const options = node.arguments[1];
|
||||
if (options !== undefined && options.type !== "ObjectExpression") return true; // Forwarded context is owned elsewhere.
|
||||
if (options === undefined) return false;
|
||||
return options.properties.some(
|
||||
(property) =>
|
||||
property.type === "SpreadElement" ||
|
||||
(property.type === "Property" &&
|
||||
(property.computed
|
||||
? property.key.type !== "Literal" || property.key.value === "cause"
|
||||
: (property.key.type === "Identifier"
|
||||
? property.key.name
|
||||
: property.key.value) === "cause")),
|
||||
);
|
||||
};
|
||||
|
||||
const inspectExpression = (expression, context) => {
|
||||
if (expression?.type === "NewExpression") {
|
||||
if (
|
||||
isCanonicalConstructor(expression.callee, context) &&
|
||||
!hasExplicitCause(expression)
|
||||
)
|
||||
context.report({
|
||||
node: expression,
|
||||
messageId: "missingCause",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (expression?.type === "CallExpression") {
|
||||
// Common Result adapter: return err(new AnalysisCancelledError(...)).
|
||||
for (const argument of expression.arguments)
|
||||
inspectExpression(argument, context);
|
||||
} else if (expression?.type === "AssignmentExpression") {
|
||||
inspectExpression(expression.right, context);
|
||||
}
|
||||
};
|
||||
|
||||
const inspectBranch = (branch, context) => {
|
||||
if (branch.type === "BlockStatement") {
|
||||
for (const statement of branch.body) inspectBranch(statement, context);
|
||||
} else if (branch.type === "VariableDeclaration") {
|
||||
for (const declaration of branch.declarations)
|
||||
inspectExpression(declaration.init, context);
|
||||
} else if (
|
||||
branch.type === "ThrowStatement" ||
|
||||
branch.type === "ReturnStatement"
|
||||
) {
|
||||
inspectExpression(branch.argument, context);
|
||||
} else if (branch.type === "ExpressionStatement") {
|
||||
inspectExpression(branch.expression, context);
|
||||
}
|
||||
};
|
||||
|
||||
const cancellationCauseRule = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
docs: {
|
||||
description:
|
||||
"Preserve a directly checked caller AbortSignal reason in AnalysisCancelledError",
|
||||
},
|
||||
messages: {
|
||||
missingCause:
|
||||
"Pass the checked AbortSignal's reason as an explicit cancellation cause.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
IfStatement(node) {
|
||||
if (positiveAbortGuard(node.test, context))
|
||||
inspectBranch(node.consequent, context);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default cancellationCauseRule;
|
||||
@@ -0,0 +1,10 @@
|
||||
import noBufferDeepEquality from "./no-buffer-deep-equality.mjs";
|
||||
import cancellationCause from "./cancellation-cause.mjs";
|
||||
|
||||
export default {
|
||||
meta: { name: "rea" },
|
||||
rules: {
|
||||
"no-buffer-deep-equality": noBufferDeepEquality,
|
||||
"cancellation-cause": cancellationCause,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
import type { RuleTester } from "oxlint/plugins-dev";
|
||||
|
||||
declare const noBufferDeepEquality: Parameters<RuleTester["run"]>[1];
|
||||
export default noBufferDeepEquality;
|
||||
@@ -0,0 +1,166 @@
|
||||
import { findBinding } from "./bindings.mjs";
|
||||
|
||||
const memberName = (node) =>
|
||||
node?.type === "MemberExpression" &&
|
||||
!node.computed &&
|
||||
node.property.type === "Identifier"
|
||||
? node.property.name
|
||||
: null;
|
||||
|
||||
const unwrap = (node) => {
|
||||
while (
|
||||
node?.type === "TSAsExpression" ||
|
||||
node?.type === "TSSatisfiesExpression" ||
|
||||
node?.type === "TSNonNullExpression" ||
|
||||
node?.type === "TSTypeAssertion" ||
|
||||
node?.type === "ParenthesizedExpression"
|
||||
)
|
||||
node = node.expression;
|
||||
return node;
|
||||
};
|
||||
|
||||
const importedKind = (variable) => {
|
||||
const definition = variable?.defs[0];
|
||||
if (definition?.type !== "ImportBinding") return null;
|
||||
const source = definition.parent?.source?.value;
|
||||
const node = definition.node;
|
||||
if (node?.type === "ImportNamespaceSpecifier") {
|
||||
if (source === "node:fs/promises") return "fsPromises";
|
||||
if (source === "node:fs") return "fs";
|
||||
return null;
|
||||
}
|
||||
if (node?.type !== "ImportSpecifier") return null;
|
||||
const imported = node.imported?.name ?? node.imported?.value;
|
||||
if (source === "vitest" && imported === "expect") return "expect";
|
||||
if (source === "node:buffer" && imported === "Buffer") return "Buffer";
|
||||
if (source === "node:fs/promises" && imported === "readFile")
|
||||
return "readFile";
|
||||
if (source === "node:fs" && imported === "readFileSync")
|
||||
return "readFileSync";
|
||||
return null;
|
||||
};
|
||||
|
||||
const constInitializer = (variable) => {
|
||||
if (variable?.defs.length !== 1) return null;
|
||||
const definition = variable.defs[0];
|
||||
if (
|
||||
definition?.type !== "Variable" ||
|
||||
definition.node?.type !== "VariableDeclarator" ||
|
||||
definition.parent?.kind !== "const" ||
|
||||
variable.references.some(
|
||||
(reference) => reference.isWrite() && !reference.init,
|
||||
)
|
||||
)
|
||||
return null;
|
||||
return definition.node.init;
|
||||
};
|
||||
|
||||
/** Flag byte comparisons that make Vitest enumerate a Node Buffer. */
|
||||
const noBufferDeepEquality = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
messages: {
|
||||
nativeBytes:
|
||||
"Compare Node Buffers with Buffer.equals or Buffer.compare; deep equality can enumerate every byte and exhaust memory.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
const { sourceCode } = context;
|
||||
const symbolKind = (expression, seen = new Set()) => {
|
||||
const node = unwrap(expression);
|
||||
if (node?.type === "Identifier") {
|
||||
const variable = findBinding(sourceCode, node);
|
||||
if (
|
||||
(variable === undefined || variable.defs.length === 0) &&
|
||||
sourceCode.isGlobalReference(node)
|
||||
)
|
||||
return node.name === "Buffer" ? "Buffer" : null;
|
||||
const imported = importedKind(variable);
|
||||
if (imported !== null) return imported;
|
||||
if (variable === undefined || seen.has(variable)) return null;
|
||||
const initializer = constInitializer(variable);
|
||||
if (initializer === null) return null;
|
||||
seen.add(variable);
|
||||
return symbolKind(initializer, seen);
|
||||
}
|
||||
const property = memberName(node);
|
||||
if (property === null) return null;
|
||||
const owner = symbolKind(node.object, seen);
|
||||
if (owner === "fsPromises" && property === "readFile") return "readFile";
|
||||
if (owner === "fs" && property === "readFileSync") return "readFileSync";
|
||||
if (
|
||||
owner === "Buffer" &&
|
||||
["from", "alloc", "allocUnsafe", "allocUnsafeSlow", "concat"].includes(
|
||||
property,
|
||||
)
|
||||
)
|
||||
return "bufferFactory";
|
||||
return null;
|
||||
};
|
||||
const isBuffer = (expression, seen = new Set(), awaited = false) => {
|
||||
const node = unwrap(expression);
|
||||
if (node?.type === "AwaitExpression")
|
||||
return isBuffer(node.argument, seen, true);
|
||||
if (node?.type === "Identifier") {
|
||||
const variable = findBinding(sourceCode, node);
|
||||
if (variable === undefined || seen.has(variable)) return false;
|
||||
const initializer = constInitializer(variable);
|
||||
if (initializer === null) return false;
|
||||
seen.add(variable);
|
||||
return isBuffer(initializer, seen, awaited);
|
||||
}
|
||||
if (node?.type !== "CallExpression" || node.optional) return false;
|
||||
const kind = symbolKind(node.callee);
|
||||
return (
|
||||
kind === "bufferFactory" ||
|
||||
((kind === "readFileSync" || (kind === "readFile" && awaited)) &&
|
||||
node.arguments.length === 1 &&
|
||||
node.arguments[0].type !== "SpreadElement")
|
||||
);
|
||||
};
|
||||
const expectedCall = (object, settlement = null) => {
|
||||
const node = unwrap(object);
|
||||
const property = memberName(node);
|
||||
if (property === "not") return expectedCall(node.object, settlement);
|
||||
if (property === "resolves" || property === "rejects")
|
||||
return expectedCall(node.object, property);
|
||||
return node?.type === "CallExpression" &&
|
||||
!node.optional &&
|
||||
symbolKind(node.callee) === "expect"
|
||||
? { call: node, settlement }
|
||||
: null;
|
||||
};
|
||||
return {
|
||||
CallExpression(node) {
|
||||
if (node.optional) return;
|
||||
const matcher = memberName(node.callee);
|
||||
if (matcher !== "toEqual" && matcher !== "toStrictEqual") return;
|
||||
const assertion = expectedCall(node.callee.object);
|
||||
if (
|
||||
assertion === null ||
|
||||
![1, 2].includes(assertion.call.arguments.length) ||
|
||||
assertion.call.arguments.some(
|
||||
(argument) => argument.type === "SpreadElement",
|
||||
) ||
|
||||
node.arguments.length !== 1
|
||||
)
|
||||
return;
|
||||
if (
|
||||
(assertion.settlement !== "rejects" &&
|
||||
isBuffer(
|
||||
assertion.call.arguments[0],
|
||||
new Set(),
|
||||
assertion.settlement === "resolves",
|
||||
)) ||
|
||||
isBuffer(node.arguments[0])
|
||||
)
|
||||
context.report({
|
||||
node: node.callee.property,
|
||||
messageId: "nativeBytes",
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default noBufferDeepEquality;
|
||||
@@ -524,7 +524,7 @@ const registerSignatureInputAdmissionCases = () => {
|
||||
corrupt.writeUInt32LE(0x06064b51, endOffset);
|
||||
const restored = Buffer.from(corrupt);
|
||||
restored.writeUInt32LE(0x06064b50, endOffset);
|
||||
expect(restored).toEqual(valid);
|
||||
expect(Buffer.compare(restored, valid)).toBe(0);
|
||||
for (const [name, bytes] of [
|
||||
["valid", valid],
|
||||
["restored", restored],
|
||||
|
||||
@@ -18,10 +18,13 @@ it("binds readable certificate fields to the exact carried DER despite embedded
|
||||
createHash("sha256").update(outer).digest("hex"),
|
||||
);
|
||||
expect(
|
||||
new X509Certificate(
|
||||
`-----BEGIN CERTIFICATE-----\n${Buffer.from(outer).toString("base64")}\n-----END CERTIFICATE-----\n`,
|
||||
).raw,
|
||||
).toEqual(Buffer.from(outer));
|
||||
Buffer.compare(
|
||||
new X509Certificate(
|
||||
`-----BEGIN CERTIFICATE-----\n${Buffer.from(outer).toString("base64")}\n-----END CERTIFICATE-----\n`,
|
||||
).raw,
|
||||
Buffer.from(outer),
|
||||
),
|
||||
).toBe(0);
|
||||
}
|
||||
});
|
||||
it.each([
|
||||
|
||||
@@ -250,7 +250,7 @@ sdkInfo:
|
||||
coverage: "complete",
|
||||
},
|
||||
});
|
||||
expect(await readFile(apk.path)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(apk.path), original)).toBe(0);
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
||||
@@ -150,9 +150,13 @@ const sameTree = async (left: string, right: string): Promise<number> => {
|
||||
const files = await listFiles(left);
|
||||
expect(await listFiles(right)).toEqual(files);
|
||||
for (const file of files)
|
||||
expect(await readFile(join(left, file)), file).toEqual(
|
||||
await readFile(join(right, file)),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(left, file)),
|
||||
await readFile(join(right, file)),
|
||||
),
|
||||
file,
|
||||
).toBe(0);
|
||||
return files.length;
|
||||
};
|
||||
|
||||
|
||||
@@ -66,8 +66,11 @@ it("retains the admitted tarball descriptor and refuses a pathname replacement d
|
||||
error: { _tag: "AnalysisArtifactChangedError", path: tarball },
|
||||
});
|
||||
expect(
|
||||
await readFile(join(directory, "envs/grafana-example/rea-agents.tgz")),
|
||||
).toEqual(originalBytes);
|
||||
Buffer.compare(
|
||||
await readFile(join(directory, "envs/grafana-example/rea-agents.tgz")),
|
||||
originalBytes,
|
||||
),
|
||||
).toBe(0);
|
||||
} finally {
|
||||
writer.mockRestore();
|
||||
}
|
||||
@@ -158,8 +161,11 @@ it("uses confirmed publication after the output owner's descriptor cleanup compl
|
||||
});
|
||||
expect(result).toMatchObject({ ok: true, value: { status: "exported" } });
|
||||
expect(
|
||||
await readFile(join(directory, "envs/grafana-example/evidence.json")),
|
||||
).toEqual(inputs.value.evidence.bytes);
|
||||
Buffer.compare(
|
||||
await readFile(join(directory, "envs/grafana-example/evidence.json")),
|
||||
inputs.value.evidence.bytes,
|
||||
),
|
||||
).toBe(0);
|
||||
} finally {
|
||||
commit.mockRestore();
|
||||
}
|
||||
|
||||
@@ -62,13 +62,19 @@ describe("readEnvironmentExportInputs", () => {
|
||||
);
|
||||
if (!inputs.ok) throw inputs.error;
|
||||
expect(inputs.value.manifest.path).toBe(files.manifestPath);
|
||||
expect(inputs.value.manifest.bytes).toEqual(
|
||||
await readFile(files.manifestPath),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
inputs.value.manifest.bytes,
|
||||
await readFile(files.manifestPath),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(inputs.value.manifest.value).toEqual(fixture.manifest);
|
||||
expect(inputs.value.evidence.bytes).toEqual(
|
||||
await readFile(files.capturePath),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
inputs.value.evidence.bytes,
|
||||
await readFile(files.capturePath),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(inputs.value.evidence.value).toEqual(fixture.capture);
|
||||
});
|
||||
|
||||
@@ -151,11 +157,17 @@ const registerBundlePublicationCases = () => {
|
||||
(await readFile(join(directory, file.path))).length,
|
||||
);
|
||||
expect(
|
||||
await readFile(join(directory, "envs/grafana-example/manifest.json")),
|
||||
).toEqual(await readFile(files.manifestPath));
|
||||
Buffer.compare(
|
||||
await readFile(join(directory, "envs/grafana-example/manifest.json")),
|
||||
await readFile(files.manifestPath),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
await readFile(join(directory, "envs/grafana-example/evidence.json")),
|
||||
).toEqual(input.evidence.bytes);
|
||||
Buffer.compare(
|
||||
await readFile(join(directory, "envs/grafana-example/evidence.json")),
|
||||
input.evidence.bytes,
|
||||
),
|
||||
).toBe(0);
|
||||
expect(await listFiles(root)).toEqual(
|
||||
expect.arrayContaining(["capture.json", "manifest.json"]),
|
||||
);
|
||||
@@ -183,8 +195,11 @@ const registerBundlePublicationCases = () => {
|
||||
bytes: 7,
|
||||
});
|
||||
expect(
|
||||
await readFile(join(directory, "envs/replay-copy/rea-agents.tgz")),
|
||||
).toEqual(await readFile(tarball));
|
||||
Buffer.compare(
|
||||
await readFile(join(directory, "envs/replay-copy/rea-agents.tgz")),
|
||||
await readFile(tarball),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
await readFile(join(directory, "envs/replay-copy/Dockerfile"), "utf8"),
|
||||
).toContain("COPY rea-agents.tgz /tmp/");
|
||||
|
||||
@@ -43,9 +43,12 @@ it("seals privately parsed files and shares reported trees across both Evidence
|
||||
expect(webNetworkCaptureSchema.parse(normalized).records[0]?.reported).toBe(
|
||||
reported,
|
||||
);
|
||||
expect(inputs.value.evidence.bytes).toEqual(
|
||||
await readFile(files.capturePath),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
inputs.value.evidence.bytes,
|
||||
await readFile(files.capturePath),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
immutableJsonSnapshotMember(
|
||||
inputs.value.evidence.value,
|
||||
|
||||
@@ -371,7 +371,7 @@ describe("MachOSliceArtifactReader", () => {
|
||||
const verifiedRead = await reader.open(verifiedArmEntry);
|
||||
for await (const chunk of verifiedRead)
|
||||
verifiedChunks.push(Buffer.from(chunk));
|
||||
expect(Buffer.concat(verifiedChunks)).toEqual(arm);
|
||||
expect(Buffer.compare(Buffer.concat(verifiedChunks), arm)).toBe(0);
|
||||
|
||||
const truncatedController = new AbortController();
|
||||
const truncated = await reader.open(
|
||||
|
||||
@@ -408,8 +408,11 @@ it("extracts the main script and assets without executing them", async () => {
|
||||
await readFile(join(extracted.output_root, "assets/message.txt"), "utf8"),
|
||||
).toBe("hello");
|
||||
expect(
|
||||
await readFile(join(extracted.output_root, "__node_sea__/code-cache")),
|
||||
).toEqual(Buffer.from("cache"));
|
||||
Buffer.compare(
|
||||
await readFile(join(extracted.output_root, "__node_sea__/code-cache")),
|
||||
Buffer.from("cache"),
|
||||
),
|
||||
).toBe(0);
|
||||
const extractedInventory = await scanCanonicalArtifactInventory(
|
||||
extracted.output_root,
|
||||
);
|
||||
|
||||
@@ -103,7 +103,9 @@ describe("ZipArtifactReader positional reads", () => {
|
||||
const chunks: Buffer[] = [];
|
||||
for await (const chunk of await reader.open(entry))
|
||||
chunks.push(Buffer.from(chunk));
|
||||
expect(Buffer.concat(chunks)).toEqual(Buffer.from(fixture.content));
|
||||
expect(
|
||||
Buffer.compare(Buffer.concat(chunks), Buffer.from(fixture.content)),
|
||||
).toBe(0);
|
||||
expect(reads.mock.calls.length).toBeGreaterThan(3);
|
||||
} finally {
|
||||
reads.mockRestore();
|
||||
|
||||
@@ -578,7 +578,7 @@ describe("binary keyed archive dates", () => {
|
||||
dateScalar("2001-01-01T00:00:00.100Z"),
|
||||
);
|
||||
expect(graph.limitations).not.toContain(unknownDateLimitation(1));
|
||||
expect(bytes).toEqual(pythonBinaryDateControl);
|
||||
expect(Buffer.compare(bytes, pythonBinaryDateControl)).toBe(0);
|
||||
expect(createHash("sha256").update(bytes).digest("hex")).toBe(
|
||||
"39f08db8341bd74220352dfd559485515cce1e6035e08f27a59ab8f856374a30",
|
||||
);
|
||||
@@ -593,7 +593,9 @@ describe("binary keyed archive dates", () => {
|
||||
dateScalar("2001-01-01T00:00:00.100Z"),
|
||||
);
|
||||
expect(inspected.limitations).not.toContain(unknownDateLimitation(1));
|
||||
expect(await readFile(join(root, "archive.plist"))).toEqual(bytes);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(root, "archive.plist")), bytes),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it.each(
|
||||
@@ -612,7 +614,7 @@ describe("binary keyed archive dates", () => {
|
||||
`binary plist date marker 0x${marker.toString(16)} is invalid`,
|
||||
),
|
||||
);
|
||||
expect(bytes).toEqual(original);
|
||||
expect(Buffer.compare(bytes, original)).toBe(0);
|
||||
if (marker === 0x30)
|
||||
expect(createHash("sha256").update(bytes).digest("hex")).toBe(
|
||||
"ac5696b866c312feb53c2e82edd8fea79dbeb572eb1b07e4291603faa41e8c0e",
|
||||
@@ -631,7 +633,7 @@ describe("binary keyed archive dates", () => {
|
||||
reason: "format",
|
||||
message: `Cannot decode selected Foundation keyed archive: binary plist date marker 0x${marker.toString(16)} is invalid`,
|
||||
});
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -649,7 +651,7 @@ describe("binary keyed archive dates", () => {
|
||||
expect(graph.limitations.join("\n")).not.toContain(
|
||||
"number metadata could not be completely observed",
|
||||
);
|
||||
expect(submillisecond).toEqual(original);
|
||||
expect(Buffer.compare(submillisecond, original)).toBe(0);
|
||||
expect(createHash("sha256").update(submillisecond).digest("hex")).toBe(
|
||||
"ab69ba6e8034c6f60b828ee323a5a3e81bae3e7657477e0ebfbfdb93d53ed2ce",
|
||||
);
|
||||
@@ -662,7 +664,12 @@ describe("binary keyed archive dates", () => {
|
||||
});
|
||||
expect(inspected.objects[1]).toMatchObject(dateScalar(null));
|
||||
expect(inspected.limitations).toContain(unknownDateLimitation(1));
|
||||
expect(await readFile(join(root, "archive.plist"))).toEqual(submillisecond);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(root, "archive.plist")),
|
||||
submillisecond,
|
||||
),
|
||||
).toBe(0);
|
||||
|
||||
const mixed = Buffer.from(
|
||||
buildBinary({
|
||||
@@ -697,7 +704,7 @@ describe("binary keyed archive dates", () => {
|
||||
{ $plist_type: "date", iso8601: null },
|
||||
]);
|
||||
expect(mixedGraph.limitations).toContain(unknownDateLimitation(2));
|
||||
expect(mixed).toEqual(mixedOriginal);
|
||||
expect(Buffer.compare(mixed, mixedOriginal)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -321,9 +321,12 @@ describe("binary plist number rewriting", () => {
|
||||
uidOffsetsToNormalize: [],
|
||||
}),
|
||||
).toBe(bytes);
|
||||
expect(bytes.subarray(13, 30)).toEqual(
|
||||
Buffer.from([0x14, ...Array<number>(16).fill(0xff)]),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
bytes.subarray(13, 30),
|
||||
Buffer.from([0x14, ...Array<number>(16).fill(0xff)]),
|
||||
),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it("does not rewrite a wide integer when a date aliases its payload", () => {
|
||||
@@ -362,7 +365,7 @@ describe("binary plist number rewriting", () => {
|
||||
},
|
||||
{ $plist_type: "date", iso8601: null },
|
||||
]);
|
||||
expect(bytes).toEqual(original);
|
||||
expect(Buffer.compare(bytes, original)).toBe(0);
|
||||
expect(bytes[11]).toBe(0x14);
|
||||
expect(bytes[18]).toBe(0x33);
|
||||
});
|
||||
@@ -424,7 +427,7 @@ describe("binary plist shared object-table entries", () => {
|
||||
expect(numbers.limitations().join("\n")).not.toContain(
|
||||
"could not be completely observed",
|
||||
);
|
||||
expect(bytes).toEqual(original);
|
||||
expect(Buffer.compare(bytes, original)).toBe(0);
|
||||
});
|
||||
|
||||
it("rewrites a shared 16-byte integer once for every entry", () => {
|
||||
@@ -450,7 +453,7 @@ describe("binary plist shared object-table entries", () => {
|
||||
{ $plist_type: "integer", decimal: "18446744073709551618" },
|
||||
{ $plist_type: "integer", decimal: "1152921504606846979" },
|
||||
]);
|
||||
expect(bytes).toEqual(original);
|
||||
expect(Buffer.compare(bytes, original)).toBe(0);
|
||||
});
|
||||
|
||||
it("records a shared date once and keeps its sibling exact", () => {
|
||||
|
||||
@@ -373,14 +373,19 @@ it("extracts derived members into the safe output tree", async () => {
|
||||
path,
|
||||
snapshot,
|
||||
);
|
||||
expect(await readFile(join(output, "hello"))).toEqual(derived(script));
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(output, "hello")), derived(script)),
|
||||
).toBe(0);
|
||||
expect(
|
||||
extracted.artifacts.find((artifact) => artifact.relative_path === "hello")
|
||||
?.sha256,
|
||||
).toBe(sha256(derived(script)));
|
||||
expect(await readFile(join(output, "PYZ.pyz", "app.pyc"))).toEqual(
|
||||
derived(Buffer.from("app-body")),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(output, "PYZ.pyz", "app.pyc")),
|
||||
derived(Buffer.from("app-body")),
|
||||
),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it("reports encrypted PYZ entries and refuses to extract them", async () => {
|
||||
@@ -509,7 +514,9 @@ it.each([false, true])(
|
||||
path,
|
||||
snapshot,
|
||||
);
|
||||
expect(await readFile(join(outputRoot, "PYZ.pyz"))).toEqual(payload);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(outputRoot, "PYZ.pyz")), payload),
|
||||
).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -808,7 +815,9 @@ it("projects CArchive type n entries as symlinks", async () => {
|
||||
await expect(readFile(join(output, "libfoo.so"))).rejects.toMatchObject({
|
||||
code: "ENOENT",
|
||||
});
|
||||
expect(await readFile(join(output, "data.bin"))).toEqual(payload);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(output, "data.bin")), payload),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it.each([false, true])(
|
||||
@@ -948,10 +957,15 @@ it("inventories and extracts a Windows member name under its canonical path", as
|
||||
path,
|
||||
snapshot,
|
||||
);
|
||||
expect(await readFile(join(output, "pkg", "data.bin"))).toEqual(payload);
|
||||
expect(await readFile(join(output, "PYZ.pyz", "res", "icon.bin"))).toEqual(
|
||||
icon,
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(output, "pkg", "data.bin")), payload),
|
||||
).toBe(0);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(output, "PYZ.pyz", "res", "icon.bin")),
|
||||
icon,
|
||||
),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it("preserves distinct POSIX backslash and slash member paths", async () => {
|
||||
@@ -1008,8 +1022,15 @@ it("preserves distinct POSIX backslash and slash member paths", async () => {
|
||||
path,
|
||||
snapshot,
|
||||
);
|
||||
expect(await readFile(join(output, backslashName))).toEqual(backslashPayload);
|
||||
expect(await readFile(join(output, "a", "b.txt"))).toEqual(slashPayload);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(output, backslashName)),
|
||||
backslashPayload,
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(output, "a", "b.txt")), slashPayload),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it("reads a PE signature beyond the carrier prefix before projecting paths", async () => {
|
||||
@@ -1304,7 +1325,9 @@ it("uses known PYZ magic for separate CArchive scripts when the marshal table st
|
||||
path,
|
||||
snapshot,
|
||||
);
|
||||
expect(await readFile(join(output, "hello"))).toEqual(derived(script));
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(output, "hello")), derived(script)),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it("retains colliding CArchive rows and PYZ children but refuses extraction", async () => {
|
||||
|
||||
@@ -656,7 +656,9 @@ for (const cancel of [false, true]) {
|
||||
} else {
|
||||
expect(result.ok).toBe(true);
|
||||
if (!result.ok) throw result.cause;
|
||||
expect(result.value.subarray(16)).toEqual(Buffer.from("body"));
|
||||
expect(
|
||||
Buffer.compare(result.value.subarray(16), Buffer.from("body")),
|
||||
).toBe(0);
|
||||
}
|
||||
await reader.close();
|
||||
expect(attempts).toBe(failClose ? 2 : 1);
|
||||
|
||||
@@ -572,7 +572,9 @@ for (const typeCode of ["o", "d"] as const) {
|
||||
path,
|
||||
inventory,
|
||||
);
|
||||
expect(await readFile(join(output, realPath))).toEqual(payload);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(output, realPath)), payload),
|
||||
).toBe(0);
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -795,8 +797,11 @@ it.each(["x", "s", "empty-module"])(
|
||||
inventory,
|
||||
);
|
||||
expect(
|
||||
(await readFile(join(output, "PYZ.pyz/app.pyc"))).subarray(16),
|
||||
).toEqual(Buffer.from("readable module"));
|
||||
Buffer.compare(
|
||||
(await readFile(join(output, "PYZ.pyz/app.pyc"))).subarray(16),
|
||||
Buffer.from("readable module"),
|
||||
),
|
||||
).toBe(0);
|
||||
},
|
||||
);
|
||||
},
|
||||
@@ -1380,7 +1385,9 @@ it.each([true, false])(
|
||||
source,
|
||||
inventory,
|
||||
);
|
||||
expect(await readFile(join(output, path))).toEqual(file.payload);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(output, path)), file.payload),
|
||||
).toBe(0);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -29,7 +29,7 @@ it("lists modules from a supported PYZ and leaves an unknown magic opaque", asyn
|
||||
);
|
||||
expect(opaque.ok).toBe(true);
|
||||
if (!opaque.ok || opaque.value.kind !== "opaque") return;
|
||||
expect(opaque.value.pythonMagic).toEqual(Buffer.alloc(4));
|
||||
expect(Buffer.compare(opaque.value.pythonMagic, Buffer.alloc(4))).toBe(0);
|
||||
expect(opaque.value.limitation).toContain("left opaque");
|
||||
});
|
||||
|
||||
|
||||
@@ -102,20 +102,21 @@ describe("browser scenario secret redaction", () => {
|
||||
"raw A/B? remains case-sensitive",
|
||||
);
|
||||
expect(
|
||||
secrets.redactBytes(
|
||||
Buffer.compare(
|
||||
secrets.redactBytes(
|
||||
Buffer.concat([
|
||||
Buffer.from([0xff, 0]),
|
||||
Buffer.from("a%2fb%3F"),
|
||||
Buffer.from([0x80]),
|
||||
]),
|
||||
),
|
||||
Buffer.concat([
|
||||
Buffer.from([0xff, 0]),
|
||||
Buffer.from("a%2fb%3F"),
|
||||
Buffer.from("[REDACTED:session]"),
|
||||
Buffer.from([0x80]),
|
||||
]),
|
||||
),
|
||||
).toEqual(
|
||||
Buffer.concat([
|
||||
Buffer.from([0xff, 0]),
|
||||
Buffer.from("[REDACTED:session]"),
|
||||
Buffer.from([0x80]),
|
||||
]),
|
||||
);
|
||||
).toBe(0);
|
||||
expect(
|
||||
secrets.sanitizeUrl("https://app.example.test/?token=a%2fb%3F").url,
|
||||
).toBe("https://app.example.test/?token=[REDACTED:session]");
|
||||
|
||||
@@ -51,7 +51,9 @@ it("rejects forbidden trailer controls while retaining valid earlier trailers",
|
||||
expect(result.frames[0]?.trailers).toEqual([
|
||||
{ name: "grpc-message", value: "kept" },
|
||||
]);
|
||||
expect(input.subarray(5)).toEqual(Buffer.from(text, "utf8"));
|
||||
expect(Buffer.compare(input.subarray(5), Buffer.from(text, "utf8"))).toBe(
|
||||
0,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -116,7 +118,7 @@ it.each(["grpc-web", "grpc-web-text"] as const)(
|
||||
],
|
||||
});
|
||||
expect(result.examined_bytes).toBe(binary.length);
|
||||
expect(binary.subarray(-trailer.length)).toEqual(trailer);
|
||||
expect(Buffer.compare(binary.subarray(-trailer.length), trailer)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -401,13 +401,16 @@ it("preserves duplicate headers and binary bytes, redacting credentials and decl
|
||||
);
|
||||
if (content?.kind !== "network-content" || content.body.state !== "captured")
|
||||
throw new Error("Missing response");
|
||||
expect(Buffer.from(content.body.content, "base64")).toEqual(
|
||||
Buffer.concat([
|
||||
Buffer.from([0xff, 0x00]),
|
||||
Buffer.from("[REDACTED:declared]"),
|
||||
Buffer.from([0xfe]),
|
||||
]),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
Buffer.from(content.body.content, "base64"),
|
||||
Buffer.concat([
|
||||
Buffer.from([0xff, 0x00]),
|
||||
Buffer.from("[REDACTED:declared]"),
|
||||
Buffer.from([0xfe]),
|
||||
]),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(content.body.redacted).toBe(true);
|
||||
expect(content.headers).toEqual({
|
||||
state: "captured",
|
||||
|
||||
@@ -236,5 +236,5 @@ it.each([
|
||||
expect(projected.nonFiniteRealCount).toBe(4);
|
||||
expect(projected.negativeZeroRealCount).toBe(1);
|
||||
expect(observed).toHaveLength(5);
|
||||
expect(bytes).toEqual(original);
|
||||
expect(Buffer.compare(bytes, original)).toBe(0);
|
||||
});
|
||||
@@ -57,7 +57,7 @@ describe("NativeAOT candidate work accounting", () => {
|
||||
},
|
||||
});
|
||||
expect(summary.coverage.work_units_examined).toBeLessThan(64 * 1024);
|
||||
expect(bytes).toEqual(before);
|
||||
expect(Buffer.compare(bytes, before)).toBe(0);
|
||||
});
|
||||
|
||||
it.each(["slots", "interfaces"] as const)(
|
||||
@@ -85,7 +85,7 @@ describe("NativeAOT candidate work accounting", () => {
|
||||
scan_bytes_omitted: 0,
|
||||
},
|
||||
});
|
||||
expect(bytes).toEqual(before);
|
||||
expect(Buffer.compare(bytes, before)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -112,6 +112,6 @@ describe("NativeAOT candidate work accounting", () => {
|
||||
"0x1400022c0",
|
||||
"0x140002400",
|
||||
]);
|
||||
expect(bytes).toEqual(before);
|
||||
expect(Buffer.compare(bytes, before)).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -27,7 +27,7 @@ it.each(["before-data", "after-data"] as const)(
|
||||
expect(
|
||||
result.readTypeDetail("0x140002280", NATIVE_AOT_MAX_REPORT_BYTES),
|
||||
).toBeUndefined();
|
||||
expect(bytes).toEqual(before);
|
||||
expect(Buffer.compare(bytes, before)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -110,7 +110,7 @@ it("preserves source section order while admitting a unique unsorted mapping", (
|
||||
status: "complete",
|
||||
method_tables: 3,
|
||||
});
|
||||
expect(bytes).toEqual(before);
|
||||
expect(Buffer.compare(bytes, before)).toBe(0);
|
||||
});
|
||||
|
||||
it("does not confuse raw alignment padding with virtual section ownership", () => {
|
||||
|
||||
@@ -64,7 +64,7 @@ describe("NativeAOT indexed MethodTable closure", () => {
|
||||
"0x1400022c0",
|
||||
...expected,
|
||||
]);
|
||||
expect(bytes).toEqual(before);
|
||||
expect(Buffer.compare(bytes, before)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -91,7 +91,7 @@ describe("read-only NativeAOT PE parser", () => {
|
||||
SUMMARY_BUDGET,
|
||||
"0x140000000",
|
||||
);
|
||||
expect(bytes).toEqual(before);
|
||||
expect(Buffer.compare(bytes, before)).toBe(0);
|
||||
expect(parsed.summary).toMatchObject({
|
||||
format: "dotnet-nativeaot",
|
||||
status: "complete",
|
||||
@@ -227,7 +227,7 @@ describe("read-only NativeAOT PE parser", () => {
|
||||
nativeAotPeDigest(bytes),
|
||||
SUMMARY_BUDGET,
|
||||
);
|
||||
expect(bytes).toEqual(before);
|
||||
expect(Buffer.compare(bytes, before)).toBe(0);
|
||||
expect(parsed.summary).toMatchObject({
|
||||
status: "partial",
|
||||
derived_overlay: null,
|
||||
|
||||
@@ -47,9 +47,12 @@ describe("managed metadata heaps", () => {
|
||||
blob: null,
|
||||
} as unknown as ManagedMetadataLayout;
|
||||
|
||||
expect(readMetadataBlob(Buffer.alloc(0), layout, 0, 0)).toEqual(
|
||||
Buffer.alloc(0),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
readMetadataBlob(Buffer.alloc(0), layout, 0, 0),
|
||||
Buffer.alloc(0),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(() => readMetadataBlob(Buffer.alloc(0), layout, 1, 0)).toThrowError(
|
||||
expect.objectContaining({
|
||||
issue: expect.objectContaining({
|
||||
|
||||
@@ -41,11 +41,20 @@ describe("managed PE fixture layout", () => {
|
||||
});
|
||||
|
||||
expect(
|
||||
image.subarray(rawOffset(0x2800), rawOffset(0x2800) + firstBody.length),
|
||||
).toEqual(firstBody);
|
||||
Buffer.compare(
|
||||
image.subarray(rawOffset(0x2800), rawOffset(0x2800) + firstBody.length),
|
||||
firstBody,
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
image.subarray(rawOffset(0x2840), rawOffset(0x2840) + secondBody.length),
|
||||
).toEqual(secondBody);
|
||||
Buffer.compare(
|
||||
image.subarray(
|
||||
rawOffset(0x2840),
|
||||
rawOffset(0x2840) + secondBody.length,
|
||||
),
|
||||
secondBody,
|
||||
),
|
||||
).toBe(0);
|
||||
const inspected = inspectManagedMembersBytes(
|
||||
image,
|
||||
managedPeFixtureTarget(image),
|
||||
@@ -92,11 +101,14 @@ describe("managed PE fixture layout", () => {
|
||||
expect(layout.cli.resources.size).toBe(resourceData.length + 4);
|
||||
expect(image.readUInt32LE(directoryOffset)).toBe(resourceData.length);
|
||||
expect(
|
||||
image.subarray(
|
||||
directoryOffset + 4,
|
||||
directoryOffset + 4 + resourceData.length,
|
||||
Buffer.compare(
|
||||
image.subarray(
|
||||
directoryOffset + 4,
|
||||
directoryOffset + 4 + resourceData.length,
|
||||
),
|
||||
resourceData,
|
||||
),
|
||||
).toEqual(resourceData);
|
||||
).toBe(0);
|
||||
expect(inspection.classification.status).toBe("managed");
|
||||
expect(inspection.resources).toMatchObject([
|
||||
{
|
||||
|
||||
@@ -114,5 +114,5 @@ const assertArchitecture = async (
|
||||
expect(
|
||||
report.slices[0]?.sentinels[0]?.fuses.map((fuse) => fuse.raw_byte),
|
||||
).toEqual(OBSIDIAN_FUSE_BYTES);
|
||||
expect(await readFile(path)).toEqual(image.bytes);
|
||||
expect(Buffer.compare(await readFile(path), image.bytes)).toBe(0);
|
||||
};
|
||||
@@ -112,7 +112,7 @@ describe("readElfSymbol", () => {
|
||||
const image = strippedImageWithSections([[tag, 0xffffffffffffffffn]]);
|
||||
const original = Buffer.from(image);
|
||||
expect(await readElfSymbols(image, names)).toEqual(control);
|
||||
expect(image).toEqual(original);
|
||||
expect(Buffer.compare(image, original)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -202,7 +202,7 @@ describe("dynamic symbols without a SHT_DYNSYM section", () => {
|
||||
expect(control.symbols).toHaveLength(2);
|
||||
const before = Buffer.from(image);
|
||||
expect(await readElfSymbols(image, names)).toEqual(control);
|
||||
expect(image).toEqual(before);
|
||||
expect(Buffer.compare(image, before)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -136,10 +136,11 @@ describe("Ghidra launch failure diagnostics", () => {
|
||||
expect(outcome?.["stderrTruncated"]).toBe(true);
|
||||
expect(outcome?.["outputTruncated"]).toBe(false);
|
||||
expect(outcome?.["stderrBytes"]).toBe(oversized.length);
|
||||
expect((outcome?.["stderr"] as string).length).toBeLessThanOrEqual(
|
||||
EXPECTED_OUTPUT_BOUND_BYTES,
|
||||
);
|
||||
expect(outcome?.["stderr"] as string).not.toContain("UNRETAINED-TAIL");
|
||||
const stderr = outcome?.["stderr"];
|
||||
if (typeof stderr !== "string")
|
||||
throw new Error("Expected launcher stderr");
|
||||
expect(stderr.length).toBeLessThanOrEqual(EXPECTED_OUTPUT_BOUND_BYTES);
|
||||
expect(stderr).not.toContain("UNRETAINED-TAIL");
|
||||
} finally {
|
||||
await rm(javaHome, { recursive: true, force: true });
|
||||
await rm(runtimeRoot, { recursive: true, force: true });
|
||||
|
||||
@@ -161,9 +161,12 @@ describe("optional Ghidra extension boundary", () => {
|
||||
resources,
|
||||
);
|
||||
expect(snapshots[0]?.path).toBe(join(runtime, "extensions/nativeaot.jar"));
|
||||
expect(await readFile(join(runtime, "extensions/nativeaot.jar"))).toEqual(
|
||||
bytes,
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(runtime, "extensions/nativeaot.jar")),
|
||||
bytes,
|
||||
),
|
||||
).toBe(0);
|
||||
await expect(
|
||||
snapshotGhidraExtensions([extension], runtime, resources),
|
||||
).rejects.toMatchObject({
|
||||
|
||||
@@ -7,9 +7,12 @@ it.each(["zlib", "zstd"] as const)(
|
||||
const source = Buffer.from("kernel"),
|
||||
encode = codec === "zstd" ? zstdCompressSync : deflateSync,
|
||||
compressed = encode(source);
|
||||
expect(await decodeGpuPayload(compressed, codec, source.length)).toEqual(
|
||||
source,
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await decodeGpuPayload(compressed, codec, source.length),
|
||||
source,
|
||||
),
|
||||
).toBe(0);
|
||||
await expect(
|
||||
decodeGpuPayload(
|
||||
Buffer.concat([compressed, Buffer.from("junk")]),
|
||||
|
||||
@@ -37,8 +37,8 @@ it("whole executable copying rejects pre-copy replacement and retains captured b
|
||||
);
|
||||
expect(captured).toEqual({ ok: true, value: capturedPath });
|
||||
await writeFile(source, replacement);
|
||||
expect(await readFile(capturedPath)).toEqual(selected);
|
||||
expect(await readFile(source)).toEqual(replacement);
|
||||
expect(Buffer.compare(await readFile(capturedPath), selected)).toBe(0);
|
||||
expect(Buffer.compare(await readFile(source), replacement)).toBe(0);
|
||||
} finally {
|
||||
await resources.close();
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ it("copies exactly the selected FAT32 slice bytes and verifies the source", asyn
|
||||
arm64eOffset,
|
||||
arm64eOffset + FAT32_SLICE_SIZE,
|
||||
);
|
||||
expect(await readFile(destination)).toEqual(copied);
|
||||
expect(Buffer.compare(await readFile(destination), copied)).toBe(0);
|
||||
});
|
||||
|
||||
it("retains the caller reason when a FAT copy is cancelled after its final write", async () => {
|
||||
@@ -421,12 +421,15 @@ it("retains the caller reason when a FAT copy is cancelled after its final write
|
||||
expect(prepared.error._tag).toBe("HopperCancelledError");
|
||||
expect(prepared.error.cause).toBe(reason);
|
||||
// The private session directory remains the owner of partial output.
|
||||
await expect(readFile(destination)).resolves.toEqual(
|
||||
fixture.container.subarray(
|
||||
fixture.sliceOffsets[0],
|
||||
fixture.sliceOffsets[0]! + FAT32_SLICE_SIZE,
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(destination),
|
||||
fixture.container.subarray(
|
||||
fixture.sliceOffsets[0],
|
||||
fixture.sliceOffsets[0]! + FAT32_SLICE_SIZE,
|
||||
),
|
||||
),
|
||||
);
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it("retains a failed prepared-image close through launcher cleanup and blocks another launch", async () => {
|
||||
@@ -522,9 +525,12 @@ it("retains a failed prepared-image close through launcher cleanup and blocks an
|
||||
expect(initial.error.cleanupIncomplete).toBe(false);
|
||||
expect(blocked.error.cleanupIncomplete).toBe(false);
|
||||
expect(cleanupPending.error.cleanupIncomplete).toBe(false);
|
||||
await expect(
|
||||
readFile(join(sessionDirectory, "image.macho")),
|
||||
).resolves.toEqual(bytes);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(sessionDirectory, "image.macho")),
|
||||
bytes,
|
||||
),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it("observes caller cancellation that arrives during final source-handle cleanup", async () => {
|
||||
@@ -574,9 +580,9 @@ it("observes caller cancellation that arrives during final source-handle cleanup
|
||||
if (prepared.ok) throw new Error("Finalization cancellation was ignored");
|
||||
expect(prepared.error._tag).toBe("HopperCancelledError");
|
||||
expect(prepared.error.cause).toBe(reason);
|
||||
await expect(readFile(join(directory, "image.macho"))).resolves.toEqual(
|
||||
bytes,
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(directory, "image.macho")), bytes),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it("rejects FAT32 preparation when the source table changed after resolution", async () => {
|
||||
@@ -646,7 +652,7 @@ it("copies an admitted thin Mach-O through the owned verified-image path", async
|
||||
);
|
||||
if (!prepared.ok) throw new Error(prepared.error.userMessage);
|
||||
expect(prepared.value).toBe(destination);
|
||||
expect(await readFile(destination)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(destination), bytes)).toBe(0);
|
||||
expect(target.path).toBe(path);
|
||||
});
|
||||
|
||||
@@ -777,6 +783,6 @@ it("retains an owned partial thin image and exact cancellation reason after a wr
|
||||
if (prepared.ok) throw new Error("Cancelled partial copy was accepted");
|
||||
expect(prepared.error._tag).toBe("HopperCancelledError");
|
||||
expect(prepared.error.cause).toBe(reason);
|
||||
await expect(readFile(destination)).resolves.toEqual(partial);
|
||||
expect(Buffer.compare(await readFile(destination), partial)).toBe(0);
|
||||
await expect(access(destination)).resolves.toBeUndefined();
|
||||
});
|
||||
@@ -1147,7 +1147,9 @@ describe("headless IDA session ownership and cleanup", () => {
|
||||
});
|
||||
if (!result.ok) throw result.error;
|
||||
expect(producer.inputPath).not.toBe(target.path);
|
||||
expect(await readFile(producer.inputPath)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(producer.inputPath), original)).toBe(
|
||||
0,
|
||||
);
|
||||
expect(
|
||||
functionDossierSchema
|
||||
.parse(result.value.result)
|
||||
@@ -1167,7 +1169,7 @@ describe("headless IDA session ownership and cleanup", () => {
|
||||
producer.calls.find(({ name }) => name === "idb_close")?.args.save,
|
||||
).toBe(false);
|
||||
expect(await readdir(root)).toEqual(["target.elf"]);
|
||||
expect(await readFile(target.path)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(target.path), original)).toBe(0);
|
||||
});
|
||||
it("retains the private workspace and reports cleanup failure when worker release is unverified", async () => {
|
||||
const { producer, client, root } = await fixture("headless");
|
||||
|
||||
@@ -106,7 +106,7 @@ const parseWithoutMutatingSource = (bytes: Buffer) => {
|
||||
const parsed = parsePlistBinary(bytes);
|
||||
expect(parsed.ok).toBe(true);
|
||||
if (!parsed.ok) throw parsed.error;
|
||||
expect(bytes).toEqual(original);
|
||||
expect(Buffer.compare(bytes, original)).toBe(0);
|
||||
return parsed.value;
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ describe("core-only NT_FILE authority", () => {
|
||||
expect(result.ok).toBe(
|
||||
["/usr/bin/app", "//usr/lib/libc.so", "/a/.../b"].includes(path),
|
||||
);
|
||||
expect(bytes).toEqual(original);
|
||||
expect(Buffer.compare(bytes, original)).toBe(0);
|
||||
if (!result.ok)
|
||||
expect(result.error).toMatchObject({
|
||||
_tag: "AnalysisCapabilityUnavailableError",
|
||||
|
||||
@@ -51,8 +51,10 @@ describe("execFileOutput", () => {
|
||||
"process.stdout.write(Buffer.from([0x00, 0xff, 0x41])); process.stderr.write(Buffer.from([0xfe]));",
|
||||
]);
|
||||
|
||||
expect(result.stdout).toEqual(Buffer.from([0x00, 0xff, 0x41]));
|
||||
expect(result.stderr).toEqual(Buffer.from([0xfe]));
|
||||
expect(Buffer.compare(result.stdout, Buffer.from([0x00, 0xff, 0x41]))).toBe(
|
||||
0,
|
||||
);
|
||||
expect(Buffer.compare(result.stderr, Buffer.from([0xfe]))).toBe(0);
|
||||
});
|
||||
|
||||
it("reports raw byte counts when UTF-8 decoding changes the captured text", async () => {
|
||||
|
||||
@@ -26,7 +26,9 @@ it("retains all bytes across short reads through the declared size", async () =>
|
||||
expectedSize: BigInt(bytes.length),
|
||||
});
|
||||
if (result.status === "failed") throw result.entry;
|
||||
expect(Buffer.concat(result.chunks, result.total)).toEqual(bytes);
|
||||
expect(
|
||||
Buffer.compare(Buffer.concat(result.chunks, result.total), bytes),
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it("reports growth instead of continuing to consume a changed file", async () => {
|
||||
|
||||
@@ -327,7 +327,9 @@ it.each([
|
||||
expect(report.tool_profile.commands[0]?.arguments).toContain(
|
||||
"--ignore-custom-section-errors",
|
||||
);
|
||||
expect(await readFile(fixture.path)).toEqual(fixture.bytes);
|
||||
expect(Buffer.compare(await readFile(fixture.path), fixture.bytes)).toBe(
|
||||
0,
|
||||
);
|
||||
expect(report.headers).toBe(
|
||||
dump.slice(0, dump.indexOf("Section Details:\n")),
|
||||
);
|
||||
@@ -722,7 +724,12 @@ const launchWabtOutcome = async (
|
||||
const { bytes, dump, controller } = fixture;
|
||||
const version = input.arguments[0] === "--version";
|
||||
if (!version) {
|
||||
expect(await readFile(join(input.cwd ?? "", "module.wasm"))).toEqual(bytes);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(input.cwd ?? "", "module.wasm")),
|
||||
bytes,
|
||||
),
|
||||
).toBe(0);
|
||||
if (mode === "changed-snapshot") {
|
||||
const snapshot = join(input.cwd ?? "", "module.wasm");
|
||||
await chmod(snapshot, 0o600);
|
||||
@@ -821,7 +828,7 @@ it("enforces a selected command deadline and completes a corrected retry after c
|
||||
const report = wasmArtifactSchema.parse(corrected.value.result);
|
||||
expect(report.tool_profile.timeout_ms).toBe(2_000);
|
||||
expect(report.limitations.join(" ")).not.toContain("30-second");
|
||||
await expect(readFile(fixture.path)).resolves.toEqual(fixture.bytes);
|
||||
expect(Buffer.compare(await readFile(fixture.path), fixture.bytes)).toBe(0);
|
||||
});
|
||||
|
||||
const glueSourcesForOutcome = (mode: OutcomeMode) => {
|
||||
@@ -1006,7 +1013,7 @@ const runOwnedArtifactOutcome = async (
|
||||
);
|
||||
await assertSnapshotCleanupOutcome(mode, result, provider, runtimePath);
|
||||
await expect(access(runtimePath)).rejects.toMatchObject({ code: "ENOENT" });
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
if (acquiredPid !== undefined) {
|
||||
const pid = acquiredPid;
|
||||
expect(() => process.kill(pid, 0)).toThrow();
|
||||
|
||||
@@ -17,7 +17,9 @@ it("frames escaped quotes and trailing backslashes without consuming the next fo
|
||||
const encoded = JSON.stringify(value);
|
||||
const source = encoded + ' (export "next" (func 0))';
|
||||
expect(watStringEnd(source, 1)).toBe(encoded.length);
|
||||
expect(watString(source, 1).bytes).toEqual(Buffer.from(value));
|
||||
expect(
|
||||
Buffer.compare(watString(source, 1).bytes, Buffer.from(value)),
|
||||
).toBe(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ const expectUnsignedZip64 = async (
|
||||
runtime_execution: "not-performed",
|
||||
});
|
||||
}
|
||||
expect(await readFile(path)).toEqual(Buffer.from(bytes));
|
||||
expect(Buffer.compare(await readFile(path), Buffer.from(bytes))).toBe(0);
|
||||
};
|
||||
|
||||
const expectRefusal = async (
|
||||
@@ -75,7 +75,7 @@ const expectRefusal = async (
|
||||
const mcpError = parseMcpToolError(response).error;
|
||||
expect(mcpError).toMatchObject(expected);
|
||||
expect(mcpError.message).toBe(cliError.message);
|
||||
expect(await readFile(path)).toEqual(Buffer.from(bytes));
|
||||
expect(Buffer.compare(await readFile(path), Buffer.from(bytes))).toBe(0);
|
||||
};
|
||||
|
||||
cliTest(
|
||||
|
||||
@@ -84,7 +84,7 @@ cliTest.skipIf(process.platform === "win32")(
|
||||
"Contents/Resources/Panel.nib: Symlink target was not followed or disclosed.",
|
||||
);
|
||||
}
|
||||
expect(await readFile(link)).toEqual(fixture.nib);
|
||||
expect(Buffer.compare(await readFile(link), fixture.nib)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -204,12 +204,19 @@ cliTest(
|
||||
),
|
||||
).toEqual(ibResult);
|
||||
|
||||
expect(await readFile(archivePath)).toEqual(bytes);
|
||||
expect(await readFile(malformedArchivePath)).toEqual(malformedBytes);
|
||||
expect(Buffer.compare(await readFile(archivePath), bytes)).toBe(0);
|
||||
expect(
|
||||
await readFile(join(malformedApp, "Contents/Resources/Main.nib")),
|
||||
).toEqual(bytes);
|
||||
expect(await readFile(malformedNib)).toEqual(malformedBytes);
|
||||
Buffer.compare(await readFile(malformedArchivePath), malformedBytes),
|
||||
).toBe(0);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(malformedApp, "Contents/Resources/Main.nib")),
|
||||
bytes,
|
||||
),
|
||||
).toBe(0);
|
||||
expect(Buffer.compare(await readFile(malformedNib), malformedBytes)).toBe(
|
||||
0,
|
||||
);
|
||||
expect(createHash("sha256").update(bytes).digest("hex")).toBe(
|
||||
ibResult.documents[0]?.archive_sha256,
|
||||
);
|
||||
@@ -265,7 +272,7 @@ cliTest(
|
||||
parseEvidence(validated).normalized_result,
|
||||
);
|
||||
expect(mcpResult).toEqual(cliResult);
|
||||
expect(await readFile(archivePath)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(archivePath), bytes)).toBe(0);
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
@@ -61,6 +61,6 @@ cliTest
|
||||
},
|
||||
});
|
||||
await expect(access(marker)).rejects.toMatchObject({ code: "ENOENT" });
|
||||
expect(await readFile(target)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(target), original)).toBe(0);
|
||||
},
|
||||
);
|
||||
@@ -243,7 +243,7 @@ cliTest.for(["xml", "binary"] as const)(
|
||||
}),
|
||||
);
|
||||
expect(report.graph.truncated).toBe(false);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -92,7 +92,9 @@ cliTest.for([
|
||||
expect(properties?.parse_status).toBe(
|
||||
path === "main.mjs" ? "complete" : null,
|
||||
);
|
||||
expect(await readFile(join(directory, path))).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(join(directory, path)), bytes)).toBe(
|
||||
0,
|
||||
);
|
||||
}
|
||||
const fullResponse = await cli.run({
|
||||
arguments: [command, input, "--format", "json"],
|
||||
|
||||
@@ -28,12 +28,12 @@ cliTest(
|
||||
});
|
||||
expect(analyzed.exitCode, analyzed.stderr).toBe(1);
|
||||
expect(analyzed.json).toMatchObject(refusal);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
|
||||
const opened = await call("open_binary", { path });
|
||||
expect(opened.isError, JSON.stringify(opened)).toBe(true);
|
||||
expect(parseMcpToolError(opened).error).toMatchObject(refusal);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -154,7 +154,7 @@ cliTest.for(["xml", "binary"] as const)(
|
||||
status: "resolved",
|
||||
}),
|
||||
]);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -243,7 +243,7 @@ cliTest.for(["xml", "binary"] as const)(
|
||||
expect(result.limitations).toContain(
|
||||
'1 negative-zero real value(s) are reported as { "$plist_type": "real", "value": "-0" } because a JSON number cannot carry the sign of zero.',
|
||||
);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -346,7 +346,7 @@ cliTest("preserves binary IEEE non-finite scalar identity", async ({ cli }) => {
|
||||
parseEvidence(mcp.structuredContent).normalized_result,
|
||||
),
|
||||
).toEqual(result);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
});
|
||||
|
||||
cliTest(
|
||||
@@ -419,6 +419,6 @@ cliTest(
|
||||
expect(result.limitations).not.toContainEqual(
|
||||
expect.stringContaining('"value": null'),
|
||||
);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
@@ -130,7 +130,7 @@ cliTest.for([
|
||||
/non-finite|completely observed/u.test(note),
|
||||
),
|
||||
).toBe(false);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -178,7 +178,7 @@ cliTest(
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -105,6 +105,6 @@ cliTest(
|
||||
parseEvidence(reply.structuredContent).normalized_result,
|
||||
),
|
||||
).toEqual(result);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
@@ -207,7 +207,7 @@ cliTest.for(fixtures)(
|
||||
mode === "files" ? childPackages : [],
|
||||
);
|
||||
}
|
||||
expect(await readFile(path)).toEqual(Buffer.from(bytes));
|
||||
expect(Buffer.compare(await readFile(path), Buffer.from(bytes))).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -351,7 +351,7 @@ cliTest.for([
|
||||
}
|
||||
}
|
||||
if (encrypted) expect(Object.values(graph.components).flat()).toEqual([]);
|
||||
expect(await readFile(path)).toEqual(Buffer.from(bytes));
|
||||
expect(Buffer.compare(await readFile(path), Buffer.from(bytes))).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -174,8 +174,8 @@ describe.skipIf(process.platform !== "darwin")(
|
||||
provenance: [{ tool: "file" }],
|
||||
limitations: [],
|
||||
});
|
||||
expect(await readFile(binaryPath)).toEqual(binaryBytes);
|
||||
expect(await readFile(xmlPath)).toEqual(xmlBytes);
|
||||
expect(Buffer.compare(await readFile(binaryPath), binaryBytes)).toBe(0);
|
||||
expect(Buffer.compare(await readFile(xmlPath), xmlBytes)).toBe(0);
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
|
||||
@@ -89,7 +89,7 @@ describe.skipIf(process.platform !== "darwin")(
|
||||
environment,
|
||||
});
|
||||
const response = await call("inspect_plist", { path });
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
if (depth === 999) {
|
||||
expect(output.exitCode, output.stderr).toBe(1);
|
||||
const expectedFailure = {
|
||||
|
||||
@@ -194,7 +194,7 @@ cliTest(
|
||||
expect(report.limitations).toContainEqual(
|
||||
expect.stringContaining("NSString NS.bytes is not valid UTF-8"),
|
||||
);
|
||||
expect(await readFile(path)).toEqual(archive);
|
||||
expect(Buffer.compare(await readFile(path), archive)).toBe(0);
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
@@ -277,6 +277,6 @@ cliTest.for(["CLI", "stdio MCP"] as const)(
|
||||
}),
|
||||
);
|
||||
}
|
||||
expect(await readFile(archive)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(archive), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
@@ -132,7 +132,7 @@ const expectPeWordAlignedRecordsAcrossAdapters = async (input: {
|
||||
contract.outputSchema.parse(response.structuredContent)
|
||||
.normalized_result,
|
||||
).toEqual(evidence.normalized_result);
|
||||
expect(await readFile(path)).toEqual(fixture.bytes);
|
||||
expect(Buffer.compare(await readFile(path), fixture.bytes)).toBe(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -227,7 +227,7 @@ const expectPeMappingOwnershipAcrossAdapters = async (
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -308,7 +308,7 @@ const expectPeInventoriesAcrossAdapters = async (
|
||||
expect(contract.outputSchema.parse(JSON.parse(text.text)).evidence_id).toBe(
|
||||
evidence.evidence_id,
|
||||
);
|
||||
expect(await readFile(path)).toEqual(fixture.bytes);
|
||||
expect(Buffer.compare(await readFile(path), fixture.bytes)).toBe(0);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -406,7 +406,7 @@ const expectPeEmptyBranchesAcrossAdapters = async (
|
||||
expect(evidence.subject?.digest?.sha256).toBe(
|
||||
createHash("sha256").update(fixture.bytes).digest("hex"),
|
||||
);
|
||||
expect(await readFile(path)).toEqual(fixture.bytes);
|
||||
expect(Buffer.compare(await readFile(path), fixture.bytes)).toBe(0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -69,7 +69,11 @@ it.skipIf(process.platform !== "darwin")(
|
||||
code: "invalid_request",
|
||||
details: { issues: [{ path: ["path"] }] },
|
||||
});
|
||||
expect(await readFile(sourcePath)).toEqual(Buffer.from(source));
|
||||
expect(await readFile(decoyPath)).toEqual(Buffer.from(decoy));
|
||||
expect(
|
||||
Buffer.compare(await readFile(sourcePath), Buffer.from(source)),
|
||||
).toBe(0);
|
||||
expect(Buffer.compare(await readFile(decoyPath), Buffer.from(decoy))).toBe(
|
||||
0,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -81,7 +81,9 @@ cliTest.skipIf(process.platform !== "linux").for([false, true])(
|
||||
result.artifacts.map(({ relative_path }) => relative_path),
|
||||
).toEqual([...files.keys()]);
|
||||
for (const [path, bytes] of files)
|
||||
expect(await readFile(join(result.output_root, path))).toEqual(bytes);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(result.output_root, path)), bytes),
|
||||
).toBe(0);
|
||||
for (const limitations of [result.limitations, evidence.limitations]) {
|
||||
expect(
|
||||
limitations.some((value) => value.includes("not valid UTF-8")),
|
||||
@@ -171,7 +173,9 @@ cliTest.for([false, true])(
|
||||
result.artifacts.map(({ relative_path }) => relative_path),
|
||||
).toEqual(files.map(([path]) => path));
|
||||
for (const [path, bytes] of files) {
|
||||
expect(await readFile(join(result.output_root, path))).toEqual(bytes);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(result.output_root, path)), bytes),
|
||||
).toBe(0);
|
||||
expect(
|
||||
result.artifacts.find((file) => file.relative_path === path),
|
||||
).toMatchObject({
|
||||
|
||||
@@ -38,7 +38,7 @@ cliTest("inspects a relative DTB and preserves the source", async ({ cli }) => {
|
||||
summary: { model: "Test board" },
|
||||
coverage: { examined_nodes: 5 },
|
||||
});
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
});
|
||||
cliTest(
|
||||
"does not resolve through a legacy phandle when the canonical value is malformed",
|
||||
|
||||
@@ -51,7 +51,7 @@ cliTest(
|
||||
expect(evidence.normalized_result.entries[0]?.gnu?.build_id_hex).toBe(
|
||||
"0123456789abcdef0123456789abcdef01234567",
|
||||
);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -82,7 +82,7 @@ cliTest(
|
||||
examined_tables: 1,
|
||||
examined_entries: 1,
|
||||
});
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -138,7 +138,7 @@ cliTest(
|
||||
"Compressed ELF note sections are unsupported",
|
||||
),
|
||||
});
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -39,9 +39,12 @@ const extendedFirstAtomLength = (): Buffer => {
|
||||
const payloadOffset = chunkOffset + 8;
|
||||
const payloadSize = control.readUInt32BE(chunkOffset + 4);
|
||||
const payloadEnd = payloadOffset + payloadSize;
|
||||
expect(control.subarray(payloadOffset + 4, payloadOffset + 6)).toEqual(
|
||||
Buffer.from([0x08, 0x10]),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
control.subarray(payloadOffset + 4, payloadOffset + 6),
|
||||
Buffer.from([0x08, 0x10]),
|
||||
),
|
||||
).toBe(0);
|
||||
const payload = Buffer.concat([
|
||||
control.subarray(payloadOffset, payloadOffset + 4),
|
||||
Buffer.from([0x18, 0x00, 0x10]),
|
||||
@@ -153,7 +156,7 @@ cliTest(
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -550,8 +550,11 @@ for (const format of ["elf", "pe", "macho"] as const) {
|
||||
.toString("utf8"),
|
||||
).toBe(report.build_info.go_version);
|
||||
expect(
|
||||
fixture.bytes.subarray(module.offset, module.offset + module.bytes),
|
||||
).toEqual(Buffer.from(report.build_info.module_bytes_base64, "base64"));
|
||||
Buffer.compare(
|
||||
fixture.bytes.subarray(module.offset, module.offset + module.bytes),
|
||||
Buffer.from(report.build_info.module_bytes_base64, "base64"),
|
||||
),
|
||||
).toBe(0);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ cliTest(
|
||||
const response = await call("inspect_go_binary", { path });
|
||||
expect(response.isError, JSON.stringify(response)).not.toBe(true);
|
||||
expect(response.structuredContent).toEqual(evidence);
|
||||
expect(await readFile(path)).toEqual(fixture.bytes);
|
||||
expect(Buffer.compare(await readFile(path), fixture.bytes)).toBe(0);
|
||||
}
|
||||
|
||||
const damaged = createGoCrossLoadPointerFixture("contents");
|
||||
|
||||
@@ -343,7 +343,7 @@ cliTest(
|
||||
);
|
||||
const before = await readFile(bundle);
|
||||
expect((await cli.run({ arguments: args })).exitCode).toBe(1);
|
||||
expect(await readFile(bundle)).toEqual(before);
|
||||
expect(Buffer.compare(await readFile(bundle), before)).toBe(0);
|
||||
await unlink(source);
|
||||
const query = join(root, "query.json");
|
||||
await writeFile(
|
||||
|
||||
@@ -188,7 +188,7 @@ test("preserves Harmony archive formats through the public CLI/MCP lifecycle", a
|
||||
expect(empty.structuredContent).toMatchObject({
|
||||
result: { open: false },
|
||||
});
|
||||
expect(await readFile(path)).toEqual(Buffer.from(bytes));
|
||||
expect(Buffer.compare(await readFile(path), Buffer.from(bytes))).toBe(0);
|
||||
}
|
||||
} finally {
|
||||
await client.close();
|
||||
|
||||
@@ -78,7 +78,7 @@ cliTest(
|
||||
});
|
||||
expect(response.isError).not.toBe(true);
|
||||
expect(parseCliMetadata(response.structuredContent)).toEqual(report);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
}
|
||||
for (const [records, declaredCount, declaredBytes] of [
|
||||
[0, 1, 0],
|
||||
@@ -123,7 +123,7 @@ cliTest(
|
||||
});
|
||||
expect(response.isError).toBe(true);
|
||||
expect(parseMcpToolError(response).error).toMatchObject(expected);
|
||||
expect(await readFile(path)).toEqual(fixture.bytes);
|
||||
expect(Buffer.compare(await readFile(path), fixture.bytes)).toBe(0);
|
||||
}
|
||||
},
|
||||
30000,
|
||||
@@ -682,7 +682,7 @@ cliTest(
|
||||
const before = await readFile(bundle);
|
||||
const overwrite = await runFileCli(cli, { arguments: args });
|
||||
expect(overwrite.exitCode).toBe(1);
|
||||
expect(await readFile(bundle)).toEqual(before);
|
||||
expect(Buffer.compare(await readFile(bundle), before)).toBe(0);
|
||||
const saved = await readEvidenceBundle(bundle);
|
||||
if (!saved.ok) throw saved.error;
|
||||
const evidence = saved.value.records[0];
|
||||
@@ -928,7 +928,7 @@ cliTest(
|
||||
sha256: createHash("sha256").update(bytes).digest("hex"),
|
||||
bytes: bytes.length,
|
||||
});
|
||||
expect(await readFile(binaryPath)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(binaryPath), bytes)).toBe(0);
|
||||
return report;
|
||||
};
|
||||
const control = await inspect(createIl2cppBinaryFixture());
|
||||
@@ -1026,7 +1026,7 @@ cliTest(
|
||||
expect(response.isError, JSON.stringify(response)).not.toBe(true);
|
||||
expect(parseCliMetadata(response.structuredContent)).toEqual(report);
|
||||
}
|
||||
expect(await readFile(binaryPath)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(binaryPath), bytes)).toBe(0);
|
||||
}
|
||||
await client.ping();
|
||||
},
|
||||
|
||||
@@ -127,7 +127,7 @@ cliTest(
|
||||
parseEvidence(response.structuredContent).normalized_result,
|
||||
).toEqual(evidence.normalized_result);
|
||||
}
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
await rm(path);
|
||||
}
|
||||
const compared = await call("compare_managed_members", {
|
||||
|
||||
@@ -48,7 +48,7 @@ cliTest(
|
||||
expect(report.coverage.state).toBe("complete");
|
||||
sources.push(evidence);
|
||||
}
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
await rm(path);
|
||||
const call = await cli.sharedMcpCall!();
|
||||
for (const [index, right] of sources.slice(1).entries()) {
|
||||
@@ -129,7 +129,7 @@ cliTest(
|
||||
whole.push(evidence);
|
||||
}
|
||||
}
|
||||
expect(await readFile(path)).toEqual(content);
|
||||
expect(Buffer.compare(await readFile(path), content)).toBe(0);
|
||||
await rm(path);
|
||||
}
|
||||
const left = managedMemberInspectionSchema.parse(
|
||||
|
||||
@@ -163,7 +163,7 @@ cliTest(
|
||||
coverage,
|
||||
});
|
||||
expect(summary.summary.limitations).toContainEqual(limitation);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
await unlink(path);
|
||||
|
||||
const source = {
|
||||
@@ -419,7 +419,7 @@ cliTest(
|
||||
reason.includes("have released") || reason.includes("has released"),
|
||||
))
|
||||
expect(summary.summary.limitations).toContain(limitation);
|
||||
expect(await readFile(path)).toEqual(fixture.bytes);
|
||||
expect(Buffer.compare(await readFile(path), fixture.bytes)).toBe(0);
|
||||
await unlink(path);
|
||||
await assertRetainedLayoutViews(
|
||||
call,
|
||||
|
||||
@@ -113,8 +113,8 @@ cliTest.skipIf(process.platform !== "darwin")(
|
||||
).toEqual(
|
||||
savedSnapshot.value.workflow_entries[0]?.execution.analysis_profile,
|
||||
);
|
||||
expect(await readFile(first)).toEqual(Buffer.from(bytes));
|
||||
expect(await readFile(second)).toEqual(Buffer.from(bytes));
|
||||
expect(Buffer.compare(await readFile(first), Buffer.from(bytes))).toBe(0);
|
||||
expect(Buffer.compare(await readFile(second), Buffer.from(bytes))).toBe(0);
|
||||
},
|
||||
30000,
|
||||
);
|
||||
@@ -170,7 +170,7 @@ cliTest.skipIf(process.platform !== "darwin")(
|
||||
},
|
||||
});
|
||||
}
|
||||
expect(await readFile(target)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(target), bytes)).toBe(0);
|
||||
await client.ping();
|
||||
},
|
||||
30000,
|
||||
@@ -304,7 +304,7 @@ cliTest.skipIf(process.platform !== "darwin")(
|
||||
});
|
||||
expect(reobserved.isError, JSON.stringify(reobserved)).not.toBe(true);
|
||||
expect(parseEvidence(reobserved.structuredContent)).toEqual(mcpEvidence);
|
||||
expect(await readFile(target)).toEqual(Buffer.from(bytes));
|
||||
expect(Buffer.compare(await readFile(target), Buffer.from(bytes))).toBe(0);
|
||||
await client.ping();
|
||||
},
|
||||
30000,
|
||||
|
||||
@@ -228,7 +228,9 @@ cliTest(
|
||||
expected.map((item) => item.path).sort(),
|
||||
);
|
||||
for (const { path, body } of expected)
|
||||
expect(await readFile(join(result.output_root, path))).toEqual(body);
|
||||
expect(
|
||||
Buffer.compare(await readFile(join(result.output_root, path)), body),
|
||||
).toBe(0);
|
||||
};
|
||||
|
||||
const inspected = await cli.run({
|
||||
|
||||
@@ -289,16 +289,29 @@ cliTest(
|
||||
);
|
||||
try {
|
||||
expect(
|
||||
await readFile(join(result.output_root, "pkg", "data.bin")),
|
||||
).toEqual(stored);
|
||||
Buffer.compare(
|
||||
await readFile(join(result.output_root, "pkg", "data.bin")),
|
||||
stored,
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
await readFile(join(result.output_root, "PYZ.pyz", "res", "icon.bin")),
|
||||
).toEqual(icon);
|
||||
Buffer.compare(
|
||||
await readFile(
|
||||
join(result.output_root, "PYZ.pyz", "res", "icon.bin"),
|
||||
),
|
||||
icon,
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
(
|
||||
await readFile(join(result.output_root, "PYZ.pyz", "pkg", "mod.pyc"))
|
||||
).subarray(16),
|
||||
).toEqual(module);
|
||||
Buffer.compare(
|
||||
(
|
||||
await readFile(
|
||||
join(result.output_root, "PYZ.pyz", "pkg", "mod.pyc"),
|
||||
)
|
||||
).subarray(16),
|
||||
module,
|
||||
),
|
||||
).toBe(0);
|
||||
} finally {
|
||||
await rm(result.output_root, { recursive: true, force: true });
|
||||
}
|
||||
@@ -321,9 +334,12 @@ it("extracts legacy and modern CArchive modules with one pyc header through the
|
||||
);
|
||||
try {
|
||||
for (const module of fixture.modules) {
|
||||
expect(await readFile(join(extraction.output_root, module.name))).toEqual(
|
||||
module.bytes,
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(extraction.output_root, module.name)),
|
||||
module.bytes,
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
extraction.artifacts.find((item) => item.relative_path === module.name),
|
||||
).toMatchObject({
|
||||
@@ -465,9 +481,12 @@ it("extracts CArchive members through extract-artifact", async () => {
|
||||
expect(
|
||||
await readFile(join(extracted.output_root, "PYZ.pyz", "app.pyc")),
|
||||
).toHaveLength(16 + Buffer.from("app-body").length);
|
||||
expect(await readFile(join(extracted.output_root, "hello"))).toEqual(
|
||||
Buffer.from("print('hi')"),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(extracted.output_root, "hello")),
|
||||
Buffer.from("print('hi')"),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(await readdir(extracted.output_root)).not.toContain("__pyinstaller__");
|
||||
expect(
|
||||
extracted.artifacts.some((item) =>
|
||||
@@ -564,11 +583,17 @@ it("preserves a PYZ namespace declaration beside a physical CArchive file at the
|
||||
expect.arrayContaining(["PYZ.pyz/ns", "healthy.txt"]),
|
||||
);
|
||||
expect(
|
||||
await readFile(join(extracted.output_root, "PYZ.pyz", "ns")),
|
||||
).toEqual(Buffer.from("outer data"));
|
||||
expect(await readFile(join(extracted.output_root, "healthy.txt"))).toEqual(
|
||||
Buffer.from("healthy sibling"),
|
||||
);
|
||||
Buffer.compare(
|
||||
await readFile(join(extracted.output_root, "PYZ.pyz", "ns")),
|
||||
Buffer.from("outer data"),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(extracted.output_root, "healthy.txt")),
|
||||
Buffer.from("healthy sibling"),
|
||||
),
|
||||
).toBe(0);
|
||||
} finally {
|
||||
await rm(extracted.output_root, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
@@ -586,7 +586,7 @@ cliTest(
|
||||
{ stage: "denied", handleId: 0, open: true },
|
||||
{ stage: "released", handleId: 0, fd: -1 },
|
||||
]);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ cliTest(
|
||||
const response = await call("inspect_rust_binary", { path });
|
||||
expect(response.isError, JSON.stringify(response)).not.toBe(true);
|
||||
expect(response.structuredContent).toEqual(evidence);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
}
|
||||
await client.ping();
|
||||
},
|
||||
|
||||
@@ -166,7 +166,7 @@ for (const scenario of cases)
|
||||
});
|
||||
if (!("syntax" in scenario))
|
||||
expect(uninstall.stdout).not.toContain("not valid JSON");
|
||||
expect(await readFile(config)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(config), original)).toBe(0);
|
||||
expect(await readdir(dirname(config))).toEqual([
|
||||
scenario.path.split("/").at(-1),
|
||||
]);
|
||||
|
||||
@@ -63,7 +63,9 @@ cliTest(
|
||||
code: "ENOENT",
|
||||
});
|
||||
expect(await readFile(trust, "utf8")).toBe(text);
|
||||
expect(await readFile(fixture.user)).toEqual(fixture.originalUser);
|
||||
expect(
|
||||
Buffer.compare(await readFile(fixture.user), fixture.originalUser),
|
||||
).toBe(0);
|
||||
}
|
||||
|
||||
const workspaceText = "{ not json";
|
||||
@@ -92,7 +94,9 @@ cliTest(
|
||||
});
|
||||
expect(await readFile(fixture.workspace, "utf8")).toBe(workspaceText);
|
||||
expect(await readFile(trust, "utf8")).toBe("{ not json");
|
||||
expect(await readFile(fixture.user)).toEqual(fixture.originalUser);
|
||||
expect(
|
||||
Buffer.compare(await readFile(fixture.user), fixture.originalUser),
|
||||
).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -135,8 +139,12 @@ for (const scenario of [
|
||||
]),
|
||||
},
|
||||
});
|
||||
expect(await readFile(fixture.workspace)).toEqual(malformed);
|
||||
expect(await readFile(fixture.user)).toEqual(fixture.originalUser);
|
||||
expect(Buffer.compare(await readFile(fixture.workspace), malformed)).toBe(
|
||||
0,
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(await readFile(fixture.user), fixture.originalUser),
|
||||
).toBe(0);
|
||||
await expect(
|
||||
access(`${fixture.workspace}.rea.backup`),
|
||||
).rejects.toMatchObject({
|
||||
@@ -162,7 +170,9 @@ for (const scenario of [
|
||||
]),
|
||||
},
|
||||
});
|
||||
expect(await readFile(fixture.workspace)).toEqual(excluded);
|
||||
expect(
|
||||
Buffer.compare(await readFile(fixture.workspace), excluded),
|
||||
).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -208,8 +218,12 @@ cliTest(
|
||||
]),
|
||||
},
|
||||
});
|
||||
expect(await readFile(fixture.workspace)).toEqual(original);
|
||||
expect(await readFile(fixture.user)).toEqual(fixture.originalUser);
|
||||
expect(Buffer.compare(await readFile(fixture.workspace), original)).toBe(
|
||||
0,
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(await readFile(fixture.user), fixture.originalUser),
|
||||
).toBe(0);
|
||||
await expect(
|
||||
access(`${fixture.workspace}.rea.backup`),
|
||||
).rejects.toMatchObject({
|
||||
|
||||
@@ -173,12 +173,18 @@ cliTest(
|
||||
}),
|
||||
]),
|
||||
});
|
||||
expect(await readFile(join(selected, "SKILL.md"))).toEqual(
|
||||
await readFile(join(source, "SKILL.md")),
|
||||
);
|
||||
expect(await readFile(join(managed, "native-and-artifacts.md"))).toEqual(
|
||||
before,
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(selected, "SKILL.md")),
|
||||
await readFile(join(source, "SKILL.md")),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(managed, "native-and-artifacts.md")),
|
||||
before,
|
||||
),
|
||||
).toBe(0);
|
||||
expect((await lstat(join(selected, "references"))).isSymbolicLink()).toBe(
|
||||
true,
|
||||
);
|
||||
@@ -247,9 +253,12 @@ cliTest(
|
||||
})) {
|
||||
if (!entry.isFile()) continue;
|
||||
const path = relative(bundle, join(entry.parentPath, entry.name));
|
||||
expect(await readFile(join(selected, path))).toEqual(
|
||||
await readFile(join(bundle, path)),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(selected, path)),
|
||||
await readFile(join(bundle, path)),
|
||||
),
|
||||
).toBe(0);
|
||||
}
|
||||
};
|
||||
await assertAligned();
|
||||
|
||||
@@ -42,7 +42,7 @@ cliTest(
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(await readFile(skill)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(skill), original)).toBe(0);
|
||||
|
||||
const audit = await run(["doctor"]);
|
||||
expect(audit.json).toMatchObject({
|
||||
@@ -54,7 +54,7 @@ cliTest(
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(await readFile(skill)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(skill), original)).toBe(0);
|
||||
|
||||
await mkdir(join(home, ".cursor"));
|
||||
const withMarker = await run(["doctor"]);
|
||||
@@ -67,7 +67,7 @@ cliTest(
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(await readFile(skill)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(skill), original)).toBe(0);
|
||||
|
||||
await writeFile(
|
||||
skill,
|
||||
@@ -102,7 +102,7 @@ cliTest(
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(await readFile(reference)).toEqual(retained);
|
||||
expect(Buffer.compare(await readFile(reference), retained)).toBe(0);
|
||||
}
|
||||
|
||||
const emptyHome = await createTestTempDirectory(
|
||||
@@ -146,6 +146,6 @@ cliTest(
|
||||
healthy: false,
|
||||
identity: { skill: { state: "stale", installed_version: null } },
|
||||
});
|
||||
expect(await readFile(foreignSkill)).toEqual(foreignBytes);
|
||||
expect(Buffer.compare(await readFile(foreignSkill), foreignBytes)).toBe(0);
|
||||
},
|
||||
);
|
||||
@@ -322,7 +322,7 @@ cliTest.runIf(SQLITE_NATIVE_LIMITS_AVAILABLE)(
|
||||
{ path, table: "selected", columns: ["ID"] },
|
||||
])
|
||||
expect((await call("inspect_sqlite_database", input)).isError).toBe(true);
|
||||
expect(await readFile(path)).toEqual(before);
|
||||
expect(Buffer.compare(await readFile(path), before)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -632,7 +632,7 @@ cliTest
|
||||
});
|
||||
expect(response.isError, JSON.stringify(response)).not.toBe(true);
|
||||
expect(response.structuredContent).toEqual(result.json);
|
||||
expect(await readFile(path)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(path), original)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1074,7 +1074,7 @@ cliTest.runIf(SQLITE_NATIVE_LIMITS_AVAILABLE)(
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(await readFile(path)).toEqual(before);
|
||||
expect(Buffer.compare(await readFile(path), before)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1136,7 +1136,7 @@ cliTest.runIf(SQLITE_NATIVE_LIMITS_AVAILABLE)(
|
||||
expect(response.isError, JSON.stringify(response)).not.toBe(true);
|
||||
expect(response.structuredContent).toEqual(result.json);
|
||||
}
|
||||
expect(await readFile(path)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(path), original)).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1338,7 +1338,7 @@ cliTest.runIf(SQLITE_NATIVE_LIMITS_AVAILABLE)(
|
||||
const response = await call("inspect_sqlite_database", { path });
|
||||
expect(response.isError, JSON.stringify(response)).not.toBe(true);
|
||||
expect(response.structuredContent).toEqual(result.json);
|
||||
expect(await readFile(path)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(path), original)).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -162,7 +162,7 @@ const verifyPortableCli = async (
|
||||
expect(ids.has(dependency.evidence_id)).toBe(true);
|
||||
expect(ids.has(unrelated.evidence_id)).toBe(false);
|
||||
expect(ids.has(evidenceId)).toBe(true);
|
||||
expect(await readFile(bundlePath)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(bundlePath), original)).toBe(0);
|
||||
const incomplete = await cli.run({
|
||||
arguments: [
|
||||
"match-native-functions",
|
||||
|
||||
@@ -198,7 +198,9 @@ cliTest(
|
||||
},
|
||||
});
|
||||
}
|
||||
expect(await readFile(descriptor)).toEqual(Buffer.from(bytes));
|
||||
expect(
|
||||
Buffer.compare(await readFile(descriptor), Buffer.from(bytes)),
|
||||
).toBe(0);
|
||||
expect(await readFile(capture, "utf8")).toBe(text);
|
||||
}
|
||||
},
|
||||
@@ -295,7 +297,9 @@ cliTest(
|
||||
expect(parseEvidence(response.structuredContent).evidence_id).toBe(
|
||||
evidence.evidence_id,
|
||||
);
|
||||
expect(await readFile(descriptor)).toEqual(Buffer.from(bytes));
|
||||
expect(
|
||||
Buffer.compare(await readFile(descriptor), Buffer.from(bytes)),
|
||||
).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -165,7 +165,9 @@ cliTest(
|
||||
protobuf_coverage: { status: "partial", inspected_records: 0 },
|
||||
},
|
||||
});
|
||||
expect(await readFile(descriptor)).toEqual(Buffer.from(bytes));
|
||||
expect(
|
||||
Buffer.compare(await readFile(descriptor), Buffer.from(bytes)),
|
||||
).toBe(0);
|
||||
}
|
||||
expect(await readFile(capture, "utf8")).toBe(text);
|
||||
},
|
||||
@@ -257,6 +259,8 @@ cliTest(
|
||||
expect(parseEvidence(response.structuredContent).evidence_id).toBe(
|
||||
evidence.evidence_id,
|
||||
);
|
||||
expect(await readFile(descriptor)).toEqual(Buffer.from(definition));
|
||||
expect(
|
||||
Buffer.compare(await readFile(descriptor), Buffer.from(definition)),
|
||||
).toBe(0);
|
||||
},
|
||||
);
|
||||
@@ -149,7 +149,9 @@ cliTest(
|
||||
parseMcpToolError(response).error,
|
||||
`${scope}-${reverse}`,
|
||||
).toMatchObject(expected);
|
||||
expect(await readFile(descriptor)).toEqual(Buffer.from(bytes));
|
||||
expect(
|
||||
Buffer.compare(await readFile(descriptor), Buffer.from(bytes)),
|
||||
).toBe(0);
|
||||
}
|
||||
expect(await readFile(capture, "utf8")).toBe(text);
|
||||
},
|
||||
@@ -216,6 +218,8 @@ cliTest(
|
||||
{ number: 1, schema_name: fieldName, schema_value: "1" },
|
||||
]);
|
||||
}
|
||||
expect(await readFile(descriptor)).toEqual(Buffer.from(bytes));
|
||||
expect(Buffer.compare(await readFile(descriptor), Buffer.from(bytes))).toBe(
|
||||
0,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -60,7 +60,7 @@ it.each([
|
||||
report.decoder_diagnostics,
|
||||
),
|
||||
).not.toThrow();
|
||||
expect(snapshot).toEqual(original);
|
||||
expect(Buffer.compare(snapshot, original)).toBe(0);
|
||||
expect(report.note_interpretation_completeness).toBe("unknown");
|
||||
expect(report.live_process_identity).toBe("unknown");
|
||||
},
|
||||
@@ -178,6 +178,6 @@ it.each(["/usr/bin/fixture", "../../fixture", "/a/../fixture"])(
|
||||
expect(validateCoreFileMappingAuthority(report, snapshot).ok).toBe(
|
||||
path === "/usr/bin/fixture",
|
||||
);
|
||||
expect(snapshot).toEqual(original);
|
||||
expect(Buffer.compare(snapshot, original)).toBe(0);
|
||||
},
|
||||
);
|
||||
@@ -159,7 +159,9 @@ it
|
||||
const request = requestSchema.parse(
|
||||
JSON.parse(await readFile(spawn.arguments.at(-1) ?? "", "utf8")),
|
||||
);
|
||||
expect(await readFile(request.snapshot_path)).toEqual(bytes);
|
||||
expect(
|
||||
Buffer.compare(await readFile(request.snapshot_path), bytes),
|
||||
).toBe(0);
|
||||
const payload = structuredClone(value);
|
||||
alterRecordedCrashReply(payload, scenario);
|
||||
const {
|
||||
@@ -201,7 +203,7 @@ it
|
||||
capturedOutput: { stdout: "recorded warning" },
|
||||
},
|
||||
});
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
await expect(access(owned)).rejects.toMatchObject({ code: "ENOENT" });
|
||||
},
|
||||
);
|
||||
@@ -257,7 +259,9 @@ it
|
||||
const request = requestSchema.parse(
|
||||
JSON.parse(await readFile(spawn.arguments.at(-1) ?? "", "utf8")),
|
||||
);
|
||||
expect(await readFile(request.snapshot_path)).toEqual(bytes);
|
||||
expect(
|
||||
Buffer.compare(await readFile(request.snapshot_path), bytes),
|
||||
).toBe(0);
|
||||
if (snapshotPath === "") {
|
||||
snapshotPath = request.snapshot_path;
|
||||
owned = spawn.cwd ?? "";
|
||||
@@ -341,14 +345,14 @@ it
|
||||
}
|
||||
if (scenario === "cancelled" || scenario === "cancelled-exec")
|
||||
expectDebuggerStopped(debuggerProcess);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
if (
|
||||
scenario === "cleanup-failure" ||
|
||||
scenario === "decoder-cleanup-failure" ||
|
||||
scenario === "cancelled-exec-foreign"
|
||||
) {
|
||||
await expect(access(owned)).resolves.toBeUndefined();
|
||||
expect(await readFile(snapshotPath)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(snapshotPath), bytes)).toBe(0);
|
||||
const refused = await provider.inspect({
|
||||
path,
|
||||
include_debugger_context: true,
|
||||
@@ -538,7 +542,7 @@ it.runIf(host)(
|
||||
include_debugger_context: true,
|
||||
pwntools_timeout_ms: 1_500,
|
||||
});
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
if (result.ok) throw new Error("expected debugger timeout");
|
||||
const projected = projectAnalysisError(result.error);
|
||||
expect(projected.code).toBe("provider_timeout");
|
||||
|
||||
@@ -286,7 +286,7 @@ it("checks trailer credentials before hidden metadata blocks analysis and withho
|
||||
);
|
||||
expect(opaque.records[0]?.protobuf).toBeUndefined();
|
||||
expect(opaque.protobuf_coverage?.status).toBe("partial");
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
});
|
||||
|
||||
it("keeps automatic framing applicability unknown when SAZ Content-Type is excluded or conflicting", async () => {
|
||||
@@ -394,7 +394,7 @@ it("keeps automatic framing applicability unknown when SAZ Content-Type is exclu
|
||||
expect(explicit.records[0]?.protobuf).toMatchObject([
|
||||
{ status: "complete", fields: [{ number: 1, value: "1" }] },
|
||||
]);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
});
|
||||
|
||||
it("inspects native SAZ through the public CLI and MCP with equal evidence, bytes and archive coordinates", async () => {
|
||||
@@ -470,7 +470,7 @@ it("inspects native SAZ through the public CLI and MCP with equal evidence, byte
|
||||
expect(capture.artifact.sha256).toBe(
|
||||
createHash("sha256").update(bytes).digest("hex"),
|
||||
);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
|
||||
const { client, call } = await connectLocalToolsMcp();
|
||||
const tool = (await client.listTools()).tools.find(
|
||||
@@ -624,7 +624,7 @@ it("keeps CRLF separators inside a body after LF-only HTTP headers", async () =>
|
||||
bytes: body.length,
|
||||
sha256: createHash("sha256").update(body).digest("hex"),
|
||||
});
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
});
|
||||
|
||||
it("reports zero-byte SAZ HTTP members as null instead of rejecting the archive", async () => {
|
||||
@@ -890,7 +890,7 @@ it.each([
|
||||
expect(error.details).not.toHaveProperty("partial_observation");
|
||||
expect(mcpFailure).not.toHaveProperty("normalized_result");
|
||||
expect(mcpFailure.error.details).not.toHaveProperty("partial_observation");
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
}
|
||||
expect(JSON.stringify(result)).not.toContain("malformed-private-input");
|
||||
});
|
||||
|
||||
@@ -62,7 +62,7 @@ cliTest(
|
||||
action: "Evidence file already exists. Choose another output path.",
|
||||
},
|
||||
});
|
||||
expect(await readFile(output)).toEqual(before);
|
||||
expect(Buffer.compare(await readFile(output), before)).toBe(0);
|
||||
const next = await cli.run({
|
||||
arguments: [
|
||||
"inspect-artifact",
|
||||
|
||||
@@ -199,7 +199,7 @@ it.each(kinds)(
|
||||
detail: "summary",
|
||||
evidence_output: destination,
|
||||
});
|
||||
expect(await readFile(destination)).toEqual(original);
|
||||
expect(Buffer.compare(await readFile(destination), original)).toBe(0);
|
||||
expect(output).toHaveProperty("code");
|
||||
expect(output).not.toHaveProperty("summary");
|
||||
expect(output).toHaveProperty("details.partial_observation.evidence_id");
|
||||
|
||||
@@ -88,9 +88,13 @@ cliTest(
|
||||
expect(files).toEqual(await listFiles(join(root, "three-step")));
|
||||
expect(files).toHaveLength(7);
|
||||
for (const file of files)
|
||||
expect(await readFile(join(root, "built", file)), file).toEqual(
|
||||
await readFile(join(root, "three-step", file)),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(join(root, "built", file)),
|
||||
await readFile(join(root, "three-step", file)),
|
||||
),
|
||||
file,
|
||||
).toBe(0);
|
||||
expect(built.json).toMatchObject({
|
||||
tool_count: (exported.json as { tool_count: number }).tool_count,
|
||||
files: (exported.json as { files: unknown[] }).files,
|
||||
|
||||
@@ -116,11 +116,17 @@ cliTest(
|
||||
.sort();
|
||||
expect(written).toEqual(BUNDLE_FILES);
|
||||
expect(
|
||||
await readFile(join(directory, "envs/grafana-example/manifest.json")),
|
||||
).toEqual(await readFile(files.manifestPath));
|
||||
Buffer.compare(
|
||||
await readFile(join(directory, "envs/grafana-example/manifest.json")),
|
||||
await readFile(files.manifestPath),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(
|
||||
await readFile(join(directory, "envs/grafana-example/evidence.json")),
|
||||
).toEqual(await readFile(files.capturePath));
|
||||
Buffer.compare(
|
||||
await readFile(join(directory, "envs/grafana-example/evidence.json")),
|
||||
await readFile(files.capturePath),
|
||||
),
|
||||
).toBe(0);
|
||||
const dockerfile = await readFile(
|
||||
join(directory, "envs/grafana-example/Dockerfile"),
|
||||
"utf8",
|
||||
@@ -253,8 +259,11 @@ cliTest.skipIf(process.platform === "win32")(
|
||||
).toBeGreaterThan(0);
|
||||
}
|
||||
expect(
|
||||
await readFile(join(directory, "envs/grafana-example/evidence.json")),
|
||||
).toEqual(await readFile(files.capturePath));
|
||||
Buffer.compare(
|
||||
await readFile(join(directory, "envs/grafana-example/evidence.json")),
|
||||
await readFile(files.capturePath),
|
||||
),
|
||||
).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -290,10 +299,13 @@ cliTest.skipIf(process.platform === "win32")(
|
||||
package_source: { kind: "tarball", path: packagePath },
|
||||
});
|
||||
expect(
|
||||
await readFile(
|
||||
join(physical, "bundle/envs/grafana-example/rea-agents.tgz"),
|
||||
Buffer.compare(
|
||||
await readFile(
|
||||
join(physical, "bundle/envs/grafana-example/rea-agents.tgz"),
|
||||
),
|
||||
bytes,
|
||||
),
|
||||
).toEqual(bytes);
|
||||
).toBe(0);
|
||||
await expect(
|
||||
readFile(join(root, "bundle/README.md")),
|
||||
).rejects.toMatchObject({ code: "ENOENT" });
|
||||
|
||||
@@ -49,9 +49,12 @@ for (const role of ["manifest", "evidence"] as const) {
|
||||
timeoutMs: 30_000,
|
||||
});
|
||||
expect(await readFile(marker, "utf8")).toBe("read");
|
||||
expect(await readFile(input)).toEqual(
|
||||
Buffer.concat([before, Buffer.from(" ")]),
|
||||
);
|
||||
expect(
|
||||
Buffer.compare(
|
||||
await readFile(input),
|
||||
Buffer.concat([before, Buffer.from(" ")]),
|
||||
),
|
||||
).toBe(0);
|
||||
expect(result.exitCode, result.stderr).toBe(1);
|
||||
expect(result.json).toMatchObject({
|
||||
code: "invalid_request",
|
||||
|
||||
@@ -82,7 +82,9 @@ cliTest.skipIf(process.platform !== "darwin").for([true, false])(
|
||||
}),
|
||||
]),
|
||||
});
|
||||
expect(await readFile(registration)).toEqual(registrationBytes);
|
||||
expect(
|
||||
Buffer.compare(await readFile(registration), registrationBytes),
|
||||
).toBe(0);
|
||||
expect(await readdir(physical)).toEqual(before);
|
||||
if (usable) {
|
||||
expect(await readdir(parent)).toEqual([]);
|
||||
|
||||
@@ -59,7 +59,7 @@ cliTest(
|
||||
expect(mcpOutput.isError, JSON.stringify(mcpOutput)).not.toBe(true);
|
||||
const mcpResult = parseResult(mcpOutput.structuredContent);
|
||||
expect(mcpResult).toEqual(cliResult);
|
||||
expect(await readFile(path)).toEqual(bytes);
|
||||
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
Loaded 100 of 182 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user