// Package policy implements an in-process, attribute-based authorization // policy engine for MCIAS. Evaluation is a pure function: given a PolicyInput // and a slice of Rules it returns an Effect (Allow or Deny) and the Rule that // produced the decision. The caller is responsible for assembling PolicyInput // from JWT claims and database lookups; the engine never touches the database. // // Evaluation order: // 1. Rules are sorted by Priority (ascending; lower = higher precedence). // 2. Deny-wins: the first matching Deny rule terminates evaluation. // 3. If no Deny matched, the first matching Allow rule permits the request. // 4. Default-deny: if no rule matches, the request is denied. package policy // Action is a structured action identifier of the form "resource:verb". // Security: using typed constants prevents callers from passing arbitrary // strings, making it harder to accidentally bypass a policy check. type Action string const ( ActionListAccounts Action = "accounts:list" ActionCreateAccount Action = "accounts:create" ActionReadAccount Action = "accounts:read" ActionUpdateAccount Action = "accounts:update" ActionDeleteAccount Action = "accounts:delete" ActionReadRoles Action = "roles:read" ActionWriteRoles Action = "roles:write" ActionReadTags Action = "tags:read" ActionWriteTags Action = "tags:write" ActionIssueToken Action = "tokens:issue" ActionRevokeToken Action = "tokens:revoke" ActionValidateToken Action = "tokens:validate" // public endpoint ActionRenewToken Action = "tokens:renew" // self-service ActionReadPGCreds Action = "pgcreds:read" ActionWritePGCreds Action = "pgcreds:write" ActionReadAudit Action = "audit:read" ActionEnrollTOTP Action = "totp:enroll" // self-service ActionRemoveTOTP Action = "totp:remove" // admin ActionLogin Action = "auth:login" // public ActionLogout Action = "auth:logout" // self-service ActionListRules Action = "policy:list" ActionManageRules Action = "policy:manage" ) // ResourceType identifies what kind of object a request targets. type ResourceType string const ( ResourceAccount ResourceType = "account" ResourceToken ResourceType = "token" ResourcePGCreds ResourceType = "pgcreds" ResourceAuditLog ResourceType = "audit_log" ResourceTOTP ResourceType = "totp" ResourcePolicy ResourceType = "policy" ) // Effect is the outcome of policy evaluation. type Effect string const ( Allow Effect = "allow" Deny Effect = "deny" ) // Resource describes the object the principal is attempting to act on. Tags // are loaded from the account_tags table by the middleware before evaluation. type Resource struct { Type ResourceType // OwnerUUID is the UUID of the account that owns this resource (e.g. the // system account whose pg_credentials are being requested). Empty when the // resource is not account-owned (e.g. an audit log listing). OwnerUUID string // ServiceName is the username of the system account that owns the resource. // Used for service-name-based gating rules (ServiceNames field on Rule). ServiceName string // Tags are the account_tags values on the target account. The engine // checks RequiredTags against this slice. Tags []string } // PolicyInput is assembled by the middleware from JWT claims and the current // request context. The engine accepts a PolicyInput and a rule set; it never // queries the database directly. type PolicyInput struct { // Principal fields — from JWT claims Subject string // account UUID ("sub") AccountType string // "human" or "system" Roles []string // role strings from "roles" claim Action Action Resource Resource } // Rule is a single policy statement. All non-zero fields are AND-ed together // as match conditions. A zero/empty field is a wildcard. // // Security: rules from the database are decoded and merged with compiled-in // defaults before evaluation. Neither the JSON encoding nor the DB storage is // trusted to produce sensible rules; the engine validates each condition // independently using set membership — there is no string interpolation or // code execution involved. type Rule struct { Description string SubjectUUID string ResourceType ResourceType Effect Effect Roles []string AccountTypes []string Actions []Action ServiceNames []string RequiredTags []string ID int64 Priority int OwnerMatchesSubject bool } // RuleBody is the subset of Rule that is stored as JSON in the policy_rules // table. ID, Description, and Priority are stored as dedicated columns. // Security: the JSON blob is decoded into a RuleBody before being merged into // a full Rule, so the database cannot inject ID or Description values. type RuleBody struct { SubjectUUID string `json:"subject_uuid,omitempty"` ResourceType ResourceType `json:"resource_type,omitempty"` Effect Effect `json:"effect"` Roles []string `json:"roles,omitempty"` AccountTypes []string `json:"account_types,omitempty"` Actions []Action `json:"actions,omitempty"` ServiceNames []string `json:"service_names,omitempty"` RequiredTags []string `json:"required_tags,omitempty"` OwnerMatchesSubject bool `json:"owner_matches_subject,omitempty"` }