Skip to content

feat(extension): ship the token extension in the catalog, resolved from its signed release#392

Open
ion-alpha-dev wants to merge 2 commits into
mainfrom
feat/catalog-token-extension
Open

feat(extension): ship the token extension in the catalog, resolved from its signed release#392
ion-alpha-dev wants to merge 2 commits into
mainfrom
feat/catalog-token-extension

Conversation

@ion-alpha-dev

Copy link
Copy Markdown
Collaborator

What

Bundles the token extension as a catalog spec whose process surface names its published release, and syncs the catalog in the extensions runtime. flynn extensions ls lists it next to the API integrations, and flynn extensions call token token_verify ... resolves it through the signed-release path: download, prove the origin, launch confined, speak MCP, call the tool.

The catalog also now refuses to load a bundled process extension that carries a dev (unsigned, local) source, or a release that names no asset or version. The build-time gate validates every shipped process surface.

Why

The release resolver could already prove a published extension's origin, but nothing could ask it to. The only route into the store was extensions dev, which links a local unsigned binary by path, so no signed release could ever become a running tool. This closes that gap and makes the first official extension reachable from a stock binary.

A bundled spec ships inside the binary under a reserved name, so it must run signed code and nothing else. That is now an invariant the catalog enforces at load, not a convention.

The spec grants no egress: the extension process reaches nothing. It reads the chain by handing request bytes back to the host, which holds the endpoint, so without a host grant the call is refused rather than served.

How to verify

go test ./extension/... ./cmd/flynn/
go build -o flynn ./cmd/flynn

./flynn extensions ls
# token   bundled   yes   token.read,token.mint

./flynn extensions call token token_verify '{"mint":"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"}' \
  --endpoint https://api.devnet.solana.com
# mint 4zMM...: supply=16295256264886214240 decimals=6 mintAuthorityRevoked=false freezeAbsent=false

The first call downloads and verifies the release (about 4s); the second reuses the receipted install (about 0.2s). Dropping --endpoint refuses the call with extension_fetch_ungranted, proving the process has no network of its own.

…om its signed release

The release resolver could prove a published extension's origin, but nothing could
ask it to: the only way an extension reached the store was `extensions dev`, which
links a local, unsigned binary by path. There was no route from a signed release to a
running tool.

Bundle the token extension as a catalog spec whose process surface names its published
release (asset and version), and sync the catalog in the extensions runtime. `flynn
extensions ls` now lists it alongside the API integrations, and `flynn extensions call
token token_verify ...` downloads the release, proves it was signed by the pinned
release identity, launches it confined, speaks MCP to it, and calls the tool. The
verified install is cached with its receipt, so a second call re-checks the recorded
digests instead of going back to the network.

The spec grants no egress, so the extension process reaches nothing: it reads the chain
by handing request bytes back to the host, which holds the endpoint. Without a host
grant the call is refused rather than served.

A bundled spec ships inside the binary under a reserved name, so it must run signed
code and only signed code. The catalog now refuses to load a bundled process extension
that carries a dev source, or a release that names no asset or version, and the
build-time gate validates every shipped process surface.
@ion-alpha-dev ion-alpha-dev force-pushed the feat/catalog-token-extension branch from 51648c6 to acd7efd Compare July 12, 2026 17:07
…rsion string

A release source named an asset and a version, and the resolver trusted the
signature over the release's checksums. That proves the pinned workflow built
what it downloaded. It does not prove the download is the artifact this flynn
was built to run.

Git tags are mutable. Whoever can write to the extensions repository can
delete a released tag, re-cut it against different code, and publish it
through the very same trusted release workflow. The new binary then carries a
perfectly valid signature from the pinned identity, and every flynn in the
world fetches it and runs it, because the signature only ever attested to who
built the artifact, never to which artifact was reviewed.

A release source may now carry the expected archive digest per platform. The
resolver refuses anything whose bytes do not match, even when the signature
verifies, and a cached install of the wrong bytes is re-downloaded rather than
reused, so the cache cannot become the bypass. The hash is compiled into the
binary before any such substitution exists, which is what makes the pin hold
against an attacker who owns the repository, the tag and the release pipeline.

A platform absent from the map stays on signature-only trust, so a spec can
pin the platforms it has hashes for without breaking the rest.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant