[GH-ISSUE #3095] feat: support native macOS DMG extraction through extract-artifact #1078

Open
opened 2026-10-15 18:30:53 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @matbrgz on GitHub (Oct 14, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/3095

Type: Feature Domain: Reverse Engineering Status: Proposed Ecosystem: REA

feat: support native macOS DMG extraction through extract-artifact

inspect-artifact can inventory and hash regular files inside a DMG on macOS, but extract-artifact rejects the same image with unsupported_target. Please consider adding DMG extraction using the existing native read-only reader and extraction safety rules.

This is a capability request: the current extraction format guard explicitly excludes DMG. I am not claiming a regression or that DMG extraction is currently promised.

Environment

  • REA 6.4.0, source commit 183d21210acda588184dd9a0897047523aa644b2
  • Node.js v26.11.1
  • macOS 27.0.1, build 26A434
  • Apple hdiutil framework/revision 704
  • Tested with a synthetic compressed DMG containing one 35-byte text file; no third-party application is needed.

Reproduction

With the REA 6.4.0 CLI available as rea, run on macOS:

fixture_root=$(mktemp -d "${TMPDIR:-/tmp}/rea-dmg-repro.XXXXXX")
mkdir "$fixture_root/source"
printf '%s\n' 'hello from a synthetic DMG fixture' > "$fixture_root/source/hello.txt"
hdiutil create -srcfolder "$fixture_root/source" -volname REA-DMG-Fixture -format UDZO "$fixture_root/fixture.dmg"
rea inspect-artifact "$fixture_root/fixture.dmg" --format json > "$fixture_root/inspection.json"
rea extract-artifact "$fixture_root/fixture.dmg" --format json > "$fixture_root/extraction.json"

The reproduction was executed using the equivalent source launcher, node /path/to/rea/scripts/rea.mjs, for both public CLI commands. DMG creation and inspection require a host context that permits native image creation and read-only attachment; a sandbox that denies these operations is a separate environment limitation.

Observed result

  • inspect-artifact exits 0. Its inventory substep reports root_format: "dmg", coverage_status: "complete", three nodes, three occurrences, and two edges.
  • The inventory includes fixture.dmg/REA-DMG-Fixture/hello.txt, with verified SHA-256 62cbb9fd68f7ccc0f606401ce538a224ee6fd73a7f4719706473a411884fe42a and declared size 35.
  • Inspection provenance records hdiutil verify and hdiutil attach -readonly -nobrowse -plist -mountroot ….
  • extract-artifact exits 1. The JSON error contains:
{
  "code": "unsupported_target",
  "category": "unsupported_target",
  "retryable": false,
  "details": {
    "operation": "extract_artifact",
    "reason": "Artifact format has no extraction reader: dmg"
  }
}

This is a selected subset of the output; machine-local paths are omitted. A subsequent hdiutil info -plist reported no attached images.

Requested behavior

  • On macOS, materialize the regular files of a supported DMG through extract-artifact, with its normal containment checks, file hashes, extraction manifest, and evidence provenance.
  • Retain the native reader's read-only mount, device ownership checks, cancellation handling, and verified cleanup, including failures during extraction.
  • Preserve explicit unsupported/unavailable outcomes for hosts or DMGs that the native reader cannot handle; do not imply that inventory support alone proves every DMG is extractable.
  • Use this one-file fixture as a public CLI regression case. Verify that the extracted text matches its recorded digest and that no owned mount is left behind after success or failure.

The immediate benefit is obtaining content bytes and an extraction manifest through the same REA workflow that produced the DMG inventory, without a separate manual mount/copy procedure.

Relevant implementation

Originally created by @matbrgz on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3095 [![Type: Feature](https://img.shields.io/badge/type-feature-blue.svg?style=flat-square)](https://github.com/morluto/rea) [![Domain: Reverse Engineering](https://img.shields.io/badge/domain-reverse_engineering-blueviolet.svg?style=flat-square)](https://github.com/morluto/rea) [![Status: Proposed](https://img.shields.io/badge/status-proposed-blue.svg?style=flat-square)](https://github.com/morluto/rea) [![Ecosystem: REA](https://img.shields.io/badge/ecosystem-morluto%2Frea-8A2BE2.svg?style=flat-square)](https://github.com/morluto/rea) # feat: support native macOS DMG extraction through extract-artifact `inspect-artifact` can inventory and hash regular files inside a DMG on macOS, but `extract-artifact` rejects the same image with `unsupported_target`. Please consider adding DMG extraction using the existing native read-only reader and extraction safety rules. This is a capability request: the current extraction format guard explicitly excludes DMG. I am not claiming a regression or that DMG extraction is currently promised. ## Environment - REA 6.4.0, source commit `183d21210acda588184dd9a0897047523aa644b2` - Node.js v26.11.1 - macOS 27.0.1, build 26A434 - Apple hdiutil framework/revision 704 - Tested with a synthetic compressed DMG containing one 35-byte text file; no third-party application is needed. ## Reproduction With the REA 6.4.0 CLI available as `rea`, run on macOS: ```sh fixture_root=$(mktemp -d "${TMPDIR:-/tmp}/rea-dmg-repro.XXXXXX") mkdir "$fixture_root/source" printf '%s\n' 'hello from a synthetic DMG fixture' > "$fixture_root/source/hello.txt" hdiutil create -srcfolder "$fixture_root/source" -volname REA-DMG-Fixture -format UDZO "$fixture_root/fixture.dmg" rea inspect-artifact "$fixture_root/fixture.dmg" --format json > "$fixture_root/inspection.json" rea extract-artifact "$fixture_root/fixture.dmg" --format json > "$fixture_root/extraction.json" ``` The reproduction was executed using the equivalent source launcher, `node /path/to/rea/scripts/rea.mjs`, for both public CLI commands. DMG creation and inspection require a host context that permits native image creation and read-only attachment; a sandbox that denies these operations is a separate environment limitation. ## Observed result - `inspect-artifact` exits 0. Its inventory substep reports `root_format: "dmg"`, `coverage_status: "complete"`, three nodes, three occurrences, and two edges. - The inventory includes `fixture.dmg/REA-DMG-Fixture/hello.txt`, with verified SHA-256 `62cbb9fd68f7ccc0f606401ce538a224ee6fd73a7f4719706473a411884fe42a` and declared size 35. - Inspection provenance records `hdiutil verify` and `hdiutil attach -readonly -nobrowse -plist -mountroot …`. - `extract-artifact` exits 1. The JSON error contains: ```json { "code": "unsupported_target", "category": "unsupported_target", "retryable": false, "details": { "operation": "extract_artifact", "reason": "Artifact format has no extraction reader: dmg" } } ``` This is a selected subset of the output; machine-local paths are omitted. A subsequent `hdiutil info -plist` reported no attached images. ## Requested behavior - On macOS, materialize the regular files of a supported DMG through `extract-artifact`, with its normal containment checks, file hashes, extraction manifest, and evidence provenance. - Retain the native reader's read-only mount, device ownership checks, cancellation handling, and verified cleanup, including failures during extraction. - Preserve explicit unsupported/unavailable outcomes for hosts or DMGs that the native reader cannot handle; do not imply that inventory support alone proves every DMG is extractable. - Use this one-file fixture as a public CLI regression case. Verify that the extracted text matches its recorded digest and that no owned mount is left behind after success or failure. The immediate benefit is obtaining content bytes and an extraction manifest through the same REA workflow that produced the DMG inventory, without a separate manual mount/copy procedure. ## Relevant implementation - [Inventory reader selection](https://github.com/morluto/rea/blob/183d21210acda588184dd9a0897047523aa644b2/src/artifacts/inventory/reader.ts#L35) selects `NativeDmgArtifactReader` on Darwin. - [Extraction format guard and reader selection](https://github.com/morluto/rea/blob/183d21210acda588184dd9a0897047523aa644b2/src/artifacts/extraction/ArtifactExtraction.ts#L412) permit directories, ASAR, Mach-O and ZIP package formats, rejecting DMG before inventory work starts. - [Native attachment lifecycle](https://github.com/morluto/rea/blob/183d21210acda588184dd9a0897047523aa644b2/src/artifacts/NativeDmgArtifactReader.ts#L350) already verifies the image and attaches it read-only under an owned private mount root. Reusing it for extraction would still need verification of the extraction lifecycle and failure semantics.
Author
Owner

@akushonkamen commented on GitHub (Oct 14, 2026):

Code-level review in support of a maintainer scope decision (I am not opening a PR for this without one, per the contribution scope rule for new capabilities with host side effects — attaching images is process execution whose mounts live across the extraction window).

The reporter's reading is accurate on current main:

  • Inventory selects the native reader on darwin at src/artifacts/inventory/reader.ts:39 (new NativeDmgArtifactReader(path, environment)).
  • Extraction refuses the format up front at src/artifacts/extraction/ArtifactExtraction.ts:409 (requireExtractableFormat, refusal message at line 424: "Artifact format has no extraction reader: dmg"), before inventory work or output creation.
  • NativeDmgArtifactReader (src/artifacts/NativeDmgArtifactReader.ts:121) already implements the same ArtifactReader contract extraction consumes (src/artifacts/ArtifactReader.ts:120-129) and owns attachment plus reverse-order detach, so the plumbing delta is small.

Why this is a scope decision rather than a mechanical fix:

  1. The refusal is pinned as intended behavior: tests/boundary/providers/native/artifactProvider.extractionFormat.test.ts:15-46 asserts extract_artifact on a DMG returns AnalysisUnsupportedTargetError with exactly that reason (including through a symlinked path) and that an aborted extraction creates no output root. Flipping it is a product decision.
  2. The in-process precedent for extending extraction to inventory-supported formats — the ZIP-backed zip/hap/hsp/app-pack family (same file, lines 48-73) — has no host side effects. DMG extraction holds an owned hdiutil mount and device nodes across the whole copy window, which is the side-effect class the contribution scope rule reserves for a maintainer decision.
  3. Unresolved lifecycle questions the reporter also flags: device re-verification during extraction (the reader's #inventoryConfirmedDevices policy is inventory-named), detach folded into extraction's verified cleanup contract (cleanup: {attempted, verified, residual_paths}, ArtifactExtraction.ts:388) including detach failure after partial materialization, and cancellation mid-copy. None of these are answerable by tests alone; they define what "retained cleanup" means when a mount is involved.

If maintainers approve, the shape I would propose: admit dmg in the guard on darwin only, wire NativeDmgArtifactReader into createReader behind the same environment-gated host used by inventory, fold detach into extraction's verified cleanup with residual reporting on detach failure, keep an explicit unsupported/unsupported_host outcome on non-darwin hosts, invert the pinned refusal test into a darwin-gated extraction test plus a non-darwin unsupported test, and add a real-hdiutil verification lane mirroring the reporter's one-file fixture and the existing DMG detach checks in docs/client-verification.md (lines 238-241).

<!-- gh-comment-id:6159954936 --> @akushonkamen commented on GitHub (Oct 14, 2026): Code-level review in support of a maintainer scope decision (I am not opening a PR for this without one, per the contribution scope rule for new capabilities with host side effects — attaching images is process execution whose mounts live across the extraction window). The reporter's reading is accurate on current `main`: - Inventory selects the native reader on darwin at `src/artifacts/inventory/reader.ts:39` (`new NativeDmgArtifactReader(path, environment)`). - Extraction refuses the format up front at `src/artifacts/extraction/ArtifactExtraction.ts:409` (`requireExtractableFormat`, refusal message at line 424: "Artifact format has no extraction reader: dmg"), before inventory work or output creation. - `NativeDmgArtifactReader` (src/artifacts/NativeDmgArtifactReader.ts:121) already implements the same `ArtifactReader` contract extraction consumes (src/artifacts/ArtifactReader.ts:120-129) and owns attachment plus reverse-order detach, so the plumbing delta is small. Why this is a scope decision rather than a mechanical fix: 1. The refusal is pinned as intended behavior: `tests/boundary/providers/native/artifactProvider.extractionFormat.test.ts:15-46` asserts `extract_artifact` on a DMG returns `AnalysisUnsupportedTargetError` with exactly that reason (including through a symlinked path) and that an aborted extraction creates no output root. Flipping it is a product decision. 2. The in-process precedent for extending extraction to inventory-supported formats — the ZIP-backed `zip`/`hap`/`hsp`/`app-pack` family (same file, lines 48-73) — has no host side effects. DMG extraction holds an owned `hdiutil` mount and device nodes across the whole copy window, which is the side-effect class the contribution scope rule reserves for a maintainer decision. 3. Unresolved lifecycle questions the reporter also flags: device re-verification during extraction (the reader's `#inventoryConfirmedDevices` policy is inventory-named), detach folded into extraction's verified cleanup contract (`cleanup: {attempted, verified, residual_paths}`, ArtifactExtraction.ts:388) including detach failure after partial materialization, and cancellation mid-copy. None of these are answerable by tests alone; they define what "retained cleanup" means when a mount is involved. If maintainers approve, the shape I would propose: admit `dmg` in the guard on darwin only, wire `NativeDmgArtifactReader` into `createReader` behind the same environment-gated host used by inventory, fold detach into extraction's verified cleanup with residual reporting on detach failure, keep an explicit `unsupported`/`unsupported_host` outcome on non-darwin hosts, invert the pinned refusal test into a darwin-gated extraction test plus a non-darwin unsupported test, and add a real-`hdiutil` verification lane mirroring the reporter's one-file fixture and the existing DMG detach checks in docs/client-verification.md (lines 238-241).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#1078
No description provided.