up
This commit is contained in:
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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;
|
||||
@@ -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';
|
||||
*/
|
||||
Reference in New Issue
Block a user