Security
When building apps with Interval, it's helpful to understand the boundaries of how and where code is being executed. We've created a hybrid architecture under which business logic and secrets live within your app codebase and the rendering of interfaces for your tools is handled through an Interval Server instance.
By example, let's step through this simple app which imports the Interval SDK, written in a JavaScript codebase:
const path = require("path");
const { Interval } = require("@interval/sdk");
const databaseClient = require("./db");
const interval = new Interval({
endpoint: "wss://<YOUR INTERVAL SERVER URL>/websocket",
apiKey: "<YOUR API KEY>", // get an API key from the Keys page in your Interval dashboard
});
interval.listen();
const { Action } = require("@interval/sdk");
module.exports = new Action(async io => {
const userId = await io.input.number("Enter a user id");
const user = await databaseClient.user.findById(userId);
return {
greeting: `Hello, ${user.name}`,
};
});
This action is defined within your own codebase. @interval/sdk
is imported just like any other package.
When interval.listen()
is called, we establish a persistent bi-directional message passing link between your app and an Interval Server instance.
Of course, it's a little more involved than this under the hood, but to a first approximation, the Interval SDK exists to:
- Set up a message passing link w/ Interval Server
- Parse and act on messages from Interval Server
- Create and send messages to Interval Server
So what are these messages?
The first message sent over this link tells Interval Server, "here's the list of the actions my app can handle."
- From your app -> Interval Server:
DEFINE_ACTIONS(['hello_user'])
From within the Interval web dashboard, when someone at your company clicks "run" on the "hello_user" action, Interval sends a message to your app, saying, "start executing the "hello_user" action.
- From Interval Server -> your app:
RUN_ACTION('hello_user')
The interval
client you defined then calls the function you named hello_user
. When await io.input.number("Enter a user id")
is called, the Interval SDK sends a message saying, "Collect data of type number
from the user running the action".
- From your app -> Interval Server:
REQUEST_INPUT('number', { label: 'Enter a user id' })
The Interval dashboard will present the user running the action with an input to enter a number. When they complete entering their input, Interval sends a message back to your app saying, "here's the input you asked for."
- From Interval Server -> your app:
INPUT_PROVIDED('number', { value: 123 })
Once the function has finished executing, your app then emits a message to Interval saying, "the action has completed."
- From your app -> Interval Server:
ACTION_COMPLETED('hello_user')
I/O methods
I/O methods provide an easy way to reason about what Interval Server can and cannot see in the context of a function running. Unless you're explicitly calling an I/O method inside of your action, Interval Server has no information about what code is being executed.
Input/output data passed to/from I/O methods is strictly transient by default. Under our default configuration, your Interval Server instance never logs or otherwise stores this data.
This highlights an important security property of Interval actions: your business logic lives in your codebase and is executed exclusively on your infrastructure. Interval Server is structurally designed so that it needs to know as little as possible.
Summary
Interval's hybrid architecture allows us to develop robust and always up-to-date interfaces for your tools while keeping your most sensitive information like business logic and secrets within your app's codebase.
Below is a quick reference table you can refer to which sums up the boundaries of this architecture:
Visible to Interval Server? | Logged or persisted by Interval Server? | |
---|---|---|
Names of actions | Yes | Yes |
Action state (running, returned, etc. ) | Yes | Yes |
Source code / business logic of Actions | No | N/A |
Environment information (secrets, etc.) | No | N/A |
inputs/outputs for `io` methods | Yes | No, by default. Opt-in optionally. |
Visible to Interval Server? | |
---|---|
Names of actions | Yes |
Action state (running, returned, etc. ) | Yes |
Source code / business logic of Actions | No |
Environment information (secrets, etc.) | No |
inputs/outputs for `io` methods | Yes |
Logged or persisted by Interval Server? | |
---|---|
Names of actions | Yes |
Action state (running, returned, etc. ) | Yes |
Source code / business logic of Actions | N/A |
Environment information (secrets, etc.) | N/A |
inputs/outputs for `io` methods | No, by default. Opt-in optionally. |