mirror of
https://github.com/morluto/rea.git
synced 2026-11-12 01:41:21 +00:00
Merge remote-tracking branch 'origin/main' into codex/release-notes-6.9.0-20261111
This commit is contained in:
commit
7f99d80986
9 files changed
+123
-8
No files matched your search
@@ -74,6 +74,52 @@ describe("parseAdbDevicesOutput", () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("classifies adb mDNS wireless serials as TCP without treating them as USB", () => {
|
||||
const output = [
|
||||
"List of devices attached",
|
||||
"adb-8c4f2a1b4e5d6f70-AbCdEf._adb-tls-connect._tcp device product:cheetah model:Pixel_7_Pro device:cheetah transport_id:4",
|
||||
"phone._adb._tcp device transport_id:5",
|
||||
"not-a-service._tcp device transport_id:6",
|
||||
"adb-wired._adb-tls-connect._tcp device usb:1-1 product:raven model:Pixel_6 device:raven transport_id:7",
|
||||
"",
|
||||
].join("\n");
|
||||
const { devices, unparsedLines } = parseAdbDevicesOutput(output);
|
||||
expect(unparsedLines).toEqual({ sample: [], total: 0 });
|
||||
expect(
|
||||
devices.map(({ serial, transport, kind, kind_basis }) => ({
|
||||
serial,
|
||||
transport,
|
||||
kind,
|
||||
kind_basis,
|
||||
})),
|
||||
).toEqual([
|
||||
{
|
||||
serial: "adb-8c4f2a1b4e5d6f70-AbCdEf._adb-tls-connect._tcp",
|
||||
transport: "tcp",
|
||||
kind: "unknown",
|
||||
kind_basis: "none",
|
||||
},
|
||||
{
|
||||
serial: "phone._adb._tcp",
|
||||
transport: "tcp",
|
||||
kind: "unknown",
|
||||
kind_basis: "none",
|
||||
},
|
||||
{
|
||||
serial: "not-a-service._tcp",
|
||||
transport: "unknown",
|
||||
kind: "unknown",
|
||||
kind_basis: "none",
|
||||
},
|
||||
{
|
||||
serial: "adb-wired._adb-tls-connect._tcp",
|
||||
transport: "usb",
|
||||
kind: "physical",
|
||||
kind_basis: "usb_transport",
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ADB daemon startup notices", () => {
|
||||
|
||||
@@ -23,6 +23,14 @@ import { parseAdbTransportIdentity } from "../domain/adb/adbTransportIdentity.js
|
||||
|
||||
const DEVICE_LINE = /^(\S+)\s+(.*)$/u;
|
||||
|
||||
/**
|
||||
* adb prints a wireless-debugging transport's serial as the mDNS instance
|
||||
* `<instance>._adb._tcp` or `<instance>._adb-tls-connect._tcp`. That serial
|
||||
* has neither a colon nor a `usb:` field.
|
||||
*/
|
||||
const isAdbMdnsTcpSerial = (serial: string): boolean =>
|
||||
serial.endsWith("._adb._tcp") || serial.endsWith("._adb-tls-connect._tcp");
|
||||
|
||||
const normalizeAdbOutputLine = (rawLine: string): string => rawLine.trimEnd();
|
||||
|
||||
export const isSuccessfulDaemonStartNotice = (line: string): boolean =>
|
||||
@@ -122,7 +130,7 @@ export const parseAdbDevicesOutput = (
|
||||
transport:
|
||||
usb !== null
|
||||
? "usb"
|
||||
: isEmulator || serial.includes(":")
|
||||
: isEmulator || serial.includes(":") || isAdbMdnsTcpSerial(serial)
|
||||
? "tcp"
|
||||
: "unknown",
|
||||
product: metadataValue(remainder, "product"),
|
||||
|
||||
@@ -1259,8 +1259,8 @@ it.each(["typed", "physical"] as const)(
|
||||
const prepare = vi
|
||||
.spyOn(ownershipObservation, "prepareProcessOwnershipInspection")
|
||||
.mockResolvedValue();
|
||||
const launcher = vi.fn(
|
||||
async (options: Parameters<typeof spawnOwnedProviderProcess>[0]) => {
|
||||
const launcher = vi.fn<typeof spawnOwnedProviderProcess>(
|
||||
async (options) => {
|
||||
expect(options.signal).toBeDefined();
|
||||
controller.abort(reason);
|
||||
expect(options.signal?.reason).toBe(reason);
|
||||
@@ -1284,6 +1284,13 @@ it.each(["typed", "physical"] as const)(
|
||||
}
|
||||
expect(error.cause).toBe(reason);
|
||||
expect(launcher).toHaveBeenCalledOnce();
|
||||
launcher.mockImplementationOnce(launcherFor({ kind: "source" }));
|
||||
const recovered = await worker.analyze(
|
||||
makeScript("fetch('/after-admission');"),
|
||||
5_000,
|
||||
);
|
||||
expect(recovered.ok).toBe(true);
|
||||
expect(launcher).toHaveBeenCalledTimes(2);
|
||||
} finally {
|
||||
prepare.mockRestore();
|
||||
await worker.close();
|
||||
|
||||
@@ -326,7 +326,11 @@ export class WebBundleAnalysisWorker {
|
||||
try {
|
||||
await this.#start(deadline);
|
||||
} catch (cause: unknown) {
|
||||
if (processInspectionFailure(cause) !== undefined)
|
||||
if (
|
||||
processInspectionFailure(cause) !== undefined ||
|
||||
(this.#runtime.launchFailure !== undefined &&
|
||||
Object.is(this.#runtime.launchFailure.cause, cause))
|
||||
)
|
||||
ownershipInspectionFailure = this.#inspectionFailure(cause, deadline);
|
||||
throw cause;
|
||||
}
|
||||
|
||||
@@ -1108,6 +1108,19 @@ it("cites a non-ASCII import name by its source bytes", () => {
|
||||
expect(bytes.subarray(at, at + 7).toString("latin1")).toBe(name);
|
||||
});
|
||||
|
||||
it("treats the __chk_fail handler import as a FORTIFY sign", () => {
|
||||
const bytes = elfHardeningFixture({
|
||||
fortify: true,
|
||||
fortifyName: "__chk_fail",
|
||||
});
|
||||
const image = readElfHardening(bytes);
|
||||
const row = findRow(image.rows, "fortify");
|
||||
expect(row).toMatchObject({ state: "enabled", location: { bytes: 10 } });
|
||||
expect(row.basis).toContain("__chk_fail");
|
||||
const at = row.location?.offset ?? 0;
|
||||
expect(bytes.subarray(at, at + 10).toString("latin1")).toBe("__chk_fail");
|
||||
});
|
||||
|
||||
it("keeps malformed name offsets malformed in both formats", async () => {
|
||||
await expect(
|
||||
readMachoHardening(machoHardeningFixture({ brokenStrx: true })),
|
||||
|
||||
@@ -279,6 +279,7 @@ export const readElfHardening = (
|
||||
symbols,
|
||||
(name) =>
|
||||
name === "__fortify_fail" ||
|
||||
name === "__chk_fail" ||
|
||||
(name.startsWith("__") && name.endsWith("_chk")),
|
||||
"No fortify symbol was found in the dynamic symbol table. A static or stripped image can omit those imports while still using FORTIFY.",
|
||||
"The dynamic symbol table is absent, so FORTIFY use is unknown.",
|
||||
|
||||
@@ -238,6 +238,27 @@ architecture arm64e
|
||||
]);
|
||||
});
|
||||
|
||||
it("normalizes the CPU names lipo prints for i386 slices", () => {
|
||||
// cctools misc/lipo.c print_cputype() spells i386 with I386 names.
|
||||
expect(
|
||||
parseLipoOutput(`architecture i386
|
||||
cputype CPU_TYPE_I386
|
||||
cpusubtype CPU_SUBTYPE_I386_ALL
|
||||
capabilities 0x0
|
||||
offset 16384
|
||||
size 28
|
||||
align 2^14 (16384)
|
||||
`).architectures,
|
||||
).toMatchObject([
|
||||
{
|
||||
name: "i386",
|
||||
cpu_type_code: 7,
|
||||
cpu_subtype_code: 3,
|
||||
cpu_subtype_base: 3,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps unknown symbolic CPU values as source text without a code", () => {
|
||||
expect(
|
||||
parseLipoOutput(
|
||||
|
||||
@@ -315,6 +315,7 @@ const integer = (value: string | undefined): number | null => {
|
||||
|
||||
const CPU_TYPES: Readonly<Record<string, number>> = {
|
||||
CPU_TYPE_X86: 7,
|
||||
CPU_TYPE_I386: 7,
|
||||
CPU_TYPE_X86_64: 0x01000007,
|
||||
CPU_TYPE_ARM: 12,
|
||||
CPU_TYPE_ARM64: 0x0100000c,
|
||||
@@ -325,6 +326,7 @@ const CPU_TYPES: Readonly<Record<string, number>> = {
|
||||
|
||||
const CPU_SUBTYPES: Readonly<Record<string, number>> = {
|
||||
CPU_SUBTYPE_X86_ALL: 3,
|
||||
CPU_SUBTYPE_I386_ALL: 3,
|
||||
CPU_SUBTYPE_X86_64_ALL: 3,
|
||||
CPU_SUBTYPE_X86_64_H: 8,
|
||||
CPU_SUBTYPE_ARM64_ALL: 0,
|
||||
|
||||
@@ -152,6 +152,7 @@ export class OwnedWorkerRuntime {
|
||||
#lastRunId: string | undefined;
|
||||
#terminalCloseRequested = false;
|
||||
#inputFailure: Error | undefined;
|
||||
#launchFailure: { readonly cause: unknown } | undefined;
|
||||
#stdinGeneration = 0;
|
||||
readonly #stdoutListeners = new Set<{
|
||||
readonly stream: Readable;
|
||||
@@ -191,6 +192,11 @@ export class OwnedWorkerRuntime {
|
||||
return this.#inputFailure;
|
||||
}
|
||||
|
||||
/** Failure observed at the current launcher call, without reclassifying its cause. */
|
||||
get launchFailure(): { readonly cause: unknown } | undefined {
|
||||
return this.#launchFailure;
|
||||
}
|
||||
|
||||
/** Keep a returned typed cleanup error live until this exact owner releases. */
|
||||
bindCleanupFailure(error: OwnedWorkerCleanupFailure | AnalysisError): void {
|
||||
if (this.#cleanupEpoch === undefined) {
|
||||
@@ -243,6 +249,7 @@ export class OwnedWorkerRuntime {
|
||||
const ownRetry = this.#registry.has(this)
|
||||
? this.#retryPending()
|
||||
: Promise.resolve();
|
||||
this.#launchFailure = undefined;
|
||||
const acquisition = ownRetry.then(async () => {
|
||||
if (this.#closed) this.#closed = false;
|
||||
await this.#start(spawnOptions, initialize);
|
||||
@@ -356,10 +363,16 @@ export class OwnedWorkerRuntime {
|
||||
this.#cleanupEpoch ??= new OwnedWorkerRuntimeCleanupEpoch(this.#root.path);
|
||||
if (this.#closing) throw new ProcessAdmissionError("runtime_closing");
|
||||
this.#lastRunId = spawnOptions.runId;
|
||||
const spawned = await (this.options.launcher ?? spawnOwnedProviderProcess)({
|
||||
...spawnOptions,
|
||||
cwd: this.#root.path,
|
||||
});
|
||||
let spawned: Awaited<ReturnType<typeof spawnOwnedProviderProcess>>;
|
||||
try {
|
||||
spawned = await (this.options.launcher ?? spawnOwnedProviderProcess)({
|
||||
...spawnOptions,
|
||||
cwd: this.#root.path,
|
||||
});
|
||||
} catch (cause: unknown) {
|
||||
this.#launchFailure = { cause };
|
||||
throw cause;
|
||||
}
|
||||
this.#inputFailure = undefined;
|
||||
this.#observeStdin(spawned.process.stdin);
|
||||
this.#cleanupEpoch.setRunId(spawned.ownership?.runId ?? spawnOptions.runId);
|
||||
|
||||
Reference in new issue
Block a user