Developer tools

Developer tools

Extensions

Programs that iohr installs from an OCI registry, verifies, pins and runs, without handing them your long-lived credentials.

An extension is a separate program with its own release cycle that iohr installs, verifies, pins and runs. The first one is the agent. The design is RFC 0028; the decision in the SDK repository is ADR 0012.

iohr ext install agent          # the newest release; or [email protected]
iohr ext list                   # what is installed, with its digest and signer
iohr agent status               # iohr <name> … runs the installed program
CommandWhat it does
iohr ext install NAME[@VERSION] [--lock FILE]Fetch, verify and install one (NAME@sha256:DIGEST pins a digest); --lock also pins it in a lock file
iohr ext listThe installed extensions, their digests and who signed them
iohr ext upgrade [NAME] [--lock FILE]Install the newest release of one, or of every installed one; nothing updates by itself
iohr ext remove NAME [--lock FILE]Remove one from this machine (and from the lock file)
iohr ext verify [NAME]Check again offline: the program's hash, the bundles kept at install, the pinned signer
iohr ext sync [--lock FILE]Install exactly what a lock file pins, by digest and signer (default iohr-ext.lock)

What install checks

Nothing is written to disk until every check passes, and no flag skips them:

  1. The index and this platform's manifest match their SHA-256 digests (and the digest in the lock, for iohr ext sync).
  2. A signature and SLSA v1 build provenance, both Sigstore bundles attached to the artifact, both from InOrbit's release.yml workflow at a tag, checked offline against the Sigstore trusted root built into iohr.
  3. The manifest: the name and version asked for, an entrypoint that stays inside the extension, scopes written as resource:action.
  4. The layer matches its digest and size; only the entrypoint is taken from it.

Install prints who signed it and the API scopes it may ask for. Every run re-hashes the program first.

Pinning

What is installed is pinned in iohr-ext.lock. To pin a project's extensions in its repository and install the same digests on another machine or in CI:

iohr ext install agent --lock iohr-ext.lock
git add iohr-ext.lock
iohr ext sync                          # elsewhere: reads ./iohr-ext.lock

Credentials

A running extension never sees your refresh token or the credential store. It asks iohr for an access token over a private socket (IOHR_EXT_TOKEN_SOCKET, mode 0600), only for scopes its manifest declares; IOHR_EXT_API is the API's address. Until the platform can mint narrower tokens, the token handed out is the profile's own 15-minute access token, and only when it holds every scope asked for.

From a company's mirror

Extensions are OCI artifacts at ghcr.io/inorbithr/iohr-ext/<name>:<version>, one manifest per platform (Linux, macOS and Windows on x86-64 and arm64). A mirror that copies them with their referrers (oras cp -r) needs nothing else; point every machine at it once:

iohr config set ext.registry registry.example.com/inorbit/iohr-ext

A mirror that re-signs what it admits adds its public key, and its signature then passes too:

iohr config set ext.trusted_keys mirror.pub
iohr config get ext.trusted_keys       # prints their fingerprints

A mirror that needs a login reads IOHR_EXT_REGISTRY_AUTH=user:password from the environment; it is never a flag.

Checking by hand

With crane, cosign 3 and the GitHub CLI:

ref=ghcr.io/inorbithr/iohr-ext/agent
digest=$(crane digest "$ref:0.1.0-alpha.7")    # compare with the digest in iohr-ext.lock

cosign verify "$ref@$digest" \
  --certificate-identity-regexp '^https://github\.com/inorbithr/[^/]+/\.github/workflows/release\.yml@refs/tags/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

gh attestation verify "oci://$ref@$digest" --owner inorbithr \
  --predicate-type https://slsa.dev/provenance/v1

What is not checked: whether the release workflow's code is what you expect (the provenance names the repository, workflow and tag for you to read), and revocation (Sigstore has none; a compromised release is answered with a new release and an advisory). The SDK repository's verifying extensions has the full rules.