[PR #3496] feat(artifacts): read compiled AndroidManifest.xml attributes #5780

Open
opened 2026-10-31 01:09:22 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/3496
Author: @cevieiras
Created: 10/14/2026
Status: 🔄 Open

Base: main ← Head: feat/android-manifest-reader


📝 Commits (5)

  • 24bfc62 feat(android): check split APK set consistency from manifest facts
  • ecc9755 feat(artifacts): read compiled AndroidManifest.xml attributes
  • c7e35ef fix(android): keep unknown split-set facts unknown and order reasons
  • 2e55539 fix(artifacts): keep AXML decoding strict and bounded
  • fb377d6 Merge upstream/main into feat/android-manifest-reader

📊 Changes

8 files changed (+1793 additions, -0 deletions)

View changed files

➕ src/artifacts/android/AndroidManifestReader.test.ts (+376 -0)
➕ src/artifacts/android/AndroidManifestReader.ts (+463 -0)
➕ src/artifacts/android/AxmlBytes.ts (+40 -0)
➕ src/artifacts/android/AxmlStringPool.ts (+143 -0)
➕ src/artifacts/android/axmlBuilder.fixture.ts (+149 -0)
➕ src/domain/android/androidManifestFacts.ts (+39 -0)
➕ src/domain/android/androidSplitSet.test.ts (+316 -0)
➕ src/domain/android/androidSplitSet.ts (+267 -0)

📄 Description

Stacked on #3495. This branch contains that PR's commit plus one more; please review only the last commit (feat(artifacts): read compiled AndroidManifest.xml attributes). I will rebase once #3495 lands. Opened as a draft until then.

Summary

Adds a bounded reader for the top-level attributes of a compiled (binary XML) AndroidManifest.xml, producing the manifest facts that the split-set check in #3495 consumes. It adds no tool surface and has no consumer yet.

Refs #1813

Problem and expected behavior

REA has no way to read manifest facts from a compiled manifest without a provider process. The split-set check needs package, versionCode/versionCodeMajor, split, configForSplit, isFeatureSplit, isolatedSplits, targetSandboxVersion, uses-sdk and isSplitRequired (declared on <application>, not <manifest>). Input is untrusted, so the reader must stay bounded and return typed failures.

Change and scope

  • AndroidManifestReader.ts: pure reader over bytes, returning Result with a typed failure for every refusal (no throws).
  • AxmlBytes.ts / AxmlStringPool.ts: bounds-checked cursor and a lazy string pool. Strings are decoded on demand with per-string and aggregate byte budgets, so many offsets pointing at one large UTF-16 string cannot exhaust memory.
  • Attribute ranges are validated against the element's own chunk and the element tree must be balanced, so a forged attributeStart cannot read facts from a following chunk.
  • axmlBuilder.fixture.ts: a test-only synthetic AXML builder.
  • Not included: the ZIP/APK adapter, aapt2-built fixtures, any tool surface. The numeric limits are starting points, not measurements.

Contract and boundary impact

  • Semantic owner and earliest changed stage: src/artifacts/android/ (artifact reader); src/domain/android/androidManifestFacts.ts gains a small field set.
  • CLI and MCP/tool-catalog contract: none.
  • Provider, bridge, target-format, or platform compatibility: Android binary XML (AXML); no provider or external tool.
  • Evidence, artifact, provenance, or reconstruction contract: manifest values are reported as observed; nothing is inferred here.
  • Process execution, authorization, cleanup, or containment impact: none; the reader never executes anything and reads only the bytes it is given.
  • Generated metadata, package, or installation impact: none.

Evidence and regression coverage

  • Tests added or updated: src/artifacts/android/AndroidManifestReader.test.ts (22 tests) over hand-built manifests, including truncated chunks, forged attribute ranges, unbalanced trees and oversized string-pool offsets.

  • Base reproduction or other evidence: new capability. Compiled manifests were not produced by aapt2 in this PR; that cross-check comes with the fixtures PR.

  • User-visible CLI/MCP output: none.

  • Remaining proof gaps: no real-world manifests from large applications yet; limits are unmeasured.

  • Observed, derived, and inferred claims remain distinguishable.

  • Artifact identity, source provenance, and failed attempts remain preserved.

  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

On this branch tip, based on origin/main at cbc0e97c2:

  • npm run test:focused -- src/artifacts/android/AndroidManifestReader.test.ts — 22 passed
  • npm run verify:test-discovery — all test files discovered exactly once
  • npm run check — 6/6 tasks successful

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: parses hostile bytes; document size, string count, per-string and aggregate decoded bytes, and chunk count are bounded before work is done.

Author readiness

Human owner:

  • 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.

🤖 Generated with Claude Code


🔄 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/3496 **Author:** [@cevieiras](https://github.com/cevieiras) **Created:** 10/14/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat/android-manifest-reader` --- ### 📝 Commits (5) - [`24bfc62`](https://github.com/morluto/rea/commit/24bfc6203ec80c481e6ef67010d6e5221bc49e1c) feat(android): check split APK set consistency from manifest facts - [`ecc9755`](https://github.com/morluto/rea/commit/ecc975570379985cb59a58dc1fd1152aeccdf937) feat(artifacts): read compiled AndroidManifest.xml attributes - [`c7e35ef`](https://github.com/morluto/rea/commit/c7e35ef23185d2b0490aa91ec20e9142ccfcf509) fix(android): keep unknown split-set facts unknown and order reasons - [`2e55539`](https://github.com/morluto/rea/commit/2e5553907406566983d211e3e1c754f66fbebab4) fix(artifacts): keep AXML decoding strict and bounded - [`fb377d6`](https://github.com/morluto/rea/commit/fb377d6dd5889b4ae3bc63f3b6acfd48dfbe0cc7) Merge upstream/main into feat/android-manifest-reader ### 📊 Changes **8 files changed** (+1793 additions, -0 deletions) <details> <summary>View changed files</summary> ➕ `src/artifacts/android/AndroidManifestReader.test.ts` (+376 -0) ➕ `src/artifacts/android/AndroidManifestReader.ts` (+463 -0) ➕ `src/artifacts/android/AxmlBytes.ts` (+40 -0) ➕ `src/artifacts/android/AxmlStringPool.ts` (+143 -0) ➕ `src/artifacts/android/axmlBuilder.fixture.ts` (+149 -0) ➕ `src/domain/android/androidManifestFacts.ts` (+39 -0) ➕ `src/domain/android/androidSplitSet.test.ts` (+316 -0) ➕ `src/domain/android/androidSplitSet.ts` (+267 -0) </details> ### 📄 Description > **Stacked on #3495.** This branch contains that PR's commit plus one more; please review only the last commit (`feat(artifacts): read compiled AndroidManifest.xml attributes`). I will rebase once #3495 lands. Opened as a draft until then. ## Summary Adds a bounded reader for the top-level attributes of a compiled (binary XML) `AndroidManifest.xml`, producing the manifest facts that the split-set check in #3495 consumes. It adds no tool surface and has no consumer yet. Refs #1813 ## Problem and expected behavior REA has no way to read manifest facts from a compiled manifest without a provider process. The split-set check needs `package`, `versionCode`/`versionCodeMajor`, `split`, `configForSplit`, `isFeatureSplit`, `isolatedSplits`, `targetSandboxVersion`, `uses-sdk` and `isSplitRequired` (declared on `<application>`, not `<manifest>`). Input is untrusted, so the reader must stay bounded and return typed failures. ## Change and scope - `AndroidManifestReader.ts`: pure reader over bytes, returning `Result` with a typed failure for every refusal (no throws). - `AxmlBytes.ts` / `AxmlStringPool.ts`: bounds-checked cursor and a lazy string pool. Strings are decoded on demand with per-string and aggregate byte budgets, so many offsets pointing at one large UTF-16 string cannot exhaust memory. - Attribute ranges are validated against the element's own chunk and the element tree must be balanced, so a forged `attributeStart` cannot read facts from a following chunk. - `axmlBuilder.fixture.ts`: a test-only synthetic AXML builder. - Not included: the ZIP/APK adapter, aapt2-built fixtures, any tool surface. The numeric limits are starting points, not measurements. ## Contract and boundary impact - Semantic owner and earliest changed stage: `src/artifacts/android/` (artifact reader); `src/domain/android/androidManifestFacts.ts` gains a small field set. - CLI and MCP/tool-catalog contract: none. - Provider, bridge, target-format, or platform compatibility: Android binary XML (AXML); no provider or external tool. - Evidence, artifact, provenance, or reconstruction contract: manifest values are reported as observed; nothing is inferred here. - Process execution, authorization, cleanup, or containment impact: none; the reader never executes anything and reads only the bytes it is given. - Generated metadata, package, or installation impact: none. ## Evidence and regression coverage - Tests added or updated: `src/artifacts/android/AndroidManifestReader.test.ts` (22 tests) over hand-built manifests, including truncated chunks, forged attribute ranges, unbalanced trees and oversized string-pool offsets. - Base reproduction or other evidence: new capability. Compiled manifests were not produced by `aapt2` in this PR; that cross-check comes with the fixtures PR. - User-visible CLI/MCP output: none. - Remaining proof gaps: no real-world manifests from large applications yet; limits are unmeasured. - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed On this branch tip, based on `origin/main` at `cbc0e97c2`: - `npm run test:focused -- src/artifacts/android/AndroidManifestReader.test.ts` — 22 passed - `npm run verify:test-discovery` — all test files discovered exactly once - `npm run check` — 6/6 tasks successful ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: not applicable. - Package or release metadata impact: none. - Security, privacy, process, or containment review: parses hostile bytes; document size, string count, per-string and aggregate decoded bytes, and chunk count are bounded before work is done. ## Author readiness <!-- The human owner completes these declarations before requesting review. The PR author is the owner by default. A different owner must explicitly accept ownership on this PR. AI agents must leave these declarations to a human to dictate to them or there could be catastrophic consequences for many users of REA. Draft PRs may leave them unchecked. These declarations record initial readiness when opening the PR for review; later pushes do not require a new human sign-off. Keep the description and validation evidence current as the work changes. See CONTRIBUTING.md#pull-request-ownership-and-readiness. --> Human owner: <!-- @GitHub-handle --> - [ ] 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 <!-- Draft PRs may leave pending items unchecked. Resolve material scope and authority questions before integration. --> - [ ] 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. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
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#5780
No description provided.