approval

package
v0.20.0 Latest Latest
Warning

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

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

Documentation

Overview

Package approval holds the process-local registry of parked queries.

A hold is a proxy session goroutine blocked mid-statement waiting for a human. The registry is what lets the API handler on the same replica — or a LISTEN/NOTIFY message from another one — wake that goroutine up.

The registry only *delivers* decisions. It deliberately does not decide who may approve (that is the API's job, which has the user and their groups) and does not persist anything (that is the store's job, whose compare-and-set on approval_status = 'pending' is the real source of truth). Keeping those apart is what makes double-resolution safe: the DB update decides the winner, the registry just carries the news.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Decision

type Decision struct {
	// QueryUID identifies the hold. The waiting session asserts this equals
	// its own pending uid before acting on it: without that check, a client
	// able to influence timing could have somebody else's approval released
	// against its statement (TOCTOU substitution).
	QueryUID uuid.UUID
	// Status is one of store.ApprovalApproved / ApprovalDenied /
	// ApprovalAbandoned.
	Status string
	// By is the resolving user, nil for system resolutions (client
	// disconnect, shutdown).
	By *uuid.UUID
	// ByName is the resolver's display name, carried so every watcher sees
	// *who* unblocked a query and not merely that it unblocked.
	ByName string
	// Reason is the approver-supplied justification, surfaced to the client
	// in the protocol-native deny error.
	Reason string
	// At is when the decision was taken.
	At time.Time
}

Decision is the outcome delivered to a parked session.

type Registry

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

Registry tracks parked statements on this replica.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates an empty registry.

func (*Registry) HeldSince

func (r *Registry) HeldSince(queryUID uuid.UUID) (time.Time, bool)

HeldSince returns when a hold started, if it is parked here.

func (*Registry) Pending

func (r *Registry) Pending() []uuid.UUID

Pending returns the uids parked on this replica, oldest first is not guaranteed — callers use this for shutdown draining and telemetry, not ordering.

func (*Registry) Register

func (r *Registry) Register(queryUID uuid.UUID) (<-chan Decision, func())

Register parks a query. The returned channel receives at most one decision; release must be called (deferred) when the session stops waiting, whatever the reason — otherwise the hold leaks and shutdown would block on it.

func (*Registry) Resolve

func (r *Registry) Resolve(d Decision) bool

Resolve delivers a decision to a locally parked session. It reports whether a hold existed here — false simply means the session lives on another replica (or already gave up), which is not an error.

func (*Registry) ResolveAll

func (r *Registry) ResolveAll(status, reason string, by *uuid.UUID, byName string) []uuid.UUID

ResolveAll delivers the same status to every hold on this replica and returns the uids it resolved. Used on shutdown: draining must explicitly abandon parked queries rather than hang the shutdown or, worse, silently let them through.

Jump to

Keyboard shortcuts

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