feat(monitor/collectors/ransomware): victims repository with idempotent insert

This commit is contained in:
CarterPerez-dev 2026-05-01 22:45:23 -04:00
parent bdca22ee50
commit 01a22dc7e4
2 changed files with 147 additions and 0 deletions

View File

@ -0,0 +1,60 @@
// ©AngelaMos | 2026
// repo.go
package ransomware
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/jmoiron/sqlx"
"github.com/lib/pq"
)
type Row struct {
ID string `db:"id"`
PostTitle string `db:"post_title"`
GroupName string `db:"group_name"`
DiscoveredAt time.Time `db:"discovered_at"`
Country string `db:"country"`
Sector string `db:"sector"`
Payload json.RawMessage `db:"payload"`
}
type Repo struct {
db *sqlx.DB
}
func NewRepo(db *sqlx.DB) *Repo { return &Repo{db: db} }
func (r *Repo) Insert(ctx context.Context, row Row) error {
_, err := r.db.ExecContext(ctx, `
INSERT INTO ransomware_victims
(id, post_title, group_name, discovered_at, country, sector, payload)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (id) DO NOTHING`,
row.ID, row.PostTitle, row.GroupName, row.DiscoveredAt, row.Country, row.Sector, []byte(row.Payload),
)
if err != nil {
return fmt.Errorf("insert ransom %s: %w", row.ID, err)
}
return nil
}
func (r *Repo) KnownIDs(ctx context.Context, ids []string) (map[string]bool, error) {
if len(ids) == 0 {
return map[string]bool{}, nil
}
var found []string
if err := r.db.SelectContext(ctx, &found,
`SELECT id FROM ransomware_victims WHERE id = ANY($1::text[])`, pq.Array(ids)); err != nil {
return nil, fmt.Errorf("ransom known ids: %w", err)
}
out := make(map[string]bool, len(found))
for _, id := range found {
out[id] = true
}
return out, nil
}

View File

@ -0,0 +1,87 @@
// ©AngelaMos | 2026
// repo_test.go
package ransomware_test
import (
"context"
"encoding/json"
"testing"
"time"
_ "github.com/jackc/pgx/v5/stdlib"
"github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go/modules/postgres"
"github.com/carterperez-dev/monitor-the-situation/backend/internal/collectors/ransomware"
)
func setupDB(t *testing.T) *sqlx.DB {
t.Helper()
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()
pg, err := postgres.Run(ctx, "postgres:17-alpine",
postgres.WithDatabase("monitor"),
postgres.WithUsername("monitor"),
postgres.WithPassword("monitor"),
postgres.BasicWaitStrategies(),
)
require.NoError(t, err)
t.Cleanup(func() { _ = pg.Terminate(context.Background()) })
dsn, err := pg.ConnectionString(ctx, "sslmode=disable")
require.NoError(t, err)
db, err := sqlx.ConnectContext(ctx, "pgx", dsn)
require.NoError(t, err)
t.Cleanup(func() { _ = db.Close() })
_, err = db.ExecContext(ctx, `
CREATE TABLE ransomware_victims (
id text PRIMARY KEY,
post_title text NOT NULL,
group_name text NOT NULL,
discovered_at timestamptz NOT NULL,
country text NOT NULL DEFAULT '',
sector text NOT NULL DEFAULT '',
payload jsonb NOT NULL
)`)
require.NoError(t, err)
return db
}
func TestRepo_InsertIsIdempotent(t *testing.T) {
db := setupDB(t)
repo := ransomware.NewRepo(db)
ctx := context.Background()
row := ransomware.Row{
ID: "id-1",
PostTitle: "Acme Corp",
GroupName: "lockbit",
DiscoveredAt: time.Now().UTC(),
Country: "US",
Sector: "Healthcare",
Payload: json.RawMessage(`{}`),
}
require.NoError(t, repo.Insert(ctx, row))
require.NoError(t, repo.Insert(ctx, row))
known, err := repo.KnownIDs(ctx, []string{"id-1", "id-2"})
require.NoError(t, err)
require.True(t, known["id-1"])
require.False(t, known["id-2"])
}
func TestRepo_KnownIDsHandlesEmptySlice(t *testing.T) {
db := setupDB(t)
repo := ransomware.NewRepo(db)
ctx := context.Background()
out, err := repo.KnownIDs(ctx, nil)
require.NoError(t, err)
require.Empty(t, out)
}