[PR #2978] [MERGED] feat(electron): report custom URL protocol registrations #5531

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2978
Author: @UnknownHacker1
Created: 10/13/2026
Status: ✅ Merged
Merged: 10/30/2026
Merged by: @gensokyo-dev

Base: main ← Head: feat/electron-protocol-registrations


📝 Commits (7)

  • a3a52a0 feat(electron): report custom URL scheme registrations
  • a9c1a51 fix(electron): skip protocol calls that cannot register a scheme
  • 552a84d fix(electron): match Electron's CustomScheme conversion for privileged lists
  • 9f5877d Merge latest main and correct Electron protocol identity
  • cfaf0f7 Merge remote-tracking branch 'origin/main' into feat/2978-electron-url-protocols
  • c474f5f fix(electron): reuse the shared protocol finding key
  • 3570044 docs(electron): distinguish protocol calls from reachability

📊 Changes

24 files changed (+1134 additions, -11 deletions)

View changed files

📝 src/application/ReconstructionObligationPolicies.ts (+6 -0)
📝 src/application/javascript/ElectronBoundaryAnalysis.ts (+4 -0)
📝 src/application/javascript/ElectronBoundaryGraph.ts (+2 -0)
➕ src/application/javascript/ElectronBoundaryGraphProtocols.ts (+129 -0)
📝 src/application/javascript/JavaScriptArtifactAnalysis.ts (+2 -1)
📝 src/application/javascript/JavaScriptArtifactGraphBuilder.ts (+2 -1)
📝 src/contracts/javascript/javascriptExportShapeComparisonExample.ts (+1 -0)
📝 src/contracts/javascript/javascriptRuntimeReconciliationExample.ts (+1 -0)
📝 src/domain/javascript/electronStaticAnalysis.ts (+2 -0)
➕ src/domain/javascript/electronStaticAnalysisProtocol.test.ts (+333 -0)
➕ src/domain/javascript/electronStaticAnalysisProtocol.ts (+299 -0)
📝 src/domain/javascript/electronStaticAnalysisTypes.ts (+31 -0)
📝 src/domain/javascript/javascriptApplicationAnalysis.ts (+3 -2)
📝 src/domain/javascript/javascriptApplicationAnalysisSteps.test.ts (+12 -0)
📝 src/domain/javascript/javascriptApplicationGraphSchemas.ts (+1 -0)
📝 src/domain/javascript/javascriptApplicationProjectionResources.ts (+2 -1)
📝 src/domain/javascript/javascriptApplicationVersionKeys.ts (+11 -3)
📝 src/domain/javascript/javascriptFeatureTrace.ts (+8 -3)
📝 src/domain/javascript/javascriptStaticAnalysis.ts (+4 -0)
📝 src/domain/javascript/javascriptStaticAnalysisHelpers.ts (+1 -0)

...and 4 more files

📄 Description

Problem and outcome

REA could inspect Electron internals but did not expose custom URL protocol entry-point facts. This change records static registration calls, projects url-scheme nodes and relations, and adds an optional registration count. The existing CLI/MCP workflows share the same implementation; no provider, dependency, target execution or new tool is introduced.

Supported calls: app.setAsDefaultProtocolClient, module-level protocol.registerSchemesAsPrivileged, protocol handlers/interceptors, and handlers/interceptors on session.defaultSession.protocol. Findings retain source locations, artifact digests, API, role, session and privileges. Dynamic values remain unknown. Registration success, control-flow reachability and OS/session routing remain unproven.

Valid scheme identity is case-insensitive; original spelling is preserved per observation. Historical summaries without the count remain readable. Existing javascript-facts views support filtering, field selection, paging and retained Evidence. Non-default sessions, URL event listeners and TypeScript assertions on receivers remain outside this change.

Integration review

Integrated against main 69bf61f7c. Additional corrections:

  • Canonicalize schemes once at the graph owner; App and app share identity while raw values survive. A new public boundary regression was observed failing before the fix. Electron scheme rules.
  • Exclude the module-only privileged API from session protocol objects; keep default-session handlers. The new source regression failed before the fix. Electron implementation.
  • Use the existing compositeKey owner for finding deduplication, fixing the first CI architecture-guard failure without an exemption.
  • Align the owning finding type's documentation with emitted Evidence: a source call does not prove reachability. The valid Greptile thread is resolved with cause, boundary/consumer inspection and validation.

Validation

Final head: 3570044eadadc7866ad4bfa75f3e18628112655c.

  • Current-head CI: Source tests 22,235 passed / 16 skipped; all 8 portable shards passed; Portable tests and CI required passed (run). Static checks, build, documentation, JavaScript recovery, bundled Windows controls and Linux native package baseline passed.
  • Current-head Greptile: passed, 24 files reviewed, 0 new comments; all review threads resolved. Codex remote review was unavailable due repository credit limits and is not counted as passed.
  • Local validation: broad JavaScript suite 5,253 passed / 1 existing skip before the internal-key cleanup; after that cleanup, 61 targeted source tests and 41 public protocol/worker tests passed again. Reconstruction consumers: 47 passed. check:fast, docs:check, architecture guards, touched-file formatting and diff checks passed. The final follow-up changes only JSDoc, with no runtime statement changes.

Real application: official Obsidian 1.8.10 updater ASAR, SHA-256 f9e1d3030d2d165a559f339a91a100e1d3381972a4ce5fdb3b481bd550681dd6. Public CLI analysis selects packaged main.js (33,318 bytes; SHA-256 dea142680af9272f0663a5857f6135ba69c54dcb10e5382b943793295d55169e). Actual CLI and stdio MCP paged facts match an independent source-call/position check: registerFileProtocol("app"), handle("app"), and setAsDefaultProtocolClient("obsidian"), at line 38 columns 4128, 4266 and 14388. Three call sites, two canonical nodes; the first two are conditional alternatives. This verifies the selected packaged file, not the entire application or runtime routing. The target was never executed. Runtime validation was repeated on c474f5ffc; the final commit only corrects type JSDoc.

Real limit probe: Obsidian 1.14.5, SHA-256 3a349274f789b62c5b35ad19de10311909a94e8783033569c2210a4bac491780, selecting main.js and starter.js. Shared analysis reports its existing 512-state alias limit and cannot prove the receivers of three visible protocol calls. Evidence remains partial/unknown with zero confirmed registrations; this is a coverage gap, not an absence claim. Limits and shared identity rules were preserved.

Performance and context

Fresh processes, four-CPU affinity, 512 MiB analysis heap, 100 ms process-family RSS sampling including separate sessions. OS caches were uncontrolled: these are single observations, not controlled cold/warm measurements. Comparison pins baseline 0ffed7a48 and the integrated feature tree before the last unrelated main refresh.

Obsidian 1.8.10 selected-file CLI analysis Before After
Elapsed 11.362 s 10.782 s
CPU 11.441 s 11.886 s
Sampled peak family RSS 674.6 MiB 700.0 MiB

No speedup claim. Final runtime recheck: 10.431 s elapsed, 11.629 s CPU, 678.7 MiB RSS, identical protocol facts/provenance. The 1.14.5 probe completed before/after in 40.110 / 40.952 s, CPU 42.924 / 43.962 s and RSS 994.6 / 1009.9 MiB; those two probes shared CPU and do not establish isolated latency. The broad local JavaScript run used 66.408 s elapsed, 110.229 s CPU and 1,898.7 MiB sampled family RSS while sharing CPU with static/build checks.

Token estimates (tokenx@1.3.0; actual billing unmeasured): selected CLI summary 3,514 → 3,523; relevant MCP input schemas unchanged at 5,024; full relevant definitions 196,186 → 196,219. Summary plus two actual paged MCP request/response exchanges estimates 18,058 tokens, excluding tool definitions. The 17.1 MB complete Evidence stays local. Pages select properties and preserve identity, provenance, coverage and limitations. Existing Evidence parsing/transport costs are included in the observed workflow; no cache was added.

Executed integration checks above were on Linux/Node 24.22.1. The original contributor's Windows/editor validation remains historical evidence in the discussion, not a claim of additional current-head OS/runtime verification.

Author readiness

Human owner: @UnknownHacker1

  • 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/2978 **Author:** [@UnknownHacker1](https://github.com/UnknownHacker1) **Created:** 10/13/2026 **Status:** ✅ Merged **Merged:** 10/30/2026 **Merged by:** [@gensokyo-dev](https://github.com/gensokyo-dev) **Base:** `main` ← **Head:** `feat/electron-protocol-registrations` --- ### 📝 Commits (7) - [`a3a52a0`](https://github.com/morluto/rea/commit/a3a52a090aecaac01a20eed5eb4c358ab9376cd7) feat(electron): report custom URL scheme registrations - [`a9c1a51`](https://github.com/morluto/rea/commit/a9c1a51c4e2cc995988e24c5f7b24f3dfaa8e657) fix(electron): skip protocol calls that cannot register a scheme - [`552a84d`](https://github.com/morluto/rea/commit/552a84d762f5b0d8af180d21d1b72107cbc687a8) fix(electron): match Electron's CustomScheme conversion for privileged lists - [`9f5877d`](https://github.com/morluto/rea/commit/9f5877d895275ae5aff17271d765aaa808e8d014) Merge latest main and correct Electron protocol identity - [`cfaf0f7`](https://github.com/morluto/rea/commit/cfaf0f7be8d09d00180b98fe73bd4377cfe880f5) Merge remote-tracking branch 'origin/main' into feat/2978-electron-url-protocols - [`c474f5f`](https://github.com/morluto/rea/commit/c474f5ffc70b24c1442c4e6b880a46fd7df6332c) fix(electron): reuse the shared protocol finding key - [`3570044`](https://github.com/morluto/rea/commit/3570044eadadc7866ad4bfa75f3e18628112655c) docs(electron): distinguish protocol calls from reachability ### 📊 Changes **24 files changed** (+1134 additions, -11 deletions) <details> <summary>View changed files</summary> 📝 `src/application/ReconstructionObligationPolicies.ts` (+6 -0) 📝 `src/application/javascript/ElectronBoundaryAnalysis.ts` (+4 -0) 📝 `src/application/javascript/ElectronBoundaryGraph.ts` (+2 -0) ➕ `src/application/javascript/ElectronBoundaryGraphProtocols.ts` (+129 -0) 📝 `src/application/javascript/JavaScriptArtifactAnalysis.ts` (+2 -1) 📝 `src/application/javascript/JavaScriptArtifactGraphBuilder.ts` (+2 -1) 📝 `src/contracts/javascript/javascriptExportShapeComparisonExample.ts` (+1 -0) 📝 `src/contracts/javascript/javascriptRuntimeReconciliationExample.ts` (+1 -0) 📝 `src/domain/javascript/electronStaticAnalysis.ts` (+2 -0) ➕ `src/domain/javascript/electronStaticAnalysisProtocol.test.ts` (+333 -0) ➕ `src/domain/javascript/electronStaticAnalysisProtocol.ts` (+299 -0) 📝 `src/domain/javascript/electronStaticAnalysisTypes.ts` (+31 -0) 📝 `src/domain/javascript/javascriptApplicationAnalysis.ts` (+3 -2) 📝 `src/domain/javascript/javascriptApplicationAnalysisSteps.test.ts` (+12 -0) 📝 `src/domain/javascript/javascriptApplicationGraphSchemas.ts` (+1 -0) 📝 `src/domain/javascript/javascriptApplicationProjectionResources.ts` (+2 -1) 📝 `src/domain/javascript/javascriptApplicationVersionKeys.ts` (+11 -3) 📝 `src/domain/javascript/javascriptFeatureTrace.ts` (+8 -3) 📝 `src/domain/javascript/javascriptStaticAnalysis.ts` (+4 -0) 📝 `src/domain/javascript/javascriptStaticAnalysisHelpers.ts` (+1 -0) _...and 4 more files_ </details> ### 📄 Description ## Problem and outcome REA could inspect Electron internals but did not expose custom URL protocol entry-point facts. This change records static registration calls, projects `url-scheme` nodes and relations, and adds an optional registration count. The existing CLI/MCP workflows share the same implementation; no provider, dependency, target execution or new tool is introduced. Supported calls: `app.setAsDefaultProtocolClient`, module-level `protocol.registerSchemesAsPrivileged`, protocol handlers/interceptors, and handlers/interceptors on `session.defaultSession.protocol`. Findings retain source locations, artifact digests, API, role, session and privileges. Dynamic values remain unknown. Registration success, control-flow reachability and OS/session routing remain unproven. Valid scheme identity is case-insensitive; original spelling is preserved per observation. Historical summaries without the count remain readable. Existing `javascript-facts` views support filtering, field selection, paging and retained Evidence. Non-default sessions, URL event listeners and TypeScript assertions on receivers remain outside this change. ## Integration review Integrated against main `69bf61f7c`. Additional corrections: - Canonicalize schemes once at the graph owner; `App` and `app` share identity while raw values survive. A new public boundary regression was observed failing before the fix. [Electron scheme rules](https://www.electronjs.org/docs/latest/api/protocol/). - Exclude the module-only privileged API from session protocol objects; keep default-session handlers. The new source regression failed before the fix. [Electron implementation](https://github.com/electron/electron/blob/main/lib/browser/api/protocol.ts). - Use the existing `compositeKey` owner for finding deduplication, fixing the first CI architecture-guard failure without an exemption. - Align the owning finding type's documentation with emitted Evidence: a source call does not prove reachability. The valid Greptile thread is resolved with cause, boundary/consumer inspection and validation. ## Validation Final head: `3570044eadadc7866ad4bfa75f3e18628112655c`. - Current-head CI: Source tests 22,235 passed / 16 skipped; all 8 portable shards passed; `Portable tests` and `CI required` passed ([run](https://github.com/morluto/rea/actions/runs/41103657048)). Static checks, build, documentation, JavaScript recovery, bundled Windows controls and Linux native package baseline passed. - Current-head Greptile: passed, 24 files reviewed, 0 new comments; all review threads resolved. Codex remote review was unavailable due repository credit limits and is not counted as passed. - Local validation: broad JavaScript suite 5,253 passed / 1 existing skip before the internal-key cleanup; after that cleanup, 61 targeted source tests and 41 public protocol/worker tests passed again. Reconstruction consumers: 47 passed. `check:fast`, `docs:check`, architecture guards, touched-file formatting and diff checks passed. The final follow-up changes only JSDoc, with no runtime statement changes. Real application: official [Obsidian 1.8.10 updater ASAR](https://github.com/obsidianmd/obsidian-releases/releases/tag/v1.8.10), SHA-256 `f9e1d3030d2d165a559f339a91a100e1d3381972a4ce5fdb3b481bd550681dd6`. Public CLI analysis selects packaged `main.js` (33,318 bytes; SHA-256 `dea142680af9272f0663a5857f6135ba69c54dcb10e5382b943793295d55169e`). Actual CLI and stdio MCP paged facts match an independent source-call/position check: `registerFileProtocol("app")`, `handle("app")`, and `setAsDefaultProtocolClient("obsidian")`, at line 38 columns 4128, 4266 and 14388. Three call sites, two canonical nodes; the first two are conditional alternatives. This verifies the selected packaged file, not the entire application or runtime routing. The target was never executed. Runtime validation was repeated on `c474f5ffc`; the final commit only corrects type JSDoc. Real limit probe: Obsidian 1.14.5, SHA-256 `3a349274f789b62c5b35ad19de10311909a94e8783033569c2210a4bac491780`, selecting `main.js` and `starter.js`. Shared analysis reports its existing 512-state alias limit and cannot prove the receivers of three visible protocol calls. Evidence remains partial/unknown with zero confirmed registrations; this is a coverage gap, not an absence claim. Limits and shared identity rules were preserved. ## Performance and context Fresh processes, four-CPU affinity, 512 MiB analysis heap, 100 ms process-family RSS sampling including separate sessions. OS caches were uncontrolled: these are single observations, not controlled cold/warm measurements. Comparison pins baseline `0ffed7a48` and the integrated feature tree before the last unrelated main refresh. | Obsidian 1.8.10 selected-file CLI analysis | Before | After | |---|---:|---:| | Elapsed | 11.362 s | 10.782 s | | CPU | 11.441 s | 11.886 s | | Sampled peak family RSS | 674.6 MiB | 700.0 MiB | No speedup claim. Final runtime recheck: 10.431 s elapsed, 11.629 s CPU, 678.7 MiB RSS, identical protocol facts/provenance. The 1.14.5 probe completed before/after in 40.110 / 40.952 s, CPU 42.924 / 43.962 s and RSS 994.6 / 1009.9 MiB; those two probes shared CPU and do not establish isolated latency. The broad local JavaScript run used 66.408 s elapsed, 110.229 s CPU and 1,898.7 MiB sampled family RSS while sharing CPU with static/build checks. Token estimates (`tokenx@1.3.0`; actual billing unmeasured): selected CLI summary 3,514 → 3,523; relevant MCP input schemas unchanged at 5,024; full relevant definitions 196,186 → 196,219. Summary plus two actual paged MCP request/response exchanges estimates 18,058 tokens, excluding tool definitions. The 17.1 MB complete Evidence stays local. Pages select properties and preserve identity, provenance, coverage and limitations. Existing Evidence parsing/transport costs are included in the observed workflow; no cache was added. Executed integration checks above were on Linux/Node 24.22.1. The original contributor's Windows/editor validation remains historical evidence in the discussion, not a claim of additional current-head OS/runtime verification. ## Author readiness Human owner: @UnknownHacker1 - [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. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:07:22 +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#5531
No description provided.