Skip to content

gateway v0.3.0

Choose a tag to compare

@kikashy kikashy released this 24 Sep 01:48
627e610

Third release of the attested-input gateway: 64 commits since v0.2.0 that turn a service whose only source was a hand-written script into an engine. The receipt has a version 3; the adapters module beside the standard-library gateway holds the sources; a fifth process speaks MCP; an engine image carries all of it; two workflow-tool plugins and a second, TypeScript implementation of the verifier answer to the same frozen corpus; documents are read into signed attachment records; and gateway-owned connections reach Google Drive, Gmail, Notion, Obsidian, public HTTPS pages and Amazon S3. Eight of the pull requests are from two external contributors.

The receipt, version 3

SPEC.md §1.2a (#101) specifies the version 3 receipt: an acquisition record, commitments over the arguments under a fresh salt that is returned to the caller and never retained, the identity of the caller the engine proved, and action receipts. What a receipt signed before the change means afterwards is exactly what it meant before: a version 3 verifier verifies a version 2 store unchanged, the seal is the same record under both versions, and a verifier that knows only version 2 refuses a version 3 receipt. verify reads the version 3 vectors (#102); serve mints version 3 by default and version 2 on request (#103). Adapter sources report their acquisition in the result envelope (#104, ADR-0002); a decision record's own citations are resolved from the record's side (#112) and the golden record is checked both ways, history and live facts agreeing on the postgres platform (#116). Seals hold across a restart: /acquire consults the registry for a session it does not hold (#122). A validly signed seal counting below zero is a seal (#137).

One engine, four processes — then five

ADR-0001 (#97) adds the adapters/ module beside the gateway and the boundary it lives under. serve starts a source with a declared environment, an optional distinct user and a bounded output, and refuses a readable seed (#100); serve --config names the platforms an engine serves and refuses what the isolation claim does not survive (#107); connect writes a platform entry only after the platform answered (#108, #109). identity decides who may call, from a key set the operator holds and reads once at start, and the receipt names the caller it proved (#110). A write goes through the engine as an action, refused unless its judgment is there (#114). Three adapters: adapter-airbyte, one page of one stream from a pinned connector image (#105); adapter-mcp, one tool call on a vendor's MCP server over stdio (#106); adapter-http, one request over TLS to an endpoint the operator fixed (#117). The engine image (#111, #113, #115) builds both modules, the catalog and the corpus on a distroless static base with no shell and no libc, pinned by digest, with the runtime carried at its release.

ADR-0003 (#120, #121) adds the fifth process: gateway mcp, a client of the signer's HTTP surface and nothing more, so an MCP client calls a platform's live tools through the engine and the receipt rides with the answer. Tool descriptors are captured at connect, pinned, and served verified from the MCP server (#124, #126–#128).

/acquire bodies are bounded by --max-request and each source by --source-timeout (#135), and /acquire, /act and /seal read their envelope by exact member names, given once: {"session":"sealme","SESSION":"keepme"} no longer seals keepme (#147).

Plugins, and a second implementation

An n8n node and an Activepieces piece reach the engine from workflow tools (#118), each run the way its ecosystem runs it against a live engine (#119) and held to its refusals against a stand-in (#123); the n8n node is published from GitHub Actions (#130). verify-ts/ (#129) is a second implementation of the attestation format — canonical form and registry-anchored verification of receipt versions 2 and 3 — answering to the frozen corpus, with a CI job that checks both implementations agree.

Documents

ADR-0004 (#133) decides that documents are an adapter under the command shape, writing a version 1 attachment record. adapter-document (#134) reads an attached text file, normalized, or a PDF, for page text, with OCR delegated to an operator-supplied executable when asked. #134 landed with its last fixes reviewed by a model of the drafting vendor's own, under a one-time exception, with a different-vendor follow-up owed; that follow-up ran over #134 and #135 together and reproduced 24 defects, every blocker and major reproduced a second time by the maintainer before it was accepted. They are fixed in #145 (the record reads what the page shows), #146 (a bound the reader states is a bound it holds), #147 (the envelope above), and #150 (six further review rounds over #145's area: object-stream headers read no further than a bound, encodings established by ranges of one length, and a scan the reader could not finish leaving no reading publishable). #146's seventh round, run after its merge, found one bound still not held — an array charged less than the room append grows it to, so a small file held 66.8 MiB of operand against the stated 64 — fixed in #152, where an array is charged the capacity it grows to, before it grows, including the moment the old and new backing arrays are both held. The same round's findings on the request read are fixed in #153: an exhausted arbitration refuses the request, and the wait for an on-time result is tested as the adapter's own receive. #154 makes the document adapter's race-detector run green: a data race between tests, wall-clock allowances and test deadlines scaled under the detector, and the deadline-cut opening measured against the one pass over the file it cannot interrupt. That last pass is issue #155.

Connections

gateway-connections owns app registration, consent, tokens, refresh and revocation, and hands the adapters single-use grants. Google Drive files selected through Google's own Picker (#139); read-only Gmail message exports, with no sending or mailbox mutation (#140); publisher Google OAuth registration in local bundles (#141), public distributions being unregistered (#142). Notion pages through bounded hosted MCP OAuth, and Obsidian notes under a confined vault root (#143). gateway-connections --catalog lists what a companion implements without opening account state (#144), and catalog v3 describes connection UI and source protocols so a host can use a new provider without a release of its own (#149). adapter-web retains a bounded snapshot of one explicitly selected public HTTPS page, text file or PDF, validating the public address on every DNS answer and redirect (#148). Amazon S3 files from one bucket and prefix, under explicit credentials and the official SigV4 signer, four selections of 4 MiB each; live AWS acceptance remains pending (#151).

Hardening and tests from contributors

Verification refuses a store root that is not a directory (#79) and a registry path that cannot be read (#84), and the spec states the verdict for an absent store root (#92). Contributors pinned argumentsDigest's keyed commitment (#76) and argumentsKey's derivation against a byte-literal digest (#94), that gateway conform exits non-zero on disagreements (#96), the method contract of /acquire and /seal (#85), that /acquire refuses non-canonical arguments before the source runs (#86), and that every loadSeals drop row has exactly one obstacle (#80). A test binary committed by mistake is removed and ignored (#136), and a bound test is allowed what the connection buffers (#125).

Documentation

Five decision records (ADR-0000 to ADR-0004) and eighteen design notes under docs/design/, from the receipt to each connection.

The frozen corpus grew with version 3: 30 canon vectors, 21 store vectors for version 2 and 20 for version 3, and gateway conform reports 0 disagreements on the tagged source.