Add unit tests for SBOM ingestion and transformation
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Implement `SbomIngestServiceCollectionExtensionsTests` to verify the SBOM ingestion pipeline exports snapshots correctly.
- Create `SbomIngestTransformerTests` to ensure the transformation produces expected nodes and edges, including deduplication of license nodes and normalization of timestamps.
- Add `SbomSnapshotExporterTests` to test the export functionality for manifest, adjacency, nodes, and edges.
- Introduce `VexOverlayTransformerTests` to validate the transformation of VEX nodes and edges.
- Set up project file for the test project with necessary dependencies and configurations.
- Include JSON fixture files for testing purposes.
This commit is contained in:
master
2025-11-04 07:49:39 +02:00
parent f72c5c513a
commit 2eb6852d34
491 changed files with 39445 additions and 3917 deletions

View File

@@ -0,0 +1,138 @@
-- 001_initial.sql
-- Findings Ledger bootstrap schema (LEDGER-29-001)
BEGIN;
CREATE TYPE ledger_event_type AS ENUM (
'finding.created',
'finding.status_changed',
'finding.severity_changed',
'finding.tag_updated',
'finding.comment_added',
'finding.assignment_changed',
'finding.accepted_risk',
'finding.remediation_plan_added',
'finding.attachment_added',
'finding.closed'
);
CREATE TYPE ledger_action_type AS ENUM (
'assign',
'comment',
'attach_evidence',
'link_ticket',
'remediation_plan',
'status_change',
'accept_risk',
'reopen',
'close'
);
CREATE TABLE ledger_events (
tenant_id TEXT NOT NULL,
chain_id UUID NOT NULL,
sequence_no BIGINT NOT NULL,
event_id UUID NOT NULL,
event_type ledger_event_type NOT NULL,
policy_version TEXT NOT NULL,
finding_id TEXT NOT NULL,
artifact_id TEXT NOT NULL,
source_run_id UUID,
actor_id TEXT NOT NULL,
actor_type TEXT NOT NULL,
occurred_at TIMESTAMPTZ NOT NULL,
recorded_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
event_body JSONB NOT NULL,
event_hash CHAR(64) NOT NULL,
previous_hash CHAR(64) NOT NULL,
merkle_leaf_hash CHAR(64) NOT NULL,
CONSTRAINT pk_ledger_events PRIMARY KEY (tenant_id, chain_id, sequence_no),
CONSTRAINT uq_ledger_events_event_id UNIQUE (tenant_id, event_id),
CONSTRAINT uq_ledger_events_chain_hash UNIQUE (tenant_id, chain_id, event_hash),
CONSTRAINT ck_ledger_events_event_hash_hex CHECK (event_hash ~ '^[0-9a-f]{64}$'),
CONSTRAINT ck_ledger_events_previous_hash_hex CHECK (previous_hash ~ '^[0-9a-f]{64}$'),
CONSTRAINT ck_ledger_events_leaf_hash_hex CHECK (merkle_leaf_hash ~ '^[0-9a-f]{64}$'),
CONSTRAINT ck_ledger_events_actor_type CHECK (actor_type IN ('system', 'operator', 'integration'))
) PARTITION BY LIST (tenant_id);
CREATE TABLE ledger_events_default PARTITION OF ledger_events DEFAULT;
CREATE INDEX ix_ledger_events_finding ON ledger_events (tenant_id, finding_id, policy_version);
CREATE INDEX ix_ledger_events_type ON ledger_events (tenant_id, event_type, recorded_at DESC);
CREATE INDEX ix_ledger_events_recorded_at ON ledger_events (tenant_id, recorded_at DESC);
CREATE TABLE ledger_merkle_roots (
tenant_id TEXT NOT NULL,
anchor_id UUID NOT NULL,
window_start TIMESTAMPTZ NOT NULL,
window_end TIMESTAMPTZ NOT NULL,
sequence_start BIGINT NOT NULL,
sequence_end BIGINT NOT NULL,
root_hash CHAR(64) NOT NULL,
leaf_count INTEGER NOT NULL,
anchored_at TIMESTAMPTZ NOT NULL,
anchor_reference TEXT,
CONSTRAINT pk_ledger_merkle_roots PRIMARY KEY (tenant_id, anchor_id),
CONSTRAINT uq_ledger_merkle_root_hash UNIQUE (tenant_id, root_hash),
CONSTRAINT ck_ledger_merkle_root_hash_hex CHECK (root_hash ~ '^[0-9a-f]{64}$')
) PARTITION BY LIST (tenant_id);
CREATE TABLE ledger_merkle_roots_default PARTITION OF ledger_merkle_roots DEFAULT;
CREATE INDEX ix_merkle_sequences ON ledger_merkle_roots (tenant_id, sequence_end DESC);
CREATE TABLE findings_projection (
tenant_id TEXT NOT NULL,
finding_id TEXT NOT NULL,
policy_version TEXT NOT NULL,
status TEXT NOT NULL,
severity NUMERIC(6,3),
labels JSONB NOT NULL DEFAULT '{}'::JSONB,
current_event_id UUID NOT NULL,
explain_ref TEXT,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
cycle_hash CHAR(64) NOT NULL,
CONSTRAINT pk_findings_projection PRIMARY KEY (tenant_id, finding_id, policy_version),
CONSTRAINT ck_findings_projection_cycle_hash_hex CHECK (cycle_hash ~ '^[0-9a-f]{64}$')
) PARTITION BY LIST (tenant_id);
CREATE TABLE findings_projection_default PARTITION OF findings_projection DEFAULT;
CREATE INDEX ix_projection_status ON findings_projection (tenant_id, status, severity DESC);
CREATE INDEX ix_projection_labels_gin ON findings_projection USING GIN (labels JSONB_PATH_OPS);
CREATE TABLE finding_history (
tenant_id TEXT NOT NULL,
finding_id TEXT NOT NULL,
policy_version TEXT NOT NULL,
event_id UUID NOT NULL,
status TEXT NOT NULL,
severity NUMERIC(6,3),
actor_id TEXT NOT NULL,
comment TEXT,
occurred_at TIMESTAMPTZ NOT NULL,
CONSTRAINT pk_finding_history PRIMARY KEY (tenant_id, finding_id, event_id)
) PARTITION BY LIST (tenant_id);
CREATE TABLE finding_history_default PARTITION OF finding_history DEFAULT;
CREATE INDEX ix_finding_history_timeline ON finding_history (tenant_id, finding_id, occurred_at DESC);
CREATE TABLE triage_actions (
tenant_id TEXT NOT NULL,
action_id UUID NOT NULL,
event_id UUID NOT NULL,
finding_id TEXT NOT NULL,
action_type ledger_action_type NOT NULL,
payload JSONB NOT NULL DEFAULT '{}'::JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT NOT NULL,
CONSTRAINT pk_triage_actions PRIMARY KEY (tenant_id, action_id)
) PARTITION BY LIST (tenant_id);
CREATE TABLE triage_actions_default PARTITION OF triage_actions DEFAULT;
CREATE INDEX ix_triage_actions_event ON triage_actions (tenant_id, event_id);
CREATE INDEX ix_triage_actions_created_at ON triage_actions (tenant_id, created_at DESC);
COMMIT;

