access

package
v1.0.0-rc.7 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package access owns who may do what (design/subsystems/ authorization-capabilities.md): the capability catalog and the stock roles as compiled data, the words for scopes and subjects, and, in the slices that follow, the decision rule, grants and the directory. AppTown keeps the HTTP doors, the receipts' prose and the resource adapters.

Package access is the authorization rule and its vocabulary: who is asking (principal, caller), what they want (capability, resource, permission), the catalog of capabilities and stock roles, the decision, and the denial. It owns no tables, reads no database, and imports nothing of AppTown, so a decision is testable on its own.

Index

Constants

View Source
const (
	ViaSession    = "session"
	ViaHeader     = "header"
	ViaOpen       = "open"
	ViaTokenCLI   = "token-cli"
	ViaTokenAgent = "token-agent"
	ViaOAuth      = "oauth"
	ViaChat       = "chat"
	ViaRunStep    = "run-step"
	ViaTicket     = "ticket"
	ViaBinding    = "binding"
	ViaSchedule   = "schedule"
	ViaEval       = "eval"
	ViaWhatIf     = "what-if"
	ViaAnonymous  = "anonymous"
)

The ways of acting an actor's Via names. A way with a subject is "<way>:<subject>" (token-cli:laptop, chat:<id>, run-step:<step>).

View Source
const (
	RoleInstanceAdmin     = "instance-administrator"
	RoleStandardsAdmin    = "standards-administrator"
	RoleExecutionAdmin    = "execution-administrator"
	RoleIntegrationAdmin  = "integration-administrator"
	RoleReleaseManager    = "release-manager"
	RoleAuditor           = "auditor"
	RoleProjectCreator    = "project-creator"
	RoleGroupViewer       = "group-viewer"
	RoleGroupMember       = "group-member"
	RoleGroupCreator      = "group-project-creator"
	RoleGroupMaintainer   = "group-maintainer"
	RoleGroupOwner        = "group-owner"
	RoleGroupAuditor      = "group-auditor"
	RoleProjectViewer     = "project-viewer"
	RoleProjectContrib    = "project-contributor"
	RoleProjectMaintainer = "project-maintainer"
	RoleProjectApprover   = "project-approver"
	RoleProjectOwner      = "project-owner"
)

Stock role names.

View Source
const (
	DenyMissingCapability = "missing_capability"
	DenyOutsideScope      = "outside_scope"
	DenyDelegationNarrow  = "delegation_too_narrow"
	DenyResourceState     = "resource_state_conflict"
	DenySegregation       = "segregation_of_duties"
	DenyQuorum            = "quorum_incomplete"
	DenyReauth            = "reauthentication_required"
	DenyExpiredObjectCap  = "expired_object_capability"
	DenyAccountDisabled   = "account_disabled"
	DenyNotEligible       = "not_an_approver"
)

The authorization decision (authorization-capabilities.md §12). One rule for every protocol: HTTP guards, the MCP server, the CLI and workers all call Decide and translate its one answer. Root is explicit; other roles are bundles the catalog expands. The rule reads what it needs through Facts, so a decision is testable with no database and the reads happen exactly when the rule asks (grants only after an instrument has been resolved to its person).

Reason codes are stable so a client can act on them; the prose is for the person.

View Source
const (
	TokenCLI   = "cli"
	TokenAgent = "agent"
)

Personal token purposes: every token is made with one, never by default.

View Source
const SystemInstrument = "apptown"

SystemInstrument is the instrument AppTown acts under itself: its scheduler, engine, remediation, follow-ups, bindings and system operations. Records from before the AppTown rename name it "forge"; those are history and keep that name, but no current caller carries it.

Variables

