Documentation
¶
Overview ¶
autoupdate.go stores the fleet's auto-update policy: whether the control plane rolls its executors forward on its own, which release they converge on, and how many move at once (Task 20331).
A sibling of executorsandbox.go and projectlimits.go — an operator's standing policy about a set of devices, held in the control plane, never readable by the devices it governs. The difference is that this one is fleet-wide rather than per-executor; see the migration for why.
Package statedb provides a SQLite-backed persistent store for cloop project state. It replaces the JSON flat-file store with a normalized schema that allows concurrent-safe writes, real SQL queries for reporting, and historical task rows.
Package statedb — typed sentinel errors.
HTTP handlers, the orchestrator, and CLI commands need to distinguish a handful of well-known failure modes from a generic "something went wrong". The Go convention is to expose package-level sentinel errors and have callers use errors.Is to test against them. This file is the authoritative list for cloop's relational data layer.
HTTP mapping (used by pkg/ui and pkg/apiserver via HTTPStatus below):
ErrTaskNotFound → 404 Not Found ErrProjectNotFound → 404 Not Found ErrStaleVersion → 409 Conflict ErrDBLocked → 503 Service Unavailable ErrSchemaMismatch → 500 Internal Server Error ErrCorruptTaskColumn → 500 Internal Server Error
All these errors are safe targets for errors.Is. Internal helpers wrap driver errors with %w so the sentinel survives across package boundaries.
executoraudience.go stores who may run work on one executor.
See migrations/0046_executor_audience.sql for why this is a table rather than a set of role bindings, and pkg/authz/audience.go for the matching semantics. This file is storage only: it does not know who is asking, and deliberately does not decide anything.
executorlimits.go stores the per-executor resource ceiling.
The sibling of projectlimits.go, field for field and failure for failure. The two exist separately because they answer questions that do not reduce to each other: a project's cap travels with the project wherever it is placed, and an executor's cap holds whatever lands on it. See migrations/0045_executor_resource_limits.sql for why neither the fleet ceiling nor the project ceiling can express the second one.
executorsandbox.go stores the per-executor sandbox configuration an admin sets from the UI: whether payloads run on the executor's host or in a container on it, and which engine, runtime, image and network that container uses.
The sibling of projectlimits.go and executors.go's project_executors. All three record an operator's policy about something rather than a fact belonging to it, which is why all three live in the control plane and none is readable — or writable — from the thing they constrain.
firewall.go stores the two dashboard-set levels of the IP-layer egress firewall: one rule set per device, and one per project (Task 20363).
See migrations/0055_egress_firewall_rules.sql for the tables and pkg/fwpolicy for the rule that the project's set, and every virtual executor's firewall, fit inside the device's. This file only stores; the containment decision is made by the caller, inside UpdateFirewalls when the write depends on what it read.
Maintenance helpers for the SQLite state database (Task 20107).
VACUUM reclaims space from rows previously deleted (cloop deletes step rows on `cloop compact`, prunes archived tasks, etc.). ANALYZE refreshes the query planner's statistics so growing tables continue to use sensible indexes. Both operations run as autocommit statements and acquire d.mu so no other goroutine in this process can interleave with them; cross-process contention is bounded by busy_timeout=5000.
Persistence: every successful VACUUM/ANALYZE run is appended to the `maintenance_log` table by AppendMaintenanceLog so:
- cloop db maintain --auto can compare current page_count against the last vacuum's page_count_after to decide whether to skip,
- cloop doctor can surface "last maintenance: 3d ago, freed 4.2 MB",
- operators have a forensic trail when investigating disk-usage spikes.
Schema migration framework for statedb.
Replaces the prior "execute the entire CREATE TABLE IF NOT EXISTS blob on every Open" approach with versioned, append-only .sql files embedded into the binary. Each migration runs inside its own transaction and records itself in schema_migrations on success; a crash mid-migration rolls back cleanly so the next Open re-attempts from the failed version.
Lifecycle:
Open() ──► applyPragmas() ──► Migrate() ──► return *DB
Adding a new migration:
- Create pkg/statedb/migrations/NNNN_<slug>.sql where NNNN is the next unused 4-digit version (e.g. 0002_add_pinned.sql).
- Write idempotent-friendly DDL. Single-statement migrations are safest because the modernc.org/sqlite driver does not natively support executing multiple statements with the binding parameter API; the migration runner therefore splits on `;` boundaries before exec.
- NEVER edit a shipped migration file. Roll forward with another file.
- To add a column a database may already have — one `cloop migrate` or a development build created outside this sequence — write `ALTER TABLE t ADD COLUMN IF NOT EXISTS c <declaration>`. SQLite has no such statement; applyOne runs it as a plain ADD COLUMN when the column is missing and otherwise checks that the existing column is the one declared (see addcolumn.go). A plain ADD COLUMN on such a database fails with "duplicate column name" and stops every start that opens it.
Existing databases (pre-framework) are detected at boot: if all the 0001 tables already exist but schema_migrations is empty, version 1 is recorded as the baseline rather than re-applied. This makes the rollout safe for databases written by older binaries.
projectlimits.go stores the per-project resource ceiling.
The companion to executors.go's project_executors: both record an operator's policy *about* a project rather than a fact belonging to it, which is why both live in the control plane and neither is readable from the repository the project's developers control.
Package statedb — Store interface for the relational data layer. The DB struct (SQLite) implements Store. A future PostgreSQL driver need only implement this interface to be used as a drop-in replacement.
Package statedb — rehydration of the JSON-encoded task columns.
plan_tasks stores six list fields as JSON text: depends_on, tags and annotations since the first schema, and links, on_success and on_failure since 0054 (Task 20361). Decoding them used to be a discarded error per column per row, which made a damaged column indistinguishable from an empty one: the field came back nil, and the load reported success.
For some of them that is a visibility loss. For depends_on it is a correctness bug, because an empty dependency list is not "no information" — it is a positive assertion that the task has no prerequisites, and pm.DepsReady reads it as permission to run. A task whose dependencies were dropped on load is admitted ahead of the work it depends on, defeating the gate silently (Task 20297). on_success and on_failure are the same kind of field: pm.ResolveBranch skips the branch not taken, so an empty list lets both branches of a branched plan run. That asymmetry is why the columns are decoded under different rules rather than one.
Index ¶
- Constants
- Variables
- func AdoptAuditFailureStatus(dir string) (int64, error)
- func AllowSchemaDowngradeFromEnv() bool
- func AuditAdoptRequested(d *DB, in AdoptRequestInput)
- func AuditAnchorLink(a AuditAnchor) (want string, ok bool)
- func AuditAttachSession(d *DB, in AttachAuditInput)
- func AuditCapPause(d *DB, in CapPauseInput)
- func AuditCapResume(d *DB, in CapResumeInput)
- func AuditChainLink(ev AuditEvent) (want string, ok bool)
- func AuditExecutorLifecycle(d *DB, in ExecutorAuditInput)
- func AuditFailureStatusDir(workDir string) string
- func AuditGapLostEvents(payload string) int64
- func AuditImagePolicyDenial(d *DB, in ImagePolicyDenialInput)
- func AuditProjectFirewall(d *DB, in ProjectFirewallAuditInput)
- func AuditProjectLifecycle(d *DB, in ProjectAuditInput)
- func AuditRunReexecuted(d *DB, in RunReexecInput)
- func AuditSecretDecision(d *DB, in SecretAuditInput)
- func AuditTaskDelete(d *DB, taskID int, actor string)
- func AuditTaskDispatch(d *DB, in TaskDispatchInput)
- func AuditTaskQuarantine(d *DB, t *pm.Task, q pm.TaskQuarantine, actor string)
- func AuditTaskQuarantineRelease(d *DB, taskID int, q pm.TaskQuarantine, actor, via string)
- func AuditTaskStatus(d *DB, taskID int, oldStatus, newStatus, actor string)
- func AuditTaskUpsert(d *DB, t *pm.Task, actor string)
- func AuditWorkspaceProvision(d *DB, in WorkspaceAuditInput)
- func CheckSchemaAhead(path string) error
- func DSN(path string, access Access) string
- func FlushAuditGaps(recorded string)
- func GrowthTables() []string
- func HTTPStatus(err error) int
- func LatestSchemaVersion() (int, error)
- func MarshalAuditPayload(v any) string
- func MarshalHandleMeta(meta map[string]string) string
- func OpenConn(path string, access Access) (*sql.DB, error)
- func PeekHubCluster(dbPath, kind string) (members []HubMemberRow, owners []HubOwnerRow, err error)
- func PeekRunOwner(dbPath string) (*runbuild.Owner, error)
- func ProjectMemberID(projectPath, identityKey string) string
- func ProviderCallBodiesPruned(headersJSON string) (time.Time, bool)
- func ReadHubMeta(conn *sql.DB, key string) (string, bool, error)
- func RoleBindingID(effect, claim, value, project, executor string) string
- func SandboxSettingsFor(d *DB, executorID string) (executor.SandboxSettings, error)
- func SealedSetNames() []string
- func SetAuditEnabled(on bool)
- func SetAuditFailureStatusDir(dir string)
- func SetAutoUpdatePolicy(d *DB, p autoupdate.Policy, setBy string) error
- func SetBinaryVersion(v string)
- func SettleAuditFailuresAtExit()
- func UnmarshalHandleMeta(s string) map[string]string
- func UserErrorf(sentinel error, format string, args ...any) error
- func WALPath(dbPath string) string
- func WALSize(dbPath string) (int64, error)
- type APITokenRow
- type Access
- type AdoptRequestInput
- type AgentCredentialRow
- type AppTokenSlotRow
- type AttachAuditInput
- type AuditAnchor
- type AuditChainFailures
- type AuditCheckpointClaim
- type AuditCheckpointWindow
- type AuditEvent
- type AuditFailureStatus
- type AuditFilter
- type AuditGapCount
- type AuditGapPayload
- type AuditGapSummary
- type AuditHead
- type AuditLoss
- type AuditPruneCandidate
- type AuditVerifyReport
- type AutoUpdatePolicy
- type BrokerGrantRow
- type BrokerSecretRow
- type BrokerSecretTombstoneRow
- type CIExchangeRow
- type CIPipelineRuleRow
- type CISessionFilter
- type CISessionRow
- type CapPauseInput
- type CapResumeInput
- type CostEntry
- type DB
- func (d *DB) AbandonKEKs(ids []string, at time.Time) ([]string, error)
- func (d *DB) AcquireHubLease(row HubLeaseRow, expect HubLeaseRow) (bool, error)
- func (d *DB) AddExecutorAudience(executorID, kind, value, addedBy string) error
- func (d *DB) AdjustQuotaCounter(identity, resource, bucket string, delta, limit float64, enforce bool, ...) (value float64, admitted bool, err error)
- func (d *DB) AdvanceSpendCursor(projectPath string, from, to int64) (won bool, err error)
- func (d *DB) AllExecutorAudiences() (map[string][]ExecutorAudienceEntry, error)
- func (d *DB) Analyze() error
- func (d *DB) AppendAuditEvent(ev *AuditEvent) error
- func (d *DB) AppendAuditEvents(evs []*AuditEvent) error
- func (d *DB) AppendCost(entry CostEntry) error
- func (d *DB) AppendHubEvents(events []HubEventRow) (int64, error)
- func (d *DB) AppendMaintenanceLog(e MaintenanceLogEntry) (int64, error)
- func (d *DB) AppendProviderCall(row ProviderCallRow) (int64, error)
- func (d *DB) AppendStep(row StepRow) error
- func (d *DB) AppendTelemetry(events []telemetry.Event) error
- func (d *DB) AsControlPlane() *DB
- func (d *DB) AsProject() *DB
- func (d *DB) AttributeRequestUseTasks() (int, error)
- func (d *DB) AuditCheckpointWindowMarker() (AuditCheckpointWindow, bool, error)
- func (d *DB) AuditDistinctActors() ([]string, error)
- func (d *DB) AuditDistinctEntityTypes() ([]string, error)
- func (d *DB) AuditGapSummary() (AuditGapSummary, error)
- func (d *DB) AuditHead() (AuditHead, error)
- func (d *DB) AuditRowAt(id int64) (AuditEvent, bool, error)
- func (d *DB) BindProjectExecutor(projectPath, executorID, boundBy string) error
- func (d *DB) BrokerMeta(key string) (string, bool, error)
- func (d *DB) CheckpointCISession(id, holder, counters string, lastUsed time.Time) (bool, error)
- func (d *DB) CheckpointProxySession(kind, id, holder, counters string) (bool, error)
- func (d *DB) ClaimAuditCheckpointWindow(w int64, interval time.Duration, member string, now time.Time, ...) (AuditCheckpointClaim, error)
- func (d *DB) ClaimExecutorHandleMeta(handleID, key, expect, value string) (bool, error)
- func (d *DB) ClaimExecutorSessionRequeue(id, claimToken, newClaimToken string, maxAttempts int, at time.Time) (ExecutorSessionRow, error)
- func (d *DB) ClaimHubOwner(row, expect HubOwnerRow) (bool, error)
- func (d *DB) ClaimProjectPath(claim ProjectClaim, stale func(ProjectClaim) bool) (held *ProjectClaim, err error)
- func (d *DB) ClearAdoptRequest(id string) (bool, error)
- func (d *DB) ClearExecutorAudience(executorID string) error
- func (d *DB) ClearExecutorFirewall(executorID string) error
- func (d *DB) ClearExecutorResourceLimit(executorID string) error
- func (d *DB) ClearExecutorSandbox(executorID string) error
- func (d *DB) ClearHubLease(scope string, expect HubLeaseRow, at time.Time) (bool, error)
- func (d *DB) ClearKill(taskID int) error
- func (d *DB) ClearProjectFirewall(projectPath string) error
- func (d *DB) ClearProjectResourceLimit(projectPath string) error
- func (d *DB) ClearTaskQuarantine(taskID int) (bool, error)
- func (d *DB) Close() error
- func (d *DB) CloseCISession(id, holder string, at time.Time, reason, counters string) (bool, error)
- func (d *DB) CloseCISessionAny(id string, at time.Time, reason string) (bool, error)
- func (d *DB) CloseCISessionsForRule(ruleID string, at time.Time, reason string) ([]CISessionRow, error)
- func (d *DB) CloseExecutorSession(id, state string, at time.Time) error
- func (d *DB) CloseProxySession(kind, id, holder string, at time.Time, reason, counters string) (bool, error)
- func (d *DB) CompleteAuditCheckpointWindow(w int64, member string) (bool, error)
- func (d *DB) CompleteProjectClaim(path string, hubMade bool, root string) error
- func (d *DB) CountBrokerSecretsByKey() (map[string]int, error)
- func (d *DB) CountDeviceAuthorizations(since time.Time) (int, error)
- func (d *DB) CountEvents() (int, error)
- func (d *DB) CountHubTLSByKey() (map[string]int, error)
- func (d *DB) CountLiveSessions(c SessionCutoffs) (int, error)
- func (d *DB) CountRunningExecutorSessions(executorID string) (int, error)
- func (d *DB) CountSessionsByKey() (map[string]int, error)
- func (d *DB) CreateVirtualExecutor(v VirtualExecutor) error
- func (d *DB) CurrentSchemaVersion() (int, error)
- func (d *DB) DeleteAppTokenSlot(leaseID, grantID, holder string) (bool, error)
- func (d *DB) DeleteAppTokenSlots(leaseID, holder string) (int, error)
- func (d *DB) DeleteBrokerSecret(id string) error
- func (d *DB) DeleteBrokerSecretTombstoned(id string, tomb BrokerSecretTombstoneRow) error
- func (d *DB) DeleteCIPipelineRule(id string) (bool, error)
- func (d *DB) DeleteCISession(id, holder string) (bool, error)
- func (d *DB) DeleteDeviceAuthorizationsBefore(cutoff time.Time) ([]DeviceAuthorizationRow, error)
- func (d *DB) DeleteDispatchIntent(runID string) error
- func (d *DB) DeleteDispatchIntentForHandle(executorID, handleID string) (bool, error)
- func (d *DB) DeleteExecutor(id string) error
- func (d *DB) DeleteExecutorHandle(handleID string) error
- func (d *DB) DeleteExecutorHealth(executorID string) error
- func (d *DB) DeleteExpiredSessions(c SessionCutoffs) ([]SessionRow, error)
- func (d *DB) DeleteHubMeta(key string) error
- func (d *DB) DeleteLegalHold(identity string, audit *AuditEvent) (bool, error)
- func (d *DB) DeleteOrphanedAppTokenSlots() (int, error)
- func (d *DB) DeleteProjectMember(projectPath, identityKey string, audit MemberAudit) (*ProjectMemberRow, error)
- func (d *DB) DeleteProjectMembersOf(projectPath string, audit MemberAudit) ([]ProjectMemberRow, error)
- func (d *DB) DeleteProxySession(kind, id, holder string) (bool, error)
- func (d *DB) DeleteQuotaOverride(identity string) (bool, error)
- func (d *DB) DeleteRoleBinding(id string) (bool, error)
- func (d *DB) DeleteSCIMGroup(id string, audit []*AuditEvent) (bool, error)
- func (d *DB) DeleteSCIMUser(id string, audit []*AuditEvent) (bool, error)
- func (d *DB) DeleteSecretLease(leaseID, holder string) (bool, error)
- func (d *DB) DeleteSecretLeaseDir(dir string) error
- func (d *DB) DeleteSession(id string) (bool, error)
- func (d *DB) DeleteSessionsBySubject(subject, keepID string) ([]SessionRow, error)
- func (d *DB) DeleteTask(id int) error
- func (d *DB) DeleteVirtualExecutor(id string) error
- func (d *DB) ExecutorAudience(executorID string) ([]ExecutorAudienceEntry, error)
- func (d *DB) ExecutorFirewall(executorID string) (FirewallRecord, bool, error)
- func (d *DB) ExecutorResourceCeiling(executorID string) (executor.ResourceCeiling, bool, error)
- func (d *DB) ExecutorSandboxRecord(executorID string) (ExecutorSandbox, bool, error)
- func (d *DB) ExecutorSandboxSettings(executorID string) (executor.SandboxSettings, bool, error)
- func (d *DB) ExecutorSessionChain(id string) ([]ExecutorSessionRow, error)
- func (d *DB) ExecutorSessionForHandle(executorID, handleID string) (ExecutorSessionRow, bool, error)
- func (d *DB) ExecutorSessionSuccessor(id string) (string, bool, error)
- func (d *DB) ExpireGrantRequests(now time.Time) ([]GrantRequestRow, error)
- func (d *DB) ExtendProxySession(kind, id, holder string, expiresAt time.Time) (bool, error)
- func (d *DB) ExtendSecretLease(leaseID, holder string, expiresAt time.Time) (bool, error)
- func (d *DB) FindSCIMGroups(byDisplayName bool, value string) ([]SCIMGroupRow, error)
- func (d *DB) FindSCIMUsers(column, value string) ([]SCIMUserRow, error)
- func (d *DB) GetAPIToken(id string) (APITokenRow, error)
- func (d *DB) GetAgentCredential(agentID string) (AgentCredentialRow, error)
- func (d *DB) GetBrokerGrant(id string) (BrokerGrantRow, error)
- func (d *DB) GetBrokerSecret(id string) (BrokerSecretRow, error)
- func (d *DB) GetBrokerSecretTombstone(secretID string) (BrokerSecretTombstoneRow, error)
- func (d *DB) GetCIPipelineRule(id string) (CIPipelineRuleRow, error)
- func (d *DB) GetCISession(id string) (CISessionRow, error)
- func (d *DB) GetConfigBlob() (string, error)
- func (d *DB) GetDeviceAuthorization(deviceHash string) (DeviceAuthorizationRow, error)
- func (d *DB) GetDeviceAuthorizationByUserCode(userCodeHash string) (DeviceAuthorizationRow, error)
- func (d *DB) GetDispatchIntent(runID string) (DispatchIntentRow, error)
- func (d *DB) GetEgressGrant(id string) (EgressGrantRow, error)
- func (d *DB) GetEnrollmentToken(id string) (EnrollmentTokenRow, error)
- func (d *DB) GetExecutor(id string) (ExecutorRow, error)
- func (d *DB) GetExecutorHandle(handleID string) (ExecutorHandleRow, error)
- func (d *DB) GetExecutorHealth(executorID string) (ExecutorHealthRow, error)
- func (d *DB) GetExecutorSession(id string) (ExecutorSessionRow, error)
- func (d *DB) GetGrantRequest(id string) (GrantRequestRow, error)
- func (d *DB) GetHubLease(scope string) (HubLeaseRow, error)
- func (d *DB) GetHubOwner(kind, key string) (HubOwnerRow, error)
- func (d *DB) GetHubTLS(id string) (HubTLSRow, error)
- func (d *DB) GetProjectMember(projectPath, identityKey string) (ProjectMemberRow, error)
- func (d *DB) GetProxySession(kind, id string) (ProxySessionRow, error)
- func (d *DB) GetRoleBinding(id string) (RoleBindingRow, error)
- func (d *DB) GetSCIMCredential(id string) (SCIMCredentialRow, error)
- func (d *DB) GetSCIMGroup(id string) (SCIMGroupRow, error)
- func (d *DB) GetSCIMUser(id string) (SCIMUserRow, error)
- func (d *DB) GetSecretLease(leaseID string) (SecretLeaseRow, error)
- func (d *DB) GetSession(id string) (SessionRow, error)
- func (d *DB) GrowthTableStats() ([]TableStat, error)
- func (d *DB) HasProjectState() (bool, error)
- func (d *DB) HeartbeatHubMember(instanceID string, at time.Time) (bool, error)
- func (d *DB) History(q HistoryQuery) (HistoryPage, error)
- func (d *DB) HistoryEvent(id int64) (*EventRow, error)
- func (d *DB) HistoryStep(n int64) (*StepRow, error)
- func (d *DB) HistoryTop() (HistoryCursor, error)
- func (d *DB) HubEventBounds() (lowest, highest, issued int64, err error)
- func (d *DB) HubEventsAfter(after int64, limit int) ([]HubEventRow, error)
- func (d *DB) HubMeta(key string) (string, bool, error)
- func (d *DB) InsertCISession(row CISessionRow) error
- func (d *DB) InsertHubTLS(row HubTLSRow) (inserted bool, err error)
- func (d *DB) InsertSCIMCredential(c SCIMCredentialRow, audit *AuditEvent) error
- func (d *DB) JoinHubMember(row HubMemberRow) error
- func (d *DB) LastMaintenanceLog() (*MaintenanceLogEntry, error)
- func (d *DB) LatestAuditAnchor() (AuditAnchor, error)
- func (d *DB) LeaseRevocations(leaseID string) ([]LeaseRevocationRow, error)
- func (d *DB) LeaveHubMember(instanceID string, at time.Time) error
- func (d *DB) LegalHoldFor(identities []string) (LegalHoldRow, bool, error)
- func (d *DB) ListAPITokens() ([]APITokenRow, error)
- func (d *DB) ListAgentCredentials() ([]AgentCredentialRow, error)
- func (d *DB) ListAppTokenSlots(leaseID string) ([]AppTokenSlotRow, error)
- func (d *DB) ListAuditAnchors() ([]AuditAnchor, error)
- func (d *DB) ListAuditEvents(f AuditFilter) (rows []AuditEvent, total int, err error)
- func (d *DB) ListBrokerGrants() ([]BrokerGrantRow, error)
- func (d *DB) ListBrokerSecrets() ([]BrokerSecretRow, error)
- func (d *DB) ListBrokerSecretsNotUnderKey(keyID string, limit int) ([]SealedRow, error)
- func (d *DB) ListCIExchanges(limit int) ([]CIExchangeRow, error)
- func (d *DB) ListCIPipelineRules() ([]CIPipelineRuleRow, error)
- func (d *DB) ListCISessions(f CISessionFilter) ([]CISessionRow, error)
- func (d *DB) ListDispatchIntents() ([]DispatchIntentRow, error)
- func (d *DB) ListEgressGrants() ([]EgressGrantRow, error)
- func (d *DB) ListEnrollmentTokens() ([]EnrollmentTokenRow, error)
- func (d *DB) ListEvents(offset, limit int) (rows []EventRow, total int, err error)
- func (d *DB) ListExecutorFirewalls() ([]FirewallRecord, error)
- func (d *DB) ListExecutorHandles(executorID string) ([]ExecutorHandleRow, error)
- func (d *DB) ListExecutorHealth() ([]ExecutorHealthRow, error)
- func (d *DB) ListExecutorResourceLimits() ([]ExecutorResourceLimit, error)
- func (d *DB) ListExecutorSandboxes() ([]ExecutorSandbox, error)
- func (d *DB) ListExecutorSessions(executorID string, onlyRunning bool) ([]ExecutorSessionRow, error)
- func (d *DB) ListExecutors() ([]ExecutorRow, error)
- func (d *DB) ListGrantRequestUses(requestID string) ([]GrantRequestUseRow, error)
- func (d *DB) ListGrantRequests() ([]GrantRequestRow, error)
- func (d *DB) ListHubMembers() ([]HubMemberRow, error)
- func (d *DB) ListHubOwners(kind string) ([]HubOwnerRow, error)
- func (d *DB) ListHubTLS() ([]HubTLSRow, error)
- func (d *DB) ListHubTLSNotUnderKey(keyID string, limit int) ([]HubTLSRow, error)
- func (d *DB) ListKEKs() ([]KEKRow, error)
- func (d *DB) ListLeaseRevocations(pendingOnly bool) ([]LeaseRevocationRow, error)
- func (d *DB) ListLegalHolds() ([]LegalHoldRow, error)
- func (d *DB) ListProjectClaims() ([]ProjectClaim, error)
- func (d *DB) ListProjectExecutorBindings() ([]ProjectExecutorBinding, error)
- func (d *DB) ListProjectFirewalls() ([]FirewallRecord, error)
- func (d *DB) ListProjectMembers() ([]ProjectMemberRow, error)
- func (d *DB) ListProjectResourceLimits() ([]ProjectResourceLimit, error)
- func (d *DB) ListProviderCalls(offset, limit, taskID int, provider string) (rows []ProviderCallRow, total int, err error)
- func (d *DB) ListProxySessions(f ProxySessionFilter) ([]ProxySessionRow, error)
- func (d *DB) ListQuotaCounters() ([]QuotaCounterRow, error)
- func (d *DB) ListQuotaOverrides() ([]QuotaOverrideRow, error)
- func (d *DB) ListRetiredStaticTokens() ([]RetiredStaticTokenRow, error)
- func (d *DB) ListRoleBindings() ([]RoleBindingRow, error)
- func (d *DB) ListRotations(limit int) ([]RotationRow, error)
- func (d *DB) ListSCIMCredentials() ([]SCIMCredentialRow, error)
- func (d *DB) ListSCIMGroups(withMembers bool) ([]SCIMGroupRow, error)
- func (d *DB) ListSCIMUsers() ([]SCIMUserRow, error)
- func (d *DB) ListSecretLeaseDirs() ([]SecretLeaseDirRow, error)
- func (d *DB) ListSecretLeases() ([]SecretLeaseRow, error)
- func (d *DB) ListSessions() ([]SessionRow, error)
- func (d *DB) ListSessionsNotUnderKey(keyID string, limit int) ([]SealedRow, error)
- func (d *DB) ListStaticTokenUse() ([]StaticTokenUseRow, error)
- func (d *DB) ListTaskQuarantines() (map[int]*pm.TaskQuarantine, error)
- func (d *DB) ListTelemetrySessions(source string, limit int) ([]TelemetrySession, error)
- func (d *DB) ListVirtualExecutors() ([]VirtualExecutor, error)
- func (d *DB) LoadProviderCall(id int64) (*ProviderCallRow, error)
- func (d *DB) LoadSCIMDirectory() (SCIMDirectory, error)
- func (d *DB) LoadSpendCursor(projectPath string) (SpendCursor, bool, error)
- func (d *DB) LoadState() (*State, error)
- func (d *DB) LoadStateLite() (*State, error)
- func (d *DB) LoadTask(id int) (*pm.Task, error)
- func (d *DB) LookupKill(taskID int) (KillRequest, bool, error)
- func (d *DB) MarkDispatchStarted(runID, handleID string, egressIDs []string) (bool, error)
- func (d *DB) MarkHubSeen(kind, key string, expires, now time.Time) (bool, error)
- func (d *DB) MarkLeaseRevocationEnforced(leaseID, grantID, by, detail string, at time.Time) (bool, error)
- func (d *DB) MarkSCIMUserOffboarded(id string, at time.Time, audit []*AuditEvent) (bool, error)
- func (d *DB) MaxAuditID() (int64, error)
- func (d *DB) MaxCostRowID() (int64, error)
- func (d *DB) MonthlyCosts(year, month int) ([]CostEntry, error)
- func (d *DB) NarrowCISession(id, holder, instance, policy string, expiresAt time.Time) (bool, error)
- func (d *DB) NoteDispatchIntent(runID, detail string) error
- func (d *DB) NoteLeaseRevocation(leaseID, grantID, detail string) error
- func (d *DB) OffboardIdentity(w OffboardWrite) (OffboardApplied, error)
- func (d *DB) OpenCISessionIDsHeldBy(holder string) ([]string, error)
- func (d *DB) OpenExecutorSession(row ExecutorSessionRow) error
- func (d *DB) OpenSpendCursor(projectPath, identity string, startAt int64) error
- func (d *DB) Path() string
- func (d *DB) PendingKills() ([]KillRequest, error)
- func (d *DB) PendingSCIMOffboards(cutoff time.Time) ([]SCIMUserRow, error)
- func (d *DB) PingContext(ctx context.Context) error
- func (d *DB) PlanAuditPrune(cutoff time.Time) (AuditPruneCandidate, error)
- func (d *DB) PrimaryKEK() (KEKRow, bool, error)
- func (d *DB) ProjectClaimAt(path string) (ProjectClaim, bool, error)
- func (d *DB) ProjectExecutor(projectPath string) (string, bool, error)
- func (d *DB) ProjectFirewall(projectPath string) (FirewallRecord, bool, error)
- func (d *DB) ProjectResourceCeiling(projectPath string) (executor.ResourceCeiling, bool, error)
- func (d *DB) PromoteKEK(id string, at time.Time) error
- func (d *DB) PruneAuditPrefix(a AuditAnchor) (AuditAnchor, error)
- func (d *DB) PruneCIExchanges(keep int) (int, error)
- func (d *DB) PruneCosts(p RowRetention, now time.Time, dryRun bool) (RowPruneResult, error)
- func (d *DB) PruneEvents(p RowRetention, now time.Time, dryRun bool) (RowPruneResult, error)
- func (d *DB) PruneHubEvents(cutoff time.Time) (int64, error)
- func (d *DB) PruneHubMembers(cutoff time.Time) (int64, error)
- func (d *DB) PruneHubSeen(now time.Time) (int64, error)
- func (d *DB) PruneLeaseRevocations(cutoff time.Time) (int64, error)
- func (d *DB) PruneProviderCalls(p ProviderCallRetention, now time.Time, dryRun bool) (ProviderCallPruneResult, error)
- func (d *DB) PruneQuotaCounters(bucket string) error
- func (d *DB) PruneSteps(p RowRetention, now time.Time, dryRun bool) (RowPruneResult, error)
- func (d *DB) PruneTelemetry(cutoff time.Time) (int64, error)
- func (d *DB) PruneTelemetryRows(p RowRetention, now time.Time, dryRun bool) (RowPruneResult, error)
- func (d *DB) PutAPIToken(row APITokenRow) error
- func (d *DB) PutAgentCredential(row AgentCredentialRow) error
- func (d *DB) PutAppTokenSlot(row AppTokenSlotRow) error
- func (d *DB) PutBrokerGrant(row BrokerGrantRow) error
- func (d *DB) PutBrokerSecret(row BrokerSecretRow) error
- func (d *DB) PutCIExchange(row CIExchangeRow) error
- func (d *DB) PutCIPipelineRule(row CIPipelineRuleRow) error
- func (d *DB) PutDeviceAuthorization(row DeviceAuthorizationRow) error
- func (d *DB) PutDispatchIntent(row DispatchIntentRow) error
- func (d *DB) PutEgressGrant(row EgressGrantRow) error
- func (d *DB) PutEnrollmentToken(row EnrollmentTokenRow) error
- func (d *DB) PutExecutorHandle(row ExecutorHandleRow) error
- func (d *DB) PutExecutorHealth(row ExecutorHealthRow) error
- func (d *DB) PutGrantRequest(row GrantRequestRow) error
- func (d *DB) PutGrantRequestUse(row GrantRequestUseRow) error
- func (d *DB) PutHubOwner(row HubOwnerRow) error
- func (d *DB) PutKEK(row KEKRow) error
- func (d *DB) PutLeaseRevocation(row LeaseRevocationRow) error
- func (d *DB) PutLegalHold(h LegalHoldRow, audit *AuditEvent) error
- func (d *DB) PutProjectMember(row ProjectMemberRow, audit MemberAudit) (ProjectMemberRow, *ProjectMemberRow, error)
- func (d *DB) PutProxySession(row ProxySessionRow) error
- func (d *DB) PutQuotaCounter(row QuotaCounterRow) error
- func (d *DB) PutQuotaOverride(row QuotaOverrideRow) error
- func (d *DB) PutRoleBinding(row RoleBindingRow) (RoleBindingRow, error)
- func (d *DB) PutRotation(row RotationRow) error
- func (d *DB) PutSecretLease(row SecretLeaseRow) error
- func (d *DB) PutSecretLeaseDir(row SecretLeaseDirRow) error
- func (d *DB) PutSession(row SessionRow) error
- func (d *DB) PutTaskQuarantine(taskID int, q pm.TaskQuarantine) error
- func (d *DB) QueryTelemetry(f TelemetryFilter) ([]telemetry.Event, int, error)
- func (d *DB) ReadAuditRange(fromID, throughID int64, limit int) ([]AuditEvent, error)
- func (d *DB) ReadCosts() ([]CostEntry, error)
- func (d *DB) ReadCostsAfterID(afterID int64, limit int) ([]CostEntry, error)
- func (d *DB) ReadCostsSince(since time.Time) ([]CostEntry, error)
- func (d *DB) ReconstructTask(taskID int) (TaskStory, error)
- func (d *DB) RecordEvent(row EventRow) error
- func (d *DB) RecordTaskNodeLoss(taskID int, loss pm.NodeLoss) (bool, error)
- func (d *DB) RedeemEnrollmentToken(id, agentID string, at time.Time) error
- func (d *DB) ReleaseHubLease(scope, instanceID string, at time.Time) (bool, error)
- func (d *DB) ReleaseHubOwner(kind, key, instanceID string) (bool, error)
- func (d *DB) ReleaseHubOwnerIfClaim(expect HubOwnerRow) (bool, error)
- func (d *DB) ReleaseProjectClaim(path string) error
- func (d *DB) RemoveExecutorAudience(executorID, kind, value string) error
- func (d *DB) RenewHubLease(scope, instanceID string, at time.Time) (bool, error)
- func (d *DB) ReplaceBrokerSecretSealed(id string, expect, next SealedRow) (bool, error)
- func (d *DB) ReplaceHubTLS(next HubTLSRow, expectSerial string) (bool, error)
- func (d *DB) ReplaceHubTLSSealed(id string, expect, next SealedRow) (bool, error)
- func (d *DB) ReplaceQuotaGauges(rows []QuotaCounterRow) error
- func (d *DB) ReplaceSessionSealed(id string, expect, next SealedRow) (bool, error)
- func (d *DB) ReportStaticTokenUse(reports []StaticTokenUseReport) error
- func (d *DB) RequestKill(req KillRequest) error
- func (d *DB) RetireKEK(id string, at time.Time) error
- func (d *DB) RetireStaticToken(row RetiredStaticTokenRow, ev *AuditEvent) (stored RetiredStaticTokenRow, written bool, err error)
- func (d *DB) RevokeAPIToken(id string, at time.Time) error
- func (d *DB) RevokeAgentCredential(agentID string, at time.Time) error
- func (d *DB) RevokeBrokerGrant(id string, at time.Time) error
- func (d *DB) RevokeBrokerGrantWithCause(id string, at time.Time, cause string) error
- func (d *DB) RevokeEgressGrant(id string, at time.Time) error
- func (d *DB) RevokeEnrollmentToken(id string, at time.Time) error
- func (d *DB) RevokeSCIMCredential(id string, at time.Time, by string, audit *AuditEvent) (bool, error)
- func (d *DB) RewriteSecretLeaseRecord(leaseID, holder, record string) (bool, error)
- func (d *DB) Role() Role
- func (d *DB) RotateSCIMCredential(id, secretHash, previousHash string, previousExpires, at time.Time, by string, ...) error
- func (d *DB) SCIMDirectoryVersion() (int64, error)
- func (d *DB) SCIMGroupsOf(userID string) ([]string, error)
- func (d *DB) SaveAdoptRequest(r *runbuild.Request) error
- func (d *DB) SaveCommitPolicy(p *pm.CommitPolicy) error
- func (d *DB) SaveFollowBuilds(on bool) error
- func (d *DB) SaveReviewGate(g *pm.ReviewGate) error
- func (d *DB) SaveRunOwner(o *runbuild.Owner) error
- func (d *DB) SaveRunStatus(status string, reason *pausereason.Reason, updatedAt time.Time) error
- func (d *DB) SaveState(s *State) error
- func (d *DB) SchemaStamp() (SchemaStamp, error)
- func (d *DB) SessionsDueForRefresh(cutoff time.Time, limit int) ([]SessionRow, error)
- func (d *DB) SetBrokerGrantUnguardedAck(id, at, by, reason string) error
- func (d *DB) SetBrokerMeta(key, value string) error
- func (d *DB) SetConfigBlob(yamlBlob string) error
- func (d *DB) SetExecutorFirewall(executorID string, r executor.FirewallRules, setBy string) error
- func (d *DB) SetExecutorResourceLimit(executorID string, c executor.ResourceCeiling, setBy string) error
- func (d *DB) SetExecutorSandbox(executorID string, s executor.SandboxSettings, setBy string) error
- func (d *DB) SetExecutorSessionRunningTasks(id string, tasks []int) (bool, error)
- func (d *DB) SetHubMeta(key, value string) error
- func (d *DB) SetHubMetaIfAbsent(key, value string) (string, error)
- func (d *DB) SetProjectFirewall(projectPath string, r executor.FirewallRules, setBy string) error
- func (d *DB) SetProjectResourceLimit(projectPath string, c executor.ResourceCeiling, setBy string) error
- func (d *DB) SetQueryOnly(on bool) error
- func (d *DB) SizeStats() (SizeStats, error)
- func (d *DB) SpendByIdentity(from, to time.Time) ([]IdentitySpend, error)
- func (d *DB) SupersedeBrokerGrant(id string, at time.Time, successor string) error
- func (d *DB) TakeAppTokenSlots(leaseID, from, holder string) (int, error)
- func (d *DB) TakeCISession(id, from, holder, instance string) (bool, error)
- func (d *DB) TakeProxySession(kind, id, from, holder string) (bool, error)
- func (d *DB) TakeSecretLease(leaseID, from, holder string) (bool, error)
- func (d *DB) TaskNodeLosses(taskID int) ([]pm.NodeLoss, error)
- func (d *DB) TaskQuarantine(taskID int) (*pm.TaskQuarantine, error)
- func (d *DB) TaskRunID(taskID int) (string, bool, error)
- func (d *DB) TaskStatuses() (map[int]pm.TaskStatus, error)
- func (d *DB) TouchAPIToken(id string, at time.Time) error
- func (d *DB) TouchAgentCredential(agentID string, at time.Time) error
- func (d *DB) TouchCIPipelineRule(id string, at time.Time) error
- func (d *DB) TouchExecutorHeartbeat(id, status string, at time.Time) error
- func (d *DB) TouchSCIMCredential(id string, at time.Time) error
- func (d *DB) TouchSession(id string, t time.Time) error
- func (d *DB) UnbindProjectExecutor(projectPath string) error
- func (d *DB) UpdateAppTokenSlot(row AppTokenSlotRow) (bool, error)
- func (d *DB) UpdateDeviceAuthorization(deviceHash string, change func(*DeviceAuthorizationRow) (bool, error)) (DeviceAuthorizationRow, error)
- func (d *DB) UpdateFirewalls(fn func(*FirewallTx) error) error
- func (d *DB) UpdateHubOwnerMeta(kind, key, instanceID, meta string, at time.Time) (bool, error)
- func (d *DB) UpdateSessionRefresh(id string, up SessionRefreshUpdate) error
- func (d *DB) UpdateVirtualExecutor(id, name string, spec executor.VirtualSpec, by string) error
- func (d *DB) UpsertExecutor(row ExecutorRow) error
- func (d *DB) UpsertTask(t *pm.Task) error
- func (d *DB) Vacuum() error
- func (d *DB) VacuumInto(outPath string) error
- func (d *DB) VerifyAuditChain() (AuditVerifyReport, error)
- func (d *DB) VirtualExecutor(id string) (VirtualExecutor, bool, error)
- func (d *DB) WALCheckpointTruncate() (string, error)
- func (d *DB) WriteSCIMGroup(w SCIMGroupWrite) (SCIMGroupApplied, error)
- func (d *DB) WriteSCIMUser(w SCIMUserWrite) (SCIMUserApplied, error)
- type DeviceAuthorizationRow
- type DispatchIntentRow
- type EgressGrantRow
- type EnrollmentTokenRow
- type EventRow
- type EventType
- type ExecutorAudienceEntry
- type ExecutorAuditInput
- type ExecutorHandleRow
- type ExecutorHealthRow
- type ExecutorInventory
- type ExecutorResourceLimit
- type ExecutorRow
- type ExecutorSandbox
- type ExecutorSessionRow
- type FirewallRecord
- type FirewallTx
- func (t *FirewallTx) ClearExecutorFirewall(executorID string) error
- func (t *FirewallTx) ClearProjectFirewall(projectPath string) error
- func (t *FirewallTx) CreateVirtualExecutor(v VirtualExecutor) error
- func (t *FirewallTx) ExecutorFirewall(executorID string) (FirewallRecord, bool, error)
- func (t *FirewallTx) ListProjectFirewalls() ([]FirewallRecord, error)
- func (t *FirewallTx) ProjectExecutor(projectPath string) (string, bool, error)
- func (t *FirewallTx) ProjectFirewall(projectPath string) (FirewallRecord, bool, error)
- func (t *FirewallTx) ProjectsBoundTo(ids ...string) ([]string, error)
- func (t *FirewallTx) SetExecutorFirewall(executorID string, r executor.FirewallRules, setBy string) error
- func (t *FirewallTx) SetProjectFirewall(projectPath string, r executor.FirewallRules, setBy string) error
- func (t *FirewallTx) SetVirtualExecutorSpec(id string, spec executor.VirtualSpec, by string) error
- func (t *FirewallTx) UpdateVirtualExecutor(id, name string, spec executor.VirtualSpec, by string) error
- func (t *FirewallTx) VirtualExecutor(id string) (VirtualExecutor, bool, error)
- func (t *FirewallTx) VirtualExecutorsOf(parentID string) ([]VirtualExecutor, error)
- type GrantRequestRow
- type GrantRequestUseRow
- type HistoryCursor
- type HistoryPage
- type HistoryPlace
- type HistoryQuery
- type HistoryRow
- type HubEventRow
- type HubLeaseRow
- type HubMemberRow
- type HubOwnerRow
- type HubTLSRow
- type IdentitySpend
- type ImagePolicyDenialInput
- type KEKRow
- type KillRequest
- type LeaseRevocationRow
- type LegalHoldRow
- type MaintenanceLogEntry
- type MemberAudit
- type MigrateOptions
- type MigrationCompat
- type MigrationReport
- type OffboardApplied
- type OffboardWrite
- type OpenOptions
- type ProjectAuditInput
- type ProjectClaim
- type ProjectExecutorBinding
- type ProjectFirewallAuditInput
- type ProjectMemberRow
- type ProjectResourceLimit
- type ProviderCallPruneResult
- type ProviderCallRetention
- type ProviderCallRow
- type ProxySessionFilter
- type ProxySessionRow
- type QuarantinedTask
- type QuotaCounterRow
- type QuotaOverrideRow
- type RetiredStaticTokenRow
- type Role
- type RoleBindingRow
- type RotationRow
- type RowPruneResult
- type RowRetention
- type RunReexecInput
- type SCIMConflict
- type SCIMCredentialRow
- type SCIMDirectory
- type SCIMDirectoryGroup
- type SCIMDirectoryUser
- type SCIMGroupApplied
- type SCIMGroupRow
- type SCIMGroupWrite
- type SCIMSuspendWrite
- type SCIMSuspensionRecord
- type SCIMUnique
- type SCIMUserApplied
- type SCIMUserRow
- type SCIMUserWrite
- type SchemaStamp
- type SchemaState
- type SchemaTooNewError
- type SealedFacts
- type SealedRow
- type SecretAuditInput
- type SecretLeaseDirRow
- type SecretLeaseRow
- type SessionClaims
- type SessionCutoffs
- type SessionRefreshUpdate
- type SessionRow
- type SizeStats
- type SpendCursor
- type State
- type StaticTokenUseReport
- type StaticTokenUseRow
- type StepRow
- type Store
- type TableStat
- type TaskDispatchInput
- type TaskRunStory
- type TaskStory
- type TelemetryFilter
- type TelemetrySession
- type VersionDivergence
- type VirtualExecutor
- type WALCheckpoint
- type WorkspaceAuditInput
Constants ¶
const ( // AuditChainIntact: every row verified and none records a loss. AuditChainIntact = "intact" // AuditChainGaps: every row verified, and some are audit.gap rows // recording events that could not be appended. AuditChainGaps = "gaps" // AuditChainBroken: a row failed verification. AuditChainBroken = "broken" )
Verdicts a chain verification can reach, from AuditVerifyReport.Status.
const ( // GapRecordedOnRecovery: ahead of the next append that succeeded. GapRecordedOnRecovery = "recovery" // GapRecordedByFlush: by the background reporter, on its own. GapRecordedByFlush = "flush" // GapRecordedAtShutdown: by a hub shutting down cleanly. GapRecordedAtShutdown = "shutdown" // GapRecordedAtExit: by a CLI command finishing. GapRecordedAtExit = "exit" )
How a gap row came to be written, recorded in its payload.
const ( // DispatchIntentDispatching: the executor has been, or is about to be, // asked to start the workload, and has not answered. DispatchIntentDispatching = "dispatching" // DispatchIntentStarted: the executor answered with a handle. DispatchIntentStarted = "started" )
Dispatch intent states.
const ( // ExecutorSessionRunning: work is in flight on the executor. ExecutorSessionRunning = "running" // ExecutorSessionRequeued: a supervisor claimed the session for failover // and the work has been handed to another executor. ExecutorSessionRequeued = "requeued" // ExecutorSessionFinished: the work completed on this executor. ExecutorSessionFinished = "finished" // ExecutorSessionFailed: the work ended in failure and was not requeued. ExecutorSessionFailed = "failed" // ExecutorSessionFailoverExhausted: the executor went unreachable after // the session had already been re-dispatched as often as // executors.failover.max_attempts allows (Task 20391). The claim closed // it in this state instead of requeued, and nothing re-dispatches it. ExecutorSessionFailoverExhausted = "failover_exhausted" )
Executor session states as persisted in the state column.
const ( ExecutorStatusOnline = "online" ExecutorStatusOffline = "offline" ExecutorStatusDegraded = "degraded" ExecutorStatusUnknown = "unknown" )
Executor health states as persisted in the status column.
const ( // ProjectClaimCreating: a creation holds the path while it makes the // directory and initialises it. ProjectClaimCreating = "creating" // ProjectClaimCreated: the project exists and is registered. ProjectClaimCreated = "created" )
Project claim states.
const ( ProxySessionGit = "git" ProxySessionKube = "kube" ProxySessionEgress = "egress" )
Proxy session kinds.
const ( RoleEffectAllow = "allow" RoleEffectDeny = "deny" )
Effect values for RoleBindingRow.Effect.
const ( SessionKindBrowser = "browser" SessionKindCLI = "cli" )
The session kinds the kind column holds. pkg/oidcauth owns what they mean; these are the stored spellings, and the sweep below compares against one.
const AuditGenesisHash = genesisHash
AuditGenesisHash is the prev_hash of a chain that has never been pruned. Exported so the sealer can start its own verification from the same place the verifier does.
const BusyTimeoutMillis = 5000
BusyTimeoutMillis is how long any connection under the policy waits on another connection's lock before returning SQLITE_BUSY.
const EnvAllowSchemaDowngrade = "CLOOP_ALLOW_SCHEMA_DOWNGRADE"
EnvAllowSchemaDowngrade names the operator opt-out. Set it to 1/true/yes/on to open a database whose schema is ahead of this binary's.
An environment variable rather than a config key on purpose: the check runs inside statedb.Open, which is reached from CLI commands, the orchestrator and the hub alike, several of them before any config file has been read. A knob that cannot be set in every context where the guard fires is not an opt-out.
const HubScope = "hub"
HubScope is the fence name this binary writes. See the migration for why the column exists at all when there is only ever one value.
const JournalSizeLimitBytes int64 = 64 << 20
JournalSizeLimitBytes is the size a read-write connection under the policy trims the write-ahead log back to when it restarts it (Task 20392).
SQLite rewrites a WAL from its start once a checkpoint has copied every frame back into the database, but it never shrinks the file: the log stays at the high-water mark of the largest burst written between two checkpoints — a bulk delete, a VACUUM, which writes the whole database through it — for as long as the database is open. On 2026-10-06 the hub's own log was 340 MB beside a 409 MB database on a disk 98% full, in use, and never coming back. With journal_size_limit set, the connection whose write restarts the log truncates the file to this size when that write commits, or to the size of the write if that is larger. Nothing else changes: the limit is not a cap on how large the log may grow, and checkpoints run as before.
64 MiB is several times the log a busy hub needs between two automatic checkpoints (1000 pages, 4 MiB), so the trim costs a steady-state hub nothing, and small enough that a burst no longer leaves a meaningful share of a small disk behind.
const LatestVersion = 1 << 30
LatestVersion is the sentinel MigrateTo accepts to mean "every embedded migration". Any real schema version is far below it.
const LegacyKeyID = "legacy"
LegacyKeyID is the key id pre-envelope material reads as (secretbroker's LegacyKeyID, which migration 0019 stamps).
const NoStep = -1
NoStep is the EventRow.Step value for events that are not bound to any step. Steps are 0-based, so 0 is a real step number — callers recording a non-step-bound event must set Step to NoStep explicitly.
const ProviderCallBodiesPrunedKey = "bodies_pruned_at"
ProviderCallBodiesPrunedKey is the key under which a stripped provider-call row records when its bodies went, inside the headers JSON object.
Exported because pkg/ui reads it: the detail endpoint surfaces it so the panel can say "bodies pruned" instead of showing an empty prompt, and the replay endpoint refuses a call whose prompt no longer exists rather than sending an empty one to a provider.
const TelemetryMaxLimit = 1000
TelemetryMaxLimit bounds one page. Chosen so that a page of worst-case rows still marshals to a response a browser will render rather than choke on.
const TelemetryMaxRows = 50000
TelemetryMaxRows is the hard ceiling on stored events.
Enforced on the write path rather than by the hourly retention janitor, because the writer here is an endpoint that accepts unauthenticated POSTs: a bound that only holds once an hour is not a bound against the traffic this table is actually exposed to. At the field budgets pkg/telemetry enforces, the worst case is a few hundred megabytes, and the realistic case — the trails of a handful of sessions — is a few megabytes.
const WALCheckpointBusyTimeout = 250 * time.Millisecond
WALCheckpointBusyTimeout is how long a TRUNCATE checkpoint waits for another connection before reporting busy — and so roughly the longest a writer can be held up behind one, which SQLite makes wait while the checkpoint holds the write lock. A quarter of a second outlasts the reads and writes cloop makes, and is a twentieth of the 5 s every writer waits before giving up.
Variables ¶
var ( // ErrTaskNotFound indicates the requested task ID does not exist in the // project plan. Returned by lookup helpers in pkg/state and pkg/statedb. ErrTaskNotFound = errors.New("statedb: task not found") // ErrProjectNotFound indicates the working directory has no cloop project // (no state.db, no migratable state.json). Returned by state.Load. ErrProjectNotFound = errors.New("statedb: project not found") // ErrStaleVersion indicates an optimistic-concurrency check failed: the // caller's plan version no longer matches the on-disk version. Callers // should re-load and re-apply. ErrStaleVersion = errors.New("statedb: stale plan version") // ErrDBLocked indicates SQLite returned a busy/locked error that the // busy_timeout did not absorb (extreme contention or a long-running // writer in another process). Callers may retry the operation. ErrDBLocked = errors.New("statedb: database busy") // ErrSchemaMismatch indicates the on-disk schema is not what this binary // expects (corruption, partial migration, or a future binary's database // opened by an older one). Manual intervention is usually required. ErrSchemaMismatch = errors.New("statedb: schema mismatch") // ErrSchemaTooNew indicates the database has been migrated past the // highest migration this binary embeds — an older binary opened a // database a newer one moved forward. // // Distinct from ErrSchemaMismatch because the remedy is different: this // is fixed by running a different binary, not by repairing the database. // Errors carrying it also satisfy errors.Is for ErrSchemaMismatch, so // callers that only handle the general case keep working. The detail — // both versions, and which build applied the newer schema — is in // *SchemaTooNewError, reachable with errors.As. ErrSchemaTooNew = errors.New("statedb: database schema is newer than this binary") // ErrExecutorNotFound indicates the requested execution backend is not // registered in the executors table. Callers must treat this as fatal // for the operation rather than falling back to host execution — see // pkg/executor's fail-closed resolution policy. ErrExecutorNotFound = errors.New("statedb: executor not found") // ErrBrokerSecretNotFound indicates no broker_secrets row has the // requested ID. Like ErrExecutorNotFound this is fatal for the // operation: a caller must never substitute a different credential for // one it could not find. ErrBrokerSecretNotFound = errors.New("statedb: broker secret not found") // ErrBrokerGrantNotFound indicates no broker_grants row has the // requested ID. ErrBrokerGrantNotFound = errors.New("statedb: broker grant not found") // ErrGrantRequestNotFound indicates no secret_grant_requests row has the // requested ID (Task 20271). Distinct from ErrBrokerGrantNotFound because // the two answer different questions: an unknown grant means the // authorisation does not exist, while an unknown request means nobody ever // asked — and a decide call that confused them would report "already // decided" for an id that was simply mistyped. ErrGrantRequestNotFound = errors.New("statedb: grant request not found") // ErrEgressGrantNotFound indicates no egress_grants row has the // requested ID. Like the broker sentinels this is fatal for the // operation: a caller must never fall back to a different egress policy // than the one it asked for. ErrEgressGrantNotFound = errors.New("statedb: egress grant not found") // ErrExecutorHealthNotFound indicates the executor has no health record: // the scheduler has never probed it. Callers must not read this as // "healthy" — an unobserved executor is unknown, not ready. ErrExecutorHealthNotFound = errors.New("statedb: executor health not found") // ErrExecutorSessionNotFound indicates no executor_sessions row has the // requested ID. ErrExecutorSessionNotFound = errors.New("statedb: executor session not found") // ErrExecutorSessionClaimLost indicates a conditional requeue matched no // row: another supervisor already claimed the session, or it is no longer // running. This is the exactly-once signal, and it is a distinct error // because "someone else is failing this over" must never be retried as if // it were a transient fault — doing so is how the same work ends up // running twice. ErrExecutorSessionClaimLost = errors.New("statedb: executor session claim lost") // ErrAPITokenNotFound indicates no api_tokens row has the requested ID. // // On the verification path this is an ordinary outcome, not a fault: it // is what a forged or already-purged token id looks like. Callers must // answer it exactly as they answer a bad secret — an unauthenticated // caller must not be able to use the difference to learn which token ids // exist. ErrAPITokenNotFound = errors.New("statedb: api token not found") // ErrSessionNotFound indicates no sessions row has the requested id. // // Like ErrAPITokenNotFound this is an ordinary outcome on the // authentication path, not a fault: it is what a forged cookie, a cookie // from before a restart that wiped the database, and a session an // administrator just terminated all look like. All three must produce the // same answer to the caller. ErrSessionNotFound = errors.New("statedb: session not found") // ErrDeviceAuthorizationNotFound indicates no device_authorizations row // has the requested device code or user code (Task 20412). An ordinary // outcome: a mistyped user code, and a device code that expired and was // swept, look exactly like this, and must be answered alike. ErrDeviceAuthorizationNotFound = errors.New("statedb: device authorization not found") // ErrRoleBindingNotFound indicates no role_bindings row has the requested // id. Unlike the two above this is a genuine operator error rather than an // expected outcome — binding ids are only ever obtained by listing the // table — so callers should surface it instead of absorbing it. ErrRoleBindingNotFound = errors.New("statedb: role binding not found") // ErrCorruptTaskColumn indicates a task row holds a JSON-encoded column // that could not be decoded (Task 20297). // // Only raised for columns where dropping the value would change what the // program does rather than what it displays: depends_on, whose empty value // pm.DepsReady reads as "no prerequisites, may run", and on_success and // on_failure, whose empty value lets both branches of a branched plan run // (Task 20361). Fatal to the load on purpose: the alternative is admitting // a task ahead of work it depends on, and the error names the task and // column so the row can be repaired. Columns that are safe to drop are // reported through the sink in taskcolumns.go instead and do not produce // this error. ErrCorruptTaskColumn = errors.New("statedb: corrupt task column") // ErrCIPipelineRuleNotFound indicates no ci_pipeline_rules row carries the // requested id (Task 20278). // // Surfaced rather than absorbed. A rule id is only ever obtained from a // listing, so not finding one means the operator's view is stale — most // likely because a second maintainer deleted the same rule concurrently — // and a PUT that silently recreated it would resurrect an allowlist entry // somebody had just decided to remove. ErrCIPipelineRuleNotFound = errors.New("statedb: ci pipeline rule not found") // ErrProjectMemberNotFound indicates no project_members row names the // requested identity on the requested project (Task 20366). An ordinary // answer — "that person is not on this project" — which the REST layer // reports as 404 and the CLI as a plain sentence. ErrProjectMemberNotFound = errors.New("statedb: project member not found") // ErrSecretLeaseNotFound indicates no secret_leases row names the lease // (Task 20382): it was released, swept, or recorded by a binary that // predates the table. ErrSecretLeaseNotFound = errors.New("statedb: secret lease not found") // ErrProxySessionNotFound indicates no proxy_sessions row names the // session (Task 20383): it was retired, recorded by a binary that predates // the table, or never recorded — a session nothing could restore. ErrProxySessionNotFound = errors.New("statedb: proxy session not found") // ErrCISessionNotFound indicates no ci_sessions row names the session // (Task 20390): it was retired, minted by a binary that predates the // table, or never recorded — a session nothing could restore. ErrCISessionNotFound = errors.New("statedb: CI session not found") )
Sentinel errors. Add to this list — do not rename or reuse.
var ( // ErrEnrollmentNotFound: no enrollment token with that ID. ErrEnrollmentNotFound = errors.New("statedb: enrollment token not found") // ErrAgentCredentialNotFound: no agent credential with that ID. ErrAgentCredentialNotFound = errors.New("statedb: agent credential not found") // ErrEnrollmentSpent: the token was already redeemed or revoked. This is // the replay signal, and it is a distinct error because "someone reused // this token" is an operational event worth surfacing, not a generic // failure. ErrEnrollmentSpent = errors.New("statedb: enrollment token already redeemed or revoked") )
Sentinel errors for enrollment persistence. Callers use errors.Is.
var ( // ErrKEKNotFound: no KEK row with that ID. ErrKEKNotFound = errors.New("statedb: sealing key not found") // ErrKEKInUse: retirement was refused because sealed rows still // reference the key. The refusal is computed inside the same // transaction as the retirement, so a row written concurrently either // blocks the retirement or arrives after it — never in between. ErrKEKInUse = errors.New("statedb: sealing key still referenced by sealed rows") )
Sentinels for the key registry.
var ( // ErrSCIMNotFound: no provisioned user, group or credential has that id. ErrSCIMNotFound = errors.New("statedb: scim resource not found") // ErrSCIMVersion: the resource changed since the caller read it. ErrSCIMVersion = errors.New("statedb: scim resource was changed concurrently") )
Sentinels for the SCIM directory.
var ErrAuditAnchorNotFound = errors.New("statedb: no audit anchor")
ErrAuditAnchorNotFound is returned by LatestAuditAnchor when the trail has never been pruned. Callers treat it as "the chain starts at genesis", which is the pre-Task-20218 behaviour and not an error condition.
var ErrDispatchIntentNotFound = errors.New("statedb: dispatch intent not found")
ErrDispatchIntentNotFound is returned when no row names a run.
var ErrExecutorHandleNotFound = errors.New("statedb: executor handle not found")
ErrExecutorHandleNotFound is returned when no row exists for a handle id.
var ErrHubLeaseNotFound = errors.New("statedb: hub lease not found")
ErrHubLeaseNotFound is returned when no row exists for a scope.
var ErrHubOwnerNotFound = errors.New("statedb: hub owner not found")
ErrHubOwnerNotFound is returned when no member owns (kind, key).
var ErrHubTLSNotFound = errors.New("statedb: no hub certificate by that id")
ErrHubTLSNotFound is returned when the hub has no row by that id: no CA minted yet, or no leaf issued for that monitor.
var ErrStaticTokenFingerprint = errors.New("statedb: a static token fingerprint is 64 lowercase hex characters")
ErrStaticTokenFingerprint is returned for a fingerprint that is not 64 lowercase hex characters.
var ErrVirtualExecutorExists = errors.New("statedb: an executor with this id already exists")
ErrVirtualExecutorExists reports a create for an ID already in use — by a virtual executor or by any other executor the control plane has recorded.
var ErrVirtualExecutorNotFound = errors.New("statedb: virtual executor not found")
ErrVirtualExecutorNotFound reports an unknown virtual executor ID.
Functions ¶
func AdoptAuditFailureStatus ¶ added in v0.0.5
AdoptAuditFailureStatus takes over the losses that processes no longer running left in dir: each becomes owed by this process, to be recorded in its chain as an audit.gap row naming where it came from, and the file is removed. Returns how many events were adopted.
A file is claimed by renaming it before it is read, so two processes starting beside one dead one cannot both record its losses. Entries that cannot be adopted — a database that is gone, or cannot be confirmed as cloop's — are written back to a file of their own and said on stderr, so the record of the loss is not destroyed by the attempt to record it.
func AllowSchemaDowngradeFromEnv ¶
func AllowSchemaDowngradeFromEnv() bool
AllowSchemaDowngradeFromEnv reports whether the operator opt-out is set.
Exported so `cloop hub doctor` can tell an operator the guard is disabled. A safety check that can be switched off silently gets switched off and left that way, so the off state is itself a finding.
func AuditAdoptRequested ¶ added in v0.0.5
func AuditAdoptRequested(d *DB, in AdoptRequestInput)
AuditAdoptRequested records somebody asking a run to adopt the hub's build at its next task boundary (Task 20389).
func AuditAnchorLink ¶ added in v0.0.5
func AuditAnchorLink(a AuditAnchor) (want string, ok bool)
AuditAnchorLink recomputes one anchor's hash and reports whether it matches, so a verifier outside this package can walk the anchor chain.
func AuditAttachSession ¶ added in v0.0.2
func AuditAttachSession(d *DB, in AttachAuditInput)
AuditAttachSession records one interactive-session event.
Best-effort, like every other emitter in this package: a wedged journal must not stop an operator reaching a sandbox during an incident. That is a deliberate trade — an unrecorded session is worse than no session in theory, and much better than an unreachable sandbox at 3am in practice — and it is the same trade every other audit path here already makes.
func AuditCapPause ¶ added in v0.0.2
func AuditCapPause(d *DB, in CapPauseInput)
AuditCapPause records a run parked by a subscription cap.
func AuditCapResume ¶ added in v0.0.2
func AuditCapResume(d *DB, in CapResumeInput)
AuditCapResume records the hub restarting a cap-paused run with no human in the loop.
func AuditChainLink ¶
func AuditChainLink(ev AuditEvent) (want string, ok bool)
AuditChainLink recomputes one row's hash and reports whether it matches, so callers outside this package (the sealer, which must not archive a chain that is already broken) can verify without duplicating computeRowHash.
func AuditExecutorLifecycle ¶
func AuditExecutorLifecycle(d *DB, in ExecutorAuditInput)
AuditExecutorLifecycle records an executor-fleet mutation. Best-effort, like every other emitter in this file: a wedged audit log must not stop an operator from cordoning a misbehaving node.
func AuditFailureStatusDir ¶ added in v0.0.5
AuditFailureStatusDir is where a hub serving workDir keeps its status file, and where `cloop hub doctor` looks for it.
func AuditGapLostEvents ¶ added in v0.0.5
AuditGapLostEvents reads how many events a gap row's payload records as lost, ignoring every other field: a reader that wants only the count must not lose it to a field of a shape it does not expect.
func AuditImagePolicyDenial ¶
func AuditImagePolicyDenial(d *DB, in ImagePolicyDenialInput)
AuditImagePolicyDenial records a container image refused by the hub's trust policy. Best-effort, like every other emitter here.
func AuditProjectFirewall ¶ added in v0.0.5
func AuditProjectFirewall(d *DB, in ProjectFirewallAuditInput)
AuditProjectFirewall records a project's firewall rule set changing, on the control plane's chain, where the rule set is stored. Best-effort like every emitter in this file.
func AuditProjectLifecycle ¶ added in v0.0.5
func AuditProjectLifecycle(d *DB, in ProjectAuditInput)
AuditProjectLifecycle records a project created, refused, removed or kept in the control plane's chain. Best-effort, like every helper here.
func AuditRunReexecuted ¶ added in v0.0.5
func AuditRunReexecuted(d *DB, in RunReexecInput)
AuditRunReexecuted records a run moving to a newer build. Written by the new image, on the project's chain: which build ran which of its tasks is a question about the project.
func AuditSecretDecision ¶
func AuditSecretDecision(d *DB, in SecretAuditInput)
AuditSecretDecision records a secret-broker mint, grant, lease, renew, revoke, or denial. Best-effort, like every other emitter in this file: an unavailable audit log must not stop an executor from receiving the credentials it was granted.
func AuditTaskDelete ¶
AuditTaskDelete records a task removal. EntityID is the deleted task's id.
func AuditTaskDispatch ¶ added in v0.0.2
func AuditTaskDispatch(d *DB, in TaskDispatchInput)
AuditTaskDispatch records one task entering execution.
Best-effort, like every other emitter in this file: a wedged audit log must not stop a task from running. The chain verifier surfaces the resulting gap.
func AuditTaskQuarantine ¶ added in v0.0.5
AuditTaskQuarantine records a task marked as a suspected node killer (Task 20391). It belongs in the project's chain: d must be the project's handle.
func AuditTaskQuarantineRelease ¶ added in v0.0.5
func AuditTaskQuarantineRelease(d *DB, taskID int, q pm.TaskQuarantine, actor, via string)
AuditTaskQuarantineRelease records an explicit reset releasing a suspected node killer. via names the reset; actor is who pressed it.
func AuditTaskStatus ¶
AuditTaskStatus records a manual status flip (UI/CLI initiated).
func AuditTaskUpsert ¶
AuditTaskUpsert is the exported wrapper that callers outside this package (orchestrator, UI handlers) use to emit a task-mutation event with their own actor identity. Best-effort.
func AuditWorkspaceProvision ¶
func AuditWorkspaceProvision(d *DB, in WorkspaceAuditInput)
AuditWorkspaceProvision records one workspace-provisioning phase.
Best-effort, like every other emitter in this file: an unavailable audit log must not stop a workload from getting its source tree.
func CheckSchemaAhead ¶ added in v0.0.5
CheckSchemaAhead reports, without writing, whether this build would refuse to open the database at path because it was migrated past this binary: the decision Open's guard makes (checkNotFromFuture), asked of a read-only connection. Nil means it would open it — not ahead, or ahead only by migrations recorded as additive — and a *SchemaTooNewError names what blocks it. Any other error means the question could not be asked: the file would not open read-only, or its schema_migrations would not read. CLOOP_ALLOW_SCHEMA_DOWNGRADE is not consulted; the caller weighs the opt-out.
`cloop hub doctor` asks this rather than comparing version numbers itself. It used to fail every database that was ahead, including the ones this guard opens without complaint (Task 20387).
func DSN ¶ added in v0.0.5
DSN returns the data source name a handle with the given access opens path with.
The name is a file: URI, so that the path is escaped rather than parsed: the driver cuts a bare path at its first '?', so a project directory with a question mark in its name would open some other file, and mode=ro only means something to SQLite inside a URI.
func FlushAuditGaps ¶ added in v0.0.5
func FlushAuditGaps(recorded string)
FlushAuditGaps records what every chain is owed now, rather than at the reporter's next tick, and prints whatever has not been said. recorded is one of the GapRecorded* values. A hub calls it as it shuts down.
func GrowthTables ¶ added in v0.0.2
func GrowthTables() []string
GrowthTables names the row tables retention covers, in the order a report should list them. Exported so hubdoctor can enumerate them without duplicating the list and drifting from it.
func HTTPStatus ¶
HTTPStatus returns the HTTP status code that best represents err for an API response. Unknown errors map to 500. Use this from any HTTP handler to keep status-code logic out of individual call sites.
if err != nil {
jsonErr(w, err.Error(), statedb.HTTPStatus(err))
return
}
func LatestSchemaVersion ¶
LatestSchemaVersion returns the highest migration version this *binary* carries, which is what a database will be at once Migrate has run.
It exists so a diagnostic can compare the two numbers. On its own, CurrentSchemaVersion answers "what has been applied" and cannot distinguish a fully-migrated database from one an older binary left behind — and the second is the interesting case, because a hub rolled back to a previous image runs against a schema from the future and fails on whichever column it does not know about.
func MarshalAuditPayload ¶
MarshalAuditPayload is a small helper around json.Marshal used by audit callers that want a non-empty payload but don't want to import encoding/json at every call site. Returns "" on marshal failure rather than aborting the caller's flow — the audit row still records the mutation type.
Every payload is passed through redaction on the way out (see audit_redact.go), so no emitter can write credential material into the chain even by accident. Doing it here rather than at each call site is the point: the audit table is append-only and hash-chained, so a leaked secret cannot be edited out afterwards without breaking the chain.
func MarshalHandleMeta ¶
MarshalHandleMeta renders a driver's extras for the meta_json column. A nil or empty map becomes "{}" rather than "", so the column always holds valid JSON and a reader never has to special-case the empty string.
func OpenConn ¶ added in v0.0.5
OpenConn opens path under the connection policy and checks that the first connection can be established, so a missing file or a bad path is reported here rather than by whichever query happens to run first.
The pool holds one connection. Within a process that serialises every statement on the handle, which is what all of cloop's callers want; the policy does not depend on it, because the driver applies the policy to every connection it opens, so a caller that needs more may raise the limit.
A ReadOnly open of a file that does not exist fails rather than creating it.
func PeekHubCluster ¶ added in v0.0.5
func PeekHubCluster(dbPath, kind string) (members []HubMemberRow, owners []HubOwnerRow, err error)
PeekHubCluster reads the members serving the control plane at dbPath and the ownership rows of one kind (every kind when kind is empty), through a read-only handle (Task 20374).
It is for a process that is not a member and must not become one by looking: a CLI deciding whether a hub is running a project. Open would migrate the database, and a hub's live control plane is the one database a newer CLI build must never migrate early — nor may an older one be refused for asking a question this narrow. Nothing here writes, so neither the schema version nor a lock held by the hub stands in the way, beyond the busy timeout every connection waits.
A control plane no clustered hub has served has no cluster tables, and reads as no members and no owners rather than as an error.
func PeekRunOwner ¶ added in v0.0.5
PeekRunOwner reads the run-owner record of the project database at dbPath through a read-only handle: it never migrates or creates the database, so a diagnostic may read any project's record, whatever build wrote it. Nil when no run has recorded one.
func ProjectMemberID ¶ added in v0.0.5
ProjectMemberID derives a new membership's id from the one tuple that identifies it: the project and the person. Role is not part of it, so changing someone's role replaces their row rather than adding a second one whose winner nobody could predict.
96 bits, because the id is also the primary key that keeps the pair unique — the table predates this build and has no UNIQUE constraint on the pair. Lookups go by the pair, not the id (PutProjectMember), so a collision fails an insert rather than landing on another person's row.
func ProviderCallBodiesPruned ¶ added in v0.0.2
ProviderCallBodiesPruned reports when a provider-call row's bodies were dropped by retention, reading the marker out of its headers JSON.
ok is false for a row that still has its bodies, which is every row on a hub where the strip has not run. Callers that render or replay a prompt should check this before treating an empty prompt as the truth.
func ReadHubMeta ¶ added in v0.0.5
ReadHubMeta is HubMeta through a bare connection: one OpenConn opened, typically ReadOnly, so that reading a hub's record neither migrates its database nor, when the file is missing, creates one (Task 20410). A database without the metadata table holds no value.
func RoleBindingID ¶ added in v0.0.2
RoleBindingID derives the deterministic identifier for a binding's identity tuple.
Identity is (effect, claim, value, project, executor) and deliberately excludes role, reason and provenance: re-granting the same subject a different role on the same scope should replace the binding, not leave two rows whose winner depends on resolution order. The reason and the actor of the most recent write are what the audit trail keeps.
Truncated to 48 bits. This is a content address for deduplication, not a security boundary — the values it covers are already visible to anyone who can read the table — and a 12-character id is one an operator can retype from a terminal during an incident.
func SandboxSettingsFor ¶ added in v0.0.3
func SandboxSettingsFor(d *DB, executorID string) (executor.SandboxSettings, error)
SandboxSettingsFor resolves an executor's settings for a dispatch, collapsing "no row" and "lookup failed" onto the same answer the caller can act on.
The two are not the same, and the difference is the reason this helper exists rather than every caller deciding for itself. A missing row is a fact: this executor was never configured, and it should run what it always ran. A failed lookup is not a fact about the executor at all, and answering it with the zero value would silently unconfigure a container-mode executor for the duration of a database fault — a downgrade from containment to host execution, arrived at by no one's decision, at the moment the hub is least able to notice.
So a failed lookup returns the error and the caller refuses the dispatch. The run fails loudly and is retried; it does not quietly run somewhere weaker than the admin asked for. That is the same trade the container driver makes when it refuses to construct without a runtime.
A nil DB means no control plane — the single-user, no-database path — and yields unset settings with no error, because there is no policy to fail to read.
func SealedSetNames ¶
func SealedSetNames() []string
SealedSetNames returns the populations retirement checks, so a test can assert they match the sets registered for rotation.
func SetAuditEnabled ¶
func SetAuditEnabled(on bool)
SetAuditEnabled toggles audit emission globally. Intended for tests and for callers running cloop against a database where the audit_events table is not desired (e.g. one-shot CLI commands that read state).
func SetAuditFailureStatusDir ¶ added in v0.0.5
func SetAuditFailureStatusDir(dir string)
SetAuditFailureStatusDir names the directory this process keeps its status file in. Empty turns it off.
func SetAutoUpdatePolicy ¶ added in v0.0.3
func SetAutoUpdatePolicy(d *DB, p autoupdate.Policy, setBy string) error
SetAutoUpdatePolicy replaces the fleet's policy. setBy is the identity that set it, for the audit trail.
func SetBinaryVersion ¶
func SetBinaryVersion(v string)
SetBinaryVersion records which build this process is, for stamping into schema_migrations when it applies a migration. Call it once during process initialisation; cmd does so with the ldflags-injected version.
It lives here rather than being read from pkg/cmd because pkg/statedb sits below the CLI in the import graph and must not depend on it.
func SettleAuditFailuresAtExit ¶ added in v0.0.5
func SettleAuditFailuresAtExit()
SettleAuditFailuresAtExit is FlushAuditGaps for a process about to exit, and says plainly what could not be recorded: a CLI command that failed an append may otherwise end before its reporter has printed anything.
func UnmarshalHandleMeta ¶
UnmarshalHandleMeta parses the meta_json column. Unparsable metadata is dropped rather than propagated: the extras are advisory, and refusing to rehydrate a workload because a hint field is corrupt would strand a running container to protect a label.
func UserErrorf ¶ added in v0.0.2
UserErrorf returns an error that prints as the formatted message and matches sentinel under errors.Is.
Use it wherever a sentinel would otherwise be wrapped in prose the user is meant to read:
return statedb.UserErrorf(statedb.ErrProjectNotFound, "no cloop project found (run 'cloop init' first)")
prints "no cloop project found (run 'cloop init' first)" and still satisfies errors.Is(err, statedb.ErrProjectNotFound).
format is rendered with fmt.Sprintf, so it takes ordinary verbs but not %w — this constructor already owns the wrapping. A nil sentinel degrades to a plain fmt.Errorf rather than producing an error that matches nothing, so a caller that passes one by mistake still gets a usable message.
Types ¶
type APITokenRow ¶
type APITokenRow struct {
ID string `json:"id"`
Name string `json:"name"`
Hash string `json:"-"` // never serialized: see the migration comment
Prefix string `json:"prefix"`
Roles []string `json:"roles"`
ProjectScope []string `json:"project_scope,omitempty"`
CreatedBy string `json:"created_by,omitempty"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at,omitempty"`
LastUsedAt time.Time `json:"last_used_at,omitempty"`
RevokedAt time.Time `json:"revoked_at,omitempty"`
// Kind labels a hub-issued token; "" is an ordinary PAT (migration 0023).
Kind string `json:"kind,omitempty"`
// OwnerJSON is the owning identity's claim bundle, stored opaquely. This
// layer deliberately does not know its shape: pkg/apitoken owns the
// encoding, and a second opinion here about what a claim set looks like is
// how the two drift apart. Never serialized outward for the same reason
// Hash is not — it carries a user's email and group memberships.
OwnerJSON string `json:"-"`
}
APITokenRow is one persisted API token.
Roles and ProjectScope are stored as JSON arrays rather than normalized child tables: both are short, always read whole with the row, and are validated by pkg/apitoken on the way in and on the way out. A join here would buy nothing and would put the verification path — which runs on every authenticated request — behind three queries instead of one.
type Access ¶ added in v0.0.5
type Access int
Access is what a handle opened under the connection policy may do.
const ( // ReadWrite handles read and write. Their transactions take the write // lock at BEGIN (BEGIN IMMEDIATE): every transaction cloop opens reads // before it writes, and a deferred one fails with SQLITE_BUSY_SNAPSHOT — // no busy handler, no retry — whenever another handle commits between its // read and its write. In WAL mode an immediate transaction blocks no // reader. ReadWrite Access = iota // ReadOnly handles cannot write, enforced by SQLite rather than by the // caller's good behaviour: the file is opened mode=ro. A diagnostic, a // backup check or a liveness probe that looks at a hub's live database // can neither change it nor, when the file does not exist, create an // empty one in its place. ReadOnly )
type AdoptRequestInput ¶ added in v0.0.5
type AdoptRequestInput struct {
ProjectPath string
RequestID string
PID int
RunBuild runbuild.Build
HubBuild runbuild.Build
Behind int
Actor string
}
AdoptRequestInput is one request for a run to adopt the hub's build.
type AgentCredentialRow ¶
type AgentCredentialRow struct {
AgentID string
Name string
// SecretHash is hex SHA-256 of the credential secret, never the secret.
SecretHash string
WorkDirRoot string
Labels map[string]string
CreatedAt time.Time
LastSeen time.Time
RevokedAt time.Time
EnrollmentID string
}
AgentCredentialRow is one enrolled agent's long-lived credential.
type AppTokenSlotRow ¶ added in v0.0.5
type AppTokenSlotRow struct {
LeaseID string
GrantID string
Holder string
SecretID string
SecretName string
// Scope is the broker's JSON account of the mint: installation, repository
// ids, permissions asked for and granted.
Scope string
// Guarded: a git proxy session presents the token, named by SessionID.
Guarded bool
SessionID string
EnvExported bool
// FileName is the lease file an unguarded token is delivered in.
FileName string
// TokenExpiresAt is when the token the workload or session holds stops
// working at GitHub.
TokenExpiresAt time.Time
UpdatedAt time.Time
}
AppTokenSlotRow is one GitHub App installation token a lease holds: the scope it was minted at and when the token held now expires, never the token.
type AttachAuditInput ¶ added in v0.0.2
type AttachAuditInput struct {
// Event is the fully-qualified action: auditaction.ActionSandboxAttachOpen,
// ActionSandboxAttachClose, or ActionSandboxAttachDenied.
//
// Passed in whole rather than assembled from an action suffix, because
// these three are the complete set and a typo should be visible at the
// call site rather than produce a plausible-looking new event type that
// no retention rule or SIEM filter knows about. Typing it as an
// auditaction.Action is what turns "should be visible" into "cannot
// compile": there is no longer a bare string to get wrong.
Event auditaction.Action
// Actor is the acting identity — the OIDC subject label, the same
// spelling auditAuthz writes, so filtering the trail by person returns a
// whole session rather than half of it.
Actor string
// SessionID correlates the open with its close.
SessionID string
// ExecutorID and HandleID name the sandbox that was entered. Both,
// because the executor alone does not identify which workload and the
// handle alone does not survive as a lookup key once the run ends.
ExecutorID string
HandleID string
// TaskID is the work the sandbox was running, and the entity this row is
// filed under: "show me everything that happened to task 41" is the query
// an incident actually starts from.
TaskID int
// Command is the argv as the caller gave it, unmodified. Not normalised
// and not shell-quoted — the point is to record what was asked for, and a
// prettied-up rendering is a different string from the one that ran.
Command string
// Writable reports whether the session had an input channel at all.
Writable bool
// Detail is the refusal reason for a denial, or the close reason for a
// close. Empty on a clean open.
Detail string
}
AttachAuditInput carries one interactive-session lifecycle event.
type AuditAnchor ¶
type AuditAnchor struct {
ID int64
CreatedAt time.Time
Actor string
// Cutoff is the --before instant the operator asked for. Kept distinct
// from the ids it resolved to so an audit of the audit can tell a policy
// decision from its effect.
Cutoff time.Time
PrunedFirstID int64
PrunedThroughID int64
PrunedCount int64
// BoundaryHash is the row_hash of PrunedThroughID: what the first
// surviving row's prev_hash must equal.
BoundaryHash string
// RetainedFromID is the first surviving id, or 0 when the prune emptied
// the table.
RetainedFromID int64
ExportPath string
ExportFormat string
ExportSHA256 string
ExportBytes int64
PrevAnchorHash string
AnchorHash string
}
AuditAnchor records one deliberate truncation of the audit chain. See migration 0027 for what each field is load-bearing for.
type AuditChainFailures ¶ added in v0.0.5
type AuditChainFailures struct {
Path string `json:"path"`
Chain string `json:"chain"`
// Unrecorded is lost and not yet in the chain as an audit.gap row.
Unrecorded AuditLoss `json:"unrecorded"`
// TotalEvents were lost since the process started; RecordedEvents of
// them are in the chain now, in GapRows gap rows.
TotalEvents int64 `json:"total_events"`
RecordedEvents int64 `json:"recorded_events"`
GapRows int64 `json:"gap_rows"`
LastGapID int64 `json:"last_gap_id,omitempty"`
LastGapAt time.Time `json:"last_gap_at,omitempty"`
GapWriteFailures int64 `json:"gap_write_failures,omitempty"`
LastGapError string `json:"last_gap_error,omitempty"`
}
AuditChainFailures is one database's account of failed audit appends in this process.
func AuditFailures ¶ added in v0.0.5
func AuditFailures() []AuditChainFailures
AuditFailures reports every database this process failed an audit append to, ordered by path. Empty when it never has.
type AuditCheckpointClaim ¶ added in v0.0.5
type AuditCheckpointClaim struct {
// Claimed: the caller writes Window now. Window is the window asked
// for, or the one before it when a member that claimed that one died
// before writing it — the window is then written late rather than not
// at all, and the caller asks again for the current one.
Claimed bool
Window int64
// Prior is the marker as it was found.
Prior AuditCheckpointWindow
// HeldBy names another member writing a window right now, whose claim
// goes stale at RetryAt; the caller should look again then.
HeldBy string
RetryAt time.Time
// FutureMarker reports a marker more than one window ahead of the
// caller's clock, which was overwritten rather than obeyed.
FutureMarker bool
}
AuditCheckpointClaim says what ClaimAuditCheckpointWindow decided.
type AuditCheckpointWindow ¶ added in v0.0.5
type AuditCheckpointWindow struct {
Window int64 `json:"window"`
// IntervalS is the interval, in seconds, the window was numbered under:
// a window number means nothing without it.
IntervalS int64 `json:"interval_s,omitempty"`
Member string `json:"member"`
ClaimedAt time.Time `json:"claimed_at"`
Done bool `json:"done"`
}
AuditCheckpointWindow is the shared record of which checkpoint window was last claimed, by which hub member, and whether it was written.
It is what keeps a leader change from either skipping or doubling a window: a new leader resumes from it rather than from its own clock. It lives in the database the checkpoints exist to distrust, which is acceptable because all it can be used for is liveness — the worst a forged marker does is stop checkpoints being written, which `cloop hub doctor` reports as stale — and a marker claiming a window in the future is ignored rather than obeyed.
type AuditEvent ¶
type AuditEvent struct {
ID int64 // monotonic primary key, assigned on append
Timestamp time.Time // UTC
Actor string // "system", "orchestrator", "ui", "cli", or user-supplied
EventType string // e.g. "task.create", "plan.update", "config.set"
EntityType string // "task" | "plan" | "config" | "step" | "session"
EntityID string // stringified id ("12" for task 12), empty for singletons
Payload string // JSON blob describing the mutation
PrevHash string // 64-hex SHA-256 of prior row, or 64 zeros for the first row
RowHash string // 64-hex SHA-256 of this row
}
AuditEvent is one row in the audit_events table.
type AuditFailureStatus ¶ added in v0.0.5
type AuditFailureStatus struct {
PID int `json:"pid"`
Host string `json:"host"`
// Instance tells this process from a later one given the same PID, and
// ProcStart is the kernel's start time for the PID (Linux), which tells it
// from an unrelated process that reused the PID.
Instance string `json:"instance,omitempty"`
ProcStart string `json:"proc_start,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
Chains []AuditChainFailures `json:"chains"`
// File is where it was read from; not stored.
File string `json:"-"`
}
AuditFailureStatus is one process's status file.
func ReadAuditFailureStatus ¶ added in v0.0.5
func ReadAuditFailureStatus(dir string) ([]AuditFailureStatus, error)
ReadAuditFailureStatus reads every status file in dir. A directory that does not exist holds none. Only regular files are read: a symlink planted there is not followed.
func (AuditFailureStatus) ProcessRunning ¶ added in v0.0.5
func (s AuditFailureStatus) ProcessRunning() bool
ProcessRunning reports whether the process a status file names may still be running.
On the host that wrote it the process table decides: the PID must be alive, be this process only if the instance is this one's, and have the start time the file recorded. From another host only age can: a file nobody rewrote for auditStatusStale is abandoned, a fresher one is taken to be live, since adopting a live process's losses would record them twice.
type AuditFilter ¶
type AuditFilter struct {
Actor string // exact-match
EntityType string // exact-match (e.g. "task")
EntityID string // exact-match within EntityType
EventType string // exact-match (e.g. "task.update")
Since time.Time // only events with timestamp >= Since
Until time.Time // only events with timestamp <= Until
FromID int64 // only events with id >= FromID
ToID int64 // only events with id <= ToID
Search string // case-insensitive LIKE on payload
Order string // "asc" (default) or "desc"
Limit int // 0 = no limit (capped to 10 000 internally)
Offset int
}
AuditFilter narrows ListAuditEvents down to the rows the caller cares about. All fields are optional — zero values mean "no filter".
type AuditGapCount ¶ added in v0.0.5
AuditGapCount is one line of a gap row's histogram.
type AuditGapPayload ¶ added in v0.0.5
type AuditGapPayload struct {
LostEvents int64 `json:"lost_events"`
FailedAppends int64 `json:"failed_appends"`
FirstFailedAt string `json:"first_failed_at"`
LastFailedAt string `json:"last_failed_at"`
FirstError string `json:"first_error,omitempty"`
LastError string `json:"last_error,omitempty"`
Actions []AuditGapCount `json:"actions,omitempty"`
Reasons []AuditGapCount `json:"reasons,omitempty"`
Recorded string `json:"recorded"`
Host string `json:"host,omitempty"`
PIDs []int `json:"pids,omitempty"`
AdoptedFrom []int `json:"adopted_from,omitempty"`
}
AuditGapPayload is what an audit.gap row's payload holds. VerifyAuditChain reads LostEvents back to say how many events a chain's gaps cover.
The histograms are lists of {name, events}, not maps keyed by action. Every payload passes through key-based redaction (MarshalAuditPayload), and an action such as `secret.lease` or `api_token.created` is exactly the kind of key it withholds — as a map key its count would be replaced with a marker, for the very actions an auditor most needs counted.
type AuditGapSummary ¶ added in v0.0.5
type AuditGapSummary struct {
Gaps int
Events int64
LastID int64
LastAt time.Time
FirstAt time.Time
Truncated bool // more gap rows than were read; Events is a lower bound
}
AuditGapSummary is what a chain's audit.gap rows add up to, read without walking the chain.
type AuditHead ¶ added in v0.0.5
type AuditHead struct {
// LastID, LastRowHash and LastTimestamp describe the newest row; all zero
// when the table is empty.
LastID int64
LastRowHash string
LastTimestamp time.Time
// FirstID is the oldest surviving row's id, 0 when empty.
FirstID int64
// Rows is how many rows the table holds.
Rows int64
// Anchor is the newest prune anchor, nil when the chain was never pruned.
Anchor *AuditAnchor
}
AuditHead is where a chain ends, and what anchors its beginning.
func ReadAuditHead ¶ added in v0.0.5
ReadAuditHead reads the head of the audit chain in the database behind conn: a connection OpenConn opened, typically ReadOnly on a backup this package must not migrate (Task 20410). A database that predates the audit tables reads as an empty chain, and one that predates prune anchors as unpruned.
type AuditLoss ¶ added in v0.0.5
type AuditLoss struct {
// Events is how many audit rows were lost; Appends how many append calls
// failed (a batch is one call).
Events int64 `json:"events"`
Appends int64 `json:"appends"`
FirstAt time.Time `json:"first_at"`
LastAt time.Time `json:"last_at"`
FirstError string `json:"first_error,omitempty"`
LastError string `json:"last_error,omitempty"`
// Actions counts the lost events by action name, Reasons by failure class
// (the hubmetrics.AuditFail* values).
Actions map[string]int64 `json:"actions,omitempty"`
Reasons map[string]int64 `json:"reasons,omitempty"`
// PIDs names the processes whose failures these are: this one, and any
// whose losses it adopted. AdoptedFrom names the second kind: processes
// that exited without recording what they lost.
PIDs []int `json:"pids,omitempty"`
AdoptedFrom []int `json:"adopted_from,omitempty"`
}
AuditLoss describes audit events that could not be appended to one chain.
type AuditPruneCandidate ¶
type AuditPruneCandidate struct {
FirstID int64
ThroughID int64
Count int64
// BoundaryHash is the row_hash at ThroughID, carried so the seal and the
// delete can be checked against the same value.
BoundaryHash string
// Remaining is how many rows would survive.
Remaining int64
}
AuditPruneCandidate describes what a prune with the given cutoff would remove, without removing anything. Both the CLI's --dry-run and the real path use it, so the number an operator is shown is the number that runs.
type AuditVerifyReport ¶
type AuditVerifyReport struct {
Total int // rows checked
OK bool // true when every link verified
BreakAtID int64 // first row whose hash did not match (0 if OK)
Reason string // human-readable description of the break
// ExpectedHash and ActualHash carry the two hashes the break compared,
// in full rather than the abbreviated form embedded in Reason. Reason is
// for a human reading a terminal; these are for a UI that wants to show
// them side by side, and for a report that gets pasted into a ticket
// where a 12-character prefix is not enough to reason about. Both are
// empty for an id-gap break, where no hash was compared, and for a
// clean run.
ExpectedHash string
ActualHash string
// Anchored reports that a retention prune has truncated the chain and the
// walk was validated against an anchor rather than against genesis. The
// remaining fields describe that anchor, so a report can say "verified
// from id N; everything before it is in <export>, sha256 <digest>" instead
// of leaving an operator to wonder why the trail does not start at 1.
Anchored bool
AnchorID int64
PrunedCount int64
ExportPath string
ExportSHA256 string
// VerifiedFromID is the id of the first row the walk checked, or 0 when
// the table is empty.
VerifiedFromID int64
// Gaps counts the audit.gap rows the walk passed (Task 20404): records,
// written into the chain itself, of events that could not be appended.
// GapEvents is how many lost events they cover, GapIDs the first few of
// their ids and LastGapAt when the newest was written. A chain with gaps
// is intact — every row present hashes correctly — but it is not
// complete, and Status says so.
Gaps int
GapEvents int64
GapIDs []int64
LastGapAt time.Time
}
AuditVerifyReport summarises a chain-verification run.
func (AuditVerifyReport) Status ¶ added in v0.0.5
func (r AuditVerifyReport) Status() string
Status names the verdict: AuditChainIntact, AuditChainGaps or AuditChainBroken.
type AutoUpdatePolicy ¶ added in v0.0.3
type AutoUpdatePolicy struct {
Policy autoupdate.Policy `json:"policy"`
SetAt time.Time `json:"set_at,omitempty"`
SetBy string `json:"set_by,omitempty"`
}
AutoUpdatePolicy is the stored policy plus its provenance.
func AutoUpdatePolicyFor ¶ added in v0.0.3
func AutoUpdatePolicyFor(d *DB) (AutoUpdatePolicy, error)
AutoUpdatePolicyFor returns the fleet's policy.
A fleet that has never been configured yields a disabled zero policy and no error. "Nobody has set this" and "automatic upgrades are off" are the same operational state, and making the caller distinguish them would put an error path in front of the overwhelmingly common case.
type BrokerGrantRow ¶
type BrokerGrantRow struct {
ID string
SecretID string
Scope string
SubjectType string
SubjectValue string
ConstraintsJSON string
ExpiresAt string
CreatedAt string
CreatedBy string
RevokedAt string
// Owner is denormalised from the secret this grant points at, so a grant
// listing can be scoped without resolving each row's secret.
Owner string
// RevokedCause is why a revoked grant was revoked — "owner_offboarded",
// "secret_deleted", "superseded", or "" — see migration 0062.
RevokedCause string
// SupersededBy names the grant that replaced a superseded one — see
// migration 0063.
SupersededBy string
// SuspendedAt and SuspendedBy record a grant suspended because its owner
// was deactivated at the identity provider (Task 20415, migration 0067).
// Written by the SCIM suspension and its lift and by nothing else:
// PutBrokerGrant sets them on insert and never on update, so a writer
// holding a copy read before the suspension cannot clear it by saving.
SuspendedAt string
SuspendedBy string
// UnguardedAckAt, UnguardedAckBy and UnguardedAckReason record an
// administrator's acknowledgement that a kubeconfig grant may be
// delivered without the Kubernetes access monitor (Task 20420, migration
// 0070). Written by SetBrokerGrantUnguardedAck alone: PutBrokerGrant sets
// them on insert and never on update.
UnguardedAckAt string
UnguardedAckBy string
UnguardedAckReason string
}
BrokerGrantRow is one row of broker_grants.
type BrokerSecretRow ¶
type BrokerSecretRow struct {
ID string
Kind string
Name string
Payload []byte // ciphertext under this row's DEK; never plaintext
// KeyID names the KEK that WrappedDEK is sealed under, or "legacy" for
// rows predating envelope encryption (Task 20181). WrappedDEK is the
// row's data key, itself sealed. Neither is key material on its own.
KeyID string
WrappedDEK []byte
MetadataJSON string
CreatedAt string
CreatedBy string
// Owner is the identity that personally owns this secret, or "" for a
// shared one. See migration 0039.
Owner string
}
BrokerSecretRow is one row of broker_secrets. Times are RFC3339 strings, matching the rest of the schema.
type BrokerSecretTombstoneRow ¶ added in v0.0.5
type BrokerSecretTombstoneRow struct {
SecretID string
Name string
Kind string
Owner string
DeletedAt string
DeletedBy string
// Cause is "deleted" or "offboarded"; see migration 0062.
Cause string
Reason string
}
BrokerSecretTombstoneRow is one row of broker_secret_tombstones: what a deleted secret was, kept so a grant left pointing at it can still name it (migration 0062, Task 20400). Metadata only — nothing sealed survives a delete.
type CIExchangeRow ¶ added in v0.0.2
type CIExchangeRow struct {
ID string `json:"id"`
At time.Time `json:"at"`
Accepted bool `json:"accepted"`
Issuer string `json:"issuer,omitempty"`
Subject string `json:"subject,omitempty"`
Repository string `json:"repository,omitempty"`
Ref string `json:"ref,omitempty"`
Workflow string `json:"workflow,omitempty"`
Actor string `json:"actor,omitempty"`
EventName string `json:"event_name,omitempty"`
RunID string `json:"run_id,omitempty"`
RuleID string `json:"rule_id,omitempty"`
RuleName string `json:"rule_name,omitempty"`
SessionID string `json:"session_id,omitempty"`
// Reason is a stable code; Detail is the human-readable explanation. The
// pair exists so a dashboard can group by cause while still showing the
// sentence that names the actual problem.
Reason string `json:"reason,omitempty"`
Detail string `json:"detail,omitempty"`
RemoteAddr string `json:"remote_addr,omitempty"`
// Claims is the verified payload, or nil on a token that never verified.
Claims map[string]any `json:"claims,omitempty"`
}
CIExchangeRow is one recorded federation attempt.
type CIPipelineRuleRow ¶ added in v0.0.2
type CIPipelineRuleRow struct {
ID string `json:"id"`
Name string `json:"name"`
Enabled bool `json:"enabled"`
Repository string `json:"repository,omitempty"`
Ref string `json:"ref,omitempty"`
Workflow string `json:"workflow,omitempty"`
Environment string `json:"environment,omitempty"`
Actor string `json:"actor,omitempty"`
EventName string `json:"event_name,omitempty"`
Condition string `json:"condition,omitempty"`
Models []string `json:"models,omitempty"`
MaxRequests int `json:"max_requests,omitempty"`
MaxOutputTokens int `json:"max_output_tokens,omitempty"`
TTLSeconds int `json:"ttl_seconds,omitempty"`
Project string `json:"project,omitempty"`
CreatedBy string `json:"created_by,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
LastMatchedAt time.Time `json:"last_matched_at,omitempty"`
}
CIPipelineRuleRow is one persisted allowlist entry.
type CISessionFilter ¶ added in v0.0.5
type CISessionFilter struct {
RuleID string
Holder string
// OpenOnly drops closed sessions.
OpenOnly bool
}
CISessionFilter narrows ListCISessions. Zero fields do not filter.
type CISessionRow ¶ added in v0.0.5
type CISessionRow struct {
SessionID string
// TokenSHA256 is the hex SHA-256 of the session token the pipeline
// presents.
TokenSHA256 string
// RuleID is the allowlist rule that admitted the pipeline.
RuleID string
// Holder is the hub process serving the session.
Holder string
// Instance is the hub instance whose configuration governs the session:
// the port of the process that minted or last restored it.
Instance string
// Provenance is the JSON account of the pipeline the rule admitted: the
// rule's name, the project it binds, and the verified claims of the OIDC
// token the session was minted for.
Provenance string
// Policy is the JSON account of what the session may do.
Policy string
// Counters is the JSON checkpoint of what the session has spent.
Counters string
IssuedAt time.Time
ExpiresAt time.Time
LastUsedAt time.Time
UpdatedAt time.Time
ClosedAt time.Time
CloseReason string
}
CISessionRow is one minted CI relay session. It says who serves the session, which pipeline it was minted for, what it may do and how its token hashes — never a token, and never the credential the relay presents upstream.
func (CISessionRow) Open ¶ added in v0.0.5
func (r CISessionRow) Open() bool
Open reports whether the session has not been closed.
type CapPauseInput ¶ added in v0.0.2
type CapPauseInput struct {
// ProjectPath is the working directory whose run was stopped.
ProjectPath string
// Windows names the tripped windows ("five_hour", "weekly", ...).
Windows []string
// Utilization and Cap are the global utilization and the configured
// per-project ceiling that it reached, for the first tripped window.
Utilization float64
Cap float64
// ResumesAt is when every tripped window has rolled over. Zero when the
// usage API did not report a reset, in which case the row says so rather
// than inventing a time a resume could later be matched against.
ResumesAt time.Time
// Detail is the operator-facing phrase stored as the pause reason.
Detail string
Actor string
}
CapPauseInput is one run stopped by a Claude Code subscription cap.
type CapResumeInput ¶ added in v0.0.2
type CapResumeInput struct {
ProjectPath string
// PausedDetail is the pause reason the run carried, so the row names the
// wall it was waiting on.
PausedDetail string
// ResumesAt is the instant the run was waiting for, and ResumedAt is when
// the hub actually acted. The gap between them is the sweep interval, and
// having both is what distinguishes a late sweep from a wrong reset time.
ResumesAt time.Time
ResumedAt time.Time
Actor string
}
CapResumeInput is one cap-paused run restarted by the hub on its own.
type CostEntry ¶
type CostEntry struct {
Timestamp time.Time
TaskID int
TaskTitle string
Provider string
Model string
InputTokens int
OutputTokens int
ThinkingTokens int
EstimatedUSD float64
// Identity is who this spend is attributed to — an oidcauth OwnerKey, or
// the "local" sentinel for an unauthenticated run (Task 20264). Empty on
// rows written before migration 0035, which means *unattributed* rather
// than unowned. Self-reported by the orchestrator; see 0035 for why quota
// enforcement deliberately does not read it.
Identity string
// RowID is the costs.id of this row. Set by the readers that select it,
// zero elsewhere (AppendCost does not read it back).
//
// It exists for the hub's spend drain, which needs a watermark it can
// resume from without double-booking. A timestamp cannot serve: two tasks
// finishing in the same nanosecond collide, and a clock adjustment moves
// one backwards — either would book a tenant twice or not at all. The
// autoincrement id is monotonic in insertion order, which is the order the
// drain actually walks.
RowID int64
}
CostEntry records the cost of one task execution in the costs table.
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB is a thread-safe handle to the SQLite state database. Open one DB per workdir; Close it when done.
func Open ¶
Open opens (or creates) the SQLite database at dbPath, applies tuning pragmas, and runs any pending schema migrations.
Concurrency model: every cloop process (Web UI, orchestrator, CLI commands) opens its own *DB handle pointing at the same .cloop/state.db file. WAL mode + busy_timeout coordinate them at the SQLite file level, so writes from one process do not return SQLITE_BUSY to readers in another.
Errors returned by this function may wrap the typed sentinels ErrDBLocked or ErrSchemaMismatch — callers should use errors.Is to distinguish them from generic open failures. A database migrated past this binary's schema is refused with ErrSchemaTooNew rather than opened; see schema_guard.go.
func OpenWithOptions ¶
func OpenWithOptions(dbPath string, opts OpenOptions) (*DB, error)
OpenWithOptions is Open with the version-skew opt-out under the caller's control rather than the environment's.
func (*DB) AbandonKEKs ¶ added in v0.0.5
AbandonKEKs retires the given keys although sealed rows still reference them, and returns the ids it retired (Task 20410).
RetireKEK refuses exactly this, and it is right to: retiring a referenced key destroys what the rows hold. AbandonKEKs exists for the one caller that has already decided that — `cloop db restore --accept-secret-loss`, restoring a backup whose keys the hub's CLOOP_SECRET_KEY cannot derive. Left live, those keys stop the hub starting at all (secretbroker.OpenKeyring refuses a registry with a live key it cannot derive, rather than fork it); retired, the hub mints a fresh primary and every row sealed under them reports that its key was retired and its material cannot be recovered — which is now the truth. The backup file itself still holds the salts.
func (*DB) AcquireHubLease ¶
func (d *DB) AcquireHubLease(row HubLeaseRow, expect HubLeaseRow) (bool, error)
AcquireHubLease takes the lease for row.Scope, conditioned on the current row still matching expect.
It returns true when the lease was taken and false when it was not, without an error in either case: losing a race is an ordinary outcome here, not a failure, and the caller needs to re-read the row to describe the winner anyway.
expect is the row the caller previously read, and is the entire concurrency story. A zero-valued expect means "I saw no row": the INSERT then succeeds only if none appeared in the meantime, because a conflict falls through to a DO UPDATE whose WHERE cannot match. A populated expect means "I saw this row and judged it takeable": the update applies only if it is still byte-for-byte that row, so a holder that renewed in the intervening microseconds keeps its lease and this caller is told it lost.
This is one statement on purpose. SQLite applies it atomically without an explicit transaction, which avoids the read-then-upgrade pattern that deadlocks two processes against each other under WAL — the exact failure the busy_timeout cannot absorb.
func (*DB) AddExecutorAudience ¶ added in v0.0.3
AddExecutorAudience admits a principal to an executor. Adding one that is already admitted refreshes its provenance rather than failing, so the UI's "add" button is idempotent.
Note what the first successful call does: it turns the gate on for that executor, because an executor with no rows is unrestricted. The caller is responsible for not locking the fleet out of itself — see pkg/ui/executoraudience.go, which refuses an add that would leave the calling admin unable to reach the executor they just restricted.
func (*DB) AdjustQuotaCounter ¶ added in v0.0.5
func (d *DB) AdjustQuotaCounter(identity, resource, bucket string, delta, limit float64, enforce bool, at time.Time) (value float64, admitted bool, err error)
AdjustQuotaCounter adds delta to one counter in a single write transaction and returns the value afterwards (Task 20354).
It is the operation several hub processes sharing one control plane need and PutQuotaCounter cannot give them: PutQuotaCounter stores an absolute value each process computed from its own memory, so two processes admitting at once each write "one more than I saw" and one admission vanishes — and each process checks the limit against its own count, so N processes admit N times the cap.
With enforce set and delta positive, the addition is refused — admitted is false and the counter unchanged — when it would take the value above limit. Check and increment share the transaction, which statedb opens IMMEDIATE, so no other writer can land between them. The result never goes below zero: a double release must not mint headroom.
func (*DB) AdvanceSpendCursor ¶ added in v0.0.2
AdvanceSpendCursor moves the booking position from `from` to `to`, and reports whether this caller was the one that moved it.
It is a compare-and-swap, not a plain update, and the caller must book the spend only when it returns won=true. That is what makes the claim to charge each row exactly once true rather than merely likely:
Across processes. Two hubs run from this repository (ports 8080 and 8888) and share one control-plane database. A plain monotonic update ("only move forward") does not help: both can read cursor=100, both read rows 101-110, and both charge them — the guard fires after the double-book, on the second write, too late to matter. With a CAS only one UPDATE matches, so only one of them books.
On failure. Booking first and advancing second means a failed advance re-presents the same rows on the next tick, and a control plane that stays unwritable (SQLITE_BUSY past the busy timeout, a read-only mount, a full disk) inflates the tenant's counter by that batch every thirty seconds until the budget is spent and the run is killed on arithmetic that never happened. Advancing first converts that unbounded failure into a bounded one: a process that dies between the CAS and the booking loses exactly one batch, once.
Under-billing a bounded amount once is a cost; over-billing repeatedly stops work that should be running. The order is chosen accordingly.
func (*DB) AllExecutorAudiences ¶ added in v0.0.3
func (d *DB) AllExecutorAudiences() (map[string][]ExecutorAudienceEntry, error)
AllExecutorAudiences returns every audience row keyed by executor ID.
One query rather than one per executor, because the fleet list renders an "available to" summary for every card and the per-executor form would make that N+1 round trips against a database the dispatch path also uses.
func (*DB) Analyze ¶
Analyze runs ANALYZE to refresh the query planner's per-index statistics. Cheap on small databases; on large ones it scales roughly with total row count across all indexes.
func (*DB) AppendAuditEvent ¶
func (d *DB) AppendAuditEvent(ev *AuditEvent) error
AppendAuditEvent appends one row to the audit_events table, computing the hash chain link from the previous row. Holds the DB mutex so the chain is consistent under concurrent writers in the same process. Cross-process safety is provided by SQLite WAL + busy_timeout — concurrent writers serialise at the file level.
Mutates ev in place: the assigned ID, computed hashes, and any auto-populated fields (Timestamp, Actor) are written back so callers can inspect them.
func (*DB) AppendAuditEvents ¶
func (d *DB) AppendAuditEvents(evs []*AuditEvent) error
AppendAuditEvents chains and inserts a whole batch in a single transaction.
This is the bulk path, and the reason it exists is measured: emitting a 417-task plan through AppendAuditEvent cost 417 transactions and 417 tip reads per SaveState, which is most of what made the audit trail expensive enough to notice. Chaining in-process and writing once is the same chain with one commit.
Events are chained in slice order, so callers control causal order. Each element is mutated in place with its assigned ID and hashes. A nil or empty slice is a no-op; a nil element, or one with an empty event type, is an error and nothing is written.
func (*DB) AppendCost ¶
AppendCost inserts a cost entry into the costs table.
func (*DB) AppendHubEvents ¶ added in v0.0.5
func (d *DB) AppendHubEvents(events []HubEventRow) (int64, error)
AppendHubEvents publishes events in one transaction and returns the sequence number of the last one. Batching is what keeps a chatty run's live output from costing one write transaction per line.
func (*DB) AppendMaintenanceLog ¶
func (d *DB) AppendMaintenanceLog(e MaintenanceLogEntry) (int64, error)
AppendMaintenanceLog inserts a maintenance_log row. Returns the new row id. StartedAt / CompletedAt default to time.Now().UTC() when zero so callers don't have to fill them in for ad-hoc records.
func (*DB) AppendProviderCall ¶
func (d *DB) AppendProviderCall(row ProviderCallRow) (int64, error)
AppendProviderCall inserts one provider-call row and returns the assigned id. Best-effort: errors are wrapped through classifyDriverErr so callers can distinguish ErrDBLocked from real corruption, but production code paths typically log-and-discard.
func (*DB) AppendStep ¶
AppendStep inserts a step row (idempotent on step number).
func (*DB) AppendTelemetry ¶ added in v0.0.2
AppendTelemetry stores a normalized batch and enforces the row ceiling.
Takes the whole batch in one transaction: a trail's value is its ordering, and a partially-written batch would show a reader a gap that never happened.
func (*DB) AsControlPlane ¶ added in v0.0.2
AsControlPlane marks d as the hub's control-plane handle and returns it, so it can be chained onto an Open:
db, err := statedb.Open(state.DBPath(s.WorkDir)) ... db.AsControlPlane()
Marking is idempotent and safe to repeat.
func (*DB) AttributeRequestUseTasks ¶ added in v0.0.2
AttributeRequestUseTasks stamps the task a recorded lease was dispatched for onto the use rows that do not have one yet, and reports how many it filled in.
It exists because a lease is issued *before* the workload that will hold it is dispatched. At lease time the broker knows the executor and the project and genuinely does not know the task — there is no task yet — so the use row starts with task_id 0 and the answer arrives a moment later, when the driver writes an executor_handles row carrying both the task and the lease bindings that workload was started with.
Reconciling the two afterwards is therefore the only way to get the attribution at all, and it has to happen while the handle is still live: handle rows are deleted when the workload reaches a terminal state, so a reconciliation that only ran on demand would report nothing for exactly the runs that have finished — which are the ones an approver reviews. Callers run it on the same schedule they sweep expired requests, and again when listing.
Idempotent and monotonic: it only fills in zeros (the UPDATE's guard, and PutGrantRequestUse's) so a handle that has since been reused for other work cannot rewrite an attribution already made.
func (*DB) AuditCheckpointWindowMarker ¶ added in v0.0.5
func (d *DB) AuditCheckpointWindowMarker() (AuditCheckpointWindow, bool, error)
AuditCheckpointWindowMarker reads the window marker, for status output.
func (*DB) AuditDistinctActors ¶
AuditDistinctActors returns the set of distinct actor values across the audit log, sorted ascending. Used by the Web UI's filter dropdown so the user sees only actors that actually exist.
func (*DB) AuditDistinctEntityTypes ¶
AuditDistinctEntities returns the set of distinct (entity_type, entity_id) pairs as "type/id" strings (id may be empty for singletons). Sorted.
func (*DB) AuditGapSummary ¶ added in v0.0.5
func (d *DB) AuditGapSummary() (AuditGapSummary, error)
AuditGapSummary totals the chain's audit.gap rows through the event_type index. It is the cheap question `cloop hub doctor` asks; VerifyAuditChain is the thorough one.
func (*DB) AuditHead ¶ added in v0.0.5
AuditHead reads the chain's newest row, its row count and its newest anchor.
Three plain reads rather than one transaction: every transaction this package opens takes the write lock at BEGIN (connpolicy.go), and a checkpoint must neither stall writers nor fail on a database that has stopped taking writes — that is exactly when its record matters. Holding d.mu orders them against this handle's own appends; another process appending in between moves the head forward, which describes a later moment rather than an inconsistent one.
func (*DB) AuditRowAt ¶ added in v0.0.5
func (d *DB) AuditRowAt(id int64) (AuditEvent, bool, error)
AuditRowAt returns the row with id, and whether there is one.
func (*DB) BindProjectExecutor ¶
BindProjectExecutor pins projectPath to executorID. The executor must already exist, so a typo cannot strand a project on a nonexistent backend.
func (*DB) BrokerMeta ¶
BrokerMeta reads a broker-scoped metadata value.
func (*DB) CheckpointCISession ¶ added in v0.0.5
CheckpointCISession replaces an open session's counters and last use, provided holder holds it, and reports whether it did.
func (*DB) CheckpointProxySession ¶ added in v0.0.5
CheckpointProxySession replaces an open session's counters, provided holder holds it, and reports whether it did.
func (*DB) ClaimAuditCheckpointWindow ¶ added in v0.0.5
func (d *DB) ClaimAuditCheckpointWindow(w int64, interval time.Duration, member string, now time.Time, stale time.Duration) (AuditCheckpointClaim, error)
ClaimAuditCheckpointWindow decides, under one write transaction, whether member writes checkpoint window w of interval.
- Nothing claimed yet, an older window, or a window numbered under another interval (the interval was changed): w is claimed.
- w, or the window before it, claimed and not written: by member itself (a retry) or by a member whose claim is older than stale (it died between claiming and writing), that window is claimed — late, if it is the one before; by anybody else, not claimed, and RetryAt says when the claim lapses.
- w already written, or the next window claimed (that member is ahead): not claimed.
- Further ahead than that: the marker cannot be right, and is replaced.
func (*DB) ClaimExecutorHandleMeta ¶ added in v0.0.5
ClaimExecutorHandleMeta sets the meta key of handleID's row to value, provided it holds expect now — absent counts as "" — and reports whether it did (Task 20419). It is a compare-and-swap on the whole meta document: the row is re-read and the write conditioned on what was read, so of two hub processes adopting one workload row only one records itself as its owner, whichever process each runs in. A row that is gone is not claimed.
func (*DB) ClaimExecutorSessionRequeue ¶
func (d *DB) ClaimExecutorSessionRequeue(id, claimToken, newClaimToken string, maxAttempts int, at time.Time) (ExecutorSessionRow, error)
ClaimExecutorSessionRequeue atomically claims a running session for failover and rotates its claim token.
The exactly-once guarantee lives entirely in this statement's WHERE clause. SQLite serialises writers, so of N supervisors racing to fail over the same dead executor exactly one finds state = 'running' with the claim token it read and updates a row; every other supervisor matches nothing and gets ErrExecutorSessionClaimLost. Rotating claim_token in the same statement also makes a retry by the winner idempotent-safe: the old token can never match again.
A read-then-write implementation would let two supervisors both decide the session is running and both requeue the work — which here means two AI agents editing the same repository concurrently. That is the failure this function exists to make impossible, so the read and the write must not be separable.
The failover cap is decided in the same statement (Task 20391). A session whose attempt is at most maxAttempts — re-dispatched fewer times than the cap — becomes requeued; one past it becomes failover_exhausted, and the returned row's State says which. Deciding it here rather than in the caller is what makes every supervisor and every hub member agree: whoever wins the claim also fixes the session's fate, and a loser has nothing left to decide differently. maxAttempts below zero is read as zero — no re-dispatch — because no reading of a bad cap may be "no cap".
The follow-up read on a zero-row update is only to tell the operator which of two situations they are in; it never grants a claim, so a row appearing or vanishing between the two statements cannot turn a loss into a win.
func (*DB) ClaimHubOwner ¶ added in v0.0.5
func (d *DB) ClaimHubOwner(row, expect HubOwnerRow) (bool, error)
ClaimHubOwner takes (row.Kind, row.Key) for row.InstanceID, conditioned on the current row still matching expect — the compare-and-swap AcquireHubLease documents. A zero expect means "I saw no owner"; a populated one means "I saw this owner and judged it gone". It reports whether the claim was taken.
func (*DB) ClaimProjectPath ¶ added in v0.0.5
func (d *DB) ClaimProjectPath(claim ProjectClaim, stale func(ProjectClaim) bool) (held *ProjectClaim, err error)
ClaimProjectPath records that claim.Path is being created.
It refuses when a live claim is the same path, inside it, or above it, and returns that claim; held is nil when the path was claimed. stale decides which existing claims no longer hold their path — a creation that died with its hub, a project removed from the registry by hand — and those are deleted in the same transaction. A nil stale treats every claim as live.
claim.Path must be canonical (projectconfine.Canonical).
func (*DB) ClearAdoptRequest ¶ added in v0.0.5
ClearAdoptRequest removes the stored request if it is still the one with id, and reports whether it did. Compare-and-clear, inside one write transaction: the run clears the request it acted on, and must not clear a second one filed meanwhile.
func (*DB) ClearExecutorAudience ¶ added in v0.0.3
ClearExecutorAudience removes every principal, making the executor unrestricted. It is what executor deletion calls, so a re-enrolled executor reusing an ID does not inherit a stale allowlist.
func (*DB) ClearExecutorFirewall ¶ added in v0.0.5
ClearExecutorFirewall removes executorID's rule set. Clearing an absent one is not an error.
func (*DB) ClearExecutorResourceLimit ¶ added in v0.0.3
ClearExecutorResourceLimit removes the ceiling for executorID. Clearing an executor that was never capped is not an error.
func (*DB) ClearExecutorSandbox ¶ added in v0.0.3
ClearExecutorSandbox removes the configuration for executorID, returning it to the executor's own default. Clearing an executor that was never configured is not an error.
func (*DB) ClearHubLease ¶
ClearHubLease marks a lease released on behalf of an operator, conditioned on the row still matching expect.
This backs the `cloop hub lease clear` escape hatch. The compare-and-swap is what makes the command's staleness gate meaningful: the caller checks that the lease is stale and then clears it, and if the holder heartbeats in between, the observed heartbeat no longer matches and the clear is refused. Without it the gate would be advisory and the command could evict a hub that had just come back.
func (*DB) ClearKill ¶
ClearKill removes the kill row for taskID. Idempotent — clearing a row that does not exist returns nil.
func (*DB) ClearProjectFirewall ¶ added in v0.0.5
ClearProjectFirewall removes the project's rule set.
func (*DB) ClearProjectResourceLimit ¶ added in v0.0.2
ClearProjectResourceLimit removes the ceiling for projectPath. Clearing a project that was never capped is not an error.
func (*DB) ClearTaskQuarantine ¶ added in v0.0.5
ClearTaskQuarantine is the explicit reset's half: it removes a task's mark and the losses behind it, so the task starts again with no evidence against it. It reports whether there was a mark to remove.
The losses go with the mark on purpose. A reset is a person deciding the task deserves another chance; keeping its old losses would quarantine it again on the first node lost afterwards, which is not another chance. The audit trail and the event journal keep the history.
func (*DB) CloseCISession ¶ added in v0.0.5
CloseCISession marks an open session closed with reason, provided holder holds it, and reports whether it did. counters, when non-empty, replaces the checkpoint with the session's final count. A session closed once stays closed: nothing restores it, and a second close changes nothing.
func (*DB) CloseCISessionAny ¶ added in v0.0.5
CloseCISessionAny marks an open session closed whoever holds it, and reports whether it did: an operator's revocation, which must land whether or not the process holding the record is the one asked, or alive. The holder, if live, stops serving it at its next checkpoint.
func (*DB) CloseCISessionsForRule ¶ added in v0.0.5
func (d *DB) CloseCISessionsForRule(ruleID string, at time.Time, reason string) ([]CISessionRow, error)
CloseCISessionsForRule closes every open session ruleID minted, whoever holds it, and returns them as they were before the close. It is how an operator's edit, disable or deletion of a rule reaches a session no process is serving at that moment, which would otherwise be restored later under a rule that no longer stands.
func (*DB) CloseExecutorSession ¶
CloseExecutorSession moves a running session to a terminal state. Returns ErrExecutorSessionNotFound when the ID is unknown, so a driver reporting completion for a session the control plane never opened surfaces loudly instead of being silently dropped.
A session that is no longer running is left as it is and the call succeeds: its end is already recorded. That matters for the one writer that gets there first on purpose — a failover's claim, which records requeued or failover_exhausted (Task 20391). The workload's own watcher notices the end much later, often only when the dead node's stream finally closes, and before this condition its close overwrote the claim's verdict with "failed": the exhausted session vanished from the record, and with it what stops a re-dispatch.
func (*DB) CloseProxySession ¶ added in v0.0.5
func (d *DB) CloseProxySession(kind, id, holder string, at time.Time, reason, counters string) (bool, error)
CloseProxySession marks an open session closed with reason, provided holder holds it, and reports whether it did. counters, when non-empty, replaces the checkpoint with the session's final count. A session closed once stays closed: nothing restores it, and a second close changes nothing.
func (*DB) CompleteAuditCheckpointWindow ¶ added in v0.0.5
CompleteAuditCheckpointWindow marks window w written, if member still holds it. Reports whether it did: a member whose claim was taken over in the meantime does not overwrite the new holder's marker.
func (*DB) CompleteProjectClaim ¶ added in v0.0.5
CompleteProjectClaim marks a claim created, and records whether this hub made the directory and under which projects root. It fails when there is no claim on path to complete.
func (*DB) CountBrokerSecretsByKey ¶
CountBrokerSecretsByKey groups secrets by the key they are sealed under.
func (*DB) CountDeviceAuthorizations ¶ added in v0.0.5
CountDeviceAuthorizations counts the rows with created_at after since — the code-issuing rate a hub with several members shares.
func (*DB) CountEvents ¶
CountEvents returns the total number of journal rows. Cheap; used by the UI to decide whether to refresh the top page.
func (*DB) CountHubTLSByKey ¶ added in v0.0.5
CountHubTLSByKey groups the rows by the key sealing their private keys.
func (*DB) CountLiveSessions ¶ added in v0.0.5
func (d *DB) CountLiveSessions(c SessionCutoffs) (int, error)
CountLiveSessions counts the sessions DeleteExpiredSessions would keep under the same cutoffs. A count rather than a listing, so nothing sealed leaves the row.
func (*DB) CountRunningExecutorSessions ¶
CountRunningExecutorSessions returns how many sessions are still in flight. An empty executorID counts across the whole fleet.
func (*DB) CountSessionsByKey ¶
CountSessionsByKey groups sessions holding a refresh token by sealing key.
Sessions with no refresh token are excluded: they hold nothing sealed, so counting them would make a rotation look permanently incomplete on a hub whose IdP issues no refresh tokens.
func (*DB) CreateVirtualExecutor ¶ added in v0.0.5
func (d *DB) CreateVirtualExecutor(v VirtualExecutor) error
CreateVirtualExecutor records a new virtual executor and the executors-table row that makes it bindable, in one transaction.
The ID must be free across *every* executor the control plane knows: a virtual executor that shared an ID with a device would inherit that device's bindings, ceiling and access list, and a binding meant for one would run on the other.
func (*DB) CurrentSchemaVersion ¶
CurrentSchemaVersion returns the highest migration version recorded in the database. Useful for diagnostic commands (cloop db verify, cloop migrate status). Acquires the DB mutex like other read helpers in this package.
func (*DB) DeleteAppTokenSlot ¶ added in v0.0.5
DeleteAppTokenSlot forgets one slot, provided holder holds it.
func (*DB) DeleteAppTokenSlots ¶ added in v0.0.5
DeleteAppTokenSlots forgets the slots of leaseID that holder holds, and returns how many went.
func (*DB) DeleteBrokerSecret ¶
DeleteBrokerSecret removes a secret. Deleting one that does not exist is an error, so a CLI can tell the operator their reference was wrong instead of reporting a successful no-op.
func (*DB) DeleteBrokerSecretTombstoned ¶ added in v0.0.5
func (d *DB) DeleteBrokerSecretTombstoned(id string, tomb BrokerSecretTombstoneRow) error
DeleteBrokerSecretTombstoned removes a secret and records its tombstone in the same transaction, so there is no moment at which the row is gone and nothing remembers what it was. A tombstone already present for the id — a secret deleted, re-minted under the same id by a restore, and deleted again — is replaced by the newer one.
func (*DB) DeleteCIPipelineRule ¶ added in v0.0.2
DeleteCIPipelineRule removes a rule. It reports whether a row was removed, so the caller can tell "deleted" from "already gone" without a prior read.
func (*DB) DeleteCISession ¶ added in v0.0.5
DeleteCISession forgets a session, provided holder holds it, and reports whether a row went. It is how the janitor retires the record of a session that closed or lapsed.
func (*DB) DeleteDeviceAuthorizationsBefore ¶ added in v0.0.5
func (d *DB) DeleteDeviceAuthorizationsBefore(cutoff time.Time) ([]DeviceAuthorizationRow, error)
DeleteDeviceAuthorizationsBefore removes the rows whose expires_at is at or before cutoff and returns them, so the caller can act on an approval nobody collected. Read and deleted in one transaction, for the reason DeleteExpiredSessions gives.
func (*DB) DeleteDispatchIntent ¶ added in v0.0.5
DeleteDispatchIntent forgets one intent. A missing row is not an error: the run's record and its end both retire it, and either may come second.
func (*DB) DeleteDispatchIntentForHandle ¶ added in v0.0.5
DeleteDispatchIntentForHandle forgets the intent naming handleID on executorID, and reports whether one went: what recording the run does, which knows the workload by its handle rather than by the run id.
func (*DB) DeleteExecutor ¶
DeleteExecutor removes an executor and every project binding that pointed at it. Both happen in one transaction so a project can never be left pinned to an executor that no longer exists — such a project would fail every Resolve until an operator noticed.
func (*DB) DeleteExecutorHandle ¶
DeleteExecutorHandle forgets one row. Deleting a row that is not there is not an error: a terminal transition can be recorded twice (once by the log pump, once by an explicit reap) and neither call should fail.
func (*DB) DeleteExecutorHealth ¶
DeleteExecutorHealth forgets the health record for executorID. Deleting a row that was never written is not an error: de-enrolling an executor that was never probed must not fail.
func (*DB) DeleteExpiredSessions ¶
func (d *DB) DeleteExpiredSessions(c SessionCutoffs) ([]SessionRow, error)
DeleteExpiredSessions removes sessions past one of c's cutoffs and returns what it deleted.
The absolute cutoff is compared against expires_at (the ceiling set at login) and the idle cutoffs against last_seen, each kind against its own: a CLI session idles out on a clock no longer than a browser's (Task 20412). All are absolute times computed by the caller from its configured policy, so this layer stays free of any opinion about how long a session should live.
func (*DB) DeleteHubMeta ¶ added in v0.0.2
DeleteHubMeta removes a hub-scoped metadata value. Deleting one that is not there succeeds: the caller asked for it to be gone, and it is.
func (*DB) DeleteLegalHold ¶ added in v0.0.5
func (d *DB) DeleteLegalHold(identity string, audit *AuditEvent) (bool, error)
DeleteLegalHold releases a hold, reporting whether one was placed.
func (*DB) DeleteOrphanedAppTokenSlots ¶ added in v0.0.5
DeleteOrphanedAppTokenSlots forgets every slot whose lease has no record any more — released, retired or swept — and returns how many went. The janitor's sweep: a slot outlives its lease only when the process holding both stopped between the two deletes.
func (*DB) DeleteProjectMember ¶ added in v0.0.5
func (d *DB) DeleteProjectMember(projectPath, identityKey string, audit MemberAudit) (*ProjectMemberRow, error)
DeleteProjectMember removes one membership and returns the row it removed, or nil when there was none — in which case nothing is written and audit is not called, because nothing changed.
func (*DB) DeleteProjectMembersOf ¶ added in v0.0.5
func (d *DB) DeleteProjectMembersOf(projectPath string, audit MemberAudit) ([]ProjectMemberRow, error)
DeleteProjectMembersOf removes every membership on one project and returns the rows removed. Called when the project leaves the hub: memberships are keyed by path, and a roster outliving its project would admit those people to whatever is registered at that path next. audit is called once per removed row.
func (*DB) DeleteProxySession ¶ added in v0.0.5
DeleteProxySession forgets a session, provided holder holds it, and reports whether a row went. It is how the janitor retires the record of a session that closed or lapsed.
func (*DB) DeleteQuotaOverride ¶
DeleteQuotaOverride removes one identity's override, reporting whether a row existed.
func (*DB) DeleteRoleBinding ¶ added in v0.0.2
DeleteRoleBinding removes a binding, reporting whether a row existed.
func (*DB) DeleteSCIMGroup ¶ added in v0.0.5
func (d *DB) DeleteSCIMGroup(id string, audit []*AuditEvent) (bool, error)
DeleteSCIMGroup removes a provisioned group and its memberships.
func (*DB) DeleteSCIMUser ¶ added in v0.0.5
func (d *DB) DeleteSCIMUser(id string, audit []*AuditEvent) (bool, error)
DeleteSCIMUser removes a provisioned user and its group memberships, with its audit rows, after the offboarding that deleting one runs.
func (*DB) DeleteSecretLease ¶ added in v0.0.5
DeleteSecretLease forgets a lease, provided holder still holds it, and reports whether a row went. A missing row is not an error: a lease can be released twice — once when its run ends, once by a revocation that raced it — and neither call should fail.
func (*DB) DeleteSecretLeaseDir ¶
DeleteSecretLeaseDir forgets one directory, after it has been wiped.
Deleting a row that is not there is not an error: a lease can be wiped twice — once when its workload exits, once by a revocation that raced it — and neither call should fail.
func (*DB) DeleteSession ¶
DeleteSession removes one session and reports whether a row existed.
func (*DB) DeleteSessionsBySubject ¶
func (d *DB) DeleteSessionsBySubject(subject, keepID string) ([]SessionRow, error)
DeleteSessionsBySubject removes every session belonging to subject except the one named by keepID (pass "" to remove all of them), returning the rows it deleted so the caller can audit each one.
Read-then-delete inside one transaction: an audit entry the operator cannot tie to a specific session is not much of an audit entry, and doing it in two statements outside a transaction would let a login between them produce a row that is deleted but never recorded.
func (*DB) DeleteTask ¶
DeleteTask removes a single task by id. Returns nil even if the row did not exist — the post-condition (task absent) is satisfied either way.
func (*DB) DeleteVirtualExecutor ¶ added in v0.0.5
DeleteVirtualExecutor removes a virtual executor and everything keyed by its ID: its executors-table row, the projects bound to it, and its sandbox, ceiling and access-list rows. One transaction, because a half-deleted virtual executor whose access list survived would, if the ID were ever reused, hand the new one an audience nobody chose for it.
func (*DB) ExecutorAudience ¶ added in v0.0.3
func (d *DB) ExecutorAudience(executorID string) ([]ExecutorAudienceEntry, error)
ExecutorAudience returns the principals admitted to executorID, oldest first so the panel's order is stable as entries are added.
An empty slice with a nil error means the executor is unrestricted. An error means the question could not be answered, which callers must not read as "unrestricted" — see pkg/ui/executoraudience.go for the failure posture a gate requires, which is the opposite of the one a ceiling requires.
func (*DB) ExecutorFirewall ¶ added in v0.0.5
func (d *DB) ExecutorFirewall(executorID string) (FirewallRecord, bool, error)
ExecutorFirewall returns the device-level rule set stored for executorID.
func (*DB) ExecutorResourceCeiling ¶ added in v0.0.3
ExecutorResourceCeiling returns the ceiling for executorID.
The boolean is false when the executor has no ceiling, which the dispatch path reads as "the fleet and project ceilings alone apply" — deliberately distinct from an error, which means the lookup failed and must not be read as "uncapped". A storage fault that silently became "no limit" would remove the policy exactly when the hub is least healthy.
func (*DB) ExecutorSandboxRecord ¶ added in v0.0.3
func (d *DB) ExecutorSandboxRecord(executorID string) (ExecutorSandbox, bool, error)
ExecutorSandboxRecord returns the settings for executorID together with their provenance, for the fleet view that shows who chose an executor's containment.
func (*DB) ExecutorSandboxSettings ¶ added in v0.0.3
ExecutorSandboxSettings returns the settings for executorID.
The boolean is false when the executor has no row, which the dispatch path reads as "this executor keeps its own default" — deliberately distinct from an error, which means the lookup failed. The distinction matters in one direction especially: a storage fault that silently became "unset" would downgrade a container-mode executor to host execution exactly when the hub is least healthy, which is the failure this whole feature exists to prevent. See SandboxSettingsFor for the caller that has to choose what to do about it.
func (*DB) ExecutorSessionChain ¶ added in v0.0.5
func (d *DB) ExecutorSessionChain(id string) ([]ExecutorSessionRow, error)
ExecutorSessionChain returns the failover chain that ends at id, oldest first: the session the run was first dispatched as, then each replacement a failover opened (requeued_from), down to id itself (Task 20391). It is how a failover names every node a run has lost so far.
The walk is bounded (maxSessionChain) and refuses to revisit a session, so a cycle written into the table by hand ends the walk rather than the process. A predecessor that is gone — pruned by retention — ends it too: the chain is then what is left of it.
func (*DB) ExecutorSessionForHandle ¶ added in v0.0.5
func (d *DB) ExecutorSessionForHandle(executorID, handleID string) (ExecutorSessionRow, bool, error)
ExecutorSessionForHandle returns the session recorded for the workload handleID on executorID, the most recent one if several name it, and whether there is one (Task 20396).
It is how the hub learns, from a run it follows — which it knows by its executor and handle, not by its session — whether the failover claim has taken that run off its executor. Read from the table rather than told by the supervisor because the supervisor that claims a session is often in another process: another hub member, or this hub before a restart.
The executor_id half of idx_executor_sessions_executor_state narrows the scan to one executor's sessions.
func (*DB) ExecutorSessionSuccessor ¶ added in v0.0.5
ExecutorSessionSuccessor returns the session a failover opened to replace id, if there is one.
func (*DB) ExpireGrantRequests ¶ added in v0.0.2
func (d *DB) ExpireGrantRequests(now time.Time) ([]GrantRequestRow, error)
ExpireGrantRequests moves every pending request whose deadline has passed to the expired state, and returns the rows it changed.
Returning the rows rather than a count is what lets the caller emit one audit event per expiry. A request that lapses is a decision — nobody made one, and access was refused as a result — and the trail should say so with the same weight as a deny, so the requester can see why nothing happened.
Requests with no deadline (expires_at = ”) are left alone: the broker always sets one, and a row from some future path that deliberately has none should not be swept by a rule it never opted into.
func (*DB) ExtendProxySession ¶ added in v0.0.5
ExtendProxySession moves an open session's deadline, provided holder holds it, and reports whether it did.
func (*DB) ExtendSecretLease ¶ added in v0.0.5
ExtendSecretLease moves a lease's deadline, provided holder still holds it, and reports whether it did. A lease taken over by another process is not extended by the one that lost it.
func (*DB) FindSCIMGroups ¶ added in v0.0.5
func (d *DB) FindSCIMGroups(byDisplayName bool, value string) ([]SCIMGroupRow, error)
FindSCIMGroups returns the groups whose display name is name, compared lowercased, or whose external id is name, exactly.
func (*DB) FindSCIMUsers ¶ added in v0.0.5
func (d *DB) FindSCIMUsers(column, value string) ([]SCIMUserRow, error)
FindSCIMUsers returns the users whose column equals value: user_name_key or external_id_key compare lowercased values, external_id and email as given.
func (*DB) GetAPIToken ¶
func (d *DB) GetAPIToken(id string) (APITokenRow, error)
GetAPIToken returns one token by ID, or ErrAPITokenNotFound.
This is the verification path's only read, which is why the lookup is by primary key: an authenticated request must not cost a table scan, and a scan would additionally make request latency a function of how many tokens the hub has ever issued.
func (*DB) GetAgentCredential ¶
func (d *DB) GetAgentCredential(agentID string) (AgentCredentialRow, error)
GetAgentCredential returns one agent by ID, or ErrAgentCredentialNotFound.
func (*DB) GetBrokerGrant ¶
func (d *DB) GetBrokerGrant(id string) (BrokerGrantRow, error)
GetBrokerGrant returns one grant by ID.
func (*DB) GetBrokerSecret ¶
func (d *DB) GetBrokerSecret(id string) (BrokerSecretRow, error)
GetBrokerSecret returns one secret by ID.
func (*DB) GetBrokerSecretTombstone ¶ added in v0.0.5
func (d *DB) GetBrokerSecretTombstone(secretID string) (BrokerSecretTombstoneRow, error)
GetBrokerSecretTombstone returns the tombstone of a deleted secret, or a wrapped ErrBrokerSecretNotFound when nothing was recorded for the id — a secret deleted before tombstones existed, or one that never existed.
func (*DB) GetCIPipelineRule ¶ added in v0.0.2
func (d *DB) GetCIPipelineRule(id string) (CIPipelineRuleRow, error)
GetCIPipelineRule returns one rule by ID.
func (*DB) GetCISession ¶ added in v0.0.5
func (d *DB) GetCISession(id string) (CISessionRow, error)
GetCISession returns one session, or a wrapped ErrCISessionNotFound.
func (*DB) GetConfigBlob ¶
GetConfigBlob returns the YAML-serialised project config previously stored via SetConfigBlob. Returns ("", nil) when no blob has been written yet (fresh project, or DB created before this column existed).
func (*DB) GetDeviceAuthorization ¶ added in v0.0.5
func (d *DB) GetDeviceAuthorization(deviceHash string) (DeviceAuthorizationRow, error)
GetDeviceAuthorization returns the row for a device code digest, or an error wrapping ErrDeviceAuthorizationNotFound.
func (*DB) GetDeviceAuthorizationByUserCode ¶ added in v0.0.5
func (d *DB) GetDeviceAuthorizationByUserCode(userCodeHash string) (DeviceAuthorizationRow, error)
GetDeviceAuthorizationByUserCode returns the newest row for a user code digest. Newest, because the index is not unique: a code drawn again after its first holder expired would otherwise resolve to the dead one.
func (*DB) GetDispatchIntent ¶ added in v0.0.5
func (d *DB) GetDispatchIntent(runID string) (DispatchIntentRow, error)
GetDispatchIntent returns one intent, or a wrapped ErrDispatchIntentNotFound.
func (*DB) GetEgressGrant ¶
func (d *DB) GetEgressGrant(id string) (EgressGrantRow, error)
GetEgressGrant returns one grant by ID.
func (*DB) GetEnrollmentToken ¶
func (d *DB) GetEnrollmentToken(id string) (EnrollmentTokenRow, error)
GetEnrollmentToken returns one token by ID, or ErrEnrollmentNotFound.
func (*DB) GetExecutor ¶
func (d *DB) GetExecutor(id string) (ExecutorRow, error)
GetExecutor returns one executor by ID, or ErrExecutorNotFound.
func (*DB) GetExecutorHandle ¶
func (d *DB) GetExecutorHandle(handleID string) (ExecutorHandleRow, error)
GetExecutorHandle returns one row, or ErrExecutorHandleNotFound.
func (*DB) GetExecutorHealth ¶
func (d *DB) GetExecutorHealth(executorID string) (ExecutorHealthRow, error)
GetExecutorHealth returns one health row, or ErrExecutorHealthNotFound.
"Never probed" is deliberately an error rather than a zero-valued ready row: a caller that cannot tell the two apart would treat an unobserved executor as healthy, which is the failure mode this table exists to prevent.
func (*DB) GetExecutorSession ¶
func (d *DB) GetExecutorSession(id string) (ExecutorSessionRow, error)
GetExecutorSession returns one session by ID, or ErrExecutorSessionNotFound.
func (*DB) GetGrantRequest ¶ added in v0.0.2
func (d *DB) GetGrantRequest(id string) (GrantRequestRow, error)
GetGrantRequest returns one request by ID.
func (*DB) GetHubLease ¶
func (d *DB) GetHubLease(scope string) (HubLeaseRow, error)
GetHubLease returns the row for scope, or ErrHubLeaseNotFound.
func (*DB) GetHubOwner ¶ added in v0.0.5
func (d *DB) GetHubOwner(kind, key string) (HubOwnerRow, error)
GetHubOwner returns the owner row for (kind, key), or ErrHubOwnerNotFound.
func (*DB) GetProjectMember ¶ added in v0.0.5
func (d *DB) GetProjectMember(projectPath, identityKey string) (ProjectMemberRow, error)
GetProjectMember returns one membership, or an error wrapping ErrProjectMemberNotFound.
func (*DB) GetProxySession ¶ added in v0.0.5
func (d *DB) GetProxySession(kind, id string) (ProxySessionRow, error)
GetProxySession returns one session, or a wrapped ErrProxySessionNotFound.
func (*DB) GetRoleBinding ¶ added in v0.0.2
func (d *DB) GetRoleBinding(id string) (RoleBindingRow, error)
GetRoleBinding returns one binding by id, or ErrRoleBindingNotFound.
func (*DB) GetSCIMCredential ¶ added in v0.0.5
func (d *DB) GetSCIMCredential(id string) (SCIMCredentialRow, error)
GetSCIMCredential returns one credential by id.
func (*DB) GetSCIMGroup ¶ added in v0.0.5
func (d *DB) GetSCIMGroup(id string) (SCIMGroupRow, error)
GetSCIMGroup returns one provisioned group with its members.
func (*DB) GetSCIMUser ¶ added in v0.0.5
func (d *DB) GetSCIMUser(id string) (SCIMUserRow, error)
GetSCIMUser returns one provisioned user, or an error wrapping ErrSCIMNotFound.
func (*DB) GetSecretLease ¶ added in v0.0.5
func (d *DB) GetSecretLease(leaseID string) (SecretLeaseRow, error)
GetSecretLease returns one lease, or a wrapped ErrSecretLeaseNotFound.
func (*DB) GetSession ¶
func (d *DB) GetSession(id string) (SessionRow, error)
GetSession returns one session by id, or an error wrapping ErrSessionNotFound.
This sits on the authentication path, so the lookup is by primary key: a signed-in request must not cost a scan, and a scan would make request latency a function of how many people are logged in.
func (*DB) GrowthTableStats ¶ added in v0.0.2
GrowthTableStats measures every table retention covers.
One full scan per table: `cloop hub doctor` is an on-demand command and the whole point of the finding is to be accurate about a table nobody has looked at. Not for a request path.
func (*DB) HasProjectState ¶
HasProjectState reports whether any project state has ever been written to this database — that is, whether the metadata table holds a row.
It distinguishes a database that merely *exists* from one that holds a project. Opening a state.db creates the file and every table in it, so file existence alone says nothing: several code paths open a project's database for reasons unrelated to its state (executor reconciliation does it on every CLI invocation), and each of them leaves behind a complete but empty database. Callers that need "is there a project here" must ask this.
func (*DB) HeartbeatHubMember ¶ added in v0.0.5
HeartbeatHubMember advances a member's heartbeat.
false means the row is gone or marked left: a peer or an operator decided this process is no longer a member, and it must stop acting as one rather than quietly re-inserting itself.
func (*DB) History ¶ added in v0.0.5
func (d *DB) History(q HistoryQuery) (HistoryPage, error)
History reads one page of the journal.
Every read is a seek and a LIMIT query per table, on the julianday index for a page down and on the primary key for a read of what is new, so its cost follows the page size rather than the journal's length. An Offset read also walks the index entries it skips.
func (*DB) HistoryEvent ¶ added in v0.0.5
HistoryEvent returns event id whole, or nil when there is no such event.
func (*DB) HistoryStep ¶ added in v0.0.5
HistoryStep returns step n whole, or nil when there is no such step.
func (*DB) HistoryTop ¶ added in v0.0.5
func (d *DB) HistoryTop() (HistoryCursor, error)
HistoryTop returns the newest step and event written.
func (*DB) HubEventBounds ¶ added in v0.0.5
HubEventBounds returns the lowest and highest seq still on the bus, and the highest seq ever issued. A reader starts at the high-water mark so it does not replay history, and compares its cursor with the lowest seq to learn that it fell so far behind that pruning took events it never read.
The high-water mark comes from sqlite_sequence, not MAX(seq): after the leader prunes every row the table is empty, and a reader that restarted then must still begin past the numbers already handed out.
func (*DB) HubEventsAfter ¶ added in v0.0.5
func (d *DB) HubEventsAfter(after int64, limit int) ([]HubEventRow, error)
HubEventsAfter returns up to limit events with seq > after, in order.
Reading by seq is only lossless because SQLite has one writer at a time: a row with a higher seq can never become visible before one with a lower seq, so a reader that has seen seq N has seen everything at or below it. A database with concurrent writers would need a different cursor.
func (*DB) HubMeta ¶ added in v0.0.2
HubMeta reads a hub-scoped metadata value, reporting whether it was present.
The bool matters and callers must read it: an absent record and a record holding the empty string mean different things to every caller this has, and the one that exists today reads "no probe has run" versus "a probe wrote something unparsable" — which get different messages and different remedies.
func (*DB) InsertCISession ¶ added in v0.0.5
func (d *DB) InsertCISession(row CISessionRow) error
InsertCISession records a session that was just minted. A row with the same id is an error, never overwritten: an id is 96 random bits, and a second session under one would be a session whose record describes another.
func (*DB) InsertHubTLS ¶ added in v0.0.5
InsertHubTLS writes a row that does not exist yet, and reports whether it was written. An existing row is left exactly as it is and inserted is false: the CA is minted once, and of two hub processes minting it at the same moment the one that loses must adopt the winner's rather than replace it — a replaced CA is one every sandbox already given the old one refuses.
func (*DB) InsertSCIMCredential ¶ added in v0.0.5
func (d *DB) InsertSCIMCredential(c SCIMCredentialRow, audit *AuditEvent) error
InsertSCIMCredential stores a new credential, refusing a name a live one already has, in one transaction with its audit row.
func (*DB) JoinHubMember ¶ added in v0.0.5
func (d *DB) JoinHubMember(row HubMemberRow) error
JoinHubMember records row as a serving member, replacing any previous row for the same instance id. Instance ids are minted per process, so a replace only ever happens to a process re-joining after it left.
func (*DB) LastMaintenanceLog ¶
func (d *DB) LastMaintenanceLog() (*MaintenanceLogEntry, error)
LastMaintenanceLog returns the most recent maintenance_log row. Returns (nil, nil) when no maintenance has been recorded yet — callers should treat that as "schedule a maintenance run on first invocation".
func (*DB) LatestAuditAnchor ¶
func (d *DB) LatestAuditAnchor() (AuditAnchor, error)
LatestAuditAnchor returns the most recent anchor, or ErrAuditAnchorNotFound when the trail has never been pruned.
"Most recent" is by pruned_through_id rather than by id: the anchor that governs the live table is the one that cut furthest into it, and ordering by the boundary rather than by insertion order means an out-of-order write cannot make a stale anchor authoritative.
func (*DB) LeaseRevocations ¶ added in v0.0.5
func (d *DB) LeaseRevocations(leaseID string) ([]LeaseRevocationRow, error)
LeaseRevocations returns every revocation recorded for leaseID, the whole-lease one first.
func (*DB) LeaveHubMember ¶ added in v0.0.5
LeaveHubMember marks a member as having left gracefully. Idempotent.
func (*DB) LegalHoldFor ¶ added in v0.0.5
func (d *DB) LegalHoldFor(identities []string) (LegalHoldRow, bool, error)
LegalHoldFor returns the hold placed on any of identities, if there is one.
func (*DB) ListAPITokens ¶
func (d *DB) ListAPITokens() ([]APITokenRow, error)
ListAPITokens returns every token, newest first. Revoked and expired rows are included: an operator auditing access needs to see what was withdrawn, and the caller decides how to present it.
func (*DB) ListAgentCredentials ¶
func (d *DB) ListAgentCredentials() ([]AgentCredentialRow, error)
ListAgentCredentials returns every enrolled agent, oldest first.
func (*DB) ListAppTokenSlots ¶ added in v0.0.5
func (d *DB) ListAppTokenSlots(leaseID string) ([]AppTokenSlotRow, error)
ListAppTokenSlots returns the slots leaseID holds, or every slot when leaseID is empty.
func (*DB) ListAuditAnchors ¶
func (d *DB) ListAuditAnchors() ([]AuditAnchor, error)
ListAuditAnchors returns every anchor in ascending boundary order. Used by `cloop hub audit anchors` and by the verifier's report so an operator can see the full retention history, not just the newest cut.
func (*DB) ListAuditEvents ¶
func (d *DB) ListAuditEvents(f AuditFilter) (rows []AuditEvent, total int, err error)
ListAuditEvents returns rows matching the filter, plus the unfiltered total count for paging UIs.
func (*DB) ListBrokerGrants ¶
func (d *DB) ListBrokerGrants() ([]BrokerGrantRow, error)
ListBrokerGrants returns every grant, including revoked and expired ones.
Filtering is the broker's job, not the store's: an audit UI listing "who had access" needs the rows a policy filter would drop, and a store that silently hid them would make that question unanswerable.
func (*DB) ListBrokerSecrets ¶
func (d *DB) ListBrokerSecrets() ([]BrokerSecretRow, error)
ListBrokerSecrets returns every stored secret, name-ordered.
func (*DB) ListBrokerSecretsNotUnderKey ¶
ListBrokerSecretsNotUnderKey returns secrets still sealed under some other key. Ordered by ID so a stuck row appears in the same position each round, which makes an operator's "it keeps failing on the same one" observation true rather than coincidental.
func (*DB) ListCIExchanges ¶ added in v0.0.2
func (d *DB) ListCIExchanges(limit int) ([]CIExchangeRow, error)
ListCIExchanges returns the most recent exchanges, newest first.
func (*DB) ListCIPipelineRules ¶ added in v0.0.2
func (d *DB) ListCIPipelineRules() ([]CIPipelineRuleRow, error)
ListCIPipelineRules returns every rule in evaluation order: oldest first, then by ID.
The order is the matching order, and it is stable across restarts on purpose. "First match wins" is only a meaningful rule if two hubs reading the same table agree about which rule is first.
func (*DB) ListCISessions ¶ added in v0.0.5
func (d *DB) ListCISessions(f CISessionFilter) ([]CISessionRow, error)
ListCISessions returns the sessions matching f, oldest first.
func (*DB) ListDispatchIntents ¶ added in v0.0.5
func (d *DB) ListDispatchIntents() ([]DispatchIntentRow, error)
ListDispatchIntents returns every outstanding intent, oldest first.
func (*DB) ListEgressGrants ¶
func (d *DB) ListEgressGrants() ([]EgressGrantRow, error)
ListEgressGrants returns every grant, including revoked and expired ones.
Filtering is the broker's job for the same reason it is in ListBrokerGrants: an audit reader asking "who could reach the Internet last quarter" needs exactly the rows a policy filter would drop.
func (*DB) ListEnrollmentTokens ¶
func (d *DB) ListEnrollmentTokens() ([]EnrollmentTokenRow, error)
ListEnrollmentTokens returns every token, newest first.
func (*DB) ListEvents ¶
ListEvents returns events in reverse-chronological order (latest first). limit caps the page size; offset skips past the most recent N. total is the total number of events in the journal so callers can drive infinite- scroll UIs.
func (*DB) ListExecutorFirewalls ¶ added in v0.0.5
func (d *DB) ListExecutorFirewalls() ([]FirewallRecord, error)
ListExecutorFirewalls returns every device-level rule set, newest first.
func (*DB) ListExecutorHandles ¶
func (d *DB) ListExecutorHandles(executorID string) ([]ExecutorHandleRow, error)
ListExecutorHandles returns rows owned by executorID, oldest first. Passing "" returns every row, which is what a cross-driver sweep wants.
Oldest-first matters: an orphan sweep applies a grace period to started_at, and processing in dispatch order means the first row it examines is the one most likely to have aged past it.
func (*DB) ListExecutorHealth ¶
func (d *DB) ListExecutorHealth() ([]ExecutorHealthRow, error)
ListExecutorHealth returns every health row ordered by executor ID.
func (*DB) ListExecutorResourceLimits ¶ added in v0.0.3
func (d *DB) ListExecutorResourceLimits() ([]ExecutorResourceLimit, error)
ListExecutorResourceLimits returns every recorded executor ceiling, newest first, for the admin-facing panel.
func (*DB) ListExecutorSandboxes ¶ added in v0.0.3
func (d *DB) ListExecutorSandboxes() ([]ExecutorSandbox, error)
ListExecutorSandboxes returns every recorded configuration, newest first, so the fleet view can render each card's containment in one query rather than one per executor.
func (*DB) ListExecutorSessions ¶
func (d *DB) ListExecutorSessions(executorID string, onlyRunning bool) ([]ExecutorSessionRow, error)
ListExecutorSessions returns sessions ordered by start time then ID. An empty executorID lists every executor's sessions; onlyRunning restricts the result to work that is still in flight, which is what failover and capacity checks ask for.
func (*DB) ListExecutors ¶
func (d *DB) ListExecutors() ([]ExecutorRow, error)
ListExecutors returns every persisted executor ordered by ID.
func (*DB) ListGrantRequestUses ¶ added in v0.0.2
func (d *DB) ListGrantRequestUses(requestID string) ([]GrantRequestUseRow, error)
ListGrantRequestUses returns the leases recorded against one request, or — when requestID is empty — every recorded use.
func (*DB) ListGrantRequests ¶ added in v0.0.2
func (d *DB) ListGrantRequests() ([]GrantRequestRow, error)
ListGrantRequests returns every request, newest first.
Unfiltered, for the same reason ListBrokerGrants is: deciding which requests a caller may see is an authorisation question, and a store that pre-filtered would make "show me everything that was ever asked for" — the review question — unanswerable.
func (*DB) ListHubMembers ¶ added in v0.0.5
func (d *DB) ListHubMembers() ([]HubMemberRow, error)
ListHubMembers returns every member row, serving or not, oldest first.
func (*DB) ListHubOwners ¶ added in v0.0.5
func (d *DB) ListHubOwners(kind string) ([]HubOwnerRow, error)
ListHubOwners returns every row of one kind, or of every kind when kind is empty, ordered by kind then key.
func (*DB) ListHubTLS ¶ added in v0.0.5
ListHubTLS returns every row, by id.
func (*DB) ListHubTLSNotUnderKey ¶ added in v0.0.5
ListHubTLSNotUnderKey returns up to limit rows whose private key is sealed under some other key, by id.
func (*DB) ListLeaseRevocations ¶ added in v0.0.5
func (d *DB) ListLeaseRevocations(pendingOnly bool) ([]LeaseRevocationRow, error)
ListLeaseRevocations returns every recorded revocation, or with pendingOnly those not yet enforced, oldest first.
func (*DB) ListLegalHolds ¶ added in v0.0.5
func (d *DB) ListLegalHolds() ([]LegalHoldRow, error)
ListLegalHolds returns every hold.
func (*DB) ListProjectClaims ¶ added in v0.0.5
func (d *DB) ListProjectClaims() ([]ProjectClaim, error)
ListProjectClaims returns every claim, ordered by path.
func (*DB) ListProjectExecutorBindings ¶
func (d *DB) ListProjectExecutorBindings() ([]ProjectExecutorBinding, error)
ListProjectExecutorBindings returns every project→executor binding, ordered by project path.
func (*DB) ListProjectFirewalls ¶ added in v0.0.5
func (d *DB) ListProjectFirewalls() ([]FirewallRecord, error)
ListProjectFirewalls returns every project rule set, newest first.
func (*DB) ListProjectMembers ¶ added in v0.0.5
func (d *DB) ListProjectMembers() ([]ProjectMemberRow, error)
ListProjectMembers returns every membership on the hub, ordered by project then identity. The whole table, because the authorization path needs all of it: pkg/projectmember caches one snapshot and answers both "who is on this project" and "what does this person hold" from it. Rows number one per person per shared project, so the table stays small.
func (*DB) ListProjectResourceLimits ¶ added in v0.0.2
func (d *DB) ListProjectResourceLimits() ([]ProjectResourceLimit, error)
ListProjectResourceLimits returns every recorded ceiling, newest first, for the operator-facing panel.
func (*DB) ListProviderCalls ¶
func (d *DB) ListProviderCalls(offset, limit, taskID int, provider string) (rows []ProviderCallRow, total int, err error)
ListProviderCalls returns up to limit rows ordered most-recent-first, optionally filtered. The summary form omits the heavy prompt/response/headers columns so the list endpoint stays cheap even when the table grows large.
Filters:
- taskID > 0: only calls bound to that task
- provider != "": only calls from that provider
Returns total = count of all matching rows (regardless of limit/offset) so the UI can render pagination controls.
func (*DB) ListProxySessions ¶ added in v0.0.5
func (d *DB) ListProxySessions(f ProxySessionFilter) ([]ProxySessionRow, error)
ListProxySessions returns the sessions matching f, oldest first.
func (*DB) ListQuotaCounters ¶
func (d *DB) ListQuotaCounters() ([]QuotaCounterRow, error)
ListQuotaCounters returns every counter row.
func (*DB) ListQuotaOverrides ¶
func (d *DB) ListQuotaOverrides() ([]QuotaOverrideRow, error)
ListQuotaOverrides returns every override, ordered by identity so the admin panel renders the same way on every load.
func (*DB) ListRetiredStaticTokens ¶ added in v0.0.5
func (d *DB) ListRetiredStaticTokens() ([]RetiredStaticTokenRow, error)
ListRetiredStaticTokens returns every retirement, newest first. The whole table, because a hub refuses every fingerprint in it and the table holds one row per token ever retired.
func (*DB) ListRoleBindings ¶ added in v0.0.2
func (d *DB) ListRoleBindings() ([]RoleBindingRow, error)
ListRoleBindings returns every binding.
Denies sort first so that a human reading the output — and the resolver's own scan — meets the rows that take away authority before the rows that grant it. Within an effect the order is stable by claim, value and id so repeated listings do not shuffle.
func (*DB) ListRotations ¶
func (d *DB) ListRotations(limit int) ([]RotationRow, error)
ListRotations returns rotation records, newest first.
func (*DB) ListSCIMCredentials ¶ added in v0.0.5
func (d *DB) ListSCIMCredentials() ([]SCIMCredentialRow, error)
ListSCIMCredentials returns every credential, revoked ones included, newest first.
func (*DB) ListSCIMGroups ¶ added in v0.0.5
func (d *DB) ListSCIMGroups(withMembers bool) ([]SCIMGroupRow, error)
ListSCIMGroups returns every provisioned group, oldest first, with members when withMembers is set.
func (*DB) ListSCIMUsers ¶ added in v0.0.5
func (d *DB) ListSCIMUsers() ([]SCIMUserRow, error)
ListSCIMUsers returns every provisioned user, oldest first.
func (*DB) ListSecretLeaseDirs ¶
func (d *DB) ListSecretLeaseDirs() ([]SecretLeaseDirRow, error)
ListSecretLeaseDirs returns every recorded directory, oldest first.
At startup this is precisely the orphan set: a hub that shut down cleanly deleted its rows as it wiped, so anything still here outlived the process that created it.
func (*DB) ListSecretLeases ¶ added in v0.0.5
func (d *DB) ListSecretLeases() ([]SecretLeaseRow, error)
ListSecretLeases returns every recorded lease, oldest first.
func (*DB) ListSessions ¶
func (d *DB) ListSessions() ([]SessionRow, error)
ListSessions returns every session, most recently active first.
func (*DB) ListSessionsNotUnderKey ¶
ListSessionsNotUnderKey returns sessions whose sealed refresh token is under some other key.
func (*DB) ListStaticTokenUse ¶ added in v0.0.5
func (d *DB) ListStaticTokenUse() ([]StaticTokenUseRow, error)
ListStaticTokenUse returns every row, the most recently held first.
func (*DB) ListTaskQuarantines ¶ added in v0.0.5
func (d *DB) ListTaskQuarantines() (map[int]*pm.TaskQuarantine, error)
ListTaskQuarantines returns every marked task's mark, keyed by task id.
func (*DB) ListTelemetrySessions ¶ added in v0.0.2
func (d *DB) ListTelemetrySessions(source string, limit int) ([]TelemetrySession, error)
ListTelemetrySessions rolls events up by session, most recently active first.
func (*DB) ListVirtualExecutors ¶ added in v0.0.5
func (d *DB) ListVirtualExecutors() ([]VirtualExecutor, error)
ListVirtualExecutors returns every virtual executor, ordered by parent and then name.
func (*DB) LoadProviderCall ¶
func (d *DB) LoadProviderCall(id int64) (*ProviderCallRow, error)
LoadProviderCall returns the full row (including prompt, response, headers) for a single audit-log id. Returns sql.ErrNoRows-wrapped error when missing.
func (*DB) LoadSCIMDirectory ¶ added in v0.0.5
func (d *DB) LoadSCIMDirectory() (SCIMDirectory, error)
LoadSCIMDirectory reads the whole directory at one version.
func (*DB) LoadSpendCursor ¶ added in v0.0.2
func (d *DB) LoadSpendCursor(projectPath string) (SpendCursor, bool, error)
LoadSpendCursor returns the cursor for projectPath, or ok=false when the hub has never dispatched a run for it.
ok=false is not an error: it is the normal state of a project the hub only reads, and of every project on a hub that has just been upgraded. The caller charges nothing until a dispatch opens a cursor, which is the safe direction — the alternative would be charging an identity the hub had to guess.
func (*DB) LoadStateLite ¶
LoadStateLite is like LoadState but skips loading the per-step rows (which on long-running projects can be megabytes of Output strings). The returned State has Steps == nil; StepCount and LastStepTime are filled from cheap aggregate SQL so handlers that only render counts or check last-activity for health don't pay for decoding every Output (Task 20125).
func (*DB) LoadTask ¶
LoadTask returns a single task by ID. Returns ErrTaskNotFound if the task does not exist. Useful from HTTP handlers where the typical 404 path is "the requested task does not exist".
func (*DB) LookupKill ¶
func (d *DB) LookupKill(taskID int) (KillRequest, bool, error)
LookupKill returns the pending kill for taskID and whether a row exists. Used by the orchestrator after a worker exits to recover the operator's chosen target_status. Returns (KillRequest{}, false, nil) when no row.
func (*DB) MarkDispatchStarted ¶ added in v0.0.5
MarkDispatchStarted completes an intent with the workload's handle and the egress sessions bound to it, and reports whether the intent was there.
func (*DB) MarkHubSeen ¶ added in v0.0.5
MarkHubSeen records (kind, key) as seen until expires and reports whether it was fresh — not already recorded with an expiry still ahead of now. Check and record share one write transaction, so of two members presenting the same value at once exactly one is told it was fresh.
func (*DB) MarkLeaseRevocationEnforced ¶ added in v0.0.5
func (d *DB) MarkLeaseRevocationEnforced(leaseID, grantID, by, detail string, at time.Time) (bool, error)
MarkLeaseRevocationEnforced records that a pending revocation's material was taken back from every holder, and reports whether it was pending.
func (*DB) MarkSCIMUserOffboarded ¶ added in v0.0.5
MarkSCIMUserOffboarded records that the full offboarding ran for a user and clears its suspension record: what an offboarding destroyed is never restored, so a later reactivation must find nothing to lift. It reports false when the user is gone, active again, or already marked.
func (*DB) MaxAuditID ¶
MaxAuditID returns the largest id currently in the table, or 0 if empty. Used by the `events tail --follow` poller to discover new rows.
func (*DB) MaxCostRowID ¶ added in v0.0.2
MaxCostRowID returns the highest costs.id present, or 0 when the table is empty. It seeds a drain watermark at a point that means "everything already here is somebody else's business", so a hub adopting an existing project does not retroactively bill a tenant for spend that predates it.
func (*DB) MonthlyCosts ¶
MonthlyCosts returns cost entries for the given UTC year/month.
func (*DB) NarrowCISession ¶ added in v0.0.5
func (d *DB) NarrowCISession(id, holder, instance, policy string, expiresAt time.Time) (bool, error)
NarrowCISession rewrites an open session's policy and deadline — what a restore held it to — and the instance now serving it, provided holder holds it, and reports whether it did.
func (*DB) NoteDispatchIntent ¶ added in v0.0.5
NoteDispatchIntent records why an intent is still outstanding.
func (*DB) NoteLeaseRevocation ¶ added in v0.0.5
NoteLeaseRevocation records why a pending revocation is still pending. A revocation already enforced is left alone.
func (*DB) OffboardIdentity ¶ added in v0.0.2
func (d *DB) OffboardIdentity(w OffboardWrite) (OffboardApplied, error)
OffboardIdentity severs the listed sessions and tokens and writes the deny binding, in one transaction, chaining the caller's audit events into the same commit.
Ordering inside the transaction is deliberate: the deny binding is written first. Within a transaction the order is invisible to other readers, but it is not invisible to a crash-and-retry: if the commit is lost and the operator re-runs, the surface that matters most for a *future* sign-in is the one already expressed in the row they will re-write identically (the binding id is content-addressed, so re-writing is idempotent).
func (*DB) OpenCISessionIDsHeldBy ¶ added in v0.0.5
OpenCISessionIDsHeldBy returns the ids of the open sessions holder holds: what a hub process checks the sessions it serves against on every checkpoint tick, without reading the records themselves.
func (*DB) OpenExecutorSession ¶
func (d *DB) OpenExecutorSession(row ExecutorSessionRow) error
OpenExecutorSession records work starting on an executor.
This is a plain INSERT, not an upsert: a session id identifies one attempt, and silently overwriting an existing row would erase the claim token a supervisor may already be holding for the in-flight attempt.
func (*DB) OpenSpendCursor ¶ added in v0.0.2
OpenSpendCursor records who is paying for the run about to start and where its billing begins, replacing any previous cursor for the project.
startAt is the project ledger's current MAX(id) — everything already there belongs to an earlier run and must not be charged to this one. Passing it in rather than reading it here keeps this package free of any assumption about which database the cost rows live in: the control plane holds the cursor, the project holds the ledger, and they are different files.
func (*DB) Path ¶ added in v0.0.5
Path returns the database file this handle was opened over, as the caller named it. A subscriber to the secret broker's revocations uses it to tell which control plane a revocation belongs to (Task 20403).
func (*DB) PendingKills ¶
func (d *DB) PendingKills() ([]KillRequest, error)
PendingKills returns all currently-pending abort requests, oldest first. The orchestrator's poller calls this every fast tick.
func (*DB) PendingSCIMOffboards ¶ added in v0.0.5
func (d *DB) PendingSCIMOffboards(cutoff time.Time) ([]SCIMUserRow, error)
PendingSCIMOffboards returns the users inactive since before cutoff whose full offboarding has not run.
func (*DB) PingContext ¶
PingContext runs a `SELECT 1` against the underlying connection, honouring ctx for cancellation/deadline. Used by readiness probes (e.g. /readyz) to verify the SQLite store is reachable.
Intentionally does NOT acquire d.mu: *sql.DB is concurrency-safe, and the mutex is reserved for transactional read-modify-write ops in this package. Holding it here would block readiness on whichever long-running write happens to own the lock — exactly what a probe must NOT do. The ctx timeout bounds wait time on the single underlying connection (we set MaxOpenConns(1)) when it is busy.
func (*DB) PlanAuditPrune ¶
func (d *DB) PlanAuditPrune(cutoff time.Time) (AuditPruneCandidate, error)
PlanAuditPrune resolves a time cutoff to a contiguous id prefix.
Rows strictly older than cutoff are eligible. The boundary is the largest such id, and because ids are assigned monotonically under d.mu while timestamps come from the same clock, "older than cutoff" and "id <= boundary" describe the same set — but we count the set explicitly rather than assuming it, so a clock that went backwards produces a visibly wrong count instead of a silently over-broad delete.
func (*DB) PrimaryKEK ¶
PrimaryKEK returns the current primary, if any.
Separate from ListKEKs because it sits on the seal path: every seal re-reads it to confirm this process has not fallen behind a rotation run elsewhere, so it has to be one indexed lookup and not a scan.
func (*DB) ProjectClaimAt ¶ added in v0.0.5
func (d *DB) ProjectClaimAt(path string) (ProjectClaim, bool, error)
ProjectClaimAt returns the claim on exactly path.
func (*DB) ProjectExecutor ¶
ProjectExecutor returns the executor ID bound to projectPath. The boolean is false when the project has no binding, which callers treat as "use the registry default" — distinct from an error, which means the lookup itself failed and must not be interpreted as "unbound".
func (*DB) ProjectFirewall ¶ added in v0.0.5
func (d *DB) ProjectFirewall(projectPath string) (FirewallRecord, bool, error)
ProjectFirewall returns the rule set stored for the project at projectPath.
func (*DB) ProjectResourceCeiling ¶ added in v0.0.2
ProjectResourceCeiling returns the ceiling for projectPath.
The boolean is false when the project has no ceiling, which the dispatch path reads as "the fleet ceiling alone applies" — deliberately distinct from an error, which means the lookup failed and must not be read as "uncapped". A storage fault that silently became "no limit" would remove the policy exactly when the hub is least healthy.
func (*DB) PromoteKEK ¶
PromoteKEK makes id the sole primary.
Demotion and promotion happen in one transaction because the partial unique index permits only one primary: doing them in two statements outside a transaction would leave a window with none (a hub starting in that window mints a third key) or, if ordered the other way, fail on the index. The index is what makes this correct under concurrency rather than merely usually correct.
func (*DB) PruneAuditPrefix ¶
func (d *DB) PruneAuditPrefix(a AuditAnchor) (AuditAnchor, error)
PruneAuditPrefix deletes audit_events with id <= throughID and records an anchor describing the cut.
The caller must already have sealed the prefix; this function will not delete rows without an export digest, because an anchor with no evidence behind it is indistinguishable from a cover-up and the whole point of the anchor is to be checkable. Pass a.ExportSHA256 and a.ExportPath from the completed seal.
Delete and anchor happen in one transaction: a crash between them would otherwise leave either a truncated chain nothing explains, or an anchor claiming a truncation that did not happen. Both verify as tampering, and both would be this function's fault rather than an attacker's.
Returns the anchor as written, with ID, RetainedFromID and the hashes filled in.
func (*DB) PruneCIExchanges ¶ added in v0.0.2
PruneCIExchanges keeps the newest keep rows and deletes the rest.
The exchange log is a debugging surface, not the audit trail, so it is bounded by count rather than by age: an operator debugging a pipeline wants the last N attempts, and a hub nobody has federated against in a month should still be able to show the exchange that failed.
func (*DB) PruneCosts ¶ added in v0.0.2
func (d *DB) PruneCosts(p RowRetention, now time.Time, dryRun bool) (RowPruneResult, error)
PruneCosts bounds the cost ledger.
The ledger is mirrored to .cloop/costs.jsonl, so a pruned row is not the last record of the spend — which is why bounding it at all is defensible. Two readers still argue for a generous ceiling. `cloop cost report` aggregates over the whole table, so pruning shortens the history it can show; and the hub's spend enforcement tracks its booking position in project_spend_cursor.last_cost_row_id, reading forward from it with ReadCostsAfterID. Deleting the oldest rows cannot strand that cursor unless the hub has fallen more than MaxRows behind, which is a broken hub rather than a busy one — but it is the reason this prune takes the oldest rows and never the newest.
func (*DB) PruneEvents ¶ added in v0.0.2
func (d *DB) PruneEvents(p RowRetention, now time.Time, dryRun bool) (RowPruneResult, error)
PruneEvents bounds the unified event history.
func (*DB) PruneHubEvents ¶ added in v0.0.5
PruneHubEvents deletes events published before cutoff.
func (*DB) PruneHubMembers ¶ added in v0.0.5
PruneHubMembers deletes the rows of members that stopped heartbeating before cutoff, whether they left gracefully or not. The row of a member that is gone serves forensics for a while and then only clutters `cloop hub cluster status`, so the leader trims it.
func (*DB) PruneHubSeen ¶ added in v0.0.5
PruneHubSeen deletes rows whose expiry has passed.
func (*DB) PruneLeaseRevocations ¶ added in v0.0.5
PruneLeaseRevocations deletes the revocations enforced before cutoff, and reports how many went. A pending revocation is never pruned: it is the one thing that tells a member reaching its workload to take the material back.
func (*DB) PruneProviderCalls ¶ added in v0.0.2
func (d *DB) PruneProviderCalls(p ProviderCallRetention, now time.Time, dryRun bool) (ProviderCallPruneResult, error)
PruneProviderCalls strips aged bodies and then bounds the rows.
The two limits are applied in that order and both are honoured: a row that is old enough to lose its bodies and also falls outside the row ceiling is deleted, and the bytes are reported once — the strip empties the columns before the delete measures what the row still held.
func (*DB) PruneQuotaCounters ¶
PruneQuotaCounters deletes daily counters older than bucket. Gauge rows (bucket = ”) are never pruned: they are live state, not history, and ” sorts before every date so an unguarded comparison would delete all of them.
func (*DB) PruneSteps ¶ added in v0.0.2
func (d *DB) PruneSteps(p RowRetention, now time.Time, dryRun bool) (RowPruneResult, error)
PruneSteps bounds the steps table.
Callers must not run this while an orchestrator is executing against the same project. steps is the one table here that is not purely append-only: a run holds the whole step history in memory (state.Load reads every row) and saveStateLocked upserts all of it on each save, so rows deleted underneath a live run come straight back on its next write. The janitor skips this step for a running project for that reason.
func (*DB) PruneTelemetry ¶ added in v0.0.2
PruneTelemetry deletes events older than cutoff and returns how many went. The operator-invoked companion to the automatic row ceiling: `cloop hub telemetry prune` for when a trail should go now rather than when it ages out.
The age half of the same policy now also runs unattended — see PruneTelemetryRows and the janitor's telemetry step (Task 20291). Both go through rowretention.go's id-bounded path rather than comparing the RFC3339Nano text column directly, because a string comparison on that column is only an ordering if every writer used identical UTC formatting, and a row whose timestamp will not parse must stop the prune rather than be swept into it.
func (*DB) PruneTelemetryRows ¶ added in v0.0.2
func (d *DB) PruneTelemetryRows(p RowRetention, now time.Time, dryRun bool) (RowPruneResult, error)
PruneTelemetryRows applies age and count retention to the browser telemetry trail.
trimTelemetryTx already caps the table at TelemetryMaxRows on the write path, because a public ingest endpoint must not be able to fill a disk between two janitor passes. This is the age half of the policy, which no write-time cap can express: a debugging trail that has gone quiet should still age out.
func (*DB) PutAPIToken ¶
func (d *DB) PutAPIToken(row APITokenRow) error
PutAPIToken inserts a token row. It is an insert, not an upsert: a token's secret, roles, and scope are fixed at mint time, and silently rewriting an existing row would turn "re-run the create call" into an undetectable privilege change on a credential already in circulation. Rotating means minting a new token and revoking the old one.
func (*DB) PutAgentCredential ¶
func (d *DB) PutAgentCredential(row AgentCredentialRow) error
PutAgentCredential inserts or updates an agent credential row.
func (*DB) PutAppTokenSlot ¶ added in v0.0.5
func (d *DB) PutAppTokenSlot(row AppTokenSlotRow) error
PutAppTokenSlot records a slot, replacing any row for the same lease and grant.
func (*DB) PutBrokerGrant ¶
func (d *DB) PutBrokerGrant(row BrokerGrantRow) error
PutBrokerGrant inserts or replaces a grant.
func (*DB) PutBrokerSecret ¶
func (d *DB) PutBrokerSecret(row BrokerSecretRow) error
PutBrokerSecret inserts or replaces a secret.
The unique index on name is what makes a duplicate a storage error rather than a silently-shadowed second row, so a name collision surfaces here even if two processes race past the broker's own check.
func (*DB) PutCIExchange ¶ added in v0.0.2
func (d *DB) PutCIExchange(row CIExchangeRow) error
PutCIExchange records a federation attempt.
func (*DB) PutCIPipelineRule ¶ added in v0.0.2
func (d *DB) PutCIPipelineRule(row CIPipelineRuleRow) error
PutCIPipelineRule inserts or replaces a rule.
Unlike PutAPIToken this is an upsert, because a rule is a policy an operator edits rather than a credential in circulation: rewriting one is the intended operation, and the row carries no secret whose replacement could go unnoticed. What editing a rule must *also* do — revoke the sessions already minted under it — is the caller's job, because this layer does not know the live registry exists.
func (*DB) PutDeviceAuthorization ¶ added in v0.0.5
func (d *DB) PutDeviceAuthorization(row DeviceAuthorizationRow) error
PutDeviceAuthorization inserts a row. An insert rather than an upsert, as for sessions: the device code is 256 random bits, and silently replacing a row would hand one terminal's approval to another.
func (*DB) PutDispatchIntent ¶ added in v0.0.5
func (d *DB) PutDispatchIntent(row DispatchIntentRow) error
PutDispatchIntent records a workload about to be started. A run id is minted once per dispatch, so a conflict is the same dispatch writing again, and its row is brought up to date.
func (*DB) PutEgressGrant ¶
func (d *DB) PutEgressGrant(row EgressGrantRow) error
PutEgressGrant inserts or replaces an egress grant.
func (*DB) PutEnrollmentToken ¶
func (d *DB) PutEnrollmentToken(row EnrollmentTokenRow) error
PutEnrollmentToken inserts or updates a token row.
func (*DB) PutExecutorHandle ¶
func (d *DB) PutExecutorHandle(row ExecutorHandleRow) error
PutExecutorHandle inserts or replaces the row for row.HandleID.
Unlike OpenExecutorSession this *is* an upsert. A driver may re-record a handle it already owns — rehydration re-writes rows so updated_at reflects the adopting control plane, and a Start that retries against the same handle id must not fail on a duplicate key. There is no claim token here to clobber: the row carries identity, not ownership.
func (*DB) PutExecutorHealth ¶
func (d *DB) PutExecutorHealth(row ExecutorHealthRow) error
PutExecutorHealth inserts or updates the health row for row.ExecutorID.
The row is written wholesale rather than merged field-by-field: the prober computes the complete verdict (state, reason, failure count, transition time) in one place, and a partial update would let a stale field outlive the observation that produced it.
func (*DB) PutGrantRequest ¶ added in v0.0.2
func (d *DB) PutGrantRequest(row GrantRequestRow) error
PutGrantRequest inserts or replaces a request by ID.
func (*DB) PutGrantRequestUse ¶ added in v0.0.2
func (d *DB) PutGrantRequestUse(row GrantRequestUseRow) error
PutGrantRequestUse records that a lease redeemed an approved request's grant.
Upsert on (request_id, lease_id): a lease is leased once and then renewed every few minutes, and each renewal should move last_seen rather than add a row. first_seen is preserved by the conflict clause for the same reason RevokeBrokerGrant refuses to move a revocation timestamp — when a credential first came into use is a fact, and a renewal must not rewrite it.
func (*DB) PutHubOwner ¶ added in v0.0.5
func (d *DB) PutHubOwner(row HubOwnerRow) error
PutHubOwner records row unconditionally: the latest writer wins.
For facts rather than claims. An agent's socket is wherever the agent last connected — the member it left may not have noticed yet, and must not be able to keep the row by virtue of having written it first.
func (*DB) PutKEK ¶
PutKEK inserts or replaces a KEK record.
The WHERE clause on the upsert makes retirement terminal. Without it a PutKEK against a retired id would restore its salt and state, un-doing a crypto-shred with an ordinary write — the one operation in this file that is supposed to be irreversible.
func (*DB) PutLeaseRevocation ¶ added in v0.0.5
func (d *DB) PutLeaseRevocation(row LeaseRevocationRow) error
PutLeaseRevocation records a revocation. Revoking a lease (or grant) that is already revoked re-opens it: the reason and actor are the latest ones, a kill is never weakened to a scrub, the first revocation's time is kept, and the enforcement is cleared — the new request is enforced again, which for a revocation already enforced finds nothing left and settles at once.
func (*DB) PutLegalHold ¶ added in v0.0.5
func (d *DB) PutLegalHold(h LegalHoldRow, audit *AuditEvent) error
PutLegalHold places a hold, or restates one already placed — its reason and who placed it are replaced, its first placement time kept.
func (*DB) PutProjectMember ¶ added in v0.0.5
func (d *DB) PutProjectMember(row ProjectMemberRow, audit MemberAudit) (ProjectMemberRow, *ProjectMemberRow, error)
PutProjectMember inserts or replaces one membership and returns the row as stored along with the one it replaced (nil for a new member).
A membership is found by its pair — project and identity — never by its id alone, so a row written under another id scheme (a stranded build's) is still the one replaced, and a new pair whose derived id is taken fails on the primary key instead of overwriting somebody else's row.
The caller passes an already-normalised path and identity key; pkg/projectmember is the one definition of when two memberships are the same, and a second one here would disagree with it exactly when somebody re-grants a role.
func (*DB) PutProxySession ¶ added in v0.0.5
func (d *DB) PutProxySession(row ProxySessionRow) error
PutProxySession records a session, replacing any row with the same kind and id.
func (*DB) PutQuotaCounter ¶
func (d *DB) PutQuotaCounter(row QuotaCounterRow) error
PutQuotaCounter writes one counter's current value. A value at or below zero deletes the row instead of storing a zero: an identity holding nothing should not keep a row per resource forever, and a row that says 0 and a missing row must not be two different things the reader has to reconcile.
func (*DB) PutQuotaOverride ¶
func (d *DB) PutQuotaOverride(row QuotaOverrideRow) error
PutQuotaOverride inserts or replaces one identity's override.
func (*DB) PutRoleBinding ¶ added in v0.0.2
func (d *DB) PutRoleBinding(row RoleBindingRow) (RoleBindingRow, error)
PutRoleBinding inserts or replaces a binding, returning the row as stored.
The caller supplies already-normalized claim and value: normalization is pkg/authz's definition of when two bindings are the same one, and a second implementation here would silently disagree with it at exactly the moment an operator is trying to override a configured binding.
func (*DB) PutRotation ¶
func (d *DB) PutRotation(row RotationRow) error
PutRotation inserts or updates a rotation record.
func (*DB) PutSecretLease ¶ added in v0.0.5
func (d *DB) PutSecretLease(row SecretLeaseRow) error
PutSecretLease records a lease, replacing any row with the same id.
func (*DB) PutSecretLeaseDir ¶
func (d *DB) PutSecretLeaseDir(row SecretLeaseDirRow) error
PutSecretLeaseDir records the intent to materialise a lease at row.Dir.
Call it before anything writes plaintext there. The ordering is the whole point of the table: a row without a directory is harmless and self-clearing, a directory without a row is an orphan nothing can attribute.
func (*DB) PutSession ¶
func (d *DB) PutSession(row SessionRow) error
PutSession inserts a session row.
An insert rather than an upsert: the id is a digest of 256 random bits, so a collision is not a case worth writing code for, while silently overwriting one would replace a live session's subject and roles with another's.
func (*DB) PutTaskQuarantine ¶ added in v0.0.5
func (d *DB) PutTaskQuarantine(taskID int, q pm.TaskQuarantine) error
PutTaskQuarantine marks a task. Marking one that is already marked updates the mark in place: the newest evidence names more nodes, never fewer.
func (*DB) QueryTelemetry ¶ added in v0.0.2
QueryTelemetry returns one page of events, newest first, and the total number of rows matching the filter so a caller can render "showing 200 of 4,812".
func (*DB) ReadAuditRange ¶
func (d *DB) ReadAuditRange(fromID, throughID int64, limit int) ([]AuditEvent, error)
ReadAuditRange returns up to limit rows with fromID <= id <= throughID, in ascending id order.
It exists next to ListAuditEvents rather than reusing it because ListAuditEvents runs an unfiltered COUNT(*) on every call to populate its paging total. That is right for a UI page and wrong for a cursor: sealing a 1.09M-row prefix in batches would run a full-table count per batch. Paging by id rather than by OFFSET matters for the same reason — OFFSET re-walks the skipped rows every time.
func (*DB) ReadCostsAfterID ¶ added in v0.0.2
ReadCostsAfterID returns cost entries with id > afterID, oldest first.
This is the hub's spend drain (Task 20264): it books everything it has not booked before and remembers the highest id it saw. Ordering by id rather than timestamp is what makes the watermark sound — see CostEntry.RowID.
limit bounds one drain so a project whose ledger grew while the hub was down cannot pull an unbounded result set into memory; the caller advances its watermark and comes back for the rest.
func (*DB) ReadCostsSince ¶
ReadCostsSince returns cost entries with timestamp >= since, ordered ascending.
func (*DB) ReconstructTask ¶ added in v0.0.2
ReconstructTask assembles one task's whole story from audit_events alone.
Returns a story with no events — rather than an error — for a task id the trail has never heard of. "No rows" is a legitimate and important answer: it is what an auditor sees for work that predates the trail, and turning it into an error would make the absence of evidence indistinguishable from a failure to look.
func (*DB) RecordEvent ¶
RecordEvent appends one row to the events journal. Best-effort: the caller is expected to ignore the returned error (event-recording must never block the orchestrator). Idempotency is NOT guaranteed — duplicate calls record duplicate rows. The auto-increment id ordering is the source of truth for "what happened first" on a single host.
func (*DB) RecordTaskNodeLoss ¶ added in v0.0.5
RecordTaskNodeLoss records that loss.ExecutorID went unreachable while task taskID was running. Recording the same session twice for one task is a no-op: the claim that produces a loss is exactly-once, and a retry of its handler must not count one lost node twice.
It reports whether a row was added.
func (*DB) RedeemEnrollmentToken ¶
RedeemEnrollmentToken atomically claims a token for agentID.
The single-use guarantee lives entirely in this statement's WHERE clause. SQLite serialises writers, so of two concurrent redemptions exactly one finds redeemed_at = ” and updates a row; the other matches nothing and gets ErrEnrollmentSpent. A read-then-write implementation would let both succeed and hand two devices the same identity, which is the precise attack that single-use tokens exist to prevent.
func (*DB) ReleaseHubLease ¶
ReleaseHubLease gives up a lease held by instanceID, leaving the row in place with released_at set.
Scoped to instanceID so a late release from a hub that already lost the lease cannot free the lease its successor now holds — the same fencing discipline as RenewHubLease, applied to the path most likely to run last.
func (*DB) ReleaseHubOwner ¶ added in v0.0.5
ReleaseHubOwner deletes (kind, key) if instanceID still owns it. A member releasing something another member has since taken over releases nothing.
func (*DB) ReleaseHubOwnerIfClaim ¶ added in v0.0.5
func (d *DB) ReleaseHubOwnerIfClaim(expect HubOwnerRow) (bool, error)
ReleaseHubOwnerIfClaim deletes (kind, key) if it is still exactly the claim the caller read — owner and claim instant. It is how a member removes an orphan it judged dead without racing a member that adopted it meanwhile.
func (*DB) ReleaseProjectClaim ¶ added in v0.0.5
ReleaseProjectClaim drops the claim on path, if there is one: a creation that failed, or a project removed from the hub.
func (*DB) RemoveExecutorAudience ¶ added in v0.0.3
RemoveExecutorAudience withdraws a principal. Removing one that was never admitted is not an error.
Removing the *last* principal makes the executor unrestricted again, which is a widening of access rather than a narrowing. That is the correct reading of "the list is now empty" and it is why the REST layer audits a removal that empties the list distinctly from one that does not.
func (*DB) RenewHubLease ¶
RenewHubLease advances the heartbeat for a lease this instance holds.
Returning false is the fencing signal, and callers must treat it as such: it means the row is no longer ours — taken over while we were paused, cleared by an operator, or released by us already — and the process must stop acting as the control plane rather than retry. It is deliberately not an error, because it is not one: it is an answer.
func (*DB) ReplaceBrokerSecretSealed ¶
ReplaceBrokerSecretSealed swaps a secret's envelope under compare-and-swap.
The WHERE clause matches the old key ID *and the exact ciphertext*, not just the ID. Matching the key alone would be a lost-update bug with teeth: a rotation that read a row, and an operator who re-minted that credential while the rotation was mid-flight, would race — and the rotation would win, silently restoring the superseded credential under a fresh wrap, with every column looking correct afterwards. Comparing the bytes turns that race into a no-op the rotator counts as skipped.
func (*DB) ReplaceHubTLS ¶ added in v0.0.5
ReplaceHubTLS swaps the row by id for next if, and only if, its serial is still expectSerial, and reports whether it did. False is an ordinary outcome: another hub process replaced it first, and the caller re-reads the winner.
Updated in place, never deleted and re-inserted, for the reason SaveState is (tests/arch/rowreplace_test.go): a binary that knows fewer columns must not reset the ones it does not know.
func (*DB) ReplaceHubTLSSealed ¶ added in v0.0.5
ReplaceHubTLSSealed swaps a row's key envelope under compare-and-swap on the key id and the exact ciphertext, for the reason ReplaceBrokerSecretSealed gives: a leaf renewed while a rotation was reading it must not have the previous key restored under a fresh wrap.
func (*DB) ReplaceQuotaGauges ¶
func (d *DB) ReplaceQuotaGauges(rows []QuotaCounterRow) error
ReplaceQuotaGauges swaps every gauge row (bucket = ”) for rows in one transaction.
A transaction because the intermediate state — no gauge counters at all — is a state in which every tenant has unlimited headroom. On a hub reconciling at startup that window is short, but it is exactly the window an attacker watching for a restart would aim at, and making it atomic costs nothing.
The swap updates the gauges that stay in place and deletes only the ones that go. It used to delete every gauge row and insert the set again, which reset any column this binary does not know on every reconciliation — the row replacement Task 20388 removed from every writer.
func (*DB) ReplaceSessionSealed ¶
ReplaceSessionSealed swaps a session's sealed refresh token under compare-and-swap, with the same reasoning as above: a session that refreshed its token mid-rotation must not have the previous token restored.
func (*DB) ReportStaticTokenUse ¶ added in v0.0.5
func (d *DB) ReportStaticTokenUse(reports []StaticTokenUseReport) error
ReportStaticTokenUse merges reports into static_token_use in one transaction.
Merged rather than overwritten, because several hub processes may hold one token and each flushes only what it saw: the latest use and the latest refusal win whichever process reported them, the refusal count adds up, and a report that saw no use leaves the recorded one alone. Compared as times in Go rather than as text in SQL, since RFC 3339 with trimmed fractions does not sort as a string.
func (*DB) RequestKill ¶
func (d *DB) RequestKill(req KillRequest) error
RequestKill upserts one abort request. Repeated calls for the same task ID overwrite target_status / requested_at — the latest request wins. Returns nil when the row was written.
func (*DB) RetireKEK ¶
RetireKEK marks a KEK retired and destroys its salt.
The reference check runs inside the retiring transaction, which is the difference between a guarantee and a race: checking first and retiring after would let a lease minted in between end up sealed under a key whose salt is already gone, and that material would be unrecoverable with no error anywhere to explain it.
Blanking the salt is the point of retirement. A state flag alone could be ignored by a future code path or flipped back by a hand-edited database; without the salt the key cannot be derived from the passphrase at all, so retirement is a property of the cryptography rather than of the control flow.
func (*DB) RetireStaticToken ¶ added in v0.0.5
func (d *DB) RetireStaticToken(row RetiredStaticTokenRow, ev *AuditEvent) (stored RetiredStaticTokenRow, written bool, err error)
RetireStaticToken records a retirement and, in the same commit, the audit event saying so, so the two cannot disagree: a retirement with no record is an authority change nobody can review, and a record with no retirement claims a containment that did not happen.
Retiring a fingerprint that is already retired writes nothing and returns the stored row with written=false. The first retirement is the one an auditor reads, and re-stamping it would move the date a caller is told the token stopped working. ev may be nil, for a caller that records elsewhere.
func (*DB) RevokeAPIToken ¶
RevokeAPIToken stamps a token as revoked. Revoking an already-revoked token keeps the original timestamp: the first withdrawal is the one that matters, and overwriting it would let a later call quietly move the date an auditor reads as "when did this stop working".
Returns ErrAPITokenNotFound when no such token exists, so a caller cannot mistake a typo for a successful revocation.
func (*DB) RevokeAgentCredential ¶
RevokeAgentCredential marks an agent's credential revoked.
func (*DB) RevokeBrokerGrant ¶
RevokeBrokerGrant stamps a grant revoked.
The UPDATE is conditional on revoked_at being empty so a second revoke cannot move the timestamp forward. That matters for the audit trail: the moment access was withdrawn is a fact, and a retry must not rewrite it. Revoking an already-revoked grant is reported as success, because the caller's desired end state holds.
func (*DB) RevokeBrokerGrantWithCause ¶ added in v0.0.5
RevokeBrokerGrantWithCause is RevokeBrokerGrant recording why (migration 0062). The cause is written only by the revocation that stamps the grant: a grant already revoked keeps the cause it was revoked with, as it keeps the time.
func (*DB) RevokeEgressGrant ¶
RevokeEgressGrant stamps a grant revoked.
Conditional on revoked_at being empty, matching RevokeBrokerGrant: the moment access was withdrawn is a fact, and a retry must not move it. Revoking an already-revoked grant reports success, because the caller's desired end state holds.
func (*DB) RevokeEnrollmentToken ¶
RevokeEnrollmentToken marks a token revoked, redeemed or not.
func (*DB) RevokeSCIMCredential ¶ added in v0.0.5
func (d *DB) RevokeSCIMCredential(id string, at time.Time, by string, audit *AuditEvent) (bool, error)
RevokeSCIMCredential revokes a credential, both its secrets at once. A credential already revoked keeps the time it was revoked at and reports false.
func (*DB) RewriteSecretLeaseRecord ¶ added in v0.0.5
RewriteSecretLeaseRecord replaces a lease's record document, provided holder still holds it, and reports whether it did (Task 20403): a grant withdrawn from a live lease, or one standing on its successor, is written into the record so the process that takes the lease over inherits it.
func (*DB) RotateSCIMCredential ¶ added in v0.0.5
func (d *DB) RotateSCIMCredential(id, secretHash, previousHash string, previousExpires, at time.Time, by string, audit *AuditEvent) error
RotateSCIMCredential replaces a live credential's secret. The secret it replaces stays valid until previousExpires — zero ends it at once.
func (*DB) SCIMDirectoryVersion ¶ added in v0.0.5
SCIMDirectoryVersion reads the directory's version: one row, for a cache deciding whether to reload.
func (*DB) SCIMGroupsOf ¶ added in v0.0.5
SCIMGroupsOf returns the ids of the groups a user belongs to.
func (*DB) SaveAdoptRequest ¶ added in v0.0.5
SaveAdoptRequest files a request to adopt a newer build, replacing any earlier one.
func (*DB) SaveCommitPolicy ¶ added in v0.0.5
func (d *DB) SaveCommitPolicy(p *pm.CommitPolicy) error
SaveCommitPolicy stores the project's "done means committed" setting and nothing else (Task 20370), for the same reason as SaveReviewGate: the dashboard and the CLI change it while a run may be saving its tasks.
func (*DB) SaveFollowBuilds ¶ added in v0.0.5
SaveFollowBuilds stores the project's "follow new builds" option.
func (*DB) SaveReviewGate ¶ added in v0.0.5
func (d *DB) SaveReviewGate(g *pm.ReviewGate) error
SaveReviewGate stores the project's review gate settings and nothing else (Task 20357). The dashboard and `cloop review gate` change them while a run may be saving its tasks; a full SaveState from their copy would write stale tasks back over the run's.
func (*DB) SaveRunOwner ¶ added in v0.0.5
SaveRunOwner stores the run-owner record. Nil clears it.
func (*DB) SaveRunStatus ¶ added in v0.0.5
SaveRunStatus stores the run's status and pause reason and nothing else (Task 20362).
It exists for the one write that has to land after a full SaveState has just failed: an orchestrator that could not record a task's outcome stops, and says why it stopped. A full save rewrites every task row and merges the plan first — which is the very write that was refused when, say, a damaged row makes the merge give up — while three metadata keys in one transaction are the smallest change that tells the dashboard the run is no longer running. It leaves the plan exactly as the last successful save left it, so the outcome that was lost stays lost rather than half-written.
func (*DB) SchemaStamp ¶
func (d *DB) SchemaStamp() (SchemaStamp, error)
SchemaStamp returns provenance for the highest version recorded in this database: which migration last moved the schema, when, and by which build.
Returns a zero SchemaStamp and no error when the database has no recorded migrations at all — a brand-new file, which is not a fault.
func (*DB) SessionsDueForRefresh ¶
SessionsDueForRefresh returns sessions whose IdP check is older than cutoff and that still hold a sealed refresh token, oldest first and at most limit rows.
The limit bounds one pass: a hub where every session comes due at once must spread the token-endpoint calls over several ticks rather than opening a thousand connections to the IdP in one burst, which the IdP would rightly treat as an attack.
func (*DB) SetBrokerGrantUnguardedAck ¶ added in v0.0.5
SetBrokerGrantUnguardedAck records — or, with every argument empty, clears — the unguarded acknowledgement on grant id (migration 0070). A grant that does not exist is a wrapped ErrBrokerGrantNotFound.
func (*DB) SetBrokerMeta ¶
SetBrokerMeta writes a broker-scoped metadata value.
func (*DB) SetConfigBlob ¶
SetConfigBlob persists the YAML-serialised project config into the metadata table. The write is wrapped in a transaction so a crash mid-write leaves either the previous value or the new one — never a partial row.
func (*DB) SetExecutorFirewall ¶ added in v0.0.5
SetExecutorFirewall stores executorID's rule set, replacing any previous one. An empty rule set is stored, not refused: it means "reach nothing", the strongest thing a firewall can say. ClearExecutorFirewall removes the level.
It does not check containment or constrain anything underneath; callers whose write depends on what they read use UpdateFirewalls.
func (*DB) SetExecutorResourceLimit ¶ added in v0.0.3
func (d *DB) SetExecutorResourceLimit(executorID string, c executor.ResourceCeiling, setBy string) error
SetExecutorResourceLimit records a ceiling for executorID, replacing any previous one. setBy is the identity that set it, for the audit trail.
A zero ceiling is stored rather than rejected, for the reason its project counterpart is: "considered and capped at nothing" and "never considered" are the same to the dispatch path and different to the admin reading the panel. Callers that mean "remove the policy" call ClearExecutorResourceLimit.
func (*DB) SetExecutorSandbox ¶ added in v0.0.3
SetExecutorSandbox records sandbox settings for executorID, replacing any previous ones. setBy is the identity that set them, for the audit trail.
Settings that configure nothing are stored rather than rejected, for the reason SetProjectResourceLimit stores a zero ceiling: "no row" and "a row that asserts nothing" mean the same thing at dispatch and different things to the admin reading the panel, who wants to see that someone looked at this executor. Callers meaning "remove the policy" call ClearExecutorSandbox.
func (*DB) SetExecutorSessionRunningTasks ¶ added in v0.0.5
SetExecutorSessionRunningTasks records which tasks a running session's workload is working on (Task 20391). Only a session still running is written: once a claim has taken it, what it was running is history the failover already read, and a late write from a stream that had not caught up must not change it.
It reports whether a row was written.
func (*DB) SetHubMeta ¶ added in v0.0.2
SetHubMeta writes a hub-scoped metadata value, replacing any previous one.
func (*DB) SetHubMetaIfAbsent ¶ added in v0.0.5
SetHubMetaIfAbsent writes value only when key has no value yet, and returns whichever value the key holds afterwards. Two processes minting the same secret at once both call it and both come away with the first one written — which a read-then-SetHubMeta cannot promise, since the second write would silently replace a value the first process is already using.
func (*DB) SetProjectFirewall ¶ added in v0.0.5
SetProjectFirewall stores the project's rule set, replacing any previous one.
func (*DB) SetProjectResourceLimit ¶ added in v0.0.2
func (d *DB) SetProjectResourceLimit(projectPath string, c executor.ResourceCeiling, setBy string) error
SetProjectResourceLimit records a ceiling for projectPath, replacing any previous one. setBy is the identity that set it, for the audit trail.
A zero ceiling is stored rather than rejected: "capped at nothing on every resource" and "no row" mean the same thing to the dispatch path, but they mean different things to the operator reading the panel, who wants to see that someone considered this project and decided it needed no cap. Callers that mean "remove the policy" call ClearProjectResourceLimit.
func (*DB) SetQueryOnly ¶ added in v0.0.5
SetQueryOnly makes every write through this handle fail, as a read-only database file fails it — for root too, unlike a file mode — or allows writes again. It binds this handle's one connection and no other. For a reader that must not write, and for a test that needs a write to fail the way a read-only database fails it (Task 20419).
func (*DB) SizeStats ¶
SizeStats reads PRAGMA page_count, page_size, and freelist_count.
Connection-scoped pragmas — modernc.org/sqlite returns one row per query. We hold d.mu so the three reads stay consistent against concurrent writers in this process; concurrent writers in *other* processes can still extend the file between the page_count and freelist_count reads, but the resulting values remain individually valid (worst case: a slightly stale Bytes total).
func (*DB) SpendByIdentity ¶ added in v0.0.2
func (d *DB) SpendByIdentity(from, to time.Time) ([]IdentitySpend, error)
SpendByIdentity aggregates costs per identity over [from, to).
A zero `from` or `to` leaves that side of the window open, so the caller can ask for "today", "since Monday" or "everything" through one query. Rows with no identity aggregate under the empty string: they are reported as unattributed rather than dropped, because spend that happened is spend that happened and a total that silently omits it would not reconcile against the project ledger.
func (*DB) SupersedeBrokerGrant ¶ added in v0.0.5
SupersedeBrokerGrant stamps a grant revoked because successor replaced it (migration 0063): revoked_cause 'superseded' and superseded_by naming the successor. As with any revocation, a grant already revoked keeps the time and cause — and successor — it was revoked with.
func (*DB) TakeAppTokenSlots ¶ added in v0.0.5
TakeAppTokenSlots moves every slot of leaseID still held by from to holder, and returns how many moved.
func (*DB) TakeCISession ¶ added in v0.0.5
TakeCISession moves an open session to holder, of instance, provided from still holds it, and reports whether it did. The condition is what lets two processes race to restore the same session and only one of them serve it.
func (*DB) TakeProxySession ¶ added in v0.0.5
TakeProxySession moves an open session to holder, provided from still holds it, and reports whether it did. The condition is what lets two processes race to restore the same session and only one of them serve it.
func (*DB) TakeSecretLease ¶ added in v0.0.5
TakeSecretLease moves a lease to holder, provided it is still held by from, and reports whether it did. The condition is what lets two processes race to adopt the same run and only one of them hold its lease.
func (*DB) TaskNodeLosses ¶ added in v0.0.5
TaskNodeLosses returns the losses recorded against a task since its last explicit reset, oldest first.
func (*DB) TaskQuarantine ¶ added in v0.0.5
func (d *DB) TaskQuarantine(taskID int) (*pm.TaskQuarantine, error)
TaskQuarantine returns a task's mark, or nil when it carries none.
func (*DB) TaskRunID ¶ added in v0.0.2
TaskRunID reports the execution a task's latest attempt was dispatched into, and whether one was recorded.
Exported for the reconstruction in `cloop audit-log --task`, which needs the run id to pull the lease rows that belong to the same execution.
func (*DB) TaskStatuses ¶ added in v0.0.5
func (d *DB) TaskStatuses() (map[int]pm.TaskStatus, error)
TaskStatuses returns every task's status by ID, without loading the tasks. The janitor uses it to tell which verdict sidecars a stale-task recovery could still need (Task 20365).
func (*DB) TouchAPIToken ¶
TouchAPIToken records that a token was used. Called off the verification path and coalesced by pkg/apitoken, so a failure here is logged by the caller and never surfaces as an authentication error — a lost timestamp is not a lost authorization decision.
func (*DB) TouchAgentCredential ¶
TouchAgentCredential records a successful authentication.
func (*DB) TouchCIPipelineRule ¶ added in v0.0.2
TouchCIPipelineRule stamps a rule as having admitted a pipeline.
Failures are the caller's to ignore: last_matched_at is advisory, and a federation that succeeded must not be reported as failed because a bookkeeping write lost a race with a delete.
func (*DB) TouchExecutorHeartbeat ¶
TouchExecutorHeartbeat records liveness for an enrolled executor and updates its status. Returns ErrExecutorNotFound when the ID is unknown, so a stale agent cannot resurrect a de-enrolled record by heartbeating.
func (*DB) TouchSCIMCredential ¶ added in v0.0.5
TouchSCIMCredential records a use, moving last_used_at forward only.
func (*DB) TouchSession ¶
TouchSession records that a session was used at t.
Called off the authentication path and throttled by the caller; a failure is advisory. The write is conditional on moving the timestamp forward so two concurrent requests cannot walk last_seen backwards — the ordering the caller's in-memory cache enforces within one process, enforced again here for the cross-process case.
func (*DB) UnbindProjectExecutor ¶
UnbindProjectExecutor removes the binding for projectPath. Unbinding a project that was never bound is not an error.
func (*DB) UpdateAppTokenSlot ¶ added in v0.0.5
func (d *DB) UpdateAppTokenSlot(row AppTokenSlotRow) (bool, error)
UpdateAppTokenSlot rewrites a slot's mutable fields — guarded, session, whether the token was exported, the held token's expiry, and its scope when row.Scope is set (a restore narrows it to its grant) — provided row.Holder holds it, and reports whether it did.
func (*DB) UpdateDeviceAuthorization ¶ added in v0.0.5
func (d *DB) UpdateDeviceAuthorization(deviceHash string, change func(*DeviceAuthorizationRow) (bool, error)) (DeviceAuthorizationRow, error)
UpdateDeviceAuthorization reads the row for deviceHash, hands it to change, and writes it back when change reports that it changed it — all under the database's write lock, so two hub processes deciding the same code (an approval racing a denial, two polls racing the exchange) are serialised and the second one sees the first one's result. It returns the row as stored afterwards.
change must not touch the database: it runs inside the transaction.
func (*DB) UpdateFirewalls ¶ added in v0.0.5
func (d *DB) UpdateFirewalls(fn func(*FirewallTx) error) error
UpdateFirewalls runs fn inside one write transaction, committing when it returns nil and rolling back otherwise.
func (*DB) UpdateHubOwnerMeta ¶ added in v0.0.5
UpdateHubOwnerMeta rewrites the meta of a row instanceID still owns. false means it no longer does.
func (*DB) UpdateSessionRefresh ¶
func (d *DB) UpdateSessionRefresh(id string, up SessionRefreshUpdate) error
UpdateSessionRefresh stores a rotated refresh token, stamps the check time, and — when the provider re-asserted them — replaces the row's claims. A nil sealed value clears the stored token, which is how a session that can no longer be revalidated stops being retried.
Clearing also blanks the key id. Leaving a stale one behind would make the row look, to the rotator and to `cloop hub key retire`, like material still sealed under a key that in fact protects nothing — which is exactly the kind of phantom reference that makes an operator conclude retirement is broken.
One statement, not two. The stamp records that the session was checked and the claims record what it was checked *as*; a row carrying the first without the second is a session that looks freshly re-authorized while still holding authority the IdP has withdrawn.
func (*DB) UpdateVirtualExecutor ¶ added in v0.0.5
UpdateVirtualExecutor replaces a virtual executor's name and configuration. The parent is fixed at creation: moving a sub-executor to another machine would carry its bindings and access list to hardware nobody approved them for.
It does not check the configuration against the device's firewall; the dashboard's save goes through UpdateFirewalls for that (Task 20363).
func (*DB) UpsertExecutor ¶
func (d *DB) UpsertExecutor(row ExecutorRow) error
UpsertExecutor inserts or updates an executor row keyed by ID. CreatedAt is preserved on update: re-enrolling an agent must not rewrite its enrollment date.
func (*DB) Vacuum ¶
Vacuum runs a full VACUUM on the database. Cannot be inside a transaction; the autocommit code path in modernc.org/sqlite handles this correctly. WAL mode is preserved across the VACUUM (SQLite re-applies the journal_mode pragma internally).
func (*DB) VacuumInto ¶
VacuumInto produces a transactionally-consistent copy of the database at outPath using SQLite's `VACUUM INTO 'path'` statement. The output is a single self-contained file (no WAL/SHM sidecars) and is the recommended hot-backup primitive when the C-level Online Backup API is not available.
outPath must not already exist — VACUUM INTO refuses to overwrite. The caller is responsible for clearing any stale destination first.
The path is interpolated into a SQL string literal because VACUUM INTO does not accept bound parameters. Single quotes in the path are escaped by doubling, matching SQLite's quoting rules.
func (*DB) VerifyAuditChain ¶
func (d *DB) VerifyAuditChain() (AuditVerifyReport, error)
VerifyAuditChain walks audit_events in id order and recomputes each row's hash, comparing to the stored value. The first mismatch (or gap, or missing prev_hash linkage) stops the walk and is reported. Verification is read-only and holds the DB mutex only during the row scan.
A pruned chain (Task 20218) does not start at genesis, and the naive walk would report the first survivor as tampered. When an anchor exists the walk starts from it instead: the first row must be exactly the id the anchor pinned, and its prev_hash must be the row_hash of the last row the anchor removed. That is a stronger check than "tolerate a short chain" — it means a second, undeclared truncation just after the boundary is still caught, because the anchor says where the chain has to resume.
What this cannot do is prove the pruned prefix itself was honest; nothing inside the database can, since an attacker with write access could author both the truncation and the anchor. That is what the export digest is for, and VerifyAuditExports checks it.
func (*DB) VirtualExecutor ¶ added in v0.0.5
func (d *DB) VirtualExecutor(id string) (VirtualExecutor, bool, error)
VirtualExecutor reads one virtual executor.
func (*DB) WALCheckpointTruncate ¶
WALCheckpointTruncate flushes the WAL into the main database file and truncates the WAL to zero bytes. Used as the first step of a hot backup (Task 20115) so VACUUM INTO produces a snapshot that includes every committed transaction up to the moment of the backup, not just whatever had previously been folded into the main file.
PRAGMA wal_checkpoint returns three columns: busy (0 if checkpoint completed without contention), log_size (frames in the WAL before the checkpoint), and checkpointed (frames moved to the main DB). The string returned summarises those values for logging; a non-zero busy column is not an error per se — under heavy concurrent load the checkpoint can only flush as many frames as it could acquire — but it is reported so an operator can decide whether to retry.
It waits WALCheckpointBusyTimeout rather than the handle's 5 s (Task 20392): a TRUNCATE checkpoint holds the write lock while it waits, so a backup taken beside a live hub would otherwise hold every one of that hub's writers up for as long as a reader kept it waiting. See wal.go.
func (*DB) WriteSCIMGroup ¶ added in v0.0.5
func (d *DB) WriteSCIMGroup(w SCIMGroupWrite) (SCIMGroupApplied, error)
WriteSCIMGroup applies one change to a provisioned group in one transaction: its uniqueness check on the display name, its membership, its audit rows and the directory version bump.
func (*DB) WriteSCIMUser ¶ added in v0.0.5
func (d *DB) WriteSCIMUser(w SCIMUserWrite) (SCIMUserApplied, error)
WriteSCIMUser applies one change to a provisioned user, in one transaction with its uniqueness checks, its suspension or lift, its audit rows, and the directory version bump other hub members' caches read.
type DeviceAuthorizationRow ¶ added in v0.0.5
type DeviceAuthorizationRow struct {
DeviceHash string
UserCodeHash string
CredentialHash string
Status string
ClientIP string
ClientUserAgent string
ClientHostname string
CreatedAt time.Time
ExpiresAt time.Time
IntervalSeconds int
LastPolledAt time.Time
Approver string
ApproverSession string
Subject string
DecidedAt time.Time
Reason string
}
DeviceAuthorizationRow is one row of device_authorizations.
type DispatchIntentRow ¶ added in v0.0.5
type DispatchIntentRow struct {
RunID string
InstanceID string
ExecutorID string
Driver string
ProjectPath string
HandleID string
LeaseIDs []string
EgressIDs []string
State string
CreatedAt time.Time
UpdatedAt time.Time
Detail string
}
DispatchIntentRow is one workload a hub process is starting.
type EgressGrantRow ¶
type EgressGrantRow struct {
ID string
Scope string
SubjectType string
SubjectValue string
PolicyJSON string
ExpiresAt string
CreatedAt string
CreatedBy string
RevokedAt string
}
EgressGrantRow is one row of egress_grants. Times are RFC3339 strings, matching the rest of the schema.
type EnrollmentTokenRow ¶
type EnrollmentTokenRow struct {
ID string
Name string
// SecretHash is hex SHA-256 of the token secret, never the secret.
SecretHash string
WorkDirRoot string
Labels map[string]string
CreatedAt time.Time
ExpiresAt time.Time
CreatedBy string
RedeemedAt time.Time
RedeemedAgentID string
RevokedAt time.Time
}
EnrollmentTokenRow is one minted enrollment token.
type EventRow ¶
type EventRow struct {
ID int64 // primary key, assigned on insert (zero on the way in)
Timestamp time.Time // when the event happened
Type EventType
TaskID int // 0 when not task-bound
TaskTitle string // empty when not task-bound
Step int // NoStep (-1) when not step-bound; 0 is a real step
Message string // short, human-readable summary
Details string // free-form JSON blob (may be empty)
}
EventRow is one row in the events table.
type EventType ¶
type EventType string
EventType is a string enum identifying the kind of journal entry. Readers must treat unknown values as benign — the table is intentionally extensible.
const ( EventSessionStarted EventType = "session_started" EventSessionPaused EventType = "session_paused" EventSessionFailed EventType = "session_failed" EventPlanComplete EventType = "plan_complete" EventTaskStarted EventType = "task_started" EventTaskDone EventType = "task_done" EventTaskFailed EventType = "task_failed" EventTaskSkipped EventType = "task_skipped" EventTaskHeal EventType = "task_heal" EventTaskKilled EventType = "task_killed" EventTaskAdded EventType = "task_added" EventTaskAddedExternal EventType = "task_added_external" EventTaskDeleted EventType = "task_deleted" EventTaskStatusChange EventType = "task_status_change" EventEvolveRoundStart EventType = "evolve_round_start" EventEvolveDiscovered EventType = "evolve_discovered" EventEvolveNoOp EventType = "evolve_no_op" // EventWriteBack records what an isolated executor returned of a task's // work: the branch, the commit, and whether it merged. // // Its own type rather than a field on task_done, because the two answer // different questions and are allowed to disagree. A task can succeed and // have its work fail to come back — the harness ran, the push did not — // and a journal that folded the second into the first would have no way to // show an operator the run whose transcript was right and whose code was // lost. Making exactly that case visible is why this subsystem exists. EventWriteBack EventType = "write_back" // EventTaskBackground records work an agent harness left running after it // reported the task complete (Task 20205), and how that resolved. // // Its own type rather than a detail on task_done because it explains the // two things a status alone cannot: why a task sat running long after its // agent had stopped talking, and why a task whose output ended in // TASK_DONE was nonetheless not accepted as done. EventTaskBackground EventType = "task_background" // EventTaskReview records what a project's review gate decided about a // task's changes before they were published, and which of the agent's // held pushes went out (Task 20357). // // Its own type because it explains the case a status alone cannot: a task // whose agent said TASK_DONE and which nonetheless failed, because a // different model read its diff and would not let it leave the machine. EventTaskReview EventType = "task_review" // EventTaskAborted records a run that never produced work: a provider // usage limit or quota, a rejected credential, a harness that refused to // start, or output with no diff and no artifact behind it (Task 20211). // // Its own type rather than task_failed because the two are different // claims and are acted on differently. A failure is a judgement about the // work; an abort is the absence of any work to judge, so the task returns // to pending instead of staying terminal. Folding them together is what // let fourteen tasks be recorded as done whose entire stored summary was // "You've hit your limit" — and let auto-evolve plan follow-up work on // the belief that they had shipped. EventTaskAborted EventType = "task_aborted" // EventTaskInterrupted records a task whose execution was cut short // because its run stopped — the Stop button, a SIGINT or SIGTERM, a budget // stop from the hub, a --timeout expiring — rather than because of // anything the task did (Task 20348). // // Its own type for the same reason as task_aborted: the task goes back to // pending, and a row that read as task_failed would be a false statement // about work that was simply not allowed to finish. Filing interruptions as // failures is what left stopped tasks terminal, and the tasks depending on // them skipped, when the project was resumed. EventTaskInterrupted EventType = "task_interrupted" // EventResourceCeiling records that an operator's resource ceiling lowered // what a workload was given (Task 20301). // // It is on the project's own journal rather than only in the hub's log // because the person it concerns is the developer whose sandbox got less // memory than its .cloop/sandbox.yaml asked for. To them an unannounced // clamp is indistinguishable from a slow machine, and there is nothing in // their repository that would explain it — the ceiling lives on the hub, // deliberately out of their reach. One row naming the resource, both // numbers and which ceiling bound it is the difference between a mystery // and an address to complain to. EventResourceCeiling EventType = "resource_ceiling" // EventProjectSeed records that a run dispatched to an isolating executor // went without the project state the hub would normally send with it // (Task 20316). // // On the project's journal for the same reason as the ceiling above: the // consequence lands on the developer and nothing in their repository // explains it. A sandbox that receives no seed finds no `.cloop/` in the // tree it cloned, so `cloop run` exits with "no cloop project found" — // which reads as a broken project rather than as an executor too old to // have been sent one. One row naming the executor and the upgrade is the // difference between that and an hour spent debugging an intact project. EventProjectSeed EventType = "project_seed" // EventProjectResult records what a run on an isolating executor sent back // of the project — which tasks it finished, what it added, what the hub // kept of its own instead — or why nothing came back (Task 20339). // // It is project_seed's other half. The seed is how the plan reaches a // device that cannot read the hub's database; this is how the run's // outcome returns to the database the dashboard renders. Without a row // here, a remote run that did its work and a remote run whose results were // lost look the same afterwards: a transcript ending "All tasks complete" // beside a plan whose tasks are all still pending. EventProjectResult EventType = "project_result" // EventFeatureCreated and EventFeatureRemoved record, on a project's own // journal, a feature of it being created or removed (Task 20341). They are // the parent's rows because the feature's own journal begins with its // creation and ends — deleted along with its worktree — at its removal. EventFeatureCreated EventType = "feature_created" EventFeatureRemoved EventType = "feature_removed" // EventRunReexecuted records a run replacing its own image with a newer // build at a task boundary (Task 20389), written by the new image: which // build it left, which it runs now, and why. The process, its pid and // its live log carry on, so without this row nothing would show where // one build's tasks end and the next one's begin. EventRunReexecuted EventType = "run_reexecuted" // EventRunAdoption records an adoption that did not happen, or not yet: // a refused build and the reason, a failed exec, a request waiting for // the task in flight. The run carries on on the build it has. EventRunAdoption EventType = "run_adoption" // EventFeaturePR records a feature's pull request being opened or updated, // on the feature's journal and its parent's. EventFeaturePR EventType = "feature_pr" // EventFirewall records which stored firewall levels shaped a run — a // device's rule set, a project's — and what came of them, or why they // refused it (Task 20363). // // On the project's journal for the reason the ceiling is: a fetch that // times out inside a sandbox reads as a broken network, and the rules that // dropped it live on the hub where the developer cannot see them. EventFirewall EventType = "firewall" // EventCredentialRefresh records that a run's GitHub App token could not // be kept alive past GitHub's hour on the executor running it, or that its // renewal was refused (Task 20375). // // On the project's journal for the reason the firewall row is: the // symptom — git failing to authenticate an hour into a long run — lands on // the developer, and the cause — an agent too old to receive the new // token, a grant revoked, an installation suspended — is on the hub where // they cannot see it. EventCredentialRefresh EventType = "credential_refresh" // EventCredentialRefused records that a run went without a credential the // project was granted, because the secret behind the grant no longer // exists (Task 20400) — most often a colleague's personal credential, // destroyed when they were offboarded. // // On the project's journal for the reason the refresh row is: the symptom // — git refusing to authenticate, a cluster answering 401 — lands on the // people running the project, and the cause is a deletion on the hub they // may not even be able to see, since a grant over a personal secret is // visible to its owner and to admins alone. Written on the first run after // the loss on each hub process, not on every run. EventCredentialRefused EventType = "credential_refused" // EventEgress records what became of a run's access to the hub's egress // proxy (Task 20378): the session it was issued and the route to it, why // a project holding an egress grant got none, and when a session ended — // the run over, stopped, or its grant revoked with tunnels still open. // // On the project's journal for the reason the firewall row is: a sandbox // whose every request through the proxy fails looks like a broken // network, and the reasons — no proxy on the hub, a route the executor // cannot take, a revocation — are on the hub, out of the developer's // sight. It never carries the session's credential: the proxy URL is not // written here, only its address. EventEgress EventType = "egress" // EventFailover records what executor failover did to the project's run // and tasks (Task 20391): a lost node's tasks returned to pending for a // retry, a task marked as a suspected node killer, a run that used up // executors.failover.max_attempts and was not re-dispatched, and a // quarantine an explicit reset released. // // On the project's journal because the cause — nodes going unreachable, // the cap — is the hub's, and the effect, a task that failed or will not // run, is what the developer sees. EventFailover EventType = "failover" // EventDiskLimit records a run stopped because its workspace grew past // its disk limit — .cloop/sandbox.yaml resources.disk or an operator's // disk ceiling — or a start refused because the workspace was already // over it (Task 20405). The message names both sizes and how to raise the // limit; the details carry them as numbers. // // On the project's journal because the cause is a number the developer // may never have seen — a ceiling set on the hub — and the effect, a run // that stopped mid-task, is what they see. EventDiskLimit EventType = "disk_limit" )
type ExecutorAudienceEntry ¶ added in v0.0.3
type ExecutorAudienceEntry struct {
ExecutorID string `json:"executor_id"`
Kind string `json:"kind"` // "user" | "group" | "role"
Value string `json:"value"` // as the admin typed it
AddedAt time.Time `json:"added_at,omitempty"`
AddedBy string `json:"added_by,omitempty"`
}
ExecutorAudienceEntry is one principal admitted to one executor, plus its provenance.
func (ExecutorAudienceEntry) Member ¶ added in v0.0.3
func (e ExecutorAudienceEntry) Member() authz.AudienceMember
Member renders the entry as the claim predicate pkg/authz matches on.
type ExecutorAuditInput ¶
type ExecutorAuditInput struct {
// Action is the lifecycle verb: "enroll", "revoke", "cordon",
// "uncordon", "drain", "bind", "unbind". It becomes the suffix of the
// event type, so the whole family is filterable as event_type LIKE
// 'executor.%' and each verb individually by exact match.
Action string
// ExecutorID is the fleet identifier the action targeted. Empty is
// legitimate for "unbind", which names a project rather than a device.
ExecutorID string
// Actor is the acting identity, normally the OIDC subject label.
Actor string
// Detail is optional context: the device name, the cordon reason, the
// project path a binding points at. Never credentials — the enrollment
// token in particular must not appear here, and the central redaction
// in MarshalAuditPayload enforces that even if a caller tries.
Detail map[string]any
}
ExecutorAuditInput carries one executor-fleet decision to the audit log (Task 20167).
Executor lifecycle was the gap in the trail: enrolling a device grants an arbitrary machine the right to run project workloads and to request brokered credentials, and revoking, cordoning, draining, or re-binding one changes where a project's code executes. Those are exactly the events an operator needs to reconstruct — "who attached this machine, and when" — and none of them were recorded before.
type ExecutorHandleRow ¶
type ExecutorHandleRow struct {
HandleID string
ExecutorID string
Driver string
// ExternalID is the name the runtime knows the workload by. Its shape is
// driver-specific and nothing outside the owning driver interprets it.
ExternalID string
ProjectPath string
TaskID int
PID int
Image string
// MetaJSON is a marshalled map[string]string of driver-specific extras.
// ” and '{}' both mean "none"; readers must tolerate both because the
// column default is '{}' and a caller may write ”.
MetaJSON string
// SecretsJSON is a marshalled array of the workload's secret-lease
// bindings — lease ids, variable names and paths, never values. This
// package stores it as opaque text; pkg/executorstore owns the type.
//
// Unlike MetaJSON, ” and '[]' are *not* the same. ” means nobody
// recorded what this workload held (a row from before 0031), and '[]'
// means it held nothing. Collapsing them would let a revocation read an
// unrecorded holder as a non-holder and report success; see 0031.
SecretsJSON string
StartedAt time.Time
// Deadline is when the workload's timeout expires; the zero time means
// unbounded. Absolute, so a hub that was down does not restart the clock.
Deadline time.Time
UpdatedAt time.Time
}
ExecutorHandleRow is the durable identity of one dispatched workload.
type ExecutorHealthRow ¶
type ExecutorHealthRow struct {
ExecutorID string
State string
Reason string
ConsecutiveFailures int
LastSeen time.Time
LastProbe time.Time
StateChangedAt time.Time
}
ExecutorHealthRow is the scheduler's probe-driven view of one executor. ExecutorID shares the identifier space with ExecutorRow.ID but is not a foreign key — see the file comment.
type ExecutorInventory ¶
type ExecutorInventory struct {
// AgentVersion is the cloop build the device reported at its last connect.
// Empty means it reported none; the literal "1" means the placeholder that
// pre-inventory agents sent. Both are "unknown", but only the second tells
// an operator the device is definitely old.
AgentVersion string `json:"agent_version,omitempty"`
// OS and Arch are the device's GOOS/GOARCH.
OS string `json:"os,omitempty"`
Arch string `json:"arch,omitempty"`
// CPUs and MemoryMB are logical cores and total memory. Zero means the
// agent could not detect it, which is never "too small".
CPUs int `json:"cpus,omitempty"`
MemoryMB int `json:"memory_mb,omitempty"`
// Harnesses are the agent CLIs on the device's PATH ("claude", "codex").
Harnesses []string `json:"harnesses,omitempty"`
// ContainerRuntimes are the container runtimes it can drive.
ContainerRuntimes []string `json:"container_runtimes,omitempty"`
// WorkDirRoot is the directory the agent confines every workload beneath.
WorkDirRoot string `json:"workdir_root,omitempty"`
}
ExecutorInventory is what an edge device reported about itself, parsed out of its capability advertisement into typed, individually-queryable fields.
It is a nested struct rather than eight more fields on ExecutorRow because these travel together: they are refreshed as a set on every connect, they are all empty for a non-enrolled backend, and grouping them keeps "is this row's device inventory known" a single question.
Capabilities on ExecutorRow still holds the full advertisement. This is not a replacement for it but a projection of the parts that have to be selectable — see migration 0030 for why both exist.
func (ExecutorInventory) Known ¶
func (i ExecutorInventory) Known() bool
Known reports whether anything was actually advertised. Used to decide between rendering an inventory and rendering nothing at all — a panel that showed "0 CPUs, no harnesses" for a device that never reported would be inventing a fault.
type ExecutorResourceLimit ¶ added in v0.0.3
type ExecutorResourceLimit struct {
ExecutorID string `json:"executor_id"`
Ceiling executor.ResourceCeiling `json:"ceiling"`
SetAt time.Time `json:"set_at,omitempty"`
SetBy string `json:"set_by,omitempty"`
}
ExecutorResourceLimit is one executor's ceiling plus its provenance.
type ExecutorRow ¶
type ExecutorRow struct {
ID string `json:"id"`
Name string `json:"name"`
Kind string `json:"kind"`
Endpoint string `json:"endpoint,omitempty"`
Status string `json:"status"`
Capabilities json.RawMessage `json:"capabilities,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
LastHeartbeat time.Time `json:"last_heartbeat,omitempty"`
CreatedAt time.Time `json:"created_at"`
EnrolledBy string `json:"enrolled_by,omitempty"`
// Inventory is the parsed, queryable subset of what a device advertised.
// Zero for backends that were configured rather than enrolled: a container
// driver has no build version of its own, it runs this one.
Inventory ExecutorInventory `json:"inventory,omitzero"`
}
ExecutorRow is one persisted execution backend.
type ExecutorSandbox ¶ added in v0.0.3
type ExecutorSandbox struct {
ExecutorID string `json:"executor_id"`
Settings executor.SandboxSettings `json:"settings"`
SetAt time.Time `json:"set_at,omitempty"`
SetBy string `json:"set_by,omitempty"`
}
ExecutorSandbox is one executor's sandbox configuration plus its provenance.
Settings is the part that travels to the device in a start frame; SetAt and SetBy never leave the control plane. See executor.SandboxSettings for why that split is in the types rather than in a convention.
type ExecutorSessionRow ¶
type ExecutorSessionRow struct {
ID string
ExecutorID string
HandleID string
ProjectPath string
TaskID int
// ClaimToken gates the requeue latch. It is a concurrency token, not a
// secret: it is stored and compared in plaintext because it authorises
// nothing beyond winning one race.
ClaimToken string
State string
Attempt int
StartedAt time.Time
UpdatedAt time.Time
EndedAt time.Time
RequeuedFrom string
// SpecJSON is the marshalled executor.Spec the session was dispatched
// with. Failover re-dispatches from it, so it must survive a
// control-plane restart: a session whose spec lived only in the memory
// of the process that started it could not be requeued by the process
// that replaces it, which is exactly when requeueing matters most.
SpecJSON string
// RunningTasks are the tasks the workload last announced it was working
// on (Task 20391), kept so a failover can say which tasks a lost node
// was running even when the hub's own copy of the project cannot: a run
// on a device works on a copy. Written by SetExecutorSessionRunningTasks
// while the session runs; empty when nothing was observed.
RunningTasks []int
}
ExecutorSessionRow is one unit of work in flight on an executor.
type FirewallRecord ¶ added in v0.0.5
type FirewallRecord struct {
// Subject is the executor ID or the project path the rules are keyed by.
Subject string `json:"subject"`
Rules executor.FirewallRules `json:"rules"`
Fingerprint string `json:"fingerprint"`
SetAt time.Time `json:"set_at,omitempty"`
SetBy string `json:"set_by,omitempty"`
}
FirewallRecord is one stored rule set plus its provenance.
type FirewallTx ¶ added in v0.0.5
type FirewallTx struct {
// contains filtered or unexported fields
}
FirewallTx is one serialized read-modify-write over everything the firewall's levels are stored in: the two rule tables, virtual executor definitions and project bindings.
It exists for the saves whose correctness depends on what they read. A project's rule set is checked against its device's, and a device tightening rewrites the rule sets saved underneath it; done as separate statements, an admin narrowing a device and a maintainer saving a project at the same moment could each check against the other's old value and both commit, leaving a project outside its device until the next dispatch refused it. Inside one IMMEDIATE transaction the two serialize — across hub processes too, since the write lock is the database's.
func (*FirewallTx) ClearExecutorFirewall ¶ added in v0.0.5
func (t *FirewallTx) ClearExecutorFirewall(executorID string) error
ClearExecutorFirewall removes a device's rule set inside the transaction.
func (*FirewallTx) ClearProjectFirewall ¶ added in v0.0.5
func (t *FirewallTx) ClearProjectFirewall(projectPath string) error
ClearProjectFirewall removes a project's rule set inside the transaction.
func (*FirewallTx) CreateVirtualExecutor ¶ added in v0.0.5
func (t *FirewallTx) CreateVirtualExecutor(v VirtualExecutor) error
CreateVirtualExecutor records a new virtual executor inside the transaction, so a save checked against its device's rule set commits only if that rule set is still the one it was checked against.
func (*FirewallTx) ExecutorFirewall ¶ added in v0.0.5
func (t *FirewallTx) ExecutorFirewall(executorID string) (FirewallRecord, bool, error)
ExecutorFirewall reads a device's rule set inside the transaction.
func (*FirewallTx) ListProjectFirewalls ¶ added in v0.0.5
func (t *FirewallTx) ListProjectFirewalls() ([]FirewallRecord, error)
ListProjectFirewalls reads every project rule set inside the transaction.
func (*FirewallTx) ProjectExecutor ¶ added in v0.0.5
func (t *FirewallTx) ProjectExecutor(projectPath string) (string, bool, error)
ProjectExecutor reads a project's executor binding inside the transaction.
func (*FirewallTx) ProjectFirewall ¶ added in v0.0.5
func (t *FirewallTx) ProjectFirewall(projectPath string) (FirewallRecord, bool, error)
ProjectFirewall reads a project's rule set inside the transaction.
func (*FirewallTx) ProjectsBoundTo ¶ added in v0.0.5
func (t *FirewallTx) ProjectsBoundTo(ids ...string) ([]string, error)
ProjectsBoundTo returns the paths of the projects pinned to any of ids, in path order.
func (*FirewallTx) SetExecutorFirewall ¶ added in v0.0.5
func (t *FirewallTx) SetExecutorFirewall(executorID string, r executor.FirewallRules, setBy string) error
SetExecutorFirewall writes a device's rule set inside the transaction.
func (*FirewallTx) SetProjectFirewall ¶ added in v0.0.5
func (t *FirewallTx) SetProjectFirewall(projectPath string, r executor.FirewallRules, setBy string) error
SetProjectFirewall writes a project's rule set inside the transaction.
func (*FirewallTx) SetVirtualExecutorSpec ¶ added in v0.0.5
func (t *FirewallTx) SetVirtualExecutorSpec(id string, spec executor.VirtualSpec, by string) error
SetVirtualExecutorSpec replaces one virtual executor's configuration inside the transaction, keeping its name.
func (*FirewallTx) UpdateVirtualExecutor ¶ added in v0.0.5
func (t *FirewallTx) UpdateVirtualExecutor(id, name string, spec executor.VirtualSpec, by string) error
UpdateVirtualExecutor replaces a virtual executor's name and configuration inside the transaction.
func (*FirewallTx) VirtualExecutor ¶ added in v0.0.5
func (t *FirewallTx) VirtualExecutor(id string) (VirtualExecutor, bool, error)
VirtualExecutor reads one virtual executor inside the transaction.
func (*FirewallTx) VirtualExecutorsOf ¶ added in v0.0.5
func (t *FirewallTx) VirtualExecutorsOf(parentID string) ([]VirtualExecutor, error)
VirtualExecutorsOf reads every virtual executor of one device inside the transaction.
type GrantRequestRow ¶ added in v0.0.2
type GrantRequestRow struct {
ID string
RequestedBy string
SecretID string
SecretName string
Kind string
SubjectType string
SubjectValue string
Scope string
ConstraintsJSON string
TTLSeconds int64
Justification string
State string
CreatedAt string
ExpiresAt string
DecidedBy string
DecidedAt string
DecisionNote string
GrantID string
GrantExpiresAt string
}
GrantRequestRow is one row of secret_grant_requests. Times are RFC3339 strings and durations are whole seconds, matching the rest of the schema.
type GrantRequestUseRow ¶ added in v0.0.2
type GrantRequestUseRow struct {
RequestID string
LeaseID string
GrantID string
ExecutorID string
ProjectPath string
// TaskID is the unit of work that held the lease, or 0 when the dispatch
// was run-scoped rather than task-scoped. See the migration's note: 0 means
// "not attributed", never "no task ran".
TaskID int
FirstSeen string
LastSeen string
}
GrantRequestUseRow is one row of secret_grant_request_uses: one lease that redeemed the grant an approval produced.
type HistoryCursor ¶ added in v0.0.5
HistoryCursor is a position in the journal's write order: the newest step number and event id a reader has seen. Step is -1 when it has seen no step (step numbers start at 0) and Event is 0 when it has seen no event.
type HistoryPage ¶ added in v0.0.5
type HistoryPage struct {
// Rows in feed order, newest first.
Rows []HistoryRow
// Top is the newest step and event written when the page was read — what
// a later After read starts from. On a Before page it is not set.
Top HistoryCursor
// Bottom is the place of the page's last row, where the next page down
// starts; nil when the page is empty and was not itself a Before read.
Bottom *HistoryPlace
// More reports rows below Bottom.
More bool
// Gap is set on an After read that found more than Limit new rows: the
// page is the newest page instead, and those rows were not all returned.
Gap bool
}
HistoryPage is what History returns.
type HistoryPlace ¶ added in v0.0.5
HistoryPlace is a row's place in the feed's time order: the julian day it happened on (0 for a time that cannot be read), whether it is an event, and its step number or event id.
type HistoryQuery ¶ added in v0.0.5
type HistoryQuery struct {
// Before pages down: the Limit rows listed after this place.
Before *HistoryPlace
// After returns every row written since this cursor, in feed order, when
// there are at most Limit of them; otherwise the newest page with
// HistoryPage.Gap set.
After *HistoryCursor
// Offset skips that many rows from the top before the page starts, for
// callers that page by position. Only without Before and After; it reads
// one index entry per skipped row, which positions avoid.
Offset int
// Limit is the most rows returned; it must be positive.
Limit int
// MaxValue, when positive, is the longest step output or event details
// returned whole; longer ones are cut (see HistoryRow.Cut).
MaxValue int
}
HistoryQuery selects one page of the feed.
type HistoryRow ¶ added in v0.0.5
type HistoryRow struct {
Step *StepRow
Event *EventRow
// Place is where the row lists in the feed.
Place HistoryPlace
// Cut is the full length in bytes of the step's Output or the event's
// Details when the value here was shortened to HistoryQuery.MaxValue, and
// 0 when it is whole. A shortened Output is its first MaxValue bytes; a
// shortened Details is empty, since half a JSON document is not one.
Cut int
}
HistoryRow is one row of the feed: a step or an event, never both.
type HubEventRow ¶ added in v0.0.5
type HubEventRow struct {
Seq int64
Origin string
Target string
Topic string
Key string
Payload string
CreatedAt time.Time
}
HubEventRow is one event on the cluster bus.
type HubLeaseRow ¶
type HubLeaseRow struct {
Scope string
InstanceID string
Hostname string
PID int
// BootID disambiguates a pid across reboots; ” when the platform does
// not expose one. A liveness probe must not trust PID unless this matches
// the probing host's current boot id.
BootID string
Address string
Version string
AcquiredAt time.Time
HeartbeatAt time.Time
// ReleasedAt is the instant of a graceful release; the zero time means the
// lease is still held (or was abandoned without one).
ReleasedAt time.Time
}
HubLeaseRow is one fence row: who holds the control plane, and since when.
func (HubLeaseRow) Held ¶
func (r HubLeaseRow) Held() bool
Held reports whether the row represents a lease nobody has given up. It says nothing about whether the holder is alive — that is HeartbeatAt's job, and deciding it is pkg/hublease's.
type HubMemberRow ¶ added in v0.0.5
type HubMemberRow struct {
InstanceID string
Hostname string
PID int
// BootID disambiguates a pid across reboots, exactly as on HubLeaseRow.
BootID string
Address string
AdvertiseURL string
Version string
// Meta is a JSON object of further endpoints; "{}" when there are none.
Meta string
StartedAt time.Time
HeartbeatAt time.Time
// LeftAt is a graceful leave; the zero time while the member serves.
LeftAt time.Time
}
HubMemberRow is one hub process serving this control plane.
type HubOwnerRow ¶ added in v0.0.5
type HubOwnerRow struct {
Kind string
Key string
InstanceID string
Meta string
ClaimedAt time.Time
UpdatedAt time.Time
}
HubOwnerRow records which member holds (Kind, Key).
type HubTLSRow ¶ added in v0.0.5
type HubTLSRow struct {
// ID is "ca" or "leaf:<monitor>".
ID string
// Kind is "ca" or "leaf".
Kind string
// Serial is the certificate's serial in lowercase hex.
Serial string
// Issuer is, for a leaf, the serial of the CA that signed it.
Issuer string
// CertPEM is the certificate. Public.
CertPEM string
// KeyID, WrappedDEK and KeySealed are the private key's envelope.
KeyID string
WrappedDEK []byte
KeySealed []byte
// SANs are a leaf's names and addresses.
SANs []string
// NotBefore and NotAfter bound the certificate's validity.
NotBefore time.Time
NotAfter time.Time
// IssuedAt and IssuedBy say when and by which hub process.
IssuedAt time.Time
IssuedBy string
}
HubTLSRow is one row of hub_tls.
type IdentitySpend ¶ added in v0.0.2
type IdentitySpend struct {
Identity string
InputTokens int
OutputTokens int
ThinkingTokens int
EstimatedUSD float64
Entries int
}
IdentitySpend is one identity's total spend over a window.
type ImagePolicyDenialInput ¶
type ImagePolicyDenialInput struct {
// ProjectPath identifies the project whose .cloop/sandbox.yaml was
// refused. It is the entity the row is filed under.
ProjectPath string
// Image is the reference as the project wrote it, unmodified — the
// normalized form would hide exactly the homograph or confusion attempt
// that is the reason to look.
Image string
// Rule is the imagepolicy rule that refused it ("registry-allowlist",
// "digest-required", …). Kept as the same string the API and the error
// text use, so filtering the trail and reading a bug report agree.
Rule string
// Reason is the human-readable observation.
Reason string
// Registry and Repository are the parsed components, empty when the
// reference did not parse. They are what makes "show me every denial for
// this registry" a query rather than a grep.
Registry string
Repository string
// Actor is the acting identity, normally the OIDC subject label.
Actor string
}
ImagePolicyDenialInput carries one refused container image to the audit log (Task 20177).
This is the one sandbox decision worth a permanent row. The others describe a project asking for less than it could have; this one describes a project asking to execute code from somewhere the operator does not trust, and the question it has to answer later is "was this a typo in one repo, or did the same unknown registry get named across six projects in an hour". Only a durable, queryable trail answers the second.
type KEKRow ¶
type KEKRow struct {
ID string
Salt string
State string
CheckValue []byte
CreatedAt string
CreatedBy string
RetiredAt string
}
KEKRow is one row of broker_keks.
type KillRequest ¶
type KillRequest struct {
TaskID int
TargetStatus string // empty when the operator did not pick a final status
RequestedAt time.Time
RequestedBy string // free-form (UI client ID, "ui", etc.) — informational only
// Attempt identifies the execution being aborted: the RFC3339Nano
// started_at the requester observed on the task. The orchestrator honours
// the row only while the task's started_at still matches, so a request
// that outlives its run cannot cancel a later attempt of the same task.
// Empty means "no attempt named" and is treated as stale (Task 20203).
Attempt string
}
KillRequest is one pending manual-abort request keyed by task ID.
type LeaseRevocationRow ¶ added in v0.0.5
type LeaseRevocationRow struct {
LeaseID string
// GrantID is the grant the revocation names, "" for the whole lease.
GrantID string
Action string
Reason string
Actor string
ExecutorID string
ProjectID string
// Holder is the hub member that held the lease when it was revoked.
Holder string
RevokedAt time.Time
// EnforcedAt is when the material was found taken back from every
// holder, zero while the revocation is pending.
EnforcedAt time.Time
EnforcedBy string
Detail string
}
LeaseRevocationRow is one revocation of a lease, or of one grant of it.
func (LeaseRevocationRow) Pending ¶ added in v0.0.5
func (r LeaseRevocationRow) Pending() bool
Pending reports whether the revocation has not been enforced yet.
type LegalHoldRow ¶ added in v0.0.5
LegalHoldRow is one identity under a legal hold.
type MaintenanceLogEntry ¶
type MaintenanceLogEntry struct {
ID int64
Operation string
StartedAt time.Time
CompletedAt time.Time
PageCountBefore int64
PageCountAfter int64
PageSize int64
BytesBefore int64
BytesAfter int64
Note string
}
MaintenanceLogEntry mirrors one row of the maintenance_log table.
ID is auto-assigned by SQLite on insert. Operation is one of "vacuum", "analyze", or "vacuum+analyze" (we record the combined run as a single row). Note carries free-form context — typically the auto-mode reasoning string.
func (MaintenanceLogEntry) BytesFreed ¶
func (e MaintenanceLogEntry) BytesFreed() int64
BytesFreed returns BytesBefore - BytesAfter (zero when the file did not shrink, e.g. because freelist was already empty).
type MemberAudit ¶ added in v0.0.5
type MemberAudit func(prev, next *ProjectMemberRow) ([]*AuditEvent, error)
MemberAudit builds the audit events committed together with a membership change. prev is the row as it stood before the change and next the row after it; either is nil when there was none, so a grant has prev == nil and a removal next == nil. Returning an error aborts the change: an authorization change with no record is treated as one that did not happen.
type MigrateOptions ¶
type MigrateOptions struct {
// Target stops after the migration numbered Target. Zero means
// LatestVersion — every embedded migration.
Target int
// AllowSchemaDowngrade suppresses the refusal to open a database whose
// schema is ahead of this binary's. See schema_guard.go; the operator-
// facing spelling is the CLOOP_ALLOW_SCHEMA_DOWNGRADE environment
// variable, which Migrate and MigrateTo read on the caller's behalf.
AllowSchemaDowngrade bool
}
MigrateOptions configures MigrateWithOptions.
type MigrationCompat ¶ added in v0.0.2
type MigrationCompat string
MigrationCompat says whether a migration can be tolerated by a binary that predates it.
const ( // CompatUnknown is the zero value: nothing classified this migration, so // nothing may assume it is safe. Treated exactly like CompatBreaking. CompatUnknown MigrationCompat = "" // CompatAdditive means the migration only introduced objects that did not // exist before — new tables, new non-unique indexes, new views, and // columns appended to tables no shipped build rewrites. An older binary // cannot read or write them because it does not know their names, and // their presence changes nothing about the statements it does issue. CompatAdditive MigrationCompat = "additive" // CompatAdditiveColumns is CompatAdditive for a migration that also // appends a column to one of rewrittenTables. A build from Task 20388 on // writes those tables row by row, in the columns it knows, so the new // column survives it and it tolerates the migration. A build before that // replaces their rows on every write and would erase the column; it has // never heard of this verdict, reads it as unknown, and refuses the // database instead. CompatAdditiveColumns MigrationCompat = "additive-columns" // CompatBreaking means the migration changed something that was already // there, or did something this classifier does not understand. Either way // an older binary must not open the database. CompatBreaking MigrationCompat = "breaking" )
func (MigrationCompat) Tolerable ¶ added in v0.0.2
func (c MigrationCompat) Tolerable() bool
Tolerable reports whether a binary that does not embed this migration may still open a database that has it.
Every build from Task 20254 to Task 20387 answered this with c == CompatAdditive, which is what makes CompatAdditiveColumns a refusal for them.
type MigrationReport ¶
type MigrationReport struct {
StartVersion int // version recorded before this run (0 = brand new DB)
EndVersion int // highest version applied (or already present)
Applied []int // versions newly applied during this run
BaselineApplied bool // true when an existing pre-framework DB was adopted at v1
// Divergent names a version this database recorded under a different
// migration file than this binary embeds. See checkNames.
Divergent []VersionDivergence
}
MigrationReport summarises the outcome of a Migrate call.
func Migrate ¶
func Migrate(db *sql.DB) (*MigrationReport, error)
Migrate brings db up to the latest embedded schema version. Safe to call repeatedly: a fully migrated database is a no-op. Each pending migration runs inside a transaction together with the schema_migrations row insert, so an interrupted run leaves the database at the previous version.
Errors are wrapped with ErrSchemaMismatch so callers can use errors.Is to distinguish migration failures from generic SQLite errors. A database ahead of this binary additionally carries ErrSchemaTooNew.
func MigrateTo ¶
func MigrateTo(db *sql.DB, target int) (*MigrationReport, error)
MigrateTo is Migrate, stopping after the migration numbered target. It exists so that a test can construct the schema some earlier release actually shipped and then let Open() migrate it forward, which is the only way to exercise a migration against the database it will really meet.
The alternative — migrate fully, then hand-undo one migration's DDL and delete its schema_migrations row — does not work, and the way it fails is worth recording. currentVersion is MAX(version), so forgetting migration N forgets everything after it too, and they all re-run. That is harmless while every later migration is CREATE ... IF NOT EXISTS, and stops being harmless the moment one of them is an ALTER TABLE ADD COLUMN, which SQLite has no idempotent spelling for. It then fails with "duplicate column name" inside whichever unrelated test did the rewinding.
Note that target bounds how far *forward* this call migrates and has no bearing on the version-skew refusal, which always compares the database against the highest migration the binary embeds.
func MigrateWithOptions ¶
func MigrateWithOptions(db *sql.DB, opts MigrateOptions) (*MigrationReport, error)
MigrateWithOptions is Migrate with the opt-out under the caller's control rather than the environment's. `cloop hub doctor` uses it to inspect a database the hub itself would refuse — diagnosing a skew is the one job that must still work when the skew is present.
type OffboardApplied ¶ added in v0.0.2
type OffboardApplied struct {
// Sessions, Tokens and Glasses are the ids that really changed state:
// sessions that existed and were deleted, tokens that were live and are now
// stamped revoked. Ids that were already gone or already revoked are
// omitted — they are not this operator's action.
Sessions []string
Tokens []string
Glasses []string
// DenyBindingIDs are the ids of the bindings written.
DenyBindingIDs []string
// Members are the project memberships actually dropped (Task 20366), as
// rows rather than ids: the report names the projects the person was
// removed from, which an id cannot be read back to.
Members []ProjectMemberRow
// At is the timestamp stamped on the revocations.
At time.Time
}
OffboardApplied reports what the transaction actually changed, as opposed to what it was asked to change.
func (OffboardApplied) Severed ¶ added in v0.0.2
func (a OffboardApplied) Severed() bool
Severed reports whether anything at all changed.
type OffboardWrite ¶ added in v0.0.2
type OffboardWrite struct {
// IdentityKey labels the person in the audit trail. Free-form; pkg/offboard
// passes the canonical owner key (lowercased email, or "sub:"+subject).
IdentityKey string
// SessionIDs are hashed session ids, as stored in sessions.id.
SessionIDs []string
// TokenIDs and GlassesIDs both address api_tokens.id. They are separate
// fields rather than one list because they are separate *surfaces* to an
// operator — "their PAT still works" and "their glasses link still works"
// are different incidents — and the audit trail records them separately.
TokenIDs []string
GlassesIDs []string
// MemberKeys are the identity keys whose project memberships are dropped
// (Task 20366): every spelling of the person, because a grant recorded
// under "sub:<subject>" survives a sweep by email, and a surviving
// membership is live access to a colleague's project. Severed in this
// transaction for the reason the transaction exists — "their sessions are
// gone but they are still on three projects" is exactly the
// partially-offboarded state nobody would discover.
MemberKeys []string
// DenyBindings are written in the same transaction. They are what keep the
// account out if the IdP later hands it a fresh session: revoking sessions
// alone is undone by the next successful sign-in.
//
// It is a list because one identity can be addressed by more than one
// claim. Denying only the email leaves a re-issued session that carries the
// same subject and no email claim — which several IdPs do once an account
// is disabled — matching nothing. pkg/offboard writes one per identifier it
// resolved.
DenyBindings []RoleBindingRow
// At stamps revoked_at. Zero means now.
At time.Time
// Audit builds the events to chain into this same commit. It is a callback
// rather than a slice because it must describe what the transaction
// actually changed, which is not known until the writes have run: rows
// disappear between planning and committing (a session expires, a token was
// already revoked), and an audit trail that reports the plan instead of the
// outcome is one that overstates containment.
//
// Returning no events is allowed. An error aborts the whole transaction —
// an unrecorded severing of authority is treated as a failed severing,
// because the operator can safely re-run but cannot recover the record.
Audit func(OffboardApplied) ([]*AuditEvent, error)
}
OffboardWrite is the resolved set of rows to sever, plus the deny binding to write. Every field is optional: an identity with no API tokens simply passes an empty TokenIDs.
type OpenOptions ¶
type OpenOptions struct {
// AllowSchemaDowngrade opens a database whose schema is ahead of this
// binary's instead of refusing it. Open sets this from
// CLOOP_ALLOW_SCHEMA_DOWNGRADE; diagnostics that must read a skewed
// database in order to report on it set it directly.
AllowSchemaDowngrade bool
}
OpenOptions configures OpenWithOptions.
type ProjectAuditInput ¶ added in v0.0.5
type ProjectAuditInput struct {
Action auditaction.Action
// Path is the project's directory, the entity the row is filed under.
Path string
Actor string
Detail map[string]any
}
ProjectAuditInput carries one project.create or project.delete row (Task 20418). Detail is the action's payload beside the path, keyed as the registry lists it (pkg/auditaction).
type ProjectClaim ¶ added in v0.0.5
type ProjectClaim struct {
Path string
State string
Owner string
HubMade bool
Root string
ClaimedBy string
ClaimedAt time.Time
UpdatedAt time.Time
}
ProjectClaim is one row of project_claims.
type ProjectExecutorBinding ¶
type ProjectExecutorBinding struct {
ProjectPath string `json:"project_path"`
ExecutorID string `json:"executor_id"`
BoundAt time.Time `json:"bound_at"`
BoundBy string `json:"bound_by,omitempty"`
}
ProjectExecutorBinding pins one project directory to one executor.
type ProjectFirewallAuditInput ¶ added in v0.0.5
type ProjectFirewallAuditInput struct {
// Action is "set", "clear" or "constrain".
Action string
ProjectPath string
// ExecutorID is the executor the project resolved to when the rules were
// written, so a reviewer can see which device's rules they were checked
// against.
ExecutorID string
Actor string
Detail map[string]any
}
ProjectFirewallAuditInput carries one change to a project's firewall rule set (Task 20363).
type ProjectMemberRow ¶ added in v0.0.5
type ProjectMemberRow struct {
ID string
ProjectPath string
IdentityKey string
Role string
Reason string
GrantedAt time.Time
GrantedBy string
}
ProjectMemberRow is one row of project_members.
type ProjectResourceLimit ¶ added in v0.0.2
type ProjectResourceLimit struct {
ProjectPath string `json:"project_path"`
Ceiling executor.ResourceCeiling `json:"ceiling"`
SetAt time.Time `json:"set_at,omitempty"`
SetBy string `json:"set_by,omitempty"`
}
ProjectResourceLimit is one project's ceiling plus its provenance.
type ProviderCallPruneResult ¶ added in v0.0.2
type ProviderCallPruneResult struct {
// Stripped is the number of rows whose bodies were cleared, and
// StrippedBytes the text those bodies held.
Stripped int64 `json:"stripped"`
StrippedBytes int64 `json:"stripped_bytes"`
RowPruneResult
}
ProviderCallPruneResult reports both halves of a provider_calls pass.
type ProviderCallRetention ¶ added in v0.0.2
type ProviderCallRetention struct {
// BodyMaxAge clears prompt, system_prompt and response on rows older than
// this, keeping the row itself. Zero or less keeps every body.
BodyMaxAge time.Duration
// Rows bounds the rows themselves, applied after the strip.
Rows RowRetention
}
ProviderCallRetention bounds provider_calls, which needs two limits rather than one because its rows are cheap and its bodies are not.
func (ProviderCallRetention) Active ¶ added in v0.0.2
func (p ProviderCallRetention) Active() bool
Active reports whether this policy would change anything.
type ProviderCallRow ¶
type ProviderCallRow struct {
ID int64
Timestamp time.Time
Provider string
Model string
TaskID int
TaskTitle string
RequestID string
Prompt string
SystemPrompt string
Response string
ErrorMessage string
Status string // "ok" | "error" | "timeout" | "context_canceled"
Headers string // JSON object, secrets already redacted
InputTokens int
OutputTokens int
ThinkingTokens int
LatencyMs int
}
ProviderCallRow is one row in the provider_calls table. Headers is a JSON-encoded string by the time it reaches this layer (the redaction step runs in pkg/provideraudit before the row is built).
type ProxySessionFilter ¶ added in v0.0.5
type ProxySessionFilter struct {
Kind string
// LeaseIDs keeps the sessions fed by any of these leases.
LeaseIDs []string
// SessionIDs keeps the sessions with any of these ids.
SessionIDs []string
RunID string
Holder string
// OpenOnly drops closed sessions.
OpenOnly bool
}
ProxySessionFilter narrows ListProxySessions. Zero fields do not filter.
type ProxySessionRow ¶ added in v0.0.5
type ProxySessionRow struct {
Kind string
SessionID string
// TokenSHA256 is the hex SHA-256 of the bearer token the sandbox presents.
TokenSHA256 string
LeaseID string
GrantID string
// Holder is the hub process serving the session.
Holder string
RunID string
ProjectID string
ExecutorID string
TaskID string
Actor string
// Scope is the registry's JSON account of what the session enforces.
Scope string
// Counters is the registry's JSON checkpoint of what the session has
// moved, for a session whose quota outlives its process (egress).
Counters string
IssuedAt time.Time
ExpiresAt time.Time
UpdatedAt time.Time
ClosedAt time.Time
CloseReason string
}
ProxySessionRow is one minted session. It says who serves the session, what it enforces and how its token hashes — never a token or the credential the session presents upstream.
func (ProxySessionRow) Open ¶ added in v0.0.5
func (r ProxySessionRow) Open() bool
Open reports whether the session has not been closed.
type QuarantinedTask ¶ added in v0.0.5
type QuarantinedTask struct {
TaskID int
Title string
Status string
Mark pm.TaskQuarantine
}
QuarantinedTask is one marked task as PeekTaskQuarantines reads it.
func PeekTaskQuarantines ¶ added in v0.0.5
func PeekTaskQuarantines(dbPath string) ([]QuarantinedTask, error)
PeekTaskQuarantines lists the marked tasks in the project database at dbPath without migrating or writing it: a read-only connection, for code that surveys many projects from outside them, such as `cloop executor list --inventory`. A database that predates the table has none.
type QuotaCounterRow ¶
type QuotaCounterRow struct {
Identity string
Resource string
Bucket string
Value float64
UpdatedAt time.Time
}
QuotaCounterRow is one row of quota_counters.
type QuotaOverrideRow ¶
type QuotaOverrideRow struct {
Identity string
LimitsJSON string
UpdatedAt time.Time
UpdatedBy string
}
QuotaOverrideRow is one row of quota_overrides. LimitsJSON is stored opaquely: the set of resources is pkg/quota's business, and a storage layer that validated it would be a second place to update when one is added.
type RetiredStaticTokenRow ¶ added in v0.0.5
type RetiredStaticTokenRow struct {
Fingerprint string
RetiredAt time.Time
RetiredBy string
Reason string
}
RetiredStaticTokenRow is one row of retired_static_tokens.
type RoleBindingRow ¶ added in v0.0.2
type RoleBindingRow struct {
ID string
Effect string
Claim string
Value string
Role string
Project string
Executor string
Reason string
CreatedAt time.Time
CreatedBy string
}
RoleBindingRow is one row of role_bindings.
type RotationRow ¶
type RotationRow struct {
ID string
ToKeyID string
State string
StartedAt string
UpdatedAt string
FinishedAt string
StartedBy string
Total int
Rewrapped int
Skipped int
Failed int
LastError string
}
RotationRow is one row of key_rotations.
type RowPruneResult ¶ added in v0.0.2
type RowPruneResult struct {
// Deleted is the number of rows removed.
Deleted int64 `json:"deleted"`
// BytesReleased is the variable-width column content those rows held. It
// is returned to the database freelist, not to the filesystem — only the
// subsequent VACUUM shrinks the file — so callers must not add it to a
// "bytes reclaimed" total that also counts the VACUUM.
//
// Measured across the rows the prune set out to remove, so when the call
// also returns an error it describes the intent rather than the outcome.
// Read it together with the error, never instead of it.
BytesReleased int64 `json:"bytes_released"`
// Remaining is the row count after the prune (before it, in a dry run).
Remaining int64 `json:"remaining"`
}
RowPruneResult is what one table's prune did, or would have done in a dry run.
type RowRetention ¶ added in v0.0.2
type RowRetention struct {
// MaxRows is the hard ceiling: the newest MaxRows rows survive and the
// rest are deleted. Zero or less keeps every row.
MaxRows int
// MaxAge deletes rows older than this. Zero or less keeps every row
// regardless of age.
//
// An age bound alone does not make a table bounded — an unbounded write
// rate still produces an unbounded table within any fixed window — which is
// why hubdoctor reports boundedness off MaxRows and not off this.
MaxAge time.Duration
}
RowRetention bounds one row table. The zero value bounds nothing.
func (RowRetention) Active ¶ added in v0.0.2
func (r RowRetention) Active() bool
Active reports whether this policy would delete anything at all.
func (RowRetention) Bounded ¶ added in v0.0.2
func (r RowRetention) Bounded() bool
Bounded reports whether this policy puts a ceiling on the table's size.
type RunReexecInput ¶ added in v0.0.5
type RunReexecInput struct {
ProjectPath string
RunID string
PID int
From, To runbuild.Build
Reason string
Reexecs int
}
RunReexecInput is one run that replaced its image with a newer build at a task boundary (Task 20389).
type SCIMConflict ¶ added in v0.0.5
type SCIMConflict struct {
// Column is the uniqueness rule broken: user_name_key, email,
// external_id, external_id_key or display_name_key.
Column string
// Label is the caller's name for the rule, for the message.
Label string
// Value is the contested value, and OtherID the resource holding it.
Value string
OtherID string
}
SCIMConflict reports that a write would give a provisioned resource a value another one already holds.
func (*SCIMConflict) Error ¶ added in v0.0.5
func (c *SCIMConflict) Error() string
type SCIMCredentialRow ¶ added in v0.0.5
type SCIMCredentialRow struct {
ID string
Name string
SecretHash string
PreviousHash string
PreviousExpiresAt time.Time
CreatedAt time.Time
CreatedBy string
RotatedAt time.Time
RotatedBy string
RevokedAt time.Time
RevokedBy string
LastUsedAt time.Time
}
SCIMCredentialRow is one SCIM bearer credential. Only HMACs of its secret are stored.
func (SCIMCredentialRow) Revoked ¶ added in v0.0.5
func (c SCIMCredentialRow) Revoked() bool
Revoked reports whether the credential was revoked.
type SCIMDirectory ¶ added in v0.0.5
type SCIMDirectory struct {
Version int64
Users []SCIMDirectoryUser
// Groups maps a group id to its display name and external id.
Groups map[string]SCIMDirectoryGroup
}
SCIMDirectory is what the authorization path needs of the directory: every user's identifiers and state, and the groups each belongs to.
type SCIMDirectoryGroup ¶ added in v0.0.5
SCIMDirectoryGroup is one group's names.
type SCIMDirectoryUser ¶ added in v0.0.5
type SCIMDirectoryUser struct {
ID string
UserName string
ExternalID string
Email string
Active bool
GroupIDs []string
}
SCIMDirectoryUser is one user, without its resource.
type SCIMGroupApplied ¶ added in v0.0.5
type SCIMGroupApplied struct {
Row SCIMGroupRow
// Added and Removed are the membership changes; Unknown the member ids
// asked for that name no provisioned user, which were not stored.
Added []string
Removed []string
Unknown []string
At time.Time
}
SCIMGroupApplied reports what a group write changed.
type SCIMGroupRow ¶ added in v0.0.5
type SCIMGroupRow struct {
ID string
DisplayName string
ExternalID string
ResourceJSON string
Version int64
CreatedAt time.Time
CreatedBy string
UpdatedAt time.Time
UpdatedBy string
// Members are the member user ids, sorted.
Members []string
}
SCIMGroupRow is one provisioned group.
type SCIMGroupWrite ¶ added in v0.0.5
type SCIMGroupWrite struct {
Row SCIMGroupRow
Create bool
ExpectVersion int64
// SetMembers replaces the membership with Row.Members. Without it the
// membership is left as it is.
SetMembers bool
At time.Time
Audit func(SCIMGroupApplied) ([]*AuditEvent, error)
}
SCIMGroupWrite is one change to a provisioned group.
type SCIMSuspendWrite ¶ added in v0.0.5
type SCIMSuspendWrite struct {
// Denies are written when no binding with their id exists; a binding
// already in force — an administrator's — is left as it is.
Denies []RoleBindingRow
// SessionIDs are hashed session ids to delete.
SessionIDs []string
// TokenIDs and GlassesIDs are api_tokens rows to revoke.
TokenIDs []string
GlassesIDs []string
// GrantIDs are grants to suspend, when they stand and are not suspended.
GrantIDs []string
// Record is what the user's suspension record will say about the
// identity; the ids written are filled in here.
Record SCIMSuspensionRecord
}
SCIMSuspendWrite is what deactivating a user severs in the hub's own database: resolved by pkg/provision, written here in one transaction.
type SCIMSuspensionRecord ¶ added in v0.0.5
type SCIMSuspensionRecord struct {
At time.Time `json:"at"`
By string `json:"by"`
// Reason is the reason written on the deny bindings. The lift removes a
// binding only while it still carries it: one an administrator wrote, or
// re-wrote, for the same identity is theirs and stays.
Reason string `json:"reason"`
// Denies are the deny bindings the suspension created — not ones it
// found already in force.
Denies []string `json:"denies,omitempty"`
// Grants are the grants it suspended.
Grants []string `json:"grants,omitempty"`
// Identity, Subjects and Emails are the hub identity it resolved, for the
// offboarding that may follow.
Identity string `json:"identity,omitempty"`
Subjects []string `json:"subjects,omitempty"`
Emails []string `json:"emails,omitempty"`
}
SCIMSuspensionRecord is what a suspension wrote and its lift may take back.
type SCIMUnique ¶ added in v0.0.5
SCIMUnique is one uniqueness rule a user write must satisfy: no other user may hold Value in Column.
type SCIMUserApplied ¶ added in v0.0.5
type SCIMUserApplied struct {
Row SCIMUserRow
// Suspended: the denies written, sessions deleted, tokens, glasses
// links and grants severed.
DeniesWritten []string
DeniesInForce []string
SessionsDeleted []string
TokensRevoked []string
GlassesRevoked []string
GrantsSuspended []string
// Lifted: the denies removed and grants restored, and the ones left
// because they were no longer the suspension's.
DeniesLifted []string
DeniesKept []string
GrantsResumed []string
At time.Time
}
SCIMUserApplied reports what a user write changed.
type SCIMUserRow ¶ added in v0.0.5
type SCIMUserRow struct {
ID string
UserName string
ExternalID string
DisplayName string
// Email is the account's address, lowercased (scim.UserFields.Email).
Email string
Active bool
// ResourceJSON is the resource as provisioned, less id, meta, schemas and
// any password.
ResourceJSON string
Version int64
CreatedAt time.Time
CreatedBy string
UpdatedAt time.Time
UpdatedBy string
// DeactivatedAt is when the user last went inactive; zero while active.
DeactivatedAt time.Time
// Suspension is what the suspension in force wrote (SCIMSuspensionRecord
// as JSON), or "" when none is.
Suspension string
// OffboardedAt is when the full offboarding ran for this user.
OffboardedAt time.Time
}
SCIMUserRow is one provisioned user.
func (SCIMUserRow) SuspensionRecord ¶ added in v0.0.5
func (r SCIMUserRow) SuspensionRecord() (SCIMSuspensionRecord, bool)
SuspensionRecord decodes the row's suspension, if one is in force.
type SCIMUserWrite ¶ added in v0.0.5
type SCIMUserWrite struct {
// Row is the user as it is to be stored. Row.Version is ignored: the
// stored version becomes ExpectVersion+1, or 1 on create.
Row SCIMUserRow
// Create inserts; otherwise the row is updated, and only while its stored
// version is ExpectVersion.
Create bool
ExpectVersion int64
// Unique are the rules no other user may break.
Unique []SCIMUnique
// Suspend, when set, is written with the change; Lift likewise.
Suspend *SCIMSuspendWrite
Lift bool
// At stamps the change. Zero means now.
At time.Time
// Audit builds the audit rows from what was applied, chained into the
// same commit. An error aborts the write.
Audit func(SCIMUserApplied) ([]*AuditEvent, error)
}
SCIMUserWrite is one change to a provisioned user, with everything that follows from it.
type SchemaStamp ¶
type SchemaStamp struct {
Version int `json:"version"`
Name string `json:"name,omitempty"`
AppliedAt time.Time `json:"applied_at,omitempty"`
AppliedBy string `json:"applied_by,omitempty"`
// Compat is the applying build's reading of whether this migration is
// tolerable to older binaries. Empty for rows written before that was
// recorded, which reads as "not known to be safe".
Compat MigrationCompat `json:"compat,omitempty"`
}
SchemaStamp is one schema_migrations row: which version was applied, when, and by which build.
AppliedBy is "" for rows written before this provenance existed, and for rows written by a process that never called SetBinaryVersion. Absence is not an error — it just means the refusal message cannot name a build.
type SchemaState ¶ added in v0.0.5
type SchemaState struct {
// Version is the highest migration schema_migrations records; zero when
// the table is missing or empty. Open migrates it to LatestSchemaVersion.
Version int
// PreFramework reports a database Open would adopt as its baseline instead
// of building from scratch: cloop's metadata table, and no migration
// recorded — the rule detectBaseline applies.
PreFramework bool
// HoldsProject reports a project in the database: a metadata row, the
// test HasProjectState applies. Opening a database creates the file and
// every table in it, so the file existing says nothing.
HoldsProject bool
}
SchemaState is what a database file is, in statedb's terms.
func InspectSchema ¶ added in v0.0.5
func InspectSchema(path string) (SchemaState, error)
InspectSchema reports what the database at path is, through a read-only handle: asking neither migrates it nor, when it does not exist, creates it.
type SchemaTooNewError ¶
type SchemaTooNewError struct {
// DBVersion is the highest version recorded in schema_migrations.
DBVersion int
// BinaryVersion is the highest migration embedded in this binary.
BinaryVersion int
// Stamp describes the schema_migrations row for DBVersion, when one could
// be read. A zero Stamp means the row was unreadable, not that it is
// absent — either way the message simply omits the provenance.
Stamp SchemaStamp
// Blocking lists the migrations ahead of this binary that it cannot
// tolerate: the ones recorded as breaking, plus any it could not classify.
// Migrations recorded as additive are absent, because they did not
// contribute to the refusal.
Blocking []SchemaStamp
}
SchemaTooNewError is the detail behind ErrSchemaTooNew: the two versions that disagree, plus whatever the database records about the build that moved it forward.
It satisfies errors.Is for both ErrSchemaTooNew and ErrSchemaMismatch. The second is deliberate: every existing caller that already treats a schema mismatch as fatal (HTTPStatus maps it to 500, classifyDriverErr declines to re-wrap it) keeps working unchanged, while callers that care about this specific cause can ask for it by name.
func (*SchemaTooNewError) Blockers ¶ added in v0.0.5
func (e *SchemaTooNewError) Blockers() string
Blockers names the migrations ahead of this binary that it cannot tolerate, for a caller that reports the refusal in its own words.
func (*SchemaTooNewError) Error ¶
func (e *SchemaTooNewError) Error() string
func (*SchemaTooNewError) Is ¶
func (e *SchemaTooNewError) Is(target error) bool
Is makes both sentinels match. See the type comment for why ErrSchemaMismatch is included.
type SealedFacts ¶ added in v0.0.5
type SealedFacts struct {
// KEKs is the sealing-key registry, retired keys included.
KEKs []KEKRow
// Rows counts sealed rows by set ("secrets", "sessions", "hub_tls"),
// then by the key id each is sealed under.
Rows map[string]map[string]int
// LegacySalt is the pre-envelope cipher's salt, hex; "" when the
// database has none.
LegacySalt string
// LegacySample is one ciphertext sealed the pre-envelope way, so a
// passphrase can be checked against the legacy key, which has no check
// value; nil when no row is sealed that way.
LegacySample []byte
}
SealedFacts is what a database's sealed material depends on.
func ReadSealedFacts ¶ added in v0.0.5
func ReadSealedFacts(conn *sql.DB, legacySaltKey string) (SealedFacts, error)
ReadSealedFacts reads the facts through conn. legacySaltKey names the legacy salt's row in broker_meta (secretbroker.LegacySaltMetaKey).
func (SealedFacts) ByKey ¶ added in v0.0.5
func (f SealedFacts) ByKey() map[string]int
ByKey totals Rows per key id, across sets.
func (SealedFacts) Sets ¶ added in v0.0.5
func (f SealedFacts) Sets() []string
Sets lists the sets with sealed rows, sorted.
type SealedRow ¶
SealedRow is a row of sealed material as the rotator sees it: an ID, the associated data it is bound to, and the three envelope parts.
type SecretAuditInput ¶
type SecretAuditInput struct {
Actor string
// EventType is the registered action: auditaction.ActionSecretLease,
// ActionSecretGrant, ActionSecretRevoke, and the rest of the secret,
// lease, egress and github_app families.
//
// Typed rather than a bare string because the whole broker surface funnels
// through this one struct, which makes it the single place a made-up
// action could enter the trail. Requiring an auditaction.Action means the
// value came from the registry, and tests/arch/auditaction_test.go can see
// that it did.
EventType auditaction.Action
EntityID string // secret ID, or grant ID when no secret is involved
Timestamp time.Time
// Payload is the decision's metadata. Callers are responsible for
// redacting it; pkg/secretbroker.Redact runs over every event before it
// reaches here, and again inside the secretstore auditor.
Payload map[string]any
}
SecretAuditInput carries one secret-broker decision to the audit log (Task 20159). It exists so pkg/secretstore does not have to construct an AuditEvent — and, more to the point, so the entity_type is set in exactly one place and every broker row is filterable as entity_type='secret'.
type SecretLeaseDirRow ¶
type SecretLeaseDirRow struct {
// Dir is the absolute path of the lease directory and the primary key.
Dir string
// LeaseID is the lease whose material lives there.
LeaseID string
// ExecutorID is the executor the lease was issued to, ” when unbound.
ExecutorID string
// ProjectPath is the project the work belongs to, ” when not scoped.
ProjectPath string
// CreatedAt is when the intent was recorded — before the directory was
// created, not after.
CreatedAt time.Time
// ExpiresAt is the lease's expiry; the zero time means unbounded. The
// sweep does not need it to decide, but an operator reading the audit
// event for a swept directory needs to know whether it had already lapsed.
ExpiresAt time.Time
// InstanceID is the hub process that materialised it, on a control plane
// several of them serve (Task 20354); ” for one written before that. A
// sweep must not wipe a directory a live peer's run is reading from.
InstanceID string
}
SecretLeaseDirRow is one credential directory this hub has committed to creating. It records where plaintext is, never what it is.
type SecretLeaseRow ¶ added in v0.0.5
type SecretLeaseRow struct {
LeaseID string
// Holder is the hub process keeping the lease alive.
Holder string
ExecutorID string
ProjectID string
RunID string
// Record is the broker's JSON account of the lease: requester, actor,
// kinds, grant ids.
Record string
IssuedAt time.Time
ExpiresAt time.Time
UpdatedAt time.Time
}
SecretLeaseRow is one live lease. It says who holds the lease and who it was issued to, never what it carries.
type SessionClaims ¶ added in v0.0.2
SessionClaims is a replacement set of group and role claims.
type SessionCutoffs ¶ added in v0.0.5
SessionCutoffs are the absolute times a session is compared against to decide whether it has ended (Task 20412). Absolute applies to expires_at for every kind; the idle cutoffs to last_seen, one per kind, because a CLI session idles out on its own clock. The caller computes them from its policy, so this layer stays free of any opinion about how long a session should live.
type SessionRefreshUpdate ¶ added in v0.0.2
type SessionRefreshUpdate struct {
KeyID string
WrappedDEK []byte
Sealed []byte
CheckedAt time.Time
Claims *SessionClaims
// ClaimsAsOf and ClaimsExpireAt update the claim-freshness clocks. A zero
// value leaves the stored column alone, which is what lets one update
// express "claims re-asserted" (both set), "claims repudiated"
// (ClaimsExpireAt only, backdated to the refusal) and "grant renewed but
// nothing learned" (neither) without a separate statement for each.
ClaimsAsOf time.Time
ClaimsExpireAt time.Time
}
SessionRefreshUpdate is the outcome of one IdP revalidation.
Claims is nil when the provider returned no id_token, meaning the stored claims are left untouched; a non-nil value replaces them, including with an empty set, which is how a user losing their last group is recorded.
type SessionRow ¶
type SessionRow struct {
ID string
Subject string
Issuer string
Email string
DisplayName string
OwnerKey string
Groups []string
Roles []string
IP string
UserAgent string
IssuedAt time.Time
LastSeen time.Time
ExpiresAt time.Time
RefreshSealed []byte
// RefreshKeyID and RefreshWrappedDEK are the envelope this row's sealed
// refresh token belongs to (Task 20181). "legacy" means the token is
// sealed directly under the passphrase-derived key, with no wrapped DEK.
RefreshKeyID string
RefreshWrappedDEK []byte
RefreshCheckedAt time.Time
// ClaimsAsOf and ClaimsExpireAt date the row's groups and roles, as opposed
// to RefreshCheckedAt which dates the grant (Task 20273). See
// migrations/0038_session_claim_freshness.sql for why they must be separate
// columns, and pkg/oidcauth/claimfresh.go for what reads them.
ClaimsAsOf time.Time
ClaimsExpireAt time.Time
// Kind is what the session authenticates — SessionKindBrowser by cookie,
// SessionKindCLI by bearer — and Client the host name a terminal reported
// (Task 20412, migrations/0066_device_login.sql). An empty Kind is written
// as a browser session, which is what every row before the column was.
Kind string
Client string
// Username and OID are the preferred_username and oid claims the session
// signed in with (Task 20415, migrations/0067_scim_provisioning.sql): what
// a SCIM directory matching on either is compared against.
Username string
OID string
}
SessionRow is one row of the sessions table.
RefreshSealed is ciphertext. Nothing in this package encrypts or decrypts it — the sealing happens in pkg/sessionstore, so the storage layer never holds a live credential and cannot leak one by logging a row.
type SizeStats ¶
SizeStats captures the physical size of the SQLite database at a point in time. Bytes is derived as PageCount * PageSize for convenience; FreelistPages counts free pages that VACUUM would reclaim.
func (SizeStats) FreelistBytes ¶
FreelistBytes returns the bytes currently allocated to the freelist — roughly the upper bound on what VACUUM can reclaim.
type SpendCursor ¶ added in v0.0.2
type SpendCursor struct {
ProjectPath string
// Identity is who the hub resolved when it dispatched the current run.
// The only identity this project's spend is ever charged to.
Identity string
// LastCostRowID is the highest costs.id already charged.
LastCostRowID int64
UpdatedAt time.Time
}
SpendCursor is the hub's booking position for one project.
type State ¶
type State struct {
Goal string
WorkDir string
MaxSteps int
CurrentStep int
Status string
// PauseReason explains a "paused" Status. Stored as JSON in the
// schemaless metadata table rather than as a column, so adding it needed
// no migration — and an older binary reading this DB just ignores the key
// instead of being locked out by a schema it does not know.
PauseReason *pausereason.Reason
Steps []StepRow
// StepCount mirrors len(Steps) on full loads but is also populated by
// LoadStateLite — where Steps is nil — so callers that only need a
// count don't have to materialize every row's Output (Task 20125).
StepCount int
// LastStepTime is the timestamp of the newest step row. Populated by
// both LoadState (last element of Steps) and LoadStateLite (cheap
// lookup of the highest step number); used by health probes to detect
// stalled runs without scanning the full Steps slice.
LastStepTime time.Time
CreatedAt time.Time
UpdatedAt time.Time
Model string
Instructions string
AutoEvolve bool
EvolveStep int
Provider string
Effort string
PMMode bool
Plan *pm.Plan
Milestones []*milestone.Milestone
TotalInputTokens int
TotalOutputTokens int
DefaultMaxMinutes int
SkipClarify bool
InnovateMode bool
Parallel bool
MaxParallel int
WorktreeParallel bool
PlanOnly bool
RetryFailed bool
DryRun bool
// ReviewGate is the project's review-gate configuration (Task 20357),
// stored as JSON under the review_gate meta key. Nil when never set.
ReviewGate *pm.ReviewGate
// CommitPolicy is the project's "done means committed" setting (Task
// 20370), stored as JSON under the commit_policy meta key. Nil when never
// set.
CommitPolicy *pm.CommitPolicy
// FollowBuilds, RunOwner and AdoptRequest are the project's side of a
// run adopting newer builds (Task 20389): the "follow new builds" option
// (follow_builds), the record the run keeps of its own process and build
// (run_owner) and a pending one-shot request to adopt (run_adopt_request).
// Each is written only through its own setter — SaveFollowBuilds,
// SaveRunOwner, SaveAdoptRequest — and never by SaveState, so neither a
// run's save nor a dashboard's can put back a stale copy.
FollowBuilds bool
RunOwner *runbuild.Owner
AdoptRequest *runbuild.Request
}
State mirrors pkg/state.ProjectState but is owned by this package to avoid import cycles. pkg/state converts between the two representations.
type StaticTokenUseReport ¶ added in v0.0.5
type StaticTokenUseReport struct {
Fingerprint string
// At is when the report was made.
At time.Time
// Held says the reporting process holds this token — it is its configured
// static token — and stamps held_at, held_by and sso.
Held bool
HeldBy string
SSO bool
// UsedAt and UsedIP are the latest request admitted with the token since
// the previous flush; zero when none was.
UsedAt time.Time
UsedIP string
// Refused counts the requests refused because the token is retired since
// the previous flush, the latest at RefusedAt from RefusedIP.
Refused int64
RefusedAt time.Time
RefusedIP string
}
StaticTokenUseReport is what one hub process flushes about one fingerprint: what it saw since its previous flush.
type StaticTokenUseRow ¶ added in v0.0.5
type StaticTokenUseRow struct {
Fingerprint string
FirstSeenAt time.Time
HeldAt time.Time
HeldBy string
SSO bool
LastUsedAt time.Time
LastUsedIP string
RefusedCount int64
LastRefusedAt time.Time
LastRefusedIP string
}
StaticTokenUseRow is one row of static_token_use.
type StepRow ¶
type StepRow struct {
Step int
Task string
Output string
ExitCode int
Duration string
Time time.Time
InputTokens int
OutputTokens int
}
StepRow represents one recorded step result.
type Store ¶
type Store interface {
// SaveState atomically persists the full project state (metadata, tasks,
// steps). Existing tasks are replaced; steps are upserted (never deleted).
SaveState(s *State) error
// LoadState reads back the complete project state. Returns a zero-value
// State (not an error) when the database exists but has no rows yet.
LoadState() (*State, error)
// UpsertTask inserts or replaces a single task row. Useful for
// status-only updates without a full SaveState round-trip.
UpsertTask(t *pm.Task) error
// LoadTask returns a single task by id. Returns ErrTaskNotFound when
// the row does not exist; callers should test with errors.Is.
LoadTask(id int) (*pm.Task, error)
// AppendStep inserts a step row. Idempotent on step number (upsert).
AppendStep(row StepRow) error
// AppendCost appends a single cost entry for the current project.
AppendCost(entry CostEntry) error
// ReadCosts returns all cost entries in chronological order.
ReadCosts() ([]CostEntry, error)
// ReadCostsSince returns cost entries with timestamp >= since.
ReadCostsSince(since time.Time) ([]CostEntry, error)
// MonthlyCosts returns cost entries for the given UTC year/month.
MonthlyCosts(year, month int) ([]CostEntry, error)
// PingContext verifies the underlying store is reachable by issuing a
// trivial query. Used by readiness probes; ctx bounds wait time on a
// busy connection.
PingContext(ctx context.Context) error
// Close releases the underlying connection.
Close() error
}
Store is the abstract data-access interface for cloop project state. All methods must be safe for concurrent use.
SQLite implementation: DB (this package). PostgreSQL: implement this interface with a pgx/pgxpool-backed struct.
type TableStat ¶ added in v0.0.2
type TableStat struct {
Name string `json:"name"`
Rows int64 `json:"rows"`
// Bytes is the variable-width column content across all rows. See
// growthTable.bytesExpr: an under-estimate of what the table costs on disk,
// deliberately.
Bytes int64 `json:"bytes"`
// Oldest is the insertion timestamp of the lowest-id row, or the zero time
// when the table is empty or that row's timestamp will not parse.
Oldest time.Time `json:"oldest,omitempty"`
}
TableStat is one row table's current size, for reporting.
type TaskDispatchInput ¶ added in v0.0.2
type TaskDispatchInput struct {
// TaskID and TaskTitle identify the unit of work. The title is recorded
// rather than joined later because a plan can be edited: an auditor reading
// this row six weeks on should see what the task said when it ran.
TaskID int
TaskTitle string
// ProjectPath is the project the task belongs to.
ProjectPath string
// RunID names the execution. It is the join key to the secret.lease rows
// the hub wrote for the same dispatch, and the reason leases attach to an
// execution rather than to a task id that may run many times.
RunID string
// ExecutorID, ExecutorKind and Isolation are where the work landed, as
// advertised at placement. Stored rather than derived by joining the
// executor registry later, for the reason migration 0032 gives: an executor
// re-enrolled under the same id would otherwise rewrite the history of
// every task it ever ran.
ExecutorID string
ExecutorKind string
Isolation string
// RequestedImage is the reference the sandbox spec asked for; PinnedImage
// is what actually ran, digest-pinned where the driver could resolve one.
// Both, because the gap between them is the question — a spec naming a tag
// and a run on a digest is reproducible, a run on the tag is not.
RequestedImage string
PinnedImage string
// SpecHash is the .cloop/sandbox.yaml content hash, empty when the project
// has no spec and ran on the executor's defaults. SetupHash identifies
// commands baked into a derived image.
SpecHash string
SetupHash string
// LeaseIDs are the secret leases handed to this run.
LeaseIDs []string
// Actor is who asked for the run.
Actor string
}
TaskDispatchInput carries the placement facts for one task execution (Task 20282).
It is filled by the orchestrator, which is the only layer that knows both a task id and the environment it was placed into: the hub chose the executor and started a whole `cloop run`, and by the time a task begins there is no placement decision left to read — the decision is why the process exists. What the hub leaves behind is .cloop/sandbox-run.json, and this struct is that record joined to the task it is about to run.
No field can carry a credential. LeaseIDs are the broker's opaque handles, not material; the digest and hashes are content addresses; Actor is an identity label. The token behind a lease never enters this package's scope.
type TaskRunStory ¶ added in v0.0.2
type TaskRunStory struct {
RunID string
// Dispatched and Finished are the boundary rows. Finished is nil for a run
// still in flight — or for one whose hub died so hard it never wrote a
// terminal row, which is a gap an auditor should see rather than have
// smoothed over with an invented outcome.
Dispatched *AuditEvent
Finished *AuditEvent
// ExecutorID, ExecutorKind and Isolation are where the work ran, read from
// the dispatch payload.
ExecutorID string
ExecutorKind string
Isolation string
// PinnedImage and SpecHash pin the environment.
PinnedImage string
SpecHash string
// LeaseIDs are the credentials the dispatch row claims were handed over.
LeaseIDs []string
// LeaseEvents are the broker's own rows for this run — the authoritative
// half. They are kept separate from LeaseIDs on purpose: the dispatch row
// is written by the orchestrator, which reads its lease ids from a file in
// a directory the workload can write to, whereas these rows are written by
// the hub and cannot be influenced from inside the sandbox. A reviewer
// checking a hostile workload should believe these.
LeaseEvents []AuditEvent
// Outcome, Reason and DurationMS come from the terminal row.
Outcome string
Reason string
DurationMS int64
// Actor is who the dispatch row attributes the run to.
Actor string
}
TaskRunStory is one execution of a task.
func (TaskRunStory) Duration ¶ added in v0.0.2
func (r TaskRunStory) Duration() string
Duration renders the execution's wall time, or "" when the trail does not record one.
func (TaskRunStory) RanOnHost ¶ added in v0.0.2
func (r TaskRunStory) RanOnHost() bool
RanOnHost reports whether this execution used the hub's own machine.
Mirrors orchestrator.RanOnHost, deliberately reimplemented over the audit payload rather than over a pm.Task: the point of a reconstruction is that it works without the task record.
type TaskStory ¶ added in v0.0.2
type TaskStory struct {
// TaskID is the task the story is about.
TaskID int
// Title is the task's title as the trail recorded it, from the most recent
// row that carried one. Empty when no row named it — which is itself a
// finding, not a formatting problem.
Title string
// Events are every row that belongs to this task's history, in trail order
// (ascending id, which is the order they were appended and therefore the
// order the hash chain fixes). Includes both the task-scoped rows and the
// run-correlated rows from other entities.
Events []AuditEvent
// Runs are the executions this task was dispatched into, oldest first. A
// task that ran five times has five entries, which is the distinction the
// whole run-id mechanism exists to preserve.
Runs []TaskRunStory
// Unattributed counts lifecycle rows that named no run — history from
// before run ids existed, or a dispatch whose provenance record was
// missing. It is reported rather than silently dropped: executions the
// trail cannot correlate are exactly what an auditor needs told.
Unattributed int
}
TaskStory is one task's reconstructed history.
type TelemetryFilter ¶ added in v0.0.2
type TelemetryFilter struct {
Source string
Kind string
Session string
// Search matches message, url, view and detail. Applied in SQL rather than
// in the caller because the table is bounded but large, and a reader
// filtering client-side would page through thousands of rows to find one.
Search string
Since time.Time
Limit int
Offset int
}
TelemetryFilter selects events for reading. The zero value means "the most recent page of everything", which is the query a reader opening the panel wants before they know what they are looking for.
type TelemetrySession ¶ added in v0.0.2
type TelemetrySession struct {
Session string `json:"session"`
Source string `json:"source"`
Events int `json:"events"`
Errors int `json:"errors"`
FirstSeen time.Time `json:"first_seen"`
LastSeen time.Time `json:"last_seen"`
UserAgent string `json:"user_agent,omitempty"`
Actor string `json:"actor,omitempty"`
Release string `json:"release,omitempty"`
}
TelemetrySession is one page load, rolled up.
The index of the panel: a reader arrives knowing "a wearer reported a problem around ten past four" and needs to turn that into a session id before any per-event view is useful.
type VersionDivergence ¶ added in v0.0.3
VersionDivergence is one version whose recorded name is not the name this binary embeds for it.
type VirtualExecutor ¶ added in v0.0.5
type VirtualExecutor struct {
ID string `json:"id"`
ParentID string `json:"parent_id"`
Name string `json:"name"`
Spec executor.VirtualSpec `json:"spec"`
// CreatedAt/By and UpdatedAt/By are provenance for the panel; the audit
// trail carries the full history.
CreatedAt time.Time `json:"created_at"`
CreatedBy string `json:"created_by,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
UpdatedBy string `json:"updated_by,omitempty"`
}
VirtualExecutor is one stored virtual executor.
type WALCheckpoint ¶ added in v0.0.5
type WALCheckpoint struct {
// Busy reports that the checkpoint could not finish within its busy
// timeout: another connection held the write lock, or a reader's snapshot
// still needed frames in the log. Not an error. What could be copied back
// was, and the log keeps its size until an attempt finds it free.
Busy bool `json:"busy"`
// LogFrames and CheckpointedFrames are SQLite's counts after the attempt:
// the frames in the log, and how many of them are in the database file.
// Both are zero once the log is truncated; on a busy attempt they say how
// far it got. -1 means the database is not in WAL mode at all.
LogFrames int `json:"log_frames"`
CheckpointedFrames int `json:"checkpointed_frames"`
// BytesBefore and BytesAfter are the log file's size either side. A writer
// may start the log again the moment the checkpoint finishes, so
// BytesAfter can be a few pages rather than zero.
BytesBefore int64 `json:"bytes_before"`
BytesAfter int64 `json:"bytes_after"`
// Duration is how long the TRUNCATE checkpoint ran: an upper bound on how
// long it held the write lock. The PASSIVE one before it, which takes no
// such lock, is not counted.
Duration time.Duration `json:"duration"`
}
WALCheckpoint is the outcome of one TRUNCATE checkpoint.
func CheckpointWAL ¶ added in v0.0.5
func CheckpointWAL(dbPath string, busy time.Duration) (WALCheckpoint, error)
CheckpointWAL runs PRAGMA wal_checkpoint(TRUNCATE) on the database at dbPath, through a connection of its own whose busy timeout is busy, or WALCheckpointBusyTimeout when busy is zero or less.
It never creates a database: one that does not exist is an error wrapping os.ErrNotExist. Nothing about the schema is read, so it migrates nothing and works on a database of any version.
A busy checkpoint is a result, not an error; see WALCheckpoint.Busy.
func (WALCheckpoint) BytesFreed ¶ added in v0.0.5
func (c WALCheckpoint) BytesFreed() int64
BytesFreed is how much the log shrank by.
func (WALCheckpoint) Truncated ¶ added in v0.0.5
func (c WALCheckpoint) Truncated() bool
Truncated reports whether the checkpoint reset the log.
type WorkspaceAuditInput ¶
type WorkspaceAuditInput struct {
// Phase is "start" or "end", matching executor.WorkspaceProvisionStart /
// WorkspaceProvisionEnd. It becomes the suffix of the event type, so the
// family is filterable as event_type LIKE 'workspace.%' and each phase
// individually by exact match. Anything else is dropped rather than
// written, so a typo cannot create a third, unqueryable event family.
Phase string
// ProjectPath is the project whose tree was being materialised. It is the
// entity the row is filed under, matching how image denials are filed.
ProjectPath string
// ExecutorID and ExecutorKind name the backend doing the fetch. Both are
// recorded because an ID is stable but says nothing about *where* the code
// landed, and "was this on a Pod or on someone's laptop" is the first
// question asked of a provisioning row.
ExecutorID string
ExecutorKind string
// HandleID correlates the two phases with each other and with the run.
HandleID string
// Kind, Repo, Ref and Depth are the workspace as dispatched — the clone
// URL exactly as the executor was told to fetch it, which is the only form
// that can be compared against what the operator believes is configured.
Kind string
Repo string
Ref string
Depth int
// GrantID and LeaseID name the authority used. They are the join key back
// into the secret-broker rows, which is what turns "this repo was fetched"
// into "this grant was exercised at this time".
GrantID string
LeaseID string
// DurationMS is set on the end phase only.
DurationMS int64
// Err is the failure, already redacted by the driver, or "" on success.
Err string
// Actor is the acting identity. Empty becomes "system": provisioning is
// decided by the dispatching control plane, and on the failover path there
// is no human to attribute it to.
Actor string
}
WorkspaceAuditInput carries one workspace-provisioning observation to the audit log (Task 20179).
Provisioning earns its own rows rather than being folded into the run's, because it is the moment a brokered credential is used against an external service on behalf of a project. "Which grant fetched which repository onto which executor, and did it work" is the question an operator has after an incident, and the run's own record cannot answer it: a run looks identical whether the tree arrived or not, which is the entire reason the workspace subsystem exists.
No field here can carry a credential. The Workspace the executor dispatched is structurally incapable of holding one — pkg/executor.Workspace has no field a token could go in, by design, because a Spec is persisted, logged and shipped across the remote-executor boundary — and GrantID/LeaseID are identifiers, not material. The token never enters this package's scope.
Source Files
¶
- addcolumn.go
- apitokens.go
- audit.go
- audit_anchor.go
- audit_attach.go
- audit_checkpoint.go
- audit_emit.go
- audit_failures.go
- audit_fingerprint.go
- audit_home.go
- audit_redact.go
- audit_run.go
- audit_story.go
- autoupdate.go
- broker.go
- ci_sessions.go
- cipipelines.go
- connpolicy.go
- db.go
- device_authorizations.go
- dispatch_intents.go
- egress.go
- errors.go
- events.go
- executor_agents.go
- executor_handles.go
- executor_scheduling.go
- executoraudience.go
- executorlimits.go
- executors.go
- executorsandbox.go
- firewall.go
- grantrequests.go
- history.go
- hub_cluster.go
- hub_instances.go
- hub_tls.go
- hubmeta.go
- inspect.go
- keys.go
- kill_requests.go
- lease_revocations.go
- maintenance.go
- migrate.go
- offboard.go
- projectclaims.go
- projectlimits.go
- projectmembers.go
- provider_calls.go
- proxy_sessions.go
- quotas.go
- rolebindings.go
- rowretention.go
- runbuild.go
- schema_compat.go
- schema_guard.go
- scim.go
- sealed_facts.go
- secret_lease_dirs.go
- secret_leases.go
- sessions.go
- spend_cursor.go
- static_tokens.go
- store.go
- task_quarantine.go
- task_runs.go
- taskcolumns.go
- telemetry.go
- usererror.go
- virtualexecutors.go
- wal.go