access

package
v0.63.2 Latest Latest
Warning

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

Go to latest
Published: Aug 9, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package access is the policy-enforcement point for Agent resources.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidScope reports an admin-supplied scope that is neither system nor
	// restricted. It is a validation error (400), never an authorization denial.
	ErrInvalidScope = errors.New("agent scope must be 'system' or 'restricted'")
	// ErrUserNotFound reports an assignment target that does not exist.
	ErrUserNotFound = errors.New("assignment target user not found")
	// ErrInUse reports that a durable resource still references the Agent.
	ErrInUse = errors.New("agent is still in use")
	// ErrUnknownProvider reports a credential input whose provider_id is not an
	// existing canonical Provider (an alias or an unconfigured ID). It is a
	// validation error (400), raised before any encryption.
	ErrUnknownProvider = errors.New("provider credential targets an unknown or non-canonical provider")
	// ErrCredentialsUnavailable reports that credential support is not wired.
	ErrCredentialsUnavailable = errors.New("agent provider credentials are unavailable")
)

Management-specific typed errors. Authorization/availability reuse the Service sentinels (ErrForbidden / ErrNotFound / ErrUnavailable) so the transport maps every Agent error through one vocabulary.

View Source
var (
	ErrForbidden   = errors.New("agent access forbidden")
	ErrNotFound    = errors.New("agent not found")
	ErrUnavailable = errors.New("agent authorization unavailable")
)

Functions

func GroupAgentAuthority

func GroupAgentAuthority(groupID, agentID string) (authz.Authority, error)

GroupAgentAuthority mints an exact group/agent authority for one group turn. A triggering user is intentionally absent from this capability, so a group turn can never reach user-private access.

func SystemAgentAuthority

func SystemAgentAuthority(component string) (authz.Authority, error)

SystemAgentAuthority mints the named maintenance authority used for an agent invocation. System execution is a named component; it never inherits an admin or user identity.

func WorkerAgentAuthority

func WorkerAgentAuthority(ownerID, agentID string) (authz.Authority, error)

WorkerAgentAuthority reconstructs the sole authority shape permitted for a persisted user-owned worker: its durable owner and exact executor agent.

Types

type Access

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

Access captures one validated authority and caches its assignment relation for the duration of a multi-step use case.

func (*Access) CanCreate

func (a *Access) CanCreate() error

func (*Access) CanList

func (a *Access) CanList() error

func (*Access) CanUse

func (a *Access) CanUse(ctx context.Context, agentID string) (bool, error)

func (*Access) Delete

func (a *Access) Delete(ctx context.Context, agentID string) (config.Agent, error)

func (*Access) ListReadable

func (a *Access) ListReadable(ctx context.Context, deploymentWide bool) ([]config.Agent, error)

ListReadable returns the caller's own fleet: the agents they can actually use, plus the ones they created whatever state those are in.

deploymentWide is the admin's separate, explicit ask for everyone's agents. Without it an admin gets the same personal fleet as anyone else — being able to reach every agent is not a reason to be shown every agent, and the pages that browse your own agents should not turn into a directory of everybody's on one account. SQL may narrow candidates for performance, but never decides visibility.

func (*Access) Manage

func (a *Access) Manage(ctx context.Context, agentID string) (config.Agent, error)

func (*Access) Read

func (a *Access) Read(ctx context.Context, agentID string) (config.Agent, error)

func (*Access) Use

func (a *Access) Use(ctx context.Context, agentID string) (config.Agent, error)

func (*Access) UseDedicated

func (a *Access) UseDedicated(ctx context.Context, agentID, channelID string) (config.Agent, error)

UseDedicated requires both the authority's exact held channel binding and a current enabled DB binding from that channel to this exact agent. Either mismatch fails closed; channel ID by itself is never an agent-use capability.

func (*Access) UseDedicatedForType added in v0.63.0

func (a *Access) UseDedicatedForType(ctx context.Context, agentID, channelID, channelType string) (config.Agent, error)

UseDedicatedForType additionally requires the current channel type to match the platform that minted the queued chat. This prevents a channel record that was reconfigured for another platform from authorizing stale queued work.

type ActivityReader

type ActivityReader interface {
	ListAgentLastActive(ctx context.Context, userID string) (map[string]time.Time, error)
}

ActivityReader is the conversation-activity read model: the last-active time per agent for one user's own conversations.

type AgentReloader

type AgentReloader interface {
	SyncAgent(ctx context.Context, agentID string) error
}

AgentReloader refreshes an agent's runtime state after a durable change. agent.PoolManager.SyncAgent satisfies it. Reload is eventually-consistent, so Management treats a failure as best-effort (see Create/Update/Delete).

type AgentStore

type AgentStore interface {
	GetAgent(ctx context.Context, id string) (config.Agent, error)
	ListAgents(ctx context.Context) ([]config.Agent, error)
}

