Documentation
¶
Overview ¶
Package systemconfig is the runtime config store. Operator-tunable values land here as one row per key in the system_config table, with JSONB values typed by per-config-domain structs.
Spec: specs/services/connectivity-config.spec.yaml (the first consumer). Future config domains (compliance scheduler, retention, alert thresholds) land alongside without schema changes.
Key namespaces are managed inline (one per config struct). The Get/Set helpers operate on raw JSONB; consumers wrap them with a typed Load/Save (e.g., LoadConnectivity, SetConnectivity).
Defaults: when no row exists for a key, Load* returns the baked-in defaults the calling consumer defines. No "initial seed" migration — the absence of a row is itself a meaningful state ("never configured, defaults apply").
Audit: every Set emits audit.SystemConfigChanged with {config_key, old_value, new_value, changed_by}. The old_value is captured in the same transaction so concurrent writes can't race it into incoherence.
Index ¶
- Constants
- Variables
- type ComplianceConfig
- type ConnectivityConfig
- type DiscoveryConfig
- type EmitFunc
- type IntelligenceConfig
- type ScanConfig
- type ScanVariables
- type SecurityConfig
- type Store
- func (s *Store) LoadCompliance(ctx context.Context) (ComplianceConfig, error)
- func (s *Store) LoadConnectivity(ctx context.Context) (ConnectivityConfig, error)
- func (s *Store) LoadDiscovery(ctx context.Context) (DiscoveryConfig, error)
- func (s *Store) LoadIntelligence(ctx context.Context) (IntelligenceConfig, error)
- func (s *Store) LoadScan(ctx context.Context) (ScanConfig, error)
- func (s *Store) LoadScanVars(ctx context.Context) (ScanVariables, error)
- func (s *Store) LoadSecurity(ctx context.Context) (SecurityConfig, error)
- func (s *Store) SetCompliance(ctx context.Context, cfg ComplianceConfig, changedBy string) (ComplianceConfig, error)
- func (s *Store) SetConnectivity(ctx context.Context, cfg ConnectivityConfig, changedBy string) error
- func (s *Store) SetDiscovery(ctx context.Context, cfg DiscoveryConfig, changedBy string) error
- func (s *Store) SetIntelligence(ctx context.Context, cfg IntelligenceConfig, changedBy string) error
- func (s *Store) SetScan(ctx context.Context, cfg ScanConfig, changedBy string) (ScanConfig, error)
- func (s *Store) SetScanVars(ctx context.Context, vars ScanVariables, changedBy string) error
Constants ¶
const ( KeyConnectivity = "connectivity" KeyIntelligence = "intelligence" KeySecurity = "security" KeyDiscovery = "discovery" KeyScan = "scan" KeyScanVars = "scan_variables" KeyCompliance = "compliance" )
Key namespaces. One constant per config domain — keep them grouped here so the audit trail's config_key field has a stable enum.
const ( ScanIntervalMinFloor = 5 ScanIntervalMaxCap = 2880 )
ScanIntervalMinFloor / ScanIntervalMaxCap bound the ladder values in minutes. They mirror scheduler.MinIntervalFloor / MaxIntervalCap; duplicated as ints here so systemconfig does not import the scheduler package.
const ( ScanVarsMaxCount = 200 ScanVarsMaxValueLen = 4096 ScanVarsMaxNameLen = 128 )
Bounds for ScanVariables.Validate. The corpus uses ~20 variables; 200 names is far above any legitimate use. Values are shell-safe template substitutions (paths, hostnames, banner text) — 4 KiB covers a long login banner with margin.
const ComplianceMaxEnabledFrameworks = 32
ComplianceMaxEnabledFrameworks caps the allowlist. The corpus has a handful of families (stig, cis, nist_800_53, pci_dss_4, srg); 32 is far above any real use and just blocks an abuse shape.
Variables ¶
var ErrInvalidConfig = errors.New("systemconfig: invalid config")
ErrInvalidConfig is returned by validation when a field is out of bounds. Wrap with %w so callers can errors.Is(err, ErrInvalidConfig).
Functions ¶
This section is empty.
Types ¶
type ComplianceConfig ¶ added in v0.4.0
type ComplianceConfig struct {
DefaultFramework string `json:"default_framework"`
// EnabledFrameworks is the Phase 2 allowlist: the framework FAMILY ids an
// admin has opted the org into. Empty means ALL families found in the
// corpus are available as lenses (the factory default and every existing
// stored row). A non-empty list restricts the lens picker + the frameworks
// endpoint to these families.
EnabledFrameworks []string `json:"enabled_frameworks,omitempty"`
}
ComplianceConfig holds org-wide compliance-DISPLAY settings. Phase 1 carries only the default lens: the framework FAMILY the score surfaces (dashboard avg-compliance, hosts list, host detail) default to. An empty value means "All rules" — the full Kensa corpus, an honest framework-agnostic baseline and the factory default. A non-empty value is a family id (e.g. "stig", "cis", "nist_800_53") resolved per-host to the OS-specific corpus key at query time (internal/framework); an unknown/absent family falls back to all-rules.
func DefaultCompliance ¶ added in v0.4.0
func DefaultCompliance() ComplianceConfig
DefaultCompliance returns the baked-in default: All rules (empty lens), all families enabled.
func (ComplianceConfig) Validate ¶ added in v0.4.0
func (c ComplianceConfig) Validate() error
Validate bounds the default family id and the enabled-frameworks allowlist. An empty default (All rules) is always valid. When the allowlist is non-empty, a non-empty default MUST be one of the enabled families, so an admin cannot default the org to a hidden family.
type ConnectivityConfig ¶
type ConnectivityConfig struct {
// Per-state probe intervals in seconds. v1.1.0 NEW.
OnlineSec int `json:"online_sec"`
DegradedSec int `json:"degraded_sec"`
CriticalSec int `json:"critical_sec"`
DownSec int `json:"down_sec"`
MaintenanceSec int `json:"maintenance_sec"`
TimeoutSec int `json:"timeout_sec"`
UnreachableThreshold int `json:"unreachable_threshold"`
RateLimit int `json:"rate_limit"`
MaintenanceGlobal bool `json:"maintenance_global"`
}
ConnectivityConfig is the typed shape stored under KeyConnectivity.
Spec: services-connectivity-config v1.1.0 C-01 + C-02. Per-state intervals replace the v1.0.0 single IntervalSec — the liveness loop computes each host's next_probe_at from the band the host is in (Online / Degraded / Critical / Down).
Maintenance band stays here as a persisted config so the UI can edit it, but the loop doesn't read it yet — per-host maintenance is in the backlog. MaintenanceGlobal still pauses the whole loop.
func DefaultConnectivity ¶
func DefaultConnectivity() ConnectivityConfig
DefaultConnectivity returns the baked-in defaults — the band table in services-connectivity-config v1.1.0.
Online — 15m (consec=0, reachable: nothing's changing) Degraded — 5m (consec>=1, reachable: watch closely) Critical — 2m (consec<3, unreachable: confirm fast) Down — 30m (consec>=3: back off, don't hammer dead) Maintenance — 60m (UI/persisted band, not yet auto-applied)
func (ConnectivityConfig) Validate ¶
func (c ConnectivityConfig) Validate() error
Validate enforces the bounds in services-connectivity-config C-01. Returns a wrapped ErrInvalidConfig naming the offending field.
type DiscoveryConfig ¶
type DiscoveryConfig struct {
IntervalSec int `json:"interval_sec"`
RateLimit int `json:"rate_limit"`
DetectOnFirstContact bool `json:"detect_on_first_contact"`
MaintenanceGlobal bool `json:"maintenance_global"`
}
DiscoveryConfig is the typed shape stored under KeyDiscovery.
Spec: system-discovery-scheduler v1.0.0 C-04 + C-05.
IntervalSec is the per-host cadence the scheduler treats as "due again"; a host with os_discovered_at older than now() - IntervalSec re-enters listDiscoveryTargets. RateLimit caps the number of jobs enqueued per tick — bounds the thundering-herd shape when many hosts hit NULL os_discovered_at at once. DetectOnFirstContact gates the host-create auto-enqueue (when false, new hosts stay NULL until the sweeper or an explicit operator click finds them). MaintenanceGlobal pauses the entire scheduler loop.
func DefaultDiscovery ¶
func DefaultDiscovery() DiscoveryConfig
DefaultDiscovery returns the baked-in defaults.
IntervalSec — 86400 (24h per host) RateLimit — 25 (max jobs enqueued per tick) DetectOnFirstContact — true (host create still auto-fingerprints) MaintenanceGlobal — false
func (DiscoveryConfig) Validate ¶
func (c DiscoveryConfig) Validate() error
Validate enforces the bounds in system-discovery-scheduler C-04, C-05. Returns a wrapped ErrInvalidConfig naming the offending field.
type EmitFunc ¶
EmitFunc mirrors audit.Emit's signature so callers can substitute a no-op or capture-into-buffer for tests. Production wires audit.Emit.
type IntelligenceConfig ¶
type IntelligenceConfig struct {
IntervalSec int `json:"interval_sec"`
RateLimit int `json:"rate_limit"`
MaintenanceGlobal bool `json:"maintenance_global"`
}
IntelligenceConfig is the typed shape stored under KeyIntelligence.
Spec: system-intelligence-scheduler v1.0.0 C-06 + C-07.
IntervalSec is the per-host cadence the scheduler advances next_intelligence_at by after a successful RunCycle. RateLimit caps the bounded worker pool the scheduler uses to dispatch per-tick. MaintenanceGlobal pauses the entire loop (mirrors the connectivity flag).
func DefaultIntelligence ¶
func DefaultIntelligence() IntelligenceConfig
DefaultIntelligence returns the baked-in defaults.
IntervalSec — 3600 (1 hour per host) RateLimit — 10 (concurrent RunCycles per scheduler) MaintenanceGlobal — false
func (IntelligenceConfig) Validate ¶
func (c IntelligenceConfig) Validate() error
Validate enforces the bounds in system-intelligence-scheduler C-06, C-07. Returns a wrapped ErrInvalidConfig naming the offending field.
type ScanConfig ¶
type ScanConfig struct {
Enabled bool `json:"enabled"`
// Per-state scan intervals in minutes — the tier ladder.
UnknownMins int `json:"unknown_mins"`
CriticalMins int `json:"critical_mins"`
NonCompliantMins int `json:"non_compliant_mins"`
PartialMins int `json:"partial_mins"`
MostlyCompliantMins int `json:"mostly_compliant_mins"`
CompliantMins int `json:"compliant_mins"`
// RateLimit caps hosts dispatched per scheduler tick (1..100).
RateLimit int `json:"rate_limit"`
// MaintenanceGlobal pauses the entire dispatch loop (mirrors the
// connectivity / intelligence / discovery flags).
MaintenanceGlobal bool `json:"maintenance_global"`
}
ScanConfig is the typed shape stored under KeyScan — the adaptive compliance scan scheduler's operator-editable knobs.
Spec: system-scheduler v3.0.0 C-01 (tier ladder from systemconfig, replacing the v2 signed schedules-policy file per scan plan decision #4) + api-system-scan-config.
The six *Mins fields are the tier ladder: how long after a scan a host in that compliance state waits before its next scheduled scan. Riskier states re-scan sooner. Values are minutes; the scheduler clamps them into [5m, 48h] at load time (C-08), and Normalize applies the same clamp at PUT time so what the operator reads back is what the scheduler runs.
func DefaultScan ¶
func DefaultScan() ScanConfig
DefaultScan returns the baked-in defaults. Auto-scan is ON by default (the OpenWatch OS model is auto-scan centric); the ladder re-scans riskier states sooner.
unknown — 360m (6h: classified on first scan anyway) critical — 240m (4h) non_compliant — 480m (8h) partial — 720m (12h) mostly_compliant — 1440m (24h) compliant — 2880m (48h ceiling) rate_limit — 25 hosts per tick
func (ScanConfig) Normalize ¶
func (c ScanConfig) Normalize() ScanConfig
Normalize returns a copy with every ladder value clamped into [ScanIntervalMinFloor, ScanIntervalMaxCap] and the rate limit into [1, 100]. PUT /system/scan/config clamps rather than rejects (scan plan Phase 4: "server clamps to the scheduler's bounds") so operator typos degrade safely instead of bouncing the whole save.
func (ScanConfig) Validate ¶
func (c ScanConfig) Validate() error
Validate is satisfied by construction after Normalize — kept so the store's Set path stays uniform with the sibling configs. It rejects values Normalize would have fixed, catching callers that skip it.
type ScanVariables ¶
ScanVariables is the typed shape stored under KeyScanVars: operator overrides for the kensa rule-template variables, name -> value. Only OVERRIDES are stored — names absent here resolve to kensa's built-in defaults at rule-load time (LoadRules merges caller vars over BuiltInVars). The global tier only; per-group/per-host tiers are a later phase per the ratified Kensa boundary.
Spec: api-system-scan-config v1.1.0 (scan variables endpoints).
func (ScanVariables) Validate ¶
func (v ScanVariables) Validate() error
Validate bounds the override map. Name VALIDITY (is this a variable the corpus actually uses?) is the HTTP handler's job — it holds the kensa variable catalog; this store-side check only blocks abuse shapes (oversized maps, empty or huge names, huge values).
type SecurityConfig ¶
type SecurityConfig struct {
AllowCredentialSudoPassword bool `json:"allow_credential_sudo_password"`
// WarnDaysBeforePasswordExpiry is how many days ahead of a host
// user's password expiry the daily sweep raises a notification.
// Default 14; must be in [1, 365]. Spec system-account-policy C-03.
WarnDaysBeforePasswordExpiry int `json:"warn_days_before_password_expiry"`
}
SecurityConfig is the typed shape stored under KeySecurity.
Spec: system-ssh-connectivity v1.1.0 C-09..C-12.
AllowCredentialSudoPassword is the policy knob that gates the sudo -S password fallback in the SSH dial layer. Defaults to TRUE: OpenWatch supports the full SSH matrix out of the box (key or password auth, NOPASSWD or password sudo), so a host that needs a sudo password is reachable on a fresh install with no extra configuration. The flag is retained as a kill-switch — a site that forbids feeding credential passwords to remote sudo can set it false, and every privilege path degrades to `sudo -n` only.
func DefaultSecurity ¶
func DefaultSecurity() SecurityConfig
DefaultSecurity returns the baked-in defaults. The sudo -S password fallback is ON by default (kill-switch, not opt-in).
func (SecurityConfig) Validate ¶
func (c SecurityConfig) Validate() error
Validate bounds the password-expiry warn window to [1, 365] days. A zero value is treated as "unset" and coerced to the default by the resolver, so it is not itself an error here.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store reads and writes typed config from system_config.
func NewStore ¶
NewStore returns a Store backed by the given pool. emit may be audit.Emit in production; tests can pass a capture function.
func (*Store) LoadCompliance ¶ added in v0.4.0
func (s *Store) LoadCompliance(ctx context.Context) (ComplianceConfig, error)
LoadCompliance returns the persisted compliance-display config, or DefaultCompliance (All rules) when no row exists. Only returns an error for DB / unmarshal failures.
func (*Store) LoadConnectivity ¶
func (s *Store) LoadConnectivity(ctx context.Context) (ConnectivityConfig, error)
LoadConnectivity returns the persisted ConnectivityConfig OR DefaultConnectivity when no row exists for KeyConnectivity. Only returns an error for DB / unmarshal failures — "no row" is not an error.
Spec services-connectivity-config AC-01 / C-02.
func (*Store) LoadDiscovery ¶
func (s *Store) LoadDiscovery(ctx context.Context) (DiscoveryConfig, error)
LoadDiscovery returns the persisted DiscoveryConfig OR DefaultDiscovery when no row exists for KeyDiscovery. Only returns an error for DB / unmarshal failures.
Spec api-system-discovery-config AC-01.
func (*Store) LoadIntelligence ¶
func (s *Store) LoadIntelligence(ctx context.Context) (IntelligenceConfig, error)
LoadIntelligence returns the persisted IntelligenceConfig OR DefaultIntelligence when no row exists for KeyIntelligence. Only returns an error for DB / unmarshal failures.
Spec api-system-intelligence-config AC-01.
func (*Store) LoadScan ¶
func (s *Store) LoadScan(ctx context.Context) (ScanConfig, error)
LoadScan returns the persisted ScanConfig OR DefaultScan when no row exists for KeyScan. Only returns an error for DB / unmarshal failures — "no row" is not an error.
Spec api-system-scan-config AC-01.
func (*Store) LoadScanVars ¶
func (s *Store) LoadScanVars(ctx context.Context) (ScanVariables, error)
LoadScanVars returns the persisted operator variable overrides, or an empty map when none exist. Only returns an error for DB / unmarshal failures.
Spec api-system-scan-config v1.1.0.
func (*Store) LoadSecurity ¶
func (s *Store) LoadSecurity(ctx context.Context) (SecurityConfig, error)
LoadSecurity returns the persisted SecurityConfig OR DefaultSecurity when no row exists for KeySecurity. Only returns an error for DB / unmarshal failures.
Spec system-ssh-connectivity v1.1.0 C-09.
func (*Store) SetCompliance ¶ added in v0.4.0
func (s *Store) SetCompliance(ctx context.Context, cfg ComplianceConfig, changedBy string) (ComplianceConfig, error)
SetCompliance validates and persists the compliance-display config, emitting a SystemConfigChanged audit event with the old + new value.
func (*Store) SetConnectivity ¶
func (s *Store) SetConnectivity(ctx context.Context, cfg ConnectivityConfig, changedBy string) error
SetConnectivity validates the input, UPSERTs the row, and emits audit.SystemConfigChanged with the old + new snapshot captured in the same transaction.
Spec services-connectivity-config AC-02 / C-03 / C-07.
func (*Store) SetDiscovery ¶
SetDiscovery validates the input, UPSERTs the row, and emits audit.SystemConfigChanged with the old + new snapshot captured in the same transaction.
Spec api-system-discovery-config AC-03 / AC-05 / AC-07.
func (*Store) SetIntelligence ¶
func (s *Store) SetIntelligence(ctx context.Context, cfg IntelligenceConfig, changedBy string) error
SetIntelligence validates the input, UPSERTs the row, and emits audit.SystemConfigChanged with the old + new snapshot captured in the same transaction.
Spec api-system-intelligence-config AC-03 / AC-05 / AC-08.
func (*Store) SetScan ¶
func (s *Store) SetScan(ctx context.Context, cfg ScanConfig, changedBy string) (ScanConfig, error)
SetScan normalizes (clamps) the input, validates, UPSERTs the row, and emits audit.SystemConfigChanged with the old + new snapshot. Returns the normalized config that was actually persisted so the handler can echo back the clamped values.
Spec api-system-scan-config AC-03 (clamp-not-reject) / AC-05.
func (*Store) SetScanVars ¶
SetScanVars validates and persists the FULL override map (PUT replaces, not merges) and emits audit.SystemConfigChanged with the old + new snapshots.
Spec api-system-scan-config v1.1.0.