Files
sentryagent-idp/sdk-go/credentials.go
SentryAgent.ai Developer 91c759f455 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>
2026-03-28 15:23:02 +00:00

94 lines
3.0 KiB
Go

package agentidp
import (
"context"
"fmt"
"net/http"
"net/url"
"strings"
)
// CredentialClient provides methods for the Credential Management API endpoints.
type CredentialClient struct {
baseURL string
getToken func(ctx context.Context) (string, error)
httpClient *http.Client
}
func newCredentialClient(baseURL string, getToken func(ctx context.Context) (string, error), httpClient *http.Client) *CredentialClient {
return &CredentialClient{
baseURL: strings.TrimRight(baseURL, "/"),
getToken: getToken,
httpClient: httpClient,
}
}
// GenerateCredential creates a new credential for the given agent.
// POST /api/v1/agents/:id/credentials → 201 CredentialWithSecret
func (c *CredentialClient) GenerateCredential(ctx context.Context, agentID string) (*CredentialWithSecret, error) {
token, err := c.getToken(ctx)
if err != nil {
return nil, err
}
var cred CredentialWithSecret
if err := doRequest(ctx, c.httpClient, http.MethodPost, c.baseURL+"/api/v1/agents/"+agentID+"/credentials", struct{}{}, token, &cred); err != nil {
return nil, err
}
return &cred, nil
}
// ListCredentials returns a paginated list of credentials for the given agent.
// GET /api/v1/agents/:id/credentials → 200 PaginatedCredentials
func (c *CredentialClient) ListCredentials(ctx context.Context, agentID string, page, limit int) (*PaginatedCredentials, error) {
token, err := c.getToken(ctx)
if err != nil {
return nil, err
}
rawURL := c.baseURL + "/api/v1/agents/" + agentID + "/credentials"
q := url.Values{}
if page > 0 {
q.Set("page", fmt.Sprintf("%d", page))
}
if limit > 0 {
q.Set("limit", fmt.Sprintf("%d", limit))
}
if len(q) > 0 {
rawURL += "?" + q.Encode()
}
var result PaginatedCredentials
if err := doRequest(ctx, c.httpClient, http.MethodGet, rawURL, nil, token, &result); err != nil {
return nil, err
}
return &result, nil
}
// RotateCredential generates a new secret for the given credential.
// POST /api/v1/agents/:id/credentials/:credId/rotate → 200 CredentialWithSecret
func (c *CredentialClient) RotateCredential(ctx context.Context, agentID, credentialID string) (*CredentialWithSecret, error) {
token, err := c.getToken(ctx)
if err != nil {
return nil, err
}
rawURL := c.baseURL + "/api/v1/agents/" + agentID + "/credentials/" + credentialID + "/rotate"
var cred CredentialWithSecret
if err := doRequest(ctx, c.httpClient, http.MethodPost, rawURL, struct{}{}, token, &cred); err != nil {
return nil, err
}
return &cred, nil
}
// RevokeCredential permanently revokes a credential.
// DELETE /api/v1/agents/:id/credentials/:credId → 200 Credential
func (c *CredentialClient) RevokeCredential(ctx context.Context, agentID, credentialID string) (*Credential, error) {
token, err := c.getToken(ctx)
if err != nil {
return nil, err
}
rawURL := c.baseURL + "/api/v1/agents/" + agentID + "/credentials/" + credentialID
var cred Credential
if err := doRequest(ctx, c.httpClient, http.MethodDelete, rawURL, nil, token, &cred); err != nil {
return nil, err
}
return &cred, nil
}