- schema.sql: CREATE TABLE for findings, scans, settings with indexes - db.go: Open() with WAL mode, foreign keys, embedded schema migration - findings.go: SaveFinding encrypts key_value before INSERT, ListFindings decrypts after SELECT - MaskKey: first8...last4 masking helper - Fix: NULL scan_id handling for findings without parent scan
58 lines
1.3 KiB
Go
58 lines
1.3 KiB
Go
package storage
|
|
|
|
import (
|
|
"database/sql"
|
|
_ "embed"
|
|
"fmt"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
//go:embed schema.sql
|
|
var schemaSQLBytes []byte
|
|
|
|
// DB wraps the sql.DB connection with KeyHunter-specific behavior.
|
|
type DB struct {
|
|
sql *sql.DB
|
|
}
|
|
|
|
// Open opens or creates a SQLite database at path, runs embedded schema migrations,
|
|
// and enables WAL mode for better concurrent read performance.
|
|
// Use ":memory:" for tests.
|
|
func Open(path string) (*DB, error) {
|
|
sqlDB, err := sql.Open("sqlite", path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("opening database: %w", err)
|
|
}
|
|
|
|
// Enable WAL mode for concurrent reads
|
|
if _, err := sqlDB.Exec("PRAGMA journal_mode=WAL"); err != nil {
|
|
sqlDB.Close()
|
|
return nil, fmt.Errorf("enabling WAL mode: %w", err)
|
|
}
|
|
|
|
// Enable foreign keys
|
|
if _, err := sqlDB.Exec("PRAGMA foreign_keys=ON"); err != nil {
|
|
sqlDB.Close()
|
|
return nil, fmt.Errorf("enabling foreign keys: %w", err)
|
|
}
|
|
|
|
// Run schema migrations
|
|
if _, err := sqlDB.Exec(string(schemaSQLBytes)); err != nil {
|
|
sqlDB.Close()
|
|
return nil, fmt.Errorf("running schema migrations: %w", err)
|
|
}
|
|
|
|
return &DB{sql: sqlDB}, nil
|
|
}
|
|
|
|
// Close closes the underlying database connection.
|
|
func (db *DB) Close() error {
|
|
return db.sql.Close()
|
|
}
|
|
|
|
// SQL returns the underlying sql.DB for advanced use cases.
|
|
func (db *DB) SQL() *sql.DB {
|
|
return db.sql
|
|
}
|