Documentation
¶
Index ¶
- Variables
- func ApplyHostEdit(ctx context.Context, s Store, logger *slog.Logger, before, after *models.Host) error
- type AuditFilter
- type HostFilter
- type MeshImportFinalizeHost
- type MeshImportFinalizeInput
- type SQLiteStore
- func (s *SQLiteStore) AcknowledgeHostConfigVersion(ctx context.Context, hostID string, version int) error
- func (s *SQLiteStore) AddAuditEntry(ctx context.Context, actor, action, resource, details string) error
- func (s *SQLiteStore) AddPopNonce(ctx context.Context, hostID, nonce string, expiresAt time.Time) error
- func (s *SQLiteStore) AddToBlocklist(ctx context.Context, fingerprint, hostID, reason string) error
- func (s *SQLiteStore) BlockHostAndAddToBlocklist(ctx context.Context, id, reason string) (*models.Host, error)
- func (s *SQLiteStore) BumpNetworkConfigVersion(ctx context.Context, networkID string) error
- func (s *SQLiteStore) CancelMeshImport(ctx context.Context, id, reason string, now time.Time) error
- func (s *SQLiteStore) ClearPendingRekey(ctx context.Context, hostID string) error
- func (s *SQLiteStore) ClearPrevFingerprint(ctx context.Context, hostID string) error
- func (s *SQLiteStore) Close() error
- func (s *SQLiteStore) ConsumeOperatorRecoveryCode(ctx context.Context, id, rawCode string) error
- func (s *SQLiteStore) ConsumeOperatorTOTPTimestep(ctx context.Context, id string, ts int64) error
- func (s *SQLiteStore) ConsumeToken(ctx context.Context, token string) (*models.EnrollmentToken, error)
- func (s *SQLiteStore) ConsumeTokenAndEnrollHost(ctx context.Context, hostID, token string, certPEM []byte, fp string, ...) error
- func (s *SQLiteStore) ConsumeTokenAndEnrollHostWithProfile(ctx context.Context, hostID, token string, certPEM []byte, fp string, ...) (int, error)
- func (s *SQLiteStore) CountEmptyCAIDRows(ctx context.Context) (int, error)
- func (s *SQLiteStore) CreateCA(ctx context.Context, c *models.CA) error
- func (s *SQLiteStore) CreateHost(ctx context.Context, h *models.Host) error
- func (s *SQLiteStore) CreateHostAndToken(ctx context.Context, h *models.Host, t *models.EnrollmentToken, ...) error
- func (s *SQLiteStore) CreateMeshImport(ctx context.Context, item *models.MeshImport, rawToken string) error
- func (s *SQLiteStore) CreateMeshImportChallenge(ctx context.Context, challenge *models.MeshImportChallenge, now time.Time) error
- func (s *SQLiteStore) CreateNetwork(ctx context.Context, n *models.Network) error
- func (s *SQLiteStore) CreateOperator(ctx context.Context, op *models.Operator) error
- func (s *SQLiteStore) CreateOperatorAPIKey(ctx context.Context, k *models.OperatorAPIKey, rawKey string) error
- func (s *SQLiteStore) CreateOperatorSession(ctx context.Context, sess *models.OperatorSession) error
- func (s *SQLiteStore) CreateToken(ctx context.Context, t *models.EnrollmentToken, rawToken string) error
- func (s *SQLiteStore) CreateTokenForHost(ctx context.Context, hostID, token string, expiresAt time.Time) error
- func (s *SQLiteStore) CreateWebhookSubscription(ctx context.Context, sub *models.WebhookSubscription) error
- func (s *SQLiteStore) DB() *sql.DB
- func (s *SQLiteStore) DeleteCA(ctx context.Context, id string) error
- func (s *SQLiteStore) DeleteExpiredOperatorSessions(ctx context.Context, before time.Time) error
- func (s *SQLiteStore) DeleteHost(ctx context.Context, id string) error
- func (s *SQLiteStore) DeleteHostAndBlockCert(ctx context.Context, id, reason string) error
- func (s *SQLiteStore) DeleteOperatorSession(ctx context.Context, token string) error
- func (s *SQLiteStore) DeleteOperatorSessionsByOperator(ctx context.Context, operatorID string) error
- func (s *SQLiteStore) DeleteOperatorSessionsByOperatorExcept(ctx context.Context, operatorID, keepToken string) error
- func (s *SQLiteStore) DeleteWebhookSubscription(ctx context.Context, id string) error
- func (s *SQLiteStore) DisableOperator(ctx context.Context, id string) error
- func (s *SQLiteStore) EnableOperator(ctx context.Context, id string) error
- func (s *SQLiteStore) FinalizeMeshImport(ctx context.Context, input MeshImportFinalizeInput) error
- func (s *SQLiteStore) FindCAByPredecessor(ctx context.Context, predecessorID string) (*models.CA, error)
- func (s *SQLiteStore) GetBlocklist(ctx context.Context) ([]string, error)
- func (s *SQLiteStore) GetBlocklistForCA(ctx context.Context, caID string) ([]string, error)
- func (s *SQLiteStore) GetCA(ctx context.Context, id string) (*models.CA, error)
- func (s *SQLiteStore) GetCAByFingerprint(ctx context.Context, fp string) (*models.CA, error)
- func (s *SQLiteStore) GetCertAlert(ctx context.Context, hostID string) (time.Time, error)
- func (s *SQLiteStore) GetCertificateInfo(ctx context.Context, hostID string) (*models.CertificateInfo, error)
- func (s *SQLiteStore) GetCurrentCertificate(ctx context.Context, hostID string) ([]byte, error)
- func (s *SQLiteStore) GetEnrollmentToken(ctx context.Context, token string) (*models.EnrollmentToken, error)
- func (s *SQLiteStore) GetHost(ctx context.Context, id string) (*models.Host, error)
- func (s *SQLiteStore) GetHostAgentProfile(ctx context.Context, hostID string) (*models.HostAgentProfile, error)
- func (s *SQLiteStore) GetHostByFingerprint(ctx context.Context, fingerprint string) (*models.Host, error)
- func (s *SQLiteStore) GetHostConfigVersion(ctx context.Context, hostID string) (int, error)
- func (s *SQLiteStore) GetMeshImport(ctx context.Context, id string) (*models.MeshImport, error)
- func (s *SQLiteStore) GetMeshImportByToken(ctx context.Context, rawToken string, now time.Time) (*models.MeshImport, error)
- func (s *SQLiteStore) GetMeshImportChallenge(ctx context.Context, id string) (*models.MeshImportChallenge, error)
- func (s *SQLiteStore) GetMeshImportTombstone(ctx context.Context, fingerprint string) (*models.MeshImportTombstone, error)
- func (s *SQLiteStore) GetNetwork(ctx context.Context, id string) (*models.Network, error)
- func (s *SQLiteStore) GetNetworkConfig(ctx context.Context, networkID, key string) (string, error)
- func (s *SQLiteStore) GetNetworkConfigVersion(ctx context.Context, networkID string) (int, error)
- func (s *SQLiteStore) GetOperator(ctx context.Context, id string) (*models.Operator, error)
- func (s *SQLiteStore) GetOperatorAPIKey(ctx context.Context, keyID string) (*models.OperatorAPIKey, error)
- func (s *SQLiteStore) GetOperatorByAPIKey(ctx context.Context, rawKey string) (*models.Operator, *models.OperatorAPIKey, error)
- func (s *SQLiteStore) GetOperatorByOIDC(ctx context.Context, issuer, subject string) (*models.Operator, error)
- func (s *SQLiteStore) GetOperatorBySession(ctx context.Context, token string) (*models.Operator, error)
- func (s *SQLiteStore) GetOperatorByUsername(ctx context.Context, username string) (*models.Operator, error)
- func (s *SQLiteStore) GetPendingTwoFactorOperator(ctx context.Context, token string) (*models.Operator, error)
- func (s *SQLiteStore) GetServerSetting(ctx context.Context, key string) (string, error)
- func (s *SQLiteStore) GetWebhookSubscription(ctx context.Context, id string) (*models.WebhookSubscription, error)
- func (s *SQLiteStore) ListActiveWebhookSubscriptionsForCA(ctx context.Context, caID string) ([]*models.WebhookSubscription, error)
- func (s *SQLiteStore) ListAuditEntries(ctx context.Context, filter AuditFilter) ([]*models.AuditEntry, error)
- func (s *SQLiteStore) ListCAs(ctx context.Context) ([]*models.CA, error)
- func (s *SQLiteStore) ListCAsApproachingExpiry(ctx context.Context, thresholdRatio float64) ([]*models.CA, error)
- func (s *SQLiteStore) ListCAsByOwner(ctx context.Context, ownerID string) ([]*models.CA, error)
- func (s *SQLiteStore) ListEnrolledHostCerts(ctx context.Context) ([]*models.CertificateInfo, error)
- func (s *SQLiteStore) ListHosts(ctx context.Context, filter HostFilter) ([]*models.Host, error)
- func (s *SQLiteStore) ListMeshImportSnapshots(ctx context.Context, meshImportID string) ([]*models.MeshImportSnapshot, error)
- func (s *SQLiteStore) ListMeshImports(ctx context.Context) ([]*models.MeshImport, error)
- func (s *SQLiteStore) ListMeshImportsByOwner(ctx context.Context, ownerID string) ([]*models.MeshImport, error)
- func (s *SQLiteStore) ListNetworks(ctx context.Context) ([]*models.Network, error)
- func (s *SQLiteStore) ListOperatorAPIKeys(ctx context.Context, operatorID string) ([]*models.OperatorAPIKey, error)
- func (s *SQLiteStore) ListOperatorRecoveryCodes(ctx context.Context, id string) ([]string, error)
- func (s *SQLiteStore) ListOperators(ctx context.Context) ([]*models.Operator, error)
- func (s *SQLiteStore) ListWebhookSubscriptions(ctx context.Context) ([]*models.WebhookSubscription, error)
- func (s *SQLiteStore) ListWebhookSubscriptionsByOwner(ctx context.Context, ownerID string) ([]*models.WebhookSubscription, error)
- func (s *SQLiteStore) Migrate(ctx context.Context) error
- func (s *SQLiteStore) Ping(ctx context.Context) error
- func (s *SQLiteStore) PromoteOperatorSession(ctx context.Context, token string, newExpiry time.Time) error
- func (s *SQLiteStore) RecordCertAlert(ctx context.Context, hostID string, alertedNotAfter time.Time) error
- func (s *SQLiteStore) RecordFailedLoginAttempt(ctx context.Context, id string, maxAttempts int, lockUntil time.Time) (bool, error)
- func (s *SQLiteStore) RecordWebhookDelivery(ctx context.Context, id string, ok bool, errMsg string, at time.Time) error
- func (s *SQLiteStore) RegisterImportedHost(ctx context.Context, registration *models.MeshImportRegistration, ...) (*models.MeshImportRegistrationResult, error)
- func (s *SQLiteStore) RemoveFromBlocklist(ctx context.Context, fingerprint string) error
- func (s *SQLiteStore) ReplaceOperatorRecoveryCodes(ctx context.Context, id string, rawCodes []string) error
- func (s *SQLiteStore) ResetFailedLoginAttempts(ctx context.Context, id string) error
- func (s *SQLiteStore) ResetOperatorTOTPBreakGlass(ctx context.Context, username string) error
- func (s *SQLiteStore) RevokeOperatorAPIKey(ctx context.Context, keyID string) error
- func (s *SQLiteStore) RotateMeshImportToken(ctx context.Context, id, rawToken string, expiresAt, now time.Time) error
- func (s *SQLiteStore) SaveCertificate(ctx context.Context, hostID string, certPEM []byte, fp string, ...) error
- func (s *SQLiteStore) SaveCertificateAndEnrollHost(ctx context.Context, hostID string, certPEM []byte, fp string, ...) error
- func (s *SQLiteStore) SaveCertificateAndUpdateHostCert(ctx context.Context, hostID string, certPEM []byte, fp string, ...) error
- func (s *SQLiteStore) SaveCertificateIfIssuanceAllowed(ctx context.Context, hostID string, expectedStatus models.HostStatus, ...) error
- func (s *SQLiteStore) SeedInitialAdminOperator(ctx context.Context, op *models.Operator, key *models.OperatorAPIKey, ...) (bool, error)
- func (s *SQLiteStore) SetNetworkConfig(ctx context.Context, networkID, key, value string) error
- func (s *SQLiteStore) SetNetworkConfigAndBumpVersion(ctx context.Context, networkID, key, value string) error
- func (s *SQLiteStore) SetOperatorTOTP(ctx context.Context, id, secret string, enabled bool) error
- func (s *SQLiteStore) SetPendingHostConfigVersion(ctx context.Context, hostID string, version int) error
- func (s *SQLiteStore) SetPendingRekey(ctx context.Context, hostID string) error
- func (s *SQLiteStore) SetPrevFingerprint(ctx context.Context, hostID, prev string, rotatedAt time.Time) error
- func (s *SQLiteStore) SetServerSetting(ctx context.Context, key, value string) error
- func (s *SQLiteStore) TouchOperatorAPIKey(ctx context.Context, keyID string, t time.Time) error
- func (s *SQLiteStore) UnblockHostAndRemoveFromBlocklist(ctx context.Context, id string) (*models.Host, error)
- func (s *SQLiteStore) UpdateCAStatus(ctx context.Context, id string, status models.CAStatus) error
- func (s *SQLiteStore) UpdateHost(ctx context.Context, h *models.Host) error
- func (s *SQLiteStore) UpdateHostCert(ctx context.Context, id, fingerprint string, expiresAt time.Time) error
- func (s *SQLiteStore) UpdateHostConfigVersion(ctx context.Context, hostID string, version int) error
- func (s *SQLiteStore) UpdateHostLastSeen(ctx context.Context, id string, t time.Time) error
- func (s *SQLiteStore) UpdateHostSigningPub(ctx context.Context, hostID, signingPubPEM string) error
- func (s *SQLiteStore) UpdateHostStatus(ctx context.Context, id string, status models.HostStatus) error
- func (s *SQLiteStore) UpdateNetwork(ctx context.Context, n *models.Network) error
- func (s *SQLiteStore) UpdateOperatorLastLogin(ctx context.Context, id string, t time.Time) error
- func (s *SQLiteStore) UpdateOperatorPassword(ctx context.Context, id, passwordHash string) error
- func (s *SQLiteStore) UpdateWebhookSubscription(ctx context.Context, sub *models.WebhookSubscription) error
- type SQLiteStoreOption
- type Store
Constants ¶
This section is empty.
Variables ¶
var ( ErrNotFound = errors.New("not found") ErrTokenUsed = errors.New("token already used") ErrTokenExpired = errors.New("token expired") ErrDuplicateEntry = errors.New("duplicate entry") ErrRekeyAlreadyPending = errors.New("rekey already pending") ErrReplayedNonce = errors.New("replayed nonce") ErrIPTaken = errors.New("nebula ip already assigned in network") ErrTOTPReplayed = errors.New("totp timestep already used") ErrMeshImportInProgress = errors.New("mesh import collection in progress") ErrMeshImportNotCollecting = errors.New("mesh import is not collecting") ErrMeshImportTokenExpired = errors.New("mesh import token expired") ErrMeshImportChallengeExpired = errors.New("mesh import challenge expired") ErrMeshImportChallengeLimit = errors.New("mesh import challenge limit reached") ErrMeshImportChallengeUsed = errors.New("mesh import challenge already used") ErrMeshImportChallengeMismatch = errors.New("mesh import challenge does not match registration") ErrMeshImportSigningKeyConflict = errors.New("certificate fingerprint is bound to another signing key") ErrMeshImportPayloadConflict = errors.New("certificate fingerprint is bound to another snapshot payload") ErrConfigAckUnsupported = errors.New("config acknowledgement is not supported by this host") ErrConfigVersionMismatch = errors.New("config acknowledgement version does not match pending delivery") ErrHostNotEnrolled = errors.New("host is not enrolled") ErrIssuanceNotAllowed = errors.New("certificate issuance is not allowed") ErrMeshImportExpectedHostsReached = errors.New("mesh import expected host count reached") ErrMeshImportScopeInvalid = errors.New("mesh import scope is invalid") ErrMeshImportConflict = errors.New("mesh import changed since preview") ErrCredentialCutoverBlocked = errors.New("credential cutover blocked by a collecting mesh import") ErrCredentialCutoverGuardMissing = errors.New("credential cutover master-key guard unavailable") )
Functions ¶
func ApplyHostEdit ¶ added in v0.11.0
func ApplyHostEdit(ctx context.Context, s Store, logger *slog.Logger, before, after *models.Host) error
ApplyHostEdit persists an edited host together with the follow-up writes a host edit implies. Both edit paths — the API's PATCH handler and the web UI's edit form — go through here so they cannot drift apart on what an edit means; they previously kept separate copies of these rules, and the copies disagreed about whether a group change needs a new certificate.
Callers are expected to have snapshotted `before`, merged their input into `after`, validated it, and established that something actually changed.
The pending-rekey flag is set on the host struct rather than through a separate SetPendingRekey write. UpdateHost commits it in the same transaction as the config_version reset (SEC-PERSIST-001), so a crash between the two cannot leave a host whose certificate-bound fields moved but whose re-issuance was never scheduled — which would strand an agent on a stale, possibly more permissive, certificate. Setting the flag when it is already set is a no-op, so retries stay idempotent.
The returned error is the one from persisting the host; callers map it to their own transport (ErrIPTaken → 409, ErrNotFound → 404). The network config-version bump is best-effort and only logged: it is a propagation hint for peers, and failing an otherwise-applied edit over it would be worse than a late peer update.
Types ¶
type AuditFilter ¶
AuditFilter specifies filters for audit log queries.
type HostFilter ¶
type HostFilter struct {
NetworkID string
Group string
Status models.HostStatus
// CAIDs scopes results to hosts under these CA ids. When non-empty the
// scope is applied in SQL, so it composes correctly with Limit — the
// limit applies after scoping, not before. Empty means no CA scoping.
CAIDs []string
Limit int // 0 = no limit
}
HostFilter specifies filters for listing hosts.
type MeshImportFinalizeHost ¶ added in v0.8.0
type MeshImportFinalizeInput ¶ added in v0.8.0
type SQLiteStore ¶
type SQLiteStore struct {
// contains filtered or unexported fields
}
SQLiteStore implements Store using SQLite.
func NewSQLiteStore ¶
func NewSQLiteStore(dbPath string, options ...SQLiteStoreOption) (*SQLiteStore, error)
NewSQLiteStore opens a SQLite database at the given path. Use ":memory:" for in-memory database.
func (*SQLiteStore) AcknowledgeHostConfigVersion ¶ added in v0.8.0
func (*SQLiteStore) AddAuditEntry ¶
func (s *SQLiteStore) AddAuditEntry(ctx context.Context, actor, action, resource, details string) error
func (*SQLiteStore) AddPopNonce ¶
func (s *SQLiteStore) AddPopNonce(ctx context.Context, hostID, nonce string, expiresAt time.Time) error
AddPopNonce records a (hostID, nonce) pair valid until expiresAt. Returns nil when the row was freshly inserted (or replaced an expired duplicate), and ErrReplayedNonce when a live duplicate exists. GHSA-v2jf-442r-6mjh.
The lazy DELETE prune clears any past-expiry rows; the subsequent INSERT OR IGNORE either lands fresh (RowsAffected == 1) or is swallowed by the (host_id, nonce) UNIQUE constraint (RowsAffected == 0 → replay). Both statements run inside a single transaction so the writer lock is acquired once per call instead of twice — matching the DELETE+INSERT shape used elsewhere in this package (e.g. CreateTokenForHost). SQLite's single-writer model linearizes concurrent same-key calls. expires_at is stored as unix-epoch INTEGER, so sub-second RFC3339 precision truncates down — harmless inside the ±5m skew that gates this call upstream.
func (*SQLiteStore) AddToBlocklist ¶
func (s *SQLiteStore) AddToBlocklist(ctx context.Context, fingerprint, hostID, reason string) error
func (*SQLiteStore) BlockHostAndAddToBlocklist ¶
func (s *SQLiteStore) BlockHostAndAddToBlocklist(ctx context.Context, id, reason string) (*models.Host, error)
BlockHostAndAddToBlocklist atomically blocks a host and adds its cert to the blocklist. Every network under the host CA is bumped whenever a fingerprint enters the blocklist so every peer under that CA receives a re-rendered config.yml carrying the new pki.blocklist entry (GHSA-cm26-5974-52h8). An additional bump for enrolled lighthouses is redundant — the single bump below already covers blocklist propagation — but the lighthouse-specific path is kept so peers also stop directing traffic at the blocked lighthouse.
func (*SQLiteStore) BumpNetworkConfigVersion ¶
func (s *SQLiteStore) BumpNetworkConfigVersion(ctx context.Context, networkID string) error
func (*SQLiteStore) CancelMeshImport ¶ added in v0.8.0
func (*SQLiteStore) ClearPendingRekey ¶
func (s *SQLiteStore) ClearPendingRekey(ctx context.Context, hostID string) error
ClearPendingRekey resets the pending_rekey flag, typically after the agent has redeemed the rekey token and the new keypair has been bound to the existing host row.
func (*SQLiteStore) ClearPrevFingerprint ¶
func (s *SQLiteStore) ClearPrevFingerprint(ctx context.Context, hostID string) error
ClearPrevFingerprint drops the rotation overlap state once the agent has successfully polled under the new fingerprint or the wall-clock window expired.
func (*SQLiteStore) ConsumeOperatorRecoveryCode ¶
func (s *SQLiteStore) ConsumeOperatorRecoveryCode(ctx context.Context, id, rawCode string) error
ConsumeOperatorRecoveryCode marks the given hash as consumed if it exists and is unused. Returns ErrNotFound otherwise.
func (*SQLiteStore) ConsumeOperatorTOTPTimestep ¶ added in v0.4.0
ConsumeOperatorTOTPTimestep advances the operator's last-accepted TOTP timestep to ts, but only if ts is strictly greater than the stored value — the same atomic verify-and-mark shape as ConsumeOperatorRecoveryCode, so two concurrent logins presenting the same code cannot both win. Returns ErrTOTPReplayed when ts has already been used (or an older one accepted after it), which the caller must treat as an authentication failure (RFC 6238 §5.2).
func (*SQLiteStore) ConsumeToken ¶
func (s *SQLiteStore) ConsumeToken(ctx context.Context, token string) (*models.EnrollmentToken, error)
ConsumeToken accepts the raw token from the caller, derives its keyed verifier, and marks the matching row used on success.
func (*SQLiteStore) ConsumeTokenAndEnrollHost ¶
func (s *SQLiteStore) ConsumeTokenAndEnrollHost(ctx context.Context, hostID, token string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
ConsumeTokenAndEnrollHost atomically consumes the single-use enrollment token and enrolls the host with its freshly-signed certificate in one transaction, so the token is marked used IFF the certificate is persisted and the host enrolled. A transient failure anywhere in the caller before this call (CA signing error, DB blip) therefore leaves the token usable for a clean retry, while a concurrent second enrollment racing the same token loses the used=0 CAS and receives ErrTokenUsed -- preserving single-use. This closes the burn-on-failure window left by consuming the token up front in its own transaction. The caller is expected to have validated the token via GetEnrollmentToken first, so a zero-row CAS here means the race was lost.
func (*SQLiteStore) ConsumeTokenAndEnrollHostWithProfile ¶ added in v0.8.0
func (s *SQLiteStore) ConsumeTokenAndEnrollHostWithProfile( ctx context.Context, hostID, token string, certPEM []byte, fp string, notBefore, notAfter time.Time, signingPubPEM string, profile models.AgentProfile, signedIdentity *models.CertificateIdentity, ) (int, error)
func (*SQLiteStore) CountEmptyCAIDRows ¶
func (s *SQLiteStore) CountEmptyCAIDRows(ctx context.Context) (int, error)
CountEmptyCAIDRows counts the total number of rows across networks, hosts, certificates, and blocklist tables that have an empty ca_id. This is used at startup to detect rows from the pre-multi-CA era that have not been backfilled with a CA owner.
func (*SQLiteStore) CreateHost ¶
func (*SQLiteStore) CreateHostAndToken ¶
func (s *SQLiteStore) CreateHostAndToken(ctx context.Context, h *models.Host, t *models.EnrollmentToken, rawToken string) error
CreateHostAndToken atomically creates a host and its enrollment token.
func (*SQLiteStore) CreateMeshImport ¶ added in v0.8.0
func (s *SQLiteStore) CreateMeshImport(ctx context.Context, item *models.MeshImport, rawToken string) error
func (*SQLiteStore) CreateMeshImportChallenge ¶ added in v0.8.0
func (s *SQLiteStore) CreateMeshImportChallenge(ctx context.Context, challenge *models.MeshImportChallenge, now time.Time) error
func (*SQLiteStore) CreateNetwork ¶
func (*SQLiteStore) CreateOperator ¶
CreateOperator inserts a new operator. Caller fills in PasswordHash.
func (*SQLiteStore) CreateOperatorAPIKey ¶
func (s *SQLiteStore) CreateOperatorAPIKey(ctx context.Context, k *models.OperatorAPIKey, rawKey string) error
func (*SQLiteStore) CreateOperatorSession ¶
func (s *SQLiteStore) CreateOperatorSession(ctx context.Context, sess *models.OperatorSession) error
func (*SQLiteStore) CreateToken ¶
func (s *SQLiteStore) CreateToken(ctx context.Context, t *models.EnrollmentToken, rawToken string) error
func (*SQLiteStore) CreateTokenForHost ¶
func (s *SQLiteStore) CreateTokenForHost(ctx context.Context, hostID, token string, expiresAt time.Time) error
CreateTokenForHost atomically invalidates any active enrollment tokens for the host and writes a fresh single-use one. Used by the regenerate-token, reenroll, and rekey flows (ADR 0004) where the host row must be preserved. The `token` argument is the raw value handed back to the caller; the store only ever persists its keyed verifier (SEC-CREDENTIAL-001).
func (*SQLiteStore) CreateWebhookSubscription ¶ added in v0.6.0
func (s *SQLiteStore) CreateWebhookSubscription(ctx context.Context, sub *models.WebhookSubscription) error
CreateWebhookSubscription inserts a new subscription.
func (*SQLiteStore) DB ¶
func (s *SQLiteStore) DB() *sql.DB
DB returns the underlying *sql.DB for advanced usage.
func (*SQLiteStore) DeleteCA ¶
func (s *SQLiteStore) DeleteCA(ctx context.Context, id string) error
DeleteCA removes a CA row. ca_id is a plain column on networks, hosts, certificates, and blocklist with no DB-level foreign key (it defaults to the empty string for pre-multi-CA rows), so referential integrity is enforced here: the call refuses while any of those tables still references the CA. Without checking all four, deleting a CA orphans rows whose ca_id no longer resolves, surfacing later as a silent failure in caForHost (ErrNotFound, then 500). Each table is checked independently because they can reference a CA in isolation, e.g. a blocklist row whose host was deleted via ON DELETE SET NULL, or a host whose ca_id diverged from its network's.
func (*SQLiteStore) DeleteExpiredOperatorSessions ¶
func (*SQLiteStore) DeleteHost ¶
func (s *SQLiteStore) DeleteHost(ctx context.Context, id string) error
func (*SQLiteStore) DeleteHostAndBlockCert ¶
func (s *SQLiteStore) DeleteHostAndBlockCert(ctx context.Context, id, reason string) error
DeleteHostAndBlockCert atomically deletes a host and adds its cert to the blocklist. Every network under the host CA is bumped whenever a fingerprint enters the blocklist so peers receive the updated pki.blocklist (GHSA-cm26-5974-52h8).
func (*SQLiteStore) DeleteOperatorSession ¶
func (s *SQLiteStore) DeleteOperatorSession(ctx context.Context, token string) error
func (*SQLiteStore) DeleteOperatorSessionsByOperator ¶
func (s *SQLiteStore) DeleteOperatorSessionsByOperator(ctx context.Context, operatorID string) error
func (*SQLiteStore) DeleteOperatorSessionsByOperatorExcept ¶ added in v0.7.0
func (s *SQLiteStore) DeleteOperatorSessionsByOperatorExcept(ctx context.Context, operatorID, keepToken string) error
DeleteOperatorSessionsByOperatorExcept removes every session of an operator except the one identified by keepToken, used by self-service password change to revoke other (possibly compromised) sessions while keeping the caller's current session alive (#259). keepToken is the raw cookie value; it is hashed here, mirroring DeleteOperatorSession.
func (*SQLiteStore) DeleteWebhookSubscription ¶ added in v0.6.0
func (s *SQLiteStore) DeleteWebhookSubscription(ctx context.Context, id string) error
DeleteWebhookSubscription removes a subscription.
func (*SQLiteStore) DisableOperator ¶
func (s *SQLiteStore) DisableOperator(ctx context.Context, id string) error
DisableOperator marks operator as disabled and atomically deletes their sessions and revokes all of their non-revoked API keys.
func (*SQLiteStore) EnableOperator ¶
func (s *SQLiteStore) EnableOperator(ctx context.Context, id string) error
func (*SQLiteStore) FinalizeMeshImport ¶ added in v0.8.0
func (s *SQLiteStore) FinalizeMeshImport(ctx context.Context, input MeshImportFinalizeInput) error
func (*SQLiteStore) FindCAByPredecessor ¶
func (*SQLiteStore) GetBlocklist ¶
func (s *SQLiteStore) GetBlocklist(ctx context.Context) ([]string, error)
func (*SQLiteStore) GetBlocklistForCA ¶ added in v0.3.8
GetBlocklistForCA returns the revoked fingerprints scoped to a single CA — the set an agent under that CA needs to reject peers, without leaking other operators' revocations across the tenant boundary (#203). Rows with an empty ca_id (legacy/orphan entries from before the column was populated, whose owning host is already deleted so the CA can't be recovered) are included as a fail-safe so revocation is never silently weakened.
func (*SQLiteStore) GetCAByFingerprint ¶
func (*SQLiteStore) GetCertAlert ¶
GetCertAlert returns the alerted_not_after recorded for hostID, or ErrNotFound when no alert has been recorded yet.
func (*SQLiteStore) GetCertificateInfo ¶
func (s *SQLiteStore) GetCertificateInfo(ctx context.Context, hostID string) (*models.CertificateInfo, error)
func (*SQLiteStore) GetCurrentCertificate ¶
func (*SQLiteStore) GetEnrollmentToken ¶
func (s *SQLiteStore) GetEnrollmentToken(ctx context.Context, token string) (*models.EnrollmentToken, error)
GetEnrollmentToken resolves a raw enrollment token by its keyed verifier WITHOUT consuming it, applying the same validity checks as ConsumeToken (ErrNotFound / ErrTokenUsed / ErrTokenExpired). It lets the enrollment handler resolve the target host and fail fast before the expensive CA signature; the actual single-use consume then happens atomically with the certificate save in ConsumeTokenAndEnrollHost.
func (*SQLiteStore) GetHostAgentProfile ¶ added in v0.8.0
func (s *SQLiteStore) GetHostAgentProfile(ctx context.Context, hostID string) (*models.HostAgentProfile, error)
func (*SQLiteStore) GetHostByFingerprint ¶
func (s *SQLiteStore) GetHostByFingerprint(ctx context.Context, fingerprint string) (*models.Host, error)
GetHostByFingerprint resolves the host by either its current or previous cert fingerprint. The previous-fingerprint match window exists so cert auto-rotation does not lock the agent out between server-side cert update and on-disk cert write (ADR 0004 §7.1 cert rotation overlap).
The returned host's CertFingerprint always reflects the row's current value; callers that need to know which fingerprint matched can compare against the input.
func (*SQLiteStore) GetHostConfigVersion ¶
func (*SQLiteStore) GetMeshImport ¶ added in v0.8.0
func (s *SQLiteStore) GetMeshImport(ctx context.Context, id string) (*models.MeshImport, error)
func (*SQLiteStore) GetMeshImportByToken ¶ added in v0.12.0
func (s *SQLiteStore) GetMeshImportByToken(ctx context.Context, rawToken string, now time.Time) (*models.MeshImport, error)
func (*SQLiteStore) GetMeshImportChallenge ¶ added in v0.8.0
func (s *SQLiteStore) GetMeshImportChallenge(ctx context.Context, id string) (*models.MeshImportChallenge, error)
func (*SQLiteStore) GetMeshImportTombstone ¶ added in v0.8.0
func (s *SQLiteStore) GetMeshImportTombstone(ctx context.Context, fingerprint string) (*models.MeshImportTombstone, error)
func (*SQLiteStore) GetNetwork ¶
func (*SQLiteStore) GetNetworkConfig ¶
func (*SQLiteStore) GetNetworkConfigVersion ¶
func (*SQLiteStore) GetOperator ¶
func (*SQLiteStore) GetOperatorAPIKey ¶
func (s *SQLiteStore) GetOperatorAPIKey(ctx context.Context, keyID string) (*models.OperatorAPIKey, error)
GetOperatorAPIKey returns the API key by its ID regardless of revoked state. Callers that need ownership verification compare the returned .OperatorID against the expected operator.
func (*SQLiteStore) GetOperatorByAPIKey ¶ added in v0.12.0
func (s *SQLiteStore) GetOperatorByAPIKey(ctx context.Context, rawKey string) (*models.Operator, *models.OperatorAPIKey, error)
GetOperatorByAPIKey returns the operator associated with a non-revoked raw API key, ensuring the operator is active.
func (*SQLiteStore) GetOperatorByOIDC ¶
func (s *SQLiteStore) GetOperatorByOIDC(ctx context.Context, issuer, subject string) (*models.Operator, error)
GetOperatorByOIDC returns the operator matching the issuer+subject pair, if any. Used to look up federated operators after a successful OIDC callback.
func (*SQLiteStore) GetOperatorBySession ¶
func (s *SQLiteStore) GetOperatorBySession(ctx context.Context, token string) (*models.Operator, error)
GetOperatorBySession returns the operator associated with a non-expired, fully-authenticated session whose operator is still active. Sessions in pending_totp state are NOT returned here.
func (*SQLiteStore) GetOperatorByUsername ¶
func (*SQLiteStore) GetPendingTwoFactorOperator ¶
func (s *SQLiteStore) GetPendingTwoFactorOperator(ctx context.Context, token string) (*models.Operator, error)
GetPendingTwoFactorOperator returns the operator associated with a session that is awaiting a second factor (`pending_totp`). The operator must still be active. Sessions already authenticated are not returned.
func (*SQLiteStore) GetServerSetting ¶
GetServerSetting returns the stored value for key, or "" + ErrNotFound when the key has never been set.
func (*SQLiteStore) GetWebhookSubscription ¶ added in v0.6.0
func (s *SQLiteStore) GetWebhookSubscription(ctx context.Context, id string) (*models.WebhookSubscription, error)
GetWebhookSubscription returns one subscription by id.
func (*SQLiteStore) ListActiveWebhookSubscriptionsForCA ¶ added in v0.8.0
func (s *SQLiteStore) ListActiveWebhookSubscriptionsForCA(ctx context.Context, caID string) ([]*models.WebhookSubscription, error)
ListActiveWebhookSubscriptionsForCA returns active subscriptions owned by the operator that owns caID. An unknown or empty CA id matches no owner.
func (*SQLiteStore) ListAuditEntries ¶
func (s *SQLiteStore) ListAuditEntries(ctx context.Context, filter AuditFilter) ([]*models.AuditEntry, error)
func (*SQLiteStore) ListCAsApproachingExpiry ¶
func (*SQLiteStore) ListCAsByOwner ¶
func (*SQLiteStore) ListEnrolledHostCerts ¶
func (s *SQLiteStore) ListEnrolledHostCerts(ctx context.Context) ([]*models.CertificateInfo, error)
func (*SQLiteStore) ListHosts ¶
func (s *SQLiteStore) ListHosts(ctx context.Context, filter HostFilter) ([]*models.Host, error)
func (*SQLiteStore) ListMeshImportSnapshots ¶ added in v0.8.0
func (s *SQLiteStore) ListMeshImportSnapshots(ctx context.Context, meshImportID string) ([]*models.MeshImportSnapshot, error)
func (*SQLiteStore) ListMeshImports ¶ added in v0.8.0
func (s *SQLiteStore) ListMeshImports(ctx context.Context) ([]*models.MeshImport, error)
func (*SQLiteStore) ListMeshImportsByOwner ¶ added in v0.8.0
func (s *SQLiteStore) ListMeshImportsByOwner(ctx context.Context, ownerID string) ([]*models.MeshImport, error)
func (*SQLiteStore) ListNetworks ¶
func (*SQLiteStore) ListOperatorAPIKeys ¶
func (s *SQLiteStore) ListOperatorAPIKeys(ctx context.Context, operatorID string) ([]*models.OperatorAPIKey, error)
func (*SQLiteStore) ListOperatorRecoveryCodes ¶
ListOperatorRecoveryCodes returns the hashes of all non-consumed recovery codes for the operator. Used by tests and integrity checks.
func (*SQLiteStore) ListOperators ¶
func (*SQLiteStore) ListWebhookSubscriptions ¶ added in v0.6.0
func (s *SQLiteStore) ListWebhookSubscriptions(ctx context.Context) ([]*models.WebhookSubscription, error)
ListWebhookSubscriptions returns every subscription (admin view).
func (*SQLiteStore) ListWebhookSubscriptionsByOwner ¶ added in v0.6.0
func (s *SQLiteStore) ListWebhookSubscriptionsByOwner(ctx context.Context, ownerID string) ([]*models.WebhookSubscription, error)
ListWebhookSubscriptionsByOwner returns subscriptions owned by ownerID.
func (*SQLiteStore) Migrate ¶
func (s *SQLiteStore) Migrate(ctx context.Context) error
Migrate applies all pending migrations. Each migration file is executed at most once per database — its name is recorded in `schema_migrations` once applied. This fixes two latent issues:
- Destructive recreate-style migrations (e.g. 004_blocklist_fk, which rebuilds `blocklist` via blocklist_new + RENAME) used to run on every start, silently dropping columns that later migrations had added.
- Multi-statement migration files used to be Exec'd as one string; `modernc.org/sqlite` stops processing the remainder of the blob on the first error (e.g. a duplicate-column ALTER), so the trailing statements were skipped. We now split each file by top-level `;` boundaries and Exec one statement at a time.
See https://github.com/forgekeep/nebula-mesh/issues/37.
The entire run is pinned to a single pooled connection. PRAGMA foreign_keys is connection-scoped, and migration 014 turns it OFF, drops and recreates tables, then turns it back ON across separate statements — if those statements were dispatched to different pool connections (every connection opens with foreign_keys ON via the DSN), the DROP TABLE would run with FK enforcement live and cascade-delete every child row (certificates, host_addresses, enrollment_tokens, cert_alerts).
func (*SQLiteStore) Ping ¶
func (s *SQLiteStore) Ping(ctx context.Context) error
Ping verifies the database connection is alive.
func (*SQLiteStore) PromoteOperatorSession ¶
func (s *SQLiteStore) PromoteOperatorSession(ctx context.Context, token string, newExpiry time.Time) error
PromoteOperatorSession upgrades a pending_totp session to authenticated and resets the expiry to a fresh 24h window. Returns ErrNotFound if the session does not exist or is not pending.
func (*SQLiteStore) RecordCertAlert ¶
func (s *SQLiteStore) RecordCertAlert(ctx context.Context, hostID string, alertedNotAfter time.Time) error
RecordCertAlert upserts the (host_id, alerted_not_after) tuple so subsequent scans for the same cert do not re-emit the alert. Update alerted_at to now on every call so dashboards can show "last fired" times.
func (*SQLiteStore) RecordFailedLoginAttempt ¶ added in v0.7.0
func (s *SQLiteStore) RecordFailedLoginAttempt(ctx context.Context, id string, maxAttempts int, lockUntil time.Time) (bool, error)
RecordFailedLoginAttempt increments the operator's consecutive failed-login counter and, when the count reaches maxAttempts, sets locked_until to lockUntil — atomically in one UPDATE so concurrent failures can't race past the threshold (#263). It reports whether the account is now locked.
func (*SQLiteStore) RecordWebhookDelivery ¶ added in v0.6.0
func (s *SQLiteStore) RecordWebhookDelivery(ctx context.Context, id string, ok bool, errMsg string, at time.Time) error
RecordWebhookDelivery updates a subscription's delivery-status columns after an attempt. On success it clears the failure counter and error; on failure it increments the counter and stores the (truncated) error.
func (*SQLiteStore) RegisterImportedHost ¶ added in v0.8.0
func (s *SQLiteStore) RegisterImportedHost(ctx context.Context, registration *models.MeshImportRegistration, now time.Time) (*models.MeshImportRegistrationResult, error)
func (*SQLiteStore) RemoveFromBlocklist ¶
func (s *SQLiteStore) RemoveFromBlocklist(ctx context.Context, fingerprint string) error
func (*SQLiteStore) ReplaceOperatorRecoveryCodes ¶
func (s *SQLiteStore) ReplaceOperatorRecoveryCodes(ctx context.Context, id string, rawCodes []string) error
ReplaceOperatorRecoveryCodes deletes any existing codes for the operator and inserts the provided list of hashes (atomic).
func (*SQLiteStore) ResetFailedLoginAttempts ¶ added in v0.7.0
func (s *SQLiteStore) ResetFailedLoginAttempts(ctx context.Context, id string) error
ResetFailedLoginAttempts clears the failed-login counter and any active lock, called on a successful login and when an expired lock is observed (#263).
func (*SQLiteStore) ResetOperatorTOTPBreakGlass ¶ added in v0.12.0
func (s *SQLiteStore) ResetOperatorTOTPBreakGlass(ctx context.Context, username string) error
ResetOperatorTOTPBreakGlass disables TOTP for one operator, removes its recovery codes and sessions, and records the local recovery action in the same transaction. The operator status is deliberately unchanged.
func (*SQLiteStore) RevokeOperatorAPIKey ¶
func (s *SQLiteStore) RevokeOperatorAPIKey(ctx context.Context, keyID string) error
func (*SQLiteStore) RotateMeshImportToken ¶ added in v0.8.0
func (*SQLiteStore) SaveCertificate ¶
func (*SQLiteStore) SaveCertificateAndEnrollHost ¶
func (s *SQLiteStore) SaveCertificateAndEnrollHost(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
SaveCertificateAndEnrollHost atomically saves a certificate and marks the host as enrolled. Used by token-less enrollment paths (e.g. mobile-bundle generation). The agent token flow uses ConsumeTokenAndEnrollHost, which folds the single-use token consume into the same transaction.
func (*SQLiteStore) SaveCertificateAndUpdateHostCert ¶
func (s *SQLiteStore) SaveCertificateAndUpdateHostCert(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
SaveCertificateAndUpdateHostCert atomically saves a certificate and updates the host's cert metadata. The previous fingerprint (if non-empty) is parked in prev_cert_fingerprint with cert_rotated_at = now() so the poll handler can accept either fingerprint during the rotation overlap window (ADR 0004 §7.1).
func (*SQLiteStore) SaveCertificateIfIssuanceAllowed ¶ added in v0.9.0
func (s *SQLiteStore) SaveCertificateIfIssuanceAllowed( ctx context.Context, hostID string, expectedStatus models.HostStatus, certPEM []byte, fp string, notBefore, notAfter time.Time, ) error
SaveCertificateIfIssuanceAllowed atomically re-checks durable Host and owner state and persists a mobile certificate only when both still authorize the transition. expectedStatus prevents a stale builder from changing a Host whose lifecycle state changed while the bundle was being rendered.
func (*SQLiteStore) SeedInitialAdminOperator ¶
func (s *SQLiteStore) SeedInitialAdminOperator(ctx context.Context, op *models.Operator, key *models.OperatorAPIKey, rawKey string) (bool, error)
SeedInitialAdminOperator atomically inserts op (and key, if non-nil) only when the operators table is empty. The check-then-write is wrapped in a single transaction whose INSERT is guarded by `WHERE NOT EXISTS (SELECT 1 FROM operators)`, so two concurrent first-boot seed calls cannot both succeed: the loser sees `RowsAffected() == 0` and returns (false, nil) without touching the API-key table.
Returns (true, nil) if this call performed the seed; (false, nil) if the operators table already had at least one row (either because the caller ran a second time on a populated DB, or because a concurrent boot won the race). Any non-nil error indicates a real failure.
func (*SQLiteStore) SetNetworkConfig ¶
func (s *SQLiteStore) SetNetworkConfig(ctx context.Context, networkID, key, value string) error
func (*SQLiteStore) SetNetworkConfigAndBumpVersion ¶
func (s *SQLiteStore) SetNetworkConfigAndBumpVersion(ctx context.Context, networkID, key, value string) error
SetNetworkConfigAndBumpVersion atomically sets a config value and bumps the config version.
func (*SQLiteStore) SetOperatorTOTP ¶
SetOperatorTOTP records the operator's TOTP secret and enabled flag. Passing enabled=false with secret="" clears 2FA entirely.
func (*SQLiteStore) SetPendingHostConfigVersion ¶ added in v0.8.0
func (*SQLiteStore) SetPendingRekey ¶
func (s *SQLiteStore) SetPendingRekey(ctx context.Context, hostID string) error
SetPendingRekey flips the pending_rekey flag atomically. If the flag is already set on this host the call returns ErrRekeyAlreadyPending so a duplicate force-rotate request can be rejected with 409.
func (*SQLiteStore) SetPrevFingerprint ¶
func (s *SQLiteStore) SetPrevFingerprint(ctx context.Context, hostID, prev string, rotatedAt time.Time) error
SetPrevFingerprint records the previous cert fingerprint and the rotation timestamp on the host row. Called from SaveCertificateAndUpdateHostCert before the new fingerprint is written so the overlap window is preserved.
func (*SQLiteStore) SetServerSetting ¶
func (s *SQLiteStore) SetServerSetting(ctx context.Context, key, value string) error
SetServerSetting upserts a key/value pair into server_settings.
func (*SQLiteStore) TouchOperatorAPIKey ¶
func (*SQLiteStore) UnblockHostAndRemoveFromBlocklist ¶
func (s *SQLiteStore) UnblockHostAndRemoveFromBlocklist(ctx context.Context, id string) (*models.Host, error)
UnblockHostAndRemoveFromBlocklist atomically marks a blocked host as pending and removes its certificate fingerprint from the blocklist. The host must re-enroll to obtain a new certificate after unblocking.
func (*SQLiteStore) UpdateCAStatus ¶
func (*SQLiteStore) UpdateHost ¶
UpdateHost persists all host fields. NOTE: mutates h.UpdatedAt to current time.
func (*SQLiteStore) UpdateHostCert ¶
func (*SQLiteStore) UpdateHostConfigVersion ¶
func (*SQLiteStore) UpdateHostLastSeen ¶
func (*SQLiteStore) UpdateHostSigningPub ¶
func (s *SQLiteStore) UpdateHostSigningPub(ctx context.Context, hostID, signingPubPEM string) error
UpdateHostSigningPub stores the Ed25519 PEM public key bound to the host's signing identity at enrollment / re-enrollment time.
func (*SQLiteStore) UpdateHostStatus ¶
func (s *SQLiteStore) UpdateHostStatus(ctx context.Context, id string, status models.HostStatus) error
func (*SQLiteStore) UpdateNetwork ¶
func (*SQLiteStore) UpdateOperatorLastLogin ¶
func (*SQLiteStore) UpdateOperatorPassword ¶
func (s *SQLiteStore) UpdateOperatorPassword(ctx context.Context, id, passwordHash string) error
func (*SQLiteStore) UpdateWebhookSubscription ¶ added in v0.6.0
func (s *SQLiteStore) UpdateWebhookSubscription(ctx context.Context, sub *models.WebhookSubscription) error
UpdateWebhookSubscription writes the mutable fields (url, events, active, allow_private, secret envelope) and bumps updated_at. Delivery-status columns are left to RecordWebhookDelivery.
type SQLiteStoreOption ¶ added in v0.12.0
type SQLiteStoreOption func(*SQLiteStore)
SQLiteStoreOption configures a SQLiteStore.
func WithCredentialCutoverGuard ¶ added in v0.12.0
func WithCredentialCutoverGuard(guard func(context.Context, *SQLiteStore) error) SQLiteStoreOption
WithCredentialCutoverGuard verifies that the configured master key can decrypt persisted CA material before migration 027 destroys legacy credential verifiers.
func WithCredentialHasher ¶ added in v0.12.0
func WithCredentialHasher(hasher *credentialhash.Hasher) SQLiteStoreOption
WithCredentialHasher configures the HMAC boundary for persisted credentials.
type Store ¶
type Store interface {
// CAs
CreateCA(ctx context.Context, c *models.CA) error
GetCA(ctx context.Context, id string) (*models.CA, error)
GetCAByFingerprint(ctx context.Context, fp string) (*models.CA, error)
ListCAs(ctx context.Context) ([]*models.CA, error)
ListCAsByOwner(ctx context.Context, ownerID string) ([]*models.CA, error)
ListCAsApproachingExpiry(ctx context.Context, thresholdRatio float64) ([]*models.CA, error)
FindCAByPredecessor(ctx context.Context, predecessorID string) (*models.CA, error)
UpdateCAStatus(ctx context.Context, id string, status models.CAStatus) error
DeleteCA(ctx context.Context, id string) error
// Webhook subscriptions
CreateWebhookSubscription(ctx context.Context, sub *models.WebhookSubscription) error
GetWebhookSubscription(ctx context.Context, id string) (*models.WebhookSubscription, error)
ListWebhookSubscriptions(ctx context.Context) ([]*models.WebhookSubscription, error)
ListWebhookSubscriptionsByOwner(ctx context.Context, ownerID string) ([]*models.WebhookSubscription, error)
ListActiveWebhookSubscriptionsForCA(ctx context.Context, caID string) ([]*models.WebhookSubscription, error)
UpdateWebhookSubscription(ctx context.Context, sub *models.WebhookSubscription) error
DeleteWebhookSubscription(ctx context.Context, id string) error
RecordWebhookDelivery(ctx context.Context, id string, ok bool, errMsg string, at time.Time) error
// Networks
CreateNetwork(ctx context.Context, n *models.Network) error
GetNetwork(ctx context.Context, id string) (*models.Network, error)
ListNetworks(ctx context.Context) ([]*models.Network, error)
UpdateNetwork(ctx context.Context, n *models.Network) error
// Existing mesh adoption.
CreateMeshImport(ctx context.Context, item *models.MeshImport, rawToken string) error
GetMeshImport(ctx context.Context, id string) (*models.MeshImport, error)
GetMeshImportByToken(ctx context.Context, rawToken string, now time.Time) (*models.MeshImport, error)
ListMeshImports(ctx context.Context) ([]*models.MeshImport, error)
ListMeshImportsByOwner(ctx context.Context, ownerID string) ([]*models.MeshImport, error)
RotateMeshImportToken(ctx context.Context, id, rawToken string, expiresAt, now time.Time) error
CancelMeshImport(ctx context.Context, id, reason string, now time.Time) error
CreateMeshImportChallenge(ctx context.Context, challenge *models.MeshImportChallenge, now time.Time) error
GetMeshImportChallenge(ctx context.Context, id string) (*models.MeshImportChallenge, error)
RegisterImportedHost(ctx context.Context, registration *models.MeshImportRegistration, now time.Time) (*models.MeshImportRegistrationResult, error)
ListMeshImportSnapshots(ctx context.Context, meshImportID string) ([]*models.MeshImportSnapshot, error)
FinalizeMeshImport(ctx context.Context, input MeshImportFinalizeInput) error
GetHostAgentProfile(ctx context.Context, hostID string) (*models.HostAgentProfile, error)
SetPendingHostConfigVersion(ctx context.Context, hostID string, version int) error
AcknowledgeHostConfigVersion(ctx context.Context, hostID string, version int) error
GetMeshImportTombstone(ctx context.Context, fingerprint string) (*models.MeshImportTombstone, error)
// Hosts
CreateHost(ctx context.Context, h *models.Host) error
GetHost(ctx context.Context, id string) (*models.Host, error)
GetHostByFingerprint(ctx context.Context, fingerprint string) (*models.Host, error)
ListHosts(ctx context.Context, filter HostFilter) ([]*models.Host, error)
// UpdateHost persists the host row and atomically resets its
// config_version to 0 in the same transaction (SEC-PERSIST-001), so the
// agent re-renders its config on the next poll.
UpdateHost(ctx context.Context, h *models.Host) error
UpdateHostLastSeen(ctx context.Context, id string, t time.Time) error
UpdateHostCert(ctx context.Context, id, fingerprint string, expiresAt time.Time) error
UpdateHostStatus(ctx context.Context, id string, status models.HostStatus) error
DeleteHost(ctx context.Context, id string) error
BlockHostAndAddToBlocklist(ctx context.Context, id, reason string) (*models.Host, error)
UnblockHostAndRemoveFromBlocklist(ctx context.Context, id string) (*models.Host, error)
DeleteHostAndBlockCert(ctx context.Context, id, reason string) error
// Agent authorization (ADR 0004 / #75).
//
// SetPrevFingerprint records the prior cert fingerprint and the time of
// rotation; SaveCertificateAndUpdateHostCert is the natural caller.
// ClearPrevFingerprint drops the overlap window once the agent has
// successfully polled under the new fingerprint.
//
// SetPendingRekey is a compare-and-swap that succeeds only when the host
// is not already mid-rekey; the second concurrent call returns
// ErrRekeyAlreadyPending so the API layer can answer 409.
SetPrevFingerprint(ctx context.Context, hostID, prev string, rotatedAt time.Time) error
ClearPrevFingerprint(ctx context.Context, hostID string) error
SetPendingRekey(ctx context.Context, hostID string) error
ClearPendingRekey(ctx context.Context, hostID string) error
UpdateHostSigningPub(ctx context.Context, hostID, signingPubPEM string) error
// AddPopNonce records a (hostID, nonce) pair valid until expiresAt.
// Returns nil when the row was freshly inserted (or replaced an expired
// duplicate); returns ErrReplayedNonce when a live duplicate exists.
// Rows past expiresAt are pruned lazily on the next call; callers must
// not infer freshness from the row's age alone. GHSA-v2jf-442r-6mjh.
AddPopNonce(ctx context.Context, hostID, nonce string, expiresAt time.Time) error
// Enrollment tokens
CreateHostAndToken(ctx context.Context, h *models.Host, t *models.EnrollmentToken, rawToken string) error
CreateToken(ctx context.Context, t *models.EnrollmentToken, rawToken string) error
CreateTokenForHost(ctx context.Context, hostID, token string, expiresAt time.Time) error
ConsumeToken(ctx context.Context, token string) (*models.EnrollmentToken, error)
GetEnrollmentToken(ctx context.Context, token string) (*models.EnrollmentToken, error)
// Certificates
SaveCertificate(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
SaveCertificateAndEnrollHost(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
SaveCertificateIfIssuanceAllowed(ctx context.Context, hostID string, expectedStatus models.HostStatus, certPEM []byte, fp string, notBefore, notAfter time.Time) error
ConsumeTokenAndEnrollHost(ctx context.Context, hostID, token string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
// ConsumeTokenAndEnrollHostWithProfile atomically binds an enrollment to a
// signed certificate identity snapshot. If Name, NebulaIPs, or Groups changed after
// signing, the transaction keeps pending_rekey set so a stale certificate is
// never treated as satisfying the newer identity.
ConsumeTokenAndEnrollHostWithProfile(ctx context.Context, hostID, token string, certPEM []byte, fp string, notBefore, notAfter time.Time, signingPubPEM string, profile models.AgentProfile, signedIdentity *models.CertificateIdentity) (int, error)
SaveCertificateAndUpdateHostCert(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
GetCurrentCertificate(ctx context.Context, hostID string) ([]byte, error)
GetCertificateInfo(ctx context.Context, hostID string) (*models.CertificateInfo, error)
ListEnrolledHostCerts(ctx context.Context) ([]*models.CertificateInfo, error)
// Blocklist
AddToBlocklist(ctx context.Context, fingerprint, hostID, reason string) error
RemoveFromBlocklist(ctx context.Context, fingerprint string) error
GetBlocklist(ctx context.Context) ([]string, error)
GetBlocklistForCA(ctx context.Context, caID string) ([]string, error)
// Config versioning
BumpNetworkConfigVersion(ctx context.Context, networkID string) error
GetNetworkConfigVersion(ctx context.Context, networkID string) (int, error)
GetHostConfigVersion(ctx context.Context, hostID string) (int, error)
UpdateHostConfigVersion(ctx context.Context, hostID string, version int) error
// Network config (key-value)
GetNetworkConfig(ctx context.Context, networkID, key string) (string, error)
SetNetworkConfig(ctx context.Context, networkID, key, value string) error
SetNetworkConfigAndBumpVersion(ctx context.Context, networkID, key, value string) error
// Audit log
AddAuditEntry(ctx context.Context, actor, action, resource, details string) error
ListAuditEntries(ctx context.Context, filter AuditFilter) ([]*models.AuditEntry, error)
// Cert-expiry alert dedup state. RecordCertAlert remembers that an
// alert was emitted for the given host whose current cert expires at
// alertedNotAfter; GetCertAlert returns the previously alerted
// not_after, or ErrNotFound if no alert has been recorded yet.
RecordCertAlert(ctx context.Context, hostID string, alertedNotAfter time.Time) error
GetCertAlert(ctx context.Context, hostID string) (time.Time, error)
// Server-wide key/value settings (e.g. enforce_2fa). Empty string is
// returned when the key has never been set — callers convert to typed
// defaults via the helpers in the consuming package.
GetServerSetting(ctx context.Context, key string) (string, error)
SetServerSetting(ctx context.Context, key, value string) error
// Operators
CreateOperator(ctx context.Context, op *models.Operator) error
// SeedInitialAdminOperator atomically inserts op (and optionally key,
// when key is non-nil) only if the operators table is empty. Returns
// (true, nil) when this call performed the seed, (false, nil) when
// another caller already populated the table. The check + insert run
// in a single transaction, so concurrent boots cannot both seed.
SeedInitialAdminOperator(ctx context.Context, op *models.Operator, key *models.OperatorAPIKey, rawKey string) (bool, error)
GetOperator(ctx context.Context, id string) (*models.Operator, error)
GetOperatorByUsername(ctx context.Context, username string) (*models.Operator, error)
GetOperatorByOIDC(ctx context.Context, issuer, subject string) (*models.Operator, error)
ListOperators(ctx context.Context) ([]*models.Operator, error)
UpdateOperatorPassword(ctx context.Context, id, passwordHash string) error
UpdateOperatorLastLogin(ctx context.Context, id string, t time.Time) error
RecordFailedLoginAttempt(ctx context.Context, id string, maxAttempts int, lockUntil time.Time) (bool, error)
ResetFailedLoginAttempts(ctx context.Context, id string) error
DisableOperator(ctx context.Context, id string) error
EnableOperator(ctx context.Context, id string) error
// Operator TOTP / recovery codes
SetOperatorTOTP(ctx context.Context, id, secret string, enabled bool) error
// ConsumeOperatorTOTPTimestep atomically records the TOTP timestep a
// code was accepted at, rejecting (ErrTOTPReplayed) any timestep at or
// below the last accepted one so an observed code cannot be replayed
// within its validity window (RFC 6238 §5.2).
ConsumeOperatorTOTPTimestep(ctx context.Context, id string, ts int64) error
ReplaceOperatorRecoveryCodes(ctx context.Context, id string, rawCodes []string) error
ConsumeOperatorRecoveryCode(ctx context.Context, id, rawCode string) error
ListOperatorRecoveryCodes(ctx context.Context, id string) ([]string, error)
ResetOperatorTOTPBreakGlass(ctx context.Context, username string) error
// Operator API keys
CreateOperatorAPIKey(ctx context.Context, k *models.OperatorAPIKey, rawKey string) error
GetOperatorAPIKey(ctx context.Context, keyID string) (*models.OperatorAPIKey, error)
GetOperatorByAPIKey(ctx context.Context, rawKey string) (*models.Operator, *models.OperatorAPIKey, error)
ListOperatorAPIKeys(ctx context.Context, operatorID string) ([]*models.OperatorAPIKey, error)
RevokeOperatorAPIKey(ctx context.Context, keyID string) error
TouchOperatorAPIKey(ctx context.Context, keyID string, t time.Time) error
// Operator sessions
CreateOperatorSession(ctx context.Context, s *models.OperatorSession) error
GetOperatorBySession(ctx context.Context, token string) (*models.Operator, error)
GetPendingTwoFactorOperator(ctx context.Context, token string) (*models.Operator, error)
PromoteOperatorSession(ctx context.Context, token string, newExpiry time.Time) error
DeleteOperatorSession(ctx context.Context, token string) error
DeleteOperatorSessionsByOperator(ctx context.Context, operatorID string) error
DeleteOperatorSessionsByOperatorExcept(ctx context.Context, operatorID, keepToken string) error
DeleteExpiredOperatorSessions(ctx context.Context, before time.Time) error
// Lifecycle
Migrate(ctx context.Context) error
Ping(ctx context.Context) error
Close() error
}
Store defines the persistence interface for the management server.