feat(01-foundation-03): implement SQLite storage with Finding CRUD and encryption
- 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
This commit is contained in:
57
pkg/storage/db.go
Normal file
57
pkg/storage/db.go
Normal file
@@ -0,0 +1,57 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user