store

package
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 4, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package store provides a pure-Go SQLite-backed persistence layer.

It uses modernc.org/sqlite which is a CGO-free SQLite implementation, so the whole application can be cross-compiled to a single static binary for Windows/Linux/macOS without a C toolchain.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = errors.New("store: not found")

ErrNotFound is returned when a lookup yields no row.

View Source
var Sections = []string{
	"dashboard", "containers", "images", "volumes", "networks", "topology",
	"logs", "events", "alerts", "hosts", "registries", "audit",
}

Sections are the access-control units, matching the app's menu. A user's permissions and the global feature flags are both expressed as sets of these.

Functions

func NormalizeRegistryHost

func NormalizeRegistryHost(host string) string

NormalizeRegistryHost maps the various Docker Hub aliases to a single key so a stored "docker.io" credential matches refs like "nginx" or "user/app".

func ValidSection

func ValidSection(key string) bool

ValidSection reports whether key is a known section.

Types

type AlertEvent

type AlertEvent struct {
	ID            int64     `json:"id"`
	RuleID        int64     `json:"ruleId"`
	RuleName      string    `json:"ruleName"`
	Type          string    `json:"type"`
	Severity      string    `json:"severity"`
	HostID        int64     `json:"hostId"`
	HostName      string    `json:"hostName"`
	ContainerID   string    `json:"containerId"`
	ContainerName string    `json:"containerName"`
	Message       string    `json:"message"`
	Value         *float64  `json:"value"`
	Acknowledged  bool      `json:"acknowledged"`
	CreatedAt     time.Time `json:"createdAt"`
}

AlertEvent is a fired alert recorded for the in-app feed.

type AlertRule

type AlertRule struct {
	ID          int64     `json:"id"`
	Name        string    `json:"name"`
	Enabled     bool      `json:"enabled"`
	Type        string    `json:"type"`     // state | resource | log | restart
	Target      string    `json:"target"`   // container name substring; ” or '*' = all
	Config      string    `json:"config"`   // raw JSON, interpreted by the engine
	Severity    string    `json:"severity"` // info | warning | critical
	WebhookID   *int64    `json:"webhookId"`
	Email       bool      `json:"email"` // also send to the configured SMTP recipient
	CooldownSec int       `json:"cooldownSec"`
	CreatedAt   time.Time `json:"createdAt"`
}

AlertRule defines when an alert fires and where it goes.

type AuditEntry

type AuditEntry struct {
	ID        int64     `json:"id"`
	UserID    int64     `json:"userId"`
	Username  string    `json:"username"`
	Action    string    `json:"action"`
	Target    string    `json:"target"`
	Detail    string    `json:"detail"`
	IP        string    `json:"ip"`
	CreatedAt time.Time `json:"createdAt"`
}

AuditEntry is a single recorded security-relevant action.

type Host

type Host struct {
	ID         int64
	Name       string
	Kind       string
	Address    string
	TLSCA      string
	TLSCert    string
	TLSKey     string
	HostKey    string // pinned SSH host public key (authorized_keys line); ssh hosts only
	AlertEmail string // per-host alert recipient override (falls back to global SMTP To)
	CreatedAt  time.Time
}

Host describes a Docker engine endpoint the app can connect to.

Kind is one of:

  • "local": the local daemon (unix socket / windows named pipe)
  • "tcp": a remote daemon over TCP, optionally TLS-secured
  • "ssh": a remote daemon reached through an SSH tunnel

type LDAPConfig

type LDAPConfig struct {
	Enabled      bool   `json:"enabled"`
	URL          string `json:"url"`      // ldap://host:389 or ldaps://host:636
	StartTLS     bool   `json:"startTls"` // upgrade a plain connection to TLS
	BindDN       string `json:"bindDn"`   // service account used to search for users
	BindPassword string `json:"bindPassword"`
	UserBaseDN   string `json:"userBaseDn"`
	UserFilter   string `json:"userFilter"`   // e.g. (uid=%s) or (sAMAccountName=%s)
	AdminGroupDN string `json:"adminGroupDn"` // optional: members are provisioned as admins
}

LDAPConfig configures optional LDAP / Active Directory authentication. The bind password is encrypted at rest (like the SMTP one) and never returned.

func (LDAPConfig) Configured

