feat: Phase 2 Workstream 3 — Go SDK (github.com/sentryagent/idp-sdk-go)
Single-package agentidp SDK in sdk-go/: - AgentIdPClient composing AgentRegistryClient, CredentialClient, TokenServiceClient, AuditClient — all 14 endpoints covered - Goroutine-safe TokenManager (sync.Mutex) with 60s refresh buffer - AgentIdPError implementing error interface with Code/HTTPStatus/Details - Context-aware: all service methods take context.Context as first arg - doRequest shared helper; token endpoints use form-encoded POST directly - go vet: 0 warnings | staticcheck: 0 warnings - go test ./...: 37/37 passed | coverage: 81.0% (>80% gate) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
83
sdk-go/client.go
Normal file
83
sdk-go/client.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package agentidp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AgentIdPClientConfig holds all configuration for AgentIdPClient.
|
||||
type AgentIdPClientConfig struct {
|
||||
// BaseURL is the root URL of the AgentIdP server (e.g. "https://idp.example.com").
|
||||
BaseURL string
|
||||
// ClientID is the agent's OAuth 2.0 client ID.
|
||||
ClientID string
|
||||
// ClientSecret is the agent's OAuth 2.0 client secret.
|
||||
ClientSecret string
|
||||
// Scope is the space-separated list of OAuth 2.0 scopes to request.
|
||||
// Defaults to all four scopes when empty.
|
||||
Scope string
|
||||
// HTTPClient allows injecting a custom *http.Client (e.g. for testing).
|
||||
// When nil, a default client with a 30-second timeout is used.
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// AgentIdPClient is the top-level client for the SentryAgent.ai AgentIdP API.
|
||||
// It composes all four service clients and manages token acquisition automatically.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// client := agentidp.NewAgentIdPClient(agentidp.AgentIdPClientConfig{
|
||||
// BaseURL: "https://idp.example.com",
|
||||
// ClientID: "my-agent-id",
|
||||
// ClientSecret: "sk_live_...",
|
||||
// })
|
||||
// agent, err := client.Agents.GetAgent(ctx, "uuid-1")
|
||||
type AgentIdPClient struct {
|
||||
// Agents provides access to the Agent Registry endpoints.
|
||||
Agents *AgentRegistryClient
|
||||
// Credentials provides access to the Credential Management endpoints.
|
||||
Credentials *CredentialClient
|
||||
// Tokens provides access to the Token introspection and revocation endpoints.
|
||||
Tokens *TokenServiceClient
|
||||
// Audit provides access to the Audit Log endpoints.
|
||||
Audit *AuditClient
|
||||
|
||||
tokenManager *TokenManager
|
||||
}
|
||||
|
||||
// NewAgentIdPClient creates a new AgentIdPClient with the given configuration.
|
||||
func NewAgentIdPClient(cfg AgentIdPClientConfig) *AgentIdPClient {
|
||||
baseURL := strings.TrimRight(cfg.BaseURL, "/")
|
||||
|
||||
scope := cfg.Scope
|
||||
if scope == "" {
|
||||
scope = "agents:read agents:write tokens:read audit:read"
|
||||
}
|
||||
|
||||
httpClient := cfg.HTTPClient
|
||||
if httpClient == nil {
|
||||
httpClient = &http.Client{Timeout: 30 * time.Second}
|
||||
}
|
||||
|
||||
tm := NewTokenManager(baseURL, cfg.ClientID, cfg.ClientSecret, scope)
|
||||
|
||||
getToken := func(ctx context.Context) (string, error) {
|
||||
return tm.GetToken(ctx)
|
||||
}
|
||||
|
||||
return &AgentIdPClient{
|
||||
Agents: newAgentRegistryClient(baseURL, getToken, httpClient),
|
||||
Credentials: newCredentialClient(baseURL, getToken, httpClient),
|
||||
Tokens: newTokenServiceClient(baseURL, getToken, httpClient),
|
||||
Audit: newAuditClient(baseURL, getToken, httpClient),
|
||||
tokenManager: tm,
|
||||
}
|
||||
}
|
||||
|
||||
// ClearTokenCache invalidates the cached access token.
|
||||
// The next API call will fetch a fresh token from the server.
|
||||
func (c *AgentIdPClient) ClearTokenCache() {
|
||||
c.tokenManager.ClearCache()
|
||||
}
|
||||
Reference in New Issue
Block a user