[PR #5359] [MERGED] feat(macho): report per-slice encryption status in inspect_macho #6896

Closed
opened 2026-11-01 21:43:54 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/5359
Author: @chordpli
Created: 10/20/2026
Status: ✅ Merged
Merged: 10/29/2026
Merged by: @gensokyo-dev

Base: main ← Head: feat/macho-encryption-info


📝 Commits (10+)

  • cd38a59 refactor(macho): extract non-throwing container and slice load-command readers
  • 2b41ca6 feat(macho): report per-slice encryption status in inspect_macho
  • f210a4f fix(macho): keep slice facts and failures under large tables and close errors
  • ee6f565 Merge remote-tracking branch 'origin/main' into feat/macho-encryption-info
  • c128c72 Merge remote-tracking branch 'origin/main' into feat/macho-encryption-info
  • c6c8c75 Merge remote-tracking branch 'origin/main' into feat/macho-encryption-info
  • 15db4e6 Merge remote-tracking branch 'origin/main' into feat/macho-encryption-info
  • c54ff26 Merge remote-tracking branch 'origin/main' into feat/macho-encryption-info
  • 0d506e2 fix(macho): map encrypted ranges only within segment VM extents
  • 3bd1541 Merge remote-tracking branch 'origin/main' into HEAD

📊 Changes

27 files changed (+2776 additions, -221 deletions)

View changed files

📝 .github/workflows/ci.yml (+1 -0)
📝 docs/mcp-contracts.md (+6 -4)
📝 docs/native-investigation.md (+34 -0)
📝 docs/testing.md (+4 -0)
📝 scripts/ci/scopes.mjs (+1 -0)
📝 scripts/verify/apple/native-provenance.mjs (+9 -0)
➕ src/artifacts/apple/MachoEncryptionReader.test.ts (+916 -0)
➕ src/artifacts/apple/MachoEncryptionReader.ts (+503 -0)
📝 src/artifacts/apple/MachoLoadCommandReader.test.ts (+66 -0)
📝 src/artifacts/apple/MachoLoadCommandReader.ts (+366 -206)
📝 src/contracts/managed/managedWorkflowExamples.ts (+1 -0)
📝 src/domain/analysisView/analysisView.ts (+1 -0)
📝 src/domain/analysisView/machoView.test.ts (+50 -2)
📝 src/domain/analysisView/machoView.ts (+9 -2)
➕ src/domain/apple/machoEncryption.ts (+121 -0)
➕ src/domain/managed/managedNativeVerificationSource.test.ts (+37 -0)
📝 src/domain/managed/managedNativeVerificationSource.ts (+2 -2)
📝 src/domain/native/nativeInspection.ts (+23 -0)
📝 src/native/NativeMacOSProvider.ts (+20 -0)
📝 src/native/NativeMachoInspection.fixture.ts (+7 -0)

...and 7 more files

📄 Description

Summary

Fixes #4306. inspect_macho now reports the declared LC_ENCRYPTION_INFO(_64) state of every slice, so analysts can distinguish a recorded ciphertext range from program bytes before interpreting disassembly. Output includes observed command fields, CPU identity, slice/input offsets, segment/section overlaps and VM mappings. CLI and MCP share the same provider/application facts; inspect_analysis_view exposes the paged macho encryption facet with retained Evidence.

This is static metadata inspection within the existing native provider. Status derives only from load commands: no entropy guess, payload-encryption test, target execution, decryption or mutation. Artifact inventory's separate container-encryption meaning remains intact. absent requires a complete walk; malformed/unknown states preserve their reason and earlier commands. Older retained Evidence remains readable.

Implementation and continuation

The contributor's history is preserved. Common container/slice framing owns identity and load-command parsing; the strict existing reader retains its defect precedence. Only encryption/segment commands are retained. Mapping uses the existing shared record allowance and checks the framing bound before retaining segment commands.

Review found that a failed early mapping still spent its entire reservation, dropping a healthy later slice's VM/section facts. The producing boundary now commits the reservation only after mapping succeeds. Four tiny double-slice regressions reproduce the original failure for missing section bytes, VM-size mismatch, address-space overflow and command-width mismatch; all pass after the fix. The existing successful-mapping test still proves that retained results consume the shared budget. No downstream repair or parallel interpretation was added.

The bound descriptor and target SHA remain checked around native tools. Cleanup retains the exact owner and primary failure. Native provenance verification now requires complete per-slice absence through real CLI/MCP, and the owned encryptable-image CLI test is included in the macOS CI lane. This tests declared cryptid=1 metadata; it is not a genuine FairPlay sample.

Executed validation

Continuation on Linux, Node 24.22.1 /npm 11.16.0. Runtime commit 26280c746; head 0eba2e7fa additionally merges main d3ecf6800 (website-only changes) and clarifies documentation/comments.

  • 199 tests pass /2 macOS-only skips across 10 selected files, including reader characterization, mapping/status semantics, retained Evidence/view/schema behavior, target replacement, cancellation and cleanup ownership. Four new budget cases failed first; the five source files now pass 155 tests.
  • check:fast, formatting of the changed paths, docs (9 README tests), MCP catalog and discovery (2,834 test files exactly once) pass. Docs reran after the website-only main merge and final documentation changes. git diff --check passes.
  • Real files: official ripgrep 14.1.1 arm64 and x86_64 macOS binaries, downloaded archives checked against published SHA-256 files. LLVM lipo 14.0.6 creates an owned universal combination. Sizes: 4,375,216 /5,162,504 /9,552,560 bytes. Independent LLVM otool/lipo header/command walks confirm all four represented slices have no encryption command; both revisions return identical complete facts.
  • This continuation cannot run real macOS CLI/MCP locally. The original contributor reported macOS 26.5.2 native-tool verification, including CLI/MCP, at c2c2e93fc; it is attributed rather than claimed as rerun here. Real Apple CI now passes: 402 tests pass /5 skip in 29 files, plus all artifact-format/metadata verifiers. Its real clang/lipo/otool/codesign encryption CLI test passes (5.980 s including fixture preparation); the actual stdio CLI/MCP provenance verifier confirms complete slice absence and unchanged target bytes. The separate macOS-only summary fixture is not selected in this lane. No genuine FairPlay-encrypted input has been verified.

Final CI 40851338708, merge d60f8bc /main d3ecf6800: source tests 21,846 pass /16 skip in 1,176 files. Static checks, build and docs pass; the first run found an additional CI integration omission: the new Apple test path was in the workflow but absent from its classifier owner. Final head 5ffb40d26 adds that Apple scope entry; all 310 scope/workflow tests and type/lint pass. Runtime code is unchanged. This keeps future test-only edits from silently skipping real-host verification.

Two other failures in that run are baseline text assertions: bundleComparisonCli.test.ts:223 and flutterMcp.test.ts:259 still expect legacy colon-delimited errors. A clean worktree on pure main d3ecf6800 reproduces both identical failures (17 pass /2 fail, npm run test:focused -- tests/boundary/cli/bundleComparisonCli.test.ts tests/boundary/mcp/flutterMcp.test.ts). These unrelated assertions were not changed. Matrix fail-fast and the superseding push cancel unfinished jobs; those jobs are not counted as passing. The final run passes shard 7; shard 3 fails only the unchanged bundleComparisonMcp.test.ts:168 legacy message assertion. Pure main d3ecf6800 reproduces this too (8 pass /1 identical failure). The other six shards are matrix-cancelled and unverified in this run, not reported as passing. Final-head Greptile gives 5/5 with no unresolved threads. Platform results are available in the linked run. The operator explicitly permits bypass for demonstrated main failures; the PR-owned scope omission has been fixed and locally validated separately.

Completed parser-task measurements

Before 9bd7dddcd is the original contribution integrated on the same main base; after is runtime 26280c746. Two alternating/reversed repetitions, fresh Node processes, warm OS caches. Each first-run task answers for all three real files; the repeated task answers the same three questions six times in one process, including the first pass. Every read uses a fresh descriptor, verifies unchanged file metadata and closes it. No new cache is retained.

Completed task Estimated request +result tokens Elapsed CPU Peak process-family RSS
Before, first three files 123 +242 82.7–83.6 ms 60–70 ms 52.7–66.1 MiB
After, first three files 123 +242 83.1 ms 60 ms 50.7–50.9 MiB
Before, 18 repeated answers 738 +1,452 111–128 ms 110–120 ms 70.1–107.1 MiB
After, 18 repeated answers 738 +1,452 104–112 ms 100 ms 75.0–112.5 MiB

All answer hashes and read counts match: 15 reads /9,560,612 bytes per three-file task. The shared JVM discriminator reads small CAFEBABE containers whole; thin images read their structural metadata. Framing/read costs remain bounded; no speedup is claimed from these short runs.

These measure the shared reader task with a 4,096-record allowance, not whole CLI/MCP agent tasks. Native commands, MCP discovery/schemas/Evidence wrappers and true cold filesystem caches are unmeasured locally. Tokenx 1.3.0 estimates serialized requests/results, not billed tokens. RSS is a 10 ms process-group sample and may miss brief peaks; CPU includes the complete Node task and excludes the sampler. A 256 MiB Node heap /512 MiB family /60 s guard bounds each run. All eight runs complete without a guard stop or survivor; downloaded inputs and measurement artifacts remain outside Git.

Author readiness

Human owner: @chordpli

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/5359 **Author:** [@chordpli](https://github.com/chordpli) **Created:** 10/20/2026 **Status:** ✅ Merged **Merged:** 10/29/2026 **Merged by:** [@gensokyo-dev](https://github.com/gensokyo-dev) **Base:** `main` ← **Head:** `feat/macho-encryption-info` --- ### 📝 Commits (10+) - [`cd38a59`](https://github.com/morluto/rea/commit/cd38a59e754132e5b8e4c883e629c96923f781f9) refactor(macho): extract non-throwing container and slice load-command readers - [`2b41ca6`](https://github.com/morluto/rea/commit/2b41ca6a429bebc7d15aa5bff1873ea4d626b8e3) feat(macho): report per-slice encryption status in inspect_macho - [`f210a4f`](https://github.com/morluto/rea/commit/f210a4f8d12e8fdaf531e330dbf685737745865d) fix(macho): keep slice facts and failures under large tables and close errors - [`ee6f565`](https://github.com/morluto/rea/commit/ee6f565354f7fa0d3be5b19eb840d031ba9889d3) Merge remote-tracking branch 'origin/main' into feat/macho-encryption-info - [`c128c72`](https://github.com/morluto/rea/commit/c128c725b5f44f1dda1a8bb57be27138ec7264d2) Merge remote-tracking branch 'origin/main' into feat/macho-encryption-info - [`c6c8c75`](https://github.com/morluto/rea/commit/c6c8c7555786472fd430e74c7086f97e82ecbe52) Merge remote-tracking branch 'origin/main' into feat/macho-encryption-info - [`15db4e6`](https://github.com/morluto/rea/commit/15db4e6ee3caba0578947536b286c11a4c42e639) Merge remote-tracking branch 'origin/main' into feat/macho-encryption-info - [`c54ff26`](https://github.com/morluto/rea/commit/c54ff266cf14f226b58631df4afd804ee9b1b5e8) Merge remote-tracking branch 'origin/main' into feat/macho-encryption-info - [`0d506e2`](https://github.com/morluto/rea/commit/0d506e220809b058e2afd18467dc1ff8b3381f4b) fix(macho): map encrypted ranges only within segment VM extents - [`3bd1541`](https://github.com/morluto/rea/commit/3bd154187bde002a0c7626d713fe98ca9fdb32e2) Merge remote-tracking branch 'origin/main' into HEAD ### 📊 Changes **27 files changed** (+2776 additions, -221 deletions) <details> <summary>View changed files</summary> 📝 `.github/workflows/ci.yml` (+1 -0) 📝 `docs/mcp-contracts.md` (+6 -4) 📝 `docs/native-investigation.md` (+34 -0) 📝 `docs/testing.md` (+4 -0) 📝 `scripts/ci/scopes.mjs` (+1 -0) 📝 `scripts/verify/apple/native-provenance.mjs` (+9 -0) ➕ `src/artifacts/apple/MachoEncryptionReader.test.ts` (+916 -0) ➕ `src/artifacts/apple/MachoEncryptionReader.ts` (+503 -0) 📝 `src/artifacts/apple/MachoLoadCommandReader.test.ts` (+66 -0) 📝 `src/artifacts/apple/MachoLoadCommandReader.ts` (+366 -206) 📝 `src/contracts/managed/managedWorkflowExamples.ts` (+1 -0) 📝 `src/domain/analysisView/analysisView.ts` (+1 -0) 📝 `src/domain/analysisView/machoView.test.ts` (+50 -2) 📝 `src/domain/analysisView/machoView.ts` (+9 -2) ➕ `src/domain/apple/machoEncryption.ts` (+121 -0) ➕ `src/domain/managed/managedNativeVerificationSource.test.ts` (+37 -0) 📝 `src/domain/managed/managedNativeVerificationSource.ts` (+2 -2) 📝 `src/domain/native/nativeInspection.ts` (+23 -0) 📝 `src/native/NativeMacOSProvider.ts` (+20 -0) 📝 `src/native/NativeMachoInspection.fixture.ts` (+7 -0) _...and 7 more files_ </details> ### 📄 Description ## Summary Fixes #4306. `inspect_macho` now reports the declared `LC_ENCRYPTION_INFO(_64)` state of every slice, so analysts can distinguish a recorded ciphertext range from program bytes before interpreting disassembly. Output includes observed command fields, CPU identity, slice/input offsets, segment/section overlaps and VM mappings. CLI and MCP share the same provider/application facts; `inspect_analysis_view` exposes the paged `macho` encryption facet with retained Evidence. This is static metadata inspection within the existing native provider. Status derives only from load commands: no entropy guess, payload-encryption test, target execution, decryption or mutation. Artifact inventory's separate container-encryption meaning remains intact. `absent` requires a complete walk; malformed/unknown states preserve their reason and earlier commands. Older retained Evidence remains readable. ## Implementation and continuation The contributor's history is preserved. Common container/slice framing owns identity and load-command parsing; the strict existing reader retains its defect precedence. Only encryption/segment commands are retained. Mapping uses the existing shared record allowance and checks the framing bound before retaining segment commands. Review found that a failed early mapping still spent its entire reservation, dropping a healthy later slice's VM/section facts. The producing boundary now commits the reservation only after mapping succeeds. Four tiny double-slice regressions reproduce the original failure for missing section bytes, VM-size mismatch, address-space overflow and command-width mismatch; all pass after the fix. The existing successful-mapping test still proves that retained results consume the shared budget. No downstream repair or parallel interpretation was added. The bound descriptor and target SHA remain checked around native tools. Cleanup retains the exact owner and primary failure. Native provenance verification now requires complete per-slice absence through real CLI/MCP, and the owned encryptable-image CLI test is included in the macOS CI lane. This tests declared `cryptid=1` metadata; it is not a genuine FairPlay sample. ## Executed validation Continuation on Linux, Node 24.22.1 /npm 11.16.0. Runtime commit `26280c746`; head `0eba2e7fa` additionally merges main `d3ecf6800` (website-only changes) and clarifies documentation/comments. - **199 tests pass /2 macOS-only skips across 10 selected files**, including reader characterization, mapping/status semantics, retained Evidence/view/schema behavior, target replacement, cancellation and cleanup ownership. Four new budget cases failed first; the five source files now pass 155 tests. - `check:fast`, formatting of the changed paths, docs (9 README tests), MCP catalog and discovery (**2,834 test files exactly once**) pass. Docs reran after the website-only main merge and final documentation changes. `git diff --check` passes. - Real files: official [ripgrep 14.1.1](https://github.com/BurntSushi/ripgrep/releases/tag/14.1.1) arm64 and x86_64 macOS binaries, downloaded archives checked against published SHA-256 files. LLVM lipo 14.0.6 creates an owned universal combination. Sizes: 4,375,216 /5,162,504 /9,552,560 bytes. Independent LLVM otool/lipo header/command walks confirm all four represented slices have no encryption command; both revisions return identical complete facts. - This continuation cannot run real macOS CLI/MCP locally. The original contributor reported macOS 26.5.2 native-tool verification, including CLI/MCP, at `c2c2e93fc`; it is attributed rather than claimed as rerun here. [Real Apple CI](https://github.com/morluto/rea/actions/runs/40851338708/job/123375271508) now passes: **402 tests pass /5 skip in 29 files**, plus all artifact-format/metadata verifiers. Its real clang/lipo/otool/codesign encryption CLI test passes (5.980 s including fixture preparation); the actual stdio CLI/MCP provenance verifier confirms complete slice absence and unchanged target bytes. The separate macOS-only summary fixture is not selected in this lane. No genuine FairPlay-encrypted input has been verified. Final [CI 40851338708](https://github.com/morluto/rea/actions/runs/40851338708), merge `d60f8bc` /main `d3ecf6800`: source tests **21,846 pass /16 skip in 1,176 files**. Static checks, build and docs pass; the first run found an additional CI integration omission: the new Apple test path was in the workflow but absent from its classifier owner. **Final head `5ffb40d26` adds that Apple scope entry; all 310 scope/workflow tests and type/lint pass.** Runtime code is unchanged. This keeps future test-only edits from silently skipping real-host verification. Two other failures in that run are baseline text assertions: `bundleComparisonCli.test.ts:223` and `flutterMcp.test.ts:259` still expect legacy colon-delimited errors. A clean worktree on **pure main `d3ecf6800`** reproduces both identical failures (**17 pass /2 fail**, `npm run test:focused -- tests/boundary/cli/bundleComparisonCli.test.ts tests/boundary/mcp/flutterMcp.test.ts`). These unrelated assertions were not changed. Matrix fail-fast and the superseding push cancel unfinished jobs; those jobs are not counted as passing. The final run passes shard 7; shard 3 fails only the unchanged `bundleComparisonMcp.test.ts:168` legacy message assertion. Pure main `d3ecf6800` reproduces this too (**8 pass /1 identical failure**). The other six shards are matrix-cancelled and unverified in this run, not reported as passing. Final-head Greptile gives **5/5 with no unresolved threads**. Platform results are available in the linked run. The operator explicitly permits bypass for demonstrated main failures; the PR-owned scope omission has been fixed and locally validated separately. ## Completed parser-task measurements Before `9bd7dddcd` is the original contribution integrated on the same main base; after is runtime `26280c746`. Two alternating/reversed repetitions, fresh Node processes, warm OS caches. Each first-run task answers for all three real files; the repeated task answers the same three questions six times in one process, including the first pass. Every read uses a fresh descriptor, verifies unchanged file metadata and closes it. No new cache is retained. | Completed task | Estimated request +result tokens | Elapsed | CPU | Peak process-family RSS | | --- | ---: | ---: | ---: | ---: | | Before, first three files | 123 +242 | 82.7–83.6 ms | 60–70 ms | 52.7–66.1 MiB | | After, first three files | 123 +242 | 83.1 ms | 60 ms | 50.7–50.9 MiB | | Before, 18 repeated answers | 738 +1,452 | 111–128 ms | 110–120 ms | 70.1–107.1 MiB | | After, 18 repeated answers | 738 +1,452 | 104–112 ms | 100 ms | 75.0–112.5 MiB | All answer hashes and read counts match: 15 reads /9,560,612 bytes per three-file task. The shared JVM discriminator reads small `CAFEBABE` containers whole; thin images read their structural metadata. Framing/read costs remain bounded; no speedup is claimed from these short runs. These measure the shared reader task with a 4,096-record allowance, **not whole CLI/MCP agent tasks**. Native commands, MCP discovery/schemas/Evidence wrappers and true cold filesystem caches are unmeasured locally. Tokenx 1.3.0 estimates serialized requests/results, not billed tokens. RSS is a 10 ms process-group sample and may miss brief peaks; CPU includes the complete Node task and excludes the sampler. A 256 MiB Node heap /512 MiB family /60 s guard bounds each run. All eight runs complete without a guard stop or survivor; downloaded inputs and measurement artifacts remain outside Git. ## Author readiness Human owner: @chordpli - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [ ] This PR addresses a concrete problem or an agreed enhancement. - [ ] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [ ] The PR has one focused outcome and the title follows `type(scope): outcome`. - [ ] Related issue is linked, or the reason for not linking one is stated above. - [ ] Tests cover changed observable behavior and meaningful failure paths. - [ ] Owning docs, contracts, and generated metadata are updated where needed. - [ ] User-visible CLI/MCP changes include representative output. - [ ] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-01 21:43:54 +00:00
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#6896
No description provided.