agentcredential

package
v0.20.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 15, 2026 License: AGPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

Package agentcredential stores Agent credentials encrypted at rest.

A credential belongs to a team and is referenced by at most one Bot Agent instance via bot_agents.agent_credential_id (enforced by product flow, not schema). Attach replaces an Agent's credential atomically and revokes the replaced row once nothing references it; runtime resolution walks session → bot_agent → credential and decrypts only while preparing the Agent process configuration.

Index

Constants

View Source
const (
	ProviderOpenAI    = "openai"
	ProviderAnthropic = "anthropic"

	AuthKindOpenAIAPIKey     = "openai_api_key" //nolint:gosec // Stable authentication-kind identifier.
	AuthKindOpenAICodexOAuth = "openai_codex_oauth"
	AuthKindAnthropicAPIKey  = "anthropic_api_key" //nolint:gosec // Stable authentication-kind identifier.
	AuthKindClaudeCodeOAuth  = "claude_code_oauth"
)

Variables

View Source
var (
	ErrAuthorizationExpired     = errors.New("authorization session expired or unavailable")
	ErrAuthorizationNotReady    = errors.New("authorization is not complete")
	ErrAuthorizationLimit       = errors.New("too many pending authorizations")
	ErrAuthorizationFailed      = errors.New("authorization failed")
	ErrAuthorizationCodeInvalid = errors.New("authorization code is invalid")
)
View Source
var (
	ErrNotFound              = errors.New("agent credential not found")
	ErrIncompatible          = errors.New("agent credential is incompatible with the agent")
	ErrRevoked               = errors.New("agent credential is revoked")
	ErrEncryptionUnavailable = errors.New("agent credential encryption is unavailable")
	ErrInvalidRequest        = errors.New("invalid agent credential request")
)

Functions

func Compatible

func Compatible(agentRuntime, authKind string) bool

Compatible reports whether an auth kind can drive the Agent runtime.

func ProviderForAuthKind

func ProviderForAuthKind(kind string) string

ProviderForAuthKind maps an auth kind to its provider so API callers only submit the kind.

Types

type Authorization

type Authorization struct {
	ID               string    `json:"id" validate:"required"`
	Runtime          string    `json:"runtime" validate:"required"`
	AuthKind         string    `json:"auth_kind" validate:"required"`
	Status           string    `json:"status" validate:"required" enums:"pending,ready,claimed"`
	ExpiresAt        time.Time `json:"expires_at" validate:"required"`
	UserCode         string    `json:"user_code,omitempty"`
	VerificationURL  string    `json:"verification_url,omitempty"`
	AuthorizationURL string    `json:"authorization_url,omitempty"`
	IntervalSeconds  int64     `json:"interval_seconds,omitempty"`
}

Authorization contains only the public handoff, never credentials or provider device IDs.

type AuthorizationRequest

type AuthorizationRequest struct {
	Runtime  string            `json:"runtime" validate:"required" enums:"codex,claude-code"`
	AuthKind string            `json:"auth_kind" validate:"required"`
	Secret   map[string]string `json:"secret,omitempty"`
}

type AuthorizationService

type AuthorizationService struct {
	// contains filtered or unexported fields
}

AuthorizationService stages encrypted credentials independently of a Bot. Row locks serialize polling and one-time claims across server instances.

func NewAuthorizationService

func NewAuthorizationService(credentials *Service, oauth *providers.Service) *AuthorizationService

func (*AuthorizationService) Cancel

func (s *AuthorizationService) Cancel(ctx context.Context, owner, id string) error

func (*AuthorizationService) Claim

func (s *AuthorizationService) Claim(ctx context.Context, owner, id, botID, agentID string) (PublicCredential, error)

Claim is idempotent for the same Agent and cannot attach a session to a second Agent. Binding, credential encryption, and erasing staged secrets commit together.

func (*AuthorizationService) Create

func (*AuthorizationService) Exchange

func (s *AuthorizationService) Exchange(ctx context.Context, owner, id, code string) (Authorization, error)

Exchange completes a pending Claude authorization. Failed exchanges remain retryable; concurrent retries cannot exchange a one-time code twice.

func (*AuthorizationService) Get

func (s *AuthorizationService) Get(ctx context.Context, owner, id string, poll bool) (Authorization, error)

type CreateRequest

type CreateRequest struct {
	Provider        string            `json:"provider"`
	AuthKind        string            `json:"auth_kind"`
	Label           string            `json:"label,omitempty"`
	Secret          map[string]string `json:"secret"`
	AccountMetadata map[string]any    `json:"account_metadata,omitempty"`
	ExpiresAt       *time.Time        `json:"expires_at,omitempty"`
}

CreateRequest carries a new secret into the store. Label may be empty; the service derives one from the auth kind when absent.

type PublicCredential

type PublicCredential struct {
	ID                string         `json:"id"`
	OwnerUserID       string         `json:"owner_user_id"`
	Provider          string         `json:"provider"`
	AuthKind          string         `json:"auth_kind"`
	Label             string         `json:"label"`
	AccountMetadata   map[string]any `json:"account_metadata,omitempty"`
	ExpiresAt         *time.Time     `json:"expires_at,omitempty"`
	CredentialVersion int64          `json:"credential_version"`
	Revoked           bool           `json:"revoked"`
	CreatedAt         time.Time      `json:"created_at"`
	UpdatedAt         time.Time      `json:"updated_at"`
}

PublicCredential is the redacted view of a stored credential. The secret never leaves the service; only labels and account metadata do.

type ResolvedCredential

type ResolvedCredential struct {
	PublicCredential
	AgentRuntime string
	Secret       map[string]string
}

type Service

type Service struct {
	// contains filtered or unexported fields
}

func NewService

func NewService(queries dbstore.Queries, cfg config.Config) *Service

func (*Service) AttachToBotAgent

func (s *Service) AttachToBotAgent(ctx context.Context, ownerUserID, botID, botAgentID string, req CreateRequest) (PublicCredential, error)

AttachToBotAgent encrypts a new secret, points the Bot Agent instance at it, and revokes the replaced credential once no other instance references it. The instance's provider is read inside the transaction and gates auth-kind compatibility, so a wrong-profile attach can never link.

func (*Service) Configured

func (s *Service) Configured() bool

func (*Service) DetachFromBotAgent

func (s *Service) DetachFromBotAgent(ctx context.Context, botID, botAgentID string) error

DetachFromBotAgent disconnects the instance and revokes the credential once nothing references it. ErrNotFound covers both a missing Agent and an Agent that was never connected.

func (*Service) GetForBotAgent

func (s *Service) GetForBotAgent(ctx context.Context, botID, botAgentID string) (PublicCredential, error)

GetForBotAgent returns the redacted credential currently attached to a Bot Agent instance, or ErrNotFound when the Agent is not connected.

func (*Service) ResolveForBotAgent

func (s *Service) ResolveForBotAgent(ctx context.Context, botID, botAgentID string) (ResolvedCredential, error)

ResolveForBotAgent decrypts the credential attached to a Bot Agent instance.

func (*Service) UpdateSecretCAS

func (s *Service) UpdateSecretCAS(ctx context.Context, credentialID string, expectedVersion int64, secret map[string]string, accountMetadata map[string]any, expiresAt *time.Time) (PublicCredential, error)

UpdateSecretCAS persists a rotated secret guarded by credential_version so a concurrent rotation (or revoke) loses cleanly instead of overwriting.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL