feat(eidas): Implement eIDAS Crypto Plugin with dependency injection and signing capabilities
- Added ServiceCollectionExtensions for eIDAS crypto providers. - Implemented EidasCryptoProvider for handling eIDAS-compliant signatures. - Created LocalEidasProvider for local signing using PKCS#12 keystores. - Defined SignatureLevel and SignatureFormat enums for eIDAS compliance. - Developed TrustServiceProviderClient for remote signing via TSP. - Added configuration support for eIDAS options in the project file. - Implemented unit tests for SM2 compliance and crypto operations. - Introduced dependency injection extensions for SM software and remote plugins.
This commit is contained in:
@@ -1,584 +1,50 @@
|
||||
-- ============================================================================
|
||||
-- Proof System Database Schema
|
||||
-- StellaOps Proof-Driven Moats Database Schema
|
||||
-- ============================================================================
|
||||
-- Purpose: Support patch-aware backport detection with cryptographic proofs
|
||||
-- Purpose: Four-tier backport detection with cryptographic proof generation
|
||||
-- Version: 1.0.0
|
||||
-- Date: 2025-12-23
|
||||
--
|
||||
-- This schema extends the existing Concelier and Scanner schemas with proof
|
||||
-- infrastructure for backport detection (Tier 1-4).
|
||||
-- Compatible with: PostgreSQL 16+
|
||||
-- ============================================================================
|
||||
|
||||
-- Advisory lock for safe migrations
|
||||
SELECT pg_advisory_lock(hashtext('proof_system'));
|
||||
-- Schema: proof_moats
|
||||
-- Contains all proof-driven backport detection tables
|
||||
CREATE SCHEMA IF NOT EXISTS proof_moats;
|
||||
|
||||
SET search_path TO proof_moats, public;
|
||||
|
||||
-- ============================================================================
|
||||
-- SCHEMA: concelier (extend existing)
|
||||
-- TIER 1: Distro Advisories (Highest Confidence)
|
||||
-- ============================================================================
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Distro Release Catalog
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS concelier.distro_release (
|
||||
release_id TEXT PRIMARY KEY, -- e.g., "ubuntu-22.04", "rhel-9.2"
|
||||
distro_name TEXT NOT NULL, -- e.g., "ubuntu", "rhel", "alpine"
|
||||
release_version TEXT NOT NULL, -- e.g., "22.04", "9.2", "3.18"
|
||||
codename TEXT, -- e.g., "jammy", "bookworm"
|
||||
release_date DATE,
|
||||
eol_date DATE,
|
||||
|
||||
-- Architecture support
|
||||
architectures TEXT[] NOT NULL DEFAULT ARRAY['x86_64', 'aarch64'],
|
||||
|
||||
-- Metadata
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT distro_release_unique UNIQUE(distro_name, release_version)
|
||||
-- Table: distro_release
|
||||
-- Tracks distribution releases for versioning context
|
||||
CREATE TABLE IF NOT EXISTS distro_release (
|
||||
release_id TEXT PRIMARY KEY,
|
||||
distro_name TEXT NOT NULL,
|
||||
release_version TEXT NOT NULL,
|
||||
release_codename TEXT,
|
||||
eol_date TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_distro_release_name ON concelier.distro_release(distro_name);
|
||||
CREATE INDEX idx_distro_release_eol ON concelier.distro_release(eol_date) WHERE eol_date IS NOT NULL;
|
||||
CREATE INDEX idx_distro_release_name ON distro_release(distro_name);
|
||||
|
||||
COMMENT ON TABLE concelier.distro_release IS 'Catalog of distro releases for backport detection';
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Distro Package Catalog
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS concelier.distro_package (
|
||||
package_id TEXT PRIMARY KEY, -- sha256:...
|
||||
release_id TEXT NOT NULL REFERENCES concelier.distro_release(release_id),
|
||||
|
||||
-- Package identity
|
||||
package_name TEXT NOT NULL,
|
||||
package_version TEXT NOT NULL, -- Full NEVRA/EVR string
|
||||
architecture TEXT NOT NULL,
|
||||
|
||||
-- Parsed version components
|
||||
epoch INTEGER DEFAULT 0,
|
||||
version TEXT NOT NULL,
|
||||
release TEXT,
|
||||
|
||||
-- Build metadata
|
||||
build_id TEXT, -- ELF build-id if available
|
||||
build_date TIMESTAMPTZ,
|
||||
|
||||
-- Source package reference
|
||||
source_package_name TEXT,
|
||||
source_package_version TEXT,
|
||||
|
||||
-- Binary hashes
|
||||
file_sha256 TEXT,
|
||||
file_size BIGINT,
|
||||
|
||||
-- Metadata
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT distro_package_unique UNIQUE(release_id, package_name, package_version, architecture)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_distro_package_release ON concelier.distro_package(release_id);
|
||||
CREATE INDEX idx_distro_package_name ON concelier.distro_package(package_name);
|
||||
CREATE INDEX idx_distro_package_build_id ON concelier.distro_package(build_id) WHERE build_id IS NOT NULL;
|
||||
CREATE INDEX idx_distro_package_source ON concelier.distro_package(source_package_name, source_package_version);
|
||||
|
||||
COMMENT ON TABLE concelier.distro_package IS 'Catalog of distro binary packages with build metadata';
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Distro Advisory Ingestion (raw)
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS concelier.distro_advisory (
|
||||
advisory_id TEXT PRIMARY KEY, -- e.g., "DSA-5432-1", "RHSA-2024:1234"
|
||||
release_id TEXT NOT NULL REFERENCES concelier.distro_release(release_id),
|
||||
|
||||
-- Advisory metadata
|
||||
advisory_type TEXT NOT NULL, -- "security" | "bugfix" | "enhancement"
|
||||
severity TEXT, -- "critical" | "high" | "medium" | "low"
|
||||
-- Table: distro_advisory
|
||||
-- Official distro security advisories (DSA, USN, RHSA, etc.)
|
||||
CREATE TABLE IF NOT EXISTS distro_advisory (
|
||||
advisory_id TEXT PRIMARY KEY,
|
||||
distro_name TEXT NOT NULL,
|
||||
advisory_type TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
severity TEXT,
|
||||
published_at TIMESTAMPTZ NOT NULL,
|
||||
updated_at TIMESTAMPTZ,
|
||||
|
||||
-- Source
|
||||
source_url TEXT NOT NULL,
|
||||
source_hash TEXT NOT NULL, -- sha256 of source document
|
||||
|
||||
-- Raw content (JSONB for flexible schema)
|
||||
raw_advisory JSONB NOT NULL,
|
||||
|
||||
-- Ingestion metadata
|
||||
ingested_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
snapshot_id TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT distro_advisory_unique UNIQUE(release_id, advisory_id)
|
||||
source_url TEXT,
|
||||
raw_data JSONB NOT NULL,
|
||||
ingested_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_distro_advisory_release ON concelier.distro_advisory(release_id);
|
||||
CREATE INDEX idx_distro_advisory_published ON concelier.distro_advisory(published_at DESC);
|
||||
CREATE INDEX idx_distro_advisory_severity ON concelier.distro_advisory(severity);
|
||||
CREATE INDEX idx_distro_advisory_snapshot ON concelier.distro_advisory(snapshot_id);
|
||||
CREATE INDEX idx_distro_advisory_distro ON distro_advisory(distro_name);
|
||||
CREATE INDEX idx_distro_advisory_published ON distro_advisory(published_at DESC);
|
||||
CREATE INDEX idx_distro_advisory_raw_data ON distro_advisory USING gin(raw_data);
|
||||
|
||||
-- GIN index for JSONB queries
|
||||
CREATE INDEX idx_distro_advisory_raw ON concelier.distro_advisory USING GIN(raw_advisory);
|
||||
|
||||
COMMENT ON TABLE concelier.distro_advisory IS 'Raw distro security advisories (Tier 1 evidence)';
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- CVE to Package Mapping (distro-specific)
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS concelier.distro_cve_affected (
|
||||
mapping_id TEXT PRIMARY KEY, -- sha256:...
|
||||
release_id TEXT NOT NULL REFERENCES concelier.distro_release(release_id),
|
||||
cve_id TEXT NOT NULL,
|
||||
package_name TEXT NOT NULL,
|
||||
|
||||
-- Affected range (distro-native format)
|
||||
range_kind TEXT NOT NULL, -- "nevra" | "evr" | "apk"
|
||||
range_start TEXT, -- Inclusive start version
|
||||
range_end TEXT, -- Exclusive end version
|
||||
|
||||
-- Fix information
|
||||
fix_state TEXT NOT NULL, -- "fixed" | "not_affected" | "vulnerable" | "wontfix" | "unknown"
|
||||
fixed_version TEXT, -- Distro-native version string
|
||||
|
||||
-- Evidence
|
||||
evidence_type TEXT NOT NULL, -- "distro_feed" | "changelog" | "patch_header" | "binary_match"
|
||||
evidence_source TEXT NOT NULL, -- Advisory ID or file path
|
||||
confidence NUMERIC(5,4) NOT NULL, -- 0.0-1.0
|
||||
|
||||
-- Provenance
|
||||
method TEXT NOT NULL, -- "security_feed" | "changelog" | "patch_header" | "binary_match"
|
||||
snapshot_id TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT distro_cve_affected_confidence_check CHECK (confidence >= 0 AND confidence <= 1),
|
||||
CONSTRAINT distro_cve_affected_unique UNIQUE(release_id, cve_id, package_name, fix_state, method)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_distro_cve_affected_release ON concelier.distro_cve_affected(release_id);
|
||||
CREATE INDEX idx_distro_cve_affected_cve ON concelier.distro_cve_affected(cve_id);
|
||||
CREATE INDEX idx_distro_cve_affected_package ON concelier.distro_cve_affected(package_name);
|
||||
CREATE INDEX idx_distro_cve_affected_confidence ON concelier.distro_cve_affected(confidence DESC);
|
||||
CREATE INDEX idx_distro_cve_affected_method ON concelier.distro_cve_affected(method);
|
||||
|
||||
COMMENT ON TABLE concelier.distro_cve_affected IS 'CVE to package mappings with fix information (Tier 1-3 evidence)';
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Source Package Artifacts
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS concelier.source_artifact (
|
||||
artifact_id TEXT PRIMARY KEY, -- sha256:...
|
||||
release_id TEXT NOT NULL REFERENCES concelier.distro_release(release_id),
|
||||
|
||||
-- Source package identity
|
||||
source_package_name TEXT NOT NULL,
|
||||
source_package_version TEXT NOT NULL,
|
||||
|
||||
-- Artifact type
|
||||
artifact_type TEXT NOT NULL, -- "changelog" | "patch_file" | "spec_file" | "apkbuild"
|
||||
artifact_path TEXT NOT NULL, -- Path within source package
|
||||
|
||||
-- Content
|
||||
content_sha256 TEXT NOT NULL,
|
||||
content_size BIGINT NOT NULL,
|
||||
content BYTEA, -- May be NULL for large files (stored externally)
|
||||
|
||||
-- Metadata
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT source_artifact_unique UNIQUE(release_id, source_package_name, source_package_version, artifact_path)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_source_artifact_release ON concelier.source_artifact(release_id);
|
||||
CREATE INDEX idx_source_artifact_package ON concelier.source_artifact(source_package_name, source_package_version);
|
||||
CREATE INDEX idx_source_artifact_type ON concelier.source_artifact(artifact_type);
|
||||
|
||||
COMMENT ON TABLE concelier.source_artifact IS 'Source package artifacts (changelogs, patches, specs) for Tier 2-3 analysis';
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Patch Signatures (HunkSig)
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS concelier.source_patch_sig (
|
||||
patch_sig_id TEXT PRIMARY KEY, -- sha256:...
|
||||
|
||||
-- Patch source
|
||||
cve_id TEXT, -- May be NULL for non-CVE patches
|
||||
upstream_repo TEXT, -- e.g., "github.com/openssl/openssl"
|
||||
commit_sha TEXT, -- Git commit SHA
|
||||
|
||||
-- Normalized hunks
|
||||
hunks JSONB NOT NULL, -- Array of normalized hunk objects
|
||||
hunk_hash TEXT NOT NULL, -- sha256 of canonical hunk representation
|
||||
|
||||
-- Function/file context
|
||||
affected_files TEXT[] NOT NULL,
|
||||
affected_functions TEXT[],
|
||||
|
||||
-- Metadata
|
||||
extracted_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
extractor_version TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT source_patch_sig_hunk_unique UNIQUE(hunk_hash)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_source_patch_sig_cve ON concelier.source_patch_sig(cve_id) WHERE cve_id IS NOT NULL;
|
||||
CREATE INDEX idx_source_patch_sig_repo ON concelier.source_patch_sig(upstream_repo);
|
||||
CREATE INDEX idx_source_patch_sig_commit ON concelier.source_patch_sig(commit_sha);
|
||||
CREATE INDEX idx_source_patch_sig_files ON concelier.source_patch_sig USING GIN(affected_files);
|
||||
|
||||
-- GIN index for JSONB queries
|
||||
CREATE INDEX idx_source_patch_sig_hunks ON concelier.source_patch_sig USING GIN(hunks);
|
||||
|
||||
COMMENT ON TABLE concelier.source_patch_sig IS 'Upstream patch signatures (HunkSig) for equivalence matching';
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Build Provenance (BuildID → Package mapping)
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS concelier.build_provenance (
|
||||
provenance_id TEXT PRIMARY KEY, -- sha256:...
|
||||
|
||||
-- Binary identity
|
||||
build_id TEXT NOT NULL, -- ELF/PE build-id
|
||||
file_sha256 TEXT NOT NULL,
|
||||
|
||||
-- Package mapping
|
||||
release_id TEXT NOT NULL REFERENCES concelier.distro_release(release_id),
|
||||
package_name TEXT NOT NULL,
|
||||
package_version TEXT NOT NULL,
|
||||
architecture TEXT NOT NULL,
|
||||
|
||||
-- Build metadata
|
||||
build_date TIMESTAMPTZ,
|
||||
compiler TEXT,
|
||||
compiler_flags TEXT,
|
||||
|
||||
-- Symbol information (optional, for advanced matching)
|
||||
symbols JSONB, -- Array of exported symbols
|
||||
|
||||
-- Metadata
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT build_provenance_build_id_unique UNIQUE(build_id, release_id, architecture),
|
||||
CONSTRAINT build_provenance_file_unique UNIQUE(file_sha256, release_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_build_provenance_build_id ON concelier.build_provenance(build_id);
|
||||
CREATE INDEX idx_build_provenance_file_sha ON concelier.build_provenance(file_sha256);
|
||||
CREATE INDEX idx_build_provenance_package ON concelier.build_provenance(package_name, package_version);
|
||||
|
||||
-- GIN index for symbol queries
|
||||
CREATE INDEX idx_build_provenance_symbols ON concelier.build_provenance USING GIN(symbols) WHERE symbols IS NOT NULL;
|
||||
|
||||
COMMENT ON TABLE concelier.build_provenance IS 'BuildID to package mapping for binary-level analysis';
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Binary Fingerprints (Tier 4)
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS concelier.binary_fingerprint (
|
||||
fingerprint_id TEXT PRIMARY KEY, -- sha256:...
|
||||
|
||||
-- CVE association
|
||||
cve_id TEXT NOT NULL,
|
||||
component TEXT NOT NULL, -- e.g., "openssl/libssl"
|
||||
architecture TEXT NOT NULL,
|
||||
|
||||
-- Fingerprint type and value
|
||||
fp_type TEXT NOT NULL, -- "func_norm_hash" | "bb_multiset" | "cfg_hash"
|
||||
fp_value TEXT NOT NULL, -- Hash value
|
||||
|
||||
-- Context
|
||||
function_hint TEXT, -- Function name if available
|
||||
confidence NUMERIC(5,4) NOT NULL, -- 0.0-1.0
|
||||
|
||||
-- Validation metrics
|
||||
true_positive_count INTEGER DEFAULT 0, -- Matches on known vulnerable binaries
|
||||
false_positive_count INTEGER DEFAULT 0, -- Matches on known fixed binaries
|
||||
validated_at TIMESTAMPTZ,
|
||||
|
||||
-- Evidence reference
|
||||
evidence_ref TEXT NOT NULL, -- Points to reference builds + patch
|
||||
|
||||
-- Metadata
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT binary_fingerprint_confidence_check CHECK (confidence >= 0 AND confidence <= 1),
|
||||
CONSTRAINT binary_fingerprint_unique UNIQUE(cve_id, component, architecture, fp_type, fp_value)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_binary_fingerprint_cve ON concelier.binary_fingerprint(cve_id);
|
||||
CREATE INDEX idx_binary_fingerprint_component ON concelier.binary_fingerprint(component);
|
||||
CREATE INDEX idx_binary_fingerprint_type ON concelier.binary_fingerprint(fp_type);
|
||||
CREATE INDEX idx_binary_fingerprint_value ON concelier.binary_fingerprint(fp_value);
|
||||
CREATE INDEX idx_binary_fingerprint_confidence ON concelier.binary_fingerprint(confidence DESC);
|
||||
|
||||
COMMENT ON TABLE concelier.binary_fingerprint IS 'Binary-level vulnerability fingerprints (Tier 4 evidence)';
|
||||
|
||||
-- ============================================================================
|
||||
-- SCHEMA: scanner (extend existing)
|
||||
-- ============================================================================
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Backport Proof Blobs
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS scanner.backport_proof (
|
||||
proof_id TEXT PRIMARY KEY, -- sha256:...
|
||||
subject_id TEXT NOT NULL, -- CVE-XXXX-YYYY:pkg:rpm/...
|
||||
|
||||
-- Proof type and method
|
||||
proof_type TEXT NOT NULL, -- "backport_fixed" | "not_affected" | "vulnerable" | "unknown"
|
||||
method TEXT NOT NULL, -- "distro_feed" | "changelog" | "patch_header" | "binary_match"
|
||||
confidence NUMERIC(5,4) NOT NULL, -- 0.0-1.0
|
||||
|
||||
-- Scan context
|
||||
scan_id UUID, -- Reference to scanner.scan_manifest if part of scan
|
||||
|
||||
-- Provenance
|
||||
tool_version TEXT NOT NULL,
|
||||
snapshot_id TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
-- Proof blob (JSONB)
|
||||
proof_blob JSONB NOT NULL,
|
||||
|
||||
-- Proof hash (canonical hash of proof_blob, excludes this field)
|
||||
proof_hash TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT backport_proof_confidence_check CHECK (confidence >= 0 AND confidence <= 1),
|
||||
CONSTRAINT backport_proof_hash_unique UNIQUE(proof_hash)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_backport_proof_subject ON scanner.backport_proof(subject_id);
|
||||
CREATE INDEX idx_backport_proof_type ON scanner.backport_proof(proof_type);
|
||||
CREATE INDEX idx_backport_proof_method ON scanner.backport_proof(method);
|
||||
CREATE INDEX idx_backport_proof_confidence ON scanner.backport_proof(confidence DESC);
|
||||
CREATE INDEX idx_backport_proof_scan ON scanner.backport_proof(scan_id) WHERE scan_id IS NOT NULL;
|
||||
CREATE INDEX idx_backport_proof_created ON scanner.backport_proof(created_at DESC);
|
||||
|
||||
-- GIN index for JSONB queries
|
||||
CREATE INDEX idx_backport_proof_blob ON scanner.backport_proof USING GIN(proof_blob);
|
||||
|
||||
COMMENT ON TABLE scanner.backport_proof IS 'Cryptographic proof blobs for backport detection verdicts';
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Proof Evidence (detailed evidence entries)
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS scanner.proof_evidence (
|
||||
evidence_id TEXT PRIMARY KEY, -- sha256:...
|
||||
proof_id TEXT NOT NULL REFERENCES scanner.backport_proof(proof_id) ON DELETE CASCADE,
|
||||
|
||||
-- Evidence metadata
|
||||
evidence_type TEXT NOT NULL, -- "distro_advisory" | "changelog_mention" | "patch_header" | "binary_fingerprint" | "version_comparison" | "build_catalog"
|
||||
source TEXT NOT NULL, -- Advisory ID, file path, or fingerprint ID
|
||||
timestamp TIMESTAMPTZ NOT NULL,
|
||||
|
||||
-- Evidence data
|
||||
evidence_data JSONB NOT NULL,
|
||||
data_hash TEXT NOT NULL, -- sha256 of canonical evidence_data
|
||||
|
||||
-- Metadata
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT proof_evidence_unique UNIQUE(proof_id, evidence_type, data_hash)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_proof_evidence_proof ON scanner.proof_evidence(proof_id);
|
||||
CREATE INDEX idx_proof_evidence_type ON scanner.proof_evidence(evidence_type);
|
||||
CREATE INDEX idx_proof_evidence_source ON scanner.proof_evidence(source);
|
||||
|
||||
-- GIN index for JSONB queries
|
||||
CREATE INDEX idx_proof_evidence_data ON scanner.proof_evidence USING GIN(evidence_data);
|
||||
|
||||
COMMENT ON TABLE scanner.proof_evidence IS 'Individual evidence entries within proof blobs';
|
||||
|
||||
-- ============================================================================
|
||||
-- SCHEMA: attestor (extend existing)
|
||||
-- ============================================================================
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Multi-Profile Signatures
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS attestor.multi_profile_signature (
|
||||
signature_id TEXT PRIMARY KEY, -- sha256:...
|
||||
|
||||
-- Signed content reference
|
||||
content_digest TEXT NOT NULL, -- sha256 of signed payload
|
||||
content_type TEXT NOT NULL, -- "proof_blob" | "vex_statement" | "sbom" | "audit_bundle"
|
||||
content_ref TEXT NOT NULL, -- Reference to signed content (proof_id, vex_id, etc.)
|
||||
|
||||
-- Signatures (array of signature objects)
|
||||
signatures JSONB NOT NULL, -- Array: [{profile, keyId, algorithm, signature, signedAt}, ...]
|
||||
|
||||
-- Metadata
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT multi_profile_signature_content_unique UNIQUE(content_digest, content_type)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_multi_profile_signature_content ON attestor.multi_profile_signature(content_digest);
|
||||
CREATE INDEX idx_multi_profile_signature_type ON attestor.multi_profile_signature(content_type);
|
||||
CREATE INDEX idx_multi_profile_signature_ref ON attestor.multi_profile_signature(content_ref);
|
||||
CREATE INDEX idx_multi_profile_signature_created ON attestor.multi_profile_signature(created_at DESC);
|
||||
|
||||
-- GIN index for signature queries
|
||||
CREATE INDEX idx_multi_profile_signature_sigs ON attestor.multi_profile_signature USING GIN(signatures);
|
||||
|
||||
COMMENT ON TABLE attestor.multi_profile_signature IS 'Multi-profile cryptographic signatures for regional compliance';
|
||||
|
||||
-- ============================================================================
|
||||
-- FUNCTIONS AND TRIGGERS
|
||||
-- ============================================================================
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Automatic updated_at trigger
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = now();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER update_distro_release_updated_at
|
||||
BEFORE UPDATE ON concelier.distro_release
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- ============================================================================
|
||||
-- VIEWS
|
||||
-- ============================================================================
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Aggregated CVE Fix Status (for querying)
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE OR REPLACE VIEW concelier.cve_fix_status_aggregated AS
|
||||
SELECT
|
||||
release_id,
|
||||
cve_id,
|
||||
package_name,
|
||||
|
||||
-- Best fix state (prioritize not_affected > fixed > wontfix > vulnerable)
|
||||
CASE
|
||||
WHEN bool_or(fix_state = 'not_affected' AND confidence >= 0.9) THEN 'not_affected'
|
||||
WHEN bool_or(fix_state = 'fixed') THEN 'fixed'
|
||||
WHEN bool_or(fix_state = 'wontfix') THEN 'wontfix'
|
||||
ELSE 'vulnerable'
|
||||
END AS fix_state,
|
||||
|
||||
-- Best fixed version (if fixed)
|
||||
max(fixed_version) FILTER (WHERE fix_state = 'fixed') AS fixed_version,
|
||||
|
||||
-- Highest confidence evidence
|
||||
max(confidence) AS confidence,
|
||||
|
||||
-- Methods contributing to verdict
|
||||
array_agg(DISTINCT method) AS methods,
|
||||
|
||||
-- Evidence count
|
||||
count(*) AS evidence_count,
|
||||
|
||||
-- Latest update
|
||||
max(created_at) AS latest_evidence_at
|
||||
|
||||
FROM concelier.distro_cve_affected
|
||||
GROUP BY release_id, cve_id, package_name;
|
||||
|
||||
COMMENT ON VIEW concelier.cve_fix_status_aggregated IS 'Aggregated CVE fix status with deterministic merge logic';
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Proof Blob Summary (for querying)
|
||||
-- ----------------------------------------------------------------------------
|
||||
CREATE OR REPLACE VIEW scanner.backport_proof_summary AS
|
||||
SELECT
|
||||
bp.proof_id,
|
||||
bp.subject_id,
|
||||
bp.proof_type,
|
||||
bp.method,
|
||||
bp.confidence,
|
||||
bp.created_at,
|
||||
|
||||
-- Evidence summary
|
||||
count(pe.evidence_id) AS evidence_count,
|
||||
array_agg(DISTINCT pe.evidence_type) AS evidence_types,
|
||||
|
||||
-- Scan reference
|
||||
bp.scan_id,
|
||||
|
||||
-- Proof hash
|
||||
bp.proof_hash
|
||||
|
||||
FROM scanner.backport_proof bp
|
||||
LEFT JOIN scanner.proof_evidence pe ON bp.proof_id = pe.proof_id
|
||||
GROUP BY bp.proof_id, bp.subject_id, bp.proof_type, bp.method, bp.confidence, bp.created_at, bp.scan_id, bp.proof_hash;
|
||||
|
||||
COMMENT ON VIEW scanner.backport_proof_summary IS 'Summary view of proof blobs with evidence counts';
|
||||
|
||||
-- ============================================================================
|
||||
-- PARTITIONING (for large deployments)
|
||||
-- ============================================================================
|
||||
|
||||
-- Partition backport_proof by created_at (monthly)
|
||||
-- This is optional and should be enabled for high-volume deployments
|
||||
|
||||
-- Example partition creation (for January 2025):
|
||||
-- CREATE TABLE scanner.backport_proof_2025_01 PARTITION OF scanner.backport_proof
|
||||
-- FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
|
||||
|
||||
-- ============================================================================
|
||||
-- RETENTION POLICIES
|
||||
-- ============================================================================
|
||||
|
||||
-- Cleanup old proof blobs (optional, configure retention period)
|
||||
-- Example: Delete proofs older than 1 year that are not referenced by active scans
|
||||
|
||||
-- CREATE OR REPLACE FUNCTION scanner.cleanup_old_proofs()
|
||||
-- RETURNS INTEGER AS $$
|
||||
-- DECLARE
|
||||
-- deleted_count INTEGER;
|
||||
-- BEGIN
|
||||
-- DELETE FROM scanner.backport_proof
|
||||
-- WHERE created_at < now() - INTERVAL '1 year'
|
||||
-- AND scan_id IS NULL;
|
||||
--
|
||||
-- GET DIAGNOSTICS deleted_count = ROW_COUNT;
|
||||
-- RETURN deleted_count;
|
||||
-- END;
|
||||
-- $$ LANGUAGE plpgsql;
|
||||
|
||||
-- ============================================================================
|
||||
-- VERIFICATION
|
||||
-- ============================================================================
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
table_count INTEGER;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO table_count
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema IN ('concelier', 'scanner', 'attestor')
|
||||
AND table_name IN (
|
||||
'distro_release',
|
||||
'distro_package',
|
||||
'distro_advisory',
|
||||
'distro_cve_affected',
|
||||
'source_artifact',
|
||||
'source_patch_sig',
|
||||
'build_provenance',
|
||||
'binary_fingerprint',
|
||||
'backport_proof',
|
||||
'proof_evidence',
|
||||
'multi_profile_signature'
|
||||
);
|
||||
|
||||
IF table_count < 11 THEN
|
||||
RAISE EXCEPTION 'Proof system schema incomplete: only % of 11 tables created', table_count;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE 'Proof system schema verified: % tables created successfully', table_count;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- Release advisory lock
|
||||
SELECT pg_advisory_unlock(hashtext('proof_system'));
|
||||
|
||||
-- ============================================================================
|
||||
-- END OF SCHEMA
|
||||
-- ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user