AgentStore is deliberately narrow, but includes list because collection filtering belongs at the PEP rather than in transports or SQL.

type AgentWriter

type AgentWriter interface {
	GetAgent(ctx context.Context, id string) (config.Agent, error)
	CreateAgent(ctx context.Context, a config.Agent) error
	UpdateAgent(ctx context.Context, a config.Agent) error
	DeleteAgent(ctx context.Context, id string) error
}

AgentWriter persists agent rows. config.Store satisfies it; the interface stays narrow so Management cannot reach unrelated aggregate config.

type AssignmentStore

type AssignmentStore interface {
	ListUserAgentIDs(ctx context.Context, userID string) ([]string, error)
}

type AssignmentWriter

type AssignmentWriter interface {
	AssignAgent(ctx context.Context, userID, agentID string) error
	RemoveAgent(ctx context.Context, userID, agentID string) error
	ListAgentUserIDs(ctx context.Context, agentID string) ([]string, error)
}

AssignmentWriter mutates and lists the user<->agent assignment relation. auth.AuthStore satisfies it.

type CredentialWriter added in v0.61.0

type CredentialWriter interface {
	List(ctx context.Context, agentID string) ([]providercred.Metadata, error)
	Set(ctx context.Context, agentID string, input providercred.Input) (providercred.Metadata, error)
	Delete(ctx context.Context, agentID, providerID string) error
	CreateAgentWithCredentials(ctx context.Context, agent config.Agent, inputs []providercred.Input) error
}

CredentialWriter is the Agent Provider credential encryption/persistence boundary. *providercred.Service satisfies it. Management authorizes and validates before delegating; it never sees plaintext after handing off.

type Management

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

Management owns the Agent write use cases: create/update/delete, admin user assignment, and the conversation-activity read model. Every method authorizes through the Agent PEP (Service) before any durable read or write, then performs the persistence, cross-write compensation, and best-effort runtime reload the HTTP transport used to orchestrate itself. Splitting these off the read-only Service keeps the PEP's decision surface narrow while giving the Agent domain a single owner for its mutating invariants (unique ID, creator auto-assignment atomicity, scope rules).

func NewManagement

func NewManagement(pep *Service, agents AgentWriter, assign AssignmentWriter, reloader AgentReloader, users UserDirectory, activity ActivityReader, creds CredentialWriter, providers ProviderReader, log *slog.Logger) *Management

NewManagement builds the Agent management service over the Agent PEP and its write/reload/lookup ports. log defaults to slog.Default() when nil.

func (*Management) AssignUser

func (m *Management) AssignUser(ctx context.Context, authority authz.Authority, agentID, userID string) (UserRef, error)

AssignUser assigns a user to an agent. Admin-only. It verifies the agent then the user exists (preserving the historical 404 order) before writing.

func (*Management) Create

func (m *Management) Create(ctx context.Context, authority authz.Authority, candidate config.Agent) (config.Agent, error)

Create authorizes and persists a new agent, enforcing the scope rules, generating a unique ID, and — for a restricted agent a non-admin creates — auto-assigning the creator. The create+auto-assign pair is atomic from the caller's view: a failed assignment compensates by deleting the just-created agent, so a restricted agent is never left invisible to its creator. The caller supplies a fully transport-validated candidate whose ID is the base slug; Management owns the scope decision, uniqueness, workspace, and creator.

func (*Management) CreateWithProviderCredentials added in v0.61.0

func (m *Management) CreateWithProviderCredentials(ctx context.Context, authority authz.Authority, candidate config.Agent, inputs []providercred.Input) (config.Agent, error)

CreateWithProviderCredentials creates an Agent together with per-Provider key overrides in one atomic persist. It shares Create's authorization, scope, and auto-assign compensation, adding canonical-Provider validation and encryption before the composite write. An empty inputs slice is equivalent to Create.

func (*Management) Delete

func (m *Management) Delete(ctx context.Context, authority authz.Authority, agentID string) error

Delete authorizes (Delete) and removes an agent. Reload is best-effort.

func (*Management) DeleteProviderCredential added in v0.61.0

func (m *Management) DeleteProviderCredential(ctx context.Context, authority authz.Authority, agentID, providerID string) error

DeleteProviderCredential removes an Agent Provider key override, restoring the global-key fallback. It requires Manage, is idempotent, and reloads only the affected Agent's runners after commit.

func (*Management) ListAgentLastActive

func (m *Management) ListAgentLastActive(ctx context.Context, userID string) (map[string]time.Time, error)

ListAgentLastActive returns the last-active time per agent for the given user's own conversations. It carries no additional authorization: the caller has already been list-authorized for the agents it enriches, and the read is scoped to that same user's activity.

func (*Management) ListAssignedUsers

