Skip to content

feat(plugins): install signed registry binaries - #728

Open
dviejokfs wants to merge 7 commits into
mainfrom
plugin-host-latest
Open

feat(plugins): install signed registry binaries#728
dviejokfs wants to merge 7 commits into
mainfrom
plugin-host-latest

Conversation

@dviejokfs

@dviejokfs dviejokfs commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Installs standalone plugin binaries from the signed registry.temps.sh catalogue.
  • Removes archive, npm, npx, bunx, and registry-entrypoint requirements from installation and runtime.
  • Selects the exact platform release, verifies its Ed25519-signed metadata, and streams the binary with SHA-256 verification.
  • Persists a monotonic registry revision before download or execution to prevent signed-catalogue rollback.
  • Stages immutable versioned candidates, completes the plugin handshake, and only then atomically activates the release.
  • Re-verifies the signed receipt and installed binary during startup discovery.
  • Requires System Administrator access plus recent sensitive-action verification, and audits the exact selected release before execution.
  • Reports full and partial reload failures without exposing filesystem paths, transport internals, plugin diagnostics, or credentials.
  • Hardens execution with a scrubbed environment, bounded protocol frames, withheld raw stderr, secure filesystem permissions, safe PID bookkeeping, and cleanup of every failed staging phase.

API

  • GET /x/plugins/catalog
  • POST /x/plugins/install with { "name": "plugin-name" }
  • GET /x/plugins/{name}/status
  • POST /x/plugins/reload returns 200 for full success, 207 for partial success, and 502 when all activated plugins fail.

Registry trust configuration

Temps accepts an operator-controlled Ed25519 trust anchor as a required pair:

temps serve \
  --plugin-registry-key-id temps-registry-2026-01 \
  --plugin-registry-public-key <64-hex-character-ed25519-public-key>

Equivalent environment variables are TEMPS_PLUGIN_REGISTRY_KEY_ID and TEMPS_PLUGIN_REGISTRY_PUBLIC_KEY. Missing trust remains visibly unconfigured and fails closed. Half-configured, malformed, empty, or non-32-byte anchors are rejected before server startup. The public key is never logged; the signing private key remains outside Temps.

Artifact model

The registry contains metadata and signed release identities. Each platform release resolves directly to one standalone executable:

<data-dir>/plugins/<name>/<version>-<unique-id>/plugin
<data-dir>/plugins/<name>/<version>-<unique-id>/receipt.json
<data-dir>/plugins/<name>/active.json
<data-dir>/plugins/registry-state.json

TypeScript plugins can be compiled into standalone binaries with Bun, and Rust plugins with Cargo. Temps only receives and runs the final executable.

Evidence

Plugin and CLI regression suites

cargo test --lib -p temps-external-plugins -p temps-cli
cargo test: 405 passed (2 suites, 3.09s)

Coverage includes trust configuration, authorization, signer errors, reload auditing, staging cleanup, receipt/binary tampering, handshake bounds, secret redaction, and lifecycle ordering. A composed protocol-v2 fixture proves signed download → Hello → launch configuration → Ready → authenticated Unix-socket WebSocket → activation/promotion. A rejected upgrade preserves the prior active record/process and removes its candidate directory.

Strict lint

cargo clippy --lib -p temps-external-plugins -p temps-cli -- -D warnings
cargo clippy: 0 errors, 3 workspace/dependency warnings

Full workspace library check

cargo check --lib
cargo build: 0 errors, 5 workspace/dependency warnings

cargo fmt --all -- --check and git diff --check also pass.

Security gate: APPROVED, with no remaining findings. Regression coverage proves that a private installation path and sentinel database credential do not reach RFC 7807 responses or serialized audit events.

Deployment dependency

https://registry.temps.sh/api/plugins must serve the signed catalogue envelope and direct binary artifacts. Operators must configure the corresponding published Ed25519 public key and key ID. The signing private key must never be stored in the Temps repository or runtime binary.

@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown

📓 Changelog preview

This is what your commits will add to the generated CHANGELOG.md at release time (via git-cliff). Do not edit CHANGELOG.md by hand — it is generated from your Conventional Commit messages.

## [Unreleased]

### Added

- **plugins:** Install signed registry binaries

### Fixed

- **plugins:** Close registry review findings
- **plugins:** Close registry merge blockers
- **plugins:** Gate management controls by role

### Testing

- **plugins:** Prove candidate process transitions
- **plugins:** Exercise protocol v2 install flow

@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown

Greptile Summary

The PR replaces legacy external-plugin installation with a signed registry binary flow and adds operator trust-anchor configuration, verified staging and activation, startup re-verification, protected management APIs, and permission-aware console controls.

  • Selects platform-specific signed releases and verifies metadata and binary digests.
  • Stages and handshakes candidates before atomic activation.
  • Re-verifies active installations during discovery and reload.
  • Adds catalog, installation, status, and reload API and console flows.
  • Aligns plugin process tracking with catalogue identity and gates management actions to administrators.

Confidence Score: 5/5

The PR appears safe to merge because the previously reported identity and administrator-gating failures are fixed and no blocking failure remains.

No blocking failure remains.

Important Files Changed

Filename Overview
crates/temps-external-plugins/src/catalog.rs Defines signed catalogue verification, platform release selection, trust-anchor parsing, and monotonic revision handling.
crates/temps-external-plugins/src/install.rs Implements streamed digest verification, secure staging, receipts, active-release verification, and atomic activation.
crates/temps-external-plugins/src/manager.rs Adds verified candidate startup and promotion while consistently indexing processes by validated catalogue identity.
crates/temps-external-plugins/src/service.rs Coordinates signed catalogue selection, installation, discovery, reload, and runtime-surface refresh.
crates/temps-external-plugins/src/handler.rs Exposes protected catalog, install, status, and reload endpoints with sensitive-action and audit integration.
crates/temps-cli/src/commands/serve/mod.rs Adds plugin-registry trust-anchor options and validates the paired configuration during server bootstrap.
web/src/pages/settings/PluginsPage.tsx Adds plugin catalogue, install, status, and reload controls while correctly restricting management actions to administrator roles.
web/src/hooks/usePlugins.ts Adds typed query and mutation hooks for plugin management and supports disabling the admin-only catalogue query.

Sequence Diagram

sequenceDiagram
    participant A as Administrator
    participant T as Temps
    participant R as Signed registry
    participant P as Plugin candidate
    A->>T: Install plugin
    T->>T: Check SystemAdmin and recent verification
    T->>R: Fetch signed catalogue
    T->>T: Verify signature and monotonic revision
    T->>R: Stream selected platform binary
    T->>T: Verify SHA-256 and stage candidate
    T->>P: Start candidate
    P-->>T: Hello and manifest
    T->>T: Validate catalogue identity
    T->>P: Launch configuration
    P-->>T: Ready
    T->>T: Atomically activate release
    T-->>A: Installation status
Loading

Reviews (14): Last reviewed commit: "chore(plugins): merge main and resolve c..." | Re-trigger Greptile

Comment thread crates/temps-external-plugins/src/handler.rs Outdated
Comment thread web/src/pages/settings/PluginsPage.tsx Outdated
@dviejokfs dviejokfs changed the title feat(plugins): host and install VibeTemps as an external plugin feat(plugins): generic external plugin registry, install flow, and deep-linked routing Aug 19, 2026
Comment thread crates/temps-external-plugins/src/handler.rs Outdated
@dviejokfs

Copy link
Copy Markdown
Contributor Author

Manifest identity breaks process tracking — if the registry manifest declares a name different from KNOWN_PLUGINS.name, installation starts a process indexed under the manifest-declared name while status and reload operations query known.name.

Confirmed and fixed in 2311cab8d.

Worth separating the two halves, because the first was already addressed and the second is the real one:

Which name we look up. start_or_reload_plugin previously passed the registry manifest's name. That put the reload key under remote control — a manifest declaring another plugin's name would reload that plugin instead. Changed to the compile-time known.name earlier in this PR.

Which name the process is actually filed under. This is the finding, and switching to known.name did not close it. start_plugin inserts at manager.rs:839 using result_manifest.name — the name the running binary declares over the handshake, which is neither known.name nor the registry manifest. Nothing verified those agree, so exactly the failure described was reachable: install returns 200, is_running(known.name) is false forever so status reports "not installed", and the next install takes the fresh-start branch and spawns a second process on top of the first.

The fix verifies the started plugin's declared identity and, on a mismatch, shuts the process down via the name it actually registered under — otherwise refusing the install would leave precisely the orphan the check exists to prevent — then fails with a message naming both identities so the operator knows which side to correct.

The rule is extracted into identity_mismatch and unit-tested (match, mismatch, and near-miss casing/whitespace, since the process map is a plain HashMap lookup where "VibeTemps" is a different key). There's no harness that can start a real plugin — it needs a binary speaking the socket protocol — so the pure rule is the testable part; the shutdown-and-refuse path around it is verified by compile and review only.

Flagging one thing you didn't: this is the second bug from the same identity conflation in this code path. The original was binary-filename vs manifest-name; this is declared vs locally-known. Both were silent — everything reports success while the plugin is unreachable — which is why the check now fails loudly rather than warning.

Comment thread crates/temps-external-plugins/src/service.rs Outdated
@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown

Want your agent to iterate on Greptile's feedback? Try greploops.

Replace archive and package-manager installation with bounded direct binary downloads authenticated by an Ed25519-signed registry. Persist revision rollback protection, verify the exact installed executable, stage candidates before activation, scrub process secrets, and audit sensitive install outcomes.

Signed-off-by: David Viejo <dviejo@kfs.es>
@dviejokfs dviejokfs changed the title feat(plugins): generic external plugin registry, install flow, and deep-linked routing feat(plugins): install signed registry binaries Sep 7, 2026
Wire operator-controlled registry trust into the shipped CLI, preserve reload failures through the API and audit trail, sanitize public diagnostics, and clean every failed staging path. Add regression coverage for trust parsing, authorization, receipt tampering, handshake bounds, secret disclosure, and lifecycle ordering.

Signed-off-by: David Viejo <dviejo@kfs.es>
Exercise promotion and discard with real child processes so rollback behavior proves old processes are reaped, accepted candidates remain active, and rejected candidates never enter the process table.

Signed-off-by: David Viejo <dviejo@kfs.es>
Use a real Unix-socket WebSocket fixture to prove signed download, staged handshake, authenticated channel setup, activation, and promotion. Verify a rejected upgrade preserves the active record and running process while removing its candidate directory.

Signed-off-by: David Viejo <dviejo@kfs.es>
Signed-off-by: David Viejo <dviejo@kfs.es>
Comment thread web/src/pages/settings/PluginsPage.tsx
Signed-off-by: David Viejo <dviejo@kfs.es>
Signed-off-by: David Viejo <dviejo@kfs.es>
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