2026-04-02 10:57:36 -04:00
package datastore
import (
"context"
"time"
2026-04-29 11:04:14 -04:00
domain2 "code.riskrancher.com/RiskRancher/core/pkg/domain"
2026-04-02 10:57:36 -04:00
)
func ( s * SQLiteStore ) UpdateAppConfig ( ctx context . Context , config domain2 . AppConfig ) error {
query := `
INSERT INTO app_config (id, timezone, business_start, business_end, default_extension_days)
VALUES (1, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
timezone = excluded.timezone,
business_start = excluded.business_start,
business_end = excluded.business_end,
default_extension_days = excluded.default_extension_days
`
_ , err := s . DB . ExecContext ( ctx , query , config . Timezone , config . BusinessStart , config . BusinessEnd , config . DefaultExtensionDays )
return err
}
func ( s * SQLiteStore ) GetAppConfig ( ctx context . Context ) ( domain2 . AppConfig , error ) {
var c domain2 . AppConfig
query := ` SELECT timezone, business_start, business_end, default_extension_days,
backup_enabled, backup_interval_hours, backup_retention_days
FROM app_config WHERE id = 1 `
err := s . DB . QueryRowContext ( ctx , query ) . Scan (
& c . Timezone , & c . BusinessStart , & c . BusinessEnd , & c . DefaultExtensionDays ,
& c . Backup . Enabled , & c . Backup . IntervalHours , & c . Backup . RetentionDays ,
)
return c , err
}
// buildSLAMap creates a fast 2D lookup table: map[Domain][Severity]Policy
func ( s * SQLiteStore ) buildSLAMap ( ctx context . Context ) ( map [ string ] map [ string ] domain2 . SLAPolicy , error ) {
policies , err := s . GetSLAPolicies ( ctx )
if err != nil {
return nil , err
}
slaMap := make ( map [ string ] map [ string ] domain2 . SLAPolicy )
for _ , p := range policies {
if slaMap [ p . Domain ] == nil {
slaMap [ p . Domain ] = make ( map [ string ] domain2 . SLAPolicy )
}
slaMap [ p . Domain ] [ p . Severity ] = p
}
return slaMap , nil
}
func ( s * SQLiteStore ) ExportSystemState ( ctx context . Context ) ( domain2 . ExportState , error ) {
var state domain2 . ExportState
state . Version = "1.1"
state . ExportedAt = time . Now ( ) . UTC ( ) . Format ( time . RFC3339 )
config , err := s . GetAppConfig ( ctx )
if err == nil {
state . AppConfig = config
}
slas , err := s . GetSLAPolicies ( ctx )
if err == nil {
state . SLAPolicies = slas
}
users , err := s . GetAllUsers ( ctx )
if err == nil {
for _ , u := range users {
u . PasswordHash = ""
state . Users = append ( state . Users , * u )
}
}
adapters , err := s . GetAdapters ( ctx )
if err == nil {
state . Adapters = adapters
}
query := ` SELECT id, domain, source, asset_identifier, title, COALESCE(description, ''), severity, status, dedupe_hash, created_at FROM tickets `
rows , err := s . DB . QueryContext ( ctx , query )
if err != nil {
return state , err
}
defer rows . Close ( )
for rows . Next ( ) {
var t domain2 . Ticket
if err := rows . Scan ( & t . ID , & t . Domain , & t . Source , & t . AssetIdentifier , & t . Title , & t . Description , & t . Severity , & t . Status , & t . DedupeHash , & t . CreatedAt ) ; err == nil {
state . Tickets = append ( state . Tickets , t )
}
}
return state , nil
}
func ( s * SQLiteStore ) UpdateBackupPolicy ( ctx context . Context , policy domain2 . BackupPolicy ) error {
_ , err := s . DB . ExecContext ( ctx , `
UPDATE app_config
SET backup_enabled = ?, backup_interval_hours = ?, backup_retention_days = ?
WHERE id = 1 ` ,
policy . Enabled , policy . IntervalHours , policy . RetentionDays )
return err
}
func ( s * SQLiteStore ) GetSLAPolicies ( ctx context . Context ) ( [ ] domain2 . SLAPolicy , error ) {
rows , err := s . DB . QueryContext ( ctx , "SELECT domain, severity, days_to_remediate, max_extensions, days_to_triage FROM sla_policies ORDER BY domain, severity" )
if err != nil {
return nil , err
}
defer rows . Close ( )
var policies [ ] domain2 . SLAPolicy
for rows . Next ( ) {
var p domain2 . SLAPolicy
rows . Scan ( & p . Domain , & p . Severity , & p . DaysToRemediate , & p . MaxExtensions , & p . DaysToTriage )
policies = append ( policies , p )
}
return policies , nil
}
func ( s * SQLiteStore ) UpdateSLAPolicies ( ctx context . Context , slas [ ] domain2 . SLAPolicy ) error {
tx , err := s . DB . BeginTx ( ctx , nil )
if err != nil {
return err
}
defer tx . Rollback ( )
stmt , err := tx . PrepareContext ( ctx , `
UPDATE sla_policies
SET days_to_triage = ?, days_to_remediate = ?, max_extensions = ?
WHERE domain = ? AND severity = ? ` )
if err != nil {
return err
}
defer stmt . Close ( )
for _ , sla := range slas {
_ , err = stmt . ExecContext ( ctx , sla . DaysToTriage , sla . DaysToRemediate , sla . MaxExtensions , sla . Domain , sla . Severity )
if err != nil {
return err
}
}
return tx . Commit ( )
}
func ( s * SQLiteStore ) GetWranglers ( ctx context . Context ) ( [ ] domain2 . User , error ) {
query := `
SELECT id, email, full_name, global_role, is_active, created_at
FROM users
WHERE global_role = 'Wrangler' AND is_active = 1
ORDER BY email ASC
`
rows , err := s . DB . QueryContext ( ctx , query )
if err != nil {
return nil , err
}
defer rows . Close ( )
var wranglers [ ] domain2 . User
for rows . Next ( ) {
var w domain2 . User
if err := rows . Scan ( & w . ID , & w . Email , & w . FullName , & w . GlobalRole , & w . IsActive , & w . CreatedAt ) ; err != nil {
return nil , err
}
wranglers = append ( wranglers , w )
}
return wranglers , nil
}