View Source
var Definitions = map[Capability]Definition{
	CapInstanceReadPublic: {"read the explicitly public instance surface", readInherits, "read"},
	CapInstitutionRead:    {"see users, groups, roles and grants", nil, "read"},

	CapProjectList:          {"discover visible projects", readInherits, "read"},
	CapProjectRead:          {"read one project's source-facing state", readInherits, "read"},
	CapProjectCreate:        {"create a project for an allowed owning group", []ScopeKind{ScopeGroup}, "mutate"},
	CapProjectConfigure:     {"change ordinary project metadata", nil, "mutate"},
	CapProjectDelete:        {"permanently remove a project", nil, "admin"},
	CapProjectManageMembers: {"change a project's roster and project roles", nil, "admin"},
	CapProjectImport:        {"import an external branch or tree", nil, "mutate"},

	CapChangeList:          {"list changes", readInherits, "read"},
	CapChangeRead:          {"read a change", readInherits, "read"},
	CapChangeCreate:        {"open a change", nil, "mutate"},
	CapChangeUpdateBrief:   {"edit a change's brief", nil, "mutate"},
	CapChangeNarrative:     {"refresh a change's So far summary", nil, "mutate"},
	CapChangeWriteRevision: {"contribute source revisions to a change", nil, "mutate"},
	CapChangeAttach:        {"attach evidence to a change", nil, "mutate"},
	CapChangeRunChecks:     {"run a change's checks", nil, "mutate"},
	CapChangePreview:       {"boot a change's preview", nil, "mutate"},
	CapChangeInvokeLane:    {"start an allowed lane on a change", nil, "mutate"},
	CapChangeSendBack:      {"send a change back to its author", nil, "mutate"},
	CapChangeAbandon:       {"abandon a change", nil, "mutate"},
	CapChangeRequestLand:   {"hand a proposed tip off for landing", nil, "mutate"},
	CapChangeLand:          {"operate a landing attempt: restart, resume, complete an unapproved lane", nil, "mutate"},
	CapChangeApprove:       {"assent at an approval step", nil, "approve"},
	CapChangeOverride:      {"bypass a failed gate with a reason", nil, "approve"},

	CapRunRead: {"read a run", readInherits, "read"},

	CapRunOperate:      {"advance, retry or stop a run", nil, "mutate"},
	CapEvidenceRead:    {"read evidence", readInherits, "read"},
	CapEvidenceAttach:  {"attach evidence to a run", nil, "mutate"},
	CapConformanceRead: {"read conformance", readInherits, "read"},
	CapConformanceRev:  {"run a read-only conformance review", nil, "mutate"},
	CapConformanceAI:   {"confirm one exact AI verdict", nil, "approve"},
	CapConformanceFix:  {"start a remediation", nil, "mutate"},

	CapExceptionApprove: {"approve a conformance exception in a dimension", nil, "approve"},
	CapExceptionRevoke:  {"revoke a conformance exception", nil, "approve"},

	CapProjectWayOfWorking: {"select the project's way of working", nil, "execute"},
	CapProjectGuidance:     {"change what guidance the project adopts", nil, "execute"},
	CapProjectServices:     {"change the project's attached services", nil, "execute"},
	CapProjectIntegrations: {"attach or wire integrations to the project", nil, "execute"},
	CapProjectModelProfile: {"choose the project's model profile", nil, "execute"},
	CapProjectWorkflow:     {"select or change the project's workflow copy", nil, "execute"},
	CapReleaseRead:         {"read releases", readInherits, "read"},
	CapReleasePromote:      {"promote a release to a wider tier", nil, "release"},
	CapDeploymentRead:      {"read deployments", readInherits, "read"},
	CapDeploymentOperate:   {"restart or rebuild a deployment, and read its parts' recent logs", nil, "mutate"},
	CapDeploymentBind:      {"point a standing deployment at a target", nil, "mutate"},
	CapDeploymentDeploy:    {"ship a bundle to a standing deployment", nil, "release"},
	CapDeploymentTeardown:  {"remove a deployment's deployment (never its data)", nil, "mutate"},
	CapDeploymentRestore:   {"fill a deployment's data from a copy, or check a copy comes back", nil, "mutate"},

	CapIdentityUsers:  {"manage user accounts", nil, "admin"},
	CapIdentityGroups: {"manage groups", nil, "admin"},
	CapIdentityAuth:   {"manage authentication settings", nil, "admin"},

	CapAuthzGrants:       {"grant and revoke roles and capabilities", nil, "admin"},
	CapStandardsGuidance: {"edit the guidance library", nil, "execute"},
	CapStandardsPacks:    {"edit packs", nil, "execute"},
	CapStandardsPolicies: {"edit policies and the policy library", nil, "execute"},
	CapStandardsEvals:    {"read evals of models and pack versions", nil, "read"},
	CapExecWorkflows:     {"edit workflow definitions", nil, "execute"},

	CapIntegrationConnector: {"manage connectors and provider bindings", nil, "admin"},
	CapIntegrationServices:  {"manage service kinds", nil, "execute"},
	CapIntegrationDeps:      {"manage dependency kinds", nil, "execute"},
	CapModelsBindings:       {"manage model provider bindings", nil, "admin"},
	CapModelsSlots:          {"manage model slots", nil, "admin"},
	CapPlatformTargets:      {"manage deploy targets", nil, "admin"},

	CapPlatformOperate: {"operate the platform", nil, "admin"},
	CapAuditRead:       {"read the audit log", readInherits, "read"},

	CapSecretRead:   {"read secret declarations and bindings (names, stores, versions; never values)", readInherits, "read"},
	CapSecretBind:   {"bind a project's secrets to a store, put a value into the built-in store, choose a deployment's profile", nil, "mutate"},
	CapSecretReveal: {"reveal a secret's value held by the built-in store, on the record (administrators only)", nil, "mutate"},
}
View Source
var ErrAuthorityUnavailable = errors.New("access authority is not configured")

