feat(05-01): migrate findings schema with verify_* columns
- schema.sql: new findings columns verified, verify_status, verify_http_code, verify_metadata_json - db.go: migrateFindingsVerifyColumns runs on Open() for legacy DBs using PRAGMA table_info + ALTER TABLE - findings.go: Finding struct gains Verified/VerifyStatus/VerifyHTTPCode/VerifyMetadata - SaveFinding serializes verify metadata as JSON (NULL when nil) - ListFindings round-trips all verify fields
This commit is contained in:
@@ -43,9 +43,64 @@ func Open(path string) (*DB, error) {
|
||||
return nil, fmt.Errorf("running schema migrations: %w", err)
|
||||
}
|
||||
|
||||
// Idempotent in-place migration for pre-Phase-5 databases that created
|
||||
// the findings table before the verify_* columns existed.
|
||||
if err := migrateFindingsVerifyColumns(sqlDB); err != nil {
|
||||
sqlDB.Close()
|
||||
return nil, fmt.Errorf("migrating findings verify columns: %w", err)
|
||||
}
|
||||
|
||||
return &DB{sql: sqlDB}, nil
|
||||
}
|
||||
|
||||
// migrateFindingsVerifyColumns adds the Phase 5 verify_* columns to an
|
||||
// existing findings table when they are missing. Uses PRAGMA table_info to
|
||||
// detect the current column set (works on SQLite versions that lack
|
||||
// ADD COLUMN IF NOT EXISTS).
|
||||
func migrateFindingsVerifyColumns(sqlDB *sql.DB) error {
|
||||
rows, err := sqlDB.Query("PRAGMA table_info(findings)")
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading findings schema: %w", err)
|
||||
}
|
||||
existing := map[string]bool{}
|
||||
for rows.Next() {
|
||||
var cid int
|
||||
var name, ctype string
|
||||
var notnull, pk int
|
||||
var dflt sql.NullString
|
||||
if err := rows.Scan(&cid, &name, &ctype, ¬null, &dflt, &pk); err != nil {
|
||||
rows.Close()
|
||||
return fmt.Errorf("scanning findings schema row: %w", err)
|
||||
}
|
||||
existing[name] = true
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
rows.Close()
|
||||
return err
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
type colDef struct {
|
||||
name string
|
||||
ddl string
|
||||
}
|
||||
wanted := []colDef{
|
||||
{"verified", "ALTER TABLE findings ADD COLUMN verified INTEGER NOT NULL DEFAULT 0"},
|
||||
{"verify_status", "ALTER TABLE findings ADD COLUMN verify_status TEXT NOT NULL DEFAULT ''"},
|
||||
{"verify_http_code", "ALTER TABLE findings ADD COLUMN verify_http_code INTEGER NOT NULL DEFAULT 0"},
|
||||
{"verify_metadata_json", "ALTER TABLE findings ADD COLUMN verify_metadata_json TEXT"},
|
||||
}
|
||||
for _, c := range wanted {
|
||||
if existing[c.name] {
|
||||
continue
|
||||
}
|
||||
if _, err := sqlDB.Exec(c.ddl); err != nil {
|
||||
return fmt.Errorf("adding column %s: %w", c.name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the underlying database connection.
|
||||
func (db *DB) Close() error {
|
||||
return db.sql.Close()
|
||||
|
||||
Reference in New Issue
Block a user