test(05-01): add failing tests for findings verify columns
- Round-trip verify fields (Verified, VerifyStatus, VerifyHTTPCode, VerifyMetadata) - Empty verify fields persist as defaults - Legacy DB schema migrates verify columns idempotently
This commit is contained in:
147
pkg/storage/findings_test.go
Normal file
147
pkg/storage/findings_test.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package storage_test
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"testing"
|
||||
|
||||
"github.com/salvacybersec/keyhunter/pkg/storage"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
func makeTestKey() []byte {
|
||||
k := make([]byte, 32)
|
||||
for i := range k {
|
||||
k[i] = byte(i)
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
func TestSaveFinding_VerifyFields_RoundTrip(t *testing.T) {
|
||||
db, err := storage.Open(":memory:")
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
encKey := makeTestKey()
|
||||
|
||||
f := storage.Finding{
|
||||
ProviderName: "openai",
|
||||
KeyValue: "sk-proj-abcdefghijklmnop1234",
|
||||
Confidence: "high",
|
||||
SourcePath: "/tmp/test.env",
|
||||
SourceType: "file",
|
||||
LineNumber: 12,
|
||||
Verified: true,
|
||||
VerifyStatus: "live",
|
||||
VerifyHTTPCode: 200,
|
||||
VerifyMetadata: map[string]string{"org": "Acme", "tier": "plus"},
|
||||
}
|
||||
_, err = db.SaveFinding(f, encKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := db.ListFindings(encKey)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, out, 1)
|
||||
|
||||
got := out[0]
|
||||
assert.True(t, got.Verified)
|
||||
assert.Equal(t, "live", got.VerifyStatus)
|
||||
assert.Equal(t, 200, got.VerifyHTTPCode)
|
||||
assert.Equal(t, "Acme", got.VerifyMetadata["org"])
|
||||
assert.Equal(t, "plus", got.VerifyMetadata["tier"])
|
||||
assert.Equal(t, f.KeyValue, got.KeyValue)
|
||||
}
|
||||
|
||||
func TestSaveFinding_VerifyFields_Empty(t *testing.T) {
|
||||
db, err := storage.Open(":memory:")
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
encKey := makeTestKey()
|
||||
|
||||
f := storage.Finding{
|
||||
ProviderName: "anthropic",
|
||||
KeyValue: "sk-ant-api03-abcdefghij1234",
|
||||
Confidence: "medium",
|
||||
SourcePath: "/tmp/cfg.yaml",
|
||||
SourceType: "file",
|
||||
}
|
||||
_, err = db.SaveFinding(f, encKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := db.ListFindings(encKey)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, out, 1)
|
||||
|
||||
got := out[0]
|
||||
assert.False(t, got.Verified)
|
||||
assert.Equal(t, "", got.VerifyStatus)
|
||||
assert.Equal(t, 0, got.VerifyHTTPCode)
|
||||
assert.Nil(t, got.VerifyMetadata)
|
||||
}
|
||||
|
||||
func TestOpen_MigratesExistingDB(t *testing.T) {
|
||||
// Create a temp file-backed DB so we can close and reopen it.
|
||||
tmp := t.TempDir() + "/legacy.db"
|
||||
|
||||
// Bootstrap an OLD-schema findings table directly (no verify columns).
|
||||
raw, err := sql.Open("sqlite", tmp)
|
||||
require.NoError(t, err)
|
||||
_, err = raw.Exec(`CREATE TABLE findings (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
scan_id INTEGER,
|
||||
provider_name TEXT NOT NULL,
|
||||
key_value BLOB NOT NULL,
|
||||
key_masked TEXT NOT NULL,
|
||||
confidence TEXT NOT NULL,
|
||||
source_path TEXT,
|
||||
source_type TEXT,
|
||||
line_number INTEGER,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)`)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, raw.Close())
|
||||
|
||||
// Reopen via storage.Open — should migrate the table in-place.
|
||||
db, err := storage.Open(tmp)
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
rows, err := db.SQL().Query("PRAGMA table_info(findings)")
|
||||
require.NoError(t, err)
|
||||
defer rows.Close()
|
||||
|
||||
cols := map[string]bool{}
|
||||
for rows.Next() {
|
||||
var cid int
|
||||
var name, ctype string
|
||||
var notnull, pk int
|
||||
var dflt sql.NullString
|
||||
require.NoError(t, rows.Scan(&cid, &name, &ctype, ¬null, &dflt, &pk))
|
||||
cols[name] = true
|
||||
}
|
||||
assert.True(t, cols["verified"], "verified column missing")
|
||||
assert.True(t, cols["verify_status"], "verify_status column missing")
|
||||
assert.True(t, cols["verify_http_code"], "verify_http_code column missing")
|
||||
assert.True(t, cols["verify_metadata_json"], "verify_metadata_json column missing")
|
||||
|
||||
// And verify the round-trip still works after migration.
|
||||
encKey := makeTestKey()
|
||||
_, err = db.SaveFinding(storage.Finding{
|
||||
ProviderName: "groq",
|
||||
KeyValue: "gsk_abcdefghijklmnop1234",
|
||||
Confidence: "high",
|
||||
Verified: true,
|
||||
VerifyStatus: "live",
|
||||
VerifyHTTPCode: 200,
|
||||
VerifyMetadata: map[string]string{"model": "mixtral"},
|
||||
}, encKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := db.ListFindings(encKey)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, out, 1)
|
||||
assert.Equal(t, "live", out[0].VerifyStatus)
|
||||
assert.Equal(t, "mixtral", out[0].VerifyMetadata["model"])
|
||||
}
|
||||
Reference in New Issue
Block a user