[GH-ISSUE #3914] [Bug] unrelated NotAssets.car directory blocks asset catalog inspection #1527

Closed
opened 2026-10-16 21:06:40 +00:00 by bsakaguchi · 1 comment
Owner

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

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

inspect-asset-catalog treats an unrelated directory named NotAssets.car as a catalog entry. When the app has no actual Assets.car, inspection fails instead of returning its supported empty catalog inventory. The source proof reaches this failure before assetutil, without catalog bytes or malformed input. REA execution was not run.

The static proof predicts an ArtifactOperationError with reason path, wrapping this message:

Asset catalog entries are not regular files and were not inspected: Contents/Resources/NotAssets.car (directory)

The selector checks the entire relative path's suffix. It adds this directory to uninspected, leaves catalogs empty, and throws. Runtime REA output and exit status were not observed.

Reproduction

These public steps are proposed and unexecuted. On macOS, create this readable disposable fixture in a fresh directory:

from pathlib import Path
import plistlib
import shutil
app = Path("Example.app")
(app / "Contents/MacOS").mkdir(parents=True)
(app / "Contents/Resources/NotAssets.car").mkdir(parents=True)
(app / "Contents/Info.plist").write_bytes(plistlib.dumps({"CFBundleExecutable": "App"}))
shutil.copyfile("/usr/bin/true", app / "Contents/MacOS/App")

Run rea inspect-asset-catalog Example.app --json. The app has a local Mach-O copied as inert bytes, an executable-resolving Info.plist and an ordinary resource directory. No file is named Assets.car, and there are no nib archives. As a control, remove only the empty Example.app/Contents/Resources/NotAssets.car directory from this disposable fixture and repeat the same command.

Expected behavior

An app without a compiled catalog returns catalogs: [], total_records: 0, and the existing explicit no-catalog limitation. An unrelated resource directory must not count as a skipped catalog or block this inventory.

Impact and scope

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A bounded filename false positive prevents supported catalog inspection even though no catalog needs decoding. The original artifact remains unchanged.

REA version

The inspected source baseline is published rea-agents-6.5.0, revision 3b79af28e80785afce9f5998d8f03289402a1847. The source review compared fetched main cf0a38ad9774ee9acff3164052688f7a58a1c72c and found the catalog analyzer, domain projection, provider dispatch and CLI unchanged. The public operation requires macOS. An exact REA runtime, Node version and OS version are NOT_ENOUGH_INFO because the fixture and REA command were not executed. No provider process or assetutil output was measured.

Runtime and platform

REA runtime reproduction was not run. Runtime and platform details for any smaller premise checks are recorded in the version/environment field above. Real-provider versions and end-to-end output are NOT_ENOUGH_INFO because no provider was launched.

Target and artifact context

macOS .app with a Mach-O executable, executable-resolving Info.plist, no compiled catalog or nib archive, and empty unrelated directory Contents/Resources/NotAssets.car.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

  • Expected source: compiled-catalog operation scope and explicit empty-inventory handling establish the supported no-catalog result.
  • Failure source: catalog candidate selection uses entry.path.endsWith("Assets.car") and records matching directories as uninspected. Lines 149-155 throw when no regular catalog was found and the uninspected list is nonempty. NotAssets.car satisfies that suffix test.
  • Evidence provenance: static
  • Local verification: static-proof
  • Reproduction completeness: complete

Primary violation evidence is the source trace. Runtime REA reproduction was not run.

The public path is src/cli/artifactCommands.ts:103-137, accepting the app and default pagination and dispatching inspect_asset_catalog; src/application/DirectAnalysis.ts:130-157,322-326,442, selecting the artifact-only session, opening the target and executing the operation; and src/application/AppBundleExecutable.ts:28-36,93-98,174-245, recognizing Contents/Info.plist, resolving CFBundleExecutable: App in Contents/MacOS and preserving the bundle path. src/application/BinaryTargetResolver.ts:202-219 admits the Mach-O executable. src/artifacts/ArtifactProvider.ts:265-285 requires executable kind and a source path ending .app, both supplied here, then invokes analyzeAppleAssetCatalogs.

In src/artifacts/apple/AppleAssetCatalogAnalysis.ts, lines 33-38 allow macOS, lines 39-58 validate default pagination and start the empty Interface Builder walk, and lines 61-66 collect catalogs. src/artifacts/DirectoryArtifactReader.ts:112-130 emits actual directories, which brings NotAssets.car to the suffix test. No sorting, parser, missing-tool or assetutil result suppresses this branch. Provider lines 226-227 and 406-422 preserve the path reason through public error translation. Completeness describes the static proof, not an executed REA reproduction.

Typed outcome or recovery expected

The exact fixture must return the same empty inventory with and without the unrelated directory. A directory whose basename is exactly Assets.car must continue to trigger the explicit uninspected-catalog failure when no regular catalog exists. Genuine regular Assets.car files must still be inspected. These unexecuted controls preserve uncertainty reporting for real catalog candidates while distinguishing the unrelated directory.

Additional context

The failure blocks a supported metadata inventory for a bounded class of readable apps. Real-app prevalence is unknown, and the original artifact is not modified. Initial duplicate screening distinguished capability request #496 and NIB resource-key joins in #2176 from this filename trigger.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A bounded filename false positive prevents supported catalog inspection even though no catalog needs decoding. The original artifact remains unchanged.
  • Workaround status: unverified
  • Workaround basis: Renaming the unrelated directory in a disposable copy avoids the suffix match by source reasoning. This was not executed, and the copy has a different bundle context, so it is not a verified equivalent-artifact workaround.
Originally created by @coygeek on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3914 ## 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 `inspect-asset-catalog` treats an unrelated directory named `NotAssets.car` as a catalog entry. When the app has no actual `Assets.car`, inspection fails instead of returning its supported empty catalog inventory. The source proof reaches this failure before assetutil, without catalog bytes or malformed input. REA execution was not run. The static proof predicts an `ArtifactOperationError` with reason `path`, wrapping this message: ```text Asset catalog entries are not regular files and were not inspected: Contents/Resources/NotAssets.car (directory) ``` The selector checks the entire relative path's suffix. It adds this directory to `uninspected`, leaves `catalogs` empty, and throws. Runtime REA output and exit status were not observed. ## Reproduction These public steps are proposed and unexecuted. On macOS, create this readable disposable fixture in a fresh directory: ```python from pathlib import Path import plistlib import shutil app = Path("Example.app") (app / "Contents/MacOS").mkdir(parents=True) (app / "Contents/Resources/NotAssets.car").mkdir(parents=True) (app / "Contents/Info.plist").write_bytes(plistlib.dumps({"CFBundleExecutable": "App"})) shutil.copyfile("/usr/bin/true", app / "Contents/MacOS/App") ``` Run `rea inspect-asset-catalog Example.app --json`. The app has a local Mach-O copied as inert bytes, an executable-resolving Info.plist and an ordinary resource directory. No file is named `Assets.car`, and there are no nib archives. As a control, remove only the empty `Example.app/Contents/Resources/NotAssets.car` directory from this disposable fixture and repeat the same command. ## Expected behavior An app without a compiled catalog returns `catalogs: []`, `total_records: 0`, and the existing explicit no-catalog limitation. An unrelated resource directory must not count as a skipped catalog or block this inventory. ## Impact and scope - Impact level: P2 - Assessment status: supported - Impact basis: A bounded filename false positive prevents supported catalog inspection even though no catalog needs decoding. The original artifact remains unchanged. ## REA version The inspected source baseline is published `rea-agents-6.5.0`, revision `3b79af28e80785afce9f5998d8f03289402a1847`. The source review compared fetched main `cf0a38ad9774ee9acff3164052688f7a58a1c72c` and found the catalog analyzer, domain projection, provider dispatch and CLI unchanged. The public operation requires macOS. An exact REA runtime, Node version and OS version are NOT_ENOUGH_INFO because the fixture and REA command were not executed. No provider process or assetutil output was measured. ## Runtime and platform REA runtime reproduction was not run. Runtime and platform details for any smaller premise checks are recorded in the version/environment field above. Real-provider versions and end-to-end output are NOT_ENOUGH_INFO because no provider was launched. ## Target and artifact context macOS `.app` with a Mach-O executable, executable-resolving Info.plist, no compiled catalog or nib archive, and empty unrelated directory `Contents/Resources/NotAssets.car`. ## Interface CLI ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence - Expected source: [compiled-catalog operation scope](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/docs/native-investigation.md#L307-L310) and [explicit empty-inventory handling](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/artifacts/apple/AppleAssetCatalogAnalysis.ts#L79-L89) establish the supported no-catalog result. - Failure source: [catalog candidate selection](https://github.com/morluto/rea/blob/3b79af28e80785afce9f5998d8f03289402a1847/src/artifacts/apple/AppleAssetCatalogAnalysis.ts#L124-L128) uses `entry.path.endsWith("Assets.car")` and records matching directories as uninspected. Lines 149-155 throw when no regular catalog was found and the uninspected list is nonempty. `NotAssets.car` satisfies that suffix test. - Evidence provenance: static - Local verification: static-proof - Reproduction completeness: complete Primary violation evidence is the source trace. Runtime REA reproduction was not run. The public path is `src/cli/artifactCommands.ts:103-137`, accepting the app and default pagination and dispatching `inspect_asset_catalog`; `src/application/DirectAnalysis.ts:130-157,322-326,442`, selecting the artifact-only session, opening the target and executing the operation; and `src/application/AppBundleExecutable.ts:28-36,93-98,174-245`, recognizing `Contents/Info.plist`, resolving `CFBundleExecutable: App` in `Contents/MacOS` and preserving the bundle path. `src/application/BinaryTargetResolver.ts:202-219` admits the Mach-O executable. `src/artifacts/ArtifactProvider.ts:265-285` requires executable kind and a source path ending `.app`, both supplied here, then invokes `analyzeAppleAssetCatalogs`. In `src/artifacts/apple/AppleAssetCatalogAnalysis.ts`, lines 33-38 allow macOS, lines 39-58 validate default pagination and start the empty Interface Builder walk, and lines 61-66 collect catalogs. `src/artifacts/DirectoryArtifactReader.ts:112-130` emits actual directories, which brings `NotAssets.car` to the suffix test. No sorting, parser, missing-tool or assetutil result suppresses this branch. Provider lines 226-227 and 406-422 preserve the `path` reason through public error translation. Completeness describes the static proof, not an executed REA reproduction. ## Typed outcome or recovery expected The exact fixture must return the same empty inventory with and without the unrelated directory. A directory whose basename is exactly `Assets.car` must continue to trigger the explicit uninspected-catalog failure when no regular catalog exists. Genuine regular `Assets.car` files must still be inspected. These unexecuted controls preserve uncertainty reporting for real catalog candidates while distinguishing the unrelated directory. ## Additional context The failure blocks a supported metadata inventory for a bounded class of readable apps. Real-app prevalence is unknown, and the original artifact is not modified. Initial duplicate screening distinguished capability request #496 and NIB resource-key joins in #2176 from this filename trigger. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A bounded filename false positive prevents supported catalog inspection even though no catalog needs decoding. The original artifact remains unchanged. - Workaround status: unverified - Workaround basis: Renaming the unrelated directory in a disposable copy avoids the suffix match by source reasoning. This was not executed, and the copy has a different bundle context, so it is not a verified equivalent-artifact workaround.
Author
Owner

@yankikucuk commented on GitHub (Oct 15, 2026):

Working on this. Confirmed with your fixture through rea inspect-asset-catalog on macOS: the selector now matches an entry whose own name is Assets.car (at any depth) instead of the path suffix, so the NotAssets.car directory is ignored and the app returns the empty inventory with the no-catalog limitation, identical to the control without the directory. A directory or symlink named exactly Assets.car still raises the uninspected-catalog failure. Draft PR follows shortly.

<!-- gh-comment-id:6189744559 --> @yankikucuk commented on GitHub (Oct 15, 2026): Working on this. Confirmed with your fixture through `rea inspect-asset-catalog` on macOS: the selector now matches an entry whose own name is `Assets.car` (at any depth) instead of the path suffix, so the `NotAssets.car` directory is ignored and the app returns the empty inventory with the no-catalog limitation, identical to the control without the directory. A directory or symlink named exactly `Assets.car` still raises the uninspected-catalog failure. Draft PR follows shortly.
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#1527
No description provided.