db

package
v1.9.1 Latest Latest
Warning

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

Go to latest
Published: Apr 7, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package db provides Warden's central persistence layer backed by SQLite.

It stores three kinds of data:

  • **Projects**: container configuration (name, image, mounts, env vars, etc.)
  • **Settings**: key-value pairs (runtime, auditLogMode, disconnectKey)
  • **Events**: centralized audit log from agent hooks, backend, frontend, containers

The database lives at ~/.config/warden/warden.db (platform-dependent). All methods on Store are safe for concurrent use.

Index

Constants

View Source
const (
	SourceAgent     = api.AuditSourceAgent
	SourceBackend   = api.AuditSourceBackend
	SourceFrontend  = api.AuditSourceFrontend
	SourceContainer = api.AuditSourceContainer
	SourceExternal  = api.AuditSourceExternal

	LevelInfo  = api.AuditLevelInfo
	LevelWarn  = api.AuditLevelWarn
	LevelError = api.AuditLevelError
)

Re-export constants so existing db.SourceAgent, db.LevelInfo, etc. still work.

View Source
const DefaultQueryLimit = 10_000

DefaultQueryLimit is applied when QueryFilters.Limit is zero.

Variables

This section is empty.

Functions

This section is empty.

Types

type AccessItemRow added in v0.4.0

type AccessItemRow struct {
	// ID is the unique identifier (UUID for user items).
	ID string
	// Label is the human-readable display name.
	Label string
	// Description explains what this access item provides.
	Description string
	// Method is the delivery strategy (only "transport" for now).
	Method string
	// Credentials is JSON-encoded []access.Credential.
	Credentials json.RawMessage
}

AccessItemRow represents a user-created access item stored in the database. Built-in items (Git, SSH) are not stored — they come from the access package.

type AuditMode

type AuditMode string

AuditMode controls which events are persisted to the audit log.

const (
	// AuditOff disables all audit logging. Nothing is written.
	AuditOff AuditMode = "off"
	// AuditStandard logs core operational events: session lifecycle,
	// terminal lifecycle, worktree lifecycle, budget, and system events.
	AuditStandard AuditMode = "standard"
	// AuditDetailed logs everything in standard plus agent tool use,
	// permissions, subagents, config changes, user prompts, and debug
	// events (auto-captured backend warnings/errors via slog tee).
	AuditDetailed AuditMode = "detailed"
)

type AuditSummaryRow

type AuditSummaryRow struct {
	TotalSessions   int
	TotalToolUses   int
	TotalPrompts    int
	UniqueProjects  int
	UniqueWorktrees int
	Earliest        string
	Latest          string
}

AuditSummaryRow holds aggregate audit data from a summary query.

type AuditWriter

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

AuditWriter gates audit log writes based on the current audit mode. All audit writes across the codebase go through this single entry point. Thread-safe for concurrent reads (mode) and writes.

func NewAuditWriter

func NewAuditWriter(store *Store, mode AuditMode, standardEvents map[string]bool) *AuditWriter

NewAuditWriter creates a writer that persists entries to the given store, filtered by the initial audit mode. The standardEvents set defines which events are logged in standard mode — events not in this set are only logged in detailed mode. Pass AuditOff as mode to start silent.

func (*AuditWriter) Mode

func (w *AuditWriter) Mode() AuditMode

Mode returns the current audit mode.

func (*AuditWriter) SetMode

func (w *AuditWriter) SetMode(mode AuditMode)

SetMode updates the audit mode at runtime. Takes effect immediately for subsequent Write calls.

func (*AuditWriter) Write

func (w *AuditWriter) Write(entry Entry)

Write persists an audit entry if the current mode allows it. Drops silently when mode is off or the event is not in the current mode's allowlist. Logs a warning on DB write failure so callers don't need error handling.

type Entry

type Entry = api.AuditEntry

Type aliases for backward compatibility. Canonical definitions live in the api package; these aliases let existing db.Entry / db.Source / db.Level references compile without changes throughout the codebase.

type Level

type Level = api.AuditLevel

Type aliases for backward compatibility. Canonical definitions live in the api package; these aliases let existing db.Entry / db.Source / db.Level references compile without changes throughout the codebase.

type OffsetStoreAdapter added in v1.5.0

type OffsetStoreAdapter struct {
	Store *Store
}

OffsetStoreAdapter wraps a Store to implement watcher.OffsetStore. Lives in the db package to avoid the watcher package importing db.

func (*OffsetStoreAdapter) DeleteOffset added in v1.5.0

func (a *OffsetStoreAdapter) DeleteOffset(projectID, agentType, filePath string) error

DeleteOffset implements watcher.OffsetStore.

func (*OffsetStoreAdapter) DeleteOffsets added in v1.5.0

func (a *OffsetStoreAdapter) DeleteOffsets(projectID, agentType string) error