func (c LDAPConfig) Configured() bool

Configured reports whether enough is set to attempt LDAP authentication.

type ParseRule

type ParseRule struct {
	ID        int64     `json:"id"`
	Name      string    `json:"name"`
	Pattern   string    `json:"pattern"`
	CreatedAt time.Time `json:"createdAt"`
}

ParseRule is a saved log-parsing rule: a regex with named capture groups that the Logs view applies to extract structured fields (columns) from log lines.

type Registry

type Registry struct {
	ID        int64
	Name      string
	Address   string
	Username  string
	CreatedAt time.Time
}

Registry holds credentials for a container image registry. The secret (password/token) is encrypted at rest and never returned in listings.

type RegistryAuth

type RegistryAuth struct {
	Address  string
	Username string
	Password string
}

RegistryAuth is the decrypted credential pair used to authenticate to a registry for pull/push. It is only assembled server-side, never serialised.

type SMTPConfig

type SMTPConfig struct {
	Host     string `json:"host"`
	Port     int    `json:"port"`
	Username string `json:"username"`
	Password string `json:"password"`
	From     string `json:"from"`
	To       string `json:"to"`  // comma-separated recipients
	TLS      bool   `json:"tls"` // implicit TLS (e.g. port 465); otherwise STARTTLS if offered
}

SMTPConfig is the mail server used for the email alert channel. The password is stored encrypted at rest (the persisted JSON holds ciphertext); it is decrypted on read and never returned to API clients.

func (SMTPConfig) Configured

func (c SMTPConfig) Configured() bool

Configured reports whether enough is set to attempt sending.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store wraps the database handle and exposes typed queries.

func Open

func Open(path string) (*Store, error)

Open opens (creating if necessary) the SQLite database at path and runs all pending migrations. A path of ":memory:" yields an ephemeral DB.

func (*Store) AckAlertEvent

func (s *Store) AckAlertEvent(ctx context.Context, id int64) error

func (*Store) Audit

func (s *Store) Audit(ctx context.Context, e AuditEntry) error

Audit appends an entry to the audit log. Failures are returned but callers generally log-and-continue: an audit write must never block a user action.

func (*Store) AuthByID

func (s *Store) AuthByID(ctx context.Context, id int64) (*RegistryAuth, error)

AuthByID returns the decrypted credentials for a single registry.

func (*Store) AuthForHost

func (s *Store) AuthForHost(ctx context.Context, host string) (*RegistryAuth, error)

AuthForHost returns the decrypted credentials whose address matches the registry host of an image reference, or ErrNotFound if none is configured.

func (*Store) Close

func (s *Store) Close() error

Close releases the underlying database handle.

func (*Store) CountAdmins

func (s *Store) CountAdmins(ctx context.Context) (int, error)

CountAdmins returns how many admin accounts exist (to guard the last admin).

func (*Store) CountUnacknowledged

func (s *Store) CountUnacknowledged(ctx context.Context) (int, error)

func (*Store) CountUsers

func (s *Store) CountUsers(ctx context.Context) (int, error)

CountUsers returns the number of accounts; used to detect first-run setup.

func (*Store) CreateAlertRule

func (s *Store) CreateAlertRule(ctx context.Context, r *AlertRule) (int64, error)

func (*Store) CreateHost

func (s *Store) CreateHost(ctx context.Context, h *Host) (int64, error)

CreateHost inserts a new host and returns its ID.

func (*Store) CreateParseRule

func (s *Store) CreateParseRule(ctx context.Context, name, pattern string) (int64, error)

func (*Store) CreateRegistry

func (s *Store) CreateRegistry(ctx context.Context, name, address, username, secret string) (int64, error)

CreateRegistry stores a registry, encrypting the secret. The address is normalised so it matches image references later (see NormalizeRegistryHost).

func (*Store) CreateUser

func (s *Store) CreateUser(ctx context.Context, u *User) (int64, error)

CreateUser inserts a new account and returns its assigned ID.

func (*Store) CreateWebhook

func (s *Store) CreateWebhook(ctx context.Context, w *Webhook) (int64, error)

func (*Store) DeleteAlertRule

func (s *Store) DeleteAlertRule(ctx context.Context, id int64) error

func (*Store) DeleteHost

