[GH-ISSUE #1235] fix(artifacts): direct Mach-O inspection reports an executable as a resource #435

Closed
opened 2026-10-15 18:25:01 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @coygeek on GitHub (Oct 9, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1235

Summary

Selecting a valid executable Mach-O directly with inspect-artifact reports its root artifact as kind: resource and executable: false. Inspecting the containing valid .app reports the exact same file, bytes and permissions as kind: executable and executable: true. Both commands succeed, so callers receive an incorrect published observation rather than an explicit limitation. The demonstrated impact is metadata correctness; no downstream execution failure was observed.

Runtime or environment

Reproduced on npm rea-agents@6.1.0 and a locally built main checkout at f0da05f67fff1411cf2f7a48a752ee7b348c71ff, with Node v26.10.0, macOS 27.0.1 (26A434), arm64. The reproduction requires Xcode Command Line Tools to compile an authored arm64 executable, and no Hopper, Ghidra or IDA provider.

Steps to reproduce

Create a harmless executable and a valid containing bundle in a disposable working directory:

mkdir -p Demo.app/Contents/MacOS
printf 'int main(void) { return 0; }\n' > demo.c
xcrun clang -arch arm64 demo.c -o Demo.app/Contents/MacOS/demo
cat > Demo.app/Contents/Info.plist <<'XML'
<?xml version="1.0"?><plist version="1.0"><dict><key>CFBundleExecutable</key><string>demo</string><key>CFBundleIdentifier</key><string>example.demo</string></dict></plist>
XML
stat -f '%Sp' Demo.app/Contents/MacOS/demo
npx -y rea-agents@6.1.0 inspect-artifact Demo.app/Contents/MacOS/demo --json > direct.json
npx -y rea-agents@6.1.0 inspect-artifact Demo.app --json > embedded.json
python3 - <<'PY'
import json
for name in ['direct', 'embedded']:
    inventory = json.load(open(name + '.json'))['normalized_result']['substeps'][0]['evidence']['normalized_result']
    for node in inventory['nodes']:
        if node['format'] == 'mach-o':
            print(name, {key: node[key] for key in ['sha256', 'kind', 'format', 'executable']})
PY

The same authored compiled-file and valid-bundle inputs were exercised through both tested CLI entry points. Compare the two reported SHA-256 values to establish that both paths inspect the same bytes. As a permission control, set the executable's mode to 644, rerun both inspections, and compare their kind and executable fields. The compiled target is inspected statically and is never executed.

Expected behavior

Artifact inspection promises all available observations and a complete content-addressed artifact graph. A detected executable Mach-O must retain its executable-format kind when selected directly, and its observed filesystem executable permission must agree with the same file's bundle occurrence. The executable-format kind and executable permission are separate facts: clearing the permission bits should change the latter without turning the Mach-O executable into a resource.

Actual behavior

Both inspection commands exit 0 on both tested builds, with matching file digests. The filesystem and artifact observations are:

mode 755:
  stat = -rwxr-xr-x
  direct node = {kind: resource, format: mach-o, executable: false}
  embedded node = {kind: executable, format: mach-o, executable: true}
mode 644 control:
  direct node = {kind: resource, format: mach-o, executable: false}
  embedded node = {kind: executable, format: mach-o, executable: false}

The direct root occurrence also reports executable: false for the mode-755 case. Both builds were actually exercised with the mode-644 control, which separates executable permission from executable-format kind. No source repair was applied.

Evidence

  • Expected source: src/contracts/artifactToolContracts.ts:66 promises the complete graph and available observations; src/domain/artifactGraph.ts:20 defines executable separately from resource, src/artifacts/inventory/ArtifactGraphConstruction.ts:310 classifies Mach-O executable bytes, and src/artifacts/DirectoryArtifactReader.ts:73 preserves filesystem executable permission for contained files.
  • Failure source: The executed direct-file and containing-bundle CLI results for the inline authored target, including their matching file digests, with mode-755 and mode-644 observations quoted under Actual behavior.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

The primary violation is the executed CLI metadata result on both tested builds, including inspection of the same bytes through the containing bundle and the mode-644 permission control. Source inspection was used separately to trace its representation.

Source inspection shows src/artifacts/inventory/ArtifactGraphConstruction.ts:144 deriving most direct-file root kinds from the pathname rather than the already detected executable format, and line 154 assigning executable: false. The inventory snapshot stores that root node and the root occurrence copies its executable flag. These are diagnostic breadcrumbs, not a prescribed repair.

Open and closed upstream issues were searched for related direct-file root, resource-kind and executable-metadata reports; no matching report was found in those searches.

Restoration check

Inspect the mode-755 target directly and through its containing bundle. Both representations must identify the same bytes as executable Mach-O content and report the observed executable permission as true. Repeat with mode 644: the executable-format kind must remain accurate, and both permission observations must be false. Retain the matching-digest comparison so a passing result cannot silently substitute a different target.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Direct-file inspection publishes incorrect kind and executable-permission metadata for a supported authored Mach-O target. The result can mislead interpretation of the artifact graph, but no byte modification or downstream runtime failure was observed.
  • Workaround status: available
  • Workaround basis: Inspecting the valid containing .app returned the correct executable kind and permission for the exact same file and digest on both tested builds. This supplies the missing facts without changing executable bytes, although it does not repair the direct-file root graph.
Originally created by @coygeek on GitHub (Oct 9, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1235 ## Summary Selecting a valid executable Mach-O directly with `inspect-artifact` reports its root artifact as `kind: resource` and `executable: false`. Inspecting the containing valid `.app` reports the exact same file, bytes and permissions as `kind: executable` and `executable: true`. Both commands succeed, so callers receive an incorrect published observation rather than an explicit limitation. The demonstrated impact is metadata correctness; no downstream execution failure was observed. ## Runtime or environment Reproduced on npm `rea-agents@6.1.0` and a locally built `main` checkout at `f0da05f67fff1411cf2f7a48a752ee7b348c71ff`, with Node v26.10.0, macOS 27.0.1 (26A434), arm64. The reproduction requires Xcode Command Line Tools to compile an authored arm64 executable, and no Hopper, Ghidra or IDA provider. ## Steps to reproduce Create a harmless executable and a valid containing bundle in a disposable working directory: ```sh mkdir -p Demo.app/Contents/MacOS printf 'int main(void) { return 0; }\n' > demo.c xcrun clang -arch arm64 demo.c -o Demo.app/Contents/MacOS/demo cat > Demo.app/Contents/Info.plist <<'XML' <?xml version="1.0"?><plist version="1.0"><dict><key>CFBundleExecutable</key><string>demo</string><key>CFBundleIdentifier</key><string>example.demo</string></dict></plist> XML stat -f '%Sp' Demo.app/Contents/MacOS/demo npx -y rea-agents@6.1.0 inspect-artifact Demo.app/Contents/MacOS/demo --json > direct.json npx -y rea-agents@6.1.0 inspect-artifact Demo.app --json > embedded.json python3 - <<'PY' import json for name in ['direct', 'embedded']: inventory = json.load(open(name + '.json'))['normalized_result']['substeps'][0]['evidence']['normalized_result'] for node in inventory['nodes']: if node['format'] == 'mach-o': print(name, {key: node[key] for key in ['sha256', 'kind', 'format', 'executable']}) PY ``` The same authored compiled-file and valid-bundle inputs were exercised through both tested CLI entry points. Compare the two reported SHA-256 values to establish that both paths inspect the same bytes. As a permission control, set the executable's mode to `644`, rerun both inspections, and compare their `kind` and `executable` fields. The compiled target is inspected statically and is never executed. ## Expected behavior Artifact inspection promises all available observations and a complete content-addressed artifact graph. A detected executable Mach-O must retain its executable-format kind when selected directly, and its observed filesystem executable permission must agree with the same file's bundle occurrence. The executable-format kind and executable permission are separate facts: clearing the permission bits should change the latter without turning the Mach-O executable into a resource. ## Actual behavior Both inspection commands exit 0 on both tested builds, with matching file digests. The filesystem and artifact observations are: ```text mode 755: stat = -rwxr-xr-x direct node = {kind: resource, format: mach-o, executable: false} embedded node = {kind: executable, format: mach-o, executable: true} mode 644 control: direct node = {kind: resource, format: mach-o, executable: false} embedded node = {kind: executable, format: mach-o, executable: false} ``` The direct root occurrence also reports `executable: false` for the mode-755 case. Both builds were actually exercised with the mode-644 control, which separates executable permission from executable-format kind. No source repair was applied. ## Evidence - Expected source: `src/contracts/artifactToolContracts.ts:66` promises the complete graph and available observations; `src/domain/artifactGraph.ts:20` defines executable separately from resource, `src/artifacts/inventory/ArtifactGraphConstruction.ts:310` classifies Mach-O executable bytes, and `src/artifacts/DirectoryArtifactReader.ts:73` preserves filesystem executable permission for contained files. - Failure source: The executed direct-file and containing-bundle CLI results for the inline authored target, including their matching file digests, with mode-755 and mode-644 observations quoted under Actual behavior. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete The primary violation is the executed CLI metadata result on both tested builds, including inspection of the same bytes through the containing bundle and the mode-644 permission control. Source inspection was used separately to trace its representation. Source inspection shows `src/artifacts/inventory/ArtifactGraphConstruction.ts:144` deriving most direct-file root kinds from the pathname rather than the already detected executable format, and line 154 assigning `executable: false`. The inventory snapshot stores that root node and the root occurrence copies its executable flag. These are diagnostic breadcrumbs, not a prescribed repair. Open and closed upstream issues were searched for related direct-file root, resource-kind and executable-metadata reports; no matching report was found in those searches. ## Restoration check Inspect the mode-755 target directly and through its containing bundle. Both representations must identify the same bytes as executable Mach-O content and report the observed executable permission as true. Repeat with mode `644`: the executable-format kind must remain accurate, and both permission observations must be false. Retain the matching-digest comparison so a passing result cannot silently substitute a different target. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Direct-file inspection publishes incorrect kind and executable-permission metadata for a supported authored Mach-O target. The result can mislead interpretation of the artifact graph, but no byte modification or downstream runtime failure was observed. - Workaround status: available - Workaround basis: Inspecting the valid containing `.app` returned the correct executable kind and permission for the exact same file and digest on both tested builds. This supplies the missing facts without changing executable bytes, although it does not repair the direct-file root graph.
bsakaguchi 2026-10-15 18:25:01 +00:00
Author
Owner

@kaoru0822-kitauji commented on GitHub (Oct 9, 2026):

Fixed on main by 63bf9140 ("refactor!: enforce canonical evidence and provider boundaries"), which moved kind and executable facts from content nodes to occurrences.

Restoration check rerun on main (098d7690) with the authored arm64 Demo.app from this report, using rea inspect-artifact:

mode 755: direct   sha256 ecf378b4add8… {artifact_kind: executable, artifact_format: mach-o, executable: true}
mode 755: Demo.app sha256 ecf378b4add8… {artifact_kind: executable, artifact_format: mach-o, executable: true}
mode 644: direct   sha256 ecf378b4add8… {artifact_kind: executable, artifact_format: mach-o, executable: false}
mode 644: Demo.app sha256 ecf378b4add8… {artifact_kind: executable, artifact_format: mach-o, executable: false}

The direct root now matches the bundle occurrence, and the executable-format kind is independent of the permission bits. #1298 adds a regression for both modes (it fails at f0da05f6, the commit this was reported against).

<!-- gh-comment-id:6083142406 --> @kaoru0822-kitauji commented on GitHub (Oct 9, 2026): Fixed on `main` by 63bf9140 ("refactor!: enforce canonical evidence and provider boundaries"), which moved kind and executable facts from content nodes to occurrences. Restoration check rerun on `main` (098d7690) with the authored arm64 `Demo.app` from this report, using `rea inspect-artifact`: ```text mode 755: direct sha256 ecf378b4add8… {artifact_kind: executable, artifact_format: mach-o, executable: true} mode 755: Demo.app sha256 ecf378b4add8… {artifact_kind: executable, artifact_format: mach-o, executable: true} mode 644: direct sha256 ecf378b4add8… {artifact_kind: executable, artifact_format: mach-o, executable: false} mode 644: Demo.app sha256 ecf378b4add8… {artifact_kind: executable, artifact_format: mach-o, executable: false} ``` The direct root now matches the bundle occurrence, and the executable-format kind is independent of the permission bits. #1298 adds a regression for both modes (it fails at f0da05f6, the commit this was reported against).
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#435
No description provided.