Documentation
¶
Overview ¶
Package store is Headmesh's Postgres access layer: tenant-scoped transactions, migrations, the tamper-evident audit log and the loader that turns database state into a policy.Snapshot.
Index ¶
- Variables
- func AppendAudit(ctx context.Context, q *dbq.Queries, ev AuditEvent) (int64, error)
- func LoadSnapshot(ctx context.Context, q *dbq.Queries, cell dbq.Cell, now time.Time, ...) (policy.Snapshot, error)
- func Migrate(ctx context.Context, pool *pgxpool.Pool) error
- func UUID(s string) (pgtype.UUID, error)
- func VerifyAuditChain(ctx context.Context, q *dbq.Queries, org pgtype.UUID) (int, error)
- type AuditEvent
- type CellStore
- func (c *CellStore) NextRevision(ctx context.Context, name string) (uint64, error)
- func (c *CellStore) RecordApplied(ctx context.Context, name string, a *cellv1.PolicyApplied) error
- func (c *CellStore) RecordHello(ctx context.Context, name string, hello *cellv1.Hello) error
- func (c *CellStore) RecordObserved(ctx context.Context, name string, obs *cellv1.Observed) error
- func (c *CellStore) RecordTimeline(ctx context.Context, name string, tl []*cellv1.PolicyRevision) error
- func (c *CellStore) Snapshot(ctx context.Context, name string, now time.Time, horizon time.Duration) (policy.Snapshot, error)
- type OrgSettings
- type PlatformSelectorJSON
- type Scope
- type SelectorJSON
- type Store
Constants ¶
This section is empty.
Variables ¶
var ErrChainBroken = errors.New("audit chain broken")
ErrChainBroken reports an audit chain whose stored hashes do not match the recomputed ones.
var ErrNoScope = errors.New("store: transaction needs a tenant scope or the system scope")
ErrNoScope is returned when a transaction is started without a tenant scope.
Functions ¶
func AppendAudit ¶
AppendAudit adds ev to its org's chain inside the caller's transaction. The chain head row is locked for the rest of the transaction, so concurrent appends to the same org serialise and the chain never forks.
func LoadSnapshot ¶
func LoadSnapshot(ctx context.Context, q *dbq.Queries, cell dbq.Cell, now time.Time, horizon time.Duration) (policy.Snapshot, error)
LoadSnapshot reads one cell's tenancy state as policy input. It must run in a System-scoped transaction. Grants are limited to those active at now or starting before now+horizon, which is everything a policy timeline over that horizon can need.
func Migrate ¶
Migrate applies all pending migrations. It must run as the schema owner, not as the application role.
func VerifyAuditChain ¶
VerifyAuditChain recomputes org's chain from genesis and checks it ends at the stored head. It returns the number of events checked, or ErrChainBroken naming the first event that does not verify.
Types ¶
type AuditEvent ¶
type AuditEvent struct {
OrgID pgtype.UUID // zero (invalid) for events that belong to no tenant
OccurredAt time.Time
ActorType string // user | api_key | system | cell | platform
ActorID string
Action string // dotted, e.g. "grant.revoked"
TargetType string
TargetID string
RequestID string
IP *netip.Addr
UserAgent string
Data map[string]any
}
AuditEvent is one entry in the tamper-evident audit log.
type CellStore ¶
type CellStore struct {
// contains filtered or unexported fields
}
CellStore implements cellserver.Store on Postgres. Every call runs in the system scope: the hub works on whole cells, never on behalf of a tenant.
func (*CellStore) NextRevision ¶
NextRevision implements cellserver.Store.
func (*CellStore) RecordApplied ¶
RecordApplied implements cellserver.Store. A guardrail refusal is also written to the audit log, because it means the control server asked a cell for something the cell considered unsafe.
func (*CellStore) RecordHello ¶
RecordHello implements cellserver.Store.
func (*CellStore) RecordObserved ¶
RecordObserved implements cellserver.Store: it syncs addresses and liveness onto known devices.
func (*CellStore) RecordTimeline ¶
func (c *CellStore) RecordTimeline(ctx context.Context, name string, tl []*cellv1.PolicyRevision) error
RecordTimeline implements cellserver.Store.
type OrgSettings ¶
type OrgSettings struct {
SSHEnabled bool `json:"ssh_enabled,omitempty"`
AllowSubnetRoutes bool `json:"allow_subnet_routes,omitempty"`
AllowExitNodes bool `json:"allow_exit_nodes,omitempty"`
MaxGrantTTLHours int `json:"max_grant_ttl_hours,omitempty"`
}
OrgSettings is the typed view of orgs.settings.
type PlatformSelectorJSON ¶
type PlatformSelectorJSON struct {
Scope string `json:"scope"` // platform | children
Role string `json:"role,omitempty"`
}
PlatformSelectorJSON is the stored form of a platform rule side.
type Scope ¶
type Scope struct {
OrgIDs []pgtype.UUID
// System grants a whole-cell view. Only background workers (policy compiler, reconciler, recovery sweep)
// use it; request handlers never do.
System bool
}
Scope says which tenants a transaction may see. Exactly one of OrgIDs or System must be set.
type SelectorJSON ¶
type SelectorJSON struct {
Kind string `json:"kind"` // all | users | role | device
Role string `json:"role,omitempty"`
Device string `json:"device,omitempty"`
}
SelectorJSON is how rule and grant selectors are stored in jsonb columns. Device selectors reference the device by UUID so renames and re-enrolments never break them.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store wraps a connection pool. The pool's role must not be a superuser and must not have BYPASSRLS, otherwise row-level security (the database half of tenant isolation) silently stops applying.
func (*Store) Tx ¶
func (s *Store) Tx(ctx context.Context, scope Scope, fn func(q *dbq.Queries, tx pgx.Tx) error) error
Tx runs fn in a transaction whose row-level-security context is set to scope. The context is transaction-local (SET LOCAL semantics), so it can never leak to another request through the pool.