Skip to content

feat: VC-based authorization, sidecar management APIs, and multi-version reasoners#188

Open
AbirAbbas wants to merge 44 commits intomainfrom
feat/connector
Open

feat: VC-based authorization, sidecar management APIs, and multi-version reasoners#188
AbirAbbas wants to merge 44 commits intomainfrom
feat/connector

Conversation

@AbirAbbas
Copy link
Contributor

@AbirAbbas AbirAbbas commented Feb 25, 2026

Summary

This PR introduces three major capabilities to the AgentField control plane:

1. VC-Based Authorization System

A complete tag-based authorization model built on W3C Verifiable Credentials and Decentralized Identifiers (DIDs):

  • Tag approval workflow — Agents propose tags at registration (agent-level, per-skill, per-reasoner). The control plane evaluates each tag against configurable approval rules (auto/manual/forbidden). Agents with manual tags enter pending_approval state until an admin reviews them.
  • Access policies — Tag-based policies control which agents can call which functions. Policies support ALLOW/DENY actions, priority ordering, function-level granularity, and parameter constraints. No matching policy = allow (backward compatible).
  • DID authentication — Ed25519 signature-based request authentication with replay protection (nonce + timestamp window). Agents sign requests with their DID private key; the control plane verifies signatures in middleware before evaluating policies.
  • did:web resolution — Control plane hosts DID documents, enabling real-time revocation. Revoking an agent's tags immediately blocks subsequent calls (returns 503).
  • AgentTagVC issuance — Upon tag approval, the control plane issues a signed W3C Verifiable Credential per agent, binding the agent's DID to its approved tags.
  • Decentralized verification — SDKs can cache policies, revocation lists, and admin public keys locally, verifying permissions without hitting the control plane on every call.
  • Admin UI — New unified Authorization page with tabbed interface: Access Rules (policy CRUD), Agent Tags (approval/revocation with context-aware dialogs).

2. Sidecar Management APIs

