Bridges
What every bridge out of an agent's sandbox speaks, through
link-bridge.
Bridges (link-bridge)
The contract is
link-bridge,
which link_bridge is, with this machine's keyring beside it
(Agent Binding). A bridge is a way out of an agent's
sandbox beside its network: the way in, a linked connection's
send.sock, the store bridge and the files bridge (Files
Bridge), and each of its
proxy's routes (Interface).
Each takes calls on a Unix socket, one call to a connection.
1. The challenge
The bridge writes {"challenge"}, 64 random hex characters, as a line
of JSON (link_bridge::Challenge).
2. Who calls
The caller writes who it is, a line of at most 4 KiB,
link_bridge::Proven: {"identity": {"agent", "owner"}, "proof"}, the
agent's ID and owner (link_bridge::Identity, each 1 to 64 letters,
digits, ., _, - and @), within 5 seconds of the challenge
(link_bridge::PROOF_WAIT), the whole exchange.
Its proof
HMAC-SHA256, keyed with the agent's key, of link bridge proof, a zero
byte, the challenge, a zero byte, the agent's ID, a zero byte and its
owner, in hex (link_bridge::proof).
Its action
Then its action, the bridge's own, as a line of its own, of at most what
the bridge takes (link_bridge::CALL_MAX, 48 MiB, at the most: a
store's event twice over and a files bridge's largest object as
base64).
3. The answer
The bridge looks the agent's key up (link_bridge::Keys) and refuses a
call whose agent isn't bound or whose proof isn't that agent's before
it reads the action; it takes the caller as its ID and owner alone,
never teams it names. It answers with a line, its own or the error
envelope, then closes the connection.
The error envelope
link_bridge::Failure, {"error": "<why>"}, with "why" when a caller
acts on it: refused (nothing done: who's calling isn't proved, or what
it sent isn't a call the bridge reads), busy (nothing done: call
again), conflict (nothing done: what the call expected isn't so any
more). A bridge's own answers never hold error.
A stream call
A stream call (link_bridge::stream, served by serve_streams) is for
a bridge whose answer is bytes as they come, a route's: steps 1 and 2
as above, then the caller sends what the call carries (a request's
body) as it comes, without waiting. The bridge answers one line, its
verdict (its own, or the error envelope), then its answer as it comes,
writing nothing before the verdict. Either side ends it by closing.
What it reaches of another's
A proved call reaches only its own agent's things, unless a role lets
it reach another's: a teammate's way in, or a team's folder. Whether
it may is link_iam::allows's to say, never the bridge's
(Who May Do What).
The bridge gives link_bridge::grants the proved identity and the
roles it reads at that very call, such as each team's role, and asks
for the action on the resource: agent.message on agent:<id>, or
bucket.write on bucket:team-<id>/drafts/.
The server
Every bridge runs on one server (link_bridge::serve, or serve_with
for one whose answers are async).
Before the proof
Connections not yet proved hold places of their own, 4 of each peer's,
the user at the other end (link_bridge::PEER_PROVING), a peer's next
closing its own oldest, answered busy, with room for 16 peers
(link_bridge::PEERS, 64 in all, PROVING), past which a new peer's is
answered busy.
A proved call
A proved call holds one of the bridge's places, one of its agent's and
one of its owner's, and is answered busy past any. Its action arrives
within the bridge's wait, and its answer is taken within another
(link_bridge::Limits, each bridge's own). take_async reads a call's
action within 30 seconds (link_bridge::CALL_WAIT).
A caller's side
link_bridge::call and call_at are a caller's side; take and
take_async, one call taken by a program that takes its calls itself,
with the same deadline before the proof.
The test every bridge passes
Every bridge's tests run link_bridge::conformance::check (the
conformance feature) against it, listening: a wrong key, a proof
replayed on a new connection, a malformed or overlong Proven, an
action it can't read, that none of those runs, a caller that never
answers or answers a byte at a time, an action sent a byte at a time, a
peer's flood, one agent's calls past its places and everyone's past the
bridge's, an answer never taken, and the envelope.