Documentation
¶
Overview ¶
Package access is the policy-enforcement point for Agent resources.
Index ¶
- Variables
- func GroupAgentAuthority(groupID, agentID string) (authz.Authority, error)
- func SystemAgentAuthority(component string) (authz.Authority, error)
- func WorkerAgentAuthority(ownerID, agentID string) (authz.Authority, error)
- type Access
- func (a *Access) CanCreate() error
- func (a *Access) CanList() error
- func (a *Access) CanUse(ctx context.Context, agentID string) (bool, error)
- func (a *Access) Delete(ctx context.Context, agentID string) (config.Agent, error)
- func (a *Access) ListReadable(ctx context.Context, deploymentWide bool) ([]config.Agent, error)
- func (a *Access) ListReadableSnapshots(ctx context.Context, deploymentWide bool) ([]config.AgentSnapshot, error)
- func (a *Access) Manage(ctx context.Context, agentID string) (config.Agent, error)
- func (a *Access) Read(ctx context.Context, agentID string) (config.Agent, error)
- func (a *Access) ReadSnapshot(ctx context.Context, agentID string) (config.AgentSnapshot, error)
- func (a *Access) Use(ctx context.Context, agentID string) (config.Agent, error)
- func (a *Access) UseDedicated(ctx context.Context, agentID, channelID string) (config.Agent, error)
- func (a *Access) UseDedicatedForType(ctx context.Context, agentID, channelID, channelType string) (config.Agent, error)
- type ActivityReader
- type AgentIDOccupancy
- type AgentReloader
- type AgentSnapshotStore
- type AgentStore
- type AgentWriter
- type AssignmentStore
- type AssignmentWriter
- type ConditionalAgentScopeWriter
- type ConditionalAgentWriter
- type ConditionalOwnerDeletion
- type CredentialWriter
- type Management
- func (m *Management) AssignUser(ctx context.Context, authority authz.Authority, agentID, userID string) (UserRef, error)
- func (m *Management) Create(ctx context.Context, authority authz.Authority, candidate config.Agent) (config.Agent, error)
- func (m *Management) CreateForTool(ctx context.Context, authority authz.Authority, candidate config.Agent) (ToolAgent, error)
- func (m *Management) CreateWithProviderCredentials(ctx context.Context, authority authz.Authority, candidate config.Agent, ...) (config.Agent, error)
- func (m *Management) Delete(ctx context.Context, authority authz.Authority, agentID string) error
- func (m *Management) DeleteIfVersion(ctx context.Context, authority authz.Authority, ...) error
- func (m *Management) DeleteProviderCredential(ctx context.Context, authority authz.Authority, agentID, providerID string) error
- func (m *Management) GetForTool(ctx context.Context, authority authz.Authority, agentID string) (ToolAgent, error)
- func (m *Management) ListAgentLastActive(ctx context.Context, userID string) (map[string]time.Time, error)
- func (m *Management) ListAssignedUsers(ctx context.Context, authority authz.Authority, agentID string) ([]UserRef, error)
- func (m *Management) ListForTool(ctx context.Context, authority authz.Authority, limit int) ([]ToolAgent, bool, error)
- func (m *Management) ListProviderCredentials(ctx context.Context, authority authz.Authority, agentID string) ([]providercred.Metadata, error)
- func (m *Management) ManageForTool(ctx context.Context, authority authz.Authority, agentID string) error
- func (m *Management) ReloadForTool(ctx context.Context, agentID string)
- func (m *Management) RemoveUser(ctx context.Context, authority authz.Authority, agentID, userID string) error
- func (m *Management) SetProviderCredential(ctx context.Context, authority authz.Authority, agentID string, ...) (providercred.Metadata, error)
- func (m *Management) Update(ctx context.Context, authority authz.Authority, candidate config.Agent) (config.Agent, error)
- func (m *Management) UpdateIfVersion(ctx context.Context, authority authz.Authority, candidate config.Agent, ...) (config.Agent, string, error)
- type ManagementOption
- type OwnerDeletion
- type ProviderReader
- type Service
- func (s *Service) Authorize(ctx context.Context, authority authz.Authority, agentID string, ...) error
- func (s *Service) AuthorizeViaChannelBinding(ctx context.Context, authority authz.Authority, agentID string) error
- func (s *Service) Begin(_ context.Context, authority authz.Authority) (*Access, error)
- func (s *Service) CanCreate(ctx context.Context, authority authz.Authority) error
- func (s *Service) CanList(ctx context.Context, authority authz.Authority) error
- func (s *Service) CanUseAsUser(ctx context.Context, userID, agentID string) (bool, error)
- func (s *Service) Delete(ctx context.Context, authority authz.Authority, agentID string) (config.Agent, error)
- func (s *Service) ListReadable(ctx context.Context, authority authz.Authority, deploymentWide bool) ([]config.Agent, error)
- func (s *Service) Manage(ctx context.Context, authority authz.Authority, agentID string) (config.Agent, error)
- func (s *Service) Read(ctx context.Context, authority authz.Authority, agentID string) (config.Agent, error)
- func (s *Service) Use(ctx context.Context, authority authz.Authority, agentID string) (config.Agent, error)
- type ToolAgent
- type UserDirectory
- type UserRef
Constants ¶
This section is empty.
Variables ¶
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 = errors.New("agent provider credentials are unavailable") // ErrConflict tells a model to re-read before making another destructive // decision. It never reports which competing caller changed the row. ErrConflict = errors.New("agent resource changed; re-read it before deciding") )
Management-specific typed errors. Authorization/availability reuse the Service sentinels (ErrForbidden / ErrNotFound / ErrUnavailable) so the transport maps every Agent error through one vocabulary.
var ( ErrForbidden = errors.New("agent access forbidden") ErrNotFound = errors.New("agent not found") )
Functions ¶
func GroupAgentAuthority ¶
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 ¶
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.
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) ListReadable ¶
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) ListReadableSnapshots ¶
func (a *Access) ListReadableSnapshots(ctx context.Context, deploymentWide bool) ([]config.AgentSnapshot, error)
ListReadableSnapshots applies the same PEP collection rule as ListReadable, retaining each authorized Agent's version from the exact row that supplied its projection. No management adapter repeats the policy or re-reads versions.
func (*Access) ReadSnapshot ¶
ReadSnapshot applies the ordinary Agent PEP read decision to a single durable snapshot. The policy stays centralized here while Agent tools receive a value and CAS version that cannot be mixed across rows or reads.
func (*Access) UseDedicated ¶
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 ¶
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 AgentIDOccupancy ¶
AgentIDOccupancy checks the deterministic global Agent workspace entry.
type AgentReloader ¶
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 AgentSnapshotStore ¶
type AgentSnapshotStore interface {
GetAgentSnapshot(ctx context.Context, id string) (config.AgentSnapshot, error)
ListAgentSnapshots(ctx context.Context) ([]config.AgentSnapshot, error)
}
AgentSnapshotStore supplies coherent Agent Settings values and conditional versions. It is deliberately optional for the general PEP, but model-facing management reads fail closed unless this store capability is wired.
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 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 ConditionalAgentScopeWriter ¶
type ConditionalAgentScopeWriter interface {
UpdateAgentIfVersionAndAssignCreator(context.Context, config.Agent, string, string) (string, error)
}
ConditionalAgentScopeWriter commits the one scope transition that needs a creator assignment as one durable unit, serialized with administrative revocations of that same assignment.
type ConditionalAgentWriter ¶
type ConditionalAgentWriter interface {
UpdateAgentIfVersion(context.Context, config.Agent, string) (string, error)
}
ConditionalAgentWriter is the narrow store port used only by model-facing management tools. HTTP retains its existing unconditional write contract.
type ConditionalOwnerDeletion ¶
type ConditionalOwnerDeletion interface {
DeleteAgentIfVersion(context.Context, string, string, string) error
}
ConditionalOwnerDeletion keeps a tool's version comparison inside the Home owner fence and the durable delete transaction.
type CredentialWriter ¶
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, opts ...ManagementOption) *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) CreateForTool ¶
func (m *Management) CreateForTool(ctx context.Context, authority authz.Authority, candidate config.Agent) (ToolAgent, error)
CreateForTool runs the normal no-credential creation path, then returns a freshly PEP-authorized snapshot so the displayed fields and version stay bound even if another admin changes the new Agent before this response is rendered.
func (*Management) CreateWithProviderCredentials ¶
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) DeleteIfVersion ¶
func (m *Management) DeleteIfVersion(ctx context.Context, authority authz.Authority, agentID, expectedVersion string) error
DeleteIfVersion removes an Agent only when the Home lifecycle still sees the exact durable version the tool read.
func (*Management) DeleteProviderCredential ¶
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) GetForTool ¶
func (m *Management) GetForTool(ctx context.Context, authority authz.Authority, agentID string) (ToolAgent, error)
GetForTool returns the Agent PEP-authorized projection and CAS version from one durable row read. It never pairs an Agent authorized in one read with a version fetched later, which could let a stale tool result overwrite a UI edit.
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) ListForTool ¶
func (m *Management) ListForTool(ctx context.Context, authority authz.Authority, limit int) ([]ToolAgent, bool, error)
ListForTool applies the Agent PEP before capping coherent projections.
func (*Management) ListProviderCredentials ¶
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) ManageForTool ¶
func (m *Management) ManageForTool(ctx context.Context, authority authz.Authority, agentID string) error
ManageForTool verifies the target Agent before a related resource such as a tool override is inspected or changed.
func (*Management) ReloadForTool ¶
func (m *Management) ReloadForTool(ctx context.Context, agentID string)
ReloadForTool invalidates only the target runner after a tool-override write.
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 ¶
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.
func (*Management) UpdateIfVersion ¶
func (m *Management) UpdateIfVersion(ctx context.Context, authority authz.Authority, candidate config.Agent, expectedVersion string) (config.Agent, string, error)
UpdateIfVersion applies the normal Agent policy, then commits with the exact version the tool read. Its empty expected value is invalid here; HTTP uses Update and keeps its unconditional semantics.
type ManagementOption ¶
type ManagementOption func(*Management)
ManagementOption configures optional Management dependencies.
func WithAgentIDOccupancy ¶
func WithAgentIDOccupancy(checker AgentIDOccupancy) ManagementOption
func WithOwnerDeletion ¶
func WithOwnerDeletion(d OwnerDeletion) ManagementOption
WithOwnerDeletion supplies the destructive Home lifecycle for Agent deletion.
type OwnerDeletion ¶
OwnerDeletion is the destructive Agent lifecycle boundary. A nil dependency keeps construction source-compatible but makes Delete fail closed.
type ProviderReader ¶
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) CanUseAsUser ¶
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) ListReadable ¶
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.