ErrAuthorityUnavailable: no authority was supplied to the check.

View Source
var ErrGrantRevoked = errors.New("grant already revoked")
View Source
var ErrPrincipalRequired = fault.New(fault.Unauthenticated, "a verified principal is required")
View Source
var Scopes = []Scope{
	{"apptown:user:read", "read your projects, Changes, checks, evidence and runs", ReadCaps},
	{"apptown:change:create", "open Changes in your name", []Capability{CapChangeCreate, CapChangeUpdateBrief, CapChangeNarrative}},
	{"apptown:change:write", "push revisions to Changes you may write", []Capability{CapChangeWriteRevision}},
	{"apptown:change:check", "run a Change's checks", []Capability{CapChangeRunChecks}},
	{"apptown:change:preview", "boot a Change's preview", []Capability{CapChangePreview}},
	{"apptown:change:request-land", "hand a Change off for approval", []Capability{CapChangeRequestLand}},
	{"apptown:evidence:attach", "attach evidence to a Change", []Capability{CapChangeAttach, CapEvidenceAttach}},

	{"apptown:project:create", "create projects in your name", []Capability{CapProjectCreate}},
	{"apptown:change:run", "put AppTown's own agent to work on a Change", []Capability{CapChangeInvokeLane}},
	{"apptown:change:return", "send a Change back with a note, or abandon it", []Capability{CapChangeSendBack, CapChangeAbandon}},
}
View Source
var StockRoles = []Role{
	{Name: RoleInstanceAdmin, Title: "Instance administrator", Scope: ScopeInstance, Surfaced: true,
		Description: "The sovereign: holds every capability on this instance.", Caps: AllCapabilities()},
	{Name: RoleStandardsAdmin, Title: "Standards administrator", Scope: ScopeInstance,
		Description: "Manages guidance, packs and policies (the amender).",
		Caps:        []Capability{CapStandardsGuidance, CapStandardsPacks, CapStandardsPolicies, CapStandardsEvals}},
	{Name: RoleExecutionAdmin, Title: "Execution administrator", Scope: ScopeInstance,
		Description: "Manages executable workflow definitions.",
		Caps:        []Capability{CapExecWorkflows}},
	{Name: RoleIntegrationAdmin, Title: "Integration administrator", Scope: ScopeInstance,
		Description: "Manages connectors, service and dependency kinds, model bindings.",
		Caps:        []Capability{CapIntegrationConnector, CapIntegrationServices, CapIntegrationDeps, CapModelsBindings, CapModelsSlots}},
	{Name: RoleReleaseManager, Title: "Release manager", Scope: ScopeInstance, Surfaced: false,
		Description: "Promotes releases to wider tiers (the releaser).",
		Caps:        []Capability{CapReleaseRead, CapReleasePromote, CapDeploymentRead, CapDeploymentDeploy}},
	{Name: RoleAuditor, Title: "Auditor", Scope: ScopeInstance,
		Description: "Reads everything, changes nothing.",
		Caps:        append(append([]Capability{}, ReadCaps...), CapInstitutionRead, CapAuditRead, CapStandardsEvals)},
	{Name: RoleProjectCreator, Title: "Project creator", Scope: ScopeInstance, Surfaced: true,
		Description: "Creates projects through approved creation profiles.",
		Caps:        []Capability{CapProjectCreate, CapProjectList}},

	{Name: RoleGroupViewer, Title: "Group viewer", Scope: ScopeGroup,
		Description: "Discovers projects visible through this group.", Caps: []Capability{CapProjectList}},
	{Name: RoleGroupMember, Title: "Group member", Scope: ScopeGroup, Surfaced: true,
		Description: "Belongs to the group. Carries no project capability by itself.", Caps: []Capability{}},
	{Name: RoleGroupCreator, Title: "Group project creator", Scope: ScopeGroup,
		Description: "Creates projects owned by the group.", Caps: []Capability{CapProjectCreate}},
	{Name: RoleGroupMaintainer, Title: "Group maintainer", Scope: ScopeGroup,
		Description: "Reserved group office; currently carries no operation permissions.",
		Caps:        []Capability{}},
	{Name: RoleGroupOwner, Title: "Group owner", Scope: ScopeGroup, Surfaced: true,
		Description: "Creates projects owned by the group.",
		Caps:        []Capability{CapProjectCreate}},
	{Name: RoleGroupAuditor, Title: "Group auditor", Scope: ScopeGroup,
		Description: "Reads projects and evidence visible through this group.",
		Caps:        append(append([]Capability{}, ReadCaps...), CapAuditRead)},

	{Name: RoleProjectViewer, Title: "Project viewer", Scope: ScopeProject, Surfaced: true,
		Description: "Reads the project, its changes, runs, evidence and deployments.", Caps: ReadCaps},
	{Name: RoleProjectContrib, Title: "Project contributor", Scope: ScopeProject, Surfaced: true,
		Description: "Opens changes, contributes revisions, runs checks, previews, hands off for landing.",
		Caps:        ContributorCaps},
	{Name: RoleProjectMaintainer, Title: "Project maintainer", Scope: ScopeProject, Surfaced: true,
		Description: "Contributor plus landing, abandoning, operating runs and deployments, and project configuration.",
		Caps:        MaintainerCaps},
	{Name: RoleProjectApprover, Title: "Project approver", Scope: ScopeProject, Surfaced: true,
		Description: "Approves at approval steps that name them. Need not write code or land.",
		Caps:        append(append([]Capability{}, ReadCaps...), CapChangeApprove, CapChangeOverride, CapExceptionApprove, CapExceptionRevoke)},
	{Name: RoleProjectOwner, Title: "Project owner", Scope: ScopeProject, Surfaced: true,
		Description: "Maintainer plus membership, configuration and deletion authority.",
		Caps:        OwnerCaps},
}

