# Realms Integrity w/ a shared DOM We are considering two approaches for the Realms API today: ## Current Proposal In the current proposal, we allow an origin Realm to create new synthetic Realms. Non synthetic Realms are those _naturally_ loaded, e.g. the first Realm in a web page with the Window, the DOM API, etc.. ### Jargon The synthetic Realms can also create new Realms. All the origin Realms are called the _incubator realms_ when compared to new realms created within. The new created Realms are also called _child realms_ of respective incubator realm. ### API The proposed API is described as the following: ```javascript declare class Realm { constructor(); readonly globalThis: typeof globalThis; import(specifier: string): Promise<Namespace>; } ``` The instance of a new Realm will provide access to the Realm's `globalThis` and a dynamic (async) `import()`. Nothing else. The `globalThis.eval` is still subject to CSP. There is a similarity over iframes, but with a proposed idea of not loading anything in the synthetic Realm beyond the intrinsics of ECMAScript. The issue with iframes is a big load including a new Window, DOM API, and unforgeable names such as `window.top` and `window.location`. Some of those values, specially `window.top` creates a non removable fingerprint reavealing the code is not running in the top origin Realm. The exposure of `globalThis` is only from the synthetic Realm to the incubator Realm. The only way for the synthetic Realm to see values and names from the incubator Realm is if a code within the incubator Realm adds a reference into the realms. Globals and other values are not leaked via `import()` as the module map is not shared. The advantage of having a visible `globalThis` is providing immediate integration of the code executed in the synthetic Realm with the origin Realm's DOM API. ### Identity Discontinuity and Membranes There is a known concern about _Identity Discontinuity_, e.g.: ```javascript Array === new Realm().globalThis.Array; // false Object === new Realm().globalThis.Object; // false ``` This is not new and has been handled for a while as a a known characteristic of Realms in ECMAScript, unregarding the new API, and can be seen similarly in iframes, Node's `vm` and in many other ways where new Realms can be created. One way to approach this is through membranes. We have libraries such as [Salesforce's NearMembranes](https://github.com/salesforce/observable-membrane) to properly connect two Realm running on the same process. The membrane enables the code evaluated inside the Child Realm to function as if it is evaluated in the Incubator Realm, exhibiting identity continuity, while preserving the integrity of the Incubator Realm by limiting the side effects that such code can have. This library offers a complete membrane implementation while the Realms still offers flexibility over more lightweight approaches. #### Membrane Goals The goals of the membranes are fit within the goals of this proposal: - Code executed inside the sandboxed environment cannot observe the sandbox. - Mutations on the object graph should only affect the sandboxed environment. #### The iframe challenges The current membranes proposal is [aware of a challenges within iframes](https://github.com/salesforce/near-membrane#challenges) such as window location discontinuity, this is something that would be mitigated over the Realms proposal. ### Integrity A common misconcept of the Realms proposal is creating a new Realm to run only a very specific function or methods as if they were a different process. The idea of the code executed in the Realms is to run them seamlessly, without observation that it is in a sandbox. Realms is a first step, followed by the membranes. This is important to preserve integrity of the code and keeping things robust. #### Use Cases The Realms enables compartmentized scripts for the same process, and this is a common use case of large (enterprise) applications and anything that runs over integration of multiple clients code. There is a need to guard the integrity of the main application code and each of those composition of clients code. From a developer perspective, this can be seen as Web-based IDEs (e.g. Visual Studio Code) running different sets of third party extensions. The extensions are provided by different users and organizations, and therefore set as trusted or verified third party scripts. From a general perspective, there is the example of SaaS and B2B Marketplaces. A web application can be composed of a fundamental structure that provides a marketplace, aka app store that lead to to a user made composition of the main application with many third party applications. This provides a custom set to the user needs. There is no illusion of extra security provided by the proposal, but there is an idea of better integrity of those third party code being properly compartmentized without leaking to each other or compromising the fundamental structure. ### Extensions and App Marketplaces This App Marketplace model is a common reflection of the era we live in and a raising need of business moving to the Web. It is not something being invented, it is a business model being used. Browsers extentions/plugins/addons/devtools share a similar capacity of being executed while in need to have proper access to the structure of a given web application. ## Structure Cloning API A [new proposal for isolated Realms](https://github.com/tc39/proposal-realms/issues/289) sets an interesting API without the exposure of `globalThis` or an immediate value from a child realm. Although, the API offers a evaluation method `realm.eval()` and preserves the `realm.import()`. Using this API, we don't get the actual values but a structured clone of the completion result. In the given example: ```javascript const realm = new Realm(); // value is a structured clone of the completion value const value = realm.eval("[1, { foo: 'bar' }]"); // Its prototype chain is thus based on *the parent realm*'s intrinsics console.assert(value.__proto__ === Array.prototype); console.assert(value[1].__proto__ === Object.prototype); ``` We did some prototyping around this idea to measure performance and it seems to not be a deal breaker, which is a good news! We also did some homework to see if some of the existing membranes would work with this proposal, and here is where things become complicated. ```javascript const realm = new Realm(); // this evaluates to { x: 1 }, the value of obj const objClone = realm.eval("globalThis.obj = { x: 1 }"); // this evaluates to a new clone of { x: 1 } const value = realm.eval("obj"); // that's a new clone of { x: 1 } // Wrong, they are diferent copies of the same reference. console.assert(objClone === value); ``` There seems to be a complicated trade off from Identity Discontinuity to Reference Discontinuity. Maybe this API could provide other internal mechanism to help overcome this issue. While it's uncertain if this is possible, the idea would be: ```javascript realm.eval(`globalThis.foo = { x: 1 }`); realm.eval(`Array.prototype`) === realm.eval(`Array.prototype`); // to yield `true` realm.eval(`foo`) === realm.eval(`foo`); // to yield `true` ``` We would need the UA to do some ref-tracking across this boundary, so the incubator realm's ref (in this case empty plain object based on the initial example) can continue to be linked to the corresponding ref from the realm, and release that memory when the realm doesn't need access to that object anymore. This is clearly a lot different than the already well establish structured cloning algo, but a variation of it to reuse some references when possible. Since both realms are in the same process, it might be possible. Similarly, we will have to define how that works for `Realm.set`/`call`/etc. But the bottom line is that such mechanism will eliminate the necessity of doing any user-land book-keeping for references that needs to be tracked across references, clearing the way for a membrane to support any kind of virtualization. ### Other Challenges We still need to go through some challenges, some of them in order to resolve the Reference problems. #### Structured Cloning As [pointed out by Jack Works](https://github.com/tc39/proposal-realms/issues/289#issuecomment-764180186), there is an ongoing proposal for serialization of data. This is important as the link between Realm values are limited very general values represented by primitives to JS built-in objects. ```javascript const realm = new Realm(); const obj = realm.eval('class Foo Extends Array {}; new Foo();'); obj.__proto__ === ??? ``` We would need to set expectations over inherited custom prototypes beyond Array and Object. The reference is not only lost for obj, but for its `__proto__` as well. There is much to be done and resolved for a structured cloning and how to make it fairly usable. #### No Reference Tracking Any changes to an evaluated result from the realm would never be tracked. I can't tell if `{ x: 1 }` is the same realm's object that further evaluates as `{ x: 1 }` __or not__. I can't tell if `{ x: 1 }` is the same realm's that further evalues as `{ x: 1, y: 2 }`, __or not__. As mentioned several times, the use case for sandbox is about integrity, not security. This model gives too little to support any integrity.