Documentation
¶
Overview ¶
Package pinapprovals records explicit pin approvals in a versioned log beside the pin stores. The log is audit data, not recomputable derived data, so it lives under pins/approvals/ rather than inside the pin file. An older gridctl rewriting a pin file drops the projected approvals list and loses nothing: the next load rebuilds it from this log.
approved_by is best-effort local attribution, not an identity system. Evidence references are opaque operator text. They are stored as given, never fetched, resolved, or opened.
Index ¶
- Constants
- Variables
- func LocalUser() (name, source string)
- func ResolveApprover(principal, declared string) (name, source string)
- func ValidateApprover(name string) error
- func ValidateReason(reason string) error
- func ValidateReference(ref string) error
- func ValidateReferences(refs []string) ([]string, error)
- type Entry
- type Log
Constants ¶
const ( // FileVersion is the approvals log version this binary writes and the // highest version it accepts. Advertised by `gridctl info --json` as // schemas.pin_approvals. FileVersion = "1" // MaxHistory is the number of approval entries kept per subject, newest // first. Older entries are dropped on append. MaxHistory = 10 // KindSkill, KindTool, KindContext, and KindHook are the log file kind // discriminants. KindSkill = "skill" KindTool = "tool" KindContext = "context" KindHook = "hook" // Attribution sources. os_user is the local OS account, declared is a // name the caller supplied and this process did not verify, and oauth // is a verified access principal. None of these authenticate the // approval. SourceOSUser = "os_user" SourceDeclared = "declared" SourceOAuth = "oauth" )
Variables ¶
var ( ErrCorrupt = errors.New("corrupt approvals log") ErrNewerVersion = errors.New("approvals log written by a newer gridctl") )
Sentinel errors reported by Load. A corrupt file resets the in-memory log to empty and returns ErrCorrupt; a caller that prefers availability may continue. ErrNewerVersion must not be papered over: appending would overwrite a log this binary does not understand.
var ( ErrInvalidReference = errors.New("invalid evidence reference") ErrCredentialShaped = errors.New("credential-shaped value") ErrTooManyReferences = errors.New("too many evidence references") ErrReasonTooLong = errors.New("approval reason too long") ErrInvalidApprover = errors.New("invalid approver") )
Sentinel errors for refused approval input. Callers map them with errors.Is. The wrapped text names the problem and says how to retry; redaction is not used, because silently mutating audit input would hide what the operator submitted.
Functions ¶
func LocalUser ¶
func LocalUser() (name, source string)
LocalUser returns the local OS account and the source os_user. On lookup failure it falls back to $USER, then $USERNAME. It returns empty strings when none is set. It never returns an error and never panics.
func ResolveApprover ¶
ResolveApprover applies the approval attribution order: a non-empty verified principal (oauth), else a non-empty declared name, else the local OS user. This is attribution, not authentication.
func ValidateApprover ¶
ValidateApprover trims name and refuses a value longer than 256 bytes or one that is credential-shaped. Empty, including whitespace-only, is allowed: attribution then falls through to the next source. The check does not authenticate the name.
func ValidateReason ¶
ValidateReason refuses a reason longer than 4096 bytes and a reason that is credential-shaped. Empty is allowed.
func ValidateReference ¶
ValidateReference trims ref and refuses an empty value, a value longer than 2048 bytes, a URL whose userinfo is set, and any string that matches a default redaction pattern. The error names what matched and says to remove it and retry.
func ValidateReferences ¶
ValidateReferences trims each entry, drops exact duplicates (first occurrence wins), refuses more than 16 remaining, and applies ValidateReference to each. The returned slice is what callers store.
Types ¶
type Entry ¶
type Entry struct {
ApprovedAt time.Time `json:"approved_at"`
ApprovedBy string `json:"approved_by,omitempty"`
ApprovedBySource string `json:"approved_by_source,omitempty"`
ApprovedHash string `json:"approved_hash"`
Bound bool `json:"bound"`
Reason string `json:"reason,omitempty"`
Evidence []string `json:"evidence,omitempty"`
}
Entry is one explicit approval. ApprovedAt is RFC 3339 UTC. ApprovedHash is the hash the approval bound to. Bound is true when the caller supplied an expected hash. Evidence order is the order the caller supplied after trim and de-duplication.
func CloneEntries ¶
CloneEntries returns a deep copy. A nil or empty input returns nil so JSON omitempty drops the field.
type Log ¶
type Log struct {
// contains filtered or unexported fields
}
Log is the approvals history for one stack and kind. Open does not touch the disk. Load and Append honor context cancellation before I/O.
Append does not take a file lock. The owning pin store calls it inside its existing state.WithLock critical section so an append and a re-pin cannot interleave across processes. Two Append calls without that lock can overwrite each other.
func (*Log) Append ¶
Append prepends entry for subject, keeps at most MaxHistory entries, and writes the file atomically with mode 0600. The in-memory log changes only after the write succeeds. A log that has not been loaded, or that Load rejected as a newer version, is not written.
Append does not take a file lock. Call it inside the owning pin store's state.WithLock critical section.
func (*Log) History ¶
History returns a copy of subject's entries, newest first. An unknown subject returns nil.
func (*Log) Latest ¶
Latest returns a copy of the newest entry. The bool is false when the subject has no entries.
func (*Log) Load ¶
Load reads the log. A missing file is an empty log. A corrupt file resets to empty and returns an error wrapping ErrCorrupt. A version other than "" or "1" resets to empty and returns an error wrapping ErrNewerVersion; the message names the path and the version. A newer-version log is not writable until a later Load succeeds.