package db import ( "database/sql" "fmt" ) // migrations is an ordered list of SQL DDL statements. Each index is the // migration version (1-based). var migrations = []string{ // Version 1: initial schema `CREATE TABLE IF NOT EXISTS seal_config ( id INTEGER PRIMARY KEY CHECK (id = 1), encrypted_mek BLOB NOT NULL, kdf_salt BLOB NOT NULL, argon2_time INTEGER NOT NULL, argon2_memory INTEGER NOT NULL, argon2_threads INTEGER NOT NULL, initialized_at DATETIME NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE IF NOT EXISTS barrier_entries ( path TEXT PRIMARY KEY, value BLOB NOT NULL, created_at DATETIME NOT NULL DEFAULT (datetime('now')), updated_at DATETIME NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE IF NOT EXISTS schema_migrations ( version INTEGER PRIMARY KEY, applied_at DATETIME NOT NULL DEFAULT (datetime('now')) );`, // Version 2: barrier key registry for per-engine DEKs `CREATE TABLE IF NOT EXISTS barrier_keys ( key_id TEXT PRIMARY KEY, version INTEGER NOT NULL DEFAULT 1, encrypted_dek BLOB NOT NULL, created_at DATETIME NOT NULL DEFAULT (datetime('now')), rotated_at DATETIME NOT NULL DEFAULT (datetime('now')) );`, } // Migrate applies all pending migrations. func Migrate(db *sql.DB) error { // Ensure the migrations table exists (bootstrap). if _, err := db.Exec(`CREATE TABLE IF NOT EXISTS schema_migrations ( version INTEGER PRIMARY KEY, applied_at DATETIME NOT NULL DEFAULT (datetime('now')) )`); err != nil { return fmt.Errorf("db: create migrations table: %w", err) } var current int row := db.QueryRow("SELECT COALESCE(MAX(version), 0) FROM schema_migrations") if err := row.Scan(¤t); err != nil { return fmt.Errorf("db: get migration version: %w", err) } for i := current; i < len(migrations); i++ { version := i + 1 tx, err := db.Begin() if err != nil { return fmt.Errorf("db: begin migration %d: %w", version, err) } if _, err := tx.Exec(migrations[i]); err != nil { _ = tx.Rollback() return fmt.Errorf("db: migration %d: %w", version, err) } if _, err := tx.Exec("INSERT INTO schema_migrations (version) VALUES (?)", version); err != nil { _ = tx.Rollback() return fmt.Errorf("db: record migration %d: %w", version, err) } if err := tx.Commit(); err != nil { return fmt.Errorf("db: commit migration %d: %w", version, err) } } return nil }