[GH-ISSUE #4743] [Bug] Apple dispatch metadata inspection loses descriptor ownership and primary failure on close rejection #2471

Closed
opened 2026-10-17 21:05:15 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @Swatantra-66 on GitHub (Oct 17, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/4743

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

A NativeMacOSProvider client returns an ordinary ProviderAdapterError with cleanupIncomplete: false when Apple dispatch metadata inspection encounters a read/integrity failure and the file descriptor close also rejects. The primary failure (e.g. EvidenceIntegrityError or AnalysisResourceConstraintError) is completely lost/overwritten by the close rejection, and the unclosed file descriptor is abandoned without ownership retention or client cleanup retry.

Reproduction

In src/native/AppleDispatchMetadata.ts:199-232, inspectAppleDispatchMetadata uses raw openRegularFile and finally { await handle.close(); }.
When an error occurs in the try block (e.g., target sha256 mismatch triggering EvidenceIntegrityError) and handle.close() throws a controlled rejection:

  1. The finally block re-throws the close error, discarding EvidenceIntegrityError.
  2. NativeMacOSProvider.execute("inspect_native_dispatch_metadata") catches the close rejection as an unknown error, returning ProviderAdapterError with cleanupIncomplete: false.
  3. The descriptor owner is not retained, and client.close() does not retry closing the leaked descriptor.

Expected behavior

Own the admitted target descriptor through withOwnedRegularFile or withArtifactRegularFile / shared resource scope. Preserve the primary physical read failure, integrity failure, or cancellation reason alongside the cleanup failure. Retain the exact descriptor owner so client.close() retries cleanup, surfaces cleanupIncomplete: true, and clears it once cleanup succeeds.

Impact and scope

Affects inspect_native_dispatch_metadata on all Mach-O executable targets when descriptor close fails or when admission fails with close rejection.

REA version

6.5.0

Runtime and platform

Node 24.18; macOS 15 arm64 / Linux x64 / Windows 11

Target and artifact context

Mach-O arm64 executable

Interface

Other

Earliest failure stage

Cleanup, cancellation, or lifecycle

Relevant output or evidence

Command or MCP request actually run:
client.execute("inspect_native_dispatch_metadata", {}) on a Mach-O target under a controlled descriptor close failure.

Relevant result, error, or artifact:
ProviderAdapterError with cleanupIncomplete: false returned; primary EvidenceIntegrityError or AnalysisResourceConstraintError lost and descriptor handle leaked without owner retention.

For source-only findings, link the file/revision and relevant code:

  • src/native/AppleDispatchMetadata.ts:199-232: inspectAppleDispatchMetadata opens target.path with raw openRegularFile and uses try { ... } finally { await handle.close(); }, dropping the in-flight error and leaking the descriptor on close rejection.
  • src/native/NativeMacOSProvider.ts:201-228: inspect_native_dispatch_metadata catches the close rejection as an unknown error and wraps it in ProviderAdapterError without binding the descriptor to client resource cleanup.

Missing evidence or remaining uncertainty:
Live operating system close failure incidence and Windows qualification: NOT_ENOUGH_INFO.

Typed outcome or recovery expected

Retain the primary typed error (EvidenceIntegrityError, AnalysisResourceConstraintError, or AnalysisCancelledError) alongside the descriptor cleanup failure, reporting cleanupIncomplete: true and retaining the descriptor owner so client.close() retries cleanup.

Analysis or suspected cause

Source-derived: In src/native/AppleDispatchMetadata.ts, inspectAppleDispatchMetadata uses raw openRegularFile without withOwnedRegularFile. In JavaScript, if handle.close() throws in a finally block, it overwrites any in-flight exception from try. Additionally, NativeMacOSProvider does not bind the dispatch metadata descriptor to its resource scope, dropping descriptor ownership on close failure.

Additional context

Related to descriptor cleanup and failure provenance work in #4521 (Allegrex inspection descriptor ownership) and #4723 (Native plist descriptor cleanup ownership). Proposed fix follows the established withOwnedRegularFile / ArtifactResourceScope pattern.

Originally created by @Swatantra-66 on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4743 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior A NativeMacOSProvider client returns an ordinary ProviderAdapterError with `cleanupIncomplete: false` when Apple dispatch metadata inspection encounters a read/integrity failure and the file descriptor close also rejects. The primary failure (e.g. EvidenceIntegrityError or AnalysisResourceConstraintError) is completely lost/overwritten by the close rejection, and the unclosed file descriptor is abandoned without ownership retention or client cleanup retry. ### Reproduction In `src/native/AppleDispatchMetadata.ts:199-232`, `inspectAppleDispatchMetadata` uses raw `openRegularFile` and `finally { await handle.close(); }`. When an error occurs in the `try` block (e.g., target sha256 mismatch triggering `EvidenceIntegrityError`) and `handle.close()` throws a controlled rejection: 1. The `finally` block re-throws the close error, discarding `EvidenceIntegrityError`. 2. `NativeMacOSProvider.execute("inspect_native_dispatch_metadata")` catches the close rejection as an unknown error, returning `ProviderAdapterError` with `cleanupIncomplete: false`. 3. The descriptor owner is not retained, and `client.close()` does not retry closing the leaked descriptor. ### Expected behavior Own the admitted target descriptor through `withOwnedRegularFile` or `withArtifactRegularFile` / shared resource scope. Preserve the primary physical read failure, integrity failure, or cancellation reason alongside the cleanup failure. Retain the exact descriptor owner so `client.close()` retries cleanup, surfaces `cleanupIncomplete: true`, and clears it once cleanup succeeds. ### Impact and scope Affects `inspect_native_dispatch_metadata` on all Mach-O executable targets when descriptor close fails or when admission fails with close rejection. ### REA version 6.5.0 ### Runtime and platform Node 24.18; macOS 15 arm64 / Linux x64 / Windows 11 ### Target and artifact context Mach-O arm64 executable ### Interface Other ### Earliest failure stage Cleanup, cancellation, or lifecycle ### Relevant output or evidence Command or MCP request actually run: `client.execute("inspect_native_dispatch_metadata", {})` on a Mach-O target under a controlled descriptor close failure. Relevant result, error, or artifact: `ProviderAdapterError` with `cleanupIncomplete: false` returned; primary `EvidenceIntegrityError` or `AnalysisResourceConstraintError` lost and descriptor handle leaked without owner retention. For source-only findings, link the file/revision and relevant code: - `src/native/AppleDispatchMetadata.ts:199-232`: `inspectAppleDispatchMetadata` opens `target.path` with raw `openRegularFile` and uses `try { ... } finally { await handle.close(); }`, dropping the in-flight error and leaking the descriptor on close rejection. - `src/native/NativeMacOSProvider.ts:201-228`: `inspect_native_dispatch_metadata` catches the close rejection as an unknown error and wraps it in `ProviderAdapterError` without binding the descriptor to client resource cleanup. Missing evidence or remaining uncertainty: Live operating system close failure incidence and Windows qualification: NOT_ENOUGH_INFO. ### Typed outcome or recovery expected Retain the primary typed error (`EvidenceIntegrityError`, `AnalysisResourceConstraintError`, or `AnalysisCancelledError`) alongside the descriptor cleanup failure, reporting `cleanupIncomplete: true` and retaining the descriptor owner so `client.close()` retries cleanup. ### Analysis or suspected cause Source-derived: In `src/native/AppleDispatchMetadata.ts`, `inspectAppleDispatchMetadata` uses raw `openRegularFile` without `withOwnedRegularFile`. In JavaScript, if `handle.close()` throws in a `finally` block, it overwrites any in-flight exception from `try`. Additionally, `NativeMacOSProvider` does not bind the dispatch metadata descriptor to its resource scope, dropping descriptor ownership on close failure. ### Additional context Related to descriptor cleanup and failure provenance work in #4521 (Allegrex inspection descriptor ownership) and #4723 (Native plist descriptor cleanup ownership). Proposed fix follows the established `withOwnedRegularFile` / `ArtifactResourceScope` pattern.
bsakaguchi 2026-10-17 21:05:15 +00:00
  • closed this issue
  • added the
    triage
    bug
    labels
Author
Owner

@Swatantra-66 commented on GitHub (Oct 17, 2026):

As the author of this issue, I have opened PR #4756 to resolve this.

It keeps descriptor cleanup owned across retries, preserves primary failure provenance, avoids breaking the public signature for callers like scripts/verify/apple/dispatch.mjs, and correctly separates decode errors from file adapter errors.

<!-- gh-comment-id:6232950859 --> @Swatantra-66 commented on GitHub (Oct 17, 2026): As the author of this issue, I have opened PR #4756 to resolve this. It keeps descriptor cleanup owned across retries, preserves primary failure provenance, avoids breaking the public signature for callers like `scripts/verify/apple/dispatch.mjs`, and correctly separates decode errors from file adapter errors.
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#2471
No description provided.