[PR #4554] feat(browser-extension): inspect declared CRX and XPI manifest surfaces #6305

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/4554
Author: @abundantbeing
Created: 10/16/2026
Status: 🔄 Open

Base: main ← Head: feat/browser-extension-manifest


📝 Commits (8)

  • 50ef7cb feat(browser-extension): inspect declared CRX and XPI manifest surfaces
  • 4f38982 fix(browser-extension): fail closed on archive budgets and duplicate manifests
  • 7a1a2c1 merge(main): keep extension inspection beside current fuse startup
  • ce36bd5 Merge remote-tracking branch 'origin/main' into feat/browser-extension-manifest
  • 036c354 fix(browser-extension): collect locale placeholders from every manifest string
  • c4ed917 docs(readme): link the browser extension guide from translated readmes
  • 5d07138 fix(browser-extension): bound distinct placeholder collection during traversal
  • ef4a3e5 Merge origin/main into feat/browser-extension-manifest

📊 Changes

49 files changed (+2198 additions, -6 deletions)

View changed files

📝 .agents/skills/reverse-engineer-anything/SKILL.md (+5 -0)
📝 README.md (+1 -0)
📝 docs/.vitepress/config.ts (+1 -0)
➕ docs/assets/browser-extension-workflow.svg (+29 -0)
➕ docs/browser-extension-analysis.md (+112 -0)
📝 docs/index.md (+1 -0)
📝 docs/readme/README_ar.md (+1 -0)
📝 docs/readme/README_de.md (+1 -0)
📝 docs/readme/README_el.md (+1 -0)
📝 docs/readme/README_es.md (+1 -0)
📝 docs/readme/README_fa.md (+1 -0)
📝 docs/readme/README_fr.md (+1 -0)
📝 docs/readme/README_id.md (+1 -0)
📝 docs/readme/README_it.md (+1 -0)
📝 docs/readme/README_ja.md (+1 -0)
📝 docs/readme/README_ko.md (+1 -0)
📝 docs/readme/README_ml.md (+1 -0)
📝 docs/readme/README_pl.md (+1 -0)
📝 docs/readme/README_pt-BR.md (+1 -0)
📝 docs/readme/README_ru.md (+1 -0)

...and 29 more files

📄 Description

Summary

Adds a read-only inspect_browser_extension / inspect-browser-extension operation for one local CRX2, CRX3, XPI/ZIP, or unpacked manifest.json.

This asks for maintainer review of a read-only extension-manifest inspector. Scope integration still depends on #4553; submitting the PR does not treat silence as merge approval.

Related: #4553.

Visual proof

The screenshots below are browser-rendered execution reports built from captured CLI JSON, real stdio MCP responses and regression-test output. They are not an extension UI mockup. Local fixture paths are shortened for display.

flowchart LR
  A["Caller-selected CRX, XPI or manifest.json"] --> B["Stable file read and manifest budget"]
  B --> C["Collect distinct locale keys"]
  C -->|"within 64-key limit"| D["Observed Evidence through CLI and MCP"]
  C -->|"over limit"| E["Typed capacity error; no partial manifest"]

Working package inspection

Compiled CLI and stdio MCP inspect the same authored CRX3 fixture

The returned message_keys includes openDescription from a command description. The displayed permissions, background entry, Gecko ID and hashes come from the captured output. Extension loading, code execution, locale resolution and signature verification remain outside this operation.

Repeated-placeholder regression

Before and after repeated placeholders, with the fixed capacity boundary and fresh test output

The recorded pre-fix failure at c4ed917 is compared with execution at 5d07138. The 2,000,038-byte manifest with 200,000 repeated placeholders succeeds through the built CLI and real stdio MCP. A separate manifest with 65 distinct keys returns a typed capacity error. Authored CRX3, XPI and unpacked-manifest fixtures were exercised. These are local Windows results, not green GitHub CI.

Problem and expected behavior

REA can inventory a ZIP and analyze an unpacked JavaScript tree. It cannot answer the first question an extension package raises: what does this manifest declare?

A CRX file starts with Cr24, so the ZIP classifier does not admit it. An XPI that is a ZIP is a generic archive. Neither path returns permissions, content-script matches, background kind, or a Gecko id. Browser tracker #39 already names extensions as part of the web surface. No open issue or pull request covered CRX, XPI, or WebExtension packages.

Expected behavior: one explicit file in, one Evidence record out. Declared text stays distinct from runtime behavior. A bad container or an exhausted budget returns no partial manifest.

Change and scope

The operation follows the portable inspect_pe_resources shape: domain contract, adapter parser, application service, CLI command, MCP registration, and a guide.

Follow the contribution scope.
Unresolved scope, authority, side effects, or required verification block integration. Link the required maintainer scope decision for new providers or capabilities involving target execution, injection, mutation, or protection recovery; ordinary fixes within existing boundaries may state "not applicable".
Draft PRs may leave the scope decision pending and the readiness and merge checklists unchecked. Maintainers can help resolve open questions.

Scope decision: pending on the linked design issue. Submission for review does not treat silence as approval.

Intentionally not included: extension loading, browser launch, store download, CRX signature verification, locale resolution, package comparison, and JavaScript parsing.

Contract and boundary impact

  • Semantic owner and earliest changed stage: new artifact-provider parser. Earliest stage is stable regular-file admission, then CRX header measurement, then one ZIP entry read.
  • Contribution scope fit and linked maintainer decision: format inspection of a caller-selected file. No target execution, injection, mutation, or protection recovery. Maintainer decision pending.
  • CLI and MCP/tool-catalog contract: adds inspect_browser_extension / inspect-browser-extension. No existing tool changes meaning.
  • Provider, bridge, target-format, or platform compatibility: portable Node parser. No Hopper, Ghidra, IDA, or browser provider.
  • Evidence, artifact, or provenance contract: subject format is file for CRX and unpacked manifests, zip for a ZIP/XPI. Confidence is observed. Limitations stay on the record.
  • Target selection, authority, upstream behavior, and cleanup details: reads one admitted regular file through the existing stable-read owner. Does not write, launch, or contact a network. zip.js is used only as a reader.
  • Generated metadata: CI generates ignored catalogs. Authored skill routing was updated in .agents/skills/reverse-engineer-anything/. Build outputs are not committed.

Expected effects (check known effects; use documentation-only on its own).
Unchecked items do not establish absence; leave uncertainties visible.

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated: src/browserExtension/parseBrowserExtension.test.ts, src/browserExtension/BrowserExtensionProvider.test.ts.
  • Base reproduction or other evidence: source inspection of main. No CRX/XPI/WebExtension tool, doc, issue, or PR. hasZipSignature requires a PK prefix, so a Cr24 file is not admitted as a ZIP.
  • User-visible CLI/MCP output: built CLI and real stdio MCP smokes passed against an unpacked manifest with 200,000 repeated placeholders and 2,000,038 bytes. Both returned observed Evidence with message_keys: ["A"] and the unresolved-placeholder limitation. An installed npm tarball was not exercised.
  • Remaining proof gaps: The full npm run docs:check wrapper exits on the missing bundled Windows native controls on this host. The underlying generators and scripts/check-doc-facts.mjs were run directly and passed. Built CLI and stdio MCP smokes passed; installed-package verification remains unrun. Real-provider lanes are not applicable. Linux CI owns the full generated-catalog check.

For evidence-bearing changes:

  • 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

  • npx vitest run src/browserExtension — 15 passed on 5d07138, including repeated placeholders, distinct-key limits, nested strings and preserved action-title validation.
  • npm run check:fast — typecheck and lint passed on 5d07138.
  • npx vitest run tests/conformance/readmeConsistency.test.ts tests/boundary/filesystem/documentationFacts.test.ts — 6 passed on 5d07138.
  • node scripts/generate-package-metadata.mjs --check, node scripts/generate-skill-metadata.mjs --check, node scripts/generate-product-catalog.mjs --check, and node scripts/check-doc-facts.mjs — passed after regenerating the ignored catalog and skill bundle.
  • npx oxfmt --check . — passed.
  • npm run compile — passed on 5d07138.
  • Built node scripts/rea.mjs inspect-browser-extension <fixture>/manifest.json --json and stdio MCP inspect_browser_extension — passed for the 2,000,038-byte repeated-placeholder fixture.

tests/boundary/mcp/serverIdentity.test.ts had one failure on this Windows host: path.resolve("/packaged/rea.mjs") becomes D:\packaged\rea.mjs, so an existing alignment fixture reports registration_path_mismatch. src/serverIdentity.ts is not in this diff. The other 15 tests in that file passed. This is not claimed as a green Linux run.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. New tool and command only.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable. Parser tests ran on Windows with Node 26.7.0.
  • Package or release metadata impact: the next generated catalog and skill bundle will include one tool. No version bump in this PR.
  • Security, privacy, process, or containment review: read-only file admission. CRX signature bytes are counted and not checked. Extension code is not parsed or executed. Manifest text is target content and is returned as such.

Author readiness

Human owner: @abundantbeing

The owner directed this PR to be submitted for maintainer review, including the AI-assisted diff and the verification recorded above.

  • 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/4554 **Author:** [@abundantbeing](https://github.com/abundantbeing) **Created:** 10/16/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat/browser-extension-manifest` --- ### 📝 Commits (8) - [`50ef7cb`](https://github.com/morluto/rea/commit/50ef7cbe268169d256c263941f74075b59b1458b) feat(browser-extension): inspect declared CRX and XPI manifest surfaces - [`4f38982`](https://github.com/morluto/rea/commit/4f38982d573c3e5917e3c1e780a1762188532f74) fix(browser-extension): fail closed on archive budgets and duplicate manifests - [`7a1a2c1`](https://github.com/morluto/rea/commit/7a1a2c1604f33bb9f330a29199a2a52cb1ef64d8) merge(main): keep extension inspection beside current fuse startup - [`ce36bd5`](https://github.com/morluto/rea/commit/ce36bd50d5510f41280e652a31ab4daa5a1d0ee6) Merge remote-tracking branch 'origin/main' into feat/browser-extension-manifest - [`036c354`](https://github.com/morluto/rea/commit/036c354d71e35275f7c6ab0deb5b38b88e2a1231) fix(browser-extension): collect locale placeholders from every manifest string - [`c4ed917`](https://github.com/morluto/rea/commit/c4ed91785d09aeeb4c3191e15f2b5e813b8aa92d) docs(readme): link the browser extension guide from translated readmes - [`5d07138`](https://github.com/morluto/rea/commit/5d071388788787fa30ce2712b0588ca2f060bb50) fix(browser-extension): bound distinct placeholder collection during traversal - [`ef4a3e5`](https://github.com/morluto/rea/commit/ef4a3e5159808f14445f982367d6817903868a12) Merge origin/main into feat/browser-extension-manifest ### 📊 Changes **49 files changed** (+2198 additions, -6 deletions) <details> <summary>View changed files</summary> 📝 `.agents/skills/reverse-engineer-anything/SKILL.md` (+5 -0) 📝 `README.md` (+1 -0) 📝 `docs/.vitepress/config.ts` (+1 -0) ➕ `docs/assets/browser-extension-workflow.svg` (+29 -0) ➕ `docs/browser-extension-analysis.md` (+112 -0) 📝 `docs/index.md` (+1 -0) 📝 `docs/readme/README_ar.md` (+1 -0) 📝 `docs/readme/README_de.md` (+1 -0) 📝 `docs/readme/README_el.md` (+1 -0) 📝 `docs/readme/README_es.md` (+1 -0) 📝 `docs/readme/README_fa.md` (+1 -0) 📝 `docs/readme/README_fr.md` (+1 -0) 📝 `docs/readme/README_id.md` (+1 -0) 📝 `docs/readme/README_it.md` (+1 -0) 📝 `docs/readme/README_ja.md` (+1 -0) 📝 `docs/readme/README_ko.md` (+1 -0) 📝 `docs/readme/README_ml.md` (+1 -0) 📝 `docs/readme/README_pl.md` (+1 -0) 📝 `docs/readme/README_pt-BR.md` (+1 -0) 📝 `docs/readme/README_ru.md` (+1 -0) _...and 29 more files_ </details> ### 📄 Description ## Summary Adds a read-only `inspect_browser_extension` / `inspect-browser-extension` operation for one local CRX2, CRX3, XPI/ZIP, or unpacked `manifest.json`. This asks for maintainer review of a read-only extension-manifest inspector. Scope integration still depends on #4553; submitting the PR does not treat silence as merge approval. Related: #4553. ## Visual proof The screenshots below are browser-rendered execution reports built from captured CLI JSON, real stdio MCP responses and regression-test output. They are not an extension UI mockup. Local fixture paths are shortened for display. ```mermaid flowchart LR A["Caller-selected CRX, XPI or manifest.json"] --> B["Stable file read and manifest budget"] B --> C["Collect distinct locale keys"] C -->|"within 64-key limit"| D["Observed Evidence through CLI and MCP"] C -->|"over limit"| E["Typed capacity error; no partial manifest"] ``` ### Working package inspection ![Compiled CLI and stdio MCP inspect the same authored CRX3 fixture](https://files.catbox.moe/eu9qso.png) The returned `message_keys` includes `openDescription` from a command description. The displayed permissions, background entry, Gecko ID and hashes come from the captured output. Extension loading, code execution, locale resolution and signature verification remain outside this operation. ### Repeated-placeholder regression ![Before and after repeated placeholders, with the fixed capacity boundary and fresh test output](https://files.catbox.moe/94w722.png) The recorded pre-fix failure at `c4ed917` is compared with execution at `5d07138`. The 2,000,038-byte manifest with 200,000 repeated placeholders succeeds through the built CLI and real stdio MCP. A separate manifest with 65 distinct keys returns a typed capacity error. Authored CRX3, XPI and unpacked-manifest fixtures were exercised. These are local Windows results, not green GitHub CI. ## Problem and expected behavior REA can inventory a ZIP and analyze an unpacked JavaScript tree. It cannot answer the first question an extension package raises: what does this manifest declare? A CRX file starts with `Cr24`, so the ZIP classifier does not admit it. An XPI that is a ZIP is a generic archive. Neither path returns permissions, content-script matches, background kind, or a Gecko id. Browser tracker #39 already names extensions as part of the web surface. No open issue or pull request covered CRX, XPI, or WebExtension packages. Expected behavior: one explicit file in, one Evidence record out. Declared text stays distinct from runtime behavior. A bad container or an exhausted budget returns no partial manifest. ## Change and scope The operation follows the portable `inspect_pe_resources` shape: domain contract, adapter parser, application service, CLI command, MCP registration, and a guide. Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope). Unresolved scope, authority, side effects, or required verification block integration. Link the required maintainer scope decision for new providers or capabilities involving target execution, injection, mutation, or protection recovery; ordinary fixes within existing boundaries may state "not applicable". Draft PRs may leave the scope decision pending and the readiness and merge checklists unchecked. Maintainers can help resolve open questions. Scope decision: pending on the linked design issue. Submission for review does not treat silence as approval. Intentionally not included: extension loading, browser launch, store download, CRX signature verification, locale resolution, package comparison, and JavaScript parsing. ## Contract and boundary impact - Semantic owner and earliest changed stage: new artifact-provider parser. Earliest stage is stable regular-file admission, then CRX header measurement, then one ZIP entry read. - Contribution scope fit and linked maintainer decision: format inspection of a caller-selected file. No target execution, injection, mutation, or protection recovery. Maintainer decision pending. - CLI and MCP/tool-catalog contract: adds `inspect_browser_extension` / `inspect-browser-extension`. No existing tool changes meaning. - Provider, bridge, target-format, or platform compatibility: portable Node parser. No Hopper, Ghidra, IDA, or browser provider. - Evidence, artifact, or provenance contract: subject format is `file` for CRX and unpacked manifests, `zip` for a ZIP/XPI. Confidence is `observed`. Limitations stay on the record. - Target selection, authority, upstream behavior, and cleanup details: reads one admitted regular file through the existing stable-read owner. Does not write, launch, or contact a network. zip.js is used only as a reader. - Generated metadata: CI generates ignored catalogs. Authored skill routing was updated in `.agents/skills/reverse-engineer-anything/`. Build outputs are not committed. Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible. - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: `src/browserExtension/parseBrowserExtension.test.ts`, `src/browserExtension/BrowserExtensionProvider.test.ts`. - Base reproduction or other evidence: source inspection of main. No CRX/XPI/WebExtension tool, doc, issue, or PR. `hasZipSignature` requires a `PK` prefix, so a `Cr24` file is not admitted as a ZIP. - User-visible CLI/MCP output: built CLI and real stdio MCP smokes passed against an unpacked manifest with 200,000 repeated placeholders and 2,000,038 bytes. Both returned observed Evidence with `message_keys: ["A"]` and the unresolved-placeholder limitation. An installed npm tarball was not exercised. - Remaining proof gaps: The full `npm run docs:check` wrapper exits on the missing bundled Windows native controls on this host. The underlying generators and `scripts/check-doc-facts.mjs` were run directly and passed. Built CLI and stdio MCP smokes passed; installed-package verification remains unrun. Real-provider lanes are not applicable. Linux CI owns the full generated-catalog check. For evidence-bearing changes: - [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 - `npx vitest run src/browserExtension` — 15 passed on 5d07138, including repeated placeholders, distinct-key limits, nested strings and preserved action-title validation. - `npm run check:fast` — typecheck and lint passed on 5d07138. - `npx vitest run tests/conformance/readmeConsistency.test.ts tests/boundary/filesystem/documentationFacts.test.ts` — 6 passed on 5d07138. - `node scripts/generate-package-metadata.mjs --check`, `node scripts/generate-skill-metadata.mjs --check`, `node scripts/generate-product-catalog.mjs --check`, and `node scripts/check-doc-facts.mjs` — passed after regenerating the ignored catalog and skill bundle. - `npx oxfmt --check .` — passed. - `npm run compile` — passed on 5d07138. - Built `node scripts/rea.mjs inspect-browser-extension <fixture>/manifest.json --json` and stdio MCP `inspect_browser_extension` — passed for the 2,000,038-byte repeated-placeholder fixture. `tests/boundary/mcp/serverIdentity.test.ts` had one failure on this Windows host: `path.resolve("/packaged/rea.mjs")` becomes `D:\packaged\rea.mjs`, so an existing alignment fixture reports `registration_path_mismatch`. `src/serverIdentity.ts` is not in this diff. The other 15 tests in that file passed. This is not claimed as a green Linux run. ## Compatibility, safety, and release - Breaking changes or migration steps: none. New tool and command only. - Real Hopper/Ghidra, browser, or OS coverage: not applicable. Parser tests ran on Windows with Node 26.7.0. - Package or release metadata impact: the next generated catalog and skill bundle will include one tool. No version bump in this PR. - Security, privacy, process, or containment review: read-only file admission. CRX signature bytes are counted and not checked. Extension code is not parsed or executed. Manifest text is target content and is returned as such. ## Author readiness Human owner: @abundantbeing The owner directed this PR to be submitted for maintainer review, including the AI-assisted diff and the verification recorded above. - [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. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [ ] User-visible CLI/MCP changes include representative output. - [x] 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>
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#6305
No description provided.