You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist / 檢查清單
背景
對應 issue #1701:Firefox 的
USER_SCRIPTworld 中,globalThis與頁面window屬於不同 JavaScript realm。原有 sandbox snapshot 將 JavaScript realm 的 intrinsic、頁面 Window 的 DOM/WebIDL 成員,以及 userscript 自己的 global 混在同一條 descriptor chain 中。這會造成
window、self、globalThisalias 不一致,讓 DOM/EventTarget method 使用錯誤 receiver,並可能在 constructor/interface 被 bind 後遺失prototype或 static properties。本次改動
window尚未有 ownglobalThis,先補上指回 hostwindow的 fallback,確保unsafeWindow.globalThis在 Firefox split-realm 下可用。realmGlobal:只收集 userscript realm 的 own descriptors,保留 JavaScript intrinsics,並對同名 descriptor 取得優先權。hostWindow:收集 host Window 的 own/prototype descriptors,補齊 DOM、Window accessor、EventTarget method 與 host constructor/interface。createProxyContext()的 roots 建模為RealmRoots;生產路徑維持預設的global/window,測試則可注入 split-realm roots。Function.prototype.bindmaterialize 需要 receiver 的 host function、getter/setter;constructor/interface 不 bind,以保留prototype和 static members。window、self、globalThis始終指向目前 sandbox;top、parent、frames在 host 指向自身時折回目前 sandbox,非自身的 iframe reference 則保留。on*event property 的註冊與移除統一作用在 host Window,callback 的this保持為 sandbox;function replacement 不重複註冊,object/primitive/null handler 不作為 function listener。window.onurlchange的 grant gate,並使用 host navigation channel;未授權時不建立 accessor 或 listener。onurlchange。example/tests/sandbox_compatibility_test.js黑盒診斷 userscript,提供頁面隔離、global alias、descriptor、host receiver、constructor/interface、事件、onurlchange、GM API 檢查,以及面板、重跑和 JSON 報告功能。sandbox_test.js重命名為sandbox_function_test.js,並同步更新e2e/gm-api.spec.ts的 fixture 名稱與輸出標籤。實現考慮
descriptor source 的順序固定為:
realmGlobal own descriptors→hostWindow own/prototype descriptors→PseudoWindow descriptors→ sandbox-specific descriptors同一來源的 prototype chain 以較近的 descriptor 優先;realm own descriptor 也優先於 host 的同名 descriptor。host own properties 會納入 snapshot,host prototype 只用來補齊尚未被前一階段取得的成員,因此可同時保留必要 host surface 與 realm intrinsic identity。
bind 目標跟隨 descriptor 的來源:realm function/accessor 綁定到
realmGlobal,host function/accessor 綁定到hostWindow。有prototype或以大寫名稱識別的 constructor/interface 不綁定,避免bind剝掉其 prototype 或 static surface;binding 使用已保存的Function.prototype.bind,不依賴 Xray callable 自身的.bindlookup。事件 property 維持既有 lifecycle 契約:註冊與移除作用在同一個 host event target,handler 的
this仍是目前 sandbox;window.onurlchange只有在對應 grant 存在時才建立。已知限制
createContext()/createProxyContext()的 split-realm sandbox model;沒有改變@grant none是否建立 sandbox 的既有 policy。sandbox_compatibility_test.js是可在瀏覽器中執行的黑盒診斷工具,目前未接入 Playwright 自動測試;自動 E2E 仍執行重命名後的sandbox_function_test.js。Cu.Sandbox/ Xray runtime 中手動驗證;Vitest 使用 deterministic roots fixture 模擬 split-realm、host receiver 與事件 contract。window.onurlchange與其他 host API 的完整 browser coverage 仍受實際瀏覽器/管理器暴露面影響,診斷器會將不可用項目標為SKIP,將可選差異標為WARN。pnpm run test:ci曾因環境禁止監聽127.0.0.1收到listen EPERM,結果為 343/344 test files、4316/4317 tests 通過;這不是本 PR 的 assertion failure。建議審查重點
realmGlobal/hostWindow的 descriptor precedence,以及 host own/prototype 成員的預期暴露邊界。prototype、static constants 與 pseudo-window 的toStringTag/constructor/__proto__identity。window、self、globalThis、top、parent、frames的 sandbox identity 與 iframe 非自身 reference 語義。on*property 的 register/remove/replace lifecycle、window.onurlchangegrant gate,以及每個 sandbox 的 state isolation。參考
src/app/service/content/create_context.tssrc/app/service/content/create_context.test.tsexample/tests/sandbox_compatibility_test.jsexample/tests/sandbox_function_test.js(由sandbox_test.js重命名)e2e/gm-api.spec.ts驗證
7b54e85c6e03cdbf75a94040ca59a546e0eb4043):Lint、Run test shard (1/2)、Run test shard (2/2)、Run E2E tests (1/4)至(4/4)、Run tests、License Compliance、codecov/project均為成功。pnpm exec vitest run src/app/service/content/create_context.test.ts src/app/service/content/exec_script.test.ts src/app/service/content/exec_warp.test.ts --reporter=dot— 3 files / 72 tests passedpnpm run typecheck— passedpnpm run lint— passedpnpm exec eslint . --cache --cache-location .eslintcache— passedpnpm exec prettier --check src/app/service/content/create_context.ts— passedpnpm run test:ci— 343/344 files、4316/4317 tests passed;唯一失敗為上述 localhostEPERM環境限制