Documentation
¶
Overview ¶
Governance profiles and their subject assignments (migration 0052).
This file is DUMB on purpose: it round-trips rows and owns exactly one piece of logic, ResolveGovernanceProfile's ORDER BY, so precedence is a property of the single indexed read, not a caller that could forget it. Every write is validated at the API boundary (internal/api/governance.go).
Governance changes (migration 0126): a governance write held for a second human. The store owns the parts that must be one transaction: proposing (expire a lapsed change at the same target, then insert) and deciding (lock the change row, require it pending and unexpired, run the target's apply, move the state, commit). It knows nothing about any target: the apply a caller hands DecideGovernanceChange is that target's own code, run on the decision transaction.
Package store provides typed CRUD over the Wardyn schema using pgx/v5. Callers supply contexts with deadlines. InsertAuditEvent stays a free function taking the pool explicitly since it predates a Store value in the audit.Recorder wiring.
Naming: Create* inserts and returns the hydrated row; Get* fetches by primary key (ErrNotFound when absent); List* returns a slice, empty never nil; Update*/Decide* are point mutations with explicit optimistic guards.
The Azure DevOps personal access tokens Wardyn creates for `minted_pat` runs (migration 0102, #1428): the record that makes a token revocable after a crash. A row holds no secret; the token value lives in daemon memory only.
The console's reads of ado_run_pats (#1428): every token a run held, and the newest token created for a person on a row. Like the table, neither carries a secret.
The Azure DevOps sign-in end counter (migration 0129): per person, how many times their sign-in was disconnected or erased and whether one is running now, so a run token created on any replica across one of those ends revokes itself. The row holds no secret.
Per-user API tokens. Kept out of store.go on purpose (lint size boundary), mirroring store_sshkeys.go's split.
SECURITY: the raw token never reaches SQL — every method here hashes it with hashToken before touching the table, so token_sha256 is the only form that exists at rest.
The reads the attention projection and GET /me/attention need beyond what GET /runs already scoped: every PENDING approval on a batch of runs, in one query, so paging runs costs one extra round trip regardless of how many are held; and the two scoped PENDING counts /me/attention answers, counted in the database rather than by listing every row.
The attach lease (migration 0129): the one writer slot of a run's shared terminal, in Postgres so every replica agrees who holds it. The database's clock decides when a lease lapses.
Console branding (migration 0091_branding). One row or none; the request is validated at the API boundary (internal/api/branding.go).
Capability grants and the per-kind enforcement switch (migration 0042). Kept out of store.go on purpose, mirroring store_sshkeys.go's split.
Registered portals and the delegated tokens they are handed. Like store_apitokens.go and store_devices.go, every method hashes the RAW credential with hashToken before it reaches SQL.
Hybrid enrolment and audit federation (migration 0066): the organisation-side device inventory (devices, device_enrolment_tokens) and the laptop side's durable forwarder cursor (org_federation). Kept out of store.go (already at a lint size boundary), mirroring store_apitokens.go/store_sshkeys.go's split.
SECURITY: hashToken (store_ephemeral.go) is reused for both credential tables — the raw device bearer and raw enrolment token never reach a row, only hex(sha256(raw)).
Short-lived control-plane handoff row (migration 0026): single-use WS attach tickets, durable and shared across every control plane — an in-process map can't survive a restart or be seen by a second control plane. Consume-once is a single DELETE ... RETURNING, atomic under concurrency and across processes.
The sign-in gate and the owner guard: how a suspended identity is refused at issuance and how a credential minted during a suspension is refused at its insert (migration 0113, 0127).
Launch presets (migration 0087_launch_presets). Round-trips rows; the request body is validated at the API boundary (internal/api/presets.go).
The store half of leaver deprovisioning: the SCIM projection on an identity row, the suspension and reactivation transactions, and the durable step ledger (migration 0127).
The identity row every successful sign-in leaves (migration 0113).
Per-person preferences (migration 0080_user_view_type).
A held push's complete path list (migration 0085_push_content_paths).
Console-managed role mappings (migration 0051): the store half of internal/auth/oidc's RoleMappingSource. Kept out of store.go on purpose, mirroring store_capabilities.go's split.
The run lease (long-holds design rev 4; migration 0073): the reads and the conditional writes the lease sweep needs. Kept out of store.go for the same size reason as store_watcher.go.
Lost-run surface (long-holds design rev 4, RL-9; migration 0083): token stamp, lapsed-token read, and lost claim. Split out of store.go for size, like store_run_lease.go.
The live exec tail (migration 0129): the masked bytes a run's dispatching replica has printed so far, readable from any replica. One final row per run is run_outputs' (0122); these chunks are what stands in for it until that row is written, and what a recovery falls back to when the substrate cannot be re-read.
The persisted run output (migration 0119): one masked final row per run, the pending row that records a capture is owed, and the erasure tombstones that keep an erased run's output erased. Kept out of store.go for the same size reason as store_watcher.go.
Pause and resume (long-holds design rev 4, §3, RL-7; migration 0097): the presence clock, the reads the pause sweep needs and its conditional writes. Kept out of store.go for the same size reason as store_run_lease.go.
A run's sealed proxy config (#1176, migration 0093): what a revive rebuilds the run's proxy from, so the proxy container never holds it at rest.
Tightened limits reach live runs (long-holds design rev 4, §2.2, RL-8; migration 0095): the read and the conditional write the re-clamp sweep needs. Kept out of store.go for the same size reason as store_run_lease.go.
Revive and restart with current limits (long-holds design rev 4, RL-10 and RL-11; migration 0084): the claim a revive makes before it replaces a run's proxy, and the read the admin version-window listing makes.
Landing-page GET /runs scoping: RunFilter, the filtered list read, and hidden-row counts. Attention projection lives elsewhere; this file only scopes, windows and orders the bare AgentRun rows.
Sandbox ref -> substrate routing rows (migration 0021): the Postgres RefStore, letting a control-plane restart rehydrate lifecycle routing in multi-substrate deployments.
SSH gateway key registry. Kept out of store.go on purpose (lint size boundary), mirroring store_sandbox_ref.go's split.
Per-user run-detail cockpit widget-layout persistence (migration 0037). Kept out of store.go/iface.go on purpose — see RunLayoutStore's doc below.
User types (migration 0071_user_types). Round-trips rows; every write is validated at the API boundary (internal/api/user_types.go).
The run-watcher lease (migration 0027): two writes that make "who is responsible for finishing this run" a fact in Postgres, not a goroutine in one process. Kept out of store.go (lint size); shares run columns with store.go's CreateRun/GetRun and pagination.go's ListRunsPage.
The workspaces table (tier 3 of the three-tier split): JSONB parameter helpers, the wsCols column list, scanWorkspace, and the CRUD and scoped-writer methods PG exposes over a workspace row. store_sources.go is the read/hydrate half of the pair (tiers 1-2 plus s.hydrated).
User drives and their subject grants (migration 0054), split out of store.go like governance.go. Kept DUMB: round-trips rows, owns only ResolveUserDrive's ORDER BY (precedence must live in the one indexed read, not a caller). Writes are validated at the API boundary (types.ValidateUserDrive, types.ValidateUserDriveGrant).
Index ¶
- Constants
- Variables
- func CapAuditTarget(target string) string
- func DeleteCapabilityGrantQ(ctx context.Context, q Querier, id uuid.UUID) error
- func DeleteGovernanceAssignmentQ(ctx context.Context, q Querier, id uuid.UUID) error
- func DeleteGovernanceProfileQ(ctx context.Context, q Querier, id uuid.UUID) error
- func DeleteRoleMappingQ(ctx context.Context, q Querier, id uuid.UUID) error
- func FederatedActor(deviceID uuid.UUID, claimed string) string
- func FederatedDeviceID(ev types.AuditEvent) *uuid.UUID
- func FederatedRowProblem(r types.FederatedAuditEvent) string
- func GetCapabilityEnforcementQ(ctx context.Context, q Querier) (map[string]bool, error)
- func GetCapabilityGrantByKeyQ(ctx context.Context, q Querier, subjectType, subject, capability, value string, ...) (types.CapabilityGrant, error)
- func GetCapabilityGrantQ(ctx context.Context, q Querier, id uuid.UUID, forUpdate bool) (types.CapabilityGrant, error)
- func GetGovernanceAssignmentByKeyQ(ctx context.Context, q Querier, subjectType, subject string, forUpdate bool) (types.GovernanceAssignment, error)
- func GetGovernanceAssignmentQ(ctx context.Context, q Querier, id uuid.UUID, forUpdate bool) (types.GovernanceAssignment, error)
- func GetGovernanceProfileQ(ctx context.Context, q Querier, id uuid.UUID, forUpdate bool) (types.GovernanceProfile, error)
- func GetLiveAPITokenQ(ctx context.Context, q Querier, id uuid.UUID) (types.APIToken, error)
- func GetUserTypeQ(ctx context.Context, q Querier, id string, forUpdate bool) (types.UserType, error)
- func InsertAuditEvent(ctx context.Context, pool *pgxpool.Pool, ev *types.AuditEvent) error
- func InsertAuditEventTx(ctx context.Context, tx pgx.Tx, ev *types.AuditEvent) error
- func ListCapabilityGrantsQ(ctx context.Context, q Querier) ([]types.CapabilityGrant, error)
- func ListCapabilityRestrictionsQ(ctx context.Context, q Querier) (map[string]map[string]bool, error)
- func ListGovernanceProfilesQ(ctx context.Context, q Querier) ([]types.GovernanceProfile, error)
- func ListRoleMappingsQ(ctx context.Context, q Querier) ([]types.RoleMapping, error)
- func ListUserTypesQ(ctx context.Context, q Querier) ([]types.UserType, error)
- func LockGovernanceAssignmentKey(ctx context.Context, q Querier, subjectType, subject string) error
- func LockGovernanceGraph(ctx context.Context, q Querier) error
- func LockGovernanceTarget(ctx context.Context, q Querier, kind string, parts ...string) error
- func PutCapabilityEnforcementQ(ctx context.Context, q Querier, enabled map[string]bool) (map[string]bool, error)
- func SetCapabilityRestrictionQ(ctx context.Context, q Querier, capability, value string, restricted bool, ...) error
- func UpdateUserTypeQ(ctx context.Context, q Querier, t types.UserType) (types.UserType, error)
- func UpsertCapabilityGrantQ(ctx context.Context, q Querier, g types.CapabilityGrant) (types.CapabilityGrant, error)
- func UpsertGovernanceAssignmentQ(ctx context.Context, q Querier, a types.GovernanceAssignment) (types.GovernanceAssignment, error)
- func UpsertRoleMappingQ(ctx context.Context, q Querier, m types.RoleMapping) (types.RoleMapping, error)
- func WithIdentityGuard(ctx context.Context, g IdentityGuard) context.Context
- func WriteGovernanceProfileQ(ctx context.Context, q Querier, id uuid.UUID, build GovernanceProfileBuild) (types.GovernanceProfile, error)
- type ADOSignInEndState
- type ADOSignInEndStore
- type APITokensByPrincipalPager
- type AWSSSOSpentTokenStore
- type ActiveRunsAtPathReader
- type ActiveRunsByCreatorReader
- type ApprovalNotifyReader
- type ApprovalsByRunCreatorPager
- type ApprovalsByRunPager
- type ApprovalsForRunsPager
- type AttachLease
- type AttachLeaseStore
- type AttachTicket
- type AuditChainStatus
- type AuditChainVerifier
- type AuditFilter
- type AuditPartitionExporter
- type AuditPartitionRow
- type AuditRetention
- type AuditRetentionDrop
- type AuditRetentionPartition
- type AuditRetentionPolicy
- type AuditRetentionPolicyChange
- type AuditRetentionRefused
- type AuditRetentionStatus
- type AuditSplitRange
- type AuditSplitRefused
- type AuditSplitResult
- type BrandingStore
- type CapabilityGrantsForPager
- type DelegateStore
- type DeprovisionFailure
- type DeprovisionJob
- type DeviceIngestResult
- type DeviceStore
- type EndedKept
- type ErrGovernanceChangeNotPending
- type ErrGovernanceChangePending
- type ErrProfileHasChildren
- type ExpiredGovernanceChange
- type GovernanceDecideFunc
- type GovernanceDecision
- type GovernanceProfileBuild
- type GrantsByRunPager
- type IdentityGuard
- type IdentityUpdate
- type JobKey
- type LeaverStore
- type LoginIdentity
- type LoginLocker
- type MemRunPATs
- func (m *MemRunPATs) InsertRunPAT(_ context.Context, p RunPAT) error
- func (m *MemRunPATs) LastRunPAT(_ context.Context, owner, providerRowID string) (RunPAT, bool, error)
- func (m *MemRunPATs) ListRunPATs(_ context.Context, runID uuid.UUID) ([]RunPAT, error)
- func (m *MemRunPATs) ListUnrevokedRunPATs(_ context.Context, f RunPATFilter) ([]RunPAT, error)
- func (m *MemRunPATs) MarkRunPATRevoked(_ context.Context, runID, authorizationID uuid.UUID, reason, lastError string) (bool, error)
- func (m *MemRunPATs) NoteRunPATRevokeFailed(_ context.Context, runID, authorizationID uuid.UUID, lastError string) error
- type PG
- func (s PG) ADOSignInEnds(ctx context.Context, owner string) (ADOSignInEndState, error)
- func (s PG) AWSSSOTokenSpent(ctx context.Context, fingerprint string) (bool, error)
- func (s PG) AcquireAttachLease(ctx context.Context, l AttachLease, from uuid.UUID, ttl time.Duration) (bool, error)
- func (s PG) ActiveRunsAtWorkspacePath(ctx context.Context, workspacePath string) ([]types.AgentRun, error)
- func (s PG) ActiveRunsByCreator(ctx context.Context, createdBy, task, agent string) ([]types.AgentRun, error)
- func (s PG) AddSSHKey(ctx context.Context, k types.SSHPublicKey) (types.SSHPublicKey, error)
- func (s PG) AddScimGroupMembers(ctx context.Context, id uuid.UUID, identities []uuid.UUID, now time.Time) error
- func (s PG) AddWorkspaceEgressDecision(ctx context.Context, id uuid.UUID, host string, allow bool, ...) (types.Workspace, error)
- func (s PG) AppendRunOutputChunk(ctx context.Context, runID uuid.UUID, replica string, b []byte, keep int) (bool, error)
- func (s PG) ApplyIdentityUpdate(ctx context.Context, id uuid.UUID, u IdentityUpdate, now time.Time) (PrincipalIdentity, error)
- func (s PG) ApprovalEscalations(ctx context.Context, ids []uuid.UUID, now time.Time) (map[uuid.UUID]types.ApprovalEscalation, error)
- func (s PG) ApprovalNotifyChannelStats(ctx context.Context, now time.Time) ([]types.ApprovalNotifyChannelStat, error)
- func (s PG) AuditHeadSeq(ctx context.Context) (int64, error)
- func (s PG) AuditKeyDestroyedAt(ctx context.Context, owner string) (time.Time, bool, error)
- func (s PG) AuditPartitionsAhead(ctx context.Context) (int, error)
- func (s PG) AuditPrincipalOf(ctx context.Context, id string) (string, bool, error)
- func (s PG) AuditRetentionStatus(ctx context.Context) (AuditRetentionStatus, error)
- func (s PG) AuditSubjectFor(ctx context.Context, principal string) (string, bool, error)
- func (s PG) AutodropAuditPartition(ctx context.Context) (AuditRetentionDrop, bool, error)
- func (s PG) BeginADOSignInEnd(ctx context.Context, owner, reason string) error
- func (s PG) BlankRunTasks(ctx context.Context, createdBy string) (int, error)
- func (s PG) ClaimSourceActiveRun(ctx context.Context, id, runID uuid.UUID) error
- func (s PG) ClaimStaleRunWatchers(ctx context.Context, owner string, staleAfter time.Duration) ([]types.AgentRun, error)
- func (s PG) ClaimWorkspaceActiveRun(ctx context.Context, id, runID uuid.UUID, expected *uuid.UUID) (types.Workspace, bool, error)
- func (s PG) ClearPauseSettle(ctx context.Context, id uuid.UUID, due time.Time) error
- func (s PG) ClearRunContainmentError(ctx context.Context, id uuid.UUID) (bool, error)
- func (s PG) ClearRunPaused(ctx context.Context, id uuid.UUID) (bool, error)
- func (s PG) ClearSourceActiveRun(ctx context.Context, id, runID uuid.UUID) error
- func (s PG) ClearWorkspaceActiveRun(ctx context.Context, id, runID uuid.UUID) (bool, error)
- func (s PG) ConsumeAttachTicket(ctx context.Context, token string, now time.Time) (AttachTicket, bool, error)
- func (s PG) ConsumeEnrolmentToken(ctx context.Context, token string, now time.Time) (types.DeviceEnrolmentToken, bool, error)
- func (s PG) CountActiveRunsBy(ctx context.Context, createdBy string) (int, error)
- func (s PG) CountApprovalsForRun(ctx context.Context, runID uuid.UUID) (int, error)
- func (s PG) CountHiddenRuns(ctx context.Context, f RunFilter) (olderHidden, killedHidden int, err error)
- func (s PG) CountNonTerminalRuns(ctx context.Context) (int, error)
- func (s PG) CountPendingApprovals(ctx context.Context) (int, error)
- func (s PG) CountPendingApprovalsByRunCreator(ctx context.Context, createdBy string) (int, error)
- func (s PG) CountPushPathLists(ctx context.Context, runID uuid.UUID) (int, error)
- func (s PG) CreateAPIToken(ctx context.Context, t types.APIToken, raw string) (types.APIToken, error)
- func (s PG) CreateApproval(ctx context.Context, a types.ApprovalRequest) (types.ApprovalRequest, error)
- func (s PG) CreateDelegate(ctx context.Context, d types.Delegate, raw string) (types.Delegate, error)
- func (s PG) CreateDevice(ctx context.Context, d types.Device, raw string) (types.Device, error)
- func (s PG) CreateGrant(ctx context.Context, g types.CredentialGrant) (types.CredentialGrant, error)
- func (s PG) CreatePerson(ctx context.Context, p types.Person) (types.Person, bool, error)
- func (s PG) CreatePolicy(ctx context.Context, p types.RunPolicy) (types.RunPolicy, error)
- func (s PG) CreateRun(ctx context.Context, r types.AgentRun) (types.AgentRun, error)
- func (s PG) CreateRunUnderCap(ctx context.Context, r types.AgentRun, limit int) (types.AgentRun, error)
- func (s PG) CreateScimGroup(ctx context.Context, externalID, displayName string, now time.Time) (ScimGroup, error)
- func (s PG) CreateScimIdentity(ctx context.Context, issuer, tenantID, objectID string, u IdentityUpdate, ...) (PrincipalIdentity, bool, error)
- func (s PG) CreateUserType(ctx context.Context, t types.UserType) (types.UserType, error)
- func (s PG) CreateWorkspace(ctx context.Context, ws types.Workspace) (types.Workspace, error)
- func (s PG) DecideApproval(ctx context.Context, id uuid.UUID, decision types.ApprovalDecision) (types.ApprovalRequest, error)
- func (s PG) DecideGovernanceChange(ctx context.Context, id uuid.UUID, d GovernanceDecision, ...) (types.GovernanceChange, error)
- func (s PG) DeleteBaseImage(ctx context.Context, id uuid.UUID, detach bool) error
- func (s PG) DeleteBranding(ctx context.Context) (bool, error)
- func (s PG) DeleteCapabilityGrant(ctx context.Context, id uuid.UUID) error
- func (s PG) DeleteGovernanceAssignment(ctx context.Context, id uuid.UUID) error
- func (s PG) DeleteGovernanceProfile(ctx context.Context, id uuid.UUID) error
- func (s PG) DeleteLaunchPreset(ctx context.Context, name string) (types.LaunchPreset, error)
- func (s PG) DeletePolicy(ctx context.Context, id uuid.UUID) error
- func (s PG) DeleteRef(ctx context.Context, ref string) error
- func (s PG) DeleteRoleMapping(ctx context.Context, id uuid.UUID) error
- func (s PG) DeleteRunOutputsOlderThan(ctx context.Context, age time.Duration) (int, error)
- func (s PG) DeleteRunProxyConfig(ctx context.Context, id uuid.UUID) error
- func (s PG) DeleteSSHKey(ctx context.Context, fingerprint, principal string) error
- func (s PG) DeleteSSHKeys(ctx context.Context, principal string) (int, error)
- func (s PG) DeleteScimGroup(ctx context.Context, id uuid.UUID) error
- func (s PG) DeleteSource(ctx context.Context, id uuid.UUID, detach bool) error
- func (s PG) DeleteUserDrive(ctx context.Context, id uuid.UUID) error
- func (s PG) DeleteUserDriveGrant(ctx context.Context, id uuid.UUID) (types.UserDriveGrant, error)
- func (s PG) DeleteUserSubjectRows(ctx context.Context, id uuid.UUID, principals, emails []string) (grants, assignments, kept int64, err error)
- func (s PG) DeleteUserType(ctx context.Context, id string) error
- func (s PG) DeleteWorkspace(ctx context.Context, id uuid.UUID) error
- func (s PG) DropAuditPartition(ctx context.Context, partition, digest, actor string) (AuditRetentionDrop, error)
- func (s PG) DryRunGovernance(ctx context.Context, fn func(q Querier) error) error
- func (s PG) DuePauseSettles(ctx context.Context) ([]PauseSettle, error)
- func (s PG) EnsureAuditPartitions(ctx context.Context, months int) (int, error)
- func (s PG) EnsureDeprovisionJobs(ctx context.Context, identityID uuid.UUID, kind string, keys []JobKey) error
- func (s PG) EraseGovernanceChangePersonalFields(ctx context.Context, names []string) (int, error)
- func (s PG) EraseRunOutputs(ctx context.Context, runIDs []uuid.UUID) error
- func (s PG) ExportAuditPartition(ctx context.Context, name string, header func(PartitionManifest) error, ...) error
- func (s PG) FailDeprovisionJob(ctx context.Context, identityID uuid.UUID, kind string, k JobKey, cause error) error
- func (s PG) FederationRevoked(ctx context.Context) (bool, error)
- func (s PG) FinishADOSignInEnd(ctx context.Context, owner string) error
- func (s PG) FinishDeprovisionJob(ctx context.Context, identityID uuid.UUID, kind string, k JobKey, ...) error
- func (s PG) GetAPITokenByRaw(ctx context.Context, raw string) (types.APIToken, error)
- func (s PG) GetApproval(ctx context.Context, id uuid.UUID) (types.ApprovalRequest, error)
- func (s PG) GetAttachLease(ctx context.Context, runID uuid.UUID) (AttachLease, bool, error)
- func (s PG) GetBaseImage(ctx context.Context, id uuid.UUID) (types.BaseImageEntry, error)
- func (s PG) GetBaseImagesByIDs(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID]types.BaseImageEntry, error)
- func (s PG) GetBranding(ctx context.Context) (types.Branding, error)
- func (s PG) GetCapabilityEnforcement(ctx context.Context) (map[string]bool, error)
- func (s PG) GetDelegateByRaw(ctx context.Context, raw string) (types.Delegate, error)
- func (s PG) GetDelegatedTokenByID(ctx context.Context, id uuid.UUID, now time.Time) (types.DelegatedToken, error)
- func (s PG) GetDelegatedTokenByRaw(ctx context.Context, raw string, now time.Time) (types.DelegatedToken, error)
- func (s PG) GetDeviceByRaw(ctx context.Context, raw string) (types.Device, error)
- func (s PG) GetFederationCursor(ctx context.Context) (int64, string, error)
- func (s PG) GetGovernanceChange(ctx context.Context, id uuid.UUID) (types.GovernanceChange, error)
- func (s PG) GetGovernanceProfile(ctx context.Context, id uuid.UUID) (types.GovernanceProfile, error)
- func (s PG) GetGovernanceProfileChain(ctx context.Context, id uuid.UUID) ([]types.GovernanceProfile, error)
- func (s PG) GetIdentity(ctx context.Context, id uuid.UUID) (PrincipalIdentity, error)
- func (s PG) GetIdentityByObject(ctx context.Context, issuer, tenantID, objectID string) (PrincipalIdentity, error)
- func (s PG) GetLaunchPreset(ctx context.Context, name string) (types.LaunchPreset, error)
- func (s PG) GetPerson(ctx context.Context, principal string) (types.Person, error)
- func (s PG) GetPolicy(ctx context.Context, id uuid.UUID) (types.RunPolicy, error)
- func (s PG) GetPrincipalPref(ctx context.Context, principal, key string) (json.RawMessage, error)
- func (s PG) GetPushPathList(ctx context.Context, approvalID uuid.UUID) (types.PushPathList, error)
- func (s PG) GetRef(ctx context.Context, ref string) (string, bool, error)
- func (s PG) GetRun(ctx context.Context, id uuid.UUID) (types.AgentRun, error)
- func (s PG) GetRunLayout(ctx context.Context, principal, preset string) (types.RunLayout, error)
- func (s PG) GetRunOutput(ctx context.Context, runID uuid.UUID) (RunOutput, bool, error)
- func (s PG) GetRunProxyConfig(ctx context.Context, id uuid.UUID) ([]byte, error)
- func (s PG) GetSSHKeyByFingerprint(ctx context.Context, fingerprint string) (types.SSHPublicKey, error)
- func (s PG) GetScimGroup(ctx context.Context, id uuid.UUID) (ScimGroup, error)
- func (s PG) GetSiteConfig(ctx context.Context) (types.SiteConfig, error)
- func (s PG) GetSource(ctx context.Context, id uuid.UUID) (types.Source, error)
- func (s PG) GetSourcesByIDs(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID]types.Source, error)
- func (s PG) GetUserDrive(ctx context.Context, id uuid.UUID) (types.UserDrive, error)
- func (s PG) GetUserType(ctx context.Context, id string) (types.UserType, error)
- func (s PG) GetWorkspace(ctx context.Context, id uuid.UUID) (types.Workspace, error)
- func (s PG) GroupRemovalFailures(ctx context.Context, limit int) ([]DeprovisionFailure, error)
- func (s PG) GroupRemovalIdentities(ctx context.Context, groupID uuid.UUID) ([]uuid.UUID, error)
- func (s PG) HasGroupTierAssignments(ctx context.Context) (bool, error)
- func (s PG) HasGroupTierDriveGrants(ctx context.Context) (bool, error)
- func (s PG) HasRunAuditEvent(ctx context.Context, runID uuid.UUID, f AuditFilter) (bool, error)
- func (s PG) HeartbeatRunWatcher(ctx context.Context, id uuid.UUID, owner string) error
- func (s PG) HeldEmails(ctx context.Context, id uuid.UUID, principals, emails []string) ([]string, error)
- func (s PG) HoldsAttachLease(ctx context.Context, runID, holderID uuid.UUID) (bool, error)
- func (s PG) IdentitiesByAlias(ctx context.Context, issuer, valueLower string) ([]PrincipalIdentity, error)
- func (s PG) IdentitiesByPrincipal(ctx context.Context, principal string) ([]PrincipalIdentity, error)
- func (s PG) IdentityAliasValues(ctx context.Context, id uuid.UUID) ([]string, error)
- func (s PG) IdentityBlocked(ctx context.Context, principal string, epoch int64) (bool, error)
- func (s PG) IdentityRefused(ctx context.Context, issuer, tenantID, objectID, principal string) (bool, error)
- func (s PG) IngestDeviceAudit(ctx context.Context, deviceID uuid.UUID, peer string, ...) (DeviceIngestResult, error)
- func (s PG) InsertPendingRunOutput(ctx context.Context, runID uuid.UUID) error
- func (s PG) InsertRunPAT(ctx context.Context, p RunPAT) error
- func (s PG) IssueLoginIdentity(ctx context.Context, in LoginIdentity, now time.Time) (epoch int64, err error)
- func (s PG) LastRunPAT(ctx context.Context, owner, providerRowID string) (RunPAT, bool, error)
- func (s PG) LatestAuditEventByAction(ctx context.Context, action string) (types.AuditEvent, error)
- func (s PG) ListAPITokens(ctx context.Context) ([]types.APIToken, error)
- func (s PG) ListAPITokensByPrincipal(ctx context.Context, principal string) ([]types.APIToken, error)
- func (s PG) ListAPITokensByPrincipalPage(ctx context.Context, principal string, p Page) ([]types.APIToken, error)
- func (s PG) ListApprovals(ctx context.Context, stateFilter types.ApprovalState) ([]types.ApprovalRequest, error)
- func (s PG) ListApprovalsPage(ctx context.Context, stateFilter types.ApprovalState, p Page) ([]types.ApprovalRequest, error)
- func (s PG) ListApprovalsPageByRun(ctx context.Context, runID uuid.UUID, stateFilter types.ApprovalState, p Page) ([]types.ApprovalRequest, error)
- func (s PG) ListApprovalsPageByRunCreator(ctx context.Context, createdBy string, stateFilter types.ApprovalState, p Page) ([]types.ApprovalRequest, error)
- func (s PG) ListAuditEventsAfterSeq(ctx context.Context, seq int64, limit int) ([]types.FederatedAuditEvent, error)
- func (s PG) ListBaseImages(ctx context.Context) ([]types.BaseImageEntry, error)
- func (s PG) ListCapabilityGrants(ctx context.Context) ([]types.CapabilityGrant, error)
- func (s PG) ListCapabilityGrantsFor(ctx context.Context, users, groups []string, userType string) ([]types.CapabilityGrant, error)
- func (s PG) ListCapabilityGrantsForPage(ctx context.Context, users, groups []string, userType string, p Page) ([]types.CapabilityGrant, error)
- func (s PG) ListCapabilityRestrictions(ctx context.Context) (map[string]map[string]bool, error)
- func (s PG) ListDeactivatedIdentities(ctx context.Context, limit int) ([]PrincipalIdentity, error)
- func (s PG) ListDelegates(ctx context.Context) ([]types.Delegate, error)
- func (s PG) ListDeprovisionFailures(ctx context.Context, limit int) ([]DeprovisionFailure, error)
- func (s PG) ListDeprovisionJobs(ctx context.Context, identityID uuid.UUID, kind string) ([]DeprovisionJob, error)
- func (s PG) ListDevices(ctx context.Context) ([]types.Device, error)
- func (s PG) ListEnrolmentTokens(ctx context.Context, now time.Time) ([]types.DeviceEnrolmentToken, error)
- func (s PG) ListGovernanceAssignments(ctx context.Context) ([]types.GovernanceAssignment, error)
- func (s PG) ListGovernanceChanges(ctx context.Context, state string) ([]types.GovernanceChange, error)
- func (s PG) ListGovernanceProfiles(ctx context.Context) ([]types.GovernanceProfile, error)
- func (s PG) ListGrantsByRun(ctx context.Context, runID uuid.UUID) ([]types.CredentialGrant, error)
- func (s PG) ListGrantsByRunPage(ctx context.Context, runID uuid.UUID, p Page) ([]types.CredentialGrant, error)
- func (s PG) ListGroupDenyGrants(ctx context.Context, capability string) ([]types.CapabilityGrant, error)
- func (s PG) ListLapsedTokenRuns(ctx context.Context, life time.Duration) ([]types.AgentRun, error)
- func (s PG) ListLaunchPresets(ctx context.Context) ([]types.LaunchPreset, error)
- func (s PG) ListLeasedRuns(ctx context.Context) ([]types.AgentRun, error)
- func (s PG) ListNonTerminalRunsBy(ctx context.Context, createdBy string) ([]types.AgentRun, error)
- func (s PG) ListPauseCandidates(ctx context.Context) ([]PauseCandidate, time.Time, error)
- func (s PG) ListPendingApprovalsForRuns(ctx context.Context, runIDs []uuid.UUID) ([]types.ApprovalRequest, error)
- func (s PG) ListPeople(ctx context.Context) ([]types.Person, error)
- func (s PG) ListPeopleDirectory(ctx context.Context, f PeopleDirectoryFilter) (PeopleDirectoryPage, error)
- func (s PG) ListPolicies(ctx context.Context) ([]types.RunPolicy, error)
- func (s PG) ListPoliciesPage(ctx context.Context, p Page) ([]types.RunPolicy, error)
- func (s PG) ListProfiledLiveRuns(ctx context.Context) ([]types.AgentRun, error)
- func (s PG) ListRoleMappings(ctx context.Context) ([]types.RoleMapping, error)
- func (s PG) ListRunPATs(ctx context.Context, runID uuid.UUID) ([]RunPAT, error)
- func (s PG) ListRunProxyReleases(ctx context.Context) ([]RunProxyRelease, error)
- func (s PG) ListRuns(ctx context.Context) ([]types.AgentRun, error)
- func (s PG) ListRunsFiltered(ctx context.Context, f RunFilter, p Page) ([]types.AgentRun, error)
- func (s PG) ListRunsPage(ctx context.Context, p Page) ([]types.AgentRun, error)
- func (s PG) ListRunsPageByCreator(ctx context.Context, createdBy string, p Page) ([]types.AgentRun, error)
- func (s PG) ListSSHKeysByPrincipal(ctx context.Context, principal string) ([]types.SSHPublicKey, error)
- func (s PG) ListSSHKeysByPrincipalPage(ctx context.Context, principal string, p Page) ([]types.SSHPublicKey, error)
- func (s PG) ListSources(ctx context.Context) ([]types.Source, error)
- func (s PG) ListStalePendingRunOutputs(ctx context.Context, age time.Duration, limit int) ([]uuid.UUID, error)
- func (s PG) ListUnrevokedRunPATs(ctx context.Context, f RunPATFilter) ([]RunPAT, error)
- func (s PG) ListUserDriveGrants(ctx context.Context) ([]types.UserDriveGrant, error)
- func (s PG) ListUserDriveGrantsPage(ctx context.Context, p Page) ([]types.UserDriveGrant, error)
- func (s PG) ListUserDrives(ctx context.Context) ([]types.UserDriveListItem, error)
- func (s PG) ListUserTypes(ctx context.Context) ([]types.UserType, error)
- func (s PG) ListWorkspaces(ctx context.Context) ([]types.Workspace, error)
- func (s PG) ListWorkspacesPage(ctx context.Context, p Page) ([]types.Workspace, error)
- func (s PG) ListWorkspacesPageForOwner(ctx context.Context, owner string, p Page) ([]types.Workspace, error)
- func (s PG) LockLoginSupersede(ctx context.Context, actor string) (func(), error)
- func (s PG) Locker() db.Locker
- func (s PG) MarkAWSSSOTokenSpent(ctx context.Context, fingerprint, owner string, markedAt time.Time) error
- func (s PG) MarkFederationRevoked(ctx context.Context) error
- func (s PG) MarkIdentityPurged(ctx context.Context, id uuid.UUID, requireDue bool) (bool, error)
- func (s PG) MarkPersonSignedIn(ctx context.Context, principal string, now time.Time) error
- func (s PG) MarkRunEnded(ctx context.Context, id uuid.UUID, now time.Time) (bool, error)
- func (s PG) MarkRunEndingSoon(ctx context.Context, id uuid.UUID, endsAt time.Time, thresholdSec int) (bool, error)
- func (s PG) MarkRunLost(ctx context.Context, id uuid.UUID, reason types.LostReason, now time.Time, ...) (bool, error)
- func (s PG) MarkRunOutputIncomplete(ctx context.Context, runID uuid.UUID) (bool, error)
- func (s PG) MarkRunPATRevoked(ctx context.Context, runID, authorizationID uuid.UUID, ...) (bool, error)
- func (s PG) MarkRunPaused(ctx context.Context, id uuid.UUID, reason types.PauseReason, ...) (bool, error)
- func (s PG) MarkRunRevived(ctx context.Context, id uuid.UUID, from types.LostReason, ended *EndedKept, ...) (bool, error)
- func (s PG) MergeWorkspaceRequirements(ctx context.Context, id uuid.UUID, add map[string]types.WorkspaceRequirement) (types.Workspace, error)
- func (s PG) MintAttachTicket(ctx context.Context, token string, t AttachTicket, now, expiresAt time.Time) error
- func (s PG) MintDelegatedToken(ctx context.Context, t types.DelegatedToken, raw string, now time.Time) (types.DelegatedToken, error)
- func (s PG) MintEnrolmentToken(ctx context.Context, token string, t types.DeviceEnrolmentToken) (types.DeviceEnrolmentToken, error)
- func (s PG) NotePauseSettle(ctx context.Context, id uuid.UUID, after time.Duration) (time.Time, error)
- func (s PG) NoteRunPATRevokeFailed(ctx context.Context, runID, authorizationID uuid.UUID, lastError string) error
- func (s PG) PendingGroupRemovals(ctx context.Context, idleFor time.Duration, limit int) ([]PendingGroupRemoval, error)
- func (s PG) PendingLeavers(ctx context.Context, idleFor time.Duration, limit int) ([]PendingLeaver, error)
- func (s PG) Ping(ctx context.Context) error
- func (s PG) PrincipalAliases(ctx context.Context, principal string) ([]string, error)
- func (s PG) PrincipalForName(ctx context.Context, name string) (string, error)
- func (s PG) PrincipalsByEmail(ctx context.Context, emails []string) ([]string, error)
- func (s PG) ProposeGovernanceChange(ctx context.Context, ch types.GovernanceChange, ttl time.Duration) (types.GovernanceChange, []ExpiredGovernanceChange, error)
- func (s PG) PruneAWSSSOSpentTokens(ctx context.Context, cutoff time.Time) (int, error)
- func (s PG) PurgeDueIdentities(ctx context.Context, limit int) ([]uuid.UUID, error)
- func (s PG) PurgeTerminalRunProxyConfigs(ctx context.Context) (int64, error)
- func (s PG) PutBranding(ctx context.Context, b types.Branding, keepLogo bool) (types.Branding, error)
- func (s PG) PutCapabilityEnforcement(ctx context.Context, enabled map[string]bool) (map[string]bool, error)
- func (s PG) PutLaunchPreset(ctx context.Context, p types.LaunchPreset) (types.LaunchPreset, PresetWrite, error)
- func (s PG) PutPrincipalPref(ctx context.Context, principal, key string, value json.RawMessage) error
- func (s PG) PutRef(ctx context.Context, ref, substrateName string) error
- func (s PG) PutRunLayout(ctx context.Context, principal, preset string, layout []types.RunLayoutWidget) (types.RunLayout, error)
- func (s PG) PutRunProxyConfig(ctx context.Context, id uuid.UUID, sealed []byte) error
- func (s PG) PutSiteConfig(ctx context.Context, cfg types.SiteConfig) (types.SiteConfig, error)
- func (s PG) QueryAuditEvents(ctx context.Context, runID uuid.UUID, limit int) ([]types.AuditEvent, error)
- func (s PG) QueryAuditEventsFilteredPage(ctx context.Context, runID *uuid.UUID, f AuditFilter, p Page) ([]types.AuditEvent, error)
- func (s PG) QueryAuditEventsPage(ctx context.Context, runID uuid.UUID, p Page) ([]types.AuditEvent, error)
- func (s PG) QueryRecentAuditEvents(ctx context.Context, limit int) ([]types.AuditEvent, error)
- func (s PG) QueryRecentAuditEventsPage(ctx context.Context, p Page) ([]types.AuditEvent, error)
- func (s PG) ReadRunOutputChunks(ctx context.Context, runID uuid.UUID, limit int) (RunOutputChunks, error)
- func (s PG) ReclampRunLimits(ctx context.Context, from types.AgentRun, toLimits types.RunLimits, ...) (bool, error)
- func (s PG) RecordPushPathList(ctx context.Context, approvalID, runID uuid.UUID, l types.PushPathList, ...) (bool, error)
- func (s PG) RefreshAPITokenIdentity(ctx context.Context, principal, role, userType string, groups []string, ...) error
- func (s PG) RefreshRunOutputClaim(ctx context.Context, runID uuid.UUID) error
- func (s PG) RefreshSSHKeyRoles(ctx context.Context, principal, role string, checkedAt time.Time) error
- func (s PG) ReleaseAttachLease(ctx context.Context, runID, holderID uuid.UUID) (bool, error)
- func (s PG) RenameScimGroup(ctx context.Context, id uuid.UUID, displayName string) error
- func (s PG) RenewAttachLease(ctx context.Context, runID, holderID uuid.UUID, ttl time.Duration) (bool, error)
- func (s PG) ReopenDeprovisionJob(ctx context.Context, identityID uuid.UUID, kind string, k JobKey) error
- func (s PG) ReserveAttachLease(ctx context.Context, runID, from uuid.UUID, taker, replica string, ...) (AttachLease, uuid.UUID, bool, error)
- func (s PG) ResetFederation(ctx context.Context) error
- func (s PG) ResolveGovernanceProfile(ctx context.Context, userSubjects, groups []string, userType string) (*types.GovernanceProfile, types.CapabilitySubjectType, error)
- func (s PG) ResolveReauthApproval(ctx context.Context, id uuid.UUID, decision types.ApprovalDecision, ...) (types.ApprovalRequest, error)
- func (s PG) ResolveUserDrive(ctx context.Context, userSubjects, groups []string, userType string) (*types.UserDrive, *types.UserDriveGrant, types.CapabilitySubjectType, error)
- func (s PG) ResumeGroupRemoval(ctx context.Context, groupID, identityID uuid.UUID) (bool, error)
- func (s PG) RevokeAPIToken(ctx context.Context, id uuid.UUID, principal string, now time.Time) (types.APIToken, error)
- func (s PG) RevokeDelegate(ctx context.Context, id uuid.UUID, now time.Time) (types.Delegate, error)
- func (s PG) RevokeDevice(ctx context.Context, id uuid.UUID, now time.Time) (types.Device, error)
- func (s PG) RevokeEnrolmentToken(ctx context.Context, id uuid.UUID, now time.Time) (types.DeviceEnrolmentToken, error)
- func (s PG) RunCapacity(ctx context.Context, o RunCapacityOpts) (RunCapacity, error)
- func (s PG) RunHasOpenRequest(ctx context.Context, id uuid.UUID) (bool, error)
- func (s PG) RunIDsCreatedBy(ctx context.Context, createdBy string) ([]uuid.UUID, error)
- func (s PG) RunWatcherFresh(ctx context.Context, id uuid.UUID, staleAfter time.Duration) (bool, error)
- func (s PG) SaveChunkedRunOutput(ctx context.Context, runID uuid.UUID, maskScope string, limit int) (bool, error)
- func (s PG) SaveFinalRunOutput(ctx context.Context, o RunOutput) error
- func (s PG) SaveGapRunOutput(ctx context.Context, runID uuid.UUID) (bool, error)
- func (s PG) ScimGroupMembers(ctx context.Context, id uuid.UUID) ([]uuid.UUID, error)
- func (s PG) SearchIdentities(ctx context.Context, issuer, attr, value string, limit int) ([]PrincipalIdentity, error)
- func (s PG) SearchScimGroups(ctx context.Context, attr, value string, limit int) ([]ScimGroup, error)
- func (s PG) SetAuditRetentionPolicy(ctx context.Context, days int) (AuditRetentionPolicyChange, error)
- func (s PG) SetBrandingLogo(ctx context.Context, logo []byte, logoType string, fromFile bool, ...) (bool, error)
- func (s PG) SetCapabilityRestriction(ctx context.Context, capability, value string, restricted bool, by string) error
- func (s PG) SetFederationCursor(ctx context.Context, seq int64, rowHash string) error
- func (s PG) SetRunAgentExecID(ctx context.Context, id uuid.UUID, execID string) error
- func (s PG) SetRunContainmentError(ctx context.Context, id uuid.UUID, msg string, now time.Time) error
- func (s PG) SetRunDiskMiB(ctx context.Context, id uuid.UUID, mib int) error
- func (s PG) SetRunEndAndWait(ctx context.Context, id uuid.UUID, fromLimits types.RunLimits, ...) (bool, error)
- func (s PG) SetRunFailureHint(ctx context.Context, id uuid.UUID, hint string) error
- func (s PG) SetRunImage(ctx context.Context, id uuid.UUID, image string) error
- func (s PG) SetRunProxyRelease(ctx context.Context, id uuid.UUID, release string) error
- func (s PG) SetRunSizing(ctx context.Context, id uuid.UUID, z RunSizing) error
- func (s PG) SetRunStatusDetail(ctx context.Context, id uuid.UUID, detail string) error
- func (s PG) SetRunTitle(ctx context.Context, id uuid.UUID, title string) error
- func (s PG) SetSandboxRef(ctx context.Context, id uuid.UUID, ref string) error
- func (s PG) SetSourceScanResult(ctx context.Context, id uuid.UUID, profile []byte, ...) (types.Source, error)
- func (s PG) SetSourceScanResultUnfenced(ctx context.Context, id uuid.UUID, profile []byte, ...) (types.Source, error)
- func (s PG) SetWorkspaceApprovedEgress(ctx context.Context, id uuid.UUID, domains []string) (types.Workspace, error)
- func (s PG) SetWorkspaceBuiltImage(ctx context.Context, id uuid.UUID, imageRef, builtHash string) (types.Workspace, error)
- func (s PG) SetWorkspaceDeniedEgress(ctx context.Context, id uuid.UUID, domains []string) (types.Workspace, error)
- func (s PG) SetWorkspaceImportState(ctx context.Context, id uuid.UUID, status types.WorkspaceStatus, ...) (types.Workspace, bool, error)
- func (s PG) SetWorkspaceLLMCred(ctx context.Context, id uuid.UUID, cred *types.WorkspaceLLMCred) (types.Workspace, error)
- func (s PG) SetWorkspaceOwner(ctx context.Context, id uuid.UUID, owner string) (types.Workspace, error)
- func (s PG) SetWorkspaceRecordResult(ctx context.Context, id uuid.UUID, taskKey string, result json.RawMessage, ...) (types.Workspace, bool, error)
- func (s PG) SetWorkspaceRequirements(ctx context.Context, id uuid.UUID, reqs map[string]types.WorkspaceRequirement) (types.Workspace, error)
- func (s PG) SpendApprovalOnce(ctx context.Context, id uuid.UUID, jti string) (bool, error)
- func (s PG) StampRunActive(ctx context.Context, id uuid.UUID) (bool, error)
- func (s PG) StampRunTokenRenewed(ctx context.Context, id uuid.UUID) (bool, error)
- func (s PG) StartGroupRemoval(ctx context.Context, groupID, identityID uuid.UUID) error
- func (s PG) StopKeptRunIf(ctx context.Context, id uuid.UUID, to types.RunState, lostAt *time.Time, ...) (bool, error)
- func (s PG) SubjectKeyDestroyedSince(ctx context.Context, owner, purpose string, since time.Time) (bool, error)
- func (s PG) SuspendIdentity(ctx context.Context, p SuspendPlan) (SuspendResult, error)
- func (s PG) TouchAPIToken(ctx context.Context, id uuid.UUID, now time.Time) error
- func (s PG) TouchDevice(ctx context.Context, id uuid.UUID, now time.Time) error
- func (s PG) TouchRun(ctx context.Context, id uuid.UUID) error
- func (s PG) UpdateBaseImageName(ctx context.Context, id uuid.UUID, name string) (types.BaseImageEntry, error)
- func (s PG) UpdatePolicy(ctx context.Context, id uuid.UUID, name string, spec types.RunPolicySpec) (types.RunPolicy, error)
- func (s PG) UpdateRunStateIf(ctx context.Context, id uuid.UUID, fromState, toState types.RunState) (bool, error)
- func (s PG) UpdateRunStateIfCreatedBefore(ctx context.Context, id uuid.UUID, fromState, toState types.RunState, ...) (bool, error)
- func (s PG) UpdateRunStateIfIdle(ctx context.Context, id uuid.UUID, fromState, toState types.RunState, ...) (bool, error)
- func (s PG) UpdateSourceConfig(ctx context.Context, id uuid.UUID, name string, ...) (types.Source, error)
- func (s PG) UpdateUserType(ctx context.Context, t types.UserType) (types.UserType, error)
- func (s PG) UpdateUserTypeMetadata(ctx context.Context, t types.UserType) (types.UserType, error)
- func (s PG) UpdateWorkspace(ctx context.Context, id uuid.UUID, ws types.Workspace, stampEgressEdit bool) (types.Workspace, error)
- func (s PG) UpsertBaseImage(ctx context.Context, b types.BaseImageEntry) (types.BaseImageEntry, error)
- func (s PG) UpsertCapabilityGrant(ctx context.Context, g types.CapabilityGrant) (types.CapabilityGrant, error)
- func (s PG) UpsertGovernanceAssignment(ctx context.Context, a types.GovernanceAssignment) (types.GovernanceAssignment, error)
- func (s PG) UpsertGovernanceProfile(ctx context.Context, p types.GovernanceProfile) (types.GovernanceProfile, error)
- func (s PG) UpsertLoginIdentity(ctx context.Context, in LoginIdentity, now time.Time) (PrincipalIdentity, error)
- func (s PG) UpsertRoleMapping(ctx context.Context, m types.RoleMapping) (types.RoleMapping, error)
- func (s PG) UpsertSource(ctx context.Context, src types.Source) (types.Source, error)
- func (s PG) UpsertUserDrive(ctx context.Context, d types.UserDrive, refuseIfAllocated bool) (types.UserDrive, error)
- func (s PG) UpsertUserDriveGrant(ctx context.Context, g types.UserDriveGrant, homeOverrideStated bool) (types.UserDriveGrant, error)
- func (s PG) UserTypeReferences(ctx context.Context, id string) (int, error)
- func (s PG) UserTypeTokenStamps(ctx context.Context, id string) (int, error)
- func (s PG) VerifyAuditChain(ctx context.Context) (AuditChainStatus, error)
- func (s PG) WithIdentityShared(ctx context.Context, g IdentityGuard, fn func() error) error
- func (s PG) WorkspacesAttaching(ctx context.Context, id uuid.UUID) ([]string, error)
- func (s PG) WorkspacesUsingBaseImage(ctx context.Context, id uuid.UUID) ([]string, error)
- func (s PG) WriteGovernanceProfile(ctx context.Context, id uuid.UUID, build GovernanceProfileBuild) (types.GovernanceProfile, error)
- type Page
- type Pager
- type PartitionDigest
- type PartitionManifest
- type PauseCandidate
- type PauseSettle
- type PauseSettler
- type PendingGroupRemoval
- type PendingLeaver
- type PeopleDirectoryFilter
- type PeopleDirectoryPage
- type PeopleDirectoryStore
- type PersonErasureStore
- type PersonListing
- type PersonStore
- type PresetWrite
- type PrincipalIdentity
- type PrincipalIdentityStore
- type PrincipalPrefStore
- type PushPathListStore
- type Querier
- type Recorder
- type RunAuditMatcher
- type RunCapacity
- type RunCapacityAge
- type RunCapacityOpts
- type RunCapacityOwner
- type RunCapacityRunner
- type RunCapacitySums
- type RunCapacityUnschedulable
- type RunFilter
- type RunLayoutStore
- type RunLeaser
- type RunLimitsReclamper
- type RunLoser
- type RunOutput
- type RunOutputChunkStore
- type RunOutputChunks
- type RunOutputStore
- type RunPAT
- type RunPATFilter
- type RunPATReader
- type RunPATStore
- type RunPauser
- type RunProxyConfigs
- type RunProxyRelease
- type RunReviver
- type RunSizing
- type RunTitler
- type RunWatcherLeaser
- type RunsByCreatorPager
- type RunsFilteredPager
- type SSHKeysByPrincipalPager
- type ScimGroup
- type ScimGroupStore
- type Store
- type SuspendPlan
- type SuspendResult
- type WorkspacesByOwnerPager
Constants ¶
const ( AuditOriginDevice = "device" AuditOriginOrganisation = "organisation" )
The two AuditFilter.Origin values: rows a device forwarded, and rows the organisation wrote itself (FederatedDeviceID decides which is which).
const ( RetentionNotOldest = "audit_retention_not_oldest" RetentionNotClosed = "audit_retention_not_closed" RetentionInsideWindow = "audit_retention_inside_window" RetentionLiveRun = "audit_retention_live_run" RetentionDigestMismatch = "audit_retention_digest_mismatch" )
The refusal reasons audit_retention_drop (migration 0123) raises, one SQLSTATE each. They are also the wire reasons of POST /audit/retention/drop, registered in internal/authz.
const ( SplitNotOwner = "audit_split_not_migrator" SplitNotPartitioned = "audit_split_not_partitioned" SplitNoLegacy = "audit_split_no_legacy_partition" SplitEmpty = "audit_split_legacy_empty" SplitChainBroken = "audit_split_chain_broken" SplitNameTaken = "audit_split_name_taken" )
The refusal reasons of SplitLegacyAudit. Each is a state the split must not run in; nothing was changed.
const ( JobKindSuspend = "suspend" // JobStepCutoff is step 1 of a suspension: the cutoff, the deactivation and the epoch bump. JobStepCutoff = "cutoff" )
Job kinds and the one step name every kind shares.
const ( SearchExternalID = "externalId" SearchUserName = "userName" SearchEmail = "emails.value" )
SearchIdentities attrs, as SCIM spells them.
const ( JobKindPurge = "purge" JobStepAuditDeprovision = "audit_deprovision" )
JobKindPurge is the ledger kind of a purge; JobStepAuditDeprovision is the step it ends on, and the one MarkIdentityPurged records pending so a purge that dies right after the mark is still on the ledger.
const ( PeopleDirectoryDefaultLimit = 50 PeopleDirectoryMaxLimit = 200 )
A Limit of zero is PeopleDirectoryDefaultLimit; one above PeopleDirectoryMaxLimit is clamped to it.
const ( JobKindGroupRemove = "group_remove" GroupStepSessions = "sessions" GroupStepTokens = "tokens" GroupStepAudit = "audit" )
The group removal ledger (migration 0127's group_remove kind): one set of rows per person and group, the target of every step being the group's id.
const ADOSignInEndsStaleAfter = 10 * time.Minute
ADOSignInEndsStaleAfter is how long an end that began and never finished (its replica died) still counts as running. Past it the count settles, so a person's mints stop revoking themselves; an end finishes in seconds.
const AuditTargetTruncatedMarker = "…[truncated]"
AuditTargetTruncatedMarker is appended to a capped target so the row says what happened to it. Without it a truncated path reads as a real one, and an operator matching `target = '/api/v1/policies/aaa…'` would believe it.
const FederatedClaimHashSQL = `` /* 334-byte string literal not displayed */
FederatedClaimHashSQL recomputes, from one stored federated row aliased e, the hash the device claimed for it: equals e.data->'device_origin'->>'row_hash' for every row IngestDeviceAudit accepts. Claimed actor/source_ip/prev_hash live in device_origin; the claimed object is stored data minus that key; a data-less claim is named by device_origin.data_null ("json" for JSON null, "sql" for absent).
const HoldsSandboxSQL = `(lost_at IS NULL OR (lost_reason = '` + string(types.LostOutage) + `' AND (ends_at IS NULL OR ends_at > now())))`
HoldsSandboxSQL is TRUE when the agent_runs row's agent is still running: the run is not kept, or it was kept after a control-plane outage and has not reached its end, so only its proxy was stopped (api stopLostSandbox). A run kept after its end or a reboot, or an outage-kept run past its end, has its agent stopped. It is the one rule for a live run under WARDYN_MAX_CONCURRENT_RUNS, in the fleet capacity view and under WARDYN_RUN_MAX_AGE.
const MaxAuditTargetLen = 512
MaxAuditTargetLen bounds the audit row's `target` column (plain TEXT, unbounded). An authenticated caller looping a huge path via authz.denied (unrate-limited, unlike auth.fail) could otherwise write megabytes per second into a table whose Postgres trigger forbids DELETE; 512 bytes holds every real target this tree writes with an order of magnitude to spare.
const PeopleDirectoryActiveSessionWindow = 24 * time.Hour
PeopleDirectoryActiveSessionWindow is how recent a sign-in must be to count as a live session. Sessions are stateless signed cookies the server keeps no row for, so the directory knows only when a person last signed in, not how many cookies are out: it counts one when that sign-in is inside this window and no revoke cutoff has passed it.
const ReauthHoldMax = 1800 * time.Second
ReauthHoldMax is the longest a credential re-auth hold keeps the agent's connection parked (WARDYN_CREDENTIAL_REAUTH_TIMEOUT's ceiling). A re-auth request counts toward a waiting pause only once it is older than this: until then the agent is still inside the connection that asked, and freezing it would cut a sign-in the person may be finishing.
const SearchDisplayName = "displayName"
SearchDisplayName is the Groups filter attribute that SearchExternalID shares the rest of with Users.
const SystemAuditActor = "wardynd"
SystemAuditActor is the actor an unattended retention drop (WARDYN_AUDIT_RETENTION_AUTODROP) records: audit_retention_drop treats exactly this name as the system and marks the chained event unattested.
Variables ¶
var AuditChainPageSize int32 = 1000
AuditChainPageSize is how many rows one page of the verify sweep reads — bounds memory to a page, never the table. Large enough that the per-page round trip is noise against re-hashing a thousand rows, small enough to stay a few hundred kilobytes. A var only so the parity test can shrink it and cross page boundaries.
var ErrAlreadyDecided = types.ErrApprovalAlreadyDecided
ErrAlreadyDecided is returned when DecideApproval targets an approval that has already left PENDING. Fail closed: a second decision never overwrites the first.
var ErrAuditPartitionOpen = errors.New("store: audit partition is still open")
ErrAuditPartitionOpen is a partition that can still receive rows: it has no digest yet.
var ErrConflict = errors.New("store: conflict")
ErrConflict reports a fenced write losing its race: a source scan slot already claimed, or the requirements merge hitting the key cap.
var ErrDeviceRevoked = errors.New("store: device is revoked")
ErrDeviceRevoked is IngestDeviceAudit's answer for a device revoked after its request was authenticated. Distinct from ErrConflict so the caller answers it as revocation, never a broken chain.
var ErrDriveAllocated = fmt.Errorf( "%w: this user drive gained an allocation while the write was being prepared", ErrConflict)
ErrDriveAllocated is returned by UpsertUserDrive when the caller asked for the write to apply only while the drive has no allocations (refuseIfAllocated) and the row has some. It is the statement-level half of the API's re-home guard: since a plain read-then-write would let a grant created in between get silently re-homed, the precondition rides the writing statement under a FOR UPDATE on the drive row in the same transaction, making it race-free.
var ErrDriveHomeNamespaceConflict = fmt.Errorf( "%w: another host_path drive on this host_root derives home directory names by a different rule", ErrConflict)
ErrDriveHomeNamespaceConflict is returned by UpsertUserDrive when a host_path drive would share a host_root with another host_path drive that derives home directory NAMES by a different rule. Wraps ErrConflict (as do ErrDriveSlugConflict and ErrDriveAllocated below) so callers asking only "is this a 409?" keep working, while the remedy stays distinguishable from a plain UNIQUE(name) collision.
var ErrDriveSlugConflict = fmt.Errorf( "%w: another user drive's name folds to the same storage-object name", ErrConflict)
ErrDriveSlugConflict is returned by UpsertUserDrive when a drive's name folds to a storage-object slug another drive already holds — "Corp NAS" against an existing "corp nas", or "Corp NAS (eng)" against "corp-nas-eng". Distinct from UNIQUE(name): the name itself is free, but types.DriveSlug(name) — the fragment every minted object name is built from — collides, so the remedy is a name differing by more than case or punctuation.
var ErrDuplicatePending = types.ErrDuplicatePendingApproval
ErrDuplicatePending is returned by CreateApproval when a partial unique index rejects a second open PENDING approval for the same dedup key (a concurrent raise lost the race). Callers treat it as a dedup signal — re-read and return the existing PENDING row — not a hard failure.
var ErrFederatedOrgRun = errors.New("store: federated row names an organisation run")
ErrFederatedOrgRun refuses a batch where a row's run_id names one of this organisation's own runs: phase one federates audit rows, never run records, so a laptop's row can't legitimately belong to one.
var ErrFederatedRowInvalid = errors.New("store: federated row cannot be stored as claimed")
ErrFederatedRowInvalid refuses a batch holding a row this organisation can't store (FederatedRowProblem) or a value Postgres can't represent (SQLSTATE class 22); the caller answers 4xx so the forwarder stops rather than retrying a 5xx forever.
var ErrGovernanceChangeStale = errors.New("store: the governance change is stale")
ErrGovernanceChangeStale is what a decision's apply returns when the target is no longer what the proposal reviewed. DecideGovernanceChange moves the change to stale and commits that, and returns this error.
var ErrIdentityBindingMismatch = errors.New("store: identity bound to another principal")
ErrIdentityBindingMismatch is a sign-in's refusal when the identity it names is already bound to another principal: issuing its session under the new one would leave it outside the identity's deactivation and epoch checks. Nothing is written.
var ErrIdentityDeactivated = errors.New("store: identity deactivated")
ErrIdentityDeactivated is the refusal of anything that would give a deactivated, purged or stale-epoch identity a new session, credential or run.
var ErrIdentityPurged = errors.New("store: identity purged")
ErrIdentityPurged is a reactivation's refusal: a purged identity is a permanent tombstone.
var ErrIdentityRebound = errors.New("store: the identity was bound since the suspension was planned")
ErrIdentityRebound is a SuspendPlan made before a sign-in bound the identity row: its forms miss the newly bound principal, so the caller reads the row again and makes a new plan.
var ErrLoginLockNoCapacity = db.ErrAdvisoryLockNoCapacity
ErrLoginLockNoCapacity is the one LockLoginSupersede error a caller may proceed unlocked on (the pool can't spare a connection); any other error means the caller should refuse.
var ErrNotFound = errors.New("store: not found")
ErrNotFound is returned when a Get* call finds no row.
var ErrPushPathListCap = errors.New("store: this run has stored its limit of push path lists")
ErrPushPathListCap is RecordPushPathList's refusal: the run already has its limit of lists.
var ErrRunCapReached = errors.New("store: deployment run cap reached")
ErrRunCapReached is CreateRunUnderCap's refusal: the deployment already holds its cap of non-terminal runs.
var ErrRunOutputErased = errors.New("store: the run's output was erased")
ErrRunOutputErased is every writer's and reader's answer for a run whose output was erased: the tombstone is checked in the same transaction as the write or read, under the run's lock, so no replica can recreate or serve it.
var ErrScimGroupExists = errors.New("store: scim group exists")
ErrScimGroupExists is a create whose externalId already names a group.
var GroupRemovalSteps = []string{GroupStepSessions, GroupStepTokens, GroupStepAudit}
GroupRemovalSteps are the steps StartGroupRemoval opens, in the order they run.
Functions ¶
func CapAuditTarget ¶ added in v0.7.4
CapAuditTarget bounds one audit target. A target already within the cap is returned BYTE-IDENTICAL: audit queries match this column exactly, so the cap must be invisible to every row that is not abusive.
func DeleteCapabilityGrantQ ¶ added in v0.8.6
DeleteCapabilityGrantQ is DeleteCapabilityGrant's statement on q.
func DeleteGovernanceAssignmentQ ¶ added in v0.8.6
DeleteGovernanceAssignmentQ is DeleteGovernanceAssignment's statement on q.
func DeleteGovernanceProfileQ ¶ added in v0.8.6
DeleteGovernanceProfileQ is DeleteGovernanceProfile's body on a caller's transaction (q must be a pgx.Tx: it takes the transaction-scoped graph lock) and answers the same errors.
func DeleteRoleMappingQ ¶ added in v0.8.6
DeleteRoleMappingQ is DeleteRoleMapping's statement on q.
func FederatedActor ¶ added in v0.8.0
FederatedActor is the actor a federated row is stored under: the forwarding device's own actor (device:<id>), a slash, then the claimed principal, so an org-principal filter never matches a laptop's claim.
func FederatedDeviceID ¶ added in v0.8.0
func FederatedDeviceID(ev types.AuditEvent) *uuid.UUID
FederatedDeviceID reports which device forwarded ev, or nil for the organisation's own row. TRUST BOUNDARY: federated only when both marks agree — data.device_origin.device_id and the FederatedActor prefix naming the same device — so no writer controlling only one can make its own row read as a device's. federatedRowSQL is the same predicate in SQL.
func FederatedRowProblem ¶ added in v0.8.0
func FederatedRowProblem(r types.FederatedAuditEvent) string
FederatedRowProblem says why r cannot be stored so its claim re-checks from the stored row, or "" when it can. data must be a JSON object without a top-level device_origin key (this organisation's marker), JSON null, or absent; target must be one CapAuditTarget leaves unchanged; device_id is this organisation's to derive, never the device's to claim. Exported so the API refuses with a 400 before any database work.
func GetCapabilityEnforcementQ ¶ added in v0.8.6
GetCapabilityEnforcementQ is GetCapabilityEnforcement on q.
func GetCapabilityGrantByKeyQ ¶ added in v0.8.6
func GetCapabilityGrantByKeyQ(ctx context.Context, q Querier, subjectType, subject, capability, value string, forUpdate bool) (types.CapabilityGrant, error)
GetCapabilityGrantByKeyQ reads the grant at one natural key on q, ErrNotFound when none; forUpdate locks the row.
func GetCapabilityGrantQ ¶ added in v0.8.6
func GetCapabilityGrantQ(ctx context.Context, q Querier, id uuid.UUID, forUpdate bool) (types.CapabilityGrant, error)
GetCapabilityGrantQ reads one grant by id on q, ErrNotFound when none; forUpdate locks the row.
func GetGovernanceAssignmentByKeyQ ¶ added in v0.8.6
func GetGovernanceAssignmentByKeyQ(ctx context.Context, q Querier, subjectType, subject string, forUpdate bool) (types.GovernanceAssignment, error)
GetGovernanceAssignmentByKeyQ reads the assignment at one natural key on q, ErrNotFound when none.
func GetGovernanceAssignmentQ ¶ added in v0.8.6
func GetGovernanceAssignmentQ(ctx context.Context, q Querier, id uuid.UUID, forUpdate bool) (types.GovernanceAssignment, error)
GetGovernanceAssignmentQ reads one assignment by id on q, ErrNotFound when none; forUpdate locks the row for the transaction.
func GetGovernanceProfileQ ¶ added in v0.8.6
func GetGovernanceProfileQ(ctx context.Context, q Querier, id uuid.UUID, forUpdate bool) (types.GovernanceProfile, error)
GetGovernanceProfileQ reads one profile row (raw, as GetGovernanceProfile does) on q.
func GetLiveAPITokenQ ¶ added in v0.8.6
GetLiveAPITokenQ re-reads one token by id on q (a caller's transaction), and only while it can still authenticate: revoked and expired rows are ErrNotFound, as in GetAPITokenByRaw. A decision that must still hold the authority of the token it was made with reads it again through this, not through the context the request was authenticated with.
func GetUserTypeQ ¶ added in v0.8.6
func GetUserTypeQ(ctx context.Context, q Querier, id string, forUpdate bool) (types.UserType, error)
GetUserTypeQ is GetUserType on q; forUpdate locks the row for the transaction.
func InsertAuditEvent ¶
InsertAuditEvent appends a single audit event. Implements audit.Recorder. The Postgres trigger blocks UPDATE/DELETE; this function only ever INSERTs.
ev is taken by POINTER so the hash chain can be handed back: on success ev.PrevHash/ev.RowHash carry the values Postgres computed, and ev.RowHash IS the chain head at that instant, which fanoutRecorder emits to the audit sinks so an external SIEM ends up holding a head hash Wardyn cannot later disown.
Runs in a transaction because pg_advisory_xact_lock must be held across the append: this caller's seq allocation and head read must not interleave with another writer's, keeping seq order and chain order identical. audit_append takes the same lock itself (the only way a row enters the table since 0111); the lock here is re-entrant and free, and keeps the bounded wait below in front of it.
func InsertAuditEventTx ¶ added in v0.8.6
InsertAuditEventTx is InsertAuditEvent's body on a caller-supplied transaction: the same target cap, pinned lock-wait bound and advisory lock on the chain, so a row written this way links exactly as every other row does.
func ListCapabilityGrantsQ ¶ added in v0.8.6
ListCapabilityGrantsQ is ListCapabilityGrants on q.
func ListCapabilityRestrictionsQ ¶ added in v0.8.6
func ListCapabilityRestrictionsQ(ctx context.Context, q Querier) (map[string]map[string]bool, error)
ListCapabilityRestrictionsQ is ListCapabilityRestrictions on q.
func ListGovernanceProfilesQ ¶ added in v0.8.6
ListGovernanceProfilesQ reads every profile by name on q.
func ListRoleMappingsQ ¶ added in v0.8.6
ListRoleMappingsQ is ListRoleMappings on q.
func ListUserTypesQ ¶ added in v0.8.6
ListUserTypesQ is ListUserTypes on q.
func LockGovernanceAssignmentKey ¶ added in v0.8.6
LockGovernanceAssignmentKey takes the transaction-scoped lock keyed to one assignment's natural key, so a write to that key and the approval of a held change to it serialize. q must be a pgx.Tx.
func LockGovernanceGraph ¶ added in v0.8.6
LockGovernanceGraph takes the transaction-scoped lock every write to the governance profile graph holds, so one write at a time sees and changes it. q must be a pgx.Tx.
func LockGovernanceTarget ¶ added in v0.8.6
LockGovernanceTarget takes the transaction-scoped lock for one target of a governance change: the direct write to it and the approval of a held change to it serialize on it. parts are the target's natural key. q must be a pgx.Tx.
func PutCapabilityEnforcementQ ¶ added in v0.8.6
func PutCapabilityEnforcementQ(ctx context.Context, q Querier, enabled map[string]bool) (map[string]bool, error)
PutCapabilityEnforcementQ is PutCapabilityEnforcement's statements on q. A held governance change applies through it inside the decision transaction.
func SetCapabilityRestrictionQ ¶ added in v0.8.6
func SetCapabilityRestrictionQ(ctx context.Context, q Querier, capability, value string, restricted bool, by string) error
SetCapabilityRestrictionQ is SetCapabilityRestriction's statement on q.
func UpdateUserTypeQ ¶ added in v0.8.6
UpdateUserTypeQ is UpdateUserType's statement on q. A held governance change applies through it inside the decision transaction.
func UpsertCapabilityGrantQ ¶ added in v0.8.6
func UpsertCapabilityGrantQ(ctx context.Context, q Querier, g types.CapabilityGrant) (types.CapabilityGrant, error)
UpsertCapabilityGrantQ is UpsertCapabilityGrant's statement on q. A held governance change applies through it inside the decision transaction.
func UpsertGovernanceAssignmentQ ¶ added in v0.8.6
func UpsertGovernanceAssignmentQ(ctx context.Context, q Querier, a types.GovernanceAssignment) (types.GovernanceAssignment, error)
UpsertGovernanceAssignmentQ is UpsertGovernanceAssignment's statement on q.
func UpsertRoleMappingQ ¶ added in v0.8.6
func UpsertRoleMappingQ(ctx context.Context, q Querier, m types.RoleMapping) (types.RoleMapping, error)
UpsertRoleMappingQ is UpsertRoleMapping's statement on q (the doc above is its contract). A held governance change applies through it inside the decision transaction.
func WithIdentityGuard ¶ added in v0.8.6
func WithIdentityGuard(ctx context.Context, g IdentityGuard) context.Context
WithIdentityGuard makes the insert writers that honour it (CreateRun, CreateRunUnderCap, CreateAPIToken, AddSSHKey) read the owner's identity rows FOR SHARE in their own transaction. Suspension takes the same rows FOR UPDATE, so a write either commits before the suspension's first step, where the sweep after it finds it, or reads the deactivation and is refused.
func WriteGovernanceProfileQ ¶ added in v0.8.6
func WriteGovernanceProfileQ(ctx context.Context, q Querier, id uuid.UUID, build GovernanceProfileBuild) (types.GovernanceProfile, error)
WriteGovernanceProfileQ is WriteGovernanceProfile's body on a caller's transaction: q must be a pgx.Tx, because the graph lock it takes is transaction-scoped. A held governance change applies through it inside the decision transaction.
Types ¶
type ADOSignInEndState ¶ added in v0.8.6
type ADOSignInEndState struct {
Gen int64
Running bool // an end began and has not finished, within ADOSignInEndsStaleAfter
Reason string
}
ADOSignInEndState is one person's count.
type ADOSignInEndStore ¶ added in v0.8.6
type ADOSignInEndStore interface {
// BeginADOSignInEnd marks the start of an end of owner's sign-in.
BeginADOSignInEnd(ctx context.Context, owner, reason string) error
// FinishADOSignInEnd marks its finish.
FinishADOSignInEnd(ctx context.Context, owner string) error
// ADOSignInEnds is owner's count now; a person with no row has gen 0.
ADOSignInEnds(ctx context.Context, owner string) (ADOSignInEndState, error)
}
ADOSignInEndStore is the sign-in end counter. Optional like RunOutputStore: the api layer type-asserts, and a store without it counts in the process.
type APITokensByPrincipalPager ¶ added in v0.8.0
type APITokensByPrincipalPager interface {
ListAPITokensByPrincipalPage(ctx context.Context, principal string, p Page) ([]types.APIToken, error)
}
APITokensByPrincipalPager is the scoped analogue of Pager for GET /me/tokens, same safe-fallback posture as GrantsByRunPager (ListAPITokensByPrincipal is already WHERE principal=$1).
type AWSSSOSpentTokenStore ¶ added in v0.8.0
type AWSSSOSpentTokenStore interface {
// MarkAWSSSOTokenSpent upserts one spent-token row, idempotent: re-marking
// an already-spent fingerprint is a no-op, so row age stays "since first
// spent" for the prune below.
MarkAWSSSOTokenSpent(ctx context.Context, fingerprint, owner string, markedAt time.Time) error
// AWSSSOTokenSpent reports whether fingerprint is already known dead; its
// one caller memoizes the answer, so a miss costs at most one query per
// fingerprint per process lifetime.
AWSSSOTokenSpent(ctx context.Context, fingerprint string) (bool, error)
// PruneAWSSSOSpentTokens deletes rows marked before cutoff, reporting the
// count removed. Called from the reaper's existing per-tick advisory lock.
PruneAWSSSOSpentTokens(ctx context.Context, cutoff time.Time) (int, error)
}
AWSSSOSpentTokenStore persists the AWS SSO refresh-token "spent" mark (internal/api/awssso_refresh.go's ssoRefreshSpent map) so it survives a daemon restart, through Store/PG rather than the secret/blob store since the mark is written precisely because that blob store failed.
type ActiveRunsAtPathReader ¶ added in v0.7.0
type ActiveRunsAtPathReader interface {
ActiveRunsAtWorkspacePath(ctx context.Context, workspacePath string) ([]types.AgentRun, error)
}
ActiveRunsAtPathReader answers which OTHER non-terminal runs already operate on one host workspace path, checked on every run create. Its absence falls back to the unbounded ListRuns + an in-Go filter, SAFE (same answer, merely slower) since the warning is advisory and never blocks a launch.
type ActiveRunsByCreatorReader ¶ added in v0.7.5
type ActiveRunsByCreatorReader interface {
ActiveRunsByCreator(ctx context.Context, createdBy, task, agent string) ([]types.AgentRun, error)
}
ActiveRunsByCreatorReader answers which of a person's runs of one task+agent are still non-terminal, so a new sign-in's supersede (supersedeCallerLoginRuns) can end them. Its absence has no fallback; PG implements it in production. task and agent, not "provider": a run row carries no provider column (it lives in the harness.login.start audit datum).
type ApprovalNotifyReader ¶ added in v0.8.6
type ApprovalNotifyReader interface {
// ApprovalEscalations reads, in one query, the escalation state of every approval in ids that has
// outbox rows. Approvals with none are absent from the map.
ApprovalEscalations(ctx context.Context, ids []uuid.UUID, now time.Time) (map[uuid.UUID]types.ApprovalEscalation, error)
// ApprovalNotifyChannelStats returns one row per channel that has outbox rows.
ApprovalNotifyChannelStats(ctx context.Context, now time.Time) ([]types.ApprovalNotifyChannelStat, error)
}
ApprovalNotifyReader is the read side of the approval notification outbox that the console needs: where each pending approval sits on its escalation schedule, and each channel's delivery history. A capability interface like ApprovalsForRunsPager: an absent implementation leaves the projection and the status endpoint empty, never an error, since both only describe notifications.
type ApprovalsByRunCreatorPager ¶ added in v0.5.0
type ApprovalsByRunCreatorPager interface {
ListApprovalsPageByRunCreator(ctx context.Context, createdBy string, stateFilter types.ApprovalState, p Page) ([]types.ApprovalRequest, error)
}
ApprovalsByRunCreatorPager is the ownership-scoped analogue of Pager.ListApprovalsPage: a member's GET /approvals (no ?run_id=) is scoped to approvals on runs THEY created, via a JOIN on agent_runs (approvals carry no created_by of their own). TRUST BOUNDARY: same fail-closed contract as RunsByCreatorPager — an absent implementation must never fall back to the unscoped list.
type ApprovalsByRunPager ¶ added in v0.7.0
type ApprovalsByRunPager interface {
ListApprovalsPageByRun(ctx context.Context, runID uuid.UUID, stateFilter types.ApprovalState, p Page) ([]types.ApprovalRequest, error)
}
ApprovalsByRunPager is Pager.ListApprovalsPage narrowed to ONE run, the ?run_id= shape of GET /api/v1/approvals. Without it, a run-scoped poll falls back to fetching every approval the deployment has ever written and filtering in Go, a cost growing with deployment age since decided rows are never deleted.
Fail-safe like Pager (not fail-closed like ApprovalsByRunCreatorPager): ownership scoping happens before this is reached (getRunAuthorized), so the fallback is a performance question, not a privilege one.
type ApprovalsForRunsPager ¶ added in v0.8.0
type ApprovalsForRunsPager interface {
// ListPendingApprovalsForRuns returns every state=PENDING approval whose
// run_id is in runIDs — no other state, since only PENDING can be held or
// contribute to Pending's count.
ListPendingApprovalsForRuns(ctx context.Context, runIDs []uuid.UUID) ([]types.ApprovalRequest, error)
// CountPendingApprovals returns how many approvals in the whole deployment
// are state=PENDING — GET /me/attention's admin-view pending_approvals,
// counted in the database rather than by listing every row.
CountPendingApprovals(ctx context.Context) (int, error)
// CountPendingApprovalsByRunCreator returns how many PENDING approvals are
// raised on runs createdBy owns — GET /me/attention's user-view
// pending_approvals, counted rather than listed.
CountPendingApprovalsByRunCreator(ctx context.Context, createdBy string) (int, error)
}
ApprovalsForRunsPager is the attention projection's read surface — kept out of Store like every capability interface in this package, since widening Store would silently route a test double's unoverridden method to the unscoped behaviour. SECURITY: an absent implementation fails CLOSED at the api-layer call site (attention projection refuses rather than silently omitting `attention` from every run).
type AttachLease ¶ added in v0.8.6
type AttachLease struct {
RunID uuid.UUID
HolderID uuid.UUID
Replica string // the replica serving the holder's socket
Principal string
Source string // "web" or "ssh"
Since time.Time
Epoch int64 // moves at each takeover of the row
ExpiresAt time.Time
Live bool // read-only: ExpiresAt was ahead of the database's clock
}
AttachLease is one row of run_attach_leases. HolderID is the lease's identity: whatever writes into the terminal must still be the holder.
type AttachLeaseStore ¶ added in v0.8.6
type AttachLeaseStore interface {
// AcquireAttachLease takes runID's lease for l.HolderID when it is free, has lapsed, or is
// held by from (uuid.Nil: nobody in particular), for ttl. It reports whether it did.
AcquireAttachLease(ctx context.Context, l AttachLease, from uuid.UUID, ttl time.Duration) (bool, error)
// RenewAttachLease extends holderID's lease by ttl, reporting whether holderID still held it.
RenewAttachLease(ctx context.Context, runID, holderID uuid.UUID, ttl time.Duration) (bool, error)
// HoldsAttachLease reports whether holderID holds runID's lease right now, unlapsed.
HoldsAttachLease(ctx context.Context, runID, holderID uuid.UUID) (bool, error)
// ReleaseAttachLease deletes the lease if holderID holds it, reporting whether it did.
ReleaseAttachLease(ctx context.Context, runID, holderID uuid.UUID) (bool, error)
// ReserveAttachLease is a take-over: it replaces the live lease held by from (uuid.Nil:
// whoever holds it) with a reservation for taker, which only taker's own client may take, for
// ttl, so no queued client of someone else gets the slot the take-over freed. It returns the
// lease it replaced and the reservation's holder id; found is false when no live lease was
// held by from.
ReserveAttachLease(ctx context.Context, runID, from uuid.UUID, taker, replica string, ttl time.Duration) (prev AttachLease, reservation uuid.UUID, found bool, err error)
// GetAttachLease returns runID's lease, lapsed or not (Live says which).
GetAttachLease(ctx context.Context, runID uuid.UUID) (AttachLease, bool, error)
}
AttachLeaseStore is the attach lease record. Optional like RunOutputStore: the api layer type-asserts, and a store without it keeps the writer slot in the process.
type AttachTicket ¶ added in v0.5.0
type AttachTicket struct {
RunID uuid.UUID
ActorType types.ActorType
Principal string
Role string
// Via is the delegated lane the ticket was minted on (#1142), nil
// otherwise; the ticket lane replays it onto the rows it writes.
Via *types.DelegationVia
// AuthorizedAt is when the minting request was admitted, and Email the
// verified email a session revoke may name ("" on the admin-token and local
// lanes). Redemption checks both against the revoke cutoff (#1474). A zero
// AuthorizedAt is a row written before the column existed: never exempt.
AuthorizedAt time.Time
Email string
}
AttachTicket is what one redeemed single-use WS attach ticket carries: the run it's bound to, the minting principal (audit attribution), and that principal's role at mint time. The ?ticket= WS lane bypasses humanOrAdminAuth entirely, so this stamped role is the only signal available to re-check owner-or-admin at consume time.
type AuditChainStatus ¶ added in v0.6.0
type AuditChainStatus struct {
// OK is true when every chained row re-hashed to its stored row_hash and
// linked to its predecessor.
OK bool `json:"ok"`
// Checked is how many chained rows the sweep walked.
Checked int64 `json:"checked"`
// Legacy is how many rows carry NO hash and sit BELOW the first chained
// row (pre-migration-0047) — expected, not a failure. A hashless row
// ABOVE that prefix is a break instead (auditChainWalk.step).
Legacy int64 `json:"legacy"`
// FirstSeq/HeadSeq bound the chained range (both 0 when Checked is 0).
FirstSeq int64 `json:"first_seq"`
HeadSeq int64 `json:"head_seq"`
// HeadHash is the row_hash of the newest chained row: the value to compare
// against what a SIEM recorded off the sink stream.
HeadHash string `json:"head_hash,omitempty"`
// AnchorSeq is the last seq of the newest attested retention drop the sweep started from: the first
// retained row must chain to that drop's recorded tail. 0 when no partition was ever dropped.
AnchorSeq int64 `json:"anchor_seq,omitempty"`
// BrokenSeq/Reason are set only when OK is false.
BrokenSeq int64 `json:"broken_seq,omitempty"`
Reason string `json:"reason,omitempty"`
}
AuditChainStatus is one verification sweep's verdict (migration 0047). OK is the only field an alert should key on; BrokenSeq/Reason name the FIRST row that failed, not every row after it, since one edited row makes every later link mismatch too and listing them all buries the edit.
type AuditChainVerifier ¶ added in v0.6.0
type AuditChainVerifier interface {
VerifyAuditChain(ctx context.Context) (AuditChainStatus, error)
}
AuditChainVerifier is the OPTIONAL store capability behind GET /api/v1/audit/chain/verify: a test fake or non-Postgres store has no chain, and the handler answers 501 rather than reporting a chain it never wrote as clean.
Operator-invoked, never run at boot (O(whole audit log)). Not a substitute for comparing HeadHash against an off-box copy: an actor who can rewrite one row can usually rewrite and re-chain the tail, which then verifies clean. See docs/OPERATIONS.md.
type AuditFilter ¶ added in v0.4.4
type AuditFilter struct {
Since time.Time // events at or after this instant
Until time.Time // events strictly before this instant
Action string // exact action, e.g. "run.kill"
ActionPrefix string // action family, e.g. "credential." or "egress."
Actor string // exact principal, e.g. "alice@corp.example" (human evidence)
ActorType types.ActorType // human / agent / system
Outcome string // success / failure / warn
Origin string // AuditOriginDevice or AuditOriginOrganisation
// ActorAlt is a second stored actor that also matches Actor: the "subject:<id>"
// a row holds for the person Actor names under WARDYN_AUDIT_SEAL=full. Rows
// written before it was turned on keep the name, so both must match.
ActorAlt string
// DataContains is a JSON object the row's data must contain (Postgres
// `data @> $n::jsonb`): every key present with an equal value, objects
// recursively. A string, not a map, so the filter stays comparable (IsZero).
DataContains string
}
AuditFilter narrows the audit feed to answer the questions a bigger window never can — "what happened between 14:00 and 16:00", "every secret.write this quarter", "every failure" — where the answer is 40 events inside 200k. The zero value matches everything, so an unfiltered read keeps taking the plain QueryRecentAuditEventsPage / QueryAuditEventsPage path unchanged.
It renders TWO ways from one declaration — SQL (where) for the Pager path and Go (Matches) for the fetch-all fallback — because a filter applied on only one of them returns silently UNFILTERED events on the other, which in a governance product is a quiet wrong answer. Keep the two in step; they are deliberately adjacent.
Actor IS filterable: for a HUMAN event it is the operator/member principal (e.g. "alice@corp.example"), so ?actor= answers "everything developer X did" — the per-principal evidence a vendor/compliance question needs and that no wider window yields. (An earlier note dismissed actor as filterable because for an AGENT event it is the per-run SPIFFE ID and would merely restate ?run_id= — but that reasoning only ever considered agent events; a human's approvals, kills, and policy writes all carry their principal here, and that is exactly what the finding asks for.) The agent-side "everything under X's runs" view still needs the agent_runs.created_by join, which does not fit this table-local filter.
func (AuditFilter) IsZero ¶ added in v0.4.4
func (f AuditFilter) IsZero() bool
IsZero reports whether the filter narrows nothing.
func (AuditFilter) Keep ¶ added in v0.4.4
func (f AuditFilter) Keep(events []types.AuditEvent) []types.AuditEvent
Keep returns the events matching f, in order. A zero filter returns events unchanged (no copy).
func (AuditFilter) Matches ¶ added in v0.4.4
func (f AuditFilter) Matches(ev types.AuditEvent) bool
Matches reports whether ev satisfies every set predicate.
type AuditPartitionExporter ¶ added in v0.8.6
type AuditPartitionExporter interface {
// ExportAuditPartition reads one closed partition in seq order from ONE snapshot. header is called
// once, before any row, with the manifest of that snapshot; row once per row. ErrNotFound when name
// is not a partition of the audit log, ErrAuditPartitionOpen when it can still receive rows; in
// both cases neither callback ran. An error from either callback stops the read and is returned.
ExportAuditPartition(ctx context.Context, name string, header func(PartitionManifest) error, row func(AuditPartitionRow) error) error
}
AuditPartitionExporter is the OPTIONAL store capability behind GET /audit/export?partition=. A test fake or non-Postgres store has no partitions.
type AuditPartitionRow ¶ added in v0.8.6
type AuditPartitionRow struct {
Seq int64
RecordedUS int64
TimeUS int64
ID uuid.UUID
RunID *uuid.UUID
ActorType string
Actor string
Action string
Target string
Outcome string
SourceIP string
// Data is the jsonb's own text form, the exact bytes audit_row_hash embeds; nil for SQL NULL.
Data *string
// PrevHash and RowHash are nil for a row from before the chain began.
PrevHash *string
RowHash *string
// FoldHash is what the digest folds: RowHash, or for a hashless row the hash it would have had.
FoldHash string
}
AuditPartitionRow is one stored row of a partition, exactly as the table holds it: the columns audit_row_hash covers, the hashes, and the position.
type AuditRetention ¶ added in v0.8.6
type AuditRetention interface {
AuditRetentionStatus(ctx context.Context) (AuditRetentionStatus, error)
// DropAuditPartition calls audit_retention_drop. A refusal is *AuditRetentionRefused; a name that is
// not a partition of the audit log is ErrNotFound.
DropAuditPartition(ctx context.Context, partition, digest, actor string) (AuditRetentionDrop, error)
// AutodropAuditPartition drops the oldest partition if it is eligible, computing its digest in the
// database, as the system actor. ok is false (and nothing was dropped) when it is not.
AutodropAuditPartition(ctx context.Context) (drop AuditRetentionDrop, ok bool, err error)
// SetAuditRetentionPolicy calls audit_retention_set_policy.
SetAuditRetentionPolicy(ctx context.Context, days int) (AuditRetentionPolicyChange, error)
// EnsureAuditPartitions calls audit_ensure_partitions and returns how many months it created.
EnsureAuditPartitions(ctx context.Context, months int) (int, error)
// AuditPartitionsAhead is how many months past the current one already have a partition.
AuditPartitionsAhead(ctx context.Context) (int, error)
}
AuditRetention is the OPTIONAL store capability behind the retention endpoints, the daily partition ensure and the leader sweeper's autodrop: a test fake or non-Postgres store has no partitions.
type AuditRetentionDrop ¶ added in v0.8.6
type AuditRetentionDrop = types.AuditRetentionDrop
The retention wire types live in internal/types, shared with pkg/client; these are their store-side names.
type AuditRetentionPartition ¶ added in v0.8.6
type AuditRetentionPartition = types.AuditRetentionPartition
The retention wire types live in internal/types, shared with pkg/client; these are their store-side names.
type AuditRetentionPolicy ¶ added in v0.8.6
type AuditRetentionPolicy = types.AuditRetentionPolicy
The retention wire types live in internal/types, shared with pkg/client; these are their store-side names.
type AuditRetentionPolicyChange ¶ added in v0.8.6
type AuditRetentionPolicyChange = types.AuditRetentionPolicyChange
The retention wire types live in internal/types, shared with pkg/client; these are their store-side names.
type AuditRetentionRefused ¶ added in v0.8.6
AuditRetentionRefused is a drop the database refused. Reason is one of the Retention* constants.
func (*AuditRetentionRefused) Error ¶ added in v0.8.6
func (e *AuditRetentionRefused) Error() string
type AuditRetentionStatus ¶ added in v0.8.6
type AuditRetentionStatus = types.AuditRetentionStatus
The retention wire types live in internal/types, shared with pkg/client; these are their store-side names.
type AuditSplitRange ¶ added in v0.8.6
type AuditSplitRange struct {
Name string
Rows int64
SeqLo int64
SeqHi int64
// RecordedLo and RecordedHi are the smallest and largest recorded_at the range's rows now carry.
RecordedLo time.Time
RecordedHi time.Time
// Digest is the range's partition digest (audit_partition_digest), equal to the fold over its source rows.
Digest string
}
AuditSplitRange is one seq-contiguous range the legacy partition was split into.
type AuditSplitRefused ¶ added in v0.8.6
AuditSplitRefused is a legacy split that was not attempted, or was undone, for a named reason.
func (*AuditSplitRefused) Error ¶ added in v0.8.6
func (e *AuditSplitRefused) Error() string
type AuditSplitResult ¶ added in v0.8.6
type AuditSplitResult struct {
Rows int64
Checked int64
Legacy int64
Ranges []AuditSplitRange
}
AuditSplitResult is what one split did. Checked and Legacy are the chain verifier's counts, which were the same before the split and after it: the split removed no row from the chain.
func SplitLegacyAudit ¶ added in v0.8.6
SplitLegacyAudit splits the legacy partition, which holds all of the audit history from before 0.8.6 under one recorded_at, into seq-contiguous ranges that ordinary retention can drop one at a time. It is the one-shot offline tool behind `wardynd -audit-split-legacy`.
It runs on tx, a read-write transaction on the migrator's connection that the caller commits only when this returns nil. The caller has already made sure no writer is running; this takes db.AuditPartitionLockKey and then db.AuditChainLockKey for the transaction (the order the retention drop takes them), so a writer that slipped in is held out, not interleaved.
A range is not a month of the rows' own time. The boundaries are where the running maximum of "time" first crosses a month, walking the rows in seq order, and each row's new recorded_at is that running maximum (never past the cutover). A spool replay writes an old "time" late, so splitting by "time" would scatter a month through the chain and leave an interior link behind when its range was dropped; the running maximum cannot go backwards, so every range is a contiguous prefix of chain order, and its largest recorded_at is the largest "time" it holds. row_hash does not cover recorded_at, so no hash changes.
Every range is copied to a new table, attached, and proved against its source (the same fold audit_partition_digest computes, and a row-for-row comparison), the legacy table is dropped, the ranges are written to the expected manifest and a 'split' anchor each, and the chain is verified again. The verification must see exactly the rows it saw before.
type BrandingStore ¶ added in v0.8.0
type BrandingStore interface {
// GetBranding returns the record, or ErrNotFound for an unbranded console.
GetBranding(ctx context.Context) (types.Branding, error)
// PutBranding replaces the record. keepLogo leaves the stored logo as it
// is and ignores b.Logo/b.LogoType.
PutBranding(ctx context.Context, b types.Branding, keepLogo bool) (types.Branding, error)
// DeleteBranding removes the record; false when there was none.
DeleteBranding(ctx context.Context) (bool, error)
// SetBrandingLogo replaces only the logo and its file-delivered mark; an
// empty logo removes it. false when there is no record to attach it to.
SetBrandingLogo(ctx context.Context, logo []byte, logoType string, fromFile bool, updatedBy string) (bool, error)
}
BrandingStore is the OPTIONAL store capability behind console branding, optional for DeviceStore's reason: a fake without it answers the public read as unbranded and refuses a write, never a silent no-op.
type CapabilityGrantsForPager ¶ added in v0.8.0
type CapabilityGrantsForPager interface {
ListCapabilityGrantsForPage(ctx context.Context, users, groups []string, userType string, p Page) ([]types.CapabilityGrant, error)
}
CapabilityGrantsForPager is the scoped analogue of Pager for GET /me/capabilities, same safe-fallback posture as GrantsByRunPager; exists for the uniform list-route contract (?limit=&offset=+X-Wardyn-Truncated), not because grant lists routinely truncate.
type DelegateStore ¶ added in v0.8.0
type DelegateStore interface {
CreateDelegate(ctx context.Context, d types.Delegate, raw string) (types.Delegate, error)
GetDelegateByRaw(ctx context.Context, raw string) (types.Delegate, error)
ListDelegates(ctx context.Context) ([]types.Delegate, error)
RevokeDelegate(ctx context.Context, id uuid.UUID, now time.Time) (types.Delegate, error)
MintDelegatedToken(ctx context.Context, t types.DelegatedToken, raw string, now time.Time) (types.DelegatedToken, error)
GetDelegatedTokenByRaw(ctx context.Context, raw string, now time.Time) (types.DelegatedToken, error)
GetDelegatedTokenByID(ctx context.Context, id uuid.UUID, now time.Time) (types.DelegatedToken, error)
}
DelegateStore is optional, type-asserted like DeviceStore: without it the exchange and delegated lane fail closed instead of silently no-op.
Authenticating reads filter revoked/expired rows in their WHERE, so revoked, expired, unknown, and mismatched credentials all answer ErrNotFound — the boundary gives no oracle signal.
type DeprovisionFailure ¶ added in v0.8.6
DeprovisionFailure is a ledger row of a suspension or purge that is still pending and has failed at least once: the step, and the error its last attempt ended on. The console's SCIM card lists them.
type DeprovisionJob ¶ added in v0.8.6
type DeprovisionJob struct {
IdentityID uuid.UUID
Kind string
Step string
Target string
Done bool
Attempts int
LastError string
Detail map[string]int
}
DeprovisionJob is one row of the step ledger.
type DeviceIngestResult ¶ added in v0.8.0
DeviceIngestResult reports what one IngestDeviceAudit call did. Accepted is how many rows were newly appended: 0 on any refusal (whole batch is one transaction) and also on an idempotent retry. Reset is true when accepted rows began with a genesis (empty-PrevHash) row while the device already had a recorded chain — a "device chain reset", accepted rather than refused.
type DeviceStore ¶ added in v0.8.0
type DeviceStore interface {
MintEnrolmentToken(ctx context.Context, token string, t types.DeviceEnrolmentToken) (types.DeviceEnrolmentToken, error)
ConsumeEnrolmentToken(ctx context.Context, token string, now time.Time) (types.DeviceEnrolmentToken, bool, error)
ListEnrolmentTokens(ctx context.Context, now time.Time) ([]types.DeviceEnrolmentToken, error)
RevokeEnrolmentToken(ctx context.Context, id uuid.UUID, now time.Time) (types.DeviceEnrolmentToken, error)
CreateDevice(ctx context.Context, d types.Device, raw string) (types.Device, error)
GetDeviceByRaw(ctx context.Context, raw string) (types.Device, error)
TouchDevice(ctx context.Context, id uuid.UUID, now time.Time) error
ListDevices(ctx context.Context) ([]types.Device, error)
RevokeDevice(ctx context.Context, id uuid.UUID, now time.Time) (types.Device, error)
IngestDeviceAudit(ctx context.Context, deviceID uuid.UUID, peer string, rows []types.FederatedAuditEvent) (DeviceIngestResult, error)
ListAuditEventsAfterSeq(ctx context.Context, seq int64, limit int) ([]types.FederatedAuditEvent, error)
GetFederationCursor(ctx context.Context) (seq int64, rowHash string, err error)
SetFederationCursor(ctx context.Context, seq int64, rowHash string) error
}
DeviceStore is the optional store capability behind hybrid enrolment and audit federation (docs/design/0.8/PLAN.md, epic #78). Optional like Pager and AuditChainVerifier: a test fake or future non-Postgres store implements neither, so mounting routes must type-assert and answer 501/401 rather than silently no-op. SECURITY (fail-closed): nothing here has a default no-op on Store, so a skipped assertion is a compile error and a failed one has an explicit absent branch.
GetDeviceByRaw's WHERE carries `revoked_at IS NULL` so a revoked credential is not an oracle.
type EndedKept ¶ added in v0.8.0
EndedKept is the condition a write on a run kept by its OWN end (LostEnded) lands under during its files grace: the row must still carry the exact ended mark decided on (LostAt), after KeptAfter (Now less the ended-run grace). A grace that runs out between check and write refuses the write; nothing here moves the mark, so no write renews the grace. A revive also needs the run's end to be after Now.
type ErrGovernanceChangeNotPending ¶ added in v0.8.6
ErrGovernanceChangeNotPending is a decision's refusal when the change is no longer pending. State is what it is now; Lapsed is true when this very decision found it past expires_at and moved it to expired.
func (*ErrGovernanceChangeNotPending) Error ¶ added in v0.8.6
func (e *ErrGovernanceChangeNotPending) Error() string
type ErrGovernanceChangePending ¶ added in v0.8.6
ErrGovernanceChangePending is a proposal's refusal when a live change already holds the target: ID is that change.
func (*ErrGovernanceChangePending) Error ¶ added in v0.8.6
func (e *ErrGovernanceChangePending) Error() string
type ErrProfileHasChildren ¶ added in v0.8.6
type ErrProfileHasChildren struct{ Names []string }
ErrProfileHasChildren is DeleteGovernanceProfile's refusal when other profiles still compose on the row: Names are those children, sorted.
func (*ErrProfileHasChildren) Error ¶ added in v0.8.6
func (e *ErrProfileHasChildren) Error() string
type ExpiredGovernanceChange ¶ added in v0.8.6
ExpiredGovernanceChange is a lapsed change a proposal moved to expired: its id and its own target key, which differs from the proposal's when it was a create of the same name.
type GovernanceDecideFunc ¶ added in v0.8.6
type GovernanceDecideFunc func(q Querier, ch types.GovernanceChange) error
GovernanceDecideFunc runs inside the decision transaction with the change as it was locked. A nil error commits the decision; ErrGovernanceChangeStale commits the change as stale; any other error rolls everything back, the change still pending.
type GovernanceDecision ¶ added in v0.8.6
type GovernanceDecision struct {
// To is types.GovernanceChangeApplied or types.GovernanceChangeRejected.
To string
By string
ByEmail string
Reason string
}
GovernanceDecision is what a decision records on the change row.
type GovernanceProfileBuild ¶ added in v0.8.6
type GovernanceProfileBuild func(all []types.GovernanceProfile) (types.GovernanceProfile, error)
GovernanceProfileBuild produces the row a graph write stores, given every profile as the write transaction sees it under the graph lock. A refusal it returns aborts the write unchanged.
type GrantsByRunPager ¶ added in v0.8.0
type GrantsByRunPager interface {
ListGrantsByRunPage(ctx context.Context, runID uuid.UUID, p Page) ([]types.CredentialGrant, error)
}
GrantsByRunPager is the scoped analogue of Pager for GET /runs/{id}/grants: ListGrantsByRun is already WHERE run_id=$1, so an absent implementation is safe (not fail-closed) — the fallback windows the same scoped rows in Go.
type IdentityGuard ¶ added in v0.8.6
IdentityGuard names the owner a write acts for and the authority epoch its caller was admitted under. Epoch < 0 means the caller carries no epoch (an API token, a request-free caller): only a deactivation refuses.
type IdentityUpdate ¶ added in v0.8.6
type IdentityUpdate struct {
ExternalID string
UserName string
Emails []string
// Reactivate clears the deactivation and the purge schedule on the identity and on every row
// bound to the same principal. A purged identity is ErrIdentityPurged.
Reactivate bool
// PeoplePrincipals are the people rows whose deactivation a reactivation clears.
PeoplePrincipals []string
}
IdentityUpdate is one SCIM write to an identity row. A projection update never touches a binding column; ExternalID is set only when the caller has already checked it against the binding.
type JobKey ¶ added in v0.8.6
type JobKey struct{ Step, Target string }
JobKey names a ledger row within one identity and kind.
type LeaverStore ¶ added in v0.8.6
type LeaverStore interface {
GetIdentity(ctx context.Context, id uuid.UUID) (PrincipalIdentity, error)
SearchIdentities(ctx context.Context, issuer, attr, value string, limit int) ([]PrincipalIdentity, error)
IdentitiesByAlias(ctx context.Context, issuer, valueLower string) ([]PrincipalIdentity, error)
IdentityAliasValues(ctx context.Context, id uuid.UUID) ([]string, error)
CreateScimIdentity(ctx context.Context, issuer, tenantID, objectID string, u IdentityUpdate, now time.Time) (PrincipalIdentity, bool, error)
ApplyIdentityUpdate(ctx context.Context, id uuid.UUID, u IdentityUpdate, now time.Time) (PrincipalIdentity, error)
SuspendIdentity(ctx context.Context, p SuspendPlan) (SuspendResult, error)
PrincipalsByEmail(ctx context.Context, emails []string) ([]string, error)
ListNonTerminalRunsBy(ctx context.Context, createdBy string) ([]types.AgentRun, error)
EnsureDeprovisionJobs(ctx context.Context, identityID uuid.UUID, kind string, keys []JobKey) error
ListDeprovisionJobs(ctx context.Context, identityID uuid.UUID, kind string) ([]DeprovisionJob, error)
FinishDeprovisionJob(ctx context.Context, identityID uuid.UUID, kind string, k JobKey, detail map[string]int) error
FailDeprovisionJob(ctx context.Context, identityID uuid.UUID, kind string, k JobKey, cause error) error
ReopenDeprovisionJob(ctx context.Context, identityID uuid.UUID, kind string, k JobKey) error
MarkIdentityPurged(ctx context.Context, id uuid.UUID, requireDue bool) (bool, error)
PurgeDueIdentities(ctx context.Context, limit int) ([]uuid.UUID, error)
PendingLeavers(ctx context.Context, idleFor time.Duration, limit int) ([]PendingLeaver, error)
DeleteUserSubjectRows(ctx context.Context, id uuid.UUID, principals, emails []string) (grants, assignments, kept int64, err error)
HeldEmails(ctx context.Context, id uuid.UUID, principals, emails []string) ([]string, error)
ListDeactivatedIdentities(ctx context.Context, limit int) ([]PrincipalIdentity, error)
ListDeprovisionFailures(ctx context.Context, limit int) ([]DeprovisionFailure, error)
}
LeaverStore is optional, like PrincipalIdentityStore: callers type-assert it.
type LoginIdentity ¶ added in v0.8.6
type LoginIdentity struct {
Principal string
Issuer string
TenantID string
ObjectID string
Email string
}
LoginIdentity is what an approved sign-in tells the store.
type LoginLocker ¶ added in v0.8.0
type LoginLocker interface {
LockLoginSupersede(ctx context.Context, actor string) (release func(), err error)
}
LoginLocker serializes one person's sign-in launches, and the credential capture that follows one, against every other replica — the piece the deterministic tie-break in api.supersedeOlderLoginRuns couldn't supply. Its absence falls back UNLOCKED (as serialized as 0.7.8 was); PG implements it in production.
Keyed by ACTOR, not credential scope: under the `shared` roster every sign-in resolves to the same empty scope owner, so a scope-keyed lock would serialize the whole deployment without serializing what it needs to.
type MemRunPATs ¶ added in v0.8.2
type MemRunPATs struct {
// contains filtered or unexported fields
}
MemRunPATs is RunPATStore in memory, for the tests of every lane that creates or revokes a token and has no database.
func NewMemRunPATs ¶ added in v0.8.2
func NewMemRunPATs() *MemRunPATs
NewMemRunPATs returns an empty MemRunPATs.
func (*MemRunPATs) InsertRunPAT ¶ added in v0.8.2
func (m *MemRunPATs) InsertRunPAT(_ context.Context, p RunPAT) error
func (*MemRunPATs) LastRunPAT ¶ added in v0.8.2
func (*MemRunPATs) ListRunPATs ¶ added in v0.8.2
func (*MemRunPATs) ListUnrevokedRunPATs ¶ added in v0.8.2
func (m *MemRunPATs) ListUnrevokedRunPATs(_ context.Context, f RunPATFilter) ([]RunPAT, error)
func (*MemRunPATs) MarkRunPATRevoked ¶ added in v0.8.2
func (*MemRunPATs) NoteRunPATRevokeFailed ¶ added in v0.8.2
type PG ¶
type PG struct {
Pool *pgxpool.Pool
// Now is THE APP CLOCK, letting a test run one that disagrees with the
// database's. Nil means time.Now. Every stamp this store writes belongs on
// the DATABASE's clock; the app clock only measures an ELAPSED TIME (a
// difference of two readings, carrying no skew) that a statement then
// subtracts from the database's own now(). See db.AppClockAgeSQL.
Now func() time.Time
}
PG is the Postgres-backed Store: its methods (defined in store.go) hold the query bodies directly, so there is exactly one implementation of each query.
func (PG) ADOSignInEnds ¶ added in v0.8.6
ADOSignInEnds — see ADOSignInEndStore.
func (PG) AWSSSOTokenSpent ¶ added in v0.8.0
AWSSSOTokenSpent reports whether fingerprint has a persisted spent-token row.
func (PG) AcquireAttachLease ¶ added in v0.8.6
func (s PG) AcquireAttachLease(ctx context.Context, l AttachLease, from uuid.UUID, ttl time.Duration) (bool, error)
AcquireAttachLease — see AttachLeaseStore.
func (PG) ActiveRunsAtWorkspacePath ¶ added in v0.7.0
func (s PG) ActiveRunsAtWorkspacePath(ctx context.Context, workspacePath string) ([]types.AgentRun, error)
ActiveRunsAtWorkspacePath returns the non-terminal runs bound to one host workspace path. Uses the POSITIVE state list, same reasoning as ActiveRunsByCreator: a forgotten new state merely under-warns rather than mis-treating it as active.
ponytail: no new index. workspace_path is selective and the state filter is a cheap check over matching rows; a composite (workspace_path, state) index is the upgrade if a deployment ever has enough runs on ONE path.
func (PG) ActiveRunsByCreator ¶ added in v0.7.5
func (s PG) ActiveRunsByCreator(ctx context.Context, createdBy, task, agent string) ([]types.AgentRun, error)
ActiveRunsByCreator returns createdBy's non-terminal runs of one task+agent. Uses the POSITIVE state list (types.NonTerminalRunStates): a state added to the enum and forgotten here merely misses a supersede, whereas `NOT IN (terminal)` would hand a new terminal state to the kill cascade.
ponytail: no new index. agent_runs_created_by_idx already indexes the selective column and one person owns few runs; upgrade to a composite if a deployment ever has enough history to notice.
func (PG) AddSSHKey ¶ added in v0.5.0
func (s PG) AddSSHKey(ctx context.Context, k types.SSHPublicKey) (types.SSHPublicKey, error)
AddSSHKey inserts a new registered key. Returns ErrConflict when the fingerprint (PK) already exists — a 23505 here means that exact key material is already registered.
func (PG) AddScimGroupMembers ¶ added in v0.8.6
func (s PG) AddScimGroupMembers(ctx context.Context, id uuid.UUID, identities []uuid.UUID, now time.Time) error
AddScimGroupMembers records each identity as a member, leaving one already recorded as it is and skipping an id that names no identity row.
func (PG) AddWorkspaceEgressDecision ¶ added in v0.5.0
func (s PG) AddWorkspaceEgressDecision(ctx context.Context, id uuid.UUID, host string, allow bool, maxApprovedEgress int) (types.Workspace, error)
AddWorkspaceEgressDecision records one `always`-scoped egress decision for host: on allow it is added to approved_egress (capped, deduped) and removed from denied_egress; on deny the mirror. Returns ErrConflict, not a bare "not found", when id exists but the cap guard refused the write.
func (PG) AppendRunOutputChunk ¶ added in v0.8.6
func (s PG) AppendRunOutputChunk(ctx context.Context, runID uuid.UUID, replica string, b []byte, keep int) (bool, error)
AppendRunOutputChunk — see RunOutputChunkStore.
func (PG) ApplyIdentityUpdate ¶ added in v0.8.6
func (s PG) ApplyIdentityUpdate(ctx context.Context, id uuid.UUID, u IdentityUpdate, now time.Time) (PrincipalIdentity, error)
ApplyIdentityUpdate applies u to the identity in one transaction: the projection, then the reactivation when asked. A purged identity refuses a reactivation and nothing else changes.
func (PG) ApprovalEscalations ¶ added in v0.8.6
func (s PG) ApprovalEscalations(ctx context.Context, ids []uuid.UUID, now time.Time) (map[uuid.UUID]types.ApprovalEscalation, error)
ApprovalEscalations — see ApprovalNotifyReader.
func (PG) ApprovalNotifyChannelStats ¶ added in v0.8.6
func (s PG) ApprovalNotifyChannelStats(ctx context.Context, now time.Time) ([]types.ApprovalNotifyChannelStat, error)
ApprovalNotifyChannelStats — see ApprovalNotifyReader.
func (PG) AuditHeadSeq ¶ added in v0.8.0
AuditHeadSeq is this deployment's newest audit_events seq, 0 on an empty table: the head the forwarder measures lag against, read every tick whether or not a push succeeds.
func (PG) AuditKeyDestroyedAt ¶ added in v0.8.6
AuditKeyDestroyedAt is when the latest generation of owner's audit-seal key was destroyed. ok is false while none has been.
func (PG) AuditPartitionsAhead ¶ added in v0.8.6
func (PG) AuditPrincipalOf ¶ added in v0.8.6
AuditPrincipalOf is the principal a subject id names. ok is false for an id that is not a uuid or that no bound identity row carries.
func (PG) AuditRetentionStatus ¶ added in v0.8.6
func (s PG) AuditRetentionStatus(ctx context.Context) (AuditRetentionStatus, error)
func (PG) AuditSubjectFor ¶ added in v0.8.6
AuditSubjectFor is principal's subject id. ok is false when the person has no identity row.
func (PG) AutodropAuditPartition ¶ added in v0.8.6
func (PG) BeginADOSignInEnd ¶ added in v0.8.6
BeginADOSignInEnd — see ADOSignInEndStore.
func (PG) BlankRunTasks ¶ added in v0.8.6
func (PG) ClaimSourceActiveRun ¶ added in v0.5.0
ClaimSourceActiveRun fences a source's in-flight scan run, mirroring ClaimWorkspaceActiveRun. Returns ErrConflict when another run holds the slot.
func (PG) ClaimStaleRunWatchers ¶ added in v0.5.0
func (s PG) ClaimStaleRunWatchers(ctx context.Context, owner string, staleAfter time.Duration) ([]types.AgentRun, error)
ClaimStaleRunWatchers atomically takes the watcher lease, for owner, on every non-terminal run with a sandbox whose lease has been silent longer than staleAfter, returning the runs claimed for re-adoption.
The conditional UPDATE ... RETURNING is the mutual exclusion: replicas sweeping at once re-evaluate WHERE against the row version they blocked on, so the loser sees the winner's fresh heartbeat and gets no row — no advisory lock needed (one per in-flight run via db.TryAdvisoryLock would exhaust the pool, which holds a connection for the whole lock).
Two predicates carry the sweep's safety: nonTerminalRunStates matches agent_runs_watcher_sweep_idx's predicate verbatim (complement of types.RunState.IsTerminal, so a finished run is never re-adopted); and a non-empty sandbox_ref limits it to runs with something to watch — a row exists through the whole pre-dispatch window (grant writes, then a multi-minute build) and would otherwise look abandoned, so cleanup there stays boot-only.
A KEPT run (lost_at set, migration 0073) is also never claimed: its agent is stopped on purpose, and a watcher would read that as exit and finalize the run, tearing down files it's kept for. updated_at is deliberately not touched: it's the idle reaper's activity signal, and a lease write isn't activity.
func (PG) ClaimWorkspaceActiveRun ¶
func (s PG) ClaimWorkspaceActiveRun(ctx context.Context, id, runID uuid.UUID, expected *uuid.UUID) (types.Workspace, bool, error)
ClaimWorkspaceActiveRun compare-and-sets active_run_id from expected (possibly nil) to runID, the serial-import-step gate: of two concurrent launches racing the same slot, the loser gets applied=false and must NOT launch.
func (PG) ClearPauseSettle ¶ added in v0.8.6
ClearPauseSettle — see PauseSettler.
func (PG) ClearRunContainmentError ¶ added in v0.8.0
ClearRunContainmentError — see RunLeaser.
func (PG) ClearRunPaused ¶ added in v0.8.0
ClearRunPaused — see RunPauser.
func (PG) ClearSourceActiveRun ¶ added in v0.5.0
ClearSourceActiveRun releases the fence (idempotent; only the named run's claim is cleared, so a stale clear can't stomp a newer claim).
func (PG) ClearWorkspaceActiveRun ¶
ClearWorkspaceActiveRun clears active_run_id ONLY while it still points at runID, so a terminal run's cleanup can never clobber a step that was concurrently launched and now owns the pointer.
func (PG) ConsumeAttachTicket ¶ added in v0.5.0
func (s PG) ConsumeAttachTicket(ctx context.Context, token string, now time.Time) (AttachTicket, bool, error)
ConsumeAttachTicket redeems token exactly once, returning the ticket it stood for. The DELETE ... RETURNING is the single-use guarantee: two racing redemptions can only have one return a row.
The run-id binding is checked by the CALLER, not here, so a redemption against the wrong run still BURNS the ticket (a leaked ticket probed against a guessed run must not survive the probe). A miss and an expired row are both (ok=false), indistinguishable to the caller.
func (PG) ConsumeEnrolmentToken ¶ added in v0.8.0
func (s PG) ConsumeEnrolmentToken(ctx context.Context, token string, now time.Time) (types.DeviceEnrolmentToken, bool, error)
ConsumeEnrolmentToken redeems token exactly once: a single-row conditional UPDATE...RETURNING, the same atomic consume-once shape as ConsumeAttachTicket, adapted to an UPDATE since the row is worth keeping after redemption for CreateDevice. TRUST BOUNDARY: an unknown, already-consumed, and expired token all answer (zero, false, nil) alike — no oracle, matching ConsumeAttachTicket.
func (PG) CountActiveRunsBy ¶ added in v0.7.0
CountActiveRunsBy counts createdBy's runs that have not ended yet — the governance quota's one read (GovernanceLimits.MaxConcurrentRuns).
The state predicate is a POSITIVE list (types.NonTerminalRunStates), not `NOT IN (terminal)`: a state added to the enum and forgotten here merely undercounts, whereas the negated form would treat a new terminal state as active and wedge a capped member with nothing to stop it. Pinned against RunState.IsTerminal by a test in internal/types.
ponytail: no new index — agent_runs_created_by_idx already covers the selective column and the state filter is cheap over one member's rows.
func (PG) CountApprovalsForRun ¶ added in v0.7.2
CountApprovalsForRun returns how many approvals a run has raised, in ANY state — the per-run DoS bound behind handleInternalRequestApproval (maxApprovalsPerRun), since a sandbox picks the hosts it asks about and could otherwise raise rows without limit. Counted in the database rather than List + filter in Go, which would read every approval row in the deployment.
func (PG) CountHiddenRuns ¶ added in v0.8.0
func (s PG) CountHiddenRuns(ctx context.Context, f RunFilter) (olderHidden, killedHidden int, err error)
CountHiddenRuns — see RunsFilteredPager.
func (PG) CountNonTerminalRuns ¶ added in v0.8.6
CountNonTerminalRuns is the number of non-terminal run rows that hold a sandbox (HoldsSandboxSQL), the quantity CreateRunUnderCap holds under the cap. It takes no lock: a pre-flight read for a refusal that must come before an identity is minted, never the authority.
func (PG) CountPendingApprovals ¶ added in v0.8.0
CountPendingApprovals — see ApprovalsForRunsPager. Backed by the partial approvals_state_idx: an index-only count, not a table scan.
func (PG) CountPendingApprovalsByRunCreator ¶ added in v0.8.0
CountPendingApprovalsByRunCreator — see ApprovalsForRunsPager. Same semi-join ListApprovalsPageByRunCreator's own query uses (approvals has no created_by column of its own), counted instead of listed.
func (PG) CountPushPathLists ¶ added in v0.8.0
func (PG) CreateAPIToken ¶ added in v0.6.0
func (s PG) CreateAPIToken(ctx context.Context, t types.APIToken, raw string) (types.APIToken, error)
CreateAPIToken inserts one token row. raw is the PLAINTEXT credential; only its hash is stored, and the caller must return the plaintext to its creator exactly once (unrecoverable afterwards). t.Token is ignored — passing the secret twice would be the one way to accidentally persist it.
A unique_violation (23505) on token_sha256 is ErrConflict: a raw collision in a 256-bit space means the caller reused a token value rather than minting a fresh one.
SECURITY: groups_truncated binds as SQL NULL when nil. NULL means "minted before anything recorded this", and consumers read that as TRUNCATED, not false. A plain bool or DEFAULT FALSE would assert "complete" for every legacy row — fail OPEN, the exact thing the marker exists to prevent.
func (PG) CreateApproval ¶
func (s PG) CreateApproval(ctx context.Context, a types.ApprovalRequest) (types.ApprovalRequest, error)
CreateApproval inserts a new approval request. With approval notifications configured it also inserts the approval's outbox rows in the same transaction, so no crash can leave an approval nobody was told about; without them the INSERT is the only write.
func (PG) CreateDelegate ¶ added in v0.8.0
func (s PG) CreateDelegate(ctx context.Context, d types.Delegate, raw string) (types.Delegate, error)
CreateDelegate registers one portal. raw is the PLAINTEXT credential; only its hash is stored. Returns ErrConflict on a credential_sha256 collision (a reused credential in a 256-bit space).
func (PG) CreateDevice ¶ added in v0.8.0
CreateDevice inserts one device row, following CreateAPIToken's shape: raw is the plaintext device credential minted at enrolment. SECURITY: only its hash is stored, and d.CredentialSHA256 is ignored, so the caller can never accidentally persist the secret twice; raw is returned to the device exactly once, unrecoverable afterwards. ErrConflict on a credential_sha256 collision, same 256-bit space as MintEnrolmentToken.
func (PG) CreateGrant ¶
func (s PG) CreateGrant(ctx context.Context, g types.CredentialGrant) (types.CredentialGrant, error)
CreateGrant inserts a credential grant (eligibility record) and returns it.
func (PG) CreatePerson ¶ added in v0.8.0
func (PG) CreatePolicy ¶
CreatePolicy inserts a policy and returns the persisted row. Returns ErrConflict when the name's UNIQUE constraint (run_policies.name) rejects a duplicate — the caller maps that to 409, never the raw driver error.
func (PG) CreateRunUnderCap ¶ added in v0.8.6
func (s PG) CreateRunUnderCap(ctx context.Context, r types.AgentRun, limit int) (types.AgentRun, error)
CreateRunUnderCap is CreateRun with a deployment-wide ceiling on non-terminal runs (WARDYN_MAX_CONCURRENT_RUNS). The count and the insert share one transaction-scoped advisory lock, so two replicas racing at the cap admit exactly the cap. limit <= 0 is unlimited and takes no lock. Rows are counted, not kept in a counter, so a crashed path cannot drift it.
func (PG) CreateScimGroup ¶ added in v0.8.6
func (s PG) CreateScimGroup(ctx context.Context, externalID, displayName string, now time.Time) (ScimGroup, error)
CreateScimGroup stores a group. An externalId any group already holds, in any case, is ErrScimGroupExists.
func (PG) CreateScimIdentity ¶ added in v0.8.6
func (s PG) CreateScimIdentity(ctx context.Context, issuer, tenantID, objectID string, u IdentityUpdate, now time.Time) (PrincipalIdentity, bool, error)
CreateScimIdentity records a SCIM user as an identity row with no principal, keyed by the object id, or finds the row already holding it (created=false). The first sign-in binds the principal.
func (PG) CreateUserType ¶ added in v0.8.0
CreateUserType inserts a custom type (built_in is never set here). ErrConflict when the id or name is taken, or the id is still named by an orphaned subject row.
func (PG) CreateWorkspace ¶
CreateWorkspace inserts an onboarded workspace and returns the persisted row.
func (PG) DecideApproval ¶
func (s PG) DecideApproval(ctx context.Context, id uuid.UUID, decision types.ApprovalDecision) (types.ApprovalRequest, error)
DecideApproval transitions an approval from PENDING to decision.State. Returns ErrAlreadyDecided if the approval is not PENDING (fail-closed), via a single UPDATE with WHERE state='PENDING' to prevent TOCTOU races. SET is kept separate from RETURNING: updating only RETURNING would echo an un-updated row back as a green result over a silent no-op.
func (PG) DecideGovernanceChange ¶ added in v0.8.6
func (s PG) DecideGovernanceChange(ctx context.Context, id uuid.UUID, d GovernanceDecision, fn GovernanceDecideFunc) (types.GovernanceChange, error)
DecideGovernanceChange decides one change in one transaction:
- lock the change row;
- require it pending and unexpired. A lapsed pending row is moved to expired here and that is committed, and the caller gets *ErrGovernanceChangeNotPending with Lapsed set;
- run fn on the transaction (the target's checks and apply);
- move the row to d.To, stamping the decider and the time;
- commit.
fn returning ErrGovernanceChangeStale moves the row to stale instead and commits that. Any other error from fn, or from the state move, rolls the whole transaction back: a target written by fn is then unwritten and the change is still pending. ErrNotFound when no such change.
func (PG) DeleteBaseImage ¶ added in v0.5.0
DeleteBaseImage removes a catalog row; detach=true drops every workspace reference first (falling back to the derived recommended build — NULL is the marker, so "detach" is honest, not destructive). detach=false mirrors DeleteSource's residual race (STORE-2): a concurrent commit between the NOT EXISTS check and delete is instead caught by the base_image_id FK (0031:61), surfacing as 23503 — mapped to ErrConflict below.
func (PG) DeleteBranding ¶ added in v0.8.0
DeleteBranding implements BrandingStore.
func (PG) DeleteCapabilityGrant ¶ added in v0.6.0
DeleteCapabilityGrant removes one grant by id. Returns ErrNotFound when no row matched — this is an admin-only surface, so there is no principal to scope the delete to and no existence oracle to worry about.
func (PG) DeleteGovernanceAssignment ¶ added in v0.7.0
DeleteGovernanceAssignment removes one assignment by id, ErrNotFound when no row matched. Unassigning is the SUPPORTED way to widen someone back to the deployment ceiling.
func (PG) DeleteGovernanceProfile ¶ added in v0.7.0
DeleteGovernanceProfile removes one profile by id. ErrNotFound when no row matched.
ErrConflict when the row is still ASSIGNED: governance_assignments' ON DELETE RESTRICT refuses (23503) rather than cascading, since cascading would silently widen every assigned member back to the deployment ceiling. Translated into a sentinel so the route answers a caller-fixable 409 instead of a 500. *ErrProfileHasChildren when other profiles still compose on it (named under the graph lock, so the answer matches what the delete saw).
func (PG) DeleteLaunchPreset ¶ added in v0.8.0
DeleteLaunchPreset removes a preset by name, returning the removed row, or ErrNotFound. Runs launched from it keep their preset/preset_version stamp.
func (PG) DeletePolicy ¶
DeletePolicy removes a policy by id. Returns ErrNotFound when no row matched. agent_runs.policy_id has no foreign key, so referencing runs keep a dangling policy_id; their authorization envelope survives via the run.policy.resolve audit event dispatch already recorded.
func (PG) DeleteRef ¶ added in v0.3.1
DeleteRef removes the row for ref. Idempotent: deleting a missing ref is nil.
func (PG) DeleteRoleMapping ¶ added in v0.7.0
DeleteRoleMapping removes one row by id. Returns ErrNotFound when no row matched — admin-only surface, so there is no principal to scope the delete to and no existence oracle to worry about, exactly DeleteCapabilityGrant.
func (PG) DeleteRunOutputsOlderThan ¶ added in v0.8.6
DeleteRunOutputsOlderThan — see RunOutputStore.
func (PG) DeleteRunProxyConfig ¶ added in v0.8.0
DeleteRunProxyConfig — see RunProxyConfigs.
func (PG) DeleteSSHKey ¶ added in v0.5.0
DeleteSSHKey removes fingerprint, scoped to principal so a human can only delete their OWN key. Returns ErrNotFound whether the fingerprint doesn't exist or belongs to someone else — indistinguishable on purpose, no existence leak across principals.
func (PG) DeleteSSHKeys ¶ added in v0.8.0
DeleteSSHKeys removes a principal's registered keys, or every key when principal is empty. The count comes from the DELETE, not a prior snapshot.
func (PG) DeleteScimGroup ¶ added in v0.8.6
DeleteScimGroup removes the group row and, by cascade, its members. Its ledger rows stay.
func (PG) DeleteSource ¶ added in v0.5.0
DeleteSource removes a library source. detach=true strips every workspace attachment referencing it (?force=1) UNLESS that would leave a workspace with zero attachments (workspacesOrphanedBySource) — '[]' must stay unreachable (STORE-1). The check and the detach are two statements, so this only narrows, never closes (STORE-2), the race against a concurrent attach; same residual race as the detach=false path below.
func (PG) DeleteUserDrive ¶ added in v0.7.0
DeleteUserDrive removes one drive by id. ErrNotFound if no row matched; ErrConflict if it's still allocated (user_drive_grants.drive_id is ON DELETE RESTRICT — Postgres refuses rather than cascading away grants whose directories may still hold someone's work).
func (PG) DeleteUserDriveGrant ¶ added in v0.7.0
DeleteUserDriveGrant removes one grant by id and returns it (ErrNotFound if no match) — removing only the binding, never the volume/claim/directory. RETURNING lets the caller audit-log what was removed without a prior scan.
func (PG) DeleteUserSubjectRows ¶ added in v0.8.6
func (s PG) DeleteUserSubjectRows(ctx context.Context, id uuid.UUID, principals, emails []string) (grants, assignments, kept int64, err error)
DeleteUserSubjectRows deletes the user-subject capability grants and governance assignments of the purged identity id, matched case-insensitively, and says how many of each. A direct delete, never the GOV4 apply path. Rows keyed by one of principals go: the subject is a purged identity that can never authenticate again. Rows keyed by one of emails go only while no other principal holds that address, because an address can be recycled and the new holder's deny rows are theirs: another identity that is neither deactivated nor purged, or an API token or people row under a principal that is not in principals (or the address itself, a form of the leaver). Rows kept for that reason are counted in kept.
func (PG) DeleteUserType ¶ added in v0.8.0
DeleteUserType removes a custom type that nothing names. ErrNotFound when no row has the id; ErrConflict when it is built in, still referenced, or held by a foreign key (role_mappings.user_type is ON DELETE RESTRICT). The reference check rides the DELETE itself, so a row written between the caller's check and this statement still refuses.
func (PG) DeleteWorkspace ¶
DeleteWorkspace removes a workspace by id. Returns ErrNotFound when no row matched.
func (PG) DropAuditPartition ¶ added in v0.8.6
func (PG) DryRunGovernance ¶ added in v0.8.6
DryRunGovernance runs fn on a transaction that is always rolled back, and returns fn's error. It is how a proposal learns whether a write would be accepted (and what it would produce) by running the very code that applies it, with nothing left behind.
func (PG) DuePauseSettles ¶ added in v0.8.6
func (s PG) DuePauseSettles(ctx context.Context) ([]PauseSettle, error)
DuePauseSettles — see PauseSettler.
func (PG) EnsureAuditPartitions ¶ added in v0.8.6
func (PG) EnsureDeprovisionJobs ¶ added in v0.8.6
func (s PG) EnsureDeprovisionJobs(ctx context.Context, identityID uuid.UUID, kind string, keys []JobKey) error
EnsureDeprovisionJobs adds each key as a pending ledger row, leaving rows that exist as they are.
func (PG) EraseGovernanceChangePersonalFields ¶ added in v0.8.6
EraseGovernanceChangePersonalFields clears the proposer and decider (their emails too, and the reason a decider typed) of every change whose recorded principal is one of names or whose recorded email matches one of them (case folded), and returns how many rows it touched. A pending change whose proposer is erased leaves pending in the same statement (to expired), so a change with no recorded proposer can never be approved. Idempotent: a row already cleared matches nothing.
func (PG) EraseRunOutputs ¶ added in v0.8.6
EraseRunOutputs — see RunOutputStore. The locks are taken in key order, so two overlapping erasures cannot each hold what the other waits for.
func (PG) ExportAuditPartition ¶ added in v0.8.6
func (s PG) ExportAuditPartition(ctx context.Context, name string, header func(PartitionManifest) error, row func(AuditPartitionRow) error) error
func (PG) FailDeprovisionJob ¶ added in v0.8.6
func (s PG) FailDeprovisionJob(ctx context.Context, identityID uuid.UUID, kind string, k JobKey, cause error) error
FailDeprovisionJob records a failed attempt and leaves the step pending.
func (PG) FederationRevoked ¶ added in v0.8.0
FederationRevoked reports whether the organisation revoked this laptop's device credential (MarkFederationRevoked), false when no row exists.
func (PG) FinishADOSignInEnd ¶ added in v0.8.6
FinishADOSignInEnd — see ADOSignInEndStore.
func (PG) FinishDeprovisionJob ¶ added in v0.8.6
func (s PG) FinishDeprovisionJob(ctx context.Context, identityID uuid.UUID, kind string, k JobKey, detail map[string]int) error
FinishDeprovisionJob marks a step done, storing the counts it produced.
func (PG) GetAPITokenByRaw ¶ added in v0.6.0
GetAPITokenByRaw is the auth-time lookup: given a bearer string, resolve the LIVE token it stands for. Deliberately UNSCOPED by principal — this call is what authenticates the caller.
SECURITY: `revoked_at IS NULL` and the not-expired test (apiTokenLive) are in the WHERE, not checked separately — a revoked, expired, unknown, or non-matching token all fail IDENTICALLY with ErrNotFound, so the boundary is never an oracle for "this token once existed".
func (PG) GetApproval ¶
GetApproval returns the approval for id, or ErrNotFound.
func (PG) GetAttachLease ¶ added in v0.8.6
GetAttachLease — see AttachLeaseStore.
func (PG) GetBaseImage ¶ added in v0.5.0
GetBaseImage returns the catalog row for id, or ErrNotFound. Not on the Store interface (no handler reads one image by id); kept as a PG method because store_hydrate_pg_test.go round-trips through it.
func (PG) GetBaseImagesByIDs ¶ added in v0.5.0
func (s PG) GetBaseImagesByIDs(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID]types.BaseImageEntry, error)
GetBaseImagesByIDs is hydrateAll's own batched read, not a Store-interface method — its only caller is inside this package. Returns the base images for ids in ONE query, keyed by id, mirroring GetSourcesByIDs. Missing ids are simply absent (hydrateWorkspace leaves BaseImage nil for them).
func (PG) GetBranding ¶ added in v0.8.0
GetBranding implements BrandingStore.
func (PG) GetCapabilityEnforcement ¶ added in v0.6.0
GetCapabilityEnforcement returns the per-kind switch map. An ABSENT row means NOT ENFORCED, so the returned map is sparse by design and a missing key reads as false — that default is the whole zero-config back-compat story (see the migration). Never nil.
func (PG) GetDelegateByRaw ¶ added in v0.8.0
GetDelegateByRaw resolves the LIVE portal a credential stands for.
func (PG) GetDelegatedTokenByID ¶ added in v0.8.5
func (s PG) GetDelegatedTokenByID(ctx context.Context, id uuid.UUID, now time.Time) (types.DelegatedToken, error)
GetDelegatedTokenByID is GetDelegatedTokenByRaw by the grant's id: live while unexpired at now AND its portal still registered. A UI session opened through a portal re-asks it, so the session ends with the grant (#1475). Expired rows are swept on any mint, so ErrNotFound means ended.
func (PG) GetDelegatedTokenByRaw ¶ added in v0.8.0
func (s PG) GetDelegatedTokenByRaw(ctx context.Context, raw string, now time.Time) (types.DelegatedToken, error)
GetDelegatedTokenByRaw is the delegated lane's auth lookup: the token must be unexpired at now AND its portal still registered — the join is what makes revoking a portal kill all its tokens on their next request.
func (PG) GetDeviceByRaw ¶ added in v0.8.0
GetDeviceByRaw is the device auth-time lookup: given the bearer a device presented, resolve the live row it stands for. TRUST BOUNDARY: `revoked_at IS NULL` is in the WHERE (mirrors GetAPITokenByRaw), so a revoked/unknown/mismatched credential all fail identically with ErrNotFound.
func (PG) GetFederationCursor ¶ added in v0.8.0
GetFederationCursor returns how far this deployment's forwarder has pushed audit_events upward, and the row_hash the organisation acknowledged at that seq — 0 and "" when nothing forwarded yet (matching GetSiteConfig's zero-value-on-no-row contract).
func (PG) GetGovernanceChange ¶ added in v0.8.6
GetGovernanceChange returns one change, ErrNotFound when none; a pending row past its expiry reads as expired.
func (PG) GetGovernanceProfile ¶ added in v0.7.0
func (s PG) GetGovernanceProfile(ctx context.Context, id uuid.UUID) (types.GovernanceProfile, error)
GetGovernanceProfile returns one profile by id, or ErrNotFound. The RAW row: a composed profile carries no authority here (see GetGovernanceProfileChain).
func (PG) GetGovernanceProfileChain ¶ added in v0.8.6
func (s PG) GetGovernanceProfileChain(ctx context.Context, id uuid.UUID) ([]types.GovernanceProfile, error)
GetGovernanceProfileChain reads one profile and its ancestors in ONE statement, leaf first, bounded at depth 3 (the profile, its base, that base's base). ErrNotFound when the leaf is gone. It returns whatever the bound reached, cycle or overflow included: the caller refuses a chain whose last row still names a base or whose ids repeat, and never composes a partial one.
func (PG) GetIdentity ¶ added in v0.8.6
GetIdentity is the row stored under id, or ErrNotFound.
func (PG) GetIdentityByObject ¶ added in v0.8.6
func (PG) GetLaunchPreset ¶ added in v0.8.0
GetLaunchPreset returns one preset by name, or ErrNotFound.
func (PG) GetPrincipalPref ¶ added in v0.8.0
func (PG) GetPushPathList ¶ added in v0.8.0
func (PG) GetRef ¶ added in v0.3.1
GetRef returns the substrate name for ref. A missing row is (found=false, nil error) — pre-migration and unknown refs are expected, not errors.
func (PG) GetRunLayout ¶ added in v0.5.0
GetRunLayout reads the one (principal, preset) row scoped to principal — a layout is never looked up by anything but its owner.
func (PG) GetRunOutput ¶ added in v0.8.6
GetRunOutput — see RunOutputStore.
func (PG) GetRunProxyConfig ¶ added in v0.8.0
GetRunProxyConfig — see RunProxyConfigs.
func (PG) GetSSHKeyByFingerprint ¶ added in v0.5.0
func (s PG) GetSSHKeyByFingerprint(ctx context.Context, fingerprint string) (types.SSHPublicKey, error)
GetSSHKeyByFingerprint is the gateway's pre-auth lookup: resolves which principal (if any) registered the offered fingerprint, and with which role, the admin-override signal. Deliberately UNSCOPED by principal — the caller has not authenticated yet; this call is what authenticates them. Returns ErrNotFound when unregistered.
func (PG) GetScimGroup ¶ added in v0.8.6
GetScimGroup is the group stored under id, or ErrNotFound.
func (PG) GetSiteConfig ¶
GetSiteConfig returns the operator-wide site config, or a ZERO-VALUE SiteConfig (not an error) when no row has been written yet — first boot has no config, and "unconfigured" is a valid, common state rather than a failure the caller must special-case.
func (PG) GetSourcesByIDs ¶ added in v0.5.0
func (s PG) GetSourcesByIDs(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID]types.Source, error)
GetSourcesByIDs returns the sources for ids in ONE query, keyed by id — the hydrate pass's bulk read. Missing ids are simply absent (a dangling attachment contributes nothing; fold and mount-gate each handle it).
func (PG) GetUserDrive ¶ added in v0.7.0
GetUserDrive returns one drive by id, or ErrNotFound.
func (PG) GetUserType ¶ added in v0.8.0
GetUserType returns one type by id, or ErrNotFound.
func (PG) GetWorkspace ¶
GetWorkspace returns the workspace for id, or ErrNotFound.
func (PG) GroupRemovalFailures ¶ added in v0.8.6
GroupRemovalFailures is ListDeprovisionFailures for the pendingGroupRemovalWhere rows with a recorded error: one row per identity and step, with the error of the target touched last.
func (PG) GroupRemovalIdentities ¶ added in v0.8.6
GroupRemovalIdentities is every identity a group's deletion must remove as a mover: the recorded members, and anyone whose removal from this group is still pending.
func (PG) HasGroupTierAssignments ¶ added in v0.7.0
HasGroupTierAssignments reports whether ANY group-tier assignment exists: the gate on the stale-snapshot refusal (see hasGroupTierRows).
func (PG) HasGroupTierDriveGrants ¶ added in v0.7.0
HasGroupTierDriveGrants reports whether ANY group-tier grant exists: the gate on the stale-snapshot refusal (see hasGroupTierRows).
func (PG) HasRunAuditEvent ¶ added in v0.8.0
HasRunAuditEvent reports whether runID has an audit row matching f.
func (PG) HeartbeatRunWatcher ¶ added in v0.5.0
HeartbeatRunWatcher refreshes the lease on id for owner: the "still watching" write every watcher goroutine repeats while alive; its silence lets another replica's ClaimStaleRunWatchers take over.
Unconditional on current owner, since a watcher can't abort its blocking Runner.Wait anyway and two watchers are harmless (the terminal transition is a CAS). Doesn't bump updated_at either, like the claim: a heartbeat there would make every run look forever-active and disable idle auto-stop. A missing row isn't an error; the lease is advisory.
func (PG) HeldEmails ¶ added in v0.8.6
func (s PG) HeldEmails(ctx context.Context, id uuid.UUID, principals, emails []string) ([]string, error)
HeldEmails is the emails another principal holds, by DeleteUserSubjectRows' rule: another identity than id that is neither deactivated nor purged, or a live API token (unrevoked, unexpired) or people row (not deactivated) under a principal that is neither one of principals nor the address itself and whose identity is neither deactivated nor purged. A previous holder that is gone holds nothing. Matched case-insensitively; the answer is lower-cased.
func (PG) HoldsAttachLease ¶ added in v0.8.6
HoldsAttachLease — see AttachLeaseStore.
func (PG) IdentitiesByAlias ¶ added in v0.8.6
func (s PG) IdentitiesByAlias(ctx context.Context, issuer, valueLower string) ([]PrincipalIdentity, error)
IdentitiesByAlias is the rows under issuer that have no object id and were seen under valueLower as an email or a userName: the removal-only link a SCIM user with no object-id match falls to.
func (PG) IdentitiesByPrincipal ¶ added in v0.8.6
func (PG) IdentityAliasValues ¶ added in v0.8.6
IdentityAliasValues is every alias value (email and userName) the identity has been seen under, sorted.
func (PG) IdentityBlocked ¶ added in v0.8.6
IdentityBlocked reports whether principal's identity rows refuse a credential admitted under epoch (epoch < 0: only a deactivation refuses). It is the read the cookie, API-token and SSH-key lanes make at authentication, as one statement.
func (PG) IdentityRefused ¶ added in v0.8.6
func (s PG) IdentityRefused(ctx context.Context, issuer, tenantID, objectID, principal string) (bool, error)
IdentityRefused is the admission half of the sign-in gate, read-only: whether the identity a sign-in names is deactivated or purged. An Entra sign-in is named by (issuer, tenant, object id), and every sign-in by its resolved principal; either match refuses.
func (PG) IngestDeviceAudit ¶ added in v0.8.0
func (s PG) IngestDeviceAudit(ctx context.Context, deviceID uuid.UUID, peer string, rows []types.FederatedAuditEvent) (DeviceIngestResult, error)
IngestDeviceAudit appends one device's forwarded batch to this organisation's own audit_events, as the organisation's own chained rows ("one chain per writer"). A federated row keeps the device's claimed actor_type, action, target and outcome; what marks it forwarded is the device's provenance folded into `data` (mergeDeviceOrigin), not a new audit action, so no filter/SIEM rule keyed on `action` has to learn about it. TRUST BOUNDARY: three fields are never the device's to choose — actor is FederatedActor (claim kept in data.device_origin.actor); source_ip is peer (claim kept in data.device_origin.source_ip); and a run_id naming one of this organisation's own runs refuses the batch (ErrFederatedOrgRun).
Order of work, chosen so a device can make the org's own audit writers wait for at most its inserts:
- Every row must be storable (FederatedRowProblem) and representable by Postgres, or ErrFederatedRowInvalid.
- Every claimed RowHash is recomputed in SQL before any transaction or lock, in ONE statement (verifyClaimedHashes), against its own claimed PrevHash. A refused or replayed batch never touches the chain lock.
- The device row is locked FOR UPDATE, serializing this device's concurrent pushes before either reaches the chain lock (deadlock-free: no transaction takes the chain lock then a device row). A revoked device answers ErrDeviceRevoked.
- Idempotency rides the cursor and the hash, not audit_events.id: rows at or before LastSeq that are the rows held here (heldPrefix) are skipped — the forwarder's cursor can lag what was committed. A reused seq is not a re-send.
- The first new row's claimed PrevHash is either empty (genesis, accepted — a chain reset if one was already recorded) or equal to LastRowHash with seq past LastSeq; every later row's claimed PrevHash equals the preceding row's claimed RowHash. Otherwise ErrConflict.
- Only then the chain lock (db.AuditChainLockKey), under the lock timeout, and the inserts: field for field as claimed except actor, source_ip and merged data. Cursor advances in the same transaction.
Any refusal refuses the entire batch, never a verified prefix: it's the retry unit, and a partial accept would leave the cursor mid-batch with no way to tell the caller which rows to resend.
func (PG) InsertPendingRunOutput ¶ added in v0.8.6
InsertPendingRunOutput — see RunOutputStore.
func (PG) InsertRunPAT ¶ added in v0.8.2
InsertRunPAT — see RunPATStore.
func (PG) IssueLoginIdentity ¶ added in v0.8.6
func (s PG) IssueLoginIdentity(ctx context.Context, in LoginIdentity, now time.Time) (epoch int64, err error)
IssueLoginIdentity is the issuance half of the sign-in gate: in one transaction it upserts and binds the identity row (a failure refuses the sign-in), re-checks deactivation on every row bound to the principal and reads the authority epoch the session cookie will carry. The rows stay locked until the commit, so a suspension either precedes it, and the sign-in is refused with ErrIdentityDeactivated, or follows it, and bumps the epoch past the one returned. A sign-in whose identity is bound to another principal is ErrIdentityBindingMismatch: its session would carry neither that identity's deactivation nor its epoch. A refused sign-in writes nothing.
func (PG) LastRunPAT ¶ added in v0.8.2
LastRunPAT — see RunPATReader.
func (PG) LatestAuditEventByAction ¶
LatestAuditEventByAction returns the most recent audit event whose action equals the given action, or ErrNotFound when none exists. Used by /healthz to find the latest kernel.sensor.ping driving the eBPF health state.
Most recent by `time`, picked from a seq-ordered window: the audit spool replays at-least-once while keeping each event's original ev.Time, so a beat spooled through a DB blip could carry the highest seq but an hours-old time and falsely mark the sensor degraded. The window orders by seq to keep using the purpose-built (action, seq DESC) index; ordering by time directly would sort the whole action's history on every probe. Twenty is a window, not a proof — a longer replay backlog can push the fresh row out, bounding the staleness to one heartbeat interval against /healthz's own TTL.
func (PG) ListAPITokens ¶ added in v0.6.0
ListAPITokens returns every token in the deployment, newest first (admin GET /tokens); revoked rows included, same reason as the self-service list.
func (PG) ListAPITokensByPrincipal ¶ added in v0.6.0
func (s PG) ListAPITokensByPrincipal(ctx context.Context, principal string) ([]types.APIToken, error)
ListAPITokensByPrincipal returns principal's own tokens, newest first (self-service GET /me/tokens). Revoked rows are INCLUDED so a human can confirm a retired token is retired; the row carries no usable credential either way.
func (PG) ListAPITokensByPrincipalPage ¶ added in v0.8.0
func (s PG) ListAPITokensByPrincipalPage(ctx context.Context, principal string, p Page) ([]types.APIToken, error)
ListAPITokensByPrincipalPage is ListAPITokensByPrincipal bounded by p.
func (PG) ListApprovals ¶
func (s PG) ListApprovals(ctx context.Context, stateFilter types.ApprovalState) ([]types.ApprovalRequest, error)
ListApprovals returns approvals filtered by state. Pass empty string to list all.
func (PG) ListApprovalsPage ¶ added in v0.3.1
func (s PG) ListApprovalsPage(ctx context.Context, stateFilter types.ApprovalState, p Page) ([]types.ApprovalRequest, error)
ListApprovalsPage returns approvals filtered by state (empty = all) in reverse request order, bounded by p. The all-state feed rides approvals_requested_at_idx; a single-state filter rides approvals_state_requested_at_idx, serving both WHERE and ORDER BY without a sort.
func (PG) ListApprovalsPageByRun ¶ added in v0.7.0
func (s PG) ListApprovalsPageByRun(ctx context.Context, runID uuid.UUID, stateFilter types.ApprovalState, p Page) ([]types.ApprovalRequest, error)
ListApprovalsPageByRun is ListApprovalsPage narrowed to one run, same state filter and ordering.
ponytail: no new index. approvals_run_idx already makes this an index scan, and one run's approvals are few enough that sorting by requested_at is free — upgrade to a composite (run_id, requested_at DESC) if that changes.
func (PG) ListApprovalsPageByRunCreator ¶ added in v0.5.0
func (s PG) ListApprovalsPageByRunCreator(ctx context.Context, createdBy string, stateFilter types.ApprovalState, p Page) ([]types.ApprovalRequest, error)
ListApprovalsPageByRunCreator is ListApprovalsPage narrowed to approvals on runs createdBy owns, via a JOIN on agent_runs (approvals has no created_by of its own). Same state filter and ordering as ListApprovalsPage.
func (PG) ListAuditEventsAfterSeq ¶ added in v0.8.0
func (s PG) ListAuditEventsAfterSeq(ctx context.Context, seq int64, limit int) ([]types.FederatedAuditEvent, error)
ListAuditEventsAfterSeq returns this deployment's own audit_events strictly after seq, oldest first — the forwarder's read of its local chain to build the next batch IngestDeviceAudit expects. limit<=0 defaults to 1000, matching QueryAuditEvents/QueryRecentAuditEvents.
func (PG) ListBaseImages ¶ added in v0.5.0
ListBaseImages returns the whole catalog, newest first.
func (PG) ListCapabilityGrants ¶ added in v0.6.0
ListCapabilityGrants returns every grant, oldest first — the admin Permissions screen's whole table in one read.
func (PG) ListCapabilityGrantsFor ¶ added in v0.6.0
func (s PG) ListCapabilityGrantsFor(ctx context.Context, users, groups []string, userType string) ([]types.CapabilityGrant, error)
ListCapabilityGrantsFor returns every grant that could apply to one caller: `all` rows, `user` rows naming any of users (the caller's lowercased sub AND email), `group` rows naming any of groups, and `user_type` rows naming the caller's one type. An empty userType matches no row, since the write boundary refuses an empty subject.
Deliberately NOT filtered by capability: the resolver needs one kind and GET /me/capabilities needs all four, and one round trip serving both beats two indexes and two queries. Per-kind/per-value matching happens in Go.
ponytail: no cache. This runs per request, on the (subject_type, subject) index; a process-local cache is the HA blocker OPERATIONS already names for other state, and a stale permission cache is a security bug, not a slow page. Add one only behind a shared invalidation channel.
func (PG) ListCapabilityGrantsForPage ¶ added in v0.8.0
func (s PG) ListCapabilityGrantsForPage(ctx context.Context, users, groups []string, userType string, p Page) ([]types.CapabilityGrant, error)
ListCapabilityGrantsForPage is ListCapabilityGrantsFor bounded by p: same four subject arms, so a page never drops a `user_type` grant the unpaged read returns.
func (PG) ListCapabilityRestrictions ¶ added in v0.8.0
ListCapabilityRestrictions returns every restricted value, kind -> set. The table holds one row per restricted admin-configured resource, so one read per resolution answers every value it asks about. Never nil.
func (PG) ListDeactivatedIdentities ¶ added in v0.8.6
ListDeactivatedIdentities is the identities deactivated and not purged, most recently deactivated first, at most limit.
func (PG) ListDelegates ¶ added in v0.8.0
ListDelegates returns every portal, newest first, including revoked — admins need to see that a retired portal is retired.
func (PG) ListDeprovisionFailures ¶ added in v0.8.6
ListDeprovisionFailures is the suspend and purge ledger rows that are pending with a recorded error for an identity still deactivated or purged (the sweeper's scope: a reactivated person's leftover rows are not unfinished work), oldest identity first, at most limit. One row per identity, kind and step: a step that fails for several targets is listed once, with the error of the one touched last.
func (PG) ListDeprovisionJobs ¶ added in v0.8.6
func (s PG) ListDeprovisionJobs(ctx context.Context, identityID uuid.UUID, kind string) ([]DeprovisionJob, error)
ListDeprovisionJobs is the ledger of one identity and kind, oldest first.
func (PG) ListDevices ¶ added in v0.8.0
ListDevices returns every enrolled device, newest first, revoked rows included (an admin needs to see a retired device is retired). Phase one has no console surface for this (CLI/API only).
func (PG) ListEnrolmentTokens ¶ added in v0.8.0
func (s PG) ListEnrolmentTokens(ctx context.Context, now time.Time) ([]types.DeviceEnrolmentToken, error)
ListEnrolmentTokens returns every token still redeemable at now (unconsumed, unexpired), newest first — the ones an admin may still cancel; a redeemed or expired token is never listed.
func (PG) ListGovernanceAssignments ¶ added in v0.7.0
ListGovernanceAssignments returns every assignment in the order the resolver itself would rank them (tier, then priority, then subject), so the console's table reads top-down as the precedence rule.
func (PG) ListGovernanceChanges ¶ added in v0.8.6
func (s PG) ListGovernanceChanges(ctx context.Context, state string) ([]types.GovernanceChange, error)
ListGovernanceChanges returns changes newest first. state narrows to one state ("" is every state); a pending row past its expiry reads as expired.
func (PG) ListGovernanceProfiles ¶ added in v0.7.0
ListGovernanceProfiles returns every profile by name (the handle an admin looks for), unlike the creation order other List* calls use. Deployment- wide config, so there's no per-caller scoping to filter on.
func (PG) ListGrantsByRun ¶
ListGrantsByRun returns all grants for a run.
func (PG) ListGrantsByRunPage ¶ added in v0.8.0
func (s PG) ListGrantsByRunPage(ctx context.Context, runID uuid.UUID, p Page) ([]types.CredentialGrant, error)
ListGrantsByRunPage is ListGrantsByRun bounded by p.
func (PG) ListGroupDenyGrants ¶ added in v0.7.0
func (s PG) ListGroupDenyGrants(ctx context.Context, capability string) ([]types.CapabilityGrant, error)
ListGroupDenyGrants returns the GROUP-subject DENY rows of one capability kind — the only rows internal/api's unresolvable-group-deny check can match.
It exists because that check runs on the FAIL-CLOSED path every caller with an unanswerable group snapshot takes (every pre-0.7 API token, every request): answering it with ListCapabilityGrants would let one such token force an unbounded full-table read per checked value — an authorization question whose cost scales with table size is an availability surface, not just a slow page. The predicate is what internal/api applied in Go afterwards, moved into SQL; value-overlap matching stays in Go (TestCapUnresolvableGroupDenyMatchesFullScan pins the two together). The (subject_type, subject) index already serves it.
ponytail: no EXISTS fast path in front of it. It would be a second round trip to save a query that already returns nothing on the deployments the fast path would help.
func (PG) ListLapsedTokenRuns ¶ added in v0.8.0
ListLapsedTokenRuns — see RunLoser. Both sides use the database's clock, so replica clock skew cannot make a live run look lapsed.
func (PG) ListLaunchPresets ¶ added in v0.8.0
ListLaunchPresets returns every preset by name.
func (PG) ListLeasedRuns ¶ added in v0.8.0
ListLeasedRuns reads the runs the lease sweep acts on. RUNNING only: a run still starting reaches its end on the first sweep after it is up, and a terminal run has nothing left to end.
func (PG) ListNonTerminalRunsBy ¶ added in v0.8.6
ListNonTerminalRunsBy is createdBy's runs that have not ended.
func (PG) ListPauseCandidates ¶ added in v0.8.0
ListPauseCandidates — see RunPauser.
func (PG) ListPendingApprovalsForRuns ¶ added in v0.8.0
func (s PG) ListPendingApprovalsForRuns(ctx context.Context, runIDs []uuid.UUID) ([]types.ApprovalRequest, error)
ListPendingApprovalsForRuns — see ApprovalsForRunsPager. Backed by approvals_run_idx and the partial approvals_state_idx: an index scan over run_id = ANY($1) intersected with the partial index, not a table scan.
func (PG) ListPeople ¶ added in v0.8.0
func (PG) ListPeopleDirectory ¶ added in v0.8.6
func (s PG) ListPeopleDirectory(ctx context.Context, f PeopleDirectoryFilter) (PeopleDirectoryPage, error)
func (PG) ListPolicies ¶
ListPolicies returns all policies in reverse creation order. The slice is empty (never nil) when no policies exist.
func (PG) ListPoliciesPage ¶ added in v0.3.1
ListPoliciesPage returns policies in reverse creation order, bounded by p (run_policies_created_at_idx covers the ORDER BY).
func (PG) ListProfiledLiveRuns ¶ added in v0.8.0
ListProfiledLiveRuns — see RunLimitsReclamper.
func (PG) ListRoleMappings ¶ added in v0.7.0
ListRoleMappings returns every row, oldest first — both the console's People screen and internal/auth/oidc's login-time merge (mergeRoleMaps) read the whole table in one call; there is no per-caller scoping to filter on, this is deployment-wide config.
func (PG) ListRunPATs ¶ added in v0.8.2
ListRunPATs — see RunPATReader. The primary key's run_id prefix serves it.
func (PG) ListRunProxyReleases ¶ added in v0.8.0
func (s PG) ListRunProxyReleases(ctx context.Context) ([]RunProxyRelease, error)
ListRunProxyReleases — see RunReviver.
func (PG) ListRunsFiltered ¶ added in v0.8.0
ListRunsFiltered is ListRunsPage narrowed and reordered per f. Owner- scoped reads ride agent_runs_created_by_idx (bitmap scan + in-memory sort); an org-wide read is a parallel seq scan with top-N heapsort — both linear in the caller's history, which the spec accepted (no ended_at index backs this CASE-based order/window).
func (PG) ListRunsPage ¶ added in v0.3.1
ListRunsPage returns runs in reverse creation order, bounded by p. agent_runs_created_at_idx makes the ORDER BY + LIMIT an index scan.
func (PG) ListRunsPageByCreator ¶ added in v0.5.0
func (s PG) ListRunsPageByCreator(ctx context.Context, createdBy string, p Page) ([]types.AgentRun, error)
ListRunsPageByCreator is ListRunsPage narrowed to one creator, same order. ponytail: no dedicated (created_by, created_at) index yet — agent_runs is small enough per-operator that the existing created_at index plus a filter scan is fine; add one if a member's run list ever gets slow.
func (PG) ListSSHKeysByPrincipal ¶ added in v0.5.0
func (s PG) ListSSHKeysByPrincipal(ctx context.Context, principal string) ([]types.SSHPublicKey, error)
ListSSHKeysByPrincipal returns principal's own registered keys, newest first — the self-service GET /me/ssh-keys list.
func (PG) ListSSHKeysByPrincipalPage ¶ added in v0.8.0
func (s PG) ListSSHKeysByPrincipalPage(ctx context.Context, principal string, p Page) ([]types.SSHPublicKey, error)
ListSSHKeysByPrincipalPage is ListSSHKeysByPrincipal bounded by p.
func (PG) ListSources ¶ added in v0.5.0
ListSources returns the whole library, newest first.
func (PG) ListStalePendingRunOutputs ¶ added in v0.8.6
func (s PG) ListStalePendingRunOutputs(ctx context.Context, age time.Duration, limit int) ([]uuid.UUID, error)
ListStalePendingRunOutputs — see RunOutputStore.
func (PG) ListUnrevokedRunPATs ¶ added in v0.8.2
ListUnrevokedRunPATs — see RunPATStore.
func (PG) ListUserDriveGrants ¶ added in v0.7.0
ListUserDriveGrants returns every grant in the order the resolver itself would rank them (tier, then priority, then subject) so the console's table reads top-down as the precedence rule, not insertion order.
func (PG) ListUserDriveGrantsPage ¶ added in v0.7.0
ListUserDriveGrantsPage is ListUserDriveGrants bounded to one window. The LIMIT changes the plan, not just the size: this ORDER BY has no serving index, so unbounded it's a Seq Scan + full sort (50k rows, PG17: 149.7ms disk sort); LIMIT turns it into a top-N heapsort (37.7ms, in memory). The Seq Scan itself needs an index (a migration) to remove.
func (PG) ListUserDrives ¶ added in v0.7.0
ListUserDrives returns every drive by name (the handle an admin looks for) with its grant count, in one read — the console's whole table. The count rides along so the delete affordance is honest (a drive with grants answers 409, visible before clicking); a grouped subquery, not a JOIN, keeps the drive row single.
func (PG) ListUserTypes ¶ added in v0.8.0
ListUserTypes returns every type: the built-in first, then by priority (highest first) and name.
func (PG) ListWorkspaces ¶
ListWorkspaces returns all workspaces in reverse creation order. The slice is empty (never nil) when no workspaces exist.
func (PG) ListWorkspacesPage ¶ added in v0.3.1
ListWorkspacesPage returns workspaces in reverse creation order, bounded by p (workspaces_created_at_idx covers the ORDER BY).
func (PG) ListWorkspacesPageForOwner ¶ added in v0.6.0
func (s PG) ListWorkspacesPageForOwner(ctx context.Context, owner string, p Page) ([]types.Workspace, error)
ListWorkspacesPageForOwner is ListWorkspacesPage narrowed to what one member may see: their own owned rows plus every operator-owned row (”, every pre-0.6 workspace). workspaces_owned_by_idx covers the IN.
func (PG) LockLoginSupersede ¶ added in v0.8.0
LockLoginSupersede holds db.LoginSupersedeLockClass keyed to actor for up to db.LoginSupersedeLockWait. Session-scoped, not transaction-scoped: it guards several independent statements, including a later read-modify-write on the capture path. Borrows one connection from this pool for the hold's duration; see ErrLoginLockNoCapacity for the one error a caller may proceed on.
func (PG) Locker ¶ added in v0.8.6
Locker is the cross-replica locker over this store's database (db.LockerFor): every PG over one pool shares it. The api package takes its ordered locks through it when the store offers one, and falls back to an in-process locker for a store with no database (nil here, for a PG with no pool).
func (PG) MarkAWSSSOTokenSpent ¶ added in v0.8.0
func (s PG) MarkAWSSSOTokenSpent(ctx context.Context, fingerprint, owner string, markedAt time.Time) error
MarkAWSSSOTokenSpent upserts idempotently: ON CONFLICT DO NOTHING keeps row age "since first spent" even on a second failed persist or invalid_grant.
func (PG) MarkFederationRevoked ¶ added in v0.8.0
MarkFederationRevoked durably records that the organisation revoked this laptop, so a restart comes back still refusing new runs.
func (PG) MarkIdentityPurged ¶ added in v0.8.6
MarkIdentityPurged turns the identity into a permanent tombstone (purged_at set) and records the purge's last step as pending, in one transaction that holds the row FOR UPDATE. It reports whether this call marked it: false when the row was already purged and, with requireDue, when it is not (still) deactivated with a purge_after that has passed. The re-check under the lock is what lets a reactivation that committed first win; once the mark commits a reactivation is ErrIdentityPurged.
func (PG) MarkPersonSignedIn ¶ added in v0.8.0
func (PG) MarkRunEnded ¶ added in v0.8.0
MarkRunEnded — see RunLeaser.
func (PG) MarkRunEndingSoon ¶ added in v0.8.0
func (s PG) MarkRunEndingSoon(ctx context.Context, id uuid.UUID, endsAt time.Time, thresholdSec int) (bool, error)
MarkRunEndingSoon — see RunLeaser. Keyed on the end itself, so moving the end re-arms every warning without anyone having to reset a counter.
func (PG) MarkRunLost ¶ added in v0.8.0
func (s PG) MarkRunLost(ctx context.Context, id uuid.UUID, reason types.LostReason, now time.Time, tokenLife time.Duration) (bool, error)
MarkRunLost — see RunLoser.
func (PG) MarkRunOutputIncomplete ¶ added in v0.8.6
MarkRunOutputIncomplete — see RunOutputStore.
func (PG) MarkRunPATRevoked ¶ added in v0.8.2
func (s PG) MarkRunPATRevoked(ctx context.Context, runID, authorizationID uuid.UUID, reason, lastError string) (bool, error)
MarkRunPATRevoked — see RunPATStore.
func (PG) MarkRunPaused ¶ added in v0.8.0
func (s PG) MarkRunPaused(ctx context.Context, id uuid.UUID, reason types.PauseReason, activeAt *time.Time) (bool, error)
MarkRunPaused — see RunPauser.
func (PG) MarkRunRevived ¶ added in v0.8.0
func (s PG) MarkRunRevived(ctx context.Context, id uuid.UUID, from types.LostReason, ended *EndedKept, limit int, startsAgent bool) (bool, error)
MarkRunRevived — see RunReviver.
func (PG) MergeWorkspaceRequirements ¶ added in v0.5.0
func (s PG) MergeWorkspaceRequirements(ctx context.Context, id uuid.UUID, add map[string]types.WorkspaceRequirement) (types.Workspace, error)
MergeWorkspaceRequirements ADDS rows to a workspace's requirements overlay atomically (`jsonb ||`), so a concurrent edit can never be clobbered by read-modify-write. The WHERE clause enforces the same key-count cap the PUT endpoint does, evaluated on the POST-merge total so a multi-key merge can't overshoot it in one jump; at the cap it returns ErrConflict.
func (PG) MintAttachTicket ¶ added in v0.5.0
func (s PG) MintAttachTicket(ctx context.Context, token string, t AttachTicket, now, expiresAt time.Time) error
MintAttachTicket records one outstanding ticket, expiring at expiresAt, and sweeps already-expired rows in the same statement. The sweep compares against the caller's clock (now), NOT now(), so a DB clock running ahead can't silently delete live tickets.
ponytail: the sweep rides the mint instead of a background worker — the table holds only unredeemed tickets inside a 30s TTL, i.e. a handful of rows. Add a sweeper (or an expires_at index) only if mint volume ever makes that false.
func (PG) MintDelegatedToken ¶ added in v0.8.0
func (s PG) MintDelegatedToken(ctx context.Context, t types.DelegatedToken, raw string, now time.Time) (types.DelegatedToken, error)
MintDelegatedToken stores one token (raw is plaintext; only its hash persists), stamps the portal's last use, and sweeps expired tokens. created_at is written on the DB clock, back-dated by t.CreatedAt's age like CreateAPIToken, since it's compared against a session cutoff that Postgres stamps.
ponytail: the sweep rides the mint, like MintAttachTicket — rows live only ten minutes. Add a real sweeper if mint volume ever breaks that.
func (PG) MintEnrolmentToken ¶ added in v0.8.0
func (s PG) MintEnrolmentToken(ctx context.Context, token string, t types.DeviceEnrolmentToken) (types.DeviceEnrolmentToken, error)
MintEnrolmentToken inserts one single-use enrolment token. ErrConflict on a unique_violation (23505) against token_sha256 — a raw collision in a 256-bit random space, same as CreateAPIToken's.
func (PG) NotePauseSettle ¶ added in v0.8.6
func (s PG) NotePauseSettle(ctx context.Context, id uuid.UUID, after time.Duration) (time.Time, error)
NotePauseSettle — see PauseSettler.
func (PG) NoteRunPATRevokeFailed ¶ added in v0.8.2
func (s PG) NoteRunPATRevokeFailed(ctx context.Context, runID, authorizationID uuid.UUID, lastError string) error
NoteRunPATRevokeFailed — see RunPATStore.
func (PG) PendingGroupRemovals ¶ added in v0.8.6
func (s PG) PendingGroupRemovals(ctx context.Context, idleFor time.Duration, limit int) ([]PendingGroupRemoval, error)
PendingGroupRemovals is the pendingGroupRemovalWhere removals that no step of the same removal has touched for idleFor (a request still working on it is not one the sweeper may race), at most limit.
func (PG) PendingLeavers ¶ added in v0.8.6
func (s PG) PendingLeavers(ctx context.Context, idleFor time.Duration, limit int) ([]PendingLeaver, error)
PendingLeavers is the identities with a suspend or purge ledger row still pending that no step has touched for idleFor (a request still working on it is not one the sweeper may race), at most limit. An identity that is neither deactivated nor purged has a stale ledger and is not listed.
func (PG) Ping ¶ added in v0.6.0
Ping proves the pool can actually reach Postgres (a live query round-trip, not just a constructed pool).
func (PG) PrincipalAliases ¶ added in v0.8.6
func (PG) PrincipalForName ¶ added in v0.8.6
func (PG) PrincipalsByEmail ¶ added in v0.8.6
PrincipalsByEmail is the distinct subs the emails resolve to through api_tokens(principal, email) and people, matched case-insensitively: how a suspension reaches someone no identity row binds.
func (PG) ProposeGovernanceChange ¶ added in v0.8.6
func (s PG) ProposeGovernanceChange(ctx context.Context, ch types.GovernanceChange, ttl time.Duration) (types.GovernanceChange, []ExpiredGovernanceChange, error)
ProposeGovernanceChange stores ch as pending, expiring ttl from now on the database's clock. In the same transaction it first moves any lapsed pending change for the same target to expired (returned, for the audit rows), so a live one is the only thing the one-pending-per-target index can refuse: that is *ErrGovernanceChangePending naming it. A create also holds the name it creates (claimCreateName).
func (PG) PruneAWSSSOSpentTokens ¶ added in v0.8.0
PruneAWSSSOSpentTokens deletes spent-token rows older than cutoff (aws_sso_spent_tokens_marked_at_idx backs the WHERE clause).
func (PG) PurgeDueIdentities ¶ added in v0.8.6
PurgeDueIdentities is the identities deactivated and not yet purged whose purge_after has passed, oldest first, at most limit. It is only a candidate read: MarkIdentityPurged re-checks under the lock.
func (PG) PurgeTerminalRunProxyConfigs ¶ added in v0.8.0
PurgeTerminalRunProxyConfigs — see RunProxyConfigs. The terminal test is types.RunState.IsTerminal itself, not a copy of its set in SQL.
func (PG) PutBranding ¶ added in v0.8.0
func (s PG) PutBranding(ctx context.Context, b types.Branding, keepLogo bool) (types.Branding, error)
PutBranding implements BrandingStore.
func (PG) PutCapabilityEnforcement ¶ added in v0.6.0
func (s PG) PutCapabilityEnforcement(ctx context.Context, enabled map[string]bool) (map[string]bool, error)
PutCapabilityEnforcement replaces the WHOLE switch map: any capability not named in enabled loses its row (absent == not enforced). One statement, not a transaction: the DELETE and INSERT run against the same CTE snapshot over disjoint capability sets, so the pair is already atomic.
func (PG) PutLaunchPreset ¶ added in v0.8.0
func (s PG) PutLaunchPreset(ctx context.Context, p types.LaunchPreset) (types.LaunchPreset, PresetWrite, error)
PutLaunchPreset creates p at version 1, or replaces the named row and moves its version by one. A write identical to the stored row changes nothing, not even the version, so re-applying an unchanged document is a no-op. The comparison and the bump are one statement, so two concurrent writers cannot both land on the same version.
func (PG) PutPrincipalPref ¶ added in v0.8.0
func (PG) PutRef ¶ added in v0.3.1
PutRef upserts the ref -> substrate-name row (ref is the primary key).
func (PG) PutRunLayout ¶ added in v0.5.0
func (s PG) PutRunLayout(ctx context.Context, principal, preset string, layout []types.RunLayoutWidget) (types.RunLayout, error)
PutRunLayout upserts principal's layout for preset. ON CONFLICT DO UPDATE makes this one idempotent write with no read-then-decide round trip and no lost-update race between two tabs saving the same preset back to back.
func (PG) PutRunProxyConfig ¶ added in v0.8.0
PutRunProxyConfig — see RunProxyConfigs.
func (PG) PutSiteConfig ¶
func (s PG) PutSiteConfig(ctx context.Context, cfg types.SiteConfig) (types.SiteConfig, error)
PutSiteConfig upserts the single operator-wide site config row. The `singleton` primary key (CHECKed true) makes a second row impossible at the schema level. A write replaces every key types.SiteConfig declares (no partial merge; the API validates the full document first) but keeps any key it doesn't, which only a newer wardynd could have written (declaredJSONKeys).
func (PG) QueryAuditEvents ¶
func (s PG) QueryAuditEvents(ctx context.Context, runID uuid.UUID, limit int) ([]types.AuditEvent, error)
QueryAuditEvents returns audit events for a run in time order. limit <= 0 means no explicit limit (returns up to 1000).
func (PG) QueryAuditEventsFilteredPage ¶ added in v0.4.4
func (s PG) QueryAuditEventsFilteredPage(ctx context.Context, runID *uuid.UUID, f AuditFilter, p Page) ([]types.AuditEvent, error)
QueryAuditEventsFilteredPage returns audit events narrowed by f, bounded by p. A non-nil runID scopes to one run and keeps that trail's chronological seq ASC order (the per-run contract in docs/sdk.md); nil is the newest-first global feed. Only a request that actually sets a predicate takes this path — an unfiltered read stays on the two plain queries above, whose plans are unchanged.
No new index: 0001 covers (time) and 0017 (action, seq DESC); a bounded LIMIT query index-scans the pkey backward and filters, which is what the caps are for. DataContains adds a per-row `data @>` test with no GIN index behind it; the planner walks the pkey or the (time) index and filters, and the LIMIT plus a Since window bound it (about 0.1 s over 2M rows in the #1449 review).
func (PG) QueryAuditEventsPage ¶ added in v0.3.1
func (s PG) QueryAuditEventsPage(ctx context.Context, runID uuid.UUID, p Page) ([]types.AuditEvent, error)
QueryAuditEventsPage returns a run's audit events in seq (chronological) order, bounded by p. audit_events_run_seq_idx makes WHERE run_id + ORDER BY seq an indexed range scan with no sort; OFFSET pages forward without flipping to DESC, so the per-run trail stays ASC (docs/sdk.md's exit-code contract) and a caller pages to the newest events with ?offset=.
func (PG) QueryRecentAuditEvents ¶
QueryRecentAuditEvents returns the most-recent audit events across ALL runs, newest first — the global SIEM-style feed the Audit view renders, unlike the chronological per-run QueryAuditEvents.
func (PG) QueryRecentAuditEventsPage ¶ added in v0.3.1
QueryRecentAuditEventsPage returns the newest-first global audit feed, bounded by p. seq is the audit_events PRIMARY KEY, so ORDER BY seq DESC + LIMIT is an index-scan-backward with no added index.
func (PG) ReadRunOutputChunks ¶ added in v0.8.6
func (s PG) ReadRunOutputChunks(ctx context.Context, runID uuid.UUID, limit int) (RunOutputChunks, error)
ReadRunOutputChunks — see RunOutputChunkStore.
func (PG) ReclampRunLimits ¶ added in v0.8.0
func (s PG) ReclampRunLimits(ctx context.Context, from types.AgentRun, toLimits types.RunLimits, toEnd *time.Time, toWait int, endTightenedAt *time.Time) (bool, error)
ReclampRunLimits — see RunLimitsReclamper. The compare on the limits read is what keeps a PATCH decided against the old gate from landing after it, and this write from landing over a PATCH's.
func (PG) RecordPushPathList ¶ added in v0.8.0
func (PG) RefreshAPITokenIdentity ¶ added in v0.8.0
func (s PG) RefreshAPITokenIdentity(ctx context.Context, principal, role, userType string, groups []string, truncated bool) error
RefreshAPITokenIdentity re-stamps role, user type, and the group snapshot (with its completeness bit) on EVERY token principal holds — the api-token twin of RefreshSSHKeyRoles; OnLogin fires both so one login bounds both frozen credentials.
SECURITY: a token's identity is frozen at mint with nothing else to refresh it — without this, demoting an admin leaves their wdn_ tokens authenticating AS AN ADMIN until explicitly revoked, and a token keeps authorizing against stale group memberships until a fresh mint.
truncated is bound EXACTLY as passed, never defaulted or inferred: it must come from the login's own session-completeness signal, the same bit a fresh mint stamps. A NULL groups_truncated already reads as TRUNCATED downstream (fail closed); silently defaulting this to false would assert "these are all their groups" for a snapshot that isn't — the wrong direction for an authorization decision.
identity_stamped_at moves with the role in the SAME statement, so a login that stamps a token's role stamps its age too, and a failed statement leaves that principal's tokens stale rather than half-updated. WARDYN_ROLE_STAMP_TTL reads it; `revoked_at IS NULL` stays in the WHERE, so a login never revives a revoked token (an expired one keeps its own expiry, which this never writes).
Still bounded-stale, not live: the ceiling is the owner's next login (see docs/SSH.md §Bounds for the key lane's equivalent). No error when the principal holds no tokens — a zero-row UPDATE is the ordinary case.
SECURITY: a token an admin minted FOR this principal (minted_by set) is revoked instead of re-stamped when the login's role differs from its stamp — its role was derived before the person's own groups were known and the minter saw its plaintext, so re-stamping upward would hand the minter's tier to whoever holds that credential. SET reads the row's OLD role, so the comparison is against the stamp.
func (PG) RefreshRunOutputClaim ¶ added in v0.8.6
RefreshRunOutputClaim — see RunOutputStore.
func (PG) RefreshSSHKeyRoles ¶ added in v0.6.0
func (s PG) RefreshSSHKeyRoles(ctx context.Context, principal, role string, checkedAt time.Time) error
RefreshSSHKeyRoles re-stamps role and role_checked_at for every key owned by principal, from the OIDC OnLogin hook, with that login's freshly-derived role. This bounds the admin-override stamp to at most WARDYN_SSH_ROLE_TTL stale: it overwrites role too, not only the timestamp, so a demoted or promoted human's keys take effect on their very next login, with no delete-then-re-register needed. No registered keys is a normal, silent no-op.
A CAPPED key (registered in the user view) keeps its user role — the login refreshes only its timestamp, never promotes it.
func (PG) ReleaseAttachLease ¶ added in v0.8.6
ReleaseAttachLease — see AttachLeaseStore.
func (PG) RenameScimGroup ¶ added in v0.8.6
RenameScimGroup changes a group's display name; its externalId never changes.
func (PG) RenewAttachLease ¶ added in v0.8.6
func (s PG) RenewAttachLease(ctx context.Context, runID, holderID uuid.UUID, ttl time.Duration) (bool, error)
RenewAttachLease — see AttachLeaseStore.
func (PG) ReopenDeprovisionJob ¶ added in v0.8.6
func (s PG) ReopenDeprovisionJob(ctx context.Context, identityID uuid.UUID, kind string, k JobKey) error
ReopenDeprovisionJob makes a finished step pending again: a run the ledger counted done that is found live once more.
func (PG) ReserveAttachLease ¶ added in v0.8.6
func (s PG) ReserveAttachLease(ctx context.Context, runID, from uuid.UUID, taker, replica string, ttl time.Duration) (AttachLease, uuid.UUID, bool, error)
ReserveAttachLease — see AttachLeaseStore.
func (PG) ResetFederation ¶ added in v0.8.0
ResetFederation is a (re-)enrolment: a new device identity starts an empty chain at the organisation, resetting the cursor to 0 and clearing the revoked mark. The only writer that clears it.
func (PG) ResolveGovernanceProfile ¶ added in v0.7.0
func (s PG) ResolveGovernanceProfile(ctx context.Context, userSubjects, groups []string, userType string) (*types.GovernanceProfile, types.CapabilitySubjectType, error)
ResolveGovernanceProfile returns THE ONE profile that applies to a caller, or ErrNotFound when no assignment matches (which the caller reads as "fall through to the deployment ceiling", the absent-row back-compat rule).
The whole precedence rule is the ORDER BY, deliberately: one indexed read on the UNIQUE(subject_type, subject) btree, so there's no second implementation in Go to skip, mis-order, or forget. subjectMatch and subjectPrecedence are the same fragments ResolveUserDrive splices, so the ceiling and the drive can't disagree about "most specific".
SECURITY: users/groups are normalized from nil to empty for the same reason ListCapabilityGrantsFor does: a nil Go slice binds as SQL NULL and `x = ANY(NULL)` is NULL, not false. Fails closed either way, but a predicate whose behavior hinges on a driver detail has no place at an authorization boundary.
userType is the caller's one type id; "" matches no row.
func (PG) ResolveReauthApproval ¶ added in v0.7.6
func (s PG) ResolveReauthApproval(ctx context.Context, id uuid.UUID, decision types.ApprovalDecision, ev types.AuditEvent) (types.ApprovalRequest, error)
ResolveReauthApproval moves a credential_reauth approval to APPROVED and writes its credential.reauth.resolve audit row in ONE transaction: the state change unblocks a HELD credential request, and the audit row is the only durable record that a human acted behind it. Committed separately, a crash between them would leave a run resuming with nothing in the trail saying who resolved it (invariant I7). If either write fails the approval stays PENDING and the idempotent reconcile-on-read tries again.
It is NOT part of the Store interface (see iface.go on transactional surfaces): internal/api type-asserts for it.
The CAS is DecideApproval's own: WHERE state='PENDING', so a concurrent resolver loses cleanly with ErrAlreadyDecided and writes no second audit row.
func (PG) ResolveUserDrive ¶ added in v0.7.0
func (s PG) ResolveUserDrive(ctx context.Context, userSubjects, groups []string, userType string) ( *types.UserDrive, *types.UserDriveGrant, types.CapabilitySubjectType, error)
ResolveUserDrive returns THE ONE drive that applies to a caller, the winning grant, and its tier — or ErrNotFound. The whole precedence rule lives in the ORDER BY (subjectMatch/subjectPrecedence, shared with ResolveGovernanceProfile since both rank the same subject vocabulary): one indexed read on UNIQUE(subject_type, subject), so there's no second Go implementation to mis-order.
Disabled grants stay in the query; the winner's own `enabled` decides PAUSED vs MOUNTED. Excluding them in the WHERE would let a paused row fall through to a wider `all`-tier drive no admin chose for this member — silently, since the only visible signal would be a mount appearing rather than one stopping (DESIGN §2.2).
userSubjects/groups are normalized from nil to empty: a nil Go slice binds as SQL NULL, and `x = ANY(NULL)` is NULL rather than false — same reasoning as ResolveGovernanceProfile.
userType is the caller's one type id; "" matches no row.
func (PG) ResumeGroupRemoval ¶ added in v0.8.6
ResumeGroupRemoval says whether the sweeper may go on with a removal it selected earlier: true only when the pair's ledger still has a pending step and the person is not recorded a member again. It never opens a removal or deletes a membership, so a candidate the identity provider added back since it was selected is dropped, not removed again. The identity row is locked FOR UPDATE first, in a statement of its own: a membership insert's foreign-key check holds that row, so the lock waits for an add in flight to commit or roll back. The membership is then read by a second statement, whose snapshot is taken after the lock and so sees that add; an add that starts later waits for this transaction, and is ordered after the answer.
func (PG) RevokeAPIToken ¶ added in v0.6.0
func (s PG) RevokeAPIToken(ctx context.Context, id uuid.UUID, principal string, now time.Time) (types.APIToken, error)
RevokeAPIToken marks id revoked. principal scopes the UPDATE when non-empty (self-service: a human may only revoke their OWN token). SECURITY: someone else's id is ErrNotFound, not a distinguishable 403 — no existence leak across principals. An EMPTY principal is the ADMIN path and revokes anyone's.
Already-revoked is ErrNotFound too (`revoked_at IS NULL` in the WHERE): revoke is idempotent, so a second call must not emit a second token.revoke audit row for an act that didn't happen.
func (PG) RevokeDelegate ¶ added in v0.8.0
func (s PG) RevokeDelegate(ctx context.Context, id uuid.UUID, now time.Time) (types.Delegate, error)
RevokeDelegate marks id revoked. Unknown or already-revoked is ErrNotFound, so a second revoke writes no second audit row. Outstanding delegated tokens need no write of their own: GetDelegatedTokenByRaw joins on this column.
func (PG) RevokeDevice ¶ added in v0.8.0
RevokeDevice marks id revoked. Already-revoked is ErrNotFound too (`revoked_at IS NULL` in the WHERE): idempotent, so a second call emits no second revoke audit row.
func (PG) RevokeEnrolmentToken ¶ added in v0.8.0
func (s PG) RevokeEnrolmentToken(ctx context.Context, id uuid.UUID, now time.Time) (types.DeviceEnrolmentToken, error)
RevokeEnrolmentToken cancels a redeemable token by setting consumed_at (the column ConsumeEnrolmentToken's WHERE requires NULL), so a revoke can't race a redemption. Already-redeemed/revoked/expired/unknown is ErrNotFound.
func (PG) RunCapacity ¶ added in v0.8.6
func (s PG) RunCapacity(ctx context.Context, o RunCapacityOpts) (RunCapacity, error)
RunCapacity reads every non-terminal row in one query (the positive types.NonTerminalRunStates list, never NOT IN terminal, so a new terminal state cannot be counted as active) and folds it per the state table in the 0.8.6 fleet design: STARTING, RUNNING and WAITING_FOR_CONFIRMATION rows with lost_at NULL hold capacity, paused ones included; kept rows (lost_at set) count as Kept; PENDING rows appear only in States. A kept row whose agent still runs (HoldsSandboxSQL: kept after an outage, before its end) also holds its agent's reservation, without the proxy that was stopped.
func (PG) RunHasOpenRequest ¶ added in v0.8.0
RunHasOpenRequest — see RunPauser.
func (PG) RunIDsCreatedBy ¶ added in v0.8.6
func (PG) RunWatcherFresh ¶ added in v0.5.0
func (s PG) RunWatcherFresh(ctx context.Context, id uuid.UUID, staleAfter time.Duration) (bool, error)
RunWatcherFresh reports whether id's watcher lease is younger than staleAfter — mirrors ClaimStaleRunWatchers' own staleness predicate (a live watcher owns it). A missing row → (false, nil): nothing is watching it, so the reaper may proceed.
func (PG) SaveChunkedRunOutput ¶ added in v0.8.6
func (s PG) SaveChunkedRunOutput(ctx context.Context, runID uuid.UUID, maskScope string, limit int) (bool, error)
SaveChunkedRunOutput — see RunOutputChunkStore.
func (PG) SaveFinalRunOutput ¶ added in v0.8.6
SaveFinalRunOutput — see RunOutputStore.
func (PG) SaveGapRunOutput ¶ added in v0.8.6
SaveGapRunOutput — see RunOutputStore.
func (PG) ScimGroupMembers ¶ added in v0.8.6
ScimGroupMembers is the identity ids recorded as members of the group, oldest first.
func (PG) SearchIdentities ¶ added in v0.8.6
func (s PG) SearchIdentities(ctx context.Context, issuer, attr, value string, limit int) ([]PrincipalIdentity, error)
SearchIdentities is the identity rows a SCIM filter `attr eq value` selects under issuer, at most limit. externalId matches the SCIM projection or the bound object id; userName and emails.value match the projection, the login email and every alias the identity has been seen under.
func (PG) SearchScimGroups ¶ added in v0.8.6
func (s PG) SearchScimGroups(ctx context.Context, attr, value string, limit int) ([]ScimGroup, error)
SearchScimGroups is the groups a SCIM filter `attr eq value` selects, at most limit. Both attributes match case-insensitively.
func (PG) SetAuditRetentionPolicy ¶ added in v0.8.6
func (PG) SetBrandingLogo ¶ added in v0.8.4
func (s PG) SetBrandingLogo(ctx context.Context, logo []byte, logoType string, fromFile bool, updatedBy string) (bool, error)
SetBrandingLogo implements BrandingStore.
func (PG) SetCapabilityRestriction ¶ added in v0.8.0
func (s PG) SetCapabilityRestriction(ctx context.Context, capability, value string, restricted bool, by string) error
SetCapabilityRestriction restricts one value (inserts its row, keeping the first writer's provenance) or lifts the restriction (deletes it).
func (PG) SetFederationCursor ¶ added in v0.8.0
SetFederationCursor durably advances the forwarder's cursor (seq and the local row's row_hash, so a later tick can tell it from a table-reset row at the same seq), upserting the singleton row. Called after a batch is accepted upstream, so a crash between accept and this write only costs an idempotent retry (see IngestDeviceAudit), never a gap.
func (PG) SetRunAgentExecID ¶ added in v0.3.1
SetRunAgentExecID scoped-writes ONLY agent_exec_id, once the driver execs the agent. The crash reconciler reads it to observe agent liveness across a restart.
func (PG) SetRunContainmentError ¶ added in v0.8.0
func (s PG) SetRunContainmentError(ctx context.Context, id uuid.UUID, msg string, now time.Time) error
SetRunContainmentError — see RunLeaser.
func (PG) SetRunDiskMiB ¶ added in v0.8.0
SetRunDiskMiB scoped-writes ONLY the resolved ephemeral-disk-cap column. Called once applyEphemeralDisk resolves the effective disk_mib, since that needs dispatch-time inputs unavailable at CreateRun.
func (PG) SetRunEndAndWait ¶ added in v0.8.0
func (s PG) SetRunEndAndWait(ctx context.Context, id uuid.UUID, fromLimits types.RunLimits, fromEnd *time.Time, fromWait int, toEnd *time.Time, toWait int, ended *EndedKept) (bool, error)
SetRunEndAndWait — see RunLeaser. The compare on the values the caller read is what makes the caller's clamp and gate decision the one that lands: a concurrent change, the lease sweep ending the run, or a re-clamp tightening the limits the gate was read from turns this into a no-op.
func (PG) SetRunFailureHint ¶ added in v0.6.0
SetRunFailureHint scoped-writes ONLY failure_hint — the one-line operator reason a run FAILED before its agent started, known only at the failure site (failAndRevoke). Best-effort at the call site; ErrNotFound when no row matched.
func (PG) SetRunImage ¶ added in v0.2.0
SetRunImage scoped-writes ONLY the resolved-image provenance column, once the image resolves after the row is inserted.
func (PG) SetRunProxyRelease ¶ added in v0.8.0
SetRunProxyRelease — see RunReviver.
func (PG) SetRunSizing ¶ added in v0.8.6
SetRunSizing scoped-writes ONLY the dispatch-time sizing columns. It does not bump updated_at: the record is not activity, and the idle clock reads updated_at.
func (PG) SetRunStatusDetail ¶ added in v0.7.6
SetRunStatusDetail scoped-writes ONLY status_detail — what the substrate says a STARTING run is waiting on, or the control plane's own `image: Building` line on a PENDING run. Fed by runner.SandboxSpec.OnWaiting, once per CHANGE of reason. Deliberately does NOT bump updated_at: that column is also what the idle reaper and the killed-run tail-upload grace measure by, and a diagnostic line a kubelet triggers must never buy a run more life or hold a terminal run's upload door open.
func (PG) SetRunTitle ¶ added in v0.8.0
SetRunTitle — see RunTitler.
func (PG) SetSandboxRef ¶
SetSandboxRef records the runner reference (container ID / pod name). A non-empty ref also records this release as the one that started the run's proxy (proxy_release, migration 0084).
func (PG) SetSourceScanResult ¶ added in v0.5.0
func (s PG) SetSourceScanResult(ctx context.Context, id uuid.UUID, profile []byte, status types.WorkspaceStatus, runID uuid.UUID, seed map[string]types.WorkspaceRequirement) (types.Source, error)
SetSourceScanResult persists a scan outcome FENCED on the claiming run: only the run holding active_run_id may write, so a stale upload from a superseded run can never clobber a fresher result. `seed` rebuilds the scan_seeded subset of requirements (provenance-aware, see sourceScanRebuild); NULL (failed scan) leaves the contract untouched, while a non-nil empty seed still rebuilds — see sourceRequirementsParam.
func (PG) SetSourceScanResultUnfenced ¶ added in v0.5.0
func (s PG) SetSourceScanResultUnfenced(ctx context.Context, id uuid.UUID, profile []byte, status types.WorkspaceStatus, seed map[string]types.WorkspaceRequirement) (types.Source, error)
SetSourceScanResultUnfenced persists a SYNCHRONOUS (inline local_dir) scan, which never claimed a run slot to fence against. Same provenance-aware rebuild semantics as the fenced writer (sourceScanRebuild).
func (PG) SetWorkspaceApprovedEgress ¶
func (s PG) SetWorkspaceApprovedEgress(ctx context.Context, id uuid.UUID, domains []string) (types.Workspace, error)
SetWorkspaceApprovedEgress replaces ONLY the approved-egress column (plus updated_at and egress_edited_at), scoped so it can never clobber a concurrently-persisted async scan. egress_edited_at always bumps, even for an identical list, since ReconcileWorkspaceEgressDecisions treats it as "the operator confirmed this at this moment".
func (PG) SetWorkspaceBuiltImage ¶
func (s PG) SetWorkspaceBuiltImage(ctx context.Context, id uuid.UUID, imageRef, builtHash string) (types.Workspace, error)
SetWorkspaceBuiltImage scoped-writes ONLY the image cache columns (build-once/reuse-many), same anti-clobber discipline as the other scoped writers.
func (PG) SetWorkspaceDeniedEgress ¶ added in v0.5.0
func (s PG) SetWorkspaceDeniedEgress(ctx context.Context, id uuid.UUID, domains []string) (types.Workspace, error)
SetWorkspaceDeniedEgress is denied_egress's mirror of SetWorkspaceApprovedEgress: same anti-clobber scoping, same full-list replace, same egress_edited_at stamp (removing a permanent DENY is an operator override the boot heal must not undo).
func (PG) SetWorkspaceImportState ¶
func (s PG) SetWorkspaceImportState(ctx context.Context, id uuid.UUID, status types.WorkspaceStatus, activeRunID *uuid.UUID, expectedActive *uuid.UUID) (types.Workspace, bool, error)
SetWorkspaceImportState is the scoped writer the scan orchestrator uses to advance status + the in-flight run pointer. Fenced on expectedActive (the active_run_id observed in the read the decision came from; nil means "no in-flight run"), so a caller deciding from a STALE read cannot land it. applied=false means the slot moved under the caller, which must re-read rather than retry blindly.
func (PG) SetWorkspaceLLMCred ¶ added in v0.4.0
func (s PG) SetWorkspaceLLMCred(ctx context.Context, id uuid.UUID, cred *types.WorkspaceLLMCred) (types.Workspace, error)
SetWorkspaceLLMCred replaces ONLY the model/harness cred binding column (plus updated_at), scoped so it can never clobber a concurrently-persisted async scan. Pass nil to clear the binding.
func (PG) SetWorkspaceOwner ¶ added in v0.6.0
func (s PG) SetWorkspaceOwner(ctx context.Context, id uuid.UUID, owner string) (types.Workspace, error)
SetWorkspaceOwner replaces ONLY the owned_by column (plus updated_at) — the offboarding reassign (decision O6). Deliberately the ONLY writer of the column after CreateWorkspace: UpdateWorkspace omits owned_by, so an ordinary edit can never move ownership.
func (PG) SetWorkspaceRecordResult ¶
func (s PG) SetWorkspaceRecordResult(ctx context.Context, id uuid.UUID, taskKey string, result json.RawMessage, onlyIfStatus string) (types.Workspace, bool, error)
SetWorkspaceRecordResult atomically upserts ONE task's entry in the Record Mode record_results map (jsonb merge, so concurrent writers of DIFFERENT tasks never lose each other's entries). When onlyIfStatus is non-empty the write is a compare-and-set against the task's stored status. Returns applied=false (no error) on a guard miss.
func (PG) SetWorkspaceRequirements ¶ added in v0.5.0
func (s PG) SetWorkspaceRequirements(ctx context.Context, id uuid.UUID, reqs map[string]types.WorkspaceRequirement) (types.Workspace, error)
SetWorkspaceRequirements replaces ONLY the requirements-contract column (plus updated_at), scoped like SetWorkspaceApprovedEgress. Pass the FULL desired map — this replaces rather than merges.
func (PG) SpendApprovalOnce ¶ added in v0.7.10
SpendApprovalOnce spends a `once` Azure DevOps capability approval: it writes jti into the row's minted_jti if, and only if, nothing has spent it yet. spent=false means another request already did (or the row is not an approved, once-scoped escalation) and the caller must not forward. The empty-minted_jti condition is the whole exactly-once argument: two concurrent re-resolves both reach this UPDATE, Postgres serialises them on the row, and the second finds the column already written.
Not part of the Store interface (see ResolveReauthApproval): the api package type-asserts for it.
func (PG) StampRunActive ¶ added in v0.8.0
StampRunActive — see RunPauser.
func (PG) StampRunTokenRenewed ¶ added in v0.8.0
StampRunTokenRenewed — see RunLoser.
func (PG) StartGroupRemoval ¶ added in v0.8.6
StartGroupRemoval opens the ledger of one person leaving one group, in one transaction with the removal of the membership row. The three steps join as pending when the person was recorded a member (a new removal, so an earlier finished one is cleared) or when no removal of this pair was ever recorded (a member whose add never reached Wardyn is still removed). A pair whose last removal finished and who has not been added since is a repeat and changes nothing, so an identity provider that repeats the request costs nothing, and a removal still pending is resumed.
func (PG) StopKeptRunIf ¶ added in v0.8.0
func (s PG) StopKeptRunIf(ctx context.Context, id uuid.UUID, to types.RunState, lostAt *time.Time, lostReason types.LostReason, endsAt *time.Time) (bool, error)
StopKeptRunIf — see RunLeaser.
func (PG) SubjectKeyDestroyedSince ¶ added in v0.8.6
func (PG) SuspendIdentity ¶ added in v0.8.6
func (s PG) SuspendIdentity(ctx context.Context, p SuspendPlan) (SuspendResult, error)
SuspendIdentity is step 1 of a suspension, one transaction. It takes every row it will change FOR UPDATE, in id order (so a sign-in holding one of them finishes first or is refused), writes the session cutoff for every sub and email form, deactivates the identity rows and bumps their authority epoch, stamps the people rows, records the step done and the plan's pending steps. A suspension of an active identity first clears the ledger of any earlier one.
func (PG) TouchAPIToken ¶ added in v0.6.0
TouchAPIToken records that id was just used. BEST EFFORT: the auth branch ignores the error, since failing to record a touch must never fail an otherwise-valid request.
ponytail: one UPDATE per authenticated request; add a throttle only if a hot token ever makes that write volume a problem.
func (PG) TouchDevice ¶ added in v0.8.0
TouchDevice records that id was just used. Best effort, like TouchAPIToken: the request path must never fail an otherwise-valid request over a lost keepalive write.
func (PG) TouchRun ¶
TouchRun bumps a run's updated_at to now() without changing any other field — the activity keepalive interactive-attach calls so the idle reaper doesn't stop a run a human is attached to. The TERMINAL-run guard lives HERE, in one WHERE clause, rather than at each of the four callers: updated_at is also the clock the killed-run tail-upload grace is measured from, so an authenticated caller touching a killed run's row on a cadence could hold that upload door open indefinitely. State predicate is the positive list, for the reason given on CountActiveRunsBy.
func (PG) UpdateBaseImageName ¶ added in v0.5.0
func (s PG) UpdateBaseImageName(ctx context.Context, id uuid.UUID, name string) (types.BaseImageEntry, error)
UpdateBaseImageName renames a catalog base-image row — the explicit, scoped rename path, mirroring UpdateSourceConfig above. handleCreateBaseImage is the only caller, on an identity hit where the REQUEST carried an explicit name (never via UpsertBaseImage's own conflict clause — see its doc).
func (PG) UpdatePolicy ¶
func (s PG) UpdatePolicy(ctx context.Context, id uuid.UUID, name string, spec types.RunPolicySpec) (types.RunPolicy, error)
UpdatePolicy replaces a policy's name and spec and bumps updated_at. Returns ErrNotFound when no policy has the given id, and ErrConflict when the rename collides with run_policies.name's UNIQUE constraint — same mapping as CreatePolicy, since a rename onto a taken name is the same caller-fixable mistake as an insert under one. The caller validates the spec before calling.
func (PG) UpdateRunStateIf ¶
func (s PG) UpdateRunStateIf(ctx context.Context, id uuid.UUID, fromState, toState types.RunState) (bool, error)
UpdateRunStateIf conditionally transitions a run from fromState to toState in a single UPDATE ... WHERE id=$ AND state=$from, returning whether it applied. TOCTOU-safe: a concurrent kill/stop that already moved the run to a terminal state is never clobbered. False with a nil error means someone else won the transition (or the run doesn't exist); the caller does nothing.
func (PG) UpdateRunStateIfCreatedBefore ¶ added in v0.8.6
func (s PG) UpdateRunStateIfCreatedBefore(ctx context.Context, id uuid.UUID, fromState, toState types.RunState, createdNotAfter time.Time) (bool, error)
UpdateRunStateIfCreatedBefore transitions a run only when still in fromState, created_at is at or before createdNotAfter, and its agent still runs (HoldsSandboxSQL: not kept, or kept after an outage before its end; a run kept with its agent stopped is left to its files grace). The max-age stop's own predicate on the run's age: it carries neither the idleness guard nor the open-request guard of UpdateRunStateIfIdle, because an absolute age cap exists to end a run that is not going to finish by itself.
func (PG) UpdateRunStateIfIdle ¶
func (s PG) UpdateRunStateIfIdle(ctx context.Context, id uuid.UUID, fromState, toState types.RunState, notAfter time.Time) (bool, error)
UpdateRunStateIfIdle is UpdateRunStateIf plus an idleness guard: it transitions a run only when still in fromState, updated_at has not advanced past notAfter (the caller's snapshot), it has no lost/end mark, and it has no open hold-aware request within its wait. Closes the reaper's idleness TOCTOU — an active `wardyn run attach` TouchRun can bump updated_at between snapshot and UPDATE, so guarding on state alone could stop a now-active run; notAfter makes a touched-since-snapshot run no-op instead. The hold-aware clause enforces "idle stop never fires while a request is open within its wait" inside the same atomic CAS, since a request raised in that window is visible only to a check inside the statement.
func (PG) UpdateSourceConfig ¶ added in v0.5.0
func (s PG) UpdateSourceConfig(ctx context.Context, id uuid.UUID, name string, reqs map[string]types.WorkspaceRequirement) (types.Source, error)
UpdateSourceConfig replaces a source's operator-editable fields (name, requirements) — scoped, never touching scan-owned columns.
func (PG) UpdateUserType ¶ added in v0.8.0
UpdateUserType rewrites a type's name, description and priority; id and built_in never change. ErrNotFound when missing, ErrConflict on name clash.
func (PG) UpdateUserTypeMetadata ¶ added in v0.8.6
UpdateUserTypeMetadata rewrites a type's name and description and never its priority, so an edit that was judged metadata-only cannot overwrite a priority change approved after it was read. ErrNotFound when missing, ErrConflict on name clash.
func (PG) UpdateWorkspace ¶
func (s PG) UpdateWorkspace(ctx context.Context, id uuid.UUID, ws types.Workspace, stampEgressEdit bool) (types.Workspace, error)
UpdateWorkspace replaces a workspace's editable composition via a FULL-column write of every scan-owned field (profile, image_ref, built_profile_hash, status, etc.), WITH ONE DELIBERATE EXCEPTION: denied_egress is NOT in this SET clause (see Workspace.DeniedEgress) — a permanent deny survives a composition edit, unlike ApprovedEgress. Callers must round-trip the fetched row. Returns ErrNotFound for an unknown id.
egress_edited_at is passed through unless stampEgressEdit marks this write as the operator action the column records: unconditional stamping would suppress the boot heal for a decision nobody undid, while plain omission let this writer clear approved_egress without moving the stamp, so ReconcileWorkspaceEgressDecisions re-widened the list on restart. The stamp is now() from the database, not wardynd's clock, since it's compared against approvals.decided_at and clock skew there fails OPEN.
func (PG) UpsertBaseImage ¶ added in v0.5.0
func (s PG) UpsertBaseImage(ctx context.Context, b types.BaseImageEntry) (types.BaseImageEntry, error)
UpsertBaseImage inserts a catalog image or returns the row with the same identity (kind, image, steps) — the identity index is the dedupe rule. The CHECK constraint refuses 'recommended' structurally: that build is derived per-workspace and has no catalog identity.
An identity hit does NOT touch name, deliberately: this upsert is also the PASSTHROUGH path a workspace/run resolves its base-image spec through, which always derives an auto-placeholder name — applying EXCLUDED.name unconditionally would silently rename an operator's custom-named row back to that placeholder. See UpdateBaseImageName for the rename path.
func (PG) UpsertCapabilityGrant ¶ added in v0.6.0
func (s PG) UpsertCapabilityGrant(ctx context.Context, g types.CapabilityGrant) (types.CapabilityGrant, error)
UpsertCapabilityGrant writes one grant, keyed on the natural (subject_type, subject, capability, value) UNIQUE: re-granting the same triple FLIPS the effect in place rather than leaving two contradictory rows (which would resolve as a permanent deny). The returned row carries the EXISTING id on a conflict, not g.ID, so a re-submit gets the id the DELETE route needs.
func (PG) UpsertGovernanceAssignment ¶ added in v0.7.0
func (s PG) UpsertGovernanceAssignment(ctx context.Context, a types.GovernanceAssignment) (types.GovernanceAssignment, error)
UpsertGovernanceAssignment binds one subject to one profile, keyed on the natural UNIQUE (subject_type, subject): re-assigning a subject REPOINTS its single row rather than leaving a second one behind (two rows for one subject would make "which profile does Bob get" a tie-break instead of the admin's last write).
The returned row carries the EXISTING id on conflict, not a.ID, so the caller gets the id the DELETE route needs.
Returns ErrNotFound when profile_id names no profile (FK 23503 → 404).
func (PG) UpsertGovernanceProfile ¶ added in v0.7.0
func (s PG) UpsertGovernanceProfile(ctx context.Context, p types.GovernanceProfile) (types.GovernanceProfile, error)
UpsertGovernanceProfile writes one profile exactly as given. It is WriteGovernanceProfile with nothing to decide, so it takes the same graph lock and a write can never skip it.
func (PG) UpsertLoginIdentity ¶ added in v0.8.6
func (s PG) UpsertLoginIdentity(ctx context.Context, in LoginIdentity, now time.Time) (PrincipalIdentity, error)
func (PG) UpsertRoleMapping ¶ added in v0.7.0
func (s PG) UpsertRoleMapping(ctx context.Context, m types.RoleMapping) (types.RoleMapping, error)
UpsertRoleMapping writes one row, keyed on the natural UNIQUE (value): re-adding an already-mapped value FLIPS its role in place rather than leaving a second row behind — the same "re-granting the same key updates it" contract UpsertCapabilityGrant follows, for the same reason (two rows for one value cannot happen; the UNIQUE index already forbids it, this just makes the natural retry path a clean update instead of a 409).
The returned row carries the row's real id, which on a conflict is the EXISTING one, not m.ID — the caller needs the id the DELETE route will be given, and an admin re-submitting the same value must not be handed an id that names no row.
A user_type naming no user_types row fails the foreign key; that is ErrNotFound, so the caller can tell a type deleted between its check and this write from a store fault.
The conflict path updates role and user_type only, deliberately NOT created_by — creation provenance (who ADDED this mapping) stays with the original creator across a later role flip by a different admin, the same way created_at is untouched on conflict (no SET at all, so Postgres leaves it).
The conflict path also forces migrated_from_member to false, UNCONDITIONALLY — on a flip to admin/security_admin too, not only a real type pick (never EXCLUDED.migrated_from_member, which the caller never sets to true anyway — see the type's own doc comment). Decision, not an oversight: the marker means "a person still needs to look at this row", and an admin choosing ANYTHING for it — a type or a tier — is that look. The alternative (clear only on a type pick) would let the marker survive a flip to admin and ride along if the row is later flipped BACK to user with no type named — a "migrated" chip on a row an admin, in the interim, explicitly decided was an admin mapping, which is a worse answer than "the row was touched, the flag's job is done" for a marker the design itself frames as a one-time prompt, never a permanent history bit. TestPG_RoleMappings_UpsertClearsMigratedFromMemberOnAdminFlip pins this call.
func (PG) UpsertSource ¶ added in v0.5.0
UpsertSource inserts a library source or returns the existing row with the same identity (kind, locator, ref) — ONE statement, no read-then-write race: the UNIQUE constraint IS the dedupe rule. Identity fields must arrive CANONICALIZED (the api layer owns that) — the store stores what it is given.
func (PG) UpsertUserDrive ¶ added in v0.7.0
func (s PG) UpsertUserDrive(ctx context.Context, d types.UserDrive, refuseIfAllocated bool) (types.UserDrive, error)
UpsertUserDrive writes one drive keyed on ID: INSERT if absent, else UPDATE in place — renaming is allowed while grants still point at it, since ON DELETE RESTRICT rules out delete-and-recreate for an allocated drive. A rename moves the PVC's name; existing members bind an object that no longer exists until they re-mount (docs/OPERATIONS.md "User drives on Kubernetes"). Returns ErrConflict on UNIQUE(name).
An identity-affecting PUT on an already-allocated drive is refused 409 (ErrDriveAllocated) unless ?confirm=rehome; the precondition is re-asserted in this statement, under the row lock UpsertUserDrive takes, so a grant created between the guard's read and this write can't be silently re-homed.
SECURITY: two host_path shares over the same root must derive home names the same way (namespace is the host_root, not the drive — see shareBackend). Different home_templates (`sub` vs `email_local`) could otherwise fold two principals onto one directory name, breaking migration 0059's one-home-per-principal invariant on a backend its index can't reach; same-template drives on one root stay legal. Enforced in the statement itself, not a prior read — not a hard constraint under READ COMMITTED, but the case that actually happens (one admin registering a second view) can't race itself.
created_by/created_at are untouched on update: provenance stays with whoever registered the drive.
func (PG) UpsertUserDriveGrant ¶ added in v0.7.0
func (s PG) UpsertUserDriveGrant(ctx context.Context, g types.UserDriveGrant, homeOverrideStated bool) (types.UserDriveGrant, error)
UpsertUserDriveGrant allocates one drive to one subject, keyed on UNIQUE(subject_type, subject): re-allocating REPOINTS the existing row rather than leaving a second one, so a subject's allocation is always the admin's last write. On conflict the returned id is the EXISTING row's, not g.ID. Returns ErrNotFound when drive_id names no drive (FK, 23503).
SECURITY: refuses (ErrConflict) if another subject already holds the same home_override in the same object-name NAMESPACE (host_root, not drive — see shareBackend) — one home_override must name one person's directory, or two people end up sharing a minted volume with every bind-time check passing. Guard checks same-drive OR two host_path drives on the same host_root (compared as the stored string; driveHostRootNesting handles the symlink case on the drive-write path). Enforced in the statement itself, one round trip: migration 0059's partial unique index is the race-free floor for the same-drive case; the cross-drive case has none, so here the statement is the whole guard — sufficient for the case that happens, one admin typing one name twice. Residual: a DERIVED (non-override) home can still collide across same-root shares with different templates; not refusable here since a group/all grant doesn't know its principals until sign-in.
enabled is written verbatim, so a zero-value grant is disabled by default — fail-closed at the API boundary, where the omission is still visible.
SECURITY: also guards a silent re-home. Clearing home_override moves that person to the derived name next run, stranding their old directory unnamed. homeOverrideStated is the API's tri-state for "the client said nothing": false refuses the update on a row with a stated override (no row returned, read as ErrConflict); stating it IS the confirmation, no ?confirm= to invent. The zero value is safe — a caller that forgets the argument gets a refusal, not a silent clear.
func (PG) UserTypeReferences ¶ added in v0.8.0
UserTypeReferences counts the capability-grant, governance-assignment and drive-grant rows that name the type as their subject.
func (PG) UserTypeTokenStamps ¶ added in v0.8.0
UserTypeTokenStamps counts the unrevoked API tokens stamped with the type.
func (PG) VerifyAuditChain ¶ added in v0.6.0
func (s PG) VerifyAuditChain(ctx context.Context) (AuditChainStatus, error)
VerifyAuditChain walks the audit_events hash chain oldest-first, re-hashing every row with migration 0047's audit_row_hash — the SAME function the insert trigger uses, so there's no second implementation to drift.
The sweep is paged as a correctness property, not just a cost one: an unbounded `ORDER BY seq` can plan as Seq Scan -> Sort, buffering the whole table before returning row one — the tamper-investigation endpoint would get slowest over time. Keyset paging (`seq > $1 ORDER BY seq LIMIT n`) is an index scan with a bound instead, so memory is one page and an early break genuinely stops the work.
Paging does not verify less: since migration 0056 the trigger allocates seq while holding the chain lock and releases it at commit, so seq order IS commit order, and a row can never appear below a cursor the walk already passed. Walk state is carried across pages by one auditChainWalk, so a chain longer than a page is one continuous chain.
Everything runs in ONE repeatable-read snapshot, so the chain, the newest attested retention drop, the high-water mark and the partition manifest are the same instant: an append between two reads cannot read as a removed tail. The walk starts from the newest `drop` anchor that dropped rows (row_count above 0: an empty partition leaves nothing to chain to; the first retained row must chain to its recorded tail) and still inspects every retained row. The chain alone cannot see a removed NEWEST tail, so after it the newest row must also match audit_partition_meta's high-water mark, and every partition the expected manifest names must be present unless an anchor accounts for it.
func (PG) WithIdentityShared ¶ added in v0.8.6
WithIdentityShared runs fn while g's identity rows are held FOR SHARE and unchanged: the write a sign-in's captured credential makes lands before a suspension takes the rows, or is refused with ErrIdentityDeactivated. fn may write through another connection (the secret store).
The rows are held on a connection dialled for this call, outside the pool: fn borrows from the pool, and a hold taken from it would wait on itself once the pool is down to that one connection. The dials are bounded like the lock connections: at most db.LockPoolMaxConns at once per pool, process-wide, and a call that finds them all in use waits db.LockPoolAcquireWait and is then refused with db.ErrLockNoCapacity.
func (PG) WorkspacesAttaching ¶ added in v0.5.0
WorkspacesAttaching returns the names of workspaces whose attachments reference source id — the loud half of delete-in-use (one GIN probe on workspaces_attachments_gin). DELETE refuses with these names rather than silently orphaning a workspace to a source that no longer exists.
func (PG) WorkspacesUsingBaseImage ¶ added in v0.5.0
WorkspacesUsingBaseImage is the catalog's delete-in-use check.
func (PG) WriteGovernanceProfile ¶ added in v0.8.6
func (s PG) WriteGovernanceProfile(ctx context.Context, id uuid.UUID, build GovernanceProfileBuild) (types.GovernanceProfile, error)
WriteGovernanceProfile writes one profile keyed on its PRIMARY KEY: an unminted id INSERTs, an existing one UPDATEs in place (name included, so a profile can be renamed while assignments still point at it, since ON DELETE RESTRICT makes delete-and-recreate impossible for an assigned profile). One statement serves POST (fresh id) and PUT (id from the path).
The whole write is one transaction under a graph-wide advisory lock: build sees every profile as that transaction reads them, decides the row (merging what a PUT left absent, refusing a cycle, a depth overflow or an overlay its base does not permit) and the row is stored before the lock is released, so two concurrent writes cannot together make a cycle or a depth-4 chain.
contact follows GovernanceProfile.ContactSet: written (or cleared, when empty) only when it is true, otherwise the stored value stays. A composed row (Overlay set) binds '{}' for ceiling and limits and sets them outright, since it stores no raw authority; its composition columns are always written from the row as given.
Returns ErrConflict when UNIQUE(name) rejects the write. created_by and created_at are NOT touched on update: creation provenance stays with whoever authored the profile.
type Page ¶ added in v0.3.1
Page bounds a List query to Limit rows after Offset, ordered by the query's own ORDER BY. Limit<=0 means unbounded, used by internal callers needing the whole table; public read handlers always pass an explicit Limit (capped by api.parseListPage).
type Pager ¶ added in v0.3.1
type Pager interface {
ListRunsPage(ctx context.Context, p Page) ([]types.AgentRun, error)
ListPoliciesPage(ctx context.Context, p Page) ([]types.RunPolicy, error)
ListWorkspacesPage(ctx context.Context, p Page) ([]types.Workspace, error)
ListApprovalsPage(ctx context.Context, stateFilter types.ApprovalState, p Page) ([]types.ApprovalRequest, error)
QueryAuditEventsPage(ctx context.Context, runID uuid.UUID, p Page) ([]types.AuditEvent, error)
QueryRecentAuditEventsPage(ctx context.Context, p Page) ([]types.AuditEvent, error)
// QueryAuditEventsFilteredPage serves a narrowed audit read (time range,
// action, outcome, actor type); see AuditFilter in auditfilter.go.
QueryAuditEventsFilteredPage(ctx context.Context, runID *uuid.UUID, f AuditFilter, p Page) ([]types.AuditEvent, error)
// ListUserDriveGrantsPage serves the drives console's allocation table;
// its ORDER BY has no index, so unbounded it sorts every allocation on
// every load of the admin screen.
ListUserDriveGrantsPage(ctx context.Context, p Page) ([]types.UserDriveGrant, error)
}
Pager is the paginated read surface, deliberately excluded from Store: widening Store would silently route a test double's embedded-but-not- overridden methods to it. Handlers type-assert for Pager, falling back to unbounded List* + in-Go windowing when a store doesn't implement it; PG always does.
type PartitionDigest ¶ added in v0.8.6
type PartitionDigest struct {
// contains filtered or unexported fields
}
PartitionDigest is the streaming fold of a closed partition, in seq order:
d_0 = sha256(Header) d_i = sha256(d_{i-1} || row_hash_i)
every value lowercase hex text. It holds one 64-byte state however many rows are added, so a partition larger than Postgres's 1 GB field limit digests in constant memory.
func NewPartitionDigest ¶ added in v0.8.6
func NewPartitionDigest(m PartitionManifest) *PartitionDigest
NewPartitionDigest starts the fold at the manifest's header.
func (*PartitionDigest) Add ¶ added in v0.8.6
func (p *PartitionDigest) Add(rowHash string)
Add folds one row's hash (the stored row_hash; a row from before the chain began folds the hash audit_row_hash(NULL, ...) would have given it) into the digest.
func (*PartitionDigest) Sum ¶ added in v0.8.6
func (p *PartitionDigest) Sum() string
Sum is the digest so far, as 64 hex characters.
type PartitionManifest ¶ added in v0.8.6
type PartitionManifest struct {
Partition string `json:"partition"`
Rows int64 `json:"row_count"`
SeqLo int64 `json:"seq_lo"`
SeqHi int64 `json:"seq_hi"`
RecordedLoUS int64 `json:"recorded_lo_us"`
RecordedHiUS int64 `json:"recorded_hi_us"`
}
PartitionManifest is what a partition's digest binds besides its rows: its name, the range of seq and recorded_at it actually holds (recorded_at as integer microseconds since the epoch, the unit audit_row_hash uses) and its row count. An empty partition has Rows 0 and every range zero.
Header is the canonical text the digest starts from. It is the migration 0119 definition, which audit_partition_digest(p_partition) implements in the database: the two are pinned together by a test.
func (PartitionManifest) Header ¶ added in v0.8.6
func (m PartitionManifest) Header() string
Header is the JSON array of strings the fold starts from, in jsonb's own text form (a comma and a space between elements), so a manifest the database and Go each render is byte-identical. A range of an empty partition renders as an empty string.
type PauseCandidate ¶ added in v0.8.0
type PauseCandidate struct {
Run types.AgentRun
// OpenRequest: the run has a PENDING request inside its wait (openHoldSQL).
OpenRequest bool
// WaitingRequest: one of those counts toward a waiting pause
// (waitingHoldSQL).
WaitingRequest bool
}
PauseCandidate is one live run as the pause sweep sees it.
type PauseSettle ¶ added in v0.8.6
PauseSettle is one run a pause compensation may have left with its agent container not matching its pause mark (migration 0132).
type PauseSettler ¶ added in v0.8.6
type PauseSettler interface {
// NotePauseSettle records run id as owing a settle from after on (the
// database's clock), moving a due_at already recorded only forward, and
// returns the due_at it holds.
NotePauseSettle(ctx context.Context, id uuid.UUID, after time.Duration) (time.Time, error)
// DuePauseSettles lists the runs whose settle is due.
DuePauseSettles(ctx context.Context) ([]PauseSettle, error)
// ClearPauseSettle deletes run id's record only while it still reads due,
// so a later note survives.
ClearPauseSettle(ctx context.Context, id uuid.UUID, due time.Time) error
}
PauseSettler is the durable record of the runs whose container may not match their pause mark. Optional like RunPauser; production is always PG.
type PendingGroupRemoval ¶ added in v0.8.6
PendingGroupRemoval is one person's removal from one group with ledger rows still pending.
type PendingLeaver ¶ added in v0.8.6
PendingLeaver is an identity with ledger rows still pending: a suspension its identity provider stopped retrying, or a purge begun and not finished.
type PeopleDirectoryFilter ¶ added in v0.8.6
type PeopleDirectoryFilter struct {
// Query keeps people whose principal starts with it (case-sensitive) or whose email starts
// with it (case-insensitive). Empty keeps everyone.
Query string
// State is "active" (not deactivated), "deactivated", or "" for both.
State string
// After is the last principal of the previous page; empty starts at the top.
After string
Limit int
}
PeopleDirectoryFilter narrows and pages ListPeopleDirectory.
type PeopleDirectoryPage ¶ added in v0.8.6
type PeopleDirectoryPage struct {
People []PersonListing
Next string
}
PeopleDirectoryPage is one page; Next is the principal to pass as After, or "" on the last page.
type PeopleDirectoryStore ¶ added in v0.8.6
type PeopleDirectoryStore interface {
// ListPeopleDirectory returns one page of the directory, ordered by principal.
ListPeopleDirectory(ctx context.Context, f PeopleDirectoryFilter) (PeopleDirectoryPage, error)
}
PeopleDirectoryStore lists the people a deployment knows: every identity that has signed in (principal_identities, migration 0113) and every person an admin set up beforehand (people, migration 0090). Optional, like PersonStore.
type PersonErasureStore ¶ added in v0.8.6
type PersonErasureStore interface {
// RunIDsCreatedBy lists every run created_by createdBy.
RunIDsCreatedBy(ctx context.Context, createdBy string) ([]uuid.UUID, error)
// BlankRunTasks empties the task text of every run created_by createdBy and
// returns how many it changed. It never touches updated_at: the idle reaper
// reads it.
BlankRunTasks(ctx context.Context, createdBy string) (int, error)
// PrincipalForName maps a name an event carries (a principal, an
// entra:<tenant>:<object> form, an email the person signed in with) to the
// person's principal. A name that resolves to none, or to more than one, is
// returned as it is.
PrincipalForName(ctx context.Context, name string) (string, error)
// PrincipalAliases lists the names the identity directory knows principal
// by: the emails it signed in with (lowercased) and its entra:<tenant>:<object>
// form. A row sealed under a name the directory did not yet know is under
// that name's own key, so an erasure destroys these too.
PrincipalAliases(ctx context.Context, principal string) ([]string, error)
// EraseGovernanceChangePersonalFields clears the proposer and decider (and the decider's reason) of
// every governance change recorded under one of names (a principal, or an email matched
// case-folded) and moves a pending change whose proposer is one of them to expired. It returns the
// rows it touched.
EraseGovernanceChangePersonalFields(ctx context.Context, names []string) (int, error)
// SubjectKeyDestroyedSince reports whether any generation of owner's key
// for purpose has a destroyed_at after since.
SubjectKeyDestroyedSince(ctx context.Context, owner, purpose string, since time.Time) (bool, error)
}
PersonErasureStore is what erasing a person reads and writes beyond the stores that own a scope: the person's runs, and the identity directory that maps the names an audit row carries onto one principal. Optional like PrincipalIdentityStore: callers type-assert and refuse a scope the store cannot serve rather than report it erased.
type PersonListing ¶ added in v0.8.6
type PersonListing struct {
Principal string
Email string
// Entra is true for a person keyed by Entra tenant and object id.
Entra bool
PreCreated bool
// FirstSignInAt and LastSignInAt are nil for a person who has never signed in.
FirstSignInAt *time.Time
LastSignInAt *time.Time
DeactivatedAt *time.Time
// ActiveSessions is 0 or 1, see PeopleDirectoryActiveSessionWindow.
ActiveSessions int
APITokens int
SSHKeys int
Credentials int
ActiveRuns int
// Groups, GroupsTruncated and GroupsVerified are the person's last verified login groups
// (key_domain_login_groups, stamped at every SSO sign-in). GroupsVerified is false when no
// snapshot exists; GroupsTruncated is the login's own bit that its groups claim was cut short.
Groups []string
GroupsTruncated bool
GroupsVerified bool
}
PersonListing is one directory row.
type PersonStore ¶ added in v0.8.0
type PersonStore interface {
// CreatePerson inserts p, or returns the row already stored under
// p.Principal with created=false. A different principal holding the same
// email (case-insensitively) is ErrConflict.
CreatePerson(ctx context.Context, p types.Person) (out types.Person, created bool, err error)
// GetPerson is the row stored under exactly principal, or ErrNotFound.
GetPerson(ctx context.Context, principal string) (types.Person, error)
// ListPeople returns every row, oldest first.
ListPeople(ctx context.Context) ([]types.Person, error)
// MarkPersonSignedIn stamps first_signed_in_at on principal's row the first
// time they sign in. No row is not an error: most people were never
// pre-created.
MarkPersonSignedIn(ctx context.Context, principal string, now time.Time) error
}
PersonStore holds the identities an admin created or confirmed before their first sign-in (migration 0090, #1157; the Entra object-id key, 0099, #1195). Optional, like DeviceStore: the API answers 501 on a store without it.
type PresetWrite ¶ added in v0.8.0
type PresetWrite string
PresetWrite is what PutLaunchPreset did: created the row, replaced it (and moved its version), or found it already identical and wrote nothing.
const ( PresetCreated PresetWrite = "created" PresetUpdated PresetWrite = "updated" PresetUnchanged PresetWrite = "unchanged" )
type PrincipalIdentity ¶ added in v0.8.6
type PrincipalIdentity struct {
ID uuid.UUID
Principal string
Issuer string
TenantID string
ObjectID string
EmailLower string
// ScimExternalID and ScimUserName are the SCIM projection, not binding columns.
ScimExternalID string
ScimUserName string
DeactivatedAt *time.Time
AuthorityEpoch int64
PurgeAfter *time.Time
PurgedAt *time.Time
CreatedAt time.Time
LastLoginAt *time.Time
}
PrincipalIdentity is one human identity Wardyn has seen sign in. An Entra identity is (Issuer, TenantID, ObjectID); any other issuer has an empty TenantID and ObjectID and is keyed by (Issuer, Principal). Principal is "" on a row written before the person's first sign-in.
type PrincipalIdentityStore ¶ added in v0.8.6
type PrincipalIdentityStore interface {
// UpsertLoginIdentity records an approved sign-in: it creates the identity row, or finds the
// one for the same (issuer, tenant, object id) on Entra and (issuer, principal) elsewhere, binds
// its principal if it has none, stamps the sign-in time and keeps the email as an alias. A row's
// principal, issuer, tenant and object id are never changed once bound; a sign-in that would
// change one writes nothing: ErrIdentityBindingMismatch when its row is bound to another
// principal, ErrConflict when it names no row at all.
UpsertLoginIdentity(ctx context.Context, in LoginIdentity, now time.Time) (PrincipalIdentity, error)
// GetIdentityByObject is the row for exactly (issuer, tenantID, objectID), or ErrNotFound. An
// empty objectID is always ErrNotFound.
GetIdentityByObject(ctx context.Context, issuer, tenantID, objectID string) (PrincipalIdentity, error)
// IdentitiesByPrincipal is every row bound to principal, oldest first (one per issuer it has
// signed in on); empty when it has none.
IdentitiesByPrincipal(ctx context.Context, principal string) ([]PrincipalIdentity, error)
}
PrincipalIdentityStore is optional, like PersonStore: it is not part of Store, so callers type-assert and treat its absence as "nothing recorded".
type PrincipalPrefStore ¶ added in v0.8.0
type PrincipalPrefStore interface {
// GetPrincipalPref returns principal's value for key, or ErrNotFound.
GetPrincipalPref(ctx context.Context, principal, key string) (json.RawMessage, error)
// PutPrincipalPref upserts principal's value for key.
PutPrincipalPref(ctx context.Context, principal, key string, value json.RawMessage) error
}
PrincipalPrefStore persists per-person preferences. Like RunLayoutStore it is not part of Store, so the api test doubles need not grow it; the api type-asserts and treats its absence as "nothing remembered".
type PushPathListStore ¶ added in v0.8.0
type PushPathListStore interface {
// RecordPushPathList stores approvalID's list once, for runID. A second
// call for the same approval stores nothing and reports false; a list
// past the run's limit returns ErrPushPathListCap. Count and insert are
// one step, so concurrent calls for a run serialize.
RecordPushPathList(ctx context.Context, approvalID, runID uuid.UUID, l types.PushPathList, limit int) (bool, error)
// GetPushPathList returns approvalID's list, or ErrNotFound.
GetPushPathList(ctx context.Context, approvalID uuid.UUID) (types.PushPathList, error)
// CountPushPathLists counts the lists stored for runID's approvals.
CountPushPathLists(ctx context.Context, runID uuid.UUID) (int, error)
}
PushPathListStore keeps each push_content approval's types.PushPathList. Like PrincipalPrefStore it is not part of Store, so the api test doubles need not grow it; the api type-asserts it.
type Querier ¶ added in v0.8.6
type Querier interface {
Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
}
Querier is the statement surface a store write needs: satisfied by *pgxpool.Pool (one statement, its own implicit transaction) and by pgx.Tx (a statement inside a caller's transaction). A write written against Querier runs the same SQL either way, which is what lets a held governance change apply inside the decision transaction.
A write that relies on a transaction-scoped lock (an advisory xact lock) must be handed a pgx.Tx: on a pool the lock is released as soon as its own statement ends.
type Recorder ¶
Recorder wraps a pool and implements audit.Recorder via InsertAuditEvent.
type RunAuditMatcher ¶ added in v0.8.0
type RunAuditMatcher interface {
HasRunAuditEvent(ctx context.Context, runID uuid.UUID, f AuditFilter) (bool, error)
}
RunAuditMatcher answers "does this run have ANY audit row matching f?" as an EXISTS, so the answer does not depend on how many other rows the run has or where the match sits in its trail — which a bounded, oldest-first QueryAuditEvents window cannot promise. A capability interface for the reason Pager gives.
type RunCapacity ¶ added in v0.8.6
type RunCapacity struct {
States map[string]int `json:"states"`
Paused int `json:"paused"`
Kept int `json:"kept"`
Totals RunCapacityRunner `json:"totals"`
AgeBuckets []RunCapacityAge `json:"age_buckets"`
ByRunner map[string]RunCapacityRunner `json:"by_runner"`
ByOwner []RunCapacityOwner `json:"by_owner"`
ByOwnerTruncated bool `json:"by_owner_truncated"`
Unschedulable []RunCapacityUnschedulable `json:"unschedulable"`
UnschedulableTotal int `json:"unschedulable_total"`
// OldestActiveSeconds is the age since created_at of the oldest holding run (0 when none).
OldestActiveSeconds int64 `json:"oldest_active_seconds"`
}
RunCapacity is the fleet's configured reservations, computed from the non-terminal rows.
type RunCapacityAge ¶ added in v0.8.6
RunCapacityAge is one age bucket (since created_at) of holding runs.
type RunCapacityOpts ¶ added in v0.8.6
type RunCapacityOpts struct {
Now time.Time
CurrentKind string
UnschedulableReason func(detail string) string
}
RunCapacityOpts parameterises RunCapacity. CurrentKind is the deployment's runner kind; Totals carries only that kind's entry; other kinds appear only under ByRunner. UnschedulableReason maps a status_detail to its capacity-blocker reason, or "" when it is not one.
type RunCapacityOwner ¶ added in v0.8.6
type RunCapacityOwner struct {
Owner string `json:"owner"`
Holding int `json:"holding"`
Runners map[string]RunCapacitySums `json:"by_runner"`
}
RunCapacityOwner is one owner's holding runs, summed per runner kind (never across kinds). Ordering uses the deployment's current kind.
type RunCapacityRunner ¶ added in v0.8.6
type RunCapacityRunner struct {
Basis string `json:"basis"`
RunCapacitySums
}
RunCapacityRunner is one runner kind's sums. Basis says what they mean: Kubernetes sums requests, Docker has no reservation and reports caps.
type RunCapacitySums ¶ added in v0.8.6
type RunCapacitySums struct {
Holding int `json:"holding"`
Unknown int `json:"unknown"`
AgentCPURequestMillis int64 `json:"agent_cpu_request_millis"`
AgentCPULimitMillis int64 `json:"agent_cpu_limit_millis"`
AgentMemoryRequestMiB int64 `json:"agent_memory_request_mib"`
AgentMemoryLimitMiB int64 `json:"agent_memory_limit_mib"`
ProxyCPUMillis int64 `json:"proxy_cpu_millis"`
ProxyMemoryMiB int64 `json:"proxy_memory_mib"`
// ProxyCPUUncapped counts recorded rows whose proxy had no CPU cap (Docker).
ProxyCPUUncapped int `json:"proxy_cpu_uncapped"`
HeldCPUMillis int64 `json:"held_cpu_millis"`
HeldMemoryMiB int64 `json:"held_memory_mib"`
}
RunCapacitySums is one set of configured-reservation sums. Holding counts the rows that hold capacity; Unknown counts the holding rows whose reservation was never recorded (runner_kind NULL), which add to no sum. A run's held figure is its agent request plus its proxy.
type RunCapacityUnschedulable ¶ added in v0.8.6
type RunCapacityUnschedulable struct {
ID uuid.UUID `json:"id"`
Owner string `json:"owner"`
WaitedSeconds int64 `json:"waited_seconds"`
Reason string `json:"reason"`
RunnerKind *string `json:"runner_kind"`
AgentCPURequestMillis *int64 `json:"agent_cpu_request_millis"`
AgentMemoryRequestMiB *int64 `json:"agent_memory_request_mib"`
ProxyCPUMillis *int64 `json:"proxy_cpu_millis"`
ProxyMemoryMiB *int64 `json:"proxy_memory_mib"`
}
RunCapacityUnschedulable is one STARTING run waiting for room, with its recorded reservation (nil where unrecorded).
type RunFilter ¶ added in v0.8.0
type RunFilter struct {
// Owner exact-matches created_by; empty = every creator. The api layer
// resolves ?owner=me|all before calling down.
Owner string
// Statuses is a subset of "active"/"ended"/"failed"/"killed", OR'd
// together; empty = no filter. "needs" is rejected at the api layer.
Statuses []string
// EndedWithin bounds ended rows' age; <= 0 = unbounded. Live rows are
// never windowed by this.
EndedWithin time.Duration
// IncludeKilled disables killedVisibleFor's default hide.
IncludeKilled bool
// Workspace exact-matches COALESCE(NULLIF(repo,”), workspace_path).
Workspace string
// Query ILIKE-searches title/task/repo/created_by. Raw — the store
// escapes '%', '_' and '\' itself.
Query string
}
RunFilter narrows ListRunsFiltered/CountHiddenRuns to the landing page's opt-in contract. Zero value matches every row (killed rows still subject to killedVisibleFor).
type RunLayoutStore ¶ added in v0.5.0
type RunLayoutStore interface {
// GetRunLayout returns ErrNotFound when nothing has been saved yet; the
// api layer treats that as the default shape, not an error.
GetRunLayout(ctx context.Context, principal, preset string) (types.RunLayout, error)
// PutRunLayout upserts principal's layout for preset and returns the
// stored row, including the server-assigned updated_at.
PutRunLayout(ctx context.Context, principal, preset string, layout []types.RunLayoutWidget) (types.RunLayout, error)
}
RunLayoutStore is the run-cockpit widget-layout persistence surface. Deliberately NOT part of the Store interface: ~30 test doubles embed store.Store, and widening it would break every one for a feature they have nothing to do with. The api layer type-asserts s.cfg.Store to RunLayoutStore and degrades when absent (GET returns the default shape, PUT 501s); production is always PG, which has it.
type RunLeaser ¶ added in v0.8.0
type RunLeaser interface {
// ListLeasedRuns returns every RUNNING run that has an end or is kept.
ListLeasedRuns(ctx context.Context) ([]types.AgentRun, error)
// MarkRunEnded marks run id kept-and-ended at now, only while still
// RUNNING, not already kept, and its end is at or before now; clears a
// pause. The conditional UPDATE is the cross-replica mutual exclusion:
// exactly one caller sees true and runs the end.
MarkRunEnded(ctx context.Context, id uuid.UUID, now time.Time) (bool, error)
// MarkRunEndingSoon records that the thresholdSec-before-endsAt warning
// went out, reporting whether this call recorded it: false when that
// warning (or a closer one) already went for this end, or the end changed.
MarkRunEndingSoon(ctx context.Context, id uuid.UUID, endsAt time.Time, thresholdSec int) (bool, error)
// SetRunEndAndWait moves run id's end/wait from (fromEnd, fromWait) to
// (toEnd, toWait), only while the run still has those values, limits
// fromLimits, and isn't terminal. A run lost to a reboot/outage may still
// move its end — extending it is how it becomes revivable again. A run
// kept by its OWN end (LostEnded) moves only with ended set, exactly as
// EndedKept describes. false means the run changed since the read (end,
// wait, or a re-clamped profile); nil ends mean "no end". Moving the end
// clears end_tightened_at.
SetRunEndAndWait(ctx context.Context, id uuid.UUID, fromLimits types.RunLimits, fromEnd *time.Time, fromWait int, toEnd *time.Time, toWait int, ended *EndedKept) (bool, error)
// StopKeptRunIf makes a kept run (RUNNING with a lost/end mark) terminal,
// only while the row still carries the EXACT kept mark read (lostAt,
// lostReason, endsAt), checked atomically with the state guard in one
// UPDATE. Closes the same TOCTOU class UpdateRunStateIfIdle closes for the
// idle reaper: a stale lease-sweep row must never win the destructive
// RUNNING->terminal transition and tear down a run it no longer describes.
// false means the mark or state changed; the caller's re-assert next sweep
// pass makes dropping that safe.
StopKeptRunIf(ctx context.Context, id uuid.UUID, to types.RunState, lostAt *time.Time, lostReason types.LostReason, endsAt *time.Time) (bool, error)
// SetRunContainmentError records that a kept run's stop (proxy or agent)
// failed with msg, only while RUNNING and kept. Message refreshes on every
// call; containment_error_at keeps the first failure's time.
SetRunContainmentError(ctx context.Context, id uuid.UUID, msg string, now time.Time) error
// ClearRunContainmentError clears it once the stop is confirmed; true only
// for the call that cleared a recorded error, so resolution is audited
// once across replicas.
ClearRunContainmentError(ctx context.Context, id uuid.UUID) (bool, error)
}
RunLeaser is the lease surface. Optional like RunWatcherLeaser and for the same reason: the ~30 test doubles that embed store.Store would route these calls to a nil interface. The api layer type-asserts and runs no lease sweep when a store lacks it; production is always PG.
type RunLimitsReclamper ¶ added in v0.8.0
type RunLimitsReclamper interface {
// ListProfiledLiveRuns returns every non-terminal run that captured a
// governance profile at create and is not kept by its own end (LostEnded).
// A run lost to a reboot or a control-plane outage is still profiled-live:
// tightening its limits must still land, the same way extending its end
// still does (F1, long-holds design rev 4 §2.3).
ListProfiledLiveRuns(ctx context.Context) ([]types.AgentRun, error)
// ReclampRunLimits writes run id's tightened limits, end and wait, but only
// while the run still has the limits, end and wait in from (the run as the
// caller read it), is not terminal and is not kept by its own end
// (LostEnded). A non-nil endTightenedAt is stamped as end_tightened_at.
// false means the run changed since it was read; the next sweep reads it
// again.
ReclampRunLimits(ctx context.Context, from types.AgentRun, toLimits types.RunLimits, toEnd *time.Time, toWait int, endTightenedAt *time.Time) (bool, error)
}
RunLimitsReclamper is the re-clamp surface. Optional like RunLeaser and for the same reason; the api layer runs no re-clamp when a store lacks it.
type RunLoser ¶ added in v0.8.0
type RunLoser interface {
// StampRunTokenRenewed records id's token renewal at the database's clock.
// false means the run is already kept (lost/ended), so the renew must be
// refused — a lost run's identity must never carry forward.
StampRunTokenRenewed(ctx context.Context, id uuid.UUID) (bool, error)
// ListLapsedTokenRuns returns every RUNNING, not-kept run whose token was
// last renewed more than life ago, by the database's clock.
ListLapsedTokenRuns(ctx context.Context, life time.Duration) ([]types.AgentRun, error)
// MarkRunLost marks id kept and lost for reason at now, only while RUNNING
// and not already kept; with tokenLife>0 it re-requires the token still
// lapsed by that much, so a race with a renew resolves to the renew.
// Exactly one caller sees true. It clears a pause only for reboot — the
// one reason whose container is truly gone — since an outage's agent
// keeps running (frozen or not) and clearing here would make resume skip
// a thaw a still-frozen agent still needs.
MarkRunLost(ctx context.Context, id uuid.UUID, reason types.LostReason, now time.Time, tokenLife time.Duration) (bool, error)
}
RunLoser is the lost-run surface, kept optional because test doubles that embed store.Store would otherwise route these calls to a nil interface; the api layer type-asserts, and production is always PG.
type RunOutput ¶ added in v0.8.6
type RunOutput struct {
RunID uuid.UUID
Output []byte
Truncated bool
Incomplete bool
CaptureGap bool
Source string // "stdout" or "pane_snapshot"
MaskScope string // "run", "globals_only" or ""
CapturedAt *time.Time
ClaimedAt time.Time
}
RunOutput is one row of run_outputs. CapturedAt is nil while the row is pending (a capture is owed); MaskScope is "" when the row carries none.
type RunOutputChunkStore ¶ added in v0.8.6
type RunOutputChunkStore interface {
// AppendRunOutputChunk adds b, which the caller's masker has already passed, as runID's next
// chunk, then deletes the oldest chunks until what is left is the fewest that still hold
// keep bytes. It reports false, and writes nothing, once the run's final row exists: a
// writer that was slower than the finisher never recreates what the final row replaced.
AppendRunOutputChunk(ctx context.Context, runID uuid.UUID, replica string, b []byte, keep int) (bool, error)
// ReadRunOutputChunks returns the last limit bytes of runID's chunks.
ReadRunOutputChunks(ctx context.Context, runID uuid.UUID, limit int) (RunOutputChunks, error)
// SaveChunkedRunOutput writes runID's row from its chunks, as an incomplete capture gap (what
// the replica that wrote them had not flushed is lost), and deletes them, in one transaction.
// It reports false, writing nothing, when the run has no chunks or already has a final row.
SaveChunkedRunOutput(ctx context.Context, runID uuid.UUID, maskScope string, limit int) (bool, error)
}
RunOutputChunkStore is the live-chunk record. Optional like RunOutputStore: the api layer type-asserts, and a store without it keeps the tail in the writing process only. Every method checks the run's erasure tombstone in its own transaction and answers ErrRunOutputErased.
type RunOutputChunks ¶ added in v0.8.6
RunOutputChunks is a run's live tail as stored: the chunks' bytes in order, ending at the newest. Found is false when no chunk is held. Truncated says bytes older than Bytes were printed: chunks were trimmed, or the read cut the front.
type RunOutputStore ¶ added in v0.8.6
type RunOutputStore interface {
// InsertPendingRunOutput records that a capture is owed for runID. A row
// that already exists is left as it is.
InsertPendingRunOutput(ctx context.Context, runID uuid.UUID) error
// RefreshRunOutputClaim stamps a pending row's claimed_at: the final write
// is being retried, so the sweeper must not resolve it yet.
RefreshRunOutputClaim(ctx context.Context, runID uuid.UUID) error
// SaveFinalRunOutput writes the run's final row (output, flags and
// mask_scope as given), replacing a pending or capture-gap row. The
// database stamps captured_at.
SaveFinalRunOutput(ctx context.Context, o RunOutput) error
// SaveGapRunOutput writes a capture-gap row with no bytes, only over a
// pending row or none: a final row already committed is never overwritten.
// It reports whether it wrote.
SaveGapRunOutput(ctx context.Context, runID uuid.UUID) (bool, error)
// MarkRunOutputIncomplete sets incomplete on runID's final row, reporting
// whether a final row was there to mark.
MarkRunOutputIncomplete(ctx context.Context, runID uuid.UUID) (bool, error)
// GetRunOutput returns runID's row, pending or final. found is false when
// there is none.
GetRunOutput(ctx context.Context, runID uuid.UUID) (o RunOutput, found bool, err error)
// EraseRunOutputs writes a tombstone for each run and deletes its rows, in
// one transaction: all of it or none of it.
EraseRunOutputs(ctx context.Context, runIDs []uuid.UUID) error
// DeleteRunOutputsOlderThan deletes final rows captured longer ago than age
// (the database's clock), returning how many went.
DeleteRunOutputsOlderThan(ctx context.Context, age time.Duration) (int, error)
// ListStalePendingRunOutputs returns the runs whose pending row was claimed
// longer ago than age and which are terminal, oldest first, at most limit.
ListStalePendingRunOutputs(ctx context.Context, age time.Duration, limit int) ([]uuid.UUID, error)
}
RunOutputStore is the run-output record. Optional like RunWatcherLeaser: the ~30 test doubles that embed Store would route these to a nil interface, so the api layer type-asserts and keeps output in memory only when a store lacks it. Production is always PG. Every method but the sweeper's two checks the run's erasure tombstone in its own transaction and answers ErrRunOutputErased.
type RunPAT ¶ added in v0.8.2
type RunPAT struct {
RunID uuid.UUID
AuthorizationID uuid.UUID
Owner string // whose token: the run's creator
ProviderRowID string // the provider row the run was dispatched on
Org string // the Azure DevOps organisation the token is scoped to
Scope string // the space-joined scope string it was created with
ValidTo time.Time
CreatedAt time.Time // stamped by the store on insert; ignored on the way in
RevokedAt *time.Time // nil while Wardyn believes the token is live
RevokeReason string
LastError string // why the last revoke attempt failed; "" otherwise
}
RunPAT is one row of ado_run_pats.
type RunPATFilter ¶ added in v0.8.2
RunPATFilter narrows ListUnrevokedRunPATs; a zero field matches everything.
type RunPATReader ¶ added in v0.8.2
type RunPATReader interface {
// ListRunPATs returns every token recorded for runID, revoked or not,
// oldest first. Empty, never nil, when there is none.
ListRunPATs(ctx context.Context, runID uuid.UUID) ([]RunPAT, error)
// LastRunPAT returns the newest token recorded for owner on
// providerRowID; found=false when there is none.
LastRunPAT(ctx context.Context, owner, providerRowID string) (p RunPAT, found bool, err error)
}
RunPATReader reads the run-token record for display. Optional like RunPATStore: a store without it has no tokens to show.
type RunPATStore ¶ added in v0.8.2
type RunPATStore interface {
// InsertRunPAT records a token BEFORE its first use. ErrConflict when that
// (run, authorization id) is already recorded. CreatedAt is the store's.
InsertRunPAT(ctx context.Context, p RunPAT) error
// MarkRunPATRevoked closes a token's record: it was revoked, or its valid_to
// has passed. reason is required (one of api's adoPATRevoke* values). It
// reports whether it closed the row: false when the row is unknown or
// already closed, so two revokers race harmlessly. lastError, if non-empty,
// keeps why the last revoke attempt failed.
MarkRunPATRevoked(ctx context.Context, runID, authorizationID uuid.UUID, reason, lastError string) (bool, error)
// NoteRunPATRevokeFailed records why a revoke attempt failed and leaves the
// row OPEN, so the sweep retries and the setup check can list a token Wardyn
// could not revoke while its valid_to is ahead. A closed or unknown row is
// left as it is.
NoteRunPATRevokeFailed(ctx context.Context, runID, authorizationID uuid.UUID, lastError string) error
// ListUnrevokedRunPATs returns the tokens still recorded live that match f,
// oldest first.
ListUnrevokedRunPATs(ctx context.Context, f RunPATFilter) ([]RunPAT, error)
}
RunPATStore is the run-token record. Optional like RunPauser: it is not part of Store because the test doubles that embed Store would route these to a nil interface; the api layer type-asserts. Production is always PG; MemRunPATs is the same contract without a database. Unlike RunPauser, a caller that finds no RunPATStore must REFUSE TO MINT: a token is never created unrecorded.
type RunPauser ¶ added in v0.8.0
type RunPauser interface {
// ListPauseCandidates returns every RUNNING, not-kept run with a sandbox,
// paused or not, and the store's own clock read with them.
ListPauseCandidates(ctx context.Context) ([]PauseCandidate, time.Time, error)
// StampRunActive moves run id's presence clock to now, and reports whether
// the run is paused. A terminal or missing run is not stamped (false, nil).
StampRunActive(ctx context.Context, id uuid.UUID) (paused bool, err error)
// MarkRunPaused marks run id paused for reason, but only while it is still
// RUNNING, not kept, not paused, its presence clock still reads activeAt
// (the snapshot the caller judged idle; nil is "never stamped"), and — for
// a waiting pause — it still has a request the waiting pause counts, or —
// for an idle pause — it has no open request. The conditional UPDATE is
// what makes a keystroke, or a request closing or opening, between the
// caller's read and this write win: false means leave the run running.
MarkRunPaused(ctx context.Context, id uuid.UUID, reason types.PauseReason, activeAt *time.Time) (bool, error)
// ClearRunPaused clears run id's pause, and reports whether it was paused.
ClearRunPaused(ctx context.Context, id uuid.UUID) (bool, error)
// RunHasOpenRequest reports whether run id has a PENDING request inside
// its wait.
RunHasOpenRequest(ctx context.Context, id uuid.UUID) (bool, error)
}
RunPauser is the pause surface. Optional like RunLeaser and for the same reason; the api layer runs no pause sweep, and stamps no presence, when a store lacks it. Production is always PG.
type RunProxyConfigs ¶ added in v0.8.0
type RunProxyConfigs interface {
// PutRunProxyConfig writes run id's sealed config, replacing any.
PutRunProxyConfig(ctx context.Context, id uuid.UUID, sealed []byte) error
// GetRunProxyConfig reads it; ErrNotFound when there is none.
GetRunProxyConfig(ctx context.Context, id uuid.UUID) ([]byte, error)
// DeleteRunProxyConfig removes it. Idempotent.
DeleteRunProxyConfig(ctx context.Context, id uuid.UUID) error
// PurgeTerminalRunProxyConfigs removes every row whose run is terminal,
// the backstop for a delete that failed, and returns how many it removed.
PurgeTerminalRunProxyConfigs(ctx context.Context) (int64, error)
}
RunProxyConfigs stores each run's sealed proxy config. The caller seals and opens it; the store never sees it in the clear. Optional for RunLeaser's reason: the api layer type-asserts, and production is always PG.
type RunProxyRelease ¶ added in v0.8.0
type RunProxyRelease struct {
RunID uuid.UUID `json:"run_id"`
CreatedBy string `json:"created_by"`
State types.RunState `json:"state"`
LostReason types.LostReason `json:"lost_reason,omitempty"`
Release string `json:"proxy_release"`
}
RunProxyRelease is one row of the version-window listing.
type RunReviver ¶ added in v0.8.0
type RunReviver interface {
// MarkRunRevived claims run id for a new proxy: while it is RUNNING and still as the revive read
// it, live (from "") or lost to an outage or a reboot (from that reason), it clears the lost
// mark (and any unresolved containment error — the old proxy it was about is replaced), stamps
// the token as just renewed (the revive mints a fresh one, and the lapsed-token sweep must not
// read the old stamp), and refreshes the watcher lease (a stopped agent starts only after the
// new proxy, and the watcher sweep must not probe it before then).
//
// A run kept by its own end (from LostEnded) is claimed only with ended set: its exact mark,
// its files grace still live, and its end after ended.Now. It also clears a pause ONLY when
// from is a reboot: that revive restarts the agent container (docker start), so a stale pause
// mark would 409 the run's files/resources reads over an agent that's actually running. A live
// restart (from "") or an outage revive never touch the agent's own process, frozen or not, so
// their pause mark, if any, must survive for the thaw an eventual resume still needs to
// perform (a lease end already cleared the pause of a run kept by its own end).
//
// false means the run went terminal, ended, was lost or revived since, or its grace or end ran
// out (an outage-kept run's end too, as revive admission requires) — it gets no proxy.
//
// startsAgent is a revive that starts the run's stopped agent (a reboot, an end, or an
// outage whose agent was stopped). With limit > 0 its claim takes a slot under the
// deployment cap like a create does: under CreateRunUnderCap's lock,
// ErrRunCapReached when every OTHER run that holds a sandbox already reaches limit,
// the run left as it was. The row's own count is not trusted for this: an outage-kept
// run whose end was moved later reads as holding a sandbox though its agent is
// stopped. A revive that starts no agent (a live restart, an outage revive whose agent
// still runs) adds nothing and is never refused.
MarkRunRevived(ctx context.Context, id uuid.UUID, from types.LostReason, ended *EndedKept, limit int, startsAgent bool) (bool, error)
// SetRunProxyRelease records release as the one that started run id's
// proxy, once a revive's new proxy runs.
SetRunProxyRelease(ctx context.Context, id uuid.UUID, release string) error
// ListRunProxyReleases returns every non-terminal run that has a sandbox,
// with the release that started its proxy ("" before migration 0084).
ListRunProxyReleases(ctx context.Context) ([]RunProxyRelease, error)
}
RunReviver is the revive surface. Optional for RunLeaser's reason: the test doubles that embed store.Store would route these calls to a nil interface. The api layer type-asserts; production is always PG.
type RunSizing ¶ added in v0.8.6
type RunSizing struct {
RunnerKind string
AgentCPURequestMillis int64
AgentCPULimitMillis int64
AgentMemoryRequestMiB int64
AgentMemoryLimitMiB int64
ProxyCPUMillis *int64
ProxyMemoryMiB int64
}
RunSizing is the configured reservation recorded at dispatch (migration 0117). A nil ProxyCPUMillis means the proxy had no CPU cap.
type RunTitler ¶ added in v0.8.0
type RunTitler interface {
// SetRunTitle overwrites run id's title unconditionally — a rename is
// allowed in any run state (design.md §3.4), unlike the lease's end/wait,
// so there is no state guard and no compare-and-swap here.
SetRunTitle(ctx context.Context, id uuid.UUID, title string) error
}
RunTitler is the run-rename surface (#1197 L2, design.md §3.4). Optional like RunLeaser and for the same reason: the ~30 hand-written test doubles that implement Store directly would otherwise need a mechanical update for a route most of them never exercise. The api layer type-asserts; production is always PG.
type RunWatcherLeaser ¶ added in v0.5.0
type RunWatcherLeaser interface {
ClaimStaleRunWatchers(ctx context.Context, owner string, staleAfter time.Duration) ([]types.AgentRun, error)
HeartbeatRunWatcher(ctx context.Context, id uuid.UUID, owner string) error
// RunWatcherFresh reports whether id's lease heartbeat is younger than
// staleAfter (a live process owns it). The undispatched-run reaper checks
// this so it never false-fails a RUNNING run whose sandbox_ref write was
// lost but whose watcher still holds the lease. Missing row = not fresh (reap it).
RunWatcherFresh(ctx context.Context, id uuid.UUID, staleAfter time.Duration) (bool, error)
}
RunWatcherLeaser is deliberately not part of Store (like Pager): ~30 test doubles embed store.Store overriding only a few methods, so widening Store would route lease writes to the embedded nil interface inside the watcher goroutine, whose recover() would swallow the panic and kill it silently. The api layer type-asserts and skips leasing when a store lacks this; PG always has it.
type RunsByCreatorPager ¶ added in v0.5.0
type RunsByCreatorPager interface {
ListRunsPageByCreator(ctx context.Context, createdBy string, p Page) ([]types.AgentRun, error)
}
RunsByCreatorPager is the ownership-scoped analogue of Pager.ListRunsPage: a member's GET /runs is scoped to created_by = the caller. TRUST BOUNDARY: unlike Pager, an absent implementation must fail closed (500), not fall back to the unscoped list — an unscoped list IS the vulnerability here.
type RunsFilteredPager ¶ added in v0.8.0
type RunsFilteredPager interface {
ListRunsFiltered(ctx context.Context, f RunFilter, p Page) ([]types.AgentRun, error)
// CountHiddenRuns answers the X-Wardyn-Hidden-* headers: rows baseWhere
// matches but ended_within excludes (olderHidden), plus rows
// killedVisibleFor additionally excludes (killedHidden) — one query.
CountHiddenRuns(ctx context.Context, f RunFilter) (olderHidden, killedHidden int, err error)
}
RunsFilteredPager is the landing-page scoping surface for GET /runs. Kept out of Pager/Store: widening either would silently route a test double's embedded method to the wrong (unscoped) behaviour. An absent implementation fails CLOSED at the api-layer call site, same as RunsByCreatorPager — a silent unscoped fallback would leak every run to a caller the filter was meant to narrow.
type SSHKeysByPrincipalPager ¶ added in v0.8.0
type SSHKeysByPrincipalPager interface {
ListSSHKeysByPrincipalPage(ctx context.Context, principal string, p Page) ([]types.SSHPublicKey, error)
}
SSHKeysByPrincipalPager is the scoped analogue of Pager for GET /me/ssh-keys, same safe-fallback posture as GrantsByRunPager (ListSSHKeysByPrincipal is already WHERE principal=$1).
type ScimGroup ¶ added in v0.8.6
ScimGroup is a group the identity provider reported. ExternalID is the provider's id for it.
type ScimGroupStore ¶ added in v0.8.6
type ScimGroupStore interface {
CreateScimGroup(ctx context.Context, externalID, displayName string, now time.Time) (ScimGroup, error)
GetScimGroup(ctx context.Context, id uuid.UUID) (ScimGroup, error)
SearchScimGroups(ctx context.Context, attr, value string, limit int) ([]ScimGroup, error)
RenameScimGroup(ctx context.Context, id uuid.UUID, displayName string) error
ScimGroupMembers(ctx context.Context, id uuid.UUID) ([]uuid.UUID, error)
// AddScimGroupMembers records identities as members, skipping any id that names no identity.
AddScimGroupMembers(ctx context.Context, id uuid.UUID, identities []uuid.UUID, now time.Time) error
StartGroupRemoval(ctx context.Context, groupID, identityID uuid.UUID) error
ResumeGroupRemoval(ctx context.Context, groupID, identityID uuid.UUID) (bool, error)
GroupRemovalIdentities(ctx context.Context, groupID uuid.UUID) ([]uuid.UUID, error)
DeleteScimGroup(ctx context.Context, id uuid.UUID) error
PendingGroupRemovals(ctx context.Context, idleFor time.Duration, limit int) ([]PendingGroupRemoval, error)
GroupRemovalFailures(ctx context.Context, limit int) ([]DeprovisionFailure, error)
}
ScimGroupStore is optional, like LeaverStore: callers type-assert it.
type Store ¶
type Store interface {
// AgentRun.
CreateRun(ctx context.Context, r types.AgentRun) (types.AgentRun, error)
GetRun(ctx context.Context, id uuid.UUID) (types.AgentRun, error)
ListRuns(ctx context.Context) ([]types.AgentRun, error)
// CountActiveRunsBy counts one creator's non-terminal runs — the governance quota's read
// (GovernanceLimits.MaxConcurrentRuns). Called only when an assigned profile sets a cap.
CountActiveRunsBy(ctx context.Context, createdBy string) (int, error)
UpdateRunStateIf(ctx context.Context, id uuid.UUID, fromState, toState types.RunState) (bool, error)
UpdateRunStateIfIdle(ctx context.Context, id uuid.UUID, fromState, toState types.RunState, notAfter time.Time) (bool, error)
SetSandboxRef(ctx context.Context, id uuid.UUID, ref string) error
SetRunImage(ctx context.Context, id uuid.UUID, image string) error
SetRunDiskMiB(ctx context.Context, id uuid.UUID, mib int) error
SetRunAgentExecID(ctx context.Context, id uuid.UUID, execID string) error
TouchRun(ctx context.Context, id uuid.UUID) error
// RunPolicy.
CreatePolicy(ctx context.Context, p types.RunPolicy) (types.RunPolicy, error)
GetPolicy(ctx context.Context, id uuid.UUID) (types.RunPolicy, error)
ListPolicies(ctx context.Context) ([]types.RunPolicy, error)
UpdatePolicy(ctx context.Context, id uuid.UUID, name string, spec types.RunPolicySpec) (types.RunPolicy, error)
DeletePolicy(ctx context.Context, id uuid.UUID) error
// Workspace.
CreateWorkspace(ctx context.Context, ws types.Workspace) (types.Workspace, error)
GetWorkspace(ctx context.Context, id uuid.UUID) (types.Workspace, error)
ListWorkspaces(ctx context.Context) ([]types.Workspace, error)
// UpdateWorkspace writes the full column set, CARRYING ws.EgressEditedAt rather than stamping
// it, or ReconcileWorkspaceEgressDecisions could re-widen a list the operator just cleared.
// stampEgressEdit lets the ONE caller that clears the list say so, stamped by the DATABASE like
// every other writer of that column.
UpdateWorkspace(ctx context.Context, id uuid.UUID, ws types.Workspace, stampEgressEdit bool) (types.Workspace, error)
// SetWorkspaceApprovedEgress replaces the approved-egress list and stamps EgressEditedAt: the
// documented undo for an `always` decision, stopping the boot heal from re-adding a removed host.
SetWorkspaceApprovedEgress(ctx context.Context, id uuid.UUID, domains []string) (types.Workspace, error)
// AddWorkspaceEgressDecision records one `always`-scoped decision: on allow, host moves into
// approved_egress (capped, deduped) and out of denied_egress; on deny the mirror. ErrConflict
// (not ErrNotFound) when the cap refuses the write. Does NOT stamp EgressEditedAt — a decision
// isn't an operator override of itself.
AddWorkspaceEgressDecision(ctx context.Context, id uuid.UUID, host string, allow bool, maxApprovedEgress int) (types.Workspace, error)
// SetWorkspaceDeniedEgress mirrors SetWorkspaceApprovedEgress for denied-egress: pass the FULL
// desired list, replacing rather than merging.
SetWorkspaceDeniedEgress(ctx context.Context, id uuid.UUID, domains []string) (types.Workspace, error)
SetWorkspaceLLMCred(ctx context.Context, id uuid.UUID, cred *types.WorkspaceLLMCred) (types.Workspace, error)
// SetWorkspaceOwner replaces ONLY owned_by (offboarding: reassign a departed member's workspace
// to the operator via owner ""). Scoped and separate from UpdateWorkspace so no ordinary edit
// can move ownership or race a concurrent async scan.
SetWorkspaceOwner(ctx context.Context, id uuid.UUID, owner string) (types.Workspace, error)
SetWorkspaceRequirements(ctx context.Context, id uuid.UUID, reqs map[string]types.WorkspaceRequirement) (types.Workspace, error)
SetWorkspaceRecordResult(ctx context.Context, id uuid.UUID, taskKey string, result json.RawMessage, onlyIfStatus string) (types.Workspace, bool, error)
ClaimWorkspaceActiveRun(ctx context.Context, id, runID uuid.UUID, expected *uuid.UUID) (types.Workspace, bool, error)
ClearWorkspaceActiveRun(ctx context.Context, id, runID uuid.UUID) (bool, error)
SetWorkspaceBuiltImage(ctx context.Context, id uuid.UUID, imageRef, builtHash string) (types.Workspace, error)
// SetWorkspaceImportState advances the scan pipeline. FENCED: applies only while the import-step
// slot still holds expectedActive; applied=false means the caller must re-read, not retry blindly.
SetWorkspaceImportState(ctx context.Context, id uuid.UUID, status types.WorkspaceStatus, activeRunID *uuid.UUID, expectedActive *uuid.UUID) (types.Workspace, bool, error)
// MergeWorkspaceRequirements ADDS overlay rows atomically (jsonb ||), safe against concurrent
// edits the full-replace SetWorkspaceRequirements would race. ErrConflict at the key cap.
MergeWorkspaceRequirements(ctx context.Context, id uuid.UUID, add map[string]types.WorkspaceRequirement) (types.Workspace, error)
DeleteWorkspace(ctx context.Context, id uuid.UUID) error
// Source library (tier 1) — a repo/dir configured once, attached to many workspaces. Upsert
// dedupes on (kind, locator, ref).
UpsertSource(ctx context.Context, src types.Source) (types.Source, error)
GetSource(ctx context.Context, id uuid.UUID) (types.Source, error)
GetSourcesByIDs(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID]types.Source, error)
ListSources(ctx context.Context) ([]types.Source, error)
UpdateSourceConfig(ctx context.Context, id uuid.UUID, name string, reqs map[string]types.WorkspaceRequirement) (types.Source, error)
WorkspacesAttaching(ctx context.Context, id uuid.UUID) ([]string, error)
DeleteSource(ctx context.Context, id uuid.UUID, detach bool) error
ClaimSourceActiveRun(ctx context.Context, id, runID uuid.UUID) error
ClearSourceActiveRun(ctx context.Context, id, runID uuid.UUID) error
SetSourceScanResult(ctx context.Context, id uuid.UUID, profile []byte, status types.WorkspaceStatus, runID uuid.UUID, seed map[string]types.WorkspaceRequirement) (types.Source, error)
SetSourceScanResultUnfenced(ctx context.Context, id uuid.UUID, profile []byte, status types.WorkspaceStatus, seed map[string]types.WorkspaceRequirement) (types.Source, error)
// Base-image catalog (tier 2). Upsert dedupes on (kind, image, steps); "recommended" is
// structurally excluded (CHECK) — it is a per-workspace derived build, never a catalog row.
UpsertBaseImage(ctx context.Context, b types.BaseImageEntry) (types.BaseImageEntry, error)
// UpdateBaseImageName renames a catalog row — the operator-editable counterpart to
// UpdateSourceConfig above, deliberately NOT folded into UpsertBaseImage's identity-hit dedupe.
UpdateBaseImageName(ctx context.Context, id uuid.UUID, name string) (types.BaseImageEntry, error)
ListBaseImages(ctx context.Context) ([]types.BaseImageEntry, error)
WorkspacesUsingBaseImage(ctx context.Context, id uuid.UUID) ([]string, error)
DeleteBaseImage(ctx context.Context, id uuid.UUID, detach bool) error
// CredentialGrant.
CreateGrant(ctx context.Context, g types.CredentialGrant) (types.CredentialGrant, error)
ListGrantsByRun(ctx context.Context, runID uuid.UUID) ([]types.CredentialGrant, error)
// ApprovalRequest.
CreateApproval(ctx context.Context, a types.ApprovalRequest) (types.ApprovalRequest, error)
GetApproval(ctx context.Context, id uuid.UUID) (types.ApprovalRequest, error)
ListApprovals(ctx context.Context, stateFilter types.ApprovalState) ([]types.ApprovalRequest, error)
// DecideApproval transitions state from PENDING to decision.State; returns
// ErrAlreadyDecided if the approval is not PENDING. See types.ApprovalDecision.
DecideApproval(ctx context.Context, id uuid.UUID, decision types.ApprovalDecision) (types.ApprovalRequest, error)
// AuditEvent.
QueryAuditEvents(ctx context.Context, runID uuid.UUID, limit int) ([]types.AuditEvent, error)
QueryRecentAuditEvents(ctx context.Context, limit int) ([]types.AuditEvent, error)
LatestAuditEventByAction(ctx context.Context, action string) (types.AuditEvent, error)
// SiteConfig.
GetSiteConfig(ctx context.Context) (types.SiteConfig, error)
PutSiteConfig(ctx context.Context, cfg types.SiteConfig) (types.SiteConfig, error)
// Sandbox ref -> substrate routing (the orchestrator's RefStore seam; see
// store_sandbox_ref.go). GetRef reports a missing row as found=false, nil.
PutRef(ctx context.Context, ref, substrateName string) error
GetRef(ctx context.Context, ref string) (substrateName string, found bool, err error)
DeleteRef(ctx context.Context, ref string) error
// Short-lived cross-process handoff row (see store_ephemeral.go): single-use WS attach tickets.
// Consume-once, and the consumer is a single DELETE ... RETURNING, so two racing redemptions —
// on one control plane or two — can only have one win.
MintAttachTicket(ctx context.Context, token string, t AttachTicket, now, expiresAt time.Time) error
ConsumeAttachTicket(ctx context.Context, token string, now time.Time) (AttachTicket, bool, error)
// SSH gateway key registry (migration 0033, self-service via /api/v1/me/ssh-keys). AddSSHKey
// returns ErrConflict on a taken fingerprint (the PK; one key maps to one owner). DeleteSSHKey is
// scoped to principal (someone else's key is ErrNotFound, no existence leak). GetSSHKeyByFingerprint
// is the gateway's unscoped auth-time lookup. RefreshSSHKeyRoles re-stamps role+role_checked_at
// (migration 0046) from the OIDC OnLogin hook, bounding the admin-override stamp's staleness.
AddSSHKey(ctx context.Context, k types.SSHPublicKey) (types.SSHPublicKey, error)
ListSSHKeysByPrincipal(ctx context.Context, principal string) ([]types.SSHPublicKey, error)
GetSSHKeyByFingerprint(ctx context.Context, fingerprint string) (types.SSHPublicKey, error)
DeleteSSHKey(ctx context.Context, fingerprint, principal string) error
// DeleteSSHKeys removes one principal's keys, or all keys when principal is empty.
DeleteSSHKeys(ctx context.Context, principal string) (int, error)
RefreshSSHKeyRoles(ctx context.Context, principal, role string, checkedAt time.Time) error
// RefreshAPITokenIdentity re-stamps role, user type and the group snapshot (plus its completeness
// bit) on every unrevoked api_tokens row a principal holds, from the same OnLogin hook as
// RefreshSSHKeyRoles — neither credential had a way to learn about a demotion or group change.
RefreshAPITokenIdentity(ctx context.Context, principal, role, userType string, groups []string, truncated bool) error
// Per-user API tokens (migration 0045). SECURITY: GetAPITokenByRaw is the
// third auth branch on every authenticated route.
//
// CreateAPIToken/GetAPITokenByRaw hash the plaintext token internally — the raw value never
// reaches SQL. GetAPITokenByRaw returns ErrNotFound for unknown, mismatched, revoked AND expired
// tokens alike, so it's not an existence oracle. RevokeAPIToken is principal-scoped when non-empty
// (self-service; someone else's id is ErrNotFound) and revokes ANY token when empty (admin).
// TouchAPIToken is best effort — its error must never fail a request.
CreateAPIToken(ctx context.Context, t types.APIToken, raw string) (types.APIToken, error)
GetAPITokenByRaw(ctx context.Context, raw string) (types.APIToken, error)
TouchAPIToken(ctx context.Context, id uuid.UUID, now time.Time) error
ListAPITokensByPrincipal(ctx context.Context, principal string) ([]types.APIToken, error)
ListAPITokens(ctx context.Context) ([]types.APIToken, error)
RevokeAPIToken(ctx context.Context, id uuid.UUID, principal string, now time.Time) (types.APIToken, error)
// Capability grants and the per-kind enforcement switch (migration 0042).
// SECURITY: the resolver runs on the request path; the fail mode is a
// fail-open authz gate hiding in an untyped test double.
UpsertCapabilityGrant(ctx context.Context, g types.CapabilityGrant) (types.CapabilityGrant, error)
DeleteCapabilityGrant(ctx context.Context, id uuid.UUID) error
ListCapabilityGrants(ctx context.Context) ([]types.CapabilityGrant, error)
// ListGroupDenyGrants returns the group-subject DENY rows of one kind, the only rows the
// unresolvable-group-deny refusal can match — separate from ListCapabilityGrants so that
// request-path check doesn't cost scale with table size.
ListGroupDenyGrants(ctx context.Context, capability string) ([]types.CapabilityGrant, error)
// ListCapabilityGrantsFor returns the grants that could apply to one caller: `all` rows plus
// `user` rows naming any of users (sub AND email) plus `group` rows naming any of groups plus
// `user_type` rows naming userType. Not filtered by capability — see the implementation.
ListCapabilityGrantsFor(ctx context.Context, users, groups []string, userType string) ([]types.CapabilityGrant, error)
// GetCapabilityEnforcement returns the sparse per-kind switch map; an absent key means NOT
// enforced, the zero-config back-compat default.
GetCapabilityEnforcement(ctx context.Context) (map[string]bool, error)
// PutCapabilityEnforcement replaces the WHOLE map (a capability the caller omits loses its row)
// and returns the stored result.
PutCapabilityEnforcement(ctx context.Context, enabled map[string]bool) (map[string]bool, error)
// ListCapabilityRestrictions returns the restricted values ("Available to: Only...", migration
// 0081) as kind -> set of values; an absent value is not restricted. Never nil.
ListCapabilityRestrictions(ctx context.Context) (map[string]map[string]bool, error)
// SetCapabilityRestriction turns one value's restriction on or off (idempotent either way).
SetCapabilityRestriction(ctx context.Context, capability, value string, restricted bool, by string) error
// Console-managed role mappings (migration 0051): the store half of internal/auth/oidc's
// RoleMappingSource, read once per login and merged with the chart's WARDYN_OIDC_ROLE_MAP.
// SECURITY: on the OIDC login path; the fail mode is silently falling back
// to env-only, WIDENING who derives admin under WARDYN_OIDC_DEFAULT_ROLE=admin.
//
// UpsertRoleMapping keys on the natural UNIQUE (value): re-adding an already-mapped value flips
// its role in place, returning the EXISTING row's id on a conflict (never the candidate's).
UpsertRoleMapping(ctx context.Context, m types.RoleMapping) (types.RoleMapping, error)
DeleteRoleMapping(ctx context.Context, id uuid.UUID) error
// ListRoleMappings returns every row, oldest first — the console's People
// screen and the OIDC login-time merge's whole data need.
ListRoleMappings(ctx context.Context) ([]types.RoleMapping, error)
// User types (migration 0071_user_types). CreateUserType and
// UpdateUserType return ErrConflict on a taken id or name; DeleteUserType
// returns ErrConflict while the type is built in or still named by a
// subject row (UserTypeReferences counts those).
ListUserTypes(ctx context.Context) ([]types.UserType, error)
GetUserType(ctx context.Context, id string) (types.UserType, error)
CreateUserType(ctx context.Context, t types.UserType) (types.UserType, error)
UpdateUserType(ctx context.Context, t types.UserType) (types.UserType, error)
// UpdateUserTypeMetadata is UpdateUserType without the priority column.
UpdateUserTypeMetadata(ctx context.Context, t types.UserType) (types.UserType, error)
UserTypeReferences(ctx context.Context, id string) (int, error)
// UserTypeTokenStamps counts the unrevoked API tokens stamped with the type.
UserTypeTokenStamps(ctx context.Context, id string) (int, error)
DeleteUserType(ctx context.Context, id string) error
// Launch presets (migration 0087, store_launch_presets.go). PutLaunchPreset
// is an upsert by name that moves the version only when the row changes.
ListLaunchPresets(ctx context.Context) ([]types.LaunchPreset, error)
GetLaunchPreset(ctx context.Context, name string) (types.LaunchPreset, error)
PutLaunchPreset(ctx context.Context, p types.LaunchPreset) (types.LaunchPreset, PresetWrite, error)
DeleteLaunchPreset(ctx context.Context, name string) (types.LaunchPreset, error)
// Governance profiles and their subject assignments (migration 0052): the assignable ceiling
// that replaces Config.DefaultPolicy for a principal an admin has named.
// SECURITY: on the run-creation request path; the fail mode is falling
// back to the deployment-wide ceiling, past the floor an admin set.
//
// UpsertGovernanceProfile keys on the PRIMARY KEY (a fresh id inserts, an existing one updates
// in place, rename included) and returns ErrConflict when UNIQUE(name) rejects the write.
// DeleteGovernanceProfile returns ErrConflict when the profile is still ASSIGNED — the ON DELETE
// RESTRICT, so deleting a profile can never silently widen its members.
UpsertGovernanceProfile(ctx context.Context, p types.GovernanceProfile) (types.GovernanceProfile, error)
// WriteGovernanceProfile is the graph-aware write: one transaction under the profile-graph
// lock, where build decides the stored row from every profile as that transaction reads them
// (migration 0125: a profile may be composed on another). DeleteGovernanceProfile also
// returns *ErrProfileHasChildren when another profile composes on the row.
WriteGovernanceProfile(ctx context.Context, id uuid.UUID, build GovernanceProfileBuild) (types.GovernanceProfile, error)
DeleteGovernanceProfile(ctx context.Context, id uuid.UUID) error
// ListGovernanceProfiles and GetGovernanceProfileChain return RAW rows: a composed row
// carries no authority of its own. Only internal/api/governance_compose.go calls them for
// authority (a source guard fails any other caller); GetGovernanceProfileChain is one
// statement, leaf first, bounded at depth 3, and ErrNotFound when the leaf is gone.
ListGovernanceProfiles(ctx context.Context) ([]types.GovernanceProfile, error)
GetGovernanceProfileChain(ctx context.Context, id uuid.UUID) ([]types.GovernanceProfile, error)
// UpsertGovernanceAssignment keys on the natural UNIQUE (subject_type,
// subject): re-assigning a subject REPOINTS its one row, returning the
// EXISTING row's id on a conflict. ErrNotFound when profile_id names no
// profile (the FK rejects it).
UpsertGovernanceAssignment(ctx context.Context, a types.GovernanceAssignment) (types.GovernanceAssignment, error)
DeleteGovernanceAssignment(ctx context.Context, id uuid.UUID) error
ListGovernanceAssignments(ctx context.Context) ([]types.GovernanceAssignment, error)
// Governance changes (migration 0126): a governance write held for a second human. Part of
// this interface, not an optional seam, because a store without them would let a covered write
// through unreviewed. See governance_changes.go for each one's contract.
ProposeGovernanceChange(ctx context.Context, ch types.GovernanceChange, ttl time.Duration) (types.GovernanceChange, []ExpiredGovernanceChange, error)
ListGovernanceChanges(ctx context.Context, state string) ([]types.GovernanceChange, error)
GetGovernanceChange(ctx context.Context, id uuid.UUID) (types.GovernanceChange, error)
DecideGovernanceChange(ctx context.Context, id uuid.UUID, d GovernanceDecision, fn GovernanceDecideFunc) (types.GovernanceChange, error)
// DryRunGovernance runs fn on a transaction that is always rolled back.
DryRunGovernance(ctx context.Context, fn func(q Querier) error) error
// ResolveGovernanceProfile returns THE ONE profile that applies to a caller — user > group >
// user_type > all, sub over email within the user tier, then priority DESC and name ASC — as a
// single indexed read whose ORDER BY is the whole precedence rule. ErrNotFound means "no
// assignment matched", read as the deployment ceiling. userSubjects must arrive in the caller's
// own precedence order since the query matches by POSITION.
//
// Also returns WHICH TIER matched, load-bearing not informational: on a
// stale/truncated group snapshot the caller must tell a user-tier winner
// (serve it) from an all-tier one (refuse), indistinguishable from the
// profile alone. HasGroupTierAssignments below is that separate read.
ResolveGovernanceProfile(ctx context.Context, userSubjects, groups []string, userType string) (*types.GovernanceProfile, types.CapabilitySubjectType, error)
// HasGroupTierAssignments gates the stale/truncated group-snapshot refusal:
// with no group-tier row there is nothing an unknown group could have
// matched, so a nil or truncated snapshot must fall through rather than
// refuse (see the implementation).
HasGroupTierAssignments(ctx context.Context) (bool, error)
// User drives and their subject grants (migration 0054): admin-registered per-user storage a
// member may mount into a run, and the rows allocating one to a user, group, or everyone.
// SECURITY: same reason as the governance resolver above.
//
// UpsertUserDrive keys on the PRIMARY KEY (fresh id inserts, existing updates in place, rename
// included) and returns ErrConflict when UNIQUE(name) rejects the write. DeleteUserDrive returns
// ErrConflict while the drive is still ALLOCATED (ON DELETE RESTRICT).
//
// refuseIfAllocated is a PRECONDITION: the write applies only while the
// drive has no allocations (ErrDriveAllocated otherwise) — the API's
// re-home guard re-asserts, inside the writing statement, the read
// decision that permitted the write.
UpsertUserDrive(ctx context.Context, d types.UserDrive, refuseIfAllocated bool) (types.UserDrive, error)
GetUserDrive(ctx context.Context, id uuid.UUID) (types.UserDrive, error)
DeleteUserDrive(ctx context.Context, id uuid.UUID) error
// ListUserDrives returns every drive by name WITH its grant count — what makes the console's
// delete affordance honest, since a drive with grants answers 409.
ListUserDrives(ctx context.Context) ([]types.UserDriveListItem, error)
// UpsertUserDriveGrant keys on the natural UNIQUE (subject_type, subject): re-allocating a
// subject REPOINTS its one row, returning the EXISTING row's id on a conflict. ErrNotFound when
// drive_id names no drive (FK). ErrConflict when ANOTHER subject already holds this drive with
// the same home_override — a directory name is one person's, and on a managed drive an override
// is the last way left to point two people at one object Wardyn creates.
//
// homeOverrideStated is the REQUEST's tri-state, not the row's: false means the caller never
// mentioned home_override, and a repoint that never mentioned it must not CLEAR one (see the
// guard in PG's statement) — that same ErrConflict, distinguished from the uniqueness one purely
// by this argument (a stated override disables the re-home guard; an unstated one is empty).
UpsertUserDriveGrant(ctx context.Context, g types.UserDriveGrant, homeOverrideStated bool) (types.UserDriveGrant, error)
// DeleteUserDriveGrant RETURNS the row it removed (ErrNotFound when none
// matched): the delete's own audit row has to name the subject that was
// de-allocated, and by then it is gone.
DeleteUserDriveGrant(ctx context.Context, id uuid.UUID) (types.UserDriveGrant, error)
ListUserDriveGrants(ctx context.Context) ([]types.UserDriveGrant, error)
// ResolveUserDrive mirrors ResolveGovernanceProfile's precedence and
// stale-snapshot reasoning. DISABLED grants stay IN the query: one that
// wins its tier comes back Enabled false, rendered PAUSED rather than
// falling through (a pause must never widen a member onto an unchosen
// drive). Returns the winning GRANT beside the drive since every override
// lives on the binding row. ErrNotFound means "no drive".
ResolveUserDrive(ctx context.Context, userSubjects, groups []string, userType string) (
*types.UserDrive, *types.UserDriveGrant, types.CapabilitySubjectType, error)
// HasGroupTierDriveGrants gates the stale/truncated group-snapshot refusal:
// with no group-tier row there is nothing an unknown group could have
// matched, so a nil or truncated snapshot must fall through rather than
// refuse (see the implementation).
HasGroupTierDriveGrants(ctx context.Context) (bool, error)
// Ping proves the store is actually reachable, not just constructed — the
// /readyz readiness probe's one call. A live TCP connect with no working
// query would otherwise read as healthy forever.
Ping(ctx context.Context) error
}
Store is the abstract persistence seam the control plane talks to. The default Postgres implementation is PG (query bodies in store.go); a future pure-Go SQLite backend satisfies this same interface unchanged.
Out of scope on purpose: transactional surfaces (broker mint FOR UPDATE, identity revocation) need a real transaction and stay on the pool directly.
SECURITY: several method groups below are deliberately part of this interface, not a type-asserted optional seam, because they run on a request-path authz decision — a test double that doesn't implement them would be a compile error instead of a silent fail-open degrade. Each such group is marked SECURITY below with its specific failure mode.
type SuspendPlan ¶ added in v0.8.6
type SuspendPlan struct {
IdentityID uuid.UUID
// Principal is the principal IdentityID's row bound when the plan was made ("" for none). A row that
// binds another under the suspension's lock is ErrIdentityRebound, and nothing is written.
Principal string
// Principals are the principals whose identity rows are deactivated with IdentityID's and whose
// people rows get deactivated_at.
Principals []string
// CutoffSubs are every sub and email form a session cutoff is written for.
CutoffSubs []string
// PurgeAfter schedules the automatic purge that long after the deactivation. Zero schedules
// none; an earlier schedule is kept.
PurgeAfter time.Duration
// PendingJobs are added as pending ledger rows in the same transaction, so a crash after the
// commit still leaves the rest of the suspension for the sweeper. Existing rows are kept.
PendingJobs []JobKey
}
SuspendPlan is what step 1 of a suspension writes, all in one transaction.
type SuspendResult ¶ added in v0.8.6
SuspendResult is step 1's outcome. WasActive says the identity was active before it, so this was a new suspension and not the repair of an old one.
type WorkspacesByOwnerPager ¶ added in v0.6.0
type WorkspacesByOwnerPager interface {
ListWorkspacesPageForOwner(ctx context.Context, owner string, p Page) ([]types.Workspace, error)
}
WorkspacesByOwnerPager is the ownership-scoped analogue of Pager.ListWorkspacesPage: a member's GET /workspaces sees their own owned rows plus the operator-owned ones (owned_by = ”), never another member's. Unlike RunsByCreatorPager, an absent implementation is not fail-closed: the api-layer fallback applies the same owned_by filter in Go before windowing, so scoping still holds.
Source Files
¶
- auditchain.go
- auditfilter.go
- auditpartition.go
- auditretention.go
- auditsplit.go
- doc_keys.go
- governance.go
- governance_changes.go
- iface.go
- locker.go
- pagination.go
- querier.go
- recorder.go
- store.go
- store_ado_run_pats.go
- store_ado_run_pats_read.go
- store_ado_signin_ends.go
- store_apitokens.go
- store_approval_notify.go
- store_approval_once.go
- store_approvals_for_runs.go
- store_attach_leases.go
- store_audit_subject.go
- store_branding.go
- store_capabilities.go
- store_delegates.go
- store_devices.go
- store_ephemeral.go
- store_erasure.go
- store_identity_guard.go
- store_launch_presets.go
- store_leaver.go
- store_leaver_purge.go
- store_people.go
- store_people_directory.go
- store_principal_identities.go
- store_principal_prefs.go
- store_push_paths.go
- store_reauth.go
- store_role_mappings.go
- store_run_capacity.go
- store_run_lease.go
- store_run_lost.go
- store_run_output_chunks.go
- store_run_outputs.go
- store_run_pause.go
- store_run_proxy_config.go
- store_run_reclamp.go
- store_run_revive.go
- store_run_title.go
- store_runs_filtered.go
- store_sandbox_ref.go
- store_scim_groups.go
- store_sources.go
- store_sshkeys.go
- store_ui_layout.go
- store_user_types.go
- store_watcher.go
- store_workspaces.go
- subject_tier.go
- user_drives.go