Functions

func AgentCredential

func AgentCredential(pr Principal) bool

AgentCredential reports a coding agent's credential: an OAuth delegation or an agent token. An act a person may do for themselves without any capability (disconnecting their own connections) still needs the person.

func AgentToken

func AgentToken(pr Principal) bool

AgentToken reports an agent-purpose personal token.

func CredentialCovers

func CredentialCovers(pr Principal, c Capability) bool

CredentialCovers is the agent bound every authority check applies before grants. An agent's credential, an OAuth delegation or an agent-purpose personal token, reaches only the scope catalogue: an OAuth delegation its consented scopes, an agent token every scope. No scope covers approving, landing or administration, so an agent never inherits those from its person. Every other credential is not narrowed here.

func CredentialNarrowReason

func CredentialNarrowReason(pr Principal, does string) string

CredentialNarrowReason says why CredentialCovers refused.

func GrantApplies

func GrantApplies(g Grant, c Capability, res Resource) bool

GrantApplies is §3: a grant sits at a scope and covers the resources inside it; instance and group grants reach down into projects only for the capabilities the catalog marks inheritable.

func GrantHolds

func GrantHolds(g Grant, c Capability) bool

GrantHolds reports whether a grant carries a capability, directly or through its role.

func Inherits

func Inherits(c Capability, to ScopeKind) bool

