postgres

package
v4.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package postgres persists a complete manifest in one PostgreSQL singleton row. New borrows pgxpool; Update uses one conditional SQL statement to match expected revision and store a newer manifest. It does not authorize publishers, run schema migrations, retry failures, invalidate caches or close the pool. Public revisions are uint64 but the schema uses signed bigint; select a compatible range. Driver responses materialize before policy.Decode byte admission. Database errors can contain sensitive diagnostics, and failures may require reconciliation when a write committed but response/decoding failed. No DB qualification is implied.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidAuthority denotes malformed scope, version, duration or handle.
	ErrInvalidAuthority = errors.New("invalid authorization authority input")
	// ErrAuthorityDenied covers both absent and mismatched authority, without
	// disclosing whether an unrelated principal exists.
	ErrAuthorityDenied = errors.New("authorization authority denied")
	// ErrAuthorityConflict denotes an initialization or expected-epoch CAS conflict.
	ErrAuthorityConflict = errors.New("authorization authority conflict")
	// ErrAuthorityOverflow is terminal; authority must never wrap or reset.
	ErrAuthorityOverflow = errors.New("authorization authority exhausted")
	// ErrAuthorityUnavailable redacts database, schema and corrupt-row failures.
	ErrAuthorityUnavailable = errors.New("authorization authority unavailable")
)
View Source
var (
	// ErrNilPool identifies authorization postgres pool is nil. Compare with errors.Is, not error text.
	ErrNilPool = errors.New("authorization postgres pool is nil")
	// ErrNotInitialized identifies authorization policy is not initialized. Compare with errors.Is, not error text.
	ErrNotInitialized = errors.New("authorization policy is not initialized")
	// ErrRevisionConflict identifies authorization policy revision conflict. Compare with errors.Is, not error text.
	ErrRevisionConflict = errors.New("authorization policy revision conflict")
	// ErrRevisionNotMonotonic identifies authorization policy revision is not monotonic. Compare with errors.Is, not error text.
	ErrRevisionNotMonotonic = errors.New("authorization policy revision is not monotonic")
)

Functions

func AuthorityGoMigration

func AuthorityGoMigration(version uint) (migrations.Migration, error)

AuthorityGoMigration adapts the separately allocated forward-only authority migration to the existing owned migrations library. Historical v1 bytes and legacy manifest APIs are unchanged; no implicit dependency on identity exists.

func GoMigration

func GoMigration() (migrations.Migration, error)

GoMigration binds the SQL to go-migrations/v4 default transaction policy; it creates a definition, not a database migration execution.

func RequireAuthority

func RequireAuthority[R AuthorityRows](ctx context.Context, q AuthorityQueryer[R], scope AuthorityScope, expected uint64, maximumDuration time.Duration) error

RequireAuthority compares exact current authority under a primary share lock retained until the original transaction owner commits/aborts. Missing or any unequal epoch denies, including a future expected value. No row/version is created or refreshed and no policy decision, proof or session is issued. The trusted native adapter must poison/abort its Work on every error, including ignored denial; passing an independent pool cannot prove protected admission.

Types

type AuthorityQueryer

type AuthorityQueryer[R AuthorityRows] interface {
	// Query honors the bounded context and returns an owned cursor to close.
	Query(context.Context, string, ...any) (R, error)
}

AuthorityQueryer supplies one trusted owner's synchronous query capability. The generic row type preserves narrower generation-bound cursors without importing identity or exposing raw connections. Protected operations require a real borrowed transaction, never a pool/autocommit or replica. The owner must fence participant scope/lifetime and abort/poison on any returned error. Methods below never retain this handle or begin/commit/rollback a transaction.

type AuthorityRecord

type AuthorityRecord struct {
	// Scope is the exact primary row identity, not caller-selected authority.
	Scope AuthorityScope
	// Version is its positive epoch; zero never represents initialized authority.
	Version uint64
}

AuthorityRecord is a structural primary projection of one positive uint64 epoch. It is neither a policy decision nor freshness evidence, and must not be promoted into a renewable positive-cache lease.

func AdvanceAuthority

func AdvanceAuthority[R AuthorityRows](ctx context.Context, q AuthorityQueryer[R], scope AuthorityScope, expected uint64, maximumDuration time.Duration) (AuthorityRecord, error)

AdvanceAuthority stages one exact expected-epoch successor under row locking. Role/statement/policy/entitlement mutation and required audit must share this transaction. Missing/stale scopes conflict; MaxUint64 fails terminally before SQL. Restore/import cannot reset authority. This is not a standalone admin workflow: caller authorization, immutable intent and recovery remain owned by the existing coordinator. A returned record is provisional, not commit proof.

func InitializeAuthority

func InitializeAuthority[R AuthorityRows](ctx context.Context, q AuthorityQueryer[R], scope AuthorityScope, maximumDuration time.Duration) (AuthorityRecord, error)

InitializeAuthority stages explicit trusted bootstrap at epoch one. Existing scopes return Conflict, including newer epochs: bootstrap never resets them. The returned projection is provisional until the owner proves commit. The owner must authorize bootstrap and abort on error; reads never call this API.

func (AuthorityRecord) Format

func (AuthorityRecord) Format(s fmt.State, _ rune)

Format hides internal scope/version correlation.

func (AuthorityRecord) MarshalJSON