func (s *Store) DeleteHost(ctx context.Context, id int64) error

DeleteHost removes a host by ID.

func (*Store) DeleteParseRule

func (s *Store) DeleteParseRule(ctx context.Context, id int64) error

func (*Store) DeleteRegistry

func (s *Store) DeleteRegistry(ctx context.Context, id int64) error

DeleteRegistry removes a registry by ID.

func (*Store) DeleteUser

func (s *Store) DeleteUser(ctx context.Context, id int64) error

DeleteUser removes an account.

func (*Store) DeleteWebhook

func (s *Store) DeleteWebhook(ctx context.Context, id int64) error

func (*Store) DisabledSections

func (s *Store) DisabledSections(ctx context.Context) ([]string, error)

DisabledSections returns the sections an admin has turned off app-wide.

func (*Store) EnsureLocalHost

func (s *Store) EnsureLocalHost(ctx context.Context) error

EnsureLocalHost guarantees a "local" host row exists so the app is usable immediately on first run without manual host configuration.

func (*Store) GetLDAP

func (s *Store) GetLDAP(ctx context.Context) (LDAPConfig, error)

GetLDAP loads the LDAP config, decrypting the bind password.

func (*Store) GetSMTP

func (s *Store) GetSMTP(ctx context.Context) (SMTPConfig, error)

GetSMTP loads the SMTP config, decrypting the password.

func (*Store) HostByID

func (s *Store) HostByID(ctx context.Context, id int64) (*Host, error)

HostByID returns a single host or ErrNotFound.

func (*Store) InsertAlertEvent

func (s *Store) InsertAlertEvent(ctx context.Context, e *AlertEvent) (int64, error)

func (*Store) ListAlertEvents

func (s *Store) ListAlertEvents(ctx context.Context, limit int) ([]AlertEvent, error)

func (*Store) ListAlertRules

func (s *Store) ListAlertRules(ctx context.Context) ([]AlertRule, error)

func (*Store) ListHosts

func (s *Store) ListHosts(ctx context.Context) ([]Host, error)

ListHosts returns all configured hosts ordered by name.

func (*Store) ListParseRules

func (s *Store) ListParseRules(ctx context.Context) ([]ParseRule, error)

func (*Store) ListRegistries

func (s *Store) ListRegistries(ctx context.Context) ([]Registry, error)

ListRegistries returns the configured registries without their secrets.

func (*Store) ListUsers

func (s *Store) ListUsers(ctx context.Context) ([]User, error)

ListUsers returns all accounts (without secrets) for the admin user manager.

func (*Store) ListWebhooks

func (s *Store) ListWebhooks(ctx context.Context) ([]Webhook, error)

func (*Store) LocalhostNo2FA

func (s *Store) LocalhostNo2FA(ctx context.Context) (bool, error)

LocalhostNo2FA reports whether password-only login is allowed from loopback.

func (*Store) Ping added in v1.1.0

func (s *Store) Ping(ctx context.Context) error

Ping checks that the database is reachable (used by the health endpoint).

func (*Store) RecentAudit

func (s *Store) RecentAudit(ctx context.Context, limit int, before int64) ([]AuditEntry, error)

RecentAudit returns the most recent audit entries, newest first. When before is > 0, only entries older than that id are returned (cursor pagination).

func (*Store) SetAlertRuleEnabled

func (s *Store) SetAlertRuleEnabled(ctx context.Context, id int64, enabled bool) error

func (*Store) SetCipher

func (s *Store) SetCipher(c *crypto.Cipher)

SetCipher installs the cipher used to encrypt secrets at rest (registry credentials). It is wired up once at startup, after the key is loaded.

func (*Store) SetDisabledSections

func (s *Store) SetDisabledSections(ctx context.Context, keys []string) error

SetDisabledSections persists the app-wide disabled sections.

func (*Store) SetHostAlertEmail

func (s *Store) SetHostAlertEmail(ctx context.Context, id int64, email string) error

SetHostAlertEmail sets a host's per-host alert recipient override.

func (*Store) SetHostKey

func (s *Store) SetHostKey(ctx context.Context, id int64, key string) error

SetHostKey pins (or clears, when key is "") the trusted SSH host public key for a host. Subsequent connections verify the daemon's key against it.