Inherits reports whether a grant at `from` (instance or group) reaches a resource whose scope chain includes `to`.

func InstrumentMay

func InstrumentMay(kind string, c Capability) bool

InstrumentMay is §11's table as a question.

func RolesCarrying

func RolesCarrying(c Capability, res Resource) []string

RolesCarrying names the surfaced roles that bundle c at the resource's natural scope, for the "how to get it" half of a denial.

func ScopeMeans

func ScopeMeans(name string) string

func ScopeNames

func ScopeNames() []string

func ScopesCover

func ScopesCover(scopes []string, c Capability) bool

ScopesCover: does a delegation's scope list reach a capability? Reads are covered by any scope (a client that may write may look).

func ValidTokenPurpose

func ValidTokenPurpose(p string) bool

ValidTokenPurpose reports whether p is a purpose a token may be made with.

func WithCaller

func WithCaller(ctx context.Context, c Caller) context.Context

Types

type Actor

type Actor struct {
	Principal ids.ID `json:"principal,omitzero"`
	Name      string `json:"name"`
	Via       string `json:"via,omitempty"`
}

Actor is who an act is recorded against (design/decisions/mergeable-forge-data.md): the principal who answers for it, the name as shown when it happened, and how they acted. An absent actor is all empty; an anonymous act has no principal and Via "anonymous"; a name read without its principal keeps the name and no principal. Nothing invents a principal.

func ActorFrom

func ActorFrom(ctx context.Context, name string) Actor

ActorFrom is the actor an act by name is recorded against: the verified caller in ctx when it is the one named (its receipt or principal name), with its principal and way of acting; otherwise the name alone, with no principal, since a name is never taken for a principal.

func (Actor) Assents

func (a Actor) Assents() bool

Assents says whether the act is a person's own assent: acting directly — a session, a trusted header, open mode or their command-line token. Through a chat, a run step, an agent token, an OAuth client, a ticket or an eval, the same person's act is not their assent. It judges the way of acting; who the person is, is the principal's to say.

func (Actor) Shown

func (a Actor) Shown(now Person, systemName func(string) bool) string

Shown is how an actor reads in history (design/decisions/mergeable-forge-data.md): the person's name today; "(then x)" when they were written as another name; "disabled" for a disabled account; "former user (was: x)" for a removed one. An act with no principal reads as it was written — the AppTown's own names, an instrument — and as "unrecorded actor (written as: x)" when it names a person AppTown never resolved.

func (Actor) Way

func (a Actor) Way() string

Way is the way of acting without its subject: "token-cli" of "token-cli:laptop".

type Authority

type Authority interface {
	Require(context.Context, Principal, Permission) (Principal, error)
}

Authority is the checked Access contract. Consumers declare their own matching interface; no consumer receives a store or a permission cache.

type Authorizer

type Authorizer interface {
	Require(context.Context, Permission) (Caller, error)
}

type Caller

type Caller struct {
	Principal Principal
	Verified  bool
	Receipt   string
}

Caller separates authenticated provenance from receipt attribution. Transports and explicit internal orchestration establish it; command inputs cannot.

func CallerFrom

func CallerFrom(ctx context.Context) (Caller, bool)

type Capability

type Capability string

Capability is a stable domain verb, resource:verb. It names an act, never an HTTP route or a button.

