import { regularFileCancellation } from "../filesystem/OwnedRegularFile.js"; import { mkdtemp, realpath, rm, type FileHandle } from "node:fs/promises"; import { tmpdir } from "node:os"; import { basename, join } from "node:path"; import type { Readable } from "node:stream"; import type { ArtifactCommand } from "../domain/artifactGraph.js"; import { ArtifactReaderFailure, type ArtifactEntry, type ArtifactReader, type ArtifactTraversalOptions, } from "./ArtifactReader.js"; import { DirectoryArtifactReader } from "./DirectoryArtifactReader.js"; import { NonRegularFileReadError, RegularFileAdmissionFailure, openRegularFile, } from "../filesystem/RegularFile.js"; import { OwnedFileHandle } from "../filesystem/OwnedFileHandle.js"; import { ExecFileOutputCancelledError, execFileOutput, execFileOutputFailure, } from "../process/ExecFileOutput.js"; import { parseNativeDmgAttachOutput, parseNativeDmgInfo, resolveNativeDmgOwnership, type NativeDmgAttachOutput, type NativeDmgInfo, } from "./NativeDmgOwnership.js"; const HDIUTIL_COMMAND_TIMEOUT_MS = 120_000; const VERIFY_SETTLE_DELAYS_MS = [250, 500] as const; // APFS ejects and busy reporting can lag a detach attempt. const DETACH_SETTLE_DELAYS_MS = [250, 500, 1000] as const; const delay = (milliseconds: number): Promise => new Promise((resolve) => setTimeout(resolve, milliseconds)); /** Narrow host seam for tested, shell-free hdiutil lifecycle operations. */ export interface NativeDmgHost { run( arguments_: readonly string[], signal?: AbortSignal, options?: { readonly timeoutMs: number }, ): Promise<{ readonly stdout: string; readonly stderr?: string; readonly exitCode: number; readonly cause?: unknown; }>; /** Wait between detach rechecks; tests may resolve immediately. */ delay?(milliseconds: number): Promise; } interface NativeDmgFailureClassification { readonly reason: ArtifactReaderFailure["reason"]; readonly verifyDiagnostic?: string; /** * hdiutil could not recognize the target, for a reason it reported only in * localized text; the cause stays unknown unless the target cannot be opened. */ readonly unrecognizedImage?: boolean; } class NativeDmgCommandFailure extends ArtifactReaderFailure { readonly processNotStarted: boolean; readonly verifyDiagnostic: string | undefined; readonly unrecognizedImage: boolean; readonly exitCode: number | null; constructor( failure: NativeDmgFailureClassification, message: string, readonly stdout: string, options?: { readonly cause?: unknown; readonly cancellation?: { readonly reason: unknown }; readonly processNotStarted?: boolean; readonly exitCode?: number; }, ) { super( failure.reason, message, options === undefined ? undefined : { ...(options.cause === undefined ? {} : { cause: options.cause }), ...(options.cancellation === undefined ? {} : { cancellation: options.cancellation }), }, ); this.processNotStarted = options?.processNotStarted ?? false; this.verifyDiagnostic = failure.verifyDiagnostic; this.unrecognizedImage = failure.unrecognizedImage ?? false; this.exitCode = options?.exitCode ?? null; } } const createSystemHost = ( environment: Readonly, ): NativeDmgHost => ({ delay, async run(arguments_, signal, options) { try { const { stdout, stderr } = await execFileOutput( "/usr/bin/hdiutil", [...arguments_], { env: environment, stopSignal: "SIGTERM", ...(options === undefined ? {} : { timeout: options.timeoutMs }), ...(signal === undefined ? {} : { signal }), }, ); return { stdout, stderr, exitCode: 0 }; } catch (cause: unknown) { const output = execFileOutputFailure(cause); if (cause instanceof ExecFileOutputCancelledError) throw new NativeDmgCommandFailure( { reason: "cancelled" }, "DMG operation cancelled", output?.stdout ?? "", { cause, cancellation: { reason: cause.cause } }, ); const exitCode = typeof output?.code === "number" ? output.code : processExitCode(cause); if (exitCode !== undefined) return { stdout: output?.stdout ?? processOutput(cause, "stdout"), stderr: output?.stderr ?? processOutput(cause, "stderr"), exitCode, cause, }; throw new NativeDmgCommandFailure( classifyCommandFailure(cause, arguments_[0]), `hdiutil ${arguments_[0] ?? "operation"} failed: ${describeCommandFailure(cause, arguments_)}`, output?.stdout ?? "", { cause, processNotStarted: processNotStarted(cause) }, ); } }, }); /** Read-only macOS DMG adapter that owns attachment and reverse-order detach. */ export class NativeDmgArtifactReader implements ArtifactReader { readonly format = "file" as const; private readonly host: NativeDmgHost; readonly #provenance: ArtifactCommand[] = []; #initialization: Promise | undefined; #directory: DirectoryArtifactReader | undefined; #devices: string[] = []; #inventoryConfirmedDevices = new Set(); #mountRoot: string | undefined; #baselineDevices = new Set(); #attachOutput: NativeDmgAttachOutput | undefined; #attachOutputReturned = false; #attachMayHaveMounted = false; #ownershipUncertainty: string | undefined; #closed = false; #closePromise: Promise | undefined; readonly #activeDirectoryOperations = new Set>(); #verificationProbeHandle: OwnedFileHandle | undefined; constructor( private readonly path: string, environment: Readonly, host?: NativeDmgHost, ) { if (process.platform !== "darwin" && host === undefined) throw new ArtifactReaderFailure( "unavailable", "Native DMG traversal is available only on macOS", ); this.host = host ?? createSystemHost(environment); } async *entries( signal?: AbortSignal, options?: ArtifactTraversalOptions, ): AsyncIterable { await this.#ensureAttached(signal); const directory = this.#directory; if (directory === undefined) throw new ArtifactReaderFailure("unavailable", "DMG is not attached"); const prefix = basename(this.path); const entries = directory .entries(signal, { onOmission: (omission) => options?.onOmission?.({ ...omission, path: `${prefix}/${omission.path}`, }), }) [Symbol.asyncIterator](); try { for (;;) { if (this.#closed) return; const next = await this.#trackDirectoryOperation(() => entries.next()); if (this.#closed) return; if (next.done) return; yield { ...next.value, path: `${prefix}/${next.value.path}` }; } } finally { await entries.return?.(); } } async open(entry: ArtifactEntry, signal?: AbortSignal): Promise { await this.#ensureAttached(signal); const directory = this.#directory; if (directory === undefined) throw new ArtifactReaderFailure("unavailable", "DMG is not attached"); return this.#trackDirectoryOperation(() => directory.open(entry, signal)); } provenance(): readonly ArtifactCommand[] { return structuredClone(this.#provenance); } close(): Promise { this.#closed = true; this.#closePromise ??= this.#closeOwnedResources().catch( (cause: unknown) => { this.#closePromise = undefined; throw cause; }, ); return this.#closePromise; } async #closeOwnedResources(): Promise { await this.#initialization?.catch(() => undefined); await Promise.allSettled(this.#activeDirectoryOperations); await this.#closeVerificationProbeHandle(); await this.#closeMountedDirectory(); let detachFailure = await this.#detachOwnedDevices(); if ( this.#devices.length === 0 && this.#mountRoot !== undefined && !this.#attachMayHaveMounted ) await rm(this.#mountRoot, { recursive: true, force: true }).then( () => { this.#mountRoot = undefined; this.#directory = undefined; }, (cause: unknown) => { detachFailure ??= cause; }, ); if (this.#attachMayHaveMounted) { detachFailure ??= new Error( this.#ownershipUncertainty ?? "hdiutil attachment ownership remains unknown", ); } if (detachFailure !== undefined) throw new ArtifactReaderFailure( "unavailable", `DMG detach or mount-root cleanup failed for ${JSON.stringify(this.path)}: ${failureMessage(detachFailure)}`, { cause: detachFailure, cleanup: { reason: failureMessage(detachFailure), resources: [ ...this.#devices.map((device) => `DMG device ${device}`), ...(this.#attachMayHaveMounted ? [ `DMG attachment ownership unknown at mount root ${this.#mountRoot ?? this.path}`, ] : []), ...(this.#mountRoot === undefined ? [] : [`DMG mount root ${this.#mountRoot}`]), ], }, }, ); } async #closeVerificationProbeHandle(): Promise { const owner = this.#verificationProbeHandle; if (owner === undefined) return; try { await owner.close(); this.#verificationProbeHandle = undefined; } catch (cause: unknown) { throw ArtifactReaderFailure.withCleanup( cause, ArtifactReaderFailure.cleanupObservation( cause, `DMG verification target descriptor ${this.path}`, ), ); } } async #detachOwnedDevices(): Promise { let detachFailure = await this.#reconcileAttachState(); let remainingDevices: string[] = []; for (const device of [...this.#devices].reverse()) { const failure = await this.#detach(device); if (failure !== undefined) { remainingDevices.push(device); detachFailure ??= failure; } } // APFS container detach may briefly leave its backing image listed. for (const delayMs of DETACH_SETTLE_DELAYS_MS) { if (remainingDevices.length === 0) break; await (this.host.delay ?? delay)(delayMs); const stillAttached: string[] = []; for (const device of remainingDevices) { if (!(await this.#isAttached(device))) continue; const failure = await this.#detach(device); if (failure !== undefined) { stillAttached.push(device); detachFailure = failure; } } remainingDevices = stillAttached; } if (remainingDevices.length === 0) detachFailure = undefined; this.#devices = remainingDevices.reverse(); return detachFailure; } async #closeMountedDirectory(): Promise { if (this.#directory !== undefined) { try { await this.#directory.close(); this.#directory = undefined; } catch (cause: unknown) { const mountRoot = this.#mountRoot ?? this.path; throw ArtifactReaderFailure.withCleanup(cause, { reason: `DMG mounted directory remains owned: ${failureMessage(cause)}`, resources: [ `DMG mounted directory at ${mountRoot}`, `DMG mount root ${mountRoot}`, ...this.#devices.map((device) => `DMG device ${device}`), ], }); } } } /** Detach one device; return the failure only while it remains attached. */ async #detach(device: string): Promise { try { await runChecked(this.host, ["detach", device], undefined, { timeoutMs: HDIUTIL_COMMAND_TIMEOUT_MS, }); this.#provenance.push(command(["detach", device], ["mount"])); return undefined; } catch (cause: unknown) { return (await this.#isAttached(device)) ? cause : undefined; } } async #reconcileAttachState(): Promise { if (!this.#attachMayHaveMounted) return undefined; try { await this.#resolveAttachOwnership(); return undefined; } catch (cause: unknown) { this.#ownershipUncertainty = failureMessage(cause); return cause; } } /** Treat unknown hdiutil state as attached during cleanup. */ async #isAttached(device: string): Promise { try { const parsed = await this.#readInfo(); const isListed = parsed.images.some((image) => image["system-entities"].some( (entity) => entity["dev-entry"] === device, ), ); if (isListed) { this.#inventoryConfirmedDevices.add(device); return true; } return !this.#inventoryConfirmedDevices.has(device); } catch { return true; } } async #ensureAttached(signal?: AbortSignal): Promise { if (this.#closed) throw new ArtifactReaderFailure("unavailable", "DMG reader is closed"); this.#initialization ??= this.#attach(signal); await this.#initialization; if (this.#closed) throw new ArtifactReaderFailure("unavailable", "DMG reader is closed"); } async #trackDirectoryOperation( operation: () => Promise, ): Promise { if (this.#closed) throw new ArtifactReaderFailure("unavailable", "DMG reader is closed"); const running = Promise.resolve().then(operation); this.#activeDirectoryOperations.add(running); try { return await running; } finally { this.#activeDirectoryOperations.delete(running); } } async #attach(signal?: AbortSignal): Promise { await this.#verify(signal); const baseline = await this.#readInfo(); this.#baselineDevices = new Set( baseline.images.flatMap((image) => image["system-entities"].map(({ "dev-entry": device }) => device), ), ); const mountRoot = await realpath(await mkdtemp(join(tmpdir(), "rea-dmg-"))); this.#mountRoot = mountRoot; const arguments_ = [ "attach", "-readonly", "-nobrowse", "-plist", "-mountroot", mountRoot, this.path, ]; try { this.#attachMayHaveMounted = true; const attached = await runChecked(this.host, arguments_, signal, { timeoutMs: HDIUTIL_COMMAND_TIMEOUT_MS, }); this.#provenance.push(command(arguments_, ["read", "mount"])); this.#attachOutputReturned = true; let parsed: NativeDmgAttachOutput; try { parsed = parseNativeDmgAttachOutput(attached.stdout); } catch (cause: unknown) { throw new ArtifactReaderFailure( "format", "hdiutil returned a malformed attachment plist", { cause }, ); } if (parsed["system-entities"].length === 0) throw new ArtifactReaderFailure( "format", "hdiutil returned no attached devices", ); this.#attachOutput = parsed; const ownership = await this.#resolveAttachOwnership(); if (ownership !== "owned") throw new ArtifactReaderFailure( ownership === "unknown" ? "unavailable" : "path", ownership === "unknown" ? `DMG attachment ownership is uncertain: ${this.#ownershipUncertainty ?? "no unique mount under the owned root"}` : "hdiutil did not mount a new image beneath the owned root", ); this.#directory = new DirectoryArtifactReader(mountRoot); } catch (cause: unknown) { if (cause instanceof NativeDmgCommandFailure) this.#provenance.push( command(arguments_, ["read", "mount"], cause.exitCode), ); if (cause instanceof NativeDmgCommandFailure && cause.stdout !== "") { try { this.#attachOutput = parseNativeDmgAttachOutput(cause.stdout); this.#attachOutputReturned = true; } catch { // The original command failure remains primary; fresh info still recovers mounts. } } if (cause instanceof NativeDmgCommandFailure && cause.processNotStarted) { this.#attachMayHaveMounted = false; this.#ownershipUncertainty = undefined; } throw cause; } } async #verify(signal?: AbortSignal): Promise { const arguments_ = ["verify", this.path]; const deadline = performance.now() + HDIUTIL_COMMAND_TIMEOUT_MS; for (let attempt = 0; ; attempt += 1) { this.#throwIfVerificationCancelled(signal); try { await runChecked(this.host, arguments_, signal, { timeoutMs: Math.max(1, Math.ceil(deadline - performance.now())), }); this.#provenance.push(command(arguments_, ["read"])); return; } catch (cause: unknown) { if (!(cause instanceof NativeDmgCommandFailure)) throw cause; this.#provenance.push(command(arguments_, ["read"], cause.exitCode)); if (cause.unrecognizedImage) { const unreadable = await this.#isUnreadableTarget(signal, cause); this.#throwIfVerificationCancelled(signal); if (unreadable) throw new NativeDmgCommandFailure( { reason: "io" }, cause.message, cause.stdout, { cause: cause.cause, ...(cause.exitCode === null ? {} : { exitCode: cause.exitCode }), }, ); } const delayMs = VERIFY_SETTLE_DELAYS_MS[attempt]; // Retry only the producer's explicit transient diagnostic, or a localized // refusal of a readable target that may be the same, before any mount. if ( (cause.verifyDiagnostic !== "Resource temporarily unavailable" && !cause.unrecognizedImage) || delayMs === undefined || deadline - performance.now() <= delayMs ) throw cause; await (this.host.delay ?? delay)(delayMs); if (performance.now() >= deadline) throw cause; } } } async #readInfo(): Promise { const info = await runChecked(this.host, ["info", "-plist"], undefined, { timeoutMs: HDIUTIL_COMMAND_TIMEOUT_MS, }); try { return parseNativeDmgInfo(info.stdout); } catch (cause: unknown) { throw new ArtifactReaderFailure( "format", "hdiutil info -plist returned malformed image inventory", { cause }, ); } } async #resolveAttachOwnership(): Promise<"owned" | "none" | "unknown"> { const mountRoot = this.#mountRoot; if (mountRoot === undefined) throw new Error("DMG mount root is unavailable for ownership discovery"); const ownership = resolveNativeDmgOwnership({ info: await this.#readInfo(), ...(this.#attachOutput === undefined ? {} : { attachOutput: this.#attachOutput }), attachOutputReturned: this.#attachOutputReturned, mountRoot, baselineDevices: this.#baselineDevices, }); if (ownership.status === "owned") { this.#devices = [...ownership.devices]; if (ownership.source === "info") for (const device of ownership.devices) this.#inventoryConfirmedDevices.add(device); this.#attachMayHaveMounted = false; this.#ownershipUncertainty = undefined; return "owned"; } if (ownership.status === "unknown") { this.#ownershipUncertainty = ownership.reason; return "unknown"; } this.#attachMayHaveMounted = false; this.#ownershipUncertainty = undefined; this.#devices = []; return "none"; } #cancelledVerification(cause: unknown): NativeDmgCommandFailure { return new NativeDmgCommandFailure( { reason: "cancelled" }, "DMG operation cancelled", "", { cause }, ); } #throwIfVerificationCancelled(signal: AbortSignal | undefined): void { if (signal?.aborted === true) throw this.#cancelledVerification(signal.reason); } async #isUnreadableTarget( signal: AbortSignal | undefined, primaryFailure: NativeDmgCommandFailure, ): Promise { let handle: FileHandle; try { handle = await openRegularFile(this.path, { symlinks: "follow", ...(signal === undefined ? {} : { signal }), }); } catch (cause: unknown) { if (cause instanceof RegularFileAdmissionFailure) { this.#verificationProbeHandle = cause.owner; const cancellation = regularFileCancellation(cause.cause); const failure = cancellation === undefined ? primaryFailure : this.#cancelledVerification(cancellation.reason); throw ArtifactReaderFailure.withCleanup( failure, ArtifactReaderFailure.cleanupObservation( cause.cleanupCause, `DMG verification target descriptor ${this.path}`, ), ); } const cancellation = regularFileCancellation(cause); if (cancellation !== undefined) throw this.#cancelledVerification(cancellation.reason); if (cause instanceof NonRegularFileReadError) return false; return classifyCommandFailure(cause, undefined).reason === "io"; } const owner = new OwnedFileHandle(handle); this.#verificationProbeHandle = owner; try { await owner.close(); this.#verificationProbeHandle = undefined; } catch (cause: unknown) { throw ArtifactReaderFailure.withCleanup( signal?.aborted === true ? this.#cancelledVerification(signal.reason) : primaryFailure, ArtifactReaderFailure.cleanupObservation( cause, `DMG verification target descriptor ${this.path}`, ), ); } if (signal?.aborted === true) throw this.#cancelledVerification(signal.reason); return false; } } const failureMessage = (cause: unknown): string => cause instanceof Error ? cause.message : String(cause); const processNotStarted = (cause: unknown): boolean => { if (!(cause instanceof Error)) return false; const syscall = Reflect.get(cause, "syscall"); const code = Reflect.get(cause, "code"); const errno = Reflect.get(cause, "errno"); return ( typeof syscall === "string" && syscall.startsWith("spawn ") && (typeof code === "string" || typeof code === "number" || typeof errno === "number") ); }; const runChecked = async ( host: NativeDmgHost, arguments_: readonly string[], signal?: AbortSignal, options?: { readonly timeoutMs: number }, ): Promise<{ readonly stdout: string; readonly exitCode: 0 }> => { let result: Awaited>; try { result = await host.run(arguments_, signal, options); } catch (cause: unknown) { if (cause instanceof ArtifactReaderFailure) throw cause; if (cause instanceof ExecFileOutputCancelledError) throw new NativeDmgCommandFailure( { reason: "cancelled" }, "DMG operation cancelled", execFileOutputFailure(cause)?.stdout ?? "", { cause, cancellation: { reason: cause.cause } }, ); const output = execFileOutputFailure(cause); throw new NativeDmgCommandFailure( classifyCommandFailure(cause, arguments_[0]), `hdiutil ${arguments_[0] ?? "operation"} failed: ${describeCommandFailure( cause, arguments_, )}`, output?.stdout ?? "", { cause, processNotStarted: processNotStarted(cause) }, ); } if (result.exitCode !== 0) { const failure = { command: "/usr/bin/hdiutil", exitCode: result.exitCode, ...(result.cause === undefined ? {} : { code: processExitCode(result.cause) }), stdout: result.stdout, ...(result.stderr === undefined ? {} : { stderr: result.stderr }), }; const classification = classifyCommandFailure(failure, arguments_[0]); const details = describeCommandFailure(failure, arguments_); const unknownVerifyFailure = arguments_[0] === "verify" && classification.reason === "unavailable"; throw new NativeDmgCommandFailure( classification, unknownVerifyFailure ? `hdiutil verify failed; captured diagnostics do not establish the failure cause: ${details}` : `hdiutil ${arguments_[0] ?? "operation"} failed: ${details}`, result.stdout, { cause: result.cause ?? failure, exitCode: result.exitCode }, ); } return { stdout: result.stdout, exitCode: 0 }; }; const describeCommandFailure = ( cause: unknown, arguments_: readonly string[], ): string => { const fields: Record = { command: "/usr/bin/hdiutil", arguments: [...arguments_], }; if (typeof cause === "object" && cause !== null) { for (const key of [ "code", "exitCode", "errno", "syscall", "signal", "stdout", "stderr", ] as const) { const value = Reflect.get(cause, key); if (typeof value === "string" || typeof value === "number") fields[key] = value; } const code = Reflect.get(cause, "code"); if (typeof code === "number") fields.exitCode = code; } if (cause instanceof ArtifactReaderFailure) fields.message = cause.message; else if (cause instanceof Error) fields.message = cause.message; return JSON.stringify(fields); }; const processExitCode = (cause: unknown): number | undefined => { if (typeof cause !== "object" || cause === null) return undefined; const exitCode = Reflect.get(cause, "exitCode"); if (typeof exitCode === "number") return exitCode; const code = Reflect.get(cause, "code"); return typeof code === "number" ? code : undefined; }; const processOutput = (cause: unknown, field: "stdout" | "stderr"): string => { if (typeof cause !== "object" || cause === null) return ""; const value = Reflect.get(cause, field); return typeof value === "string" ? value : ""; }; const classifyCommandFailure = ( cause: unknown, operation: string | undefined, ): NativeDmgFailureClassification => { if (typeof cause !== "object" || cause === null) return { reason: "unavailable" }; const code = Reflect.get(cause, "code"); const exitCode = Reflect.get(cause, "exitCode"); if (typeof code === "number" || typeof exitCode === "number") { if (operation !== "verify") return { reason: "unavailable" }; return classifyVerifyFailure( processOutput(cause, "stdout"), processOutput(cause, "stderr"), ); } if (code === "ENOENT") { const syscall = Reflect.get(cause, "syscall"); return { reason: typeof syscall === "string" && syscall.startsWith("spawn") ? "unavailable" : "io", }; } if ( code === "EACCES" || code === "EPERM" || code === "EIO" || code === "ENOTDIR" || code === "EISDIR" || code === "ENODEV" || code === "EROFS" || code === "EMFILE" || code === "ENFILE" ) return { reason: "io" }; return { reason: "unavailable" }; }; const classifyVerifyFailure = ( stdout: string, stderr: string, ): NativeDmgFailureClassification => { const diagnostic = verifyFailureDiagnostic(stdout, stderr); const reason = verifyFailureReason(diagnostic); const untranslated = reason === undefined ? untranslatedVerifyFailure(stdout, stderr) : undefined; return { ...untranslated, reason: reason ?? untranslated?.reason ?? "unavailable", ...(diagnostic === undefined ? {} : { verifyDiagnostic: diagnostic }), }; }; const verifyFailureReason = ( diagnostic: string | undefined, ): ArtifactReaderFailure["reason"] | undefined => { switch (diagnostic) { // hdiutil follows AppleLanguages, so en-GB and en-AU spell it "recognised". case "image not recognized": case "image not recognised": return "format"; case "invalid checksum": case "image data corrupted": return "integrity"; case "No such file or directory": case "Permission denied": case "Input/output error": return "io"; case "Resource temporarily unavailable": return "unavailable"; default: return undefined; } }; const verifyFailureDiagnostic = ( stdout: string, stderr: string, ): string | undefined => { const prefix = "hdiutil: verify failed - "; return outputLines(stdout, stderr) .find((line) => line.startsWith(prefix)) ?.slice(prefix.length); }; // hdiutil localizes the trailing failure reason but not its own status lines. const INVALID_CHECKSUM_LINE = /^hdiutil: verify: checksum of ".*" is INVALID$/u; const UNRECOGNIZED_IMAGE_LINE = /^hdiutil: verify: unable to recognize ".*" as a disk image\./u; const untranslatedVerifyFailure = ( stdout: string, stderr: string, ): NativeDmgFailureClassification | undefined => { const lines = outputLines(stdout, stderr); if (lines.some((line) => INVALID_CHECKSUM_LINE.test(line))) return { reason: "integrity" }; // Malformed, unreadable and transiently busy targets all produce this line; // only the localized reason distinguishes them, so the cause stays unknown. if (lines.some((line) => UNRECOGNIZED_IMAGE_LINE.test(line))) return { reason: "unavailable", unrecognizedImage: true }; return undefined; }; const outputLines = (stdout: string, stderr: string): string[] => `${stdout}\n${stderr}`.split(/\r?\n/u).map((line) => line.trim()); const command = ( arguments_: readonly string[], effects: ArtifactCommand["effects"], exitCode: number | null = 0, ): ArtifactCommand => ({ tool: "/usr/bin/hdiutil", arguments: [...arguments_], tool_version: null, executable_sha256: null, exit_code: exitCode, effects, });