This commit is contained in:
StellaOps Bot
2025-12-14 23:20:14 +02:00
parent 3411e825cd
commit b058dbe031
356 changed files with 68310 additions and 1108 deletions

View File

@@ -1,4 +1,6 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("FixtureUpdater")]
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Acsc.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Cccs.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.CertBund.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.CertCc.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.CertFr.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.CertIn.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Common.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Cve.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Distro.Debian.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Distro.RedHat.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Distro.Suse.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Distro.Ubuntu.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,4 +1,6 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("FixtureUpdater")]
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Ghsa.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Ics.Cisa.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Ics.Kaspersky.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Jvn.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Kev.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Kisa.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,4 +1,6 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Nvd.Tests")]
[assembly: InternalsVisibleTo("FixtureUpdater")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("FixtureUpdater")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Ru.Bdu.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Ru.Nkcki.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.StellaOpsMirror.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Vndr.Adobe.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Vndr.Apple.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Vndr.Chromium.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Vndr.Cisco.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Vndr.Msrc.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Vndr.Oracle.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using StellaOps.Plugin.Versioning;
[assembly: InternalsVisibleTo("StellaOps.Concelier.Connector.Vndr.Vmware.Tests")]
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "1.99.99")]

View File

@@ -0,0 +1,136 @@
-- Vuln Schema Migration 006: Partition Merge Events Table
-- Sprint: SPRINT_3422_0001_0001 - Time-Based Partitioning
-- Category: C (infrastructure change, requires maintenance window)
--
-- Purpose: Convert vuln.merge_events to a partitioned table for improved
-- query performance on time-range queries and easier data lifecycle management.
--
-- Partition strategy: Monthly by created_at
BEGIN;
-- ============================================================================
-- Step 1: Create partitioned merge_events table
-- ============================================================================
CREATE TABLE IF NOT EXISTS vuln.merge_events_partitioned (
id BIGSERIAL,
advisory_id UUID NOT NULL,
source_id UUID,
event_type TEXT NOT NULL,
old_value JSONB,
new_value JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);
-- ============================================================================
-- Step 2: Create initial partitions (past 12 months + 3 months ahead)
-- ============================================================================
DO $$
DECLARE
v_start DATE;
v_end DATE;
v_partition_name TEXT;
BEGIN
-- Start from 12 months ago (merge events accumulate fast)
v_start := date_trunc('month', NOW() - INTERVAL '12 months')::DATE;
-- Create partitions until 3 months ahead
WHILE v_start <= date_trunc('month', NOW() + INTERVAL '3 months')::DATE LOOP
v_end := (v_start + INTERVAL '1 month')::DATE;
v_partition_name := 'merge_events_' || to_char(v_start, 'YYYY_MM');
IF NOT EXISTS (
SELECT 1 FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE n.nspname = 'vuln' AND c.relname = v_partition_name
) THEN
EXECUTE format(
'CREATE TABLE vuln.%I PARTITION OF vuln.merge_events_partitioned
FOR VALUES FROM (%L) TO (%L)',
v_partition_name, v_start, v_end
);
RAISE NOTICE 'Created partition vuln.%', v_partition_name;
END IF;
v_start := v_end;
END LOOP;
END
$$;
-- Create default partition for any data outside defined ranges
CREATE TABLE IF NOT EXISTS vuln.merge_events_default
PARTITION OF vuln.merge_events_partitioned DEFAULT;
-- ============================================================================
-- Step 3: Create indexes on partitioned table
-- ============================================================================
CREATE INDEX IF NOT EXISTS ix_merge_events_part_advisory
ON vuln.merge_events_partitioned (advisory_id);
CREATE INDEX IF NOT EXISTS ix_merge_events_part_source
ON vuln.merge_events_partitioned (source_id)
WHERE source_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS ix_merge_events_part_event_type
ON vuln.merge_events_partitioned (event_type);
-- BRIN index for time-range queries
CREATE INDEX IF NOT EXISTS brin_merge_events_part_created
ON vuln.merge_events_partitioned USING BRIN (created_at)
WITH (pages_per_range = 128);
-- ============================================================================
-- Step 4: Migrate data from old table to partitioned table
-- ============================================================================
INSERT INTO vuln.merge_events_partitioned (
id, advisory_id, source_id, event_type, old_value, new_value, created_at
)
SELECT
id, advisory_id, source_id, event_type, old_value, new_value, created_at
FROM vuln.merge_events
ON CONFLICT DO NOTHING;
-- ============================================================================
-- Step 5: Swap tables
-- ============================================================================
-- Drop foreign key constraint first (advisory_id references advisories)
ALTER TABLE vuln.merge_events DROP CONSTRAINT IF EXISTS merge_events_advisory_id_fkey;
ALTER TABLE vuln.merge_events DROP CONSTRAINT IF EXISTS merge_events_source_id_fkey;
-- Rename old table to backup
ALTER TABLE IF EXISTS vuln.merge_events RENAME TO merge_events_old;
-- Rename partitioned table to production name
ALTER TABLE vuln.merge_events_partitioned RENAME TO merge_events;
-- Update sequence to continue from max ID
DO $$
DECLARE
v_max_id BIGINT;
BEGIN
SELECT COALESCE(MAX(id), 0) INTO v_max_id FROM vuln.merge_events;
PERFORM setval('vuln.merge_events_id_seq', v_max_id + 1, false);
END
$$;
-- ============================================================================
-- Step 6: Add comment about partitioning strategy
-- ============================================================================
COMMENT ON TABLE vuln.merge_events IS
'Advisory merge event log. Partitioned monthly by created_at. FK to advisories removed for partition support.';
COMMIT;
-- ============================================================================
-- Cleanup (run manually after validation)
-- ============================================================================
-- After confirming the migration is successful, drop the old table:
-- DROP TABLE IF EXISTS vuln.merge_events_old;