func (AuthorityRecord) MarshalJSON() ([]byte, error)

MarshalJSON rejects accidental authority projection export.

type AuthorityRows

type AuthorityRows interface {
	// Next advances the borrowed cursor and reports whether a row is available.
	Next() bool
	// Scan copies the current row into supplied destinations without retaining them.
	Scan(...any) error
	// Err reports iteration failures after Next returns false.
	Err() error
	// Close drains or cancels this cursor without closing the owning transaction.
	Close()
}

AuthorityRows is the minimum synchronous borrowed cursor contract. Implemented by pgx.Rows and identity's generation-bound WorkRows. Close must drain or cancel the result without terminalizing the owning transaction.

type AuthorityScope

type AuthorityScope struct {
	// TenantID is the exact tenant isolation boundary, not a defaultable label.
	TenantID authorization.TenantID
	// PolicyNamespace is a trusted domain in which SubjectID is unambiguous.
	PolicyNamespace string
	// SubjectID is the exact lifecycle subject within tenant and namespace.
	SubjectID authorization.SubjectID
}

AuthorityScope identifies one lifecycle epoch independently of policy revision. Every component is an exact 1..128-byte UTF-8 opaque ID, with ASCII whitespace and controls forbidden. No normalization occurs. PolicyNamespace must select a domain in which SubjectID is unique across subject kinds; an untrusted Subject.Kind or attribute cannot select that domain. Zero is invalid.

func (AuthorityScope) Format

func (AuthorityScope) Format(s fmt.State, _ rune)

Format redacts internal correlation scope in diagnostics.

func (AuthorityScope) Key

func (s AuthorityScope) Key() (string, error)

Key returns a stable version-one session-vector binding, not an authorization decision or private identifier. SHA-256 hashes the fixed domain followed by the three exact UTF-8 components, each framed with its big-endian uint16 byte length, in tenant/namespace/subject order. The unpadded base64url digest fits bounded snapshot keys; owner lookups still compare all three original IDs. Hashing avoids ambiguous delimiter joins, not correlation or disclosure.

func (AuthorityScope) MarshalJSON

func (AuthorityScope) MarshalJSON() ([]byte, error)

MarshalJSON rejects accidental scope export.

func (AuthorityScope) Validate

func (s AuthorityScope) Validate() error

Validate checks the complete scope without reading or provisioning authority.

type AuthorityStore

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

AuthorityStore borrows a primary pool for structural reads only. Concurrent reads are safe; the caller retains pool shutdown ownership. Zero is invalid.

func NewAuthorityStore

func NewAuthorityStore(pool *pgxpool.Pool, maximumDuration time.Duration) (*AuthorityStore, error)

NewAuthorityStore requires a primary pool and finite 0..1-minute read budget. Earlier caller deadlines win. The constructor performs no IO or bootstrap.

func (*AuthorityStore) Get

Get reads the exact primary scope without locks or implicit initialization. Missing authority denies; corrupt/storage errors are redacted. Cancellation preserves context errors. No policy decision or validity lease is returned.

type Migration

type Migration struct {
	// Version is caller-owned migration ordering; SchemaMigration returns 1.
	Version uint
	// Name is the exact application label; do not place secrets in error-visible names.
	Name string
	// Up is forward SQL; SchemaMigration supplies singleton-table creation.
	Up string
	// Down is reverse SQL; SchemaMigration supplies a destructive table drop.
	Down string
}

Migration is caller-owned executable schema SQL metadata; it is not applied here.

func AuthoritySchemaMigration

func AuthoritySchemaMigration(version uint) (Migration, error)

AuthoritySchemaMigration appends opt-in scoped lifecycle epoch storage without altering the released v1 manifest schema. Allocate a permanent version later than every existing application migration (at least 2). It bootstraps no rows. Downgrade is deliberately absent: dropping/recreating authority could reset epochs and resurrect old artifacts. Restore must preserve all authoritative rows or use the platform's explicit compromise/invalidation procedure.

func SchemaMigration

func SchemaMigration() Migration

SchemaMigration returns version-1 singleton-table SQL. Down irreversibly drops policy data; caller migration policy owns transactions/deployment/rollback.

type Store

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

Store borrows a pgx query seam; construct with New, keep schema/pool lifecycle valid and use contexts with deadlines. The zero value is unusable.

func New

func New(pool *pgxpool.Pool) (*Store, error)

New borrows a non-nil pool without opening/migrating/closing it.

func (*Store) Load

func (store *Store) Load(ctx context.Context) (policy.Manifest, error)

Load reads/decodes the singleton manifest, mapping no rows to ErrNotInitialized. It trusts database content and does not cross-check JSON revision against the separate SQL revision column. Row materialization precedes parser admission; raw driver diagnostics remain caller-protected.

func (*Store) Update

func (store *Store) Update(
	ctx context.Context,
	expected authorization.Revision,
	next policy.Manifest,
) (policy.Manifest, error)

Update validates/encodes next, then conditionally writes one newer revision under expected (zero for initialization). No rows is conflict; raw query errors or post-write decode errors can leave commit state uncertain. Reconcile with Load before repeating unknown outcomes. Revisions must fit SQL bigint; caller graphs are borrowed during encode. No retry/invalidation is owned.

Jump to

Keyboard shortcuts

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