Skip to content

feat(gateway): verification hardening + docs consolidation (post-#487)#488

Merged
raahulrahl merged 6 commits intomainfrom
feat/gateway-recipes
Apr 20, 2026
Merged

feat(gateway): verification hardening + docs consolidation (post-#487)#488
raahulrahl merged 6 commits intomainfrom
feat/gateway-recipes

Conversation

@raahulrahl
Copy link
Copy Markdown
Contributor

@raahulrahl raahulrahl commented Apr 20, 2026

Summary

6 commits that landed on feat/gateway-recipes after #487 merged. They tighten the signature-verification pipeline end-to-end and reorganize the docs to match the repo-wide layout.

Two 🔴 high-severity bugs from bugs/known-issues.md are now marked RESOLVED (vacuous-yes envelope + AgentCard dead-code fallback). One 🟠 medium bug also resolved (SSE agent_did doesn't surface observed DIDs). 15 new entries added for things the work surfaced.

What's in it

Commit What
334066c docs: add BUGS_AND_KNOWN_ISSUES.md — 20-entry registry (later consolidated)
2a3ff15 fix: detect-secrets pragma on sample DID signature — unblocks CI
b0c0b8a fix: split verified="yes" into yes/unsigned — no more vacuous pass
d540ef2 feat: fetch AgentCard on first contact — activate DID fallback
8681d48 feat: surface observed DIDs in SSE with provenance
aaeb431 docs: consolidate — bugs/known-issues.md absorbs gateway issues

Key behavior changes

  1. <remote_content verified="..."> is now four-valuedyes, no, unsigned (new), unknown. The planner LLM can distinguish a real crypto pass from "nothing was signed."
  2. trust.verifyDID: true without pinnedDID is a real feature — gateway fetches /.well-known/agent.json at first contact, verifies artifacts against the observed DID's public key.
  3. SSE agent_did + new agent_did_source fieldpinned | observed | null provenance on every task.started / task.artifact / task.finished frame. Consumers can apply their own trust policy.
  4. CI unblocked — detect-secrets false positive on the sample DID signature in docs/openapi.yaml:598 silenced with the standard # pragma: allowlist secret.

Docs reorganization (final commit)

  • gateway/docs/STORY.mddocs/GATEWAY.md (matches repo-wide docs/ layout alongside AUTHENTICATION.md, PAYMENT.md, etc.)
  • gateway/docs/BUGS_AND_KNOWN_ISSUES.md → merged into bugs/known-issues.md (single user-facing registry)
  • gateway/docs/ directory deleted.
  • 8 internal links in docs/GATEWAY.md + 6 cross-refs in gateway/README.md and fleet README updated.
  • All links resolve cleanly; link-check script in commit body.

Test plan

  • cd gateway && npm run typecheck — clean
  • cd gateway && npm test216/216 pass (up from 185 at Feat/gateway recipes #487 merge: +7 verified-label, +9 agent-card-fetch, +6 find-agent-did)
  • npx redocly lint gateway/openapi.yaml — 0 errors, same 13 benign warnings
  • Link integrity check across docs/GATEWAY.md, gateway/README.md, examples/gateway_test_fleet/README.md, bugs/known-issues.md — all local links resolve
  • Manual curl verification: trust.verifyDID: true + pinnedDID returns verified="yes" with populated signatures counts in the real running stack
  • CI green on this PR (pending merge check)

Notes

  • Pre-existing uncommitted changes on the working tree (M README.md, M examples/medical_agent/medical_agent.py, ?? assets/*.png, ?? openapi.yaml) are not part of this PR — surgical staging used throughout.
  • bugs/known-issues.md gateway counts updated: 3 high · 15 medium · 19 low · 9 nit. Two existing entries narrowed to reflect partial resolutions (tool-name-collisions-silentparse-agent-from-tool-greedy-mismatch; signature-verification-ok-when-unsignedsignature-verification-non-text-parts-unverified).

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added agent card discovery from peers to improve agent identification and DID resolution
    • SSE event payloads now include agent DID source information (pinned, observed, or unavailable)
  • Improvements

    • Verification status reporting now distinguishes four states: verified, unverified, unsigned, or unknown
  • Documentation

    • Updated documentation links and known issues catalog with new Gateway issues and corrected references

raahulrahl and others added 6 commits April 20, 2026 16:31
…his session

Living list of concrete, file-path-grounded defects and gaps. 20 entries
across 5 categories (security/correctness, reliability/observability,
recipes, fleet/DX, API surface, tests, docs). Severity-tagged so a
reader can triage:

  * 3 high-severity items — vacuous signatures.ok=true, dead AgentCard
    fallback code, and the permission model's "ask" being silently
    equivalent to "allow".
  * 10 medium items — catalog mutation on resumed sessions, no request
    size limit, no observability, no hot reload for recipes, etc.
  * 7 low items — stale names, missing tests, docs gaps.

Each entry has a file path + line number so "I'll fix one" is a concrete
task, not a discovery project. Adds a short "How to add to this list"
footer so future contributors know the format.

No code changes. Meant to be the gateway's equivalent of the "known
issues" sections most production projects keep but this one was missing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI's detect-secrets hook flagged docs/openapi.yaml:598 as a
"Base64 High Entropy String." That line is a base58-encoded Ed25519
signature used as an API example — signatures are public by design
(that's the whole point), not a secret. Adding the standard
`# pragma: allowlist secret` inline comment tells the scanner to skip
this specific line without loosening global rules.

Matches the pattern the project CLAUDE.md §Recent Learnings documents
for .env.example files.

Fixes https://github.com/GetBindu/Bindu/actions/runs/24672201148
…s pass

Addresses the first high-severity entry in BUGS_AND_KNOWN_ISSUES.md.

Before: the <remote_content> envelope collapsed `signatures.ok` (a
boolean) into a three-valued attribute — yes/no/unknown. When zero
artifacts were signed, `ok` was vacuously true (nothing to fail) and
the envelope read `verified="yes"` — indistinguishable to the planner
LLM from a real cryptographic pass.

After: four-valued `verified` attribute driven by a new pure helper
computeVerifiedLabel(signatures):

  null                                      → "unknown"
  !ok                                       → "no"
  ok && signed === 0                        → "unsigned"   (NEW)
  ok && signed > 0 && signed === verified   → "yes"

The authoritative `signatures.ok` in the Bindu client stays unchanged
— "no failures" is still a useful concept for the DB audit row and
SSE signatures field. The label is just a richer projection for the
planner's benefit.

Implementation:
- New exported VerifiedLabel type + computeVerifiedLabel() in planner
- wrapRemoteContent takes the label directly (not a boolean)
- Call site passes the full signatures object through the new helper

Test: tests/planner/verified-label.test.ts — 7 cases pinning each
branch, including the regression (vacuous-yes becomes "unsigned").

openapi.yaml: SSEEvent_TaskArtifact.content description updated to
enumerate the four labels with semantics.

BUGS_AND_KNOWN_ISSUES.md: entry marked RESOLVED with reference to
the helper and the test.

Typecheck clean, 201/201 tests pass, redocly lint 0 errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves the second high-severity entry in BUGS_AND_KNOWN_ISSUES.md —
the `peer.card` fallback at bindu/client/index.ts:196 was dead code
because nothing in the codebase ever populated it. Signature
verification required a pinnedDID; with none set, maybeVerifySignatures
always short-circuited.

New src/bindu/client/agent-card.ts — fetchAgentCard(peerUrl, opts):
  - GETs /.well-known/agent.json, Zod-parses against the AgentCard
    schema, caches per-process.
  - 2-second default timeout (short because it blocks the first call
    per peer; callers can override).
  - Every failure mode degrades to null: non-2xx, malformed JSON,
    schema mismatch, network error, abort. Failures are cached too so
    a flaky peer doesn't cost one outbound fetch per /plan.

Wired into runCall at bindu/client/index.ts: fetches only when
`trust.verifyDID: true` AND peer.card isn't already set. No cost on
peers that don't care about verification. Mutation of input.peer.card
is safe because PeerDescriptor is built fresh per catalog entry per
request.

End-to-end effect: `trust.verifyDID: true` WITHOUT `pinnedDID` is now
a real feature. The gateway observes the peer's published DID,
resolves its public key via the DID document, and verifies every
artifact signature against it. Pinned wins over observed when both
are set (pinning is a stronger security claim — the caller vouched
for the identity, while observed just trusts what the peer published).

Coverage: tests/bindu/agent-card-fetch.test.ts — 9 cases:
  - success path parses valid card
  - 404 returns null
  - malformed JSON returns null
  - schema mismatch returns null
  - network throw returns null
  - cache hit skips re-fetch (same reference returned)
  - negative cache skips re-fetch on known-bad peer
  - per-URL isolation — different peers fetched independently
  - timeout honored via internal AbortController

BUGS_AND_KNOWN_ISSUES.md: original AgentCard entry marked RESOLVED
with cross-refs to the helper and test. A new medium entry now
tracks the remaining follow-up — SSE's agent_did field still only
reflects pinned DIDs, not observed ones. That's plan-route.ts layer
(findPinnedDID → findAgentDID with observed fallback), scheduled
next.

Typecheck clean, 210/210 tests pass (+9 agent-card-fetch).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves the "SSE agent_did doesn't surface observed DIDs" follow-up
from the AgentCard fetch work. Before: findPinnedDID read only
trust.pinnedDID, so callers who didn't pin saw agent_did: null in
every task.* frame even after the Bindu client had observed the peer's
DID via AgentCard. Signature verification worked against the observed
DID; the display layer didn't know about it.

Changes:
- New findAgentDID(request, observedByName, agentName) → {did, source}
  with precedence pinned > observed > null. Replaces findPinnedDID.
- New `agent_did_source: "pinned" | "observed" | null` field on every
  task.started / task.artifact / task.finished SSE frame so consumers
  can distinguish caller-vouched pinned DIDs from self-reported
  observed DIDs and apply their own trust policies per frame.
- Upfront AgentCard discovery at /plan start via Promise.allSettled
  with a 2s TOTAL budget shared across the catalog (not 2s per peer).
  Results populate the observedByName map and hit the per-process
  fetchAgentCard cache, so the Bindu client's verification path gets
  them for free on subsequent calls.

openapi.yaml: new shared AgentDIDSource schema with trust-policy docs
referenced from all three task.* events. Each affected event's
required fields list gains `agent_did_source`.

Coverage: tests/api/find-agent-did.test.ts — 6 cases pinning precedence
(pinned wins even when observed exists), per-agent independence,
graceful null for agent names outside the catalog (load_recipe passes
through this helper too).

BUGS_AND_KNOWN_ISSUES.md: entry marked RESOLVED with cross-refs.

Typecheck clean, 216/216 tests pass (+6 find-agent-did), redocly lint
0 errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…WAY.md moves to repo-level docs/

Matches the repo's existing doc layout:
  - /docs/ has topic-based guides per subsystem (AUTHENTICATION.md,
    PAYMENT.md, SCHEDULER.md, etc.)
  - /bugs/known-issues.md is the single user-facing known-issues
    registry; the file's own rules say entries are REMOVED on fix
    and new ones added in-place.

This commit aligns gateway docs with that layout:

  /gateway/docs/STORY.md        → /docs/GATEWAY.md
  /gateway/docs/BUGS_AND_...md  → merged into /bugs/known-issues.md
  /gateway/docs/                → deleted

docs/GATEWAY.md: the end-to-end walkthrough. 8 internal links rewritten
for the new location (one level up from where it was):
  ../openapi.yaml    → ../gateway/openapi.yaml
  ../README.md       → ../gateway/README.md
  ../agents/...      → ../gateway/agents/...
  ../recipes/...     → ../gateway/recipes/...
  ../../examples/... → ../examples/...

Link check across the four affected docs (docs/GATEWAY.md,
gateway/README.md, fleet/README.md, bugs/known-issues.md) — all
resolve.

bugs/known-issues.md absorbs the unresolved work the gateway-local
file was tracking. Net:

  - 15 new gateway entries (5 medium, 6 low, 5 nit) with file
    paths, symptoms, workarounds — all the items surfaced during
    the recipes/SSE/DID work that aren't yet fixed.
  - 2 existing entries narrowed: `tool-name-collisions-silent`
    was partially fixed in this session (collision rejection
    landed at plan-open time) and is now
    `parse-agent-from-tool-greedy-mismatch` tracking only the
    residual regex issue. `signature-verification-ok-when-unsigned`
    narrowed to `signature-verification-non-text-parts-unverified`
    — the envelope ambiguity was fixed by the four-valued
    `verified` label, `data`/`file` parts are still unverified.
  - Quick-index table + TOC counts updated accordingly.
  - Header's `_Last updated_` line reflects the 2026-04-20 session.

gateway/README.md + examples/gateway_test_fleet/README.md: 6 total
references to `docs/STORY.md` rewritten to point at the new
`docs/GATEWAY.md` location.

No code changes; 216/216 tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@raahulrahl raahulrahl merged commit 0261b51 into main Apr 20, 2026
1 of 3 checks passed
@raahulrahl raahulrahl deleted the feat/gateway-recipes branch April 20, 2026 15:03
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 52adf5b9-bf3c-4c16-857b-e8fdd21551c1

📥 Commits

Reviewing files that changed from the base of the PR and between 12836f4 and aaeb431.

📒 Files selected for processing (13)
  • bugs/known-issues.md
  • docs/GATEWAY.md
  • docs/openapi.yaml
  • examples/gateway_test_fleet/README.md
  • gateway/README.md
  • gateway/openapi.yaml
  • gateway/src/api/plan-route.ts
  • gateway/src/bindu/client/agent-card.ts
  • gateway/src/bindu/client/index.ts
  • gateway/src/planner/index.ts
  • gateway/tests/api/find-agent-did.test.ts
  • gateway/tests/bindu/agent-card-fetch.test.ts
  • gateway/tests/planner/verified-label.test.ts

📝 Walkthrough

Walkthrough

The PR enhances peer DID resolution and verification metadata tracking across the Gateway. It introduces agent card discovery via fetchAgentCard, implements pinned/observed DID precedence with provenance tracking, expands SSE event schemas to include agent_did_source, refines verification state semantics from binary to four-valued labels, and extends test coverage accordingly.

Changes

Cohort / File(s) Summary
Documentation & Link Updates
bugs/known-issues.md, docs/GATEWAY.md, examples/gateway_test_fleet/README.md, gateway/README.md
Updated internal documentation links, replaced relative path references (e.g., ../...../gateway/..., ./docs/STORY.md../docs/GATEWAY.md), and refreshed known-issues metadata and issue entries (tool collision handling, signature verification scope, new Gateway nits).
OpenAPI Schema Enhancements
docs/openapi.yaml, gateway/openapi.yaml
Added pragma comment to signature example in docs schema; expanded Gateway SSE event schemas (SSEEvent_TaskStarted, SSEEvent_TaskArtifact, SSEEvent_TaskFinished) with required agent_did_source field and new AgentDIDSource enum; clarified task.artifact.content.verified to document four-valued outcomes (`yes
Agent Card Discovery Module
gateway/src/bindu/client/agent-card.ts
New module implementing fetchAgentCard(peerUrl, opts) to retrieve AgentCard from /.well-known/agent.json with per-process in-memory caching, request cancellation support, 2s default timeout, and graceful null-return on network/parse/schema failures.
DID Resolution & SSE Provenance
gateway/src/api/plan-route.ts
Pre-fetches peer AgentCards in parallel (~2s shared budget) and derives observed DIDs before SSE streaming. Replaced findPinnedDID with findAgentDID function returning DID plus provenance source (pinned|observed|null). SSE frames now emit both agent_did and agent_did_source for task events.
Bindu Client Integration
gateway/src/bindu/client/index.ts
Added pre-step in runCall to fetch and populate input.peer.card when unset and trust.verifyDID is enabled, enabling DID derivation via getPeerDID(peer.card) when pinned DID is absent.
Verification State Expansion
gateway/src/planner/index.ts
Introduced exported VerifiedLabel union type (`"yes"
Test Coverage
gateway/tests/api/find-agent-did.test.ts, gateway/tests/bindu/agent-card-fetch.test.ts, gateway/tests/planner/verified-label.test.ts
Added comprehensive test suites for DID precedence and provenance resolution, agent card caching/fetching with timeout and error handling, and four-valued verified-label derivation across signature states.

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant PlanRoute as plan-route.ts<br/>(handleRequest)
    participant AgentCardCache as agent-card.ts<br/>(fetchAgentCard)
    participant Peer as Peer Service<br/>/.well-known/agent.json
    participant Planner as planner.ts
    participant SSE as SSE Stream

    Client->>PlanRoute: POST /plan
    PlanRoute->>PlanRoute: Extract agent names from request
    par Pre-fetch all peers in parallel
        PlanRoute->>AgentCardCache: fetchAgentCard(peerUrl, {signal, timeout: 2s})
        AgentCardCache->>Peer: fetch /.well-known/agent.json
        Peer-->>AgentCardCache: AgentCard (or error/timeout)
        AgentCardCache-->>PlanRoute: AgentCard | null (cached)
    end
    PlanRoute->>PlanRoute: Build observedByName map<br/>from fetched AgentCards
    PlanRoute->>SSE: Start streaming
    loop For each SSE event (task.started, task.artifact, task.finished)
        PlanRoute->>PlanRoute: findAgentDID(request, observedByName, agentName)<br/>→ { did, source }
        PlanRoute->>SSE: Emit { agent_did, agent_did_source, ... }
    end
    SSE-->>Client: SSE stream with provenance
    PlanRoute->>Planner: Pass artifact + signatures to planner
    Planner->>Planner: computeVerifiedLabel(signatures)<br/>→ "yes"|"no"|"unsigned"|"unknown"
    Planner->>Planner: wrapRemoteContent(verified_label)
    Planner-->>Client: LLM prompt with 4-state verification
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A card to know each peer by name,
DID sources traced—no silent claim,
Four verdicts now on signatures shine,
Pinned or observed, the lines align!
SSE streams with sources divine. 🔐✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/gateway-recipes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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