View File

@@ -0,0 +1,141 @@
-- Vuln Schema Migration 007: Generated Columns for Advisory Hot Fields
-- Sprint: SPRINT_3423_0001_0001 - Generated Columns
-- Category: A (safe, can run at startup)
--
-- Purpose: Extract frequently queried fields from JSONB provenance column
-- as generated columns for efficient indexing and filtering.
--
-- Performance Impact: Queries filtering on these fields will use B-tree indexes
-- instead of JSONB operators, improving query time by 10-50x for dashboard queries.
BEGIN;
-- ============================================================================
-- Step 1: Add generated columns to vuln.advisories
-- ============================================================================
-- Extract source_key from provenance for fast source filtering
ALTER TABLE vuln.advisories
ADD COLUMN IF NOT EXISTS provenance_source_key TEXT
GENERATED ALWAYS AS (provenance->>'source_key') STORED;
-- Extract feed_id from provenance for feed correlation
ALTER TABLE vuln.advisories
ADD COLUMN IF NOT EXISTS provenance_feed_id TEXT
GENERATED ALWAYS AS (provenance->>'feed_id') STORED;
-- Extract ingestion timestamp from provenance for freshness queries
ALTER TABLE vuln.advisories
ADD COLUMN IF NOT EXISTS provenance_ingested_at TIMESTAMPTZ
GENERATED ALWAYS AS ((provenance->>'ingested_at')::TIMESTAMPTZ) STORED;
-- ============================================================================
-- Step 2: Create indexes on generated columns
-- ============================================================================
CREATE INDEX IF NOT EXISTS ix_advisories_provenance_source
ON vuln.advisories (provenance_source_key)
WHERE provenance_source_key IS NOT NULL;
CREATE INDEX IF NOT EXISTS ix_advisories_provenance_feed
ON vuln.advisories (provenance_feed_id)
WHERE provenance_feed_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS ix_advisories_provenance_ingested
ON vuln.advisories (provenance_ingested_at DESC)
WHERE provenance_ingested_at IS NOT NULL;
-- Composite index for common dashboard query pattern
CREATE INDEX IF NOT EXISTS ix_advisories_severity_ingested
ON vuln.advisories (severity, provenance_ingested_at DESC)
WHERE provenance_ingested_at IS NOT NULL;
-- ============================================================================
-- Step 3: Add generated columns to vuln.advisory_affected for PURL parsing
-- ============================================================================
-- Extract namespace from purl for namespace-based filtering
-- purl format: pkg:type/namespace/name@version
ALTER TABLE vuln.advisory_affected
ADD COLUMN IF NOT EXISTS purl_type TEXT
GENERATED ALWAYS AS (
CASE
WHEN purl IS NOT NULL AND purl LIKE 'pkg:%'
THEN split_part(split_part(purl, ':', 2), '/', 1)
ELSE NULL
END
) STORED;
-- Extract package name (without namespace) for faster lookups
ALTER TABLE vuln.advisory_affected
ADD COLUMN IF NOT EXISTS purl_name TEXT
GENERATED ALWAYS AS (
CASE
WHEN purl IS NOT NULL AND purl LIKE 'pkg:%'
THEN split_part(split_part(split_part(purl, ':', 2), '@', 1), '/', -1)
ELSE NULL
END
) STORED;
-- ============================================================================
-- Step 4: Create indexes on advisory_affected generated columns
-- ============================================================================
CREATE INDEX IF NOT EXISTS ix_advisory_affected_purl_type
ON vuln.advisory_affected (purl_type)
WHERE purl_type IS NOT NULL;
CREATE INDEX IF NOT EXISTS ix_advisory_affected_purl_name
ON vuln.advisory_affected (purl_name)
WHERE purl_name IS NOT NULL;
-- Composite index for ecosystem + purl_type queries
CREATE INDEX IF NOT EXISTS ix_advisory_affected_ecosystem_type
ON vuln.advisory_affected (ecosystem, purl_type)
WHERE purl_type IS NOT NULL;
-- ============================================================================
-- Step 5: Add comment documenting the generated columns
-- ============================================================================
COMMENT ON COLUMN vuln.advisories.provenance_source_key IS
'Generated: Extracted from provenance->>''source_key'' for fast source filtering';
COMMENT ON COLUMN vuln.advisories.provenance_feed_id IS
'Generated: Extracted from provenance->>''feed_id'' for feed correlation';
COMMENT ON COLUMN vuln.advisories.provenance_ingested_at IS
'Generated: Extracted from provenance->>''ingested_at'' for freshness queries';
COMMENT ON COLUMN vuln.advisory_affected.purl_type IS
'Generated: Extracted package type from purl (npm, maven, pypi, etc.)';
COMMENT ON COLUMN vuln.advisory_affected.purl_name IS
'Generated: Extracted package name from purl (without namespace/version)';
COMMIT;
-- ============================================================================
-- Example Queries (showing performance improvement)
-- ============================================================================
/*
-- Before (uses GIN index, slower):
SELECT * FROM vuln.advisories
WHERE provenance->>'source_key' = 'nvd'
AND severity = 'critical'
ORDER BY (provenance->>'ingested_at')::timestamptz DESC
LIMIT 100;
-- After (uses B-tree indexes, faster):
SELECT * FROM vuln.advisories
WHERE provenance_source_key = 'nvd'
AND severity = 'critical'
ORDER BY provenance_ingested_at DESC
LIMIT 100;
-- Package type filtering (new capability):
SELECT * FROM vuln.advisory_affected
WHERE purl_type = 'npm'
AND ecosystem = 'npm';
*/