July 28th, 2022 One does not simply call a function By Jeffrey M. Barber

July was exceptionally productive on many fronts. The IDE is coming along, and I’m shooting for a second early access launch with the web portal. RxHTML is shaping up, and the tension between the purity of doing everything with RxHTML and needing a few escape hatches here and there has been illuminating.

Adama now offers basic website hosting, limited CDN functionality, secret management, collaborative text editing with operational transforms, and has the foundations for calling other services. As I’m exploring how to have Adama talk to itself to become a full actor model, trust has become a central issue.

For instance, a rogue Adama developer could share a website with a community of Adama developers and collect developer principals. Adama has a client type which I should have really called a principal. Perhaps, I should rename client to principal at some point; the sooner the better, right? This client type represents a unique person that has been authenticated. Intentionally, the language can’t invent principals as they must come from the outside. Within the silo of an Adama document, the script controls everything, and developers can use the principal to restrict view or perform access control. However, going outside the sandbox requires some degree of propagation of a principal.

The more I think about it, the more annoyed I am about choosing the client name rather than principal since I lack any notion of device.

The key scenario prompting this is have Adama talk to itself. For example, the IDE needs to list the spaces of the logged in user. This requires talking to the Adama API, but turning that API into a service call requires care because the client doing the listing is an input.

  private client owner;
  formula space_listing = adama.list(owner);

The result of the list call should be considered sensitive for the eyes of the owner only, but this assumes that every Adama script can be trusted to do the right thing. Trust is hard, and I’d rather not audit developers. Instead, I want to know that people calling the Adama API don’t have the opportunity to leak data. The question on my mind is how to use the type system.

Backing up a second, we have to think about authorization and access control between services. Right now, the standard operating mode is simple service to service authorization where one service enables another via a token or credential pair. An alternative mode is allowing another service to access a particular user, and this requires something like oauth2 which has a complex asynchronous negotiation. At some point, the user needs to signal “Yes, I trust this third party service with my data hosted on your service”.

I want to skip the need for that, and I intend to use the type system to do so. I intend to take the NtClient type, rename it to NtPrincipal and then fork the TyNativeClient type into TyNativePrincipal and TyNativePrincipalTrusted. The @who expression which is a handy way of getting the principal invoking a specific action will be of type TyNativePrincipalTrusted since it is coming directly from Adama.

This bifurcation creates the potential to introduce rules which ensure that services can be marked as “trusted” can only function when provided a trusted principal.

We need the trivial rules to convert a TyNativePrincipalTrusted into a TyNativePrincipal such that existing code can function well, but the big question is how the new trusted type can be used and where. We ask whether a message handler can invoke a service that requires trust, and the answer is no.

  channel foo(M msg) {
    let listing = adama.list(@who);
    // opportunity to persist the data
  }

The reason being is that the computational context permits storing the result which can cause leaks. We then grind through the various contexts and think about the ramifications of a service call.

context can we invoke a trusted service why
message handler no data leakage
state machine transition no data leakage
web put no, and maybe for reading data, no as that leads to data leakage. For propagating a write, then yes.
bubble yes the bubble is only viewable to the trusted user
web get yes, but the result is unique to the trusted user (assuming no caching)
formula maybe requires a privacy policy to limit the owner, also requires internal control to limit reading the data

The key theme is that if the context can write to the document, then it’s a definitive no for reading data. Work is required to allow formulas to (1) enforce a privacy type that respects a unique principal, and (2) ensure that Adama code can’t read the value of the formula. Enabling the web scenarios require enforcing the return can’t specify a cache value as that leaks data between users, and we also need a way to delineate between a read-write method and a write-only method for puts to propagate information.

These concerns should be deprioritized and skipped with all focus being on first getting service calls working in bubbles and getting them to work. This has the interesting side-effect of turning Adama into a proxy which preserves trust at the user level.

This sets the stage for some of the work to get done in august. Especially as I warm up to the idea of grinding on converting client to principal. Naming things is hard.