func (m *Management) ListAssignedUsers(ctx context.Context, authority authz.Authority, agentID string) ([]UserRef, error)

ListAssignedUsers returns the account references for the users assigned to an agent. Admin-only: the gate runs before any durable read.

func (*Management) ListProviderCredentials added in v0.61.0

func (m *Management) ListProviderCredentials(ctx context.Context, authority authz.Authority, agentID string) ([]providercred.Metadata, error)

ListProviderCredentials returns secret-free credential metadata for an Agent. Read access is sufficient; only Set/Delete require Manage.

func (*Management) RemoveUser

func (m *Management) RemoveUser(ctx context.Context, authority authz.Authority, agentID, userID string) error

RemoveUser unassigns a user from an agent. Admin-only.

func (*Management) SetProviderCredential added in v0.61.0

func (m *Management) SetProviderCredential(ctx context.Context, authority authz.Authority, agentID string, input providercred.Input) (providercred.Metadata, error)

SetProviderCredential upserts (or rotates) one Agent Provider key override. It requires Manage, validates the target is a canonical configured Provider before any encryption, and reloads only the affected Agent's runners after commit.

func (*Management) Update

func (m *Management) Update(ctx context.Context, authority authz.Authority, candidate config.Agent) (config.Agent, error)

Update authorizes (Manage) and persists an agent edit. Scope is the agent's reach — system means every user may use it, restricted means only assigned users — and its manager decides it: an admin for any agent, the creator for their own. An empty scope keeps the persisted one for a creator and defaults to system for an admin (the historical create-shaped default); any other value is rejected. The caller supplies a transport-validated candidate; reload is best-effort.

type ProviderReader added in v0.61.0

type ProviderReader interface {
	ListProviderIDs(ctx context.Context) ([]string, error)
}

ProviderReader lists only canonical Provider IDs so Management can reject an alias or unconfigured Provider before encryption without reading global Provider config or its API key.

type Service

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

func NewService

func NewService(agents AgentStore, assign AssignmentStore) *Service

func (*Service) Authorize

func (s *Service) Authorize(ctx context.Context, authority authz.Authority, agentID string, action authz.Action) error

Authorize is the narrow cross-domain Agent port. It reads the durable Agent and applies the same direct Agent rules as the public access methods; a dedicated-channel binding is intentionally not inferred here.

func (*Service) AuthorizeViaChannelBinding

func (s *Service) AuthorizeViaChannelBinding(ctx context.Context, authority authz.Authority, agentID string) error

AuthorizeViaChannelBinding authorizes read/execute of agentID for a trusted dedicated-channel Authority: the exact held channel binding whose CURRENT persisted channel→agent binding names this exact agent. It is the Agent PEP's sole interpretation of a dedicated channel, so cross-domain callers (the session flow's Agent gate) never re-derive channel bindings themselves. A held binding alone is never authority for an arbitrary agent; every mismatch fails closed.

func (*Service) Begin

func (s *Service) Begin(_ context.Context, authority authz.Authority) (*Access, error)

func (*Service) CanCreate

func (s *Service) CanCreate(ctx context.Context, authority authz.Authority) error

func (*Service) CanList

func (s *Service) CanList(ctx context.Context, authority authz.Authority) error

func (*Service) CanUseAsUser added in v0.61.0

func (s *Service) CanUseAsUser(ctx context.Context, userID, agentID string) (bool, error)

CanUseAsUser evaluates one ordinary, non-admin user's current execute access. It is intended for trusted adapters validating a durable delegation before persisting it; callers receive only the decision, never a minted Authority.

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, authority authz.Authority, agentID string) (config.Agent, error)

func (*Service) ListReadable

func (s *Service) ListReadable(ctx context.Context, authority authz.Authority, deploymentWide bool) ([]config.Agent, error)

func (*Service) Manage

func (s *Service) Manage(ctx context.Context, authority authz.Authority, agentID string) (config.Agent, error)

func (*Service) Read

func (s *Service) Read(ctx context.Context, authority authz.Authority, agentID string) (config.Agent, error)

func (*Service) Use

func (s *Service) Use(ctx context.Context, authority authz.Authority, agentID string) (config.Agent, error)

type UserDirectory

type UserDirectory interface {
	LookupUser(ctx context.Context, userID string) (UserRef, error)
	LookupUsers(ctx context.Context, userIDs []string) ([]UserRef, error)
}

UserDirectory resolves assignment-target account display data. The composition root backs it with the account user store; LookupUsers skips IDs that no longer resolve so a stale assignment link never breaks the admin listing.

type UserRef

type UserRef struct {
	ID    string
	Email string
}

UserRef is the account display data an assignment view needs. It is a domain value, not an account row, so Management never depends on the Account boundary's internal shapes.

Jump to

Keyboard shortcuts

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