DeleteOffsets implements watcher.OffsetStore.

func (*OffsetStoreAdapter) LoadOffset added in v1.5.0

func (a *OffsetStoreAdapter) LoadOffset(projectID, agentType, filePath string) (int64, error)

LoadOffset implements watcher.OffsetStore.

func (*OffsetStoreAdapter) SaveOffset added in v1.5.0

func (a *OffsetStoreAdapter) SaveOffset(projectID, agentType, filePath string, offset int64) error

SaveOffset implements watcher.OffsetStore.

type ProjectAgentKey added in v0.5.0

type ProjectAgentKey struct {
	ProjectID string
	AgentType string
}

ProjectAgentKey uniquely identifies a project+agent pair. Used as a map key where the compound (project_id, agent_type) identity is needed.

type ProjectCostRow

type ProjectCostRow struct {
	TotalCost   float64
	IsEstimated bool
}

ProjectCostRow holds aggregated cost data for a project from the DB.

type ProjectRow

type ProjectRow struct {
	// ProjectID is the deterministic identifier (sha256 of host path, 12 hex chars).
	ProjectID string
	// Name is the user-chosen display label / Docker container name.
	Name string
	// HostPath is the absolute host directory mounted into the container.
	HostPath string
	// AddedAt is when the project was added to Warden.
	AddedAt time.Time
	// Image is the container image name.
	Image string
	// EnvVars is JSON-encoded map[string]string of user-provided env vars.
	EnvVars json.RawMessage
	// Mounts is JSON-encoded []Mount of additional bind mounts.
	Mounts json.RawMessage
	// OriginalMounts is JSON-encoded []Mount of pre-symlink-resolution mounts.
	OriginalMounts json.RawMessage
	// SkipPermissions controls whether terminals skip permission prompts.
	SkipPermissions bool
	// NetworkMode is the container's network isolation level (full/restricted/none).
	NetworkMode string
	// AllowedDomains is comma-separated domains for restricted mode.
	AllowedDomains string
	// CostBudget is the per-project cost limit in USD (0 = use global default).
	CostBudget float64
	// EnabledAccessItems is a comma-separated list of enabled access item IDs (e.g. "git,ssh").
	EnabledAccessItems string
	// EnabledRuntimes is a comma-separated list of enabled runtime IDs (e.g. "node,python,go").
	EnabledRuntimes string
	// ForwardedPorts is a comma-separated list of forwarded port numbers (e.g. "5173,3000").
	ForwardedPorts string
	// AgentType identifies the CLI agent running in this project (e.g. "claude-code", "codex").
	AgentType string
	// ContainerID is the Docker-assigned container ID (empty when no container exists).
	ContainerID string
	// ContainerName is the Docker container name (may differ from Name if renamed).
	ContainerName string
}

ProjectRow represents a project stored in the database.

Complex fields (EnvVars, Mounts, OriginalMounts) are stored as opaque JSON. The service layer handles marshaling to/from engine types.

type QueryFilters

type QueryFilters struct {
	// Source restricts results to a single source layer.
	Source Source
	// Level restricts results to a single severity level.
	Level Level
	// ProjectID restricts results to a single project by its deterministic ID.
	ProjectID string
	// Worktree restricts results to a single worktree ID.
	Worktree string
	// Event restricts results to a single event type identifier.
	Event string
	// Events restricts results to any of the listed event types (OR).
	Events []string
	// ExcludeEvents excludes entries whose event type is in this list (NOT IN).
	// Mutually exclusive with Events; if both are set, Events takes precedence.
	ExcludeEvents []string
	// Since returns only entries with a timestamp at or after this time.
	Since time.Time
	// Until returns only entries with a timestamp strictly before this time.
	Until time.Time
	// Limit caps the number of returned entries. Defaults to DefaultQueryLimit if zero.
	Limit int
	// Offset skips this many entries before returning results.
	Offset int
}

QueryFilters controls which entries are returned by Store.Query.

Zero-value fields are ignored (no filtering). Limit defaults to DefaultQueryLimit when zero.

type SessionCostRow added in v1.8.0

type SessionCostRow struct {
	SessionID   string
	Cost        float64
	IsEstimated bool
	CreatedAt   string
	UpdatedAt   string
}

SessionCostRow holds cost data for a single session.

type SlogHandler

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

SlogHandler is a slog.Handler that writes backend log records to the audit log. It wraps a delegate handler so logs still go to their original destination (stderr).

func NewSlogHandler

func NewSlogHandler(delegate slog.Handler, writer *AuditWriter) *SlogHandler

NewSlogHandler creates a handler that writes to both the delegate and the audit log. If writer is nil, only the delegate receives records.

func (*SlogHandler) Enabled

func (h *SlogHandler) Enabled(ctx context.Context, level slog.Level) bool

