How a plug-in runs
On this page (7)
Kanboombo's Server runs your folder on your schedule, in your time zone, for as long as a person's approval holds. A plug-in is built to be unable to do harm, not trusted not to: a reviewer reads every host it may reach, nothing can leave its room, and the same files always give the same records. The cost: no signing in to an API or paging through one; a source is a file at an address you can write down ahead.
When a run is due
Nothing runs until a person approves one exact version of your code, its digest; before every run the Server hashes your files again, and runs nothing that is not approved. Each minute it asks which plug-ins are due: a time your schedule allows has passed since the last attempt, on your zone's clock (Harbour Almanac's 15 6,18 * * * is shown as "Every day at 06:15 and 18:15, Auckland"). Missed times run once. Approve, Resume and the first run start at once. A failed run is tried again thirty minutes later, then waits for its next time. Runs go one at a time, never beside a deploy, so a due run may wait its turn.
The downloads
Your code never touches the network. Before it starts, Kanboombo downloads each declared source in order, with {today}, {year} and {month} filled:
- •https only, no name or password in the address, to a host your sources name (links.hosts is for item links, not downloads);
- •public addresses only: every address the name resolves to is checked, loopback, private, link-local, shared, multicast and reserved ones are refused, and the connection goes to the checked address and nowhere else;
- •at most five redirects, each to your sources' hosts, checked again;
- •a 200 of at most maxBytes (never over 20 MB) within 60 seconds, kept only when whole.
Each request says Kanboombo plug-ins (+https://kanboombo.com). One failed download fails the run (Could not download tides: …), and nothing is written.
The locked room
Your fetcher runs as node fetch.mjs in a room the operating system builds for one run: a throwaway user owning nothing; a network of its own that reaches nothing, with no internet socket; an empty root holding, read only, your approved files at /plugin, the downloads at /sources/<name> and Node, plus a private temporary folder. Only files the digest covers are copied in (with node_modules/ when a package-lock.json made it), so fixtures and READMEs cannot be imported. There is no database, key or secret: the environment is LANG=C.UTF-8 and what the system always sets (PATH, USER).
It stops at 120 seconds (or your lower limits.seconds) and 256 MB (a lower limits.megabytes is not yet enforced here), with at most 32 tasks and 64 MB of output, and only the system calls a service needs. Node's permission model reads only your code and sources, writes only the temporary folder, and allows no child process, worker, native addon or WASI. When the run ends, its code, downloads, output and context are deleted.
It sees only the run context: never who installed or reads it, nor how many, nothing of any account or anyone's days, no key, token or Server address. It runs once for all readers.
The write
Every line is checked against the approved manifest, and one bad line refuses the batch (Records); a batch that passes is written in one transaction. Each run is kept with its version, digest, Node version, times, counts and sources; the host shows the last five.
When a run fails
A download fails, your fetcher exits non-zero, runs past its time or memory, prints over 64 MB, or the batch breaks a rule. Nothing is written and stored records stay. The reason, at most 300 characters, is kept: your last stderr line (or the error, never its stack), a sentence such as It ran past its 30 s limit and was stopped., or the broken rule and line. The plug-in shows Failing at the host, readers see Couldn't refresh after your newest record, and the next success clears it. So when your source is not what you expect, exit 2 with one plain line: a failed run beats wrong records.
Exit 0 with nothing printed only when your source truly has nothing. An empty batch is a success, and for a series with a snapshot window it says every stored record in the window has gone.
No personal data
A record is shown to every reader and kept for years, so it holds no personal data: no private person's name, email, telephone or identity number, nothing that identifies someone who has not chosen to be public. Leave such columns out even when your source publishes them; your organization states this for every version.
Kanboombo's own sections
Sections marked Official in the store are Kanboombo's own code, run outside the locked room with the network and keys they need, each listing saying what it reaches; none of this is relaxed for yours. DOP Economy is held to all of it.