Help us shape the future of Go! Take the 2026 Go Developer Survey

skillaccess

package
v0.65.0 Latest Latest
Warning

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

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

Documentation

Overview

Package skillaccess owns the direct authorization rules for DB-backed Skill resources. Every skill-row read, write, delete, and scope-management decision flows through this domain, under a trusted authz.Authority that no request/model input can forge:

  • HTTP transports call the Begin/Authorize* methods with the caller's Authority;
  • the agent skills tool reaches read decisions through the consumer-owned skills.SkillReadAuthorizer port, which reconstructs the turn/worker identity from context — a user or delegated agent, or a confined GroupAgentActor for a group turn;
  • reflect's staged skill reconciliation and usage curation authorize each write through AuthorizeWorkerWrite under a fresh WorkerAgentAuthority.

Filesystem project/system skills merged read-only by internal/skills are not DB rows and are not security-sensitive; they are outside this PEP's scope.

Index

Constants

View Source
const (
	ScopeUser        = "user"
	ScopeUserAgent   = "user_agent"
	ScopeSystem      = "system"
	ScopeSystemAgent = "system_agent"
)

The four durable skill scopes (the DB scope column). system and system_agent are admin-managed; user and user_agent are owned by their user.

Variables

View Source
var (
	ErrForbidden    = errors.New("skill access forbidden")
	ErrNotFound     = errors.New("skill not found")
	ErrUnavailable  = errors.New("skill authorization unavailable")
	ErrInvalidScope = errors.New("invalid skill scope")
)

Errors returned by the Skill access rules. Denials on user-owned scopes are opaque (ErrNotFound, 404) so a foreign skill cannot be told from a missing one; admin-managed system scopes surface ErrForbidden (403).

Functions

This section is empty.

Types

type Access

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

Access captures one validated authority for a Skill use case. Skill owns the direct rules for DB-backed skill rows; every decision reads only immutable authority plus the durable row/scope facts, so there is no revision to re-read between use cases.

func (*Access) AuthorizeAgent

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

AuthorizeAgent folds the route agent's read gate into this use case. The agent-scoped skill endpoints reach a skill through /api/agents/{id}/skills, so the path agent {id} is gated alongside the skill decision, for every scope — including user and system DB skills whose own row is not agent-bound. This replaces the preliminary requireAgentAccess split evaluation.

func (*Access) AuthorizeList

func (a *Access) AuthorizeList() error

AuthorizeList authorizes the collection-level skill list. Per-scope and per-row visibility is decided separately in the same use case (AuthorizeManageScope / AuthorizeManage).

func (*Access) AuthorizeManage

func (a *Access) AuthorizeManage(ctx context.Context, sk skills.Skill, action authz.Action) error

AuthorizeManage authorizes an action on one already-loaded skill row. Reading, writing, or deleting a user/user_agent skill requires the acting user to own it (else the denial is opaque, ErrNotFound); any action on an admin-managed system/system_agent skill requires the admin superuser (ErrForbidden). For agent-bound scopes the caller's read access to the skill's agent is folded in.

func (*Access) AuthorizeManageByID

func (a *Access) AuthorizeManageByID(ctx context.Context, id string, action authz.Action) (skills.Skill, error)

AuthorizeManageByID loads a skill row by id and authorizes an action on it. A missing row is opaque (ErrNotFound). It returns the loaded row so the caller can perform the store mutation it just authorized.

func (*Access) AuthorizeManageScope

func (a *Access) AuthorizeManageScope(ctx context.Context, scope, agentID string) (uid, aid string, err error)

AuthorizeManageScope authorizes managing a whole scope bucket — create, install, upload, or the scope-keyed management list — and returns the owner columns a row of that scope carries. user/user_agent require the acting user to be the owner (always true here); system/system_agent require the admin superuser. When agentID is non-empty the caller's read access to that agent is folded in (the former requireAgentAccess gate).

The management-list reuses this create-authority decision deliberately: the pre-cutover resolveSkillManageScope was the single gate for both listing and creating a scope, so denying a scope also hides its list.

func (*Access) AuthorizeRead

func (a *Access) AuthorizeRead(ctx context.Context, sk skills.Skill) error

AuthorizeRead authorizes reading one DB-backed skill row through the resolve/ list surface (agent skills tool, agent HTTP list/get/file). Unlike AuthorizeManage it uses ActionRead without escalating system scopes to Manage, so a user or delegated agent may read shared system/system_agent procedures while a since-revoked agent grant still hides the row. For agent-bound scopes the caller's read access to the skill's agent is folded in. A user-scope denial is opaque (ErrNotFound); a system-scope denial is ErrForbidden — the caller decides whether to skip (list) or 404 (single load).

type Service

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

Service is the composition-root-owned Skill authorization domain. It holds the narrow skill read port and the Agent-domain gate (to fold an agent-read check into a skill decision).

func NewService

func NewService(store SkillStore, agents *agentaccess.Service) *Service

NewService constructs the Skill authorization domain. agents is the Agent-domain gate; store is the read port used to load a row for a by-id decision.

func (*Service) AuthorizeWorkerWrite

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

AuthorizeWorkerWrite authorizes a durable worker's write to a reflect-owned user_agent skill under a freshly reconstructed WorkerAgentAuthority(userID, agentID). create=true authorizes minting a new row (scope create); otherwise it authorizes writing the existing skillID. It is the single reauthorization point for reflect's staged skill reconciliation and usage curation, so a since-revoked agent grant stops the write.

func (*Service) Begin

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

Begin captures validated authority for one Skill use case.

func (*Service) BeginRead

func (s *Service) BeginRead(ctx context.Context) (skills.SkillReadDecision, error)

BeginRead implements skills.SkillReadAuthorizer for the skills tool. It derives the trusted turn/worker identity from the runtime context (an agent turn or the reflect reviewer's WithUserID+WithAgentID review context, both of which ToAuthority resolves to an AgentActor — the same shape as a reconstructed WorkerAgentAuthority) and returns a per-row read decider. A missing/invalid identity fails closed. Writes never flow through this path.

type SkillStore

type SkillStore interface {
	GetIdentity(ctx context.Context, id string) (*skills.Skill, error)
}

SkillStore is the identity-only port the PEP uses before any mutable Home bytes or lifecycle metadata are opened.

Jump to

Keyboard shortcuts

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