View File

@@ -0,0 +1,21 @@
-- 002_projection_offsets.sql
-- Projection worker checkpoint storage (LEDGER-29-003)
BEGIN;
CREATE TABLE IF NOT EXISTS ledger_projection_offsets (
worker_id TEXT NOT NULL PRIMARY KEY,
last_recorded_at TIMESTAMPTZ NOT NULL,
last_event_id UUID NOT NULL,
updated_at TIMESTAMPTZ NOT NULL
);
INSERT INTO ledger_projection_offsets (worker_id, last_recorded_at, last_event_id, updated_at)
VALUES (
'default',
'1970-01-01T00:00:00Z',
'00000000-0000-0000-0000-000000000000',
NOW())
ON CONFLICT (worker_id) DO NOTHING;
COMMIT;

View File

@@ -0,0 +1,16 @@
-- 003_policy_rationale.sql
-- Add policy rationale column to findings_projection (LEDGER-29-004)
BEGIN;
ALTER TABLE findings_projection
ADD COLUMN IF NOT EXISTS policy_rationale JSONB NOT NULL DEFAULT '[]'::JSONB;
ALTER TABLE findings_projection
ALTER COLUMN policy_rationale SET DEFAULT '[]'::JSONB;
UPDATE findings_projection
SET policy_rationale = '[]'::JSONB
WHERE policy_rationale IS NULL;
COMMIT;