const (
	CapInstanceReadPublic Capability = "instance:read-public"
	CapInstitutionRead    Capability = "institution:read-structure"

	CapProjectList          Capability = "project:list"
	CapProjectRead          Capability = "project:read"
	CapProjectCreate        Capability = "project:create"
	CapProjectConfigure     Capability = "project:configure"
	CapProjectDelete        Capability = "project:delete"
	CapProjectManageMembers Capability = "project:manage-members"
	CapProjectImport        Capability = "project:import"

	CapChangeList        Capability = "change:list"
	CapChangeRead        Capability = "change:read"
	CapChangeCreate      Capability = "change:create"
	CapChangeUpdateBrief Capability = "change:update-brief"
	// CapChangeNarrative writes a change's "So far" summary (and a title
	// nobody chose), never the person-written brief. AppTown's own engine
	// holds it, so its automatic refreshes publish.
	CapChangeNarrative     Capability = "change:write-narrative"
	CapChangeWriteRevision Capability = "change:write-revision"
	CapChangeAttach        Capability = "change:attach-evidence"
	CapChangeRunChecks     Capability = "change:run-checks"
	CapChangePreview       Capability = "change:preview"
	CapChangeInvokeLane    Capability = "change:invoke-lane"
	CapChangeSendBack      Capability = "change:send-back"
	CapChangeAbandon       Capability = "change:abandon"
	CapChangeRequestLand   Capability = "change:request-land"
	CapChangeLand          Capability = "change:land"
	CapChangeApprove       Capability = "change:approve"
	CapChangeOverride      Capability = "change:override"

	CapRunRead Capability = "run:read"

	CapRunOperate      Capability = "run:operate"
	CapEvidenceRead    Capability = "evidence:read"
	CapEvidenceAttach  Capability = "evidence:attach"
	CapConformanceRead Capability = "conformance:read"
	CapConformanceRev  Capability = "conformance:review"
	CapConformanceAI   Capability = "conformance:confirm-ai"
	CapConformanceFix  Capability = "conformance:remediate"

	CapExceptionApprove Capability = "exception:approve"
	CapExceptionRevoke  Capability = "exception:revoke"

	CapProjectWayOfWorking Capability = "project:select-way-of-working"
	CapProjectGuidance     Capability = "project:configure-guidance"
	CapProjectServices     Capability = "project:configure-services"
	CapProjectIntegrations Capability = "project:configure-integrations"
	CapProjectModelProfile Capability = "project:configure-model-profile"
	CapProjectWorkflow     Capability = "project:configure-workflow"
	CapReleaseRead         Capability = "release:read"
	CapReleasePromote      Capability = "release:promote"
	CapDeploymentRead      Capability = "deployment:read"
	CapDeploymentOperate   Capability = "deployment:operate"
	// The deployment verbs (design/subsystems/deployment.md).
	CapDeploymentBind     Capability = "deployment:bind-target"
	CapDeploymentDeploy   Capability = "deployment:deploy"
	CapDeploymentTeardown Capability = "deployment:teardown"
	// CapDeploymentRestore fills a deployment's data from a copy, or checks
	// a copy comes back (design/subsystems/deployment.md). It is
	// checked in the copy's project and in the destination's; no scope
	// carries it, so an agent never does.
	CapDeploymentRestore Capability = "deployment:restore"

	CapIdentityUsers  Capability = "identity:manage-users"
	CapIdentityGroups Capability = "identity:manage-groups"
	CapIdentityAuth   Capability = "identity:manage-auth"

	CapAuthzGrants       Capability = "authorization:manage-grants"
	CapStandardsGuidance Capability = "standards:manage-guidance"
	CapStandardsPacks    Capability = "standards:manage-packs"
	CapStandardsPolicies Capability = "standards:manage-policies"
	// CapStandardsEvals reads evals: how a model or pack version did against
	// what projects run now. A read, so an agent may hold it through its
	// person; starting one stays with standards:manage-packs.
	CapStandardsEvals Capability = "standards:read-evals"
	CapExecWorkflows  Capability = "execution:manage-workflows"

	CapIntegrationConnector Capability = "integration:manage-connectors"
	CapIntegrationServices  Capability = "integration:manage-service-kinds"
	CapIntegrationDeps      Capability = "integration:manage-dependency-kinds"
	CapModelsBindings       Capability = "models:manage-bindings"
	CapModelsSlots          Capability = "models:manage-slots"
	CapPlatformTargets      Capability = "platform:manage-deploy-targets"

	CapPlatformOperate Capability = "platform:operate"
	CapAuditRead       Capability = "audit:read"

	// Secrets: reading declarations and binding
	// status is a read; binding a secret to a store, putting a value into
	// the built-in store and choosing a deployment's profile is one
	// mutate capability. Values are never readable.
	CapSecretRead   Capability = "secret:read"
	CapSecretBind   Capability = "secret:bind"
	CapSecretReveal Capability = "secret:reveal"
)

Capability names, grouped as the design lists them.

func AllCapabilities

func AllCapabilities() []Capability

AllCapabilities is the sorted catalog, for the sovereign role and the API.

type Channel

