[PR #1815] feat(javascript): add proof-gated js-redox deobfuscation #4832

Open
opened 2026-10-31 00:55:31 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1815
Author: @codeandsolder
Created: 10/11/2026
Status: 🔄 Open

Base: main ← Head: feat/js-redox-safe-deobfuscation


📝 Commits (1)

  • 5656dea feat(javascript): add proof-gated js-redox deobfuscation

📊 Changes

54 files changed (+6318 additions, -37 deletions)

View changed files

📝 .github/workflows/real-javascript-recovery.yml (+27 -0)
📝 docs/javascript-application-workflows.md (+3 -0)
➕ docs/javascript-deobfuscation.md (+134 -0)
📝 docs/javascript-recovery.md (+3 -0)
📝 package.json (+1 -0)
📝 scripts/ci/scopes.mjs (+17 -1)
📝 scripts/lib/catalog-builders.mjs (+9 -0)
📝 scripts/lib/catalog-core.mjs (+4 -0)
📝 scripts/lib/docs-facts.mjs (+62 -0)
➕ scripts/verify/javascript/deobfuscation.mjs (+163 -0)
📝 src/apktool/ApktoolCommandRecovery.test.ts (+13 -5)
📝 src/apktool/ApktoolVersionProbe.test.ts (+9 -2)
📝 src/application/CapabilityInventory.test.ts (+5 -0)
📝 src/application/CapabilityInventory.ts (+9 -0)
➕ src/application/javascript/JavaScriptDeobfuscationPort.ts (+22 -0)
➕ src/application/javascript/JavaScriptDeobfuscationService.test.ts (+1019 -0)
➕ src/application/javascript/JavaScriptDeobfuscationService.ts (+604 -0)
📝 src/artifacts/ArtifactResourceScope.test.ts (+40 -0)
📝 src/artifacts/ArtifactResourceScope.ts (+37 -4)
📝 src/artifacts/readStableArtifact.ts (+18 -1)

...and 34 more files

📄 Description

Summary

  • add caller-supplied js-redox deobfuscate-safe 0.1.1 as a separate proof-gated single-script JavaScript deobfuscation capability
  • expose deobfuscate_javascript_source over MCP and deobfuscate-javascript-source over the CLI
  • publish the exact input, transformed JavaScript, validated js-safe-deobfuscate/v1 report, bounded diagnostics, and a manifest with engine + resource-limiter provenance
  • preserve explicit .mjs / .cjs source mode through staging, producer proof, publication, and downstream analysis handoff
  • never execute target JavaScript; rewrites whose proof preconditions do not hold remain unchanged

This remains intentionally separate from Wakaru source recovery: Wakaru recovers/extracts module structure, while js-redox emits one conservative transformed file plus a proof report describing which rewrite classes fired.

Current checkpoint

The feature is one commit directly on upstream 5d6b8a0ab693c03ab85cf0807d40bedf021e76d8.

  • head: 5656deadd92692574940b403e53e2f95d633d8a3
  • tree: 08930ed028cb95d35b4dc28f43bba591510f01d9
  • stable patch-id: 87ff08da54fa2819367a3956b4d8a78b73f2a24f
  • review surface: 54 files, +6,318/-37

The latest review pass closed the remaining lifecycle/authority holes rather than adding new feature scope: service shutdown now drains admitted transactions before provider shutdown; cleanup admission failures retain live cleanup state; returned paths must be absolute; the downstream analysis directory must contain exactly the verified transformed file; provider identity is schema-validated before Evidence construction; caller cancellation wins over admission-path failures; and the shared CLI finalizer is owned by the real JavaScript qualification lane.

Artifact authority and provenance

Provider metadata is not authority for shipped artifacts. REA physically rereads published source/output/report/manifest/diagnostics through owned stable-file reads, verifies SHA-256 and byte length, rechecks canonical path containment, and rejects physical aliases such as hard links between artifact roles.

Returned artifact and handoff paths must be absolute, canonicalize to exactly the advertised locations, remain beneath the frozen output root, and remain stable across verification. The analysis handoff directory is inventoried before and after reads and may contain only the verified transformed output.

Source/output reads are capped at 64 MiB, proof/diagnostics at 8 MiB, and manifest reads at 1 MiB. Provider-advertised sizes do not define verifier memory budgets. Inline failed-command/version diagnostics are independently UTF-8-byte bounded.

Cancellation and cleanup ownership

Service admission owns the transaction through provider work, publication, and physical verification. Shutdown first stops admission and drains all admitted service transactions, then closes the provider, so provider resources cannot disappear beneath in-flight verification.

Cleanup is represented as live ownership, not flattened prose. Descriptor, process, output-tree, private-runtime, and external artifact cleanup use independent leases. Private runtime retirement waits only on resources that can actually still own that runtime; unrelated external reads no longer retain it.

When operation failure and cleanup failure coexist, the typed operation failure remains cleanupPrimary; REA's shared cleanup-composition helper carries the unresolved cleanup alongside it and resolvedAnalysisError() returns the original typed failure once cleanup resolves.

The version probe and transformation share one absolute monotonic deadline. Limiter binding and inherited-limit discovery are charged to the same deadline, which is recomputed immediately before process launch.

Producer contract

The audited producer is current js-redox mainline commit b830d03483aed0ed2bf3f146cfa5602361e3a6ae, version 0.1.1.

It was rebuilt from a detached isolated worktree with an isolated Cargo target using Rust 1.99 through the existing sccache client:

  • engine SHA-256: 41f0d8388c64738972a04723a2225415c6a02a7681fecbfa698b19e42a642ed1
  • engine size: 7,831,032 bytes
  • real verifier: CLI and stdio MCP both pass with identical input/output/proof digests

The isolated target is deliberate: an earlier qualification demonstrated that a shared Cargo target can silently replace the binary underneath an otherwise exact source pin.

Real-provider CI ownership

The javascript_recovery selector owns the js-redox feature paths plus the shared artifact/process primitives that can change physical verification or cleanup semantics. src/cli/finishAnalysisCommand.ts is explicitly included because final CLI cleanup can change a cleanup-only result back into verified success.

Classification regressions prove these paths select the real JavaScript qualification lane without broadening ownership to all shared filesystem code.

Verification

Exact published head 5656deadd92692574940b403e53e2f95d633d8a3:

  • focused service/provider/execution/CI-scope regressions: 379/379 pass across 4 test files
  • npm run check:fast: pass on the exact head (also enforced by the pre-push hook)
  • git diff --check: pass
  • real pinned js-redox verifier: CLI and stdio MCP pass with identical output digest 9e8e0d34ccd87d9e6a070a5a885a88557f18e2a0b2926352e276dd81aeb279cc
  • audited producer revision: b830d03483aed0ed2bf3f146cfa5602361e3a6ae
  • isolated producer SHA-256: 41f0d8388c64738972a04723a2225415c6a02a7681fecbfa698b19e42a642ed1

Full GitHub qualification remains the source of truth for the broader CI/docs/architecture matrix on this published head.

AI Disclosure: AI developed, human directed and reviewed.

Author readiness

Human owner: @codeandsolder

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

🔄 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/1815 **Author:** [@codeandsolder](https://github.com/codeandsolder) **Created:** 10/11/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat/js-redox-safe-deobfuscation` --- ### 📝 Commits (1) - [`5656dea`](https://github.com/morluto/rea/commit/5656deadd92692574940b403e53e2f95d633d8a3) feat(javascript): add proof-gated js-redox deobfuscation ### 📊 Changes **54 files changed** (+6318 additions, -37 deletions) <details> <summary>View changed files</summary> 📝 `.github/workflows/real-javascript-recovery.yml` (+27 -0) 📝 `docs/javascript-application-workflows.md` (+3 -0) ➕ `docs/javascript-deobfuscation.md` (+134 -0) 📝 `docs/javascript-recovery.md` (+3 -0) 📝 `package.json` (+1 -0) 📝 `scripts/ci/scopes.mjs` (+17 -1) 📝 `scripts/lib/catalog-builders.mjs` (+9 -0) 📝 `scripts/lib/catalog-core.mjs` (+4 -0) 📝 `scripts/lib/docs-facts.mjs` (+62 -0) ➕ `scripts/verify/javascript/deobfuscation.mjs` (+163 -0) 📝 `src/apktool/ApktoolCommandRecovery.test.ts` (+13 -5) 📝 `src/apktool/ApktoolVersionProbe.test.ts` (+9 -2) 📝 `src/application/CapabilityInventory.test.ts` (+5 -0) 📝 `src/application/CapabilityInventory.ts` (+9 -0) ➕ `src/application/javascript/JavaScriptDeobfuscationPort.ts` (+22 -0) ➕ `src/application/javascript/JavaScriptDeobfuscationService.test.ts` (+1019 -0) ➕ `src/application/javascript/JavaScriptDeobfuscationService.ts` (+604 -0) 📝 `src/artifacts/ArtifactResourceScope.test.ts` (+40 -0) 📝 `src/artifacts/ArtifactResourceScope.ts` (+37 -4) 📝 `src/artifacts/readStableArtifact.ts` (+18 -1) _...and 34 more files_ </details> ### 📄 Description ## Summary - add caller-supplied js-redox `deobfuscate-safe` 0.1.1 as a separate proof-gated single-script JavaScript deobfuscation capability - expose `deobfuscate_javascript_source` over MCP and `deobfuscate-javascript-source` over the CLI - publish the exact input, transformed JavaScript, validated `js-safe-deobfuscate/v1` report, bounded diagnostics, and a manifest with engine + resource-limiter provenance - preserve explicit `.mjs` / `.cjs` source mode through staging, producer proof, publication, and downstream analysis handoff - never execute target JavaScript; rewrites whose proof preconditions do not hold remain unchanged This remains intentionally separate from Wakaru source recovery: Wakaru recovers/extracts module structure, while js-redox emits one conservative transformed file plus a proof report describing which rewrite classes fired. ## Current checkpoint The feature is one commit directly on upstream `5d6b8a0ab693c03ab85cf0807d40bedf021e76d8`. - head: `5656deadd92692574940b403e53e2f95d633d8a3` - tree: `08930ed028cb95d35b4dc28f43bba591510f01d9` - stable patch-id: `87ff08da54fa2819367a3956b4d8a78b73f2a24f` - review surface: **54 files, +6,318/-37** The latest review pass closed the remaining lifecycle/authority holes rather than adding new feature scope: service shutdown now drains admitted transactions before provider shutdown; cleanup admission failures retain live cleanup state; returned paths must be absolute; the downstream analysis directory must contain exactly the verified transformed file; provider identity is schema-validated before Evidence construction; caller cancellation wins over admission-path failures; and the shared CLI finalizer is owned by the real JavaScript qualification lane. ## Artifact authority and provenance Provider metadata is not authority for shipped artifacts. REA physically rereads published source/output/report/manifest/diagnostics through owned stable-file reads, verifies SHA-256 and byte length, rechecks canonical path containment, and rejects physical aliases such as hard links between artifact roles. Returned artifact and handoff paths must be absolute, canonicalize to exactly the advertised locations, remain beneath the frozen output root, and remain stable across verification. The analysis handoff directory is inventoried before and after reads and may contain only the verified transformed output. Source/output reads are capped at 64 MiB, proof/diagnostics at 8 MiB, and manifest reads at 1 MiB. Provider-advertised sizes do not define verifier memory budgets. Inline failed-command/version diagnostics are independently UTF-8-byte bounded. ## Cancellation and cleanup ownership Service admission owns the transaction through provider work, publication, and physical verification. Shutdown first stops admission and drains all admitted service transactions, then closes the provider, so provider resources cannot disappear beneath in-flight verification. Cleanup is represented as live ownership, not flattened prose. Descriptor, process, output-tree, private-runtime, and external artifact cleanup use independent leases. Private runtime retirement waits only on resources that can actually still own that runtime; unrelated external reads no longer retain it. When operation failure and cleanup failure coexist, the typed operation failure remains `cleanupPrimary`; REA's shared cleanup-composition helper carries the unresolved cleanup alongside it and `resolvedAnalysisError()` returns the original typed failure once cleanup resolves. The version probe and transformation share one absolute monotonic deadline. Limiter binding and inherited-limit discovery are charged to the same deadline, which is recomputed immediately before process launch. ## Producer contract The audited producer is current js-redox mainline commit `b830d03483aed0ed2bf3f146cfa5602361e3a6ae`, version `0.1.1`. It was rebuilt from a detached isolated worktree with an isolated Cargo target using Rust 1.99 through the existing sccache client: - engine SHA-256: `41f0d8388c64738972a04723a2225415c6a02a7681fecbfa698b19e42a642ed1` - engine size: **7,831,032 bytes** - real verifier: CLI and stdio MCP both pass with identical input/output/proof digests The isolated target is deliberate: an earlier qualification demonstrated that a shared Cargo target can silently replace the binary underneath an otherwise exact source pin. ## Real-provider CI ownership The `javascript_recovery` selector owns the js-redox feature paths plus the shared artifact/process primitives that can change physical verification or cleanup semantics. `src/cli/finishAnalysisCommand.ts` is explicitly included because final CLI cleanup can change a cleanup-only result back into verified success. Classification regressions prove these paths select the real JavaScript qualification lane without broadening ownership to all shared filesystem code. ## Verification Exact published head `5656deadd92692574940b403e53e2f95d633d8a3`: - focused service/provider/execution/CI-scope regressions: **379/379 pass across 4 test files** - `npm run check:fast`: pass on the exact head (also enforced by the pre-push hook) - `git diff --check`: pass - real pinned js-redox verifier: **CLI and stdio MCP pass** with identical output digest `9e8e0d34ccd87d9e6a070a5a885a88557f18e2a0b2926352e276dd81aeb279cc` - audited producer revision: `b830d03483aed0ed2bf3f146cfa5602361e3a6ae` - isolated producer SHA-256: `41f0d8388c64738972a04723a2225415c6a02a7681fecbfa698b19e42a642ed1` Full GitHub qualification remains the source of truth for the broader CI/docs/architecture matrix on this published head. AI Disclosure: AI developed, human directed and reviewed. ## Author readiness Human owner: @codeandsolder - [ ] 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. --- <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#4832
No description provided.