func (*Store) SetLDAP

func (s *Store) SetLDAP(ctx context.Context, c LDAPConfig) error

SetLDAP persists the config, encrypting the bind password. An empty bind password preserves the previously stored one.

func (*Store) SetLocalhostNo2FA

func (s *Store) SetLocalhostNo2FA(ctx context.Context, on bool) error

SetLocalhostNo2FA toggles the localhost 2FA exemption.

func (*Store) SetSMTP

func (s *Store) SetSMTP(ctx context.Context, c SMTPConfig) error

SetSMTP persists the SMTP config, encrypting the password. An empty password preserves the previously stored one (so the UI need not resend the secret).

func (*Store) SetSetting

func (s *Store) SetSetting(ctx context.Context, key, value string) error

SetSetting upserts a key/value pair.

func (*Store) SetTOTP

func (s *Store) SetTOTP(ctx context.Context, userID int64, secret string, enabled bool) error

SetTOTP stores the secret and enabled flag for a user (enrollment / disable).

func (*Store) SetUserPrefs added in v1.1.0

func (s *Store) SetUserPrefs(ctx context.Context, userID int64, prefs string) error

SetUserPrefs replaces a user's UI preferences JSON blob.

func (*Store) Setting

func (s *Store) Setting(ctx context.Context, key string) (string, error)

Setting reads a single key from the settings table. Returns ("", nil) when the key is absent so callers can treat "missing" as "use default".

func (*Store) TouchLogin

func (s *Store) TouchLogin(ctx context.Context, userID int64) error

TouchLogin records the timestamp of a successful login.

func (*Store) UpdateAlertRule

func (s *Store) UpdateAlertRule(ctx context.Context, id int64, r *AlertRule) error

UpdateAlertRule replaces a rule's mutable fields (enabled is managed separately via SetAlertRuleEnabled).

func (*Store) UpdatePassword

func (s *Store) UpdatePassword(ctx context.Context, userID int64, hash string) error

UpdatePassword replaces the stored Argon2id hash for a user.

func (*Store) UpdateUserAccess

func (s *Store) UpdateUserAccess(ctx context.Context, id int64, role string, readOnly bool, sections []string) error

UpdateUserAccess changes a user's role, read-only flag and allowed sections.

func (*Store) UserByID

func (s *Store) UserByID(ctx context.Context, id int64) (*User, error)

UserByID looks up a user by primary key.

func (*Store) UserByUsername

func (s *Store) UserByUsername(ctx context.Context, username string) (*User, error)

UserByUsername looks up a user by their unique username.

func (*Store) UserPrefs added in v1.1.0

func (s *Store) UserPrefs(ctx context.Context, userID int64) (string, error)

UserPrefs returns a user's UI preferences as a JSON object string ("{}" if none). These are opaque to the server — the frontend owns the shape.

func (*Store) WebhookByID

func (s *Store) WebhookByID(ctx context.Context, id int64) (*Webhook, error)

type User

type User struct {
	ID           int64
	Username     string
	PasswordHash string
	Role         string
	AuthSource   string // "local" (password stored here) or "ldap" (verified externally)
	ReadOnly     bool
	Sections     []string
	TOTPSecret   string
	TOTPEnabled  bool
	CreatedAt    time.Time
	LastLoginAt  time.Time
}

User is an application account. PasswordHash is an Argon2id encoded hash. TOTPSecret is the base32 shared secret; it is only meaningful once TOTPEnabled is true (i.e. the user confirmed enrollment with a valid code).

Role is "admin" (full access incl. user/feature management) or "user". For "user" accounts, Sections lists the menu sections they may access and ReadOnly blocks mutating actions. Admins ignore both.

func (*User) IsAdmin

func (u *User) IsAdmin() bool

IsAdmin reports whether the user has the admin role.

type Webhook

type Webhook struct {
	ID           int64             `json:"id"`
	Name         string            `json:"name"`
	URL          string            `json:"url"`
	Method       string            `json:"method"`
	Headers      map[string]string `json:"headers"`
	BodyTemplate string            `json:"bodyTemplate"`
	CreatedAt    time.Time         `json:"createdAt"`
}

Webhook is a generic HTTP destination an alert rule can fire to. body_template is a Go text/template rendered against the alert event.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL