Documentation
¶
Index ¶
- Constants
- Variables
- func AckFingerprint(cluster, scanner, title string) string
- func GenerateToken() (string, error)
- func HashToken(raw string) string
- func TokensEqual(a, b string) bool
- func ValidRole(r string) bool
- type APIKeyRecord
- type AckRecord
- type AlertListOptions
- type AlertRecord
- type AuditEntry
- type AuditListOptions
- type ClusterRecord
- type Driver
- type GroupRecord
- type LocationRecord
- type Postgres
- func (p *Postgres) AddClusterToGroup(ctx context.Context, group, cluster string) error
- func (p *Postgres) Close() error
- func (p *Postgres) DeleteAck(ctx context.Context, fingerprint string) error
- func (p *Postgres) DeleteClusterTag(ctx context.Context, cluster, key string) error
- func (p *Postgres) DeleteGroup(ctx context.Context, name string) error
- func (p *Postgres) DeleteLocation(ctx context.Context, cluster string) error
- func (p *Postgres) GetAPIKey(ctx context.Context, id string) (*APIKeyRecord, error)
- func (p *Postgres) GetAPIKeyByHash(ctx context.Context, hash string) (*APIKeyRecord, error)
- func (p *Postgres) GetAlert(ctx context.Context, fingerprint string) (*AlertRecord, error)
- func (p *Postgres) GetClusterHistory(ctx context.Context, cluster string, limit int) ([]ScanResultRecord, error)
- func (p *Postgres) GetClusterTags(ctx context.Context, cluster string) (map[string]string, error)
- func (p *Postgres) GetGroup(ctx context.Context, name string) (*GroupRecord, error)
- func (p *Postgres) GetLocation(ctx context.Context, cluster string) (*LocationRecord, error)
- func (p *Postgres) GetScan(ctx context.Context, id string) (*ScanRecord, error)
- func (p *Postgres) GetScanResults(ctx context.Context, scanID string) (map[string]map[string]scanner.Result, error)
- func (p *Postgres) GetScansByTimeRange(ctx context.Context, start, end time.Time) ([]ScanRecord, error)
- func (p *Postgres) IsAcked(ctx context.Context, fingerprint string) (bool, error)
- func (p *Postgres) ListAPIKeys(ctx context.Context) ([]APIKeyRecord, error)
- func (p *Postgres) ListAcks(ctx context.Context) ([]AckRecord, error)
- func (p *Postgres) ListAlerts(ctx context.Context, opts AlertListOptions) ([]AlertRecord, error)
- func (p *Postgres) ListAuditEntries(ctx context.Context, opts AuditListOptions) ([]AuditEntry, error)
- func (p *Postgres) ListClusterTags(ctx context.Context) (map[string]map[string]string, error)
- func (p *Postgres) ListClusters(ctx context.Context) ([]ClusterRecord, error)
- func (p *Postgres) ListGroups(ctx context.Context) ([]GroupRecord, error)
- func (p *Postgres) ListLocations(ctx context.Context) ([]LocationRecord, error)
- func (p *Postgres) ListScans(ctx context.Context, limit int) ([]ScanRecord, error)
- func (p *Postgres) Ping(ctx context.Context) error
- func (p *Postgres) Prune(ctx context.Context, cutoff time.Time) (int, error)
- func (p *Postgres) PruneAlerts(ctx context.Context, cutoff time.Time) (int, error)
- func (p *Postgres) PruneAuditEntries(ctx context.Context, cutoff time.Time) (int, error)
- func (p *Postgres) RemoveClusterFromGroup(ctx context.Context, group, cluster string) error
- func (p *Postgres) RevokeAPIKey(ctx context.Context, id string) error
- func (p *Postgres) SaveAPIKey(ctx context.Context, rec APIKeyRecord) error
- func (p *Postgres) SaveAck(ctx context.Context, rec AckRecord) error
- func (p *Postgres) SaveAuditEntry(ctx context.Context, rec AuditEntry) error
- func (p *Postgres) SaveGroup(ctx context.Context, name string, clusters []string) error
- func (p *Postgres) SaveScan(ctx context.Context, clusters []string, ...) (string, error)
- func (p *Postgres) SetClusterTag(ctx context.Context, cluster, key, value string) error
- func (p *Postgres) SetLocation(ctx context.Context, loc LocationRecord) error
- func (p *Postgres) TouchAPIKey(ctx context.Context, id string, at time.Time) error
- func (p *Postgres) UpsertAlert(ctx context.Context, rec AlertRecord) error
- func (p *Postgres) Vacuum(_ context.Context) error
- type SQLite
- func (s *SQLite) AddClusterToGroup(ctx context.Context, group, cluster string) error
- func (s *SQLite) Close() error
- func (s *SQLite) DeleteAck(ctx context.Context, fingerprint string) error
- func (s *SQLite) DeleteClusterTag(ctx context.Context, cluster, key string) error
- func (s *SQLite) DeleteGroup(ctx context.Context, name string) error
- func (s *SQLite) DeleteLocation(ctx context.Context, cluster string) error
- func (s *SQLite) GetAPIKey(ctx context.Context, id string) (*APIKeyRecord, error)
- func (s *SQLite) GetAPIKeyByHash(ctx context.Context, hash string) (*APIKeyRecord, error)
- func (s *SQLite) GetAlert(ctx context.Context, fingerprint string) (*AlertRecord, error)
- func (s *SQLite) GetClusterHistory(ctx context.Context, cluster string, limit int) ([]ScanResultRecord, error)
- func (s *SQLite) GetClusterTags(ctx context.Context, cluster string) (map[string]string, error)
- func (s *SQLite) GetGroup(ctx context.Context, name string) (*GroupRecord, error)
- func (s *SQLite) GetLocation(ctx context.Context, cluster string) (*LocationRecord, error)
- func (s *SQLite) GetScan(ctx context.Context, id string) (*ScanRecord, error)
- func (s *SQLite) GetScanResults(ctx context.Context, scanID string) (map[string]map[string]scanner.Result, error)
- func (s *SQLite) GetScansByTimeRange(ctx context.Context, start, end time.Time) ([]ScanRecord, error)
- func (s *SQLite) IsAcked(ctx context.Context, fingerprint string) (bool, error)
- func (s *SQLite) ListAPIKeys(ctx context.Context) ([]APIKeyRecord, error)
- func (s *SQLite) ListAcks(ctx context.Context) ([]AckRecord, error)
- func (s *SQLite) ListAlerts(ctx context.Context, opts AlertListOptions) ([]AlertRecord, error)
- func (s *SQLite) ListAuditEntries(ctx context.Context, opts AuditListOptions) ([]AuditEntry, error)
- func (s *SQLite) ListClusterTags(ctx context.Context) (map[string]map[string]string, error)
- func (s *SQLite) ListClusters(ctx context.Context) ([]ClusterRecord, error)
- func (s *SQLite) ListGroups(ctx context.Context) ([]GroupRecord, error)
- func (s *SQLite) ListLocations(ctx context.Context) ([]LocationRecord, error)
- func (s *SQLite) ListScans(ctx context.Context, limit int) ([]ScanRecord, error)
- func (s *SQLite) Ping(ctx context.Context) error
- func (s *SQLite) Prune(ctx context.Context, cutoff time.Time) (int, error)
- func (s *SQLite) PruneAlerts(ctx context.Context, cutoff time.Time) (int, error)
- func (s *SQLite) PruneAuditEntries(ctx context.Context, cutoff time.Time) (int, error)
- func (s *SQLite) RemoveClusterFromGroup(ctx context.Context, group, cluster string) error
- func (s *SQLite) RevokeAPIKey(ctx context.Context, id string) error
- func (s *SQLite) SaveAPIKey(ctx context.Context, rec APIKeyRecord) error
- func (s *SQLite) SaveAck(ctx context.Context, rec AckRecord) error
- func (s *SQLite) SaveAuditEntry(ctx context.Context, rec AuditEntry) error
- func (s *SQLite) SaveGroup(ctx context.Context, name string, clusters []string) error
- func (s *SQLite) SaveScan(ctx context.Context, clusters []string, ...) (string, error)
- func (s *SQLite) SetClusterTag(ctx context.Context, cluster, key, value string) error
- func (s *SQLite) SetLocation(ctx context.Context, loc LocationRecord) error
- func (s *SQLite) TouchAPIKey(ctx context.Context, id string, at time.Time) error
- func (s *SQLite) UpsertAlert(ctx context.Context, rec AlertRecord) error
- func (s *SQLite) Vacuum(ctx context.Context) error
- func (s *SQLite) VacuumInto(ctx context.Context, path string) error
- type ScanRecord
- type ScanResultRecord
- type Store
Constants ¶
const ( // RoleAdmin grants unrestricted access including key management and audit log. RoleAdmin = "admin" // RoleOperator may trigger scans and mutate findings within scope. RoleOperator = "operator" // RoleViewer may only read. RoleViewer = "viewer" )
Role enumerates the authorisation levels Fleetsweeper recognises.
const ScopeWildcard = "*"
ScopeWildcard is the cluster scope entry that grants access to every cluster.
Variables ¶
var ( // ErrStore indicates a general storage failure. ErrStore = errors.New("store") // ErrNotFound indicates the requested record does not exist. ErrNotFound = errors.New("not found") // ErrQuery indicates a failure executing a database query. ErrQuery = errors.New("query") // ErrMigrate indicates a failure applying schema migrations. ErrMigrate = errors.New("migrate") )
Functions ¶
func AckFingerprint ¶
AckFingerprint returns the stable SHA-256 used to key acknowledgements for a finding identified by its cluster, scanner, and title.
func GenerateToken ¶
GenerateToken returns a freshly minted token suitable for an API key. The "fsk_" prefix lets operators identify a Fleetsweeper key at a glance in logs and secret stores. The remaining 32 bytes come from crypto/rand.
func HashToken ¶
HashToken returns the lowercase-hex SHA-256 of a raw token. Used both at creation time (when persisting) and on each request (when matching).
func TokensEqual ¶
TokensEqual compares two raw tokens in constant time to defeat timing oracles.
Types ¶
type APIKeyRecord ¶
type APIKeyRecord struct {
// ID is the stable identifier used in audit log entries and revocation calls.
ID string `json:"id"`
// TokenHash is the lowercase-hex SHA-256 of the raw token.
TokenHash string `json:"-"`
// Name is a human-readable label for the key (for example "ci-runner").
Name string `json:"name"`
// Role is the authorisation role: admin, operator, or viewer.
Role string `json:"role"`
// ClusterScope lists cluster names (or "group:<name>" entries) this key may
// act on. The single element "*" grants unrestricted access.
ClusterScope []string `json:"cluster_scope"`
// CreatedAt is when the key was minted.
CreatedAt time.Time `json:"created_at"`
// ExpiresAt, when non-zero, is when the key automatically becomes invalid.
ExpiresAt time.Time `json:"expires_at,omitempty"`
// LastUsedAt is the most recent successful authentication.
LastUsedAt time.Time `json:"last_used_at,omitempty"`
// RevokedAt, when non-zero, marks the key as administratively disabled.
RevokedAt time.Time `json:"revoked_at,omitempty"`
// CreatedBy identifies the actor that created this key (admin key id, or
// "bootstrap" for the legacy --auth-token, or "cli" for offline creation).
CreatedBy string `json:"created_by,omitempty"`
}
APIKeyRecord is a persisted API key authorised to call the server. Tokens are never stored in plaintext: only TokenHash is persisted, and the raw token is returned to the operator exactly once at creation time.
type AckRecord ¶
type AckRecord struct {
// Fingerprint is the SHA-256 of cluster|scanner|title.
Fingerprint string `json:"fingerprint"`
// Cluster echoes the finding's cluster scope (or "fleet").
Cluster string `json:"cluster"`
// Scanner echoes the finding's source scanner.
Scanner string `json:"scanner"`
// Title echoes the finding's title at ack time, for human context.
Title string `json:"title"`
// AckBy identifies the operator who acked, free-form.
AckBy string `json:"ack_by,omitempty"`
// Reason is the operator's stated reason for acking.
Reason string `json:"reason,omitempty"`
// SnoozeUntil, when non-zero, is when the ack expires and the finding
// resumes alerting. Zero value means "permanent until removed".
SnoozeUntil time.Time `json:"snooze_until,omitempty"`
// CreatedAt is when the ack was recorded.
CreatedAt time.Time `json:"created_at"`
}
AckRecord is a single finding acknowledgement persisted in SQLite. The fingerprint is stable across scans for the same finding shape (cluster + scanner + title) so a recurring critical can be acknowledged once instead of every scan cycle.
type AlertListOptions ¶
type AlertListOptions struct {
// Limit caps the number of rows returned. Defaults to 200 when zero.
Limit int
// Cluster, when non-empty, restricts results to a single cluster.
Cluster string
// Status, when non-empty, filters by alert status ("firing"/"resolved").
Status string
// Severity, when non-empty, filters by severity label value.
Severity string
// Since, when non-zero, only returns alerts received strictly after this time.
Since time.Time
}
AlertListOptions filters AlertRecord queries.
type AlertRecord ¶
type AlertRecord struct {
// Fingerprint is the AlertManager-assigned stable identity.
Fingerprint string `json:"fingerprint"`
// Cluster is the cluster the alert applies to. Derived from the
// `cluster` label when present and falling back to the empty string
// when AlertManager doesn't carry a cluster label.
Cluster string `json:"cluster"`
// Status is "firing" or "resolved".
Status string `json:"status"`
// AlertName is the value of the alertname label.
AlertName string `json:"alertname"`
// Severity is the value of the severity label when present.
Severity string `json:"severity,omitempty"`
// Summary is the value of the summary annotation when present.
Summary string `json:"summary,omitempty"`
// StartsAt is when the alert began firing.
StartsAt time.Time `json:"starts_at,omitempty"`
// EndsAt is when the alert resolved (zero while firing).
EndsAt time.Time `json:"ends_at,omitempty"`
// ReceivedAt is when Fleetsweeper recorded the alert.
ReceivedAt time.Time `json:"received_at"`
// Labels carries every label AlertManager attached to the alert.
Labels map[string]string `json:"labels"`
// Annotations carries every annotation AlertManager attached to the alert.
Annotations map[string]string `json:"annotations"`
// GeneratorURL is the link back to the Prometheus rule that fired.
GeneratorURL string `json:"generator_url,omitempty"`
}
AlertRecord is one inbound AlertManager alert persisted to the alerts table. Fingerprint is AlertManager's stable per-alert identifier and is reused as the primary key so a transition from firing to resolved updates the existing row in place.
type AuditEntry ¶
type AuditEntry struct {
// ID is a time-sortable identifier.
ID string `json:"id"`
// Timestamp is when the request was received.
Timestamp time.Time `json:"timestamp"`
// ActorID identifies the api key that performed the action.
// Empty when --insecure mode allowed an anonymous call.
ActorID string `json:"actor_id,omitempty"`
// ActorName is the key's human-readable label at request time.
ActorName string `json:"actor_name,omitempty"`
// ActorRole is the role the key carried at request time.
ActorRole string `json:"actor_role,omitempty"`
// Method is the HTTP verb (POST, PUT, DELETE).
Method string `json:"method"`
// Path is the request path.
Path string `json:"path"`
// Status is the HTTP response status.
Status int `json:"status"`
// RemoteAddr is the client address as reported by the transport.
RemoteAddr string `json:"remote_addr,omitempty"`
// UserAgent is the client's User-Agent header.
UserAgent string `json:"user_agent,omitempty"`
// DurationMS is the request handler duration in milliseconds.
DurationMS int64 `json:"duration_ms"`
// Error, when non-empty, is a short message describing why the request
// failed authorisation or processing.
Error string `json:"error,omitempty"`
}
AuditEntry is a single audit log row recording one mutating request. Read-only requests are not audited to keep the table volume manageable; the request log already captures those at info level.
type AuditListOptions ¶
type AuditListOptions struct {
// Limit caps the number of rows returned. Defaults to 100 when zero.
Limit int
// Since, when non-zero, only returns entries strictly newer than this time.
Since time.Time
// ActorID, when non-empty, restricts results to a single API key.
ActorID string
// MinStatus, when non-zero, only returns entries with status >= MinStatus.
// Use 400 to surface only failures.
MinStatus int
}
AuditListOptions filters AuditEntry queries.
type ClusterRecord ¶
type ClusterRecord struct {
// Name is the kubeconfig context name.
Name string `json:"name"`
// FirstSeen is when this cluster was first scanned.
FirstSeen time.Time `json:"first_seen"`
// LastSeen is when this cluster was last scanned.
LastSeen time.Time `json:"last_seen"`
// Groups lists the group names this cluster belongs to.
Groups []string `json:"groups"`
// Tags is the cluster's free-form tag map, omitted from the wire
// when no tags are set.
Tags map[string]string `json:"tags,omitempty"`
}
ClusterRecord represents a known cluster.
type Driver ¶
type Driver string
Driver identifies a supported backend.
const ( // DriverSQLite stores data in a single SQLite file. Default for single-instance // deployments. Concurrent readers are fine; writers are serialised by the // SQLite engine. DriverSQLite Driver = "sqlite" // DriverPostgres stores data in a PostgreSQL database. Use this when running // multiple fleetsweeper replicas behind a load balancer. DriverPostgres Driver = "postgres" )
func DetectDriver ¶
DetectDriver infers the driver from a DSN's prefix. URL-shaped DSNs like "postgres://..." or "postgresql://..." choose Postgres; everything else falls back to SQLite. Callers can override with --db-driver when the DSN is ambiguous.
type GroupRecord ¶
type GroupRecord struct {
// Name is the group name.
Name string `json:"name"`
// Clusters lists the cluster names in this group.
Clusters []string `json:"clusters"`
}
GroupRecord represents a cluster group.
type LocationRecord ¶
type LocationRecord struct {
// Cluster is the cluster context name.
Cluster string `json:"cluster"`
// Lat is latitude in degrees north (positive) or south (negative).
Lat float64 `json:"lat"`
// Lng is longitude in degrees east (positive) or west (negative).
Lng float64 `json:"lng"`
// Site is a human-readable label (for example "Store #42, Manhattan").
Site string `json:"site,omitempty"`
// Notes is free-form text the operator can use.
Notes string `json:"notes,omitempty"`
// UpdatedAt is when the record was last written.
UpdatedAt time.Time `json:"updated_at"`
}
LocationRecord is a user-supplied geographic override for a cluster. This is how operators map clusters to physical sites (retail stores, factories, edge devices) that have no cloud-region label to auto-detect.
type Postgres ¶
type Postgres struct {
// contains filtered or unexported fields
}
Postgres implements Store against a PostgreSQL database. It is functionally equivalent to SQLite but tolerates concurrent writers, so multi-replica fleetsweeper deployments share a single backend. Timestamps are stored as RFC3339 TEXT and JSON columns as TEXT so the same row marshalling code as SQLite continues to work; the performance cost is negligible at the row volumes Fleetsweeper produces.
func NewPostgres ¶
NewPostgres opens a connection pool against the given DSN and applies migrations. The DSN is a standard libpq/pgx URL such as "postgres://user:pass@host:5432/db?sslmode=require".
func (*Postgres) AddClusterToGroup ¶
AddClusterToGroup adds a cluster to an existing group.
func (*Postgres) DeleteClusterTag ¶
DeleteClusterTag removes one key from a cluster's tag set.
func (*Postgres) DeleteGroup ¶
DeleteGroup removes a group. Cascades to group_clusters.
func (*Postgres) DeleteLocation ¶
DeleteLocation removes a manual override for a cluster.
func (*Postgres) GetAPIKeyByHash ¶
GetAPIKeyByHash looks up a key by token hash.
func (*Postgres) GetAlert ¶
GetAlert returns the alert row with the given fingerprint. Returns the wrapped ErrNotFound when no row matches.
func (*Postgres) GetClusterHistory ¶
func (p *Postgres) GetClusterHistory(ctx context.Context, cluster string, limit int) ([]ScanResultRecord, error)
GetClusterHistory returns scan results for a cluster across scans.
func (*Postgres) GetClusterTags ¶
GetClusterTags returns every tag pair on a cluster.
func (*Postgres) GetLocation ¶
GetLocation returns the manual override for a cluster, or nil/no error when none has been set.
func (*Postgres) GetScanResults ¶
func (p *Postgres) GetScanResults(ctx context.Context, scanID string) (map[string]map[string]scanner.Result, error)
GetScanResults retrieves all per-cluster scanner results for a scan.
func (*Postgres) GetScansByTimeRange ¶
func (p *Postgres) GetScansByTimeRange(ctx context.Context, start, end time.Time) ([]ScanRecord, error)
GetScansByTimeRange returns scans within a time window.
func (*Postgres) ListAPIKeys ¶
func (p *Postgres) ListAPIKeys(ctx context.Context) ([]APIKeyRecord, error)
ListAPIKeys returns every API key.
func (*Postgres) ListAlerts ¶
func (p *Postgres) ListAlerts(ctx context.Context, opts AlertListOptions) ([]AlertRecord, error)
ListAlerts returns alerts matching opts, newest received_at first.
func (*Postgres) ListAuditEntries ¶
func (p *Postgres) ListAuditEntries(ctx context.Context, opts AuditListOptions) ([]AuditEntry, error)
ListAuditEntries returns audit entries matching opts.
func (*Postgres) ListClusterTags ¶
ListClusterTags returns every tag across the fleet, grouped by cluster.
func (*Postgres) ListClusters ¶
func (p *Postgres) ListClusters(ctx context.Context) ([]ClusterRecord, error)
ListClusters returns all known clusters with their group memberships.
func (*Postgres) ListGroups ¶
func (p *Postgres) ListGroups(ctx context.Context) ([]GroupRecord, error)
ListGroups returns all groups.
func (*Postgres) ListLocations ¶
func (p *Postgres) ListLocations(ctx context.Context) ([]LocationRecord, error)
ListLocations returns every manual override sorted by cluster name.
func (*Postgres) PruneAlerts ¶
PruneAlerts deletes alert rows older than cutoff. Returns rows removed.
func (*Postgres) PruneAuditEntries ¶
PruneAuditEntries deletes audit_log rows older than cutoff. Returns the number of rows removed. Idempotent; safe to call from a periodic ticker.
func (*Postgres) RemoveClusterFromGroup ¶
RemoveClusterFromGroup removes a cluster from a group.
func (*Postgres) RevokeAPIKey ¶
RevokeAPIKey marks a key as revoked.
func (*Postgres) SaveAPIKey ¶
func (p *Postgres) SaveAPIKey(ctx context.Context, rec APIKeyRecord) error
SaveAPIKey inserts a new API key.
func (*Postgres) SaveAuditEntry ¶
func (p *Postgres) SaveAuditEntry(ctx context.Context, rec AuditEntry) error
SaveAuditEntry inserts one audit entry.
func (*Postgres) SaveScan ¶
func (p *Postgres) SaveScan(ctx context.Context, clusters []string, results map[string]map[string]scanner.Result) (string, error)
SaveScan persists a complete scan with all per-cluster results.
func (*Postgres) SetClusterTag ¶
SetClusterTag upserts one key/value tag on a cluster.
func (*Postgres) SetLocation ¶
func (p *Postgres) SetLocation(ctx context.Context, loc LocationRecord) error
SetLocation upserts a manual geographic override for a cluster.
func (*Postgres) TouchAPIKey ¶
TouchAPIKey records the last-used-at timestamp.
func (*Postgres) UpsertAlert ¶
func (p *Postgres) UpsertAlert(ctx context.Context, rec AlertRecord) error
UpsertAlert inserts or updates an alert keyed by fingerprint.
type SQLite ¶
type SQLite struct {
// contains filtered or unexported fields
}
SQLite implements Store using a SQLite database.
func NewSQLite ¶
NewSQLite opens or creates a SQLite database at path and runs migrations. WAL is enabled for read/write concurrency; busy_timeout retries instead of failing under contention; foreign_keys are required for ON DELETE CASCADE to work on scan_results.
func (*SQLite) AddClusterToGroup ¶
AddClusterToGroup adds a cluster to an existing group.
func (*SQLite) DeleteAck ¶
DeleteAck removes an acknowledgement by fingerprint. Idempotent: a missing row is not an error so callers can call from a "clear" button without worrying about state.
func (*SQLite) DeleteClusterTag ¶
DeleteClusterTag removes one key from a cluster's tag set.
func (*SQLite) DeleteGroup ¶
DeleteGroup removes a group. Cascades to group_clusters.
func (*SQLite) DeleteLocation ¶
DeleteLocation removes a manual override for a cluster.
func (*SQLite) GetAPIKeyByHash ¶
GetAPIKeyByHash looks up a key by its token hash. Revoked or expired keys are returned with their RevokedAt/ExpiresAt set so callers can produce the right error message.
func (*SQLite) GetAlert ¶
GetAlert returns the alert row with the given fingerprint. Returns the wrapped ErrNotFound when no row matches.
func (*SQLite) GetClusterHistory ¶
func (s *SQLite) GetClusterHistory(ctx context.Context, cluster string, limit int) ([]ScanResultRecord, error)
GetClusterHistory returns scan results for a cluster across scans.
func (*SQLite) GetClusterTags ¶
GetClusterTags returns every tag pair on a cluster.
func (*SQLite) GetLocation ¶
GetLocation returns the manual override for a cluster, or nil/no error when none has been set.
func (*SQLite) GetScanResults ¶
func (s *SQLite) GetScanResults(ctx context.Context, scanID string) (map[string]map[string]scanner.Result, error)
GetScanResults retrieves all per-cluster scanner results for a scan.
func (*SQLite) GetScansByTimeRange ¶
func (s *SQLite) GetScansByTimeRange(ctx context.Context, start, end time.Time) ([]ScanRecord, error)
GetScansByTimeRange returns scans within a time window.
func (*SQLite) IsAcked ¶
IsAcked reports whether a finding identified by fingerprint has an active (non-expired) ack.
func (*SQLite) ListAPIKeys ¶
func (s *SQLite) ListAPIKeys(ctx context.Context) ([]APIKeyRecord, error)
ListAPIKeys returns every API key, ordered by creation time descending. Revoked keys are included so administrators can audit them.
func (*SQLite) ListAcks ¶
ListAcks returns every active ack. Expired snoozes are filtered out and removed from the database as a side effect so the table stays small.
func (*SQLite) ListAlerts ¶
func (s *SQLite) ListAlerts(ctx context.Context, opts AlertListOptions) ([]AlertRecord, error)
ListAlerts returns alerts matching opts, newest received_at first.
func (*SQLite) ListAuditEntries ¶
func (s *SQLite) ListAuditEntries(ctx context.Context, opts AuditListOptions) ([]AuditEntry, error)
ListAuditEntries returns audit entries matching opts, newest first.
func (*SQLite) ListClusterTags ¶
ListClusterTags returns every tag across the fleet, grouped by cluster.
func (*SQLite) ListClusters ¶
func (s *SQLite) ListClusters(ctx context.Context) ([]ClusterRecord, error)
ListClusters returns all known clusters with their group memberships.
func (*SQLite) ListGroups ¶
func (s *SQLite) ListGroups(ctx context.Context) ([]GroupRecord, error)
ListGroups returns all groups.
func (*SQLite) ListLocations ¶
func (s *SQLite) ListLocations(ctx context.Context) ([]LocationRecord, error)
ListLocations returns every manual override sorted by cluster name.
func (*SQLite) Prune ¶
Prune deletes scans older than cutoff. The scan_results rows cascade. Returns the number of scans deleted.
func (*SQLite) PruneAlerts ¶
PruneAlerts removes alert rows older than cutoff. Returns rows removed.
func (*SQLite) PruneAuditEntries ¶
PruneAuditEntries deletes audit_log rows older than cutoff. Returns the number of rows removed. Idempotent; safe to call from a periodic ticker.
func (*SQLite) RemoveClusterFromGroup ¶
RemoveClusterFromGroup removes a cluster from a group.
func (*SQLite) RevokeAPIKey ¶
RevokeAPIKey marks a key as revoked. The row is retained so audit log entries referencing it remain interpretable.
func (*SQLite) SaveAPIKey ¶
func (s *SQLite) SaveAPIKey(ctx context.Context, rec APIKeyRecord) error
SaveAPIKey inserts a new API key. The ID and TokenHash must already be set; CreatedAt defaults to now when zero. Re-inserting the same ID returns ErrStore.
func (*SQLite) SaveAck ¶
SaveAck upserts an acknowledgement. The fingerprint is the primary key, so re-acking an already-acked finding refreshes its metadata in place.
func (*SQLite) SaveAuditEntry ¶
func (s *SQLite) SaveAuditEntry(ctx context.Context, rec AuditEntry) error
SaveAuditEntry inserts one audit entry. ID and Timestamp default to fresh values when unset, so callers can supply just the request-level fields.
func (*SQLite) SaveScan ¶
func (s *SQLite) SaveScan(ctx context.Context, clusters []string, results map[string]map[string]scanner.Result) (string, error)
SaveScan persists a complete scan with all per-cluster results.
func (*SQLite) SetClusterTag ¶
SetClusterTag upserts one key/value tag on a cluster. Keys are case-sensitive and free-form; common conventions are `env=prod`, `tier=critical`, `owner=team-a`.
func (*SQLite) SetLocation ¶
func (s *SQLite) SetLocation(ctx context.Context, loc LocationRecord) error
SetLocation upserts a manual geographic override for a cluster.
func (*SQLite) TouchAPIKey ¶
TouchAPIKey records the most recent successful authentication time. This is best-effort: a failure here does not invalidate the request.
func (*SQLite) UpsertAlert ¶
func (s *SQLite) UpsertAlert(ctx context.Context, rec AlertRecord) error
UpsertAlert inserts or updates an alert keyed by fingerprint.
func (*SQLite) VacuumInto ¶
VacuumInto writes a consistent snapshot of the database to the given file path. Wraps the SQLite `VACUUM INTO` statement which captures the entire database state atomically without blocking concurrent reads. The target path must not already exist.
type ScanRecord ¶
type ScanRecord struct {
// ID is the unique scan identifier (ULID).
ID string `json:"id"`
// Timestamp is when the scan was executed.
Timestamp time.Time `json:"timestamp"`
// Clusters lists the cluster context names that were scanned.
Clusters []string `json:"clusters"`
// Scanners lists the scanner names that were executed.
Scanners []string `json:"scanners"`
}
ScanRecord represents a persisted scan execution.
type ScanResultRecord ¶
type ScanResultRecord struct {
// ScanID is the parent scan identifier.
ScanID string `json:"scan_id"`
// Cluster is the cluster context name.
Cluster string `json:"cluster"`
// Scanner is the scanner name.
Scanner string `json:"scanner"`
// DataJSON is the raw JSON-encoded scanner output.
DataJSON []byte `json:"data_json"`
}
ScanResultRecord represents one scanner's output for one cluster in one scan.
type Store ¶
type Store interface {
// SaveScan persists a complete scan with all per-cluster results. Returns
// the generated scan ID.
SaveScan(ctx context.Context, clusters []string, results map[string]map[string]scanner.Result) (string, error)
// GetScan retrieves a scan record by ID.
GetScan(ctx context.Context, id string) (*ScanRecord, error)
// ListScans returns scan records ordered by timestamp descending.
ListScans(ctx context.Context, limit int) ([]ScanRecord, error)
// GetScanResults retrieves all per-cluster scanner results for a scan,
// reconstructed into the same map shape the scan engine produces.
GetScanResults(ctx context.Context, scanID string) (map[string]map[string]scanner.Result, error)
// ListClusters returns all known clusters.
ListClusters(ctx context.Context) ([]ClusterRecord, error)
// SaveGroup creates or updates a group with the given cluster members.
SaveGroup(ctx context.Context, name string, clusters []string) error
// GetGroup retrieves a group by name.
GetGroup(ctx context.Context, name string) (*GroupRecord, error)
// ListGroups returns all groups.
ListGroups(ctx context.Context) ([]GroupRecord, error)
// DeleteGroup removes a group.
DeleteGroup(ctx context.Context, name string) error
// AddClusterToGroup adds a cluster to an existing group.
AddClusterToGroup(ctx context.Context, group, cluster string) error
// RemoveClusterFromGroup removes a cluster from a group.
RemoveClusterFromGroup(ctx context.Context, group, cluster string) error
// GetClusterHistory returns scan results for a specific cluster across
// scans, ordered by time descending.
GetClusterHistory(ctx context.Context, cluster string, limit int) ([]ScanResultRecord, error)
// GetScansByTimeRange returns scans within a time window.
GetScansByTimeRange(ctx context.Context, start, end time.Time) ([]ScanRecord, error)
// Prune deletes scans older than cutoff. Returns the number of scans deleted.
Prune(ctx context.Context, cutoff time.Time) (int, error)
// Vacuum reclaims unused database pages.
Vacuum(ctx context.Context) error
// SetLocation upserts a manual location override for a cluster.
SetLocation(ctx context.Context, loc LocationRecord) error
// GetLocation returns a single cluster's manual override, or nil if none.
GetLocation(ctx context.Context, cluster string) (*LocationRecord, error)
// ListLocations returns every manual override.
ListLocations(ctx context.Context) ([]LocationRecord, error)
// DeleteLocation removes a manual override.
DeleteLocation(ctx context.Context, cluster string) error
// SaveAck upserts a finding acknowledgement. The fingerprint primary key
// allows the same finding to be acked once across many scan cycles.
SaveAck(ctx context.Context, rec AckRecord) error
// DeleteAck removes an acknowledgement. Idempotent.
DeleteAck(ctx context.Context, fingerprint string) error
// ListAcks returns every active acknowledgement (expired snoozes pruned).
ListAcks(ctx context.Context) ([]AckRecord, error)
// IsAcked reports whether a finding is currently acknowledged.
IsAcked(ctx context.Context, fingerprint string) (bool, error)
// SaveAPIKey inserts a new API key. The raw token is never persisted: the
// caller must hash it and place the result in rec.TokenHash before calling.
SaveAPIKey(ctx context.Context, rec APIKeyRecord) error
// GetAPIKeyByHash looks up a key by token hash. Returns the wrapped
// ErrNotFound when no row matches.
GetAPIKeyByHash(ctx context.Context, hash string) (*APIKeyRecord, error)
// GetAPIKey returns the key with the given ID.
GetAPIKey(ctx context.Context, id string) (*APIKeyRecord, error)
// ListAPIKeys returns every API key including revoked ones, newest first.
ListAPIKeys(ctx context.Context) ([]APIKeyRecord, error)
// RevokeAPIKey marks the key with the given ID as administratively disabled.
RevokeAPIKey(ctx context.Context, id string) error
// TouchAPIKey updates the last-used-at timestamp. Best-effort; callers
// should not fail authentication on error.
TouchAPIKey(ctx context.Context, id string, at time.Time) error
// SaveAuditEntry inserts one audit log row.
SaveAuditEntry(ctx context.Context, rec AuditEntry) error
// ListAuditEntries returns audit entries matching opts, newest first.
ListAuditEntries(ctx context.Context, opts AuditListOptions) ([]AuditEntry, error)
// PruneAuditEntries deletes audit log rows older than cutoff and returns
// the number of rows removed. Used by the audit-retention ticker.
PruneAuditEntries(ctx context.Context, cutoff time.Time) (int, error)
// UpsertAlert inserts or updates an inbound AlertManager alert keyed by
// its fingerprint. Reusing the fingerprint allows the same alert to
// transition between firing/resolved without producing duplicate rows.
UpsertAlert(ctx context.Context, rec AlertRecord) error
// GetAlert returns the alert row with the given fingerprint. Returns
// ErrNotFound when no row matches.
GetAlert(ctx context.Context, fingerprint string) (*AlertRecord, error)
// ListAlerts returns alerts matching opts, newest received_at first.
ListAlerts(ctx context.Context, opts AlertListOptions) ([]AlertRecord, error)
// PruneAlerts deletes alert rows older than cutoff (received_at). Returns
// the number of rows removed.
PruneAlerts(ctx context.Context, cutoff time.Time) (int, error)
// SetClusterTag upserts a single key/value tag on a cluster.
SetClusterTag(ctx context.Context, cluster, key, value string) error
// DeleteClusterTag removes one key from a cluster's tag set. Idempotent.
DeleteClusterTag(ctx context.Context, cluster, key string) error
// GetClusterTags returns every tag pair on a cluster as a key→value
// map. Empty map when no tags are set.
GetClusterTags(ctx context.Context, cluster string) (map[string]string, error)
// ListClusterTags returns every tag across the fleet, grouped by
// cluster. Convenient for the dashboard's per-cluster render.
ListClusterTags(ctx context.Context) (map[string]map[string]string, error)
// Close releases database resources.
Close() error
}
Store persists and retrieves scan data.