type Channel struct {
	Kind string // full-breadth | cli-token | agent-token | instrument | anonymous | oauth
	ID   string
}

Channel bounds what the channel may exercise of the person's authority. Sessions are "full breadth" (§1): no narrowing beyond current grants. A command-line token is bounded by the role it was made with.

func DelegationOf

func DelegationOf(pr Principal) Channel

DelegationOf is the channel's bound, from the principal's provenance.

type Checked

type Checked struct {
	Authority Authority
	Projects  ProjectResources
}

Checked completes a domain's resource and asks the existing authority. It has no database, permission cache, or dependency on an application or domain.

func (Checked) Require

func (c Checked) Require(ctx context.Context, p Permission) (Caller, error)

func (Checked) VisibleProjects

func (c Checked) VisibleProjects(ctx context.Context, capability Capability) ([]ids.ID, error)

type Context

type Context struct {
	Consequential bool   // write a decision receipt (protected acts: yes)
	Route         string // for the receipt's context
}

Context describes the decision receipt.

type Decision

type Decision struct {
	Allow     bool     `json:"allow"`
	Code      string   `json:"code,omitempty"`
	Reason    string   `json:"reason"`
	GrantIDs  []ids.ID `json:"grantIds,omitzero"`
	Roles     []string `json:"roles,omitempty"`
	Paths     []string `json:"paths,omitempty"` // membership paths that mattered, e.g. group:approvers
	ReceiptID ids.ID   `json:"receiptId,omitzero"`
}

Decision is the one answer.

func Decide

func Decide(pr Principal, d Channel, c Capability, res Resource, ctx Context, facts Facts) Decision

Decide evaluates §12's order and returns one decision. It writes nothing; the caller records the receipt.

type Definition

type Definition struct {
	Description string
	// Inherits lists the scope kinds an instance/group grant of this capability
	// reaches DOWN into (§3 table). Empty = a grant applies only at the scope it
	// names and the resources inside that scope's own project/change/run.
	Inherits []ScopeKind
	Risk     string // read | mutate | approve | release | execute | admin
}

type Denied

type Denied struct{ Code, Reason string }

Denied is a policy refusal, distinct from a failure to read policy.

func (*Denied) Error

func (d *Denied) Error() string

func (*Denied) FaultCode

func (d *Denied) FaultCode() string

FaultCode is the denial's stable reason code, for clients that branch on it.

func (*Denied) FaultKind

func (d *Denied) FaultKind() fault.Kind

FaultKind: a denial is the caller being refused, not a failure.

type Event

type Event struct{ Kind, Actor, Subject string }

type Facts

type Facts interface {
	// Disabled reports whether a user may not act as an account: it is
	// disabled, or there is no such account. A principal that was admitted
	// is judged by its ID (its name may have changed or gone to someone
	// else); a name alone, by the account of that name. Unknown is refused,
	// never enabled.
	Disabled(pr Principal) bool
	// Grants is the principal's active grants: their own, their groups' and
	// everyone's, in one snapshot.
	Grants(pr Principal) []Grant
}

Facts is what the rule reads while deciding. Each read happens only when the rule reaches it.

type Grant

type Grant struct {
	ID          ids.ID
	SubjectType string
	Subject     string
	RoleName    string
	Capability  Capability
	ScopeType   ScopeKind
	ScopeID     string
	Origin      string
	GrantedBy   string
	// GrantedByPrincipal is the granter's principal; zero for AppTown, or
	// a granter not resolved to a person.
	GrantedByPrincipal ids.ID
	Reason             string
	CreatedAt          string
	ExpiresAt          stamp.Time
	ReviewAt           stamp.Time
	RevokedAt          stamp.Time
}

Grant is a grant row as the rule reads it.

func RootGrant

func RootGrant(grants []Grant) (Grant, bool)

func (Grant) Applies

func (g Grant) Applies(c Capability, r Resource) bool

Applies covers capability and scope.

func (Grant) Live

func (g Grant) Live(at time.Time) bool

func (*Grant) Revoke

func (g *Grant) Revoke(by Principal, now time.Time) (Event, error)

type Permission

type Permission struct {
	Capability Capability
	Resource   Resource
	Context    Context
}