Enabled reports whether the handler handles records at the given level.

func (*SlogHandler) Handle

func (h *SlogHandler) Handle(ctx context.Context, record slog.Record) error

Handle writes the record to the delegate and, if the writer is non-nil, also writes a backend entry to the audit log. Only warnings and errors are written — INFO-level traffic is too noisy. These events have auto-generated snake_case names and are classified as debug category (detailed mode only) by the AuditWriter's standardEvents allowlist.

func (*SlogHandler) WithAttrs

func (h *SlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs returns a new handler with the given attributes pre-set.

func (*SlogHandler) WithGroup

func (h *SlogHandler) WithGroup(name string) slog.Handler

WithGroup returns a new handler with the given group name.

type Source

type Source = api.AuditSource

Type aliases for backward compatibility. Canonical definitions live in the api package; these aliases let existing db.Entry / db.Source / db.Level references compile without changes throughout the codebase.

type Store

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

Store writes structured audit log entries to a SQLite database.

All methods are safe for concurrent use. A nil Store is a valid no-op: all methods return immediately without error.

func New

func New(dir string) (*Store, error)

New creates a Store backed by a SQLite database at dir/warden.db. The directory is created if it does not exist. Pass the config directory root (e.g. ~/.config/warden/) — the database file is created inside it.

func (*Store) Clear

func (l *Store) Clear() error

Clear removes all audit log entries.

func (*Store) Close

func (l *Store) Close() error

Close closes the underlying database connection.

func (*Store) Delete

func (l *Store) Delete(filters QueryFilters) (int64, error)

Delete removes events matching the given filters. With no filters set, this is equivalent to [Clear]. Supports scoping by project, worktree, and time range (since/until).

func (*Store) DeleteAccessItem added in v0.4.0

func (l *Store) DeleteAccessItem(id string) error

DeleteAccessItem removes a user-created access item by ID.

func (*Store) DeleteProject

func (l *Store) DeleteProject(projectID, agentType string) error

DeleteProject removes a project from the projects table. Audit events and cost data are intentionally retained so the audit page can show historical data.

func (*Store) DeleteProjectCosts

func (l *Store) DeleteProjectCosts(projectID, agentType string) error

DeleteProjectCosts removes all cost entries for a project+agent pair.

func (*Store) DeleteSessionCosts added in v1.5.0

func (l *Store) DeleteSessionCosts(projectID string, since, until time.Time) error

DeleteSessionCosts removes session cost entries matching the given filters. Supports scoping by project ID and time range. With no filters, clears all session costs.

func (*Store) DeleteTailerOffset added in v1.5.0

func (l *Store) DeleteTailerOffset(projectID, agentType, filePath string) error

DeleteTailerOffset removes the stored offset for a single file.

func (*Store) DeleteTailerOffsets added in v1.5.0

func (l *Store) DeleteTailerOffsets(projectID, agentType string) error

DeleteTailerOffsets removes all stored offsets for a project+agent pair.

func (*Store) DistinctProjectIDs

func (l *Store) DistinctProjectIDs() ([]string, error)

DistinctProjectIDs returns sorted, unique project IDs that have at least one event logged. Empty project IDs are excluded.

func (*Store) GetAccessItem added in v0.4.0

func (l *Store) GetAccessItem(id string) (*AccessItemRow, error)

GetAccessItem returns a user-created access item by ID, or nil if not found.

func (*Store) GetAccessItemsByIDs added in v0.4.0

func (l *Store) GetAccessItemsByIDs(ids []string) ([]AccessItemRow, error)

GetAccessItemsByIDs returns user-created access items matching the given IDs. IDs not found are silently skipped.

func (*Store) GetAllProjectTotalCosts

func (l *Store) GetAllProjectTotalCosts() (map[ProjectAgentKey]ProjectCostRow, error)

GetAllProjectTotalCosts returns cumulative costs for all project+agent pairs by summing across all sessions.

func (*Store) GetCostInTimeRange

func (l *Store) GetCostInTimeRange(projectID string, since, until time.Time) (ProjectCostRow, error)

GetCostInTimeRange returns the total cost for sessions that overlap with the given time range. A session overlaps if it was created before the range ends and last updated after the range starts. Pass zero-value times to leave either bound open.

func (*Store) GetProject

func (l *Store) GetProject(projectID, agentType string) (*ProjectRow, error)

GetProject returns a project by its compound key, or nil if not found.

func (*Store) GetProjectByContainerName

func (l *Store) GetProjectByContainerName(containerName string) (*ProjectRow, error)

GetProjectByContainerName returns a project by its Docker container name, or nil if not found.

func (*Store) GetProjectTotalCost

func (l *Store) GetProjectTotalCost(projectID, agentType string) (ProjectCostRow, error)

GetProjectTotalCost returns the cumulative cost for a single project+agent pair.

func (*Store) GetProjectsByPath added in v0.5.0

func (l *Store) GetProjectsByPath(hostPath string) ([]*ProjectRow, error)

GetProjectsByPath returns all projects at a host path (one per agent type).

func (*Store) GetSetting

func (l *Store) GetSetting(key, defaultValue string) string

GetSetting returns the value for a settings key, or the provided default if the key does not exist.

func (*Store) HasProject

func (l *Store) HasProject(projectID, agentType string) (bool, error)

HasProject reports whether a project with the given compound key exists.

func (*Store) InsertAccessItem added in v0.4.0

func (l *Store) InsertAccessItem(item AccessItemRow) error

InsertAccessItem adds a user-created access item to the database.

func (*Store) InsertProject

func (l *Store) InsertProject(p ProjectRow) error

InsertProject adds a project to the database. If a project with the same project ID already exists, it is replaced (upsert).

func (*Store) ListAccessItems added in v0.4.0

func (l *Store) ListAccessItems() ([]AccessItemRow, error)

ListAccessItems returns all user-created access items.

func (*Store) ListAllProjects

func (l *Store) ListAllProjects() ([]*ProjectRow, error)

ListAllProjects returns all projects as a flat slice ordered by insertion time.

func (*Store) ListProjectKeys added in v0.5.0

func (l *Store) ListProjectKeys() ([]ProjectAgentKey, error)

ListProjectKeys returns all project+agent pairs in insertion order.

func (*Store) ListSessionCosts added in v1.8.0

func (l *Store) ListSessionCosts(projectID, agentType string) ([]SessionCostRow, error)

ListSessionCosts returns per-session cost data for a project+agent pair.

func (*Store) LoadTailerOffset added in v1.5.0

func (l *Store) LoadTailerOffset(projectID, agentType, filePath string) (int64, error)

LoadTailerOffset returns the stored byte offset for a tailed file. Returns 0 if no offset is stored.

func (*Store) Query

func (l *Store) Query(filters QueryFilters) ([]Entry, error)

Query returns entries matching the given filters, sorted by timestamp (newest first). Zero-value filter fields are ignored.

func (*Store) QueryAuditSummary

func (l *Store) QueryAuditSummary(filters QueryFilters) (*AuditSummaryRow, error)

QueryAuditSummary returns aggregate audit statistics matching the given filters. Only ProjectID, Worktree, Since, and Until fields are used for filtering.

func (*Store) QueryTopTools

func (l *Store) QueryTopTools(filters QueryFilters, limit int) ([]ToolCountRow, error)

QueryTopTools returns the most frequently used tools from tool_use events. Only ProjectID, Worktree, Since, and Until fields are used for filtering.

func (*Store) Read

func (l *Store) Read() ([]Entry, error)

Read returns all entries sorted by timestamp (newest first). This is a convenience wrapper around [Query] with empty filters.

func (*Store) SaveTailerOffset added in v1.5.0

func (l *Store) SaveTailerOffset(projectID, agentType, filePath string, offset int64) error

SaveTailerOffset persists the byte offset for a tailed file (upsert).

func (*Store) SetSetting

func (l *Store) SetSetting(key, value string) error

SetSetting writes a key-value pair to the settings table (upsert).

func (*Store) UpdateAccessItem added in v0.4.0

func (l *Store) UpdateAccessItem(item AccessItemRow) error

UpdateAccessItem updates a user-created access item.

func (*Store) UpdateProjectContainer

func (l *Store) UpdateProjectContainer(projectID, agentType, containerID, containerName string) error

UpdateProjectContainer updates the container ID and name for a project. Used after container creation, rebuild, or deletion.

func (*Store) UpdateProjectSettings added in v0.5.0

func (l *Store) UpdateProjectSettings(projectID, agentType, name, containerName string, skipPermissions bool, costBudget float64, allowedDomains, forwardedPorts string) error

UpdateProjectSettings updates lightweight project settings that do not require container recreation (name, skip_permissions, cost_budget, container_name, allowed_domains, forwarded_ports). All other fields remain unchanged.

func (*Store) UpsertSessionCost

func (l *Store) UpsertSessionCost(projectID, agentType, sessionID string, cost float64, isEstimated bool) error

UpsertSessionCost persists cost for a specific agent session. Cost for a given session ID is monotonically non-decreasing, so upserting is always safe — we simply take the max of old and new values. Project total cost is computed as SUM(cost) across all sessions for a project.

func (*Store) Write

func (l *Store) Write(entry Entry) error

Write inserts an entry into the database.

type ToolCountRow

type ToolCountRow struct {
	Name  string
	Count int
}

ToolCountRow pairs a tool name with its invocation count.

Jump to

Keyboard shortcuts

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