Skip to content

feat(agents): delegate gateway keys for remote agent access - #154

Draft
tee8z wants to merge 6 commits into
mainfrom
tee8z/agent-gateway-key
Draft

tee8z wants to merge 6 commits into
mainfrom
tee8z/agent-gateway-key

Conversation

@tee8z

@tee8z tee8z commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Problem and behavior

Paseo needs to drive a developer's remote agents without holding the developer's main Nostr key. An owner can now grant a separate key scoped agent access, expire it within 90 days, and revoke it with a durable replacement head.

sequenceDiagram
    participant Owner
    participant Relay
    participant Gateway
    participant Agent
    Owner->>Relay: Signed expiring kind30181 grant
    Gateway->>Relay: Signed prompt mentioning owner's agent
    Agent->>Relay: Read current authority from writer
    Agent->>Relay: Separately encrypted observer copies
    Owner->>Relay: Newer disabled head
    Agent->>Relay: Refresh authority within 30s cache lifetime
    Agent->>Agent: Refuse further gateway use
Loading
Path Checks
Mention launch Owner grant, registered owner/agent binding, current posting membership and trigger
Thread prompt Bound channel thread in strict owner mode; authority checked at ingress and queued dispatch
Cancellation Fresh signed NIP-44 control; gateway command exactly cancel_turn
Telemetry Relay verifies agent ownership and grant; harness checks current channel membership before separately encrypted copies
Owner DMs, profile, administration and model settings No delegated authority

A gateway is a separate ordinary relay member. Relay and channel membership must be granted explicitly. Normal own-account messages and ordinary gateway-owned workflows remain permitted in joined channels. Another owner’s workflow definitions stay protected; call_webhook retains its existing owner/admin requirement.

The SDK verifies the owner signature, scope, newest head, expiration, and agent/gateway separation. It caps live gateways at two. Revocation is a disabled head without expiration; NIP-09 deletion cannot erase it and reopen an old grant. Authority reads use consistency:strong over HTTP and WebSocket REQ so replicas cannot extend stale authority. The WebSocket extension preserves default routing for existing filters and rejects malformed consistency values.

Current channel membership is independent of the grant: the owner, agent and gateway must all be posting members of the bound channel. These checks use a relay-signed kind39002 roster. A narrowly scoped strong roster read reconciles stale discovery state from canonical writer membership under the existing lock. It authorizes the current reader before repair, propagates failures, and emits no fan-out. Removed gateway membership therefore stops prompts, cancellation and observer copies within the same bounded cache lifetime.

The CLI adds buzz gateway grant <pubkey> --expires 90d, list, and revoke. Grant management rejects agent credentials and advances timestamps for same-second replacements. Gateway documentation covers threats, memberships, failure behavior and rollout.

Validation

  • Full library suites: core289, SDK348, CLI505 and ACP1130 passed; ACP3 existing ignored tests.
  • Reaper package:143 passed,3 ignored. Its gateway launch journey covers grant, use and revocation.
  • Postgres observer integration passed against the local database: grant, telemetry/control, other-owner refusal, agent-key refusal, revocation and replay protection.
  • New factory regression passed: DM and unbound harnesses never enable gateway telemetry or control.
  • Six representative guard mutations failed assertions: expiration, newest-head ordering, owner-only CLI credentials, gateway cancel-only control, DM/unbound session isolation and channel membership. Sources were restored.
  • Formatting, Dart constant formatting, file-size gate and diff checks passed.
  • Final targeted clippy passed for core, SDK, CLI, ACP, reaper and relay with all targets and warnings denied. Focused gateway tests passed: ACP7, SDK7, launcher2 and CLI1. The membership journeys cover grant without membership, join, removal, restoration and revocation.
  • Protocol13 passed. The real two-database fixture proves default reads can miss a writer-only event while strong HTTP and WebSocket reads see it.
  • Strengthened Postgres replay tests passed for both e-tag and a-tag deletion attempts, using never-before-submitted older grants and cleared verdict caches.
  • The real Postgres roster regression passed: a committed membership removal with a stale stored discovery event is repaired for an authorized reader; removed and unrelated readers cannot read or repair it; repeated reads preserve the event ID; database failure propagates.
  • Repository-wide just ci, the complete integration gate and human acceptance remain pending. This PR stays draft.

Rollout and limits

Deploy the relay before new manager or agent binaries. Then deploy the matching manager and harness image, admit the gateway into the relay and desired channels, and grant it with the owner key. Existing owner-only Buzz app flows continue unchanged. No schema migration or cluster change is included.

#150 provisions the gateway Secret and returns gateway_pubkey. #149 consumes it from the bridge. #152 prints the explicit grant and membership steps until its SDK boundary is wired.

Explicit checkpoint/fresh recovery requests remain agent/owner controlled. Gateways cannot change models or publish owner announcements. Revocation does not cancel an already-running model turn. Observer telemetry remains ephemeral.

Human acceptance: admit a test gateway, grant it, mention one owned agent and confirm one sandbox starts. Verify telemetry and cancellation, remove its channel membership and confirm both stop after the cache window, then restore membership. Revoke, wait for the 30s cache window, and confirm prompts/control fail while the owner's key still works. Check an unrelated owner's agent and owner DM remain inaccessible through the grant.

Let owners delegate an expiring, revocable key without sharing their main identity. Recheck authority for launch, prompts, cancellation and observer telemetry, and pin authority reads to the writer. Keep direct messages and owner administration outside the grant.

Signed-off-by: Tee8z <tee8z@protonmail.com>
@tee8z tee8z self-assigned this Nov 10, 2026
@coderabbitai

coderabbitai Bot commented Nov 10, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Signed-off-by: Tee8z <tee8z@protonmail.com>
Signed-off-by: Tee8z <tee8z@protonmail.com>
Signed-off-by: Tee8z <tee8z@protonmail.com>
@tee8z

tee8z commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

Independent agent review of the gateway change, including the final canonical roster repair and constrained-filter follow-up c9e40df.

Previously identified blockers are resolved: grant/profile/roster authority reads request the writer; telemetry and cancellation require current channel membership; a failed discovery publication cannot preserve revoked membership; revocation remains a durable disabled head. The narrow roster path checks canonical reader membership before writing, repairs under the existing writer lock without fan-out, and leaves ordinary constrained/history filters on their original path.

Validation includes the real PostgreSQL regression for stale projection removal, removed/stranger readers, unchanged-head stability, extra-filter no-repair behavior, and propagated database failure. ACP/reaper grant and membership guard regressions and the two-database routing evidence were also reviewed. No remaining correctness or security blockers found. Minimalism 9/10, elegance 9/10, correctness 9/10.

Human acceptance and the repository-wide native checks remain outstanding. This comment does not attest buzz-review-completed or approve deployment.

Signed-off-by: Tee8z <tee8z@protonmail.com>
Signed-off-by: Tee8z <tee8z@protonmail.com>

This branch has not been deployed

No deployments
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