Permission names an operation and the containing resource resolved by its owner. Context carries receipt attribution.

type Person

type Person struct {
	Known    bool
	Name     string
	Disabled bool
	Removed  bool
}

Person is a principal as it stands now, for showing an actor: its name today, and whether its account is disabled or it was removed. Known is false for a principal AppTown has no record of.

type Principal

type Principal struct {
	// ID is the principal who answers: a person's UUID for a user, the
	// person's for a console they wield; Nil when none was resolved (an
	// anonymous caller, a run, a name read from a header before its account).
	ID         ids.ID
	Kind       string // user | anonymous | instrument
	Name       string // username, "anonymous", or the instrument's own name
	Person     string // for a console: the person wielding it; "" for a run
	Instrument string // "" | console | run | eval | SystemInstrument
	Via        string
	ProjectID  ids.ID // the one project an instrument may act in
	ConsoleID  string
	Role       string // token administrator ceiling; otherwise a display projection, never authority
	// Purpose is a personal token's, chosen when it was made: TokenCLI is
	// its person's own command line, TokenAgent a coding agent's
	// connection. "" for every other credential.
	Purpose string
	// An OAuth delegation behind the request: the rule narrows to its
	// scopes. Zero for sessions and personal tokens (full breadth).
	DelegationID ids.ID
	Scopes       []string
	// Credential is a non-secret reference to the credential behind the
	// request (token:<name>, session:<id>, oauth:<delegation id>,
	// header:<user>, system:<binding>), so a long operation can ask later
	// whether that credential is still live. "" when none was resolved.
	Credential string
}

Principal is who is present, resolved from the authenticated identity. Instruments (a console session, a step agent) are not people: they carry the person behind them when there is one and are bounded by §11's tables.

func (Principal) Actor

func (pr Principal) Actor() Actor

Actor is the principal as an act records it.

type ProjectResources

type ProjectResources interface {
	AuthorityResource(context.Context, ids.ID) (Resource, error)
}

ProjectResources supplies only the facts common authorization needs.

type ProjectVisibility

type ProjectVisibility interface {
	VisibleProjects(context.Context, Principal, Capability) ([]ids.ID, error)
}

ProjectVisibility evaluates a principal against complete current project facts. Returned IDs are observations for read filtering, never permission to mutate.

type ReadAuthorizer

type ReadAuthorizer interface {
	Authorizer
	VisibleProjects(context.Context, Capability) ([]ids.ID, error)
}

ReadAuthorizer keeps caller establishment and aggregate visibility at the same owner boundary as explicit resource authorization.

type Resource

type Resource struct {
	ProjectName string // display name supplied by the resource owner, never an authority fact
	Type        string // instance | group | project | change | run | step | deployment | dimension | release-target
	ID          string
	ProjectID   ids.ID
	Group       string // the project's owning group
	ChangeID    ids.ID
	RunID       ids.ID
}

Resource is the thing acted on, with its containing scopes resolved.

type Role

type Role struct {
	Name        string
	Title       string // the answerable office, in product words
	Description string
	Scope       ScopeKind // where a grant of this role sits
	Caps        []Capability
	// Surfaced roles appear on the People page and in grant pickers. The
	// rest exist for later profiles.
	Surfaced bool
}

Role is a named capability bundle shipped with AppTown.

func RoleByName

func RoleByName(name string) *Role

func (*Role) Holds

func (rv *Role) Holds(c Capability) bool

Holds reports whether a role bundles a capability.

type Scope

type Scope struct {
	Name  string
	Means string // product language for the consent screen
	Caps  []Capability
}

Scope is one consent word (mcp.md §4) mapped onto capabilities. A scope names what a client may ask for; the rule still evaluates the person's live grants underneath.

type ScopeKind

type ScopeKind string

ScopeKind names a level of the containment hierarchy a grant can sit at.

const (
	ScopeInstance  ScopeKind = "instance"
	ScopeGroup     ScopeKind = "group"
	ScopeProject   ScopeKind = "project"
	ScopeChange    ScopeKind = "change"
	ScopeRun       ScopeKind = "run"
	ScopeDimension ScopeKind = "dimension"
	ScopeTarget    ScopeKind = "release-target"
)

Jump to

Keyboard shortcuts

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