commontoolsinc / labs

13 stars 4 forks source link

Quickest way to add sandboxing to current charm framework #217

Open seefeldb opened 3 days ago

seefeldb commented 3 days ago

This just a possible approach, but let's spell it out:

As background: (See common-runner/src/cell.ts)

Proposal:

So really just three exposes functions:

I think that's it, actually!

Bonus:

jsantell commented 1 day ago

After discussing, it sounds like a single host callback can be sufficient in supporting features in the lookslike prototype with minimal changes to the sandbox. Sandboxed code can execute the host callback via globalThis.hostCallback(..), args serialized into the host environment where the callback is executed, where the return value is sent back into the sandboxed content.

// common-os, main thread
let engine = new CTEngine((input) => {
  switch (input.message) {
    case "getAtPath": return getAtPath(...input.args);
    case "setAtPath": return setAtPath(...input.args);
    case "reactivityLog": return reactivityLog(...input.args);
    default: return undefined;
  }
});
let sandbox = engine.define(`
  export const run = (input) => {
    input.foo = input.foo + 1;

    let value = globalThis.hostCallback({
      message: "getAtPath",
      args: [/* .. */],
    });

    return input;
  }
`);

let result = sandbox.run({ foo: 1 });
console.assert(result.foo === 2);

An open question is if we need any "scoping" of host callbacks per instance. For example, in the above case, any sandbox can request any values for setAtPath/getAtPath. We may want to tag each sandbox/instance with some T/UserData/identifier.

seefeldb commented 1 day ago

Ah yes, that would be great, especially a tag that doesn't roundtrip through the sandbox so it can't be tampered with. Could just be an id that is generated by the API that invokes the sandbox?