New capability-scoped REST API surface (/api/v1/connector/*) that allows an external sidecar process to manage the control plane remotely:

  • Capability manifest — Sidecar fetches its granted capabilities from the control plane at startup via GET /manifest. The control plane is the sole authority for what the sidecar token can access.
  • Reasoner management — List, inspect, set versions, restart reasoners, manage traffic weights across versions.
  • Policy management — CRUD access policies through the sidecar.
  • Tag management — Approve, reject, revoke agent tags through the sidecar.
  • Agent groups — List groups and their member nodes for fleet-level operations.
  • Dedicated auth — Separate connector token authentication, independent from the main API key / admin token.
  • Capability gating — Each route group is gated by its corresponding capability domain, so you can grant a sidecar narrow access (e.g., read-only status) or broad management capabilities.

3. Multi-Version Reasoner Support

Agents can now register multiple versions of the same reasoner, enabling blue/green deployments and canary rollouts:

  • Version-aware registration and discovery
  • Per-version traffic weight configuration
  • Per-version restart capability
  • Group-level fleet operations (list groups, list nodes per group)

SDK Changes (Go, Python, TypeScript)

  • DID authentication added to all three SDKs — agents sign execution requests with Ed25519 keys, enabling the permission middleware to identify callers cryptographically.
  • Local verification — Go and TypeScript SDKs support decentralized verification: agents cache policies and admin keys, verify incoming calls locally without round-tripping to the control plane.
  • Error propagation improvements — New ExecuteError type across all SDKs preserves HTTP status codes and structured error bodies from failed cross-agent calls (previously lost by raise_for_status()).

Database Migrations

  • 018 through 023: DID documents, access policies, agent tag VCs tables. Migration 023 cleans up two intermediate tables that were superseded during development.

Testing

  • 1,295-line integration test suite covering the full authorization lifecycle (registration → tag approval → policy evaluation → revocation → re-approval)
  • DID auth middleware unit tests (signature verification, replay protection, timestamp validation)
  • Permission middleware unit tests
  • Access policy service + tag approval service unit tests
  • Tag VC verifier tests
  • SDK-level DID auth tests for all three languages
  • Example agents for manual E2E testing (permission-agent-a as caller, permission-agent-b as protected target) in Go, Python, and TypeScript

Bug Fixes

  • Fix SSE tests leaking goroutines from incorrect context cancellation
  • Fix pre-existing test bugs exposed by enabling FTS5 build tag in CI (15 tests)
  • Fix re-approval deadlock where revoked agents couldn't re-request permissions
  • Fix empty caller_agent_id in DID registry lookups for did:key resolution
  • Fix HTTP 200 for failed inner agent-to-agent calls (now returns 502 with error details)

Test plan

  • Run go test -tags sqlite_fts5 ./... in control-plane/ — all tests pass
  • Run Python SDK tests: cd sdk/python && python -m pytest
  • Run TypeScript SDK tests: cd sdk/typescript && npm test
  • Start control plane with authorization enabled, register two agents with tags, verify approval workflow in Admin UI
  • Test sidecar API: authenticate with connector token, fetch manifest, list reasoners, manage policies
  • Test revocation: revoke an agent's tags, verify subsequent calls return 503
  • Test multi-version: register agent with two reasoner versions, set traffic weights, verify routing

🤖 Generated with Claude Code

AbirAbbas and others added 30 commits February 10, 2026 14:29
This commit introduces the foundation for the new VC-based authorization
system that replaces API key distribution with admin-approved permissions.

Key components added:
- Architecture documentation (docs/VC_AUTHORIZATION_ARCHITECTURE.md)
- Database migrations for permission approvals, DID documents, and protected agents
- Core types for permissions and did:web support
- DIDWebService for did:web generation, storage, and resolution
- PermissionService for permission requests, approvals, and VC issuance

The system enables:
- Agents self-assigning tags (identity declaration)
- Admin approval workflow for protected agent access
- Real-time revocation via did:web
- Control plane as source of truth for approvals

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…entation

- Add DID authentication middleware with Ed25519 signature verification
- Add permission checking middleware for protected agent enforcement
- Implement admin API handlers for permission management (approve/reject/revoke)
- Add permission request and check API endpoints
- Implement storage layer for DID documents, permission approvals, protected agent rules
- Add comprehensive integration test suite (14 test functions covering all phases)
- Add Admin UI pages: PendingPermissions, PermissionHistory, ProtectedAgents
- Add Go SDK DID authentication support
- Add Python SDK DID authentication support
- Fix CI to enable FTS5 tests (previously all SQLite-dependent tests were skipped)
- Add security documentation for DID authentication
- Add implementation guide documentation

Co-Authored-By: Claude <noreply@anthropic.com>
TestGetNodeDetailsHandler_Structure expected HTTP 400 for missing route
param but Gin returns 404. TestGetNodeStatusHandler_Structure was missing
a mock expectation for GetAgentStatus causing a panic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CI workflow change from `go test ./...` to `go test -tags sqlite_fts5 ./...`
caused previously-skipped tests to execute, revealing 15 pre-existing bugs:

- UI handler tests: Register agents in storage and configure mocks for
  GetAgentStatus calls; fix assertions to match actual behavior (health
  check failures mark agents inactive, not error the request)
- VC service tests: Fix GetWorkflowVC lookups to use workflow_vc_id not
  workflow_id; fix issuer mismatch test to tamper VCDocument JSON instead
  of metadata field; fix error message assertion for empty VC documents
- VC storage tests: Fix GetWorkflowVC key lookups; fix empty result assertions
- PresenceManager tests: Register agents in storage so markInactive ->
  UpdateAgentStatus -> GetAgentStatusSnapshot -> GetAgent succeeds; add
  proper sync.Mutex for callback vars; use require.Eventually instead of
  time.Sleep; set HardEvictTTL for lease deletion test
- Webhook storage: Fix hardcoded Pending status to use webhook.Status
- Execution records test: Fix LatestStarted assertion (CreateExecutionRecord
  overwrites updated_at with time.Now())
- Cleanup test: Wire countWorkflowRuns and deleteWorkflowRuns into
  workflow cleanup path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ntext cancellation

Multiple SSE tests called req.Context().Done() expecting it to cancel the
context, but Done() only returns a channel — it doesn't cancel anything.
This caused SSE handler goroutines to block forever, leaking and eventually
causing a 10-minute test timeout in CI.

Fixed all affected tests to use context.WithCancel + explicit cancel() call,
matching the pattern already used by the working SSE tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…n config

Add two example agents for manually testing the VC authorization system
end-to-end: permission-agent-a (caller) and permission-agent-b (protected
target). Enable authorization in the default config with seeded protection
rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ster_agent_with_did

The previous commit added identity_package access and client credential
wiring to _register_agent_with_did but didn't update the test fakes.
_FakeDIDManager now provides a realistic identity_package and
_FakeAgentFieldClient supports set_did_credentials, so the full
registration path is exercised in tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Go permission test agents (caller + protected target with 3 reasoners)
- Add TS permission test agents (caller + tag-protected target with VC generation)
- Fix TS SDK DID auth: pass pre-serialized JSON string to axios to ensure
  signed bytes match what's sent on the wire
- Fix Python SDK test for async execution manager payload serialization change
- Add go-perm-target protection rule to config
- Gitignore compiled Go agent binaries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The execute() method now passes a JSON string instead of an object to
axios for DID auth signing consistency. Update test assertion to match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ror propagation

- Fix re-approval deadlock: expand auto-request condition to trigger for
  revoked/rejected statuses, not just empty (permission.go)
- Fix empty caller_agent_id: add DID registry fallback in
  ResolveAgentIDByDID for did:key resolution (did_service.go, did_web_service.go)
- Fix HTTP 200 for failed executions: return 502 with proper error details
  when inner agent-to-agent calls fail (execute.go)
- Fix error propagation across all 3 SDKs:
  - Go SDK: add ExecuteError type preserving status code and error_details
  - TS SDK: propagate err.responseData as error_details in all error handlers
  - Python SDK: add ExecuteError class, extract JSON body from 4xx responses
    instead of losing it via raise_for_status(), propagate error_details in
    async callback payloads

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests expected the old 3-header format ({timestamp}:{bodyHash}) but the
implementation correctly uses 4 headers with nonce ({timestamp}:{nonce}:{bodyHash}),
matching Go and Python SDKs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses code scanning alert about missing rate limiting on the
authorization route handler. Adds a sliding-window rate limiter
(30 requests per IP per 60s) to the local verification middleware.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace custom Map-based rate limiter with express-rate-limit package,
which CodeQL recognizes as a proper rate limiting implementation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
santoshkumarradha and others added 12 commits February 13, 2026 15:07
…andardization

Replace separate TagApprovalPage and AccessPoliciesPage with a single
tabbed AuthorizationPage. Add polished authorization components:
- AccessRulesTab: 48px rows, sorted policies, ALLOW/DENY border colors
- AgentTagsTab: all agents with tag data, sorted, neutral badges
- ApproveWithContextDialog: tag selection with policy impact preview
- PolicyFormDialog: chip-input for tags with known-tag suggestions
- PolicyContextPanel: shows affected policies for selected tags
- RevokeDialog: neutral styling, optional reason
- ChipInput, TooltipTagList: reusable tag UI components

Backend additions:
- GET /api/ui/v1/authorization/agents: returns all agents with tag data
- GET /api/v1/admin/tags: returns all known tags from agents & policies

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve conflicts in async_execution_manager.py and client.py by
keeping both auth_headers (from main) and did_authenticator (from
this branch) parameters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
#	control-plane/agentfield-server
Resolve conflicts in Python SDK: keep both DID auth (feat/connector)
and typed exceptions (main) imports. Use AgentFieldClientError for
network errors while preserving detailed error body parsing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 25, 2026

Performance

SDK Memory Δ Latency Δ Tests Status
Python 9.0 KB - 0.32 µs -9%
Go 221 B -21% 0.61 µs -39%
TS 490 B +40% 1.86 µs -7%

Regression detected:

  • TypeScript memory: 350 B → 490 B (+40%)

@AbirAbbas AbirAbbas changed the title Feat/connector feat: VC-based authorization, sidecar management APIs, and multi-version reasoners Feb 25, 2026
AbirAbbas and others added 2 commits February 25, 2026 09:54
… for fresh DBs

Two CI failures:

1. linux-tests: stubStorage in server_routes_test.go was missing the
   DeleteAgentVersion method added to the StorageProvider interface
   by the multi-version work. Add the stub.

2. Functional Tests (postgres): migrateAgentNodesCompositePKPostgres
   tried to ALTER TABLE agent_nodes before GORM created it on fresh
   databases. The information_schema.columns query returns count=0
   (not an error) when the table doesn't exist, so the function
   proceeded to run ALTER statements against a nonexistent table.
   Add an explicit table existence check matching the pattern already
   used by the SQLite migration path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@santoshkumarradha
Copy link
Member

@AbirAbbas reminder for us to update docs as well b4 merging.

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.

2 participants