Files
StellaOps Bot 6a299d231f
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Add unit tests for Router configuration and transport layers
- Implemented tests for RouterConfig, RoutingOptions, StaticInstanceConfig, and RouterConfigOptions to ensure default values are set correctly.
- Added tests for RouterConfigProvider to validate configurations and ensure defaults are returned when no file is specified.
- Created tests for ConfigValidationResult to check success and error scenarios.
- Developed tests for ServiceCollectionExtensions to verify service registration for RouterConfig.
- Introduced UdpTransportTests to validate serialization, connection, request-response, and error handling in UDP transport.
- Added scripts for signing authority gaps and hashing DevPortal SDK snippets.
2025-12-05 08:01:47 +02:00

221 lines
7.9 KiB
PL/PgSQL

-- Policy Schema Migration 001: Initial Schema
-- Creates the policy schema for packs, rules, and risk profiles
-- Create schema
CREATE SCHEMA IF NOT EXISTS policy;
-- Packs table (policy pack containers)
CREATE TABLE IF NOT EXISTS policy.packs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL,
name TEXT NOT NULL,
display_name TEXT,
description TEXT,
active_version INT,
is_builtin BOOLEAN NOT NULL DEFAULT FALSE,
is_deprecated BOOLEAN NOT NULL DEFAULT FALSE,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT,
UNIQUE(tenant_id, name)
);
CREATE INDEX idx_packs_tenant ON policy.packs(tenant_id);
CREATE INDEX idx_packs_builtin ON policy.packs(is_builtin);
-- Pack versions table (immutable versions)
CREATE TABLE IF NOT EXISTS policy.pack_versions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
pack_id UUID NOT NULL REFERENCES policy.packs(id) ON DELETE CASCADE,
version INT NOT NULL,
description TEXT,
rules_hash TEXT NOT NULL,
is_published BOOLEAN NOT NULL DEFAULT FALSE,
published_at TIMESTAMPTZ,
published_by TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT,
UNIQUE(pack_id, version)
);
CREATE INDEX idx_pack_versions_pack ON policy.pack_versions(pack_id);
CREATE INDEX idx_pack_versions_published ON policy.pack_versions(pack_id, is_published);
-- Rules table (OPA/Rego rules)
CREATE TABLE IF NOT EXISTS policy.rules (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
pack_version_id UUID NOT NULL REFERENCES policy.pack_versions(id) ON DELETE CASCADE,
name TEXT NOT NULL,
description TEXT,
rule_type TEXT NOT NULL DEFAULT 'rego' CHECK (rule_type IN ('rego', 'json', 'yaml')),
content TEXT NOT NULL,
content_hash TEXT NOT NULL,
severity TEXT NOT NULL DEFAULT 'medium' CHECK (severity IN ('critical', 'high', 'medium', 'low', 'info')),
category TEXT,
tags TEXT[] NOT NULL DEFAULT '{}',
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(pack_version_id, name)
);
CREATE INDEX idx_rules_pack_version ON policy.rules(pack_version_id);
CREATE INDEX idx_rules_severity ON policy.rules(severity);
CREATE INDEX idx_rules_category ON policy.rules(category);
CREATE INDEX idx_rules_tags ON policy.rules USING GIN(tags);
-- Risk profiles table
CREATE TABLE IF NOT EXISTS policy.risk_profiles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL,
name TEXT NOT NULL,
display_name TEXT,
description TEXT,
version INT NOT NULL DEFAULT 1,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
thresholds JSONB NOT NULL DEFAULT '{}',
scoring_weights JSONB NOT NULL DEFAULT '{}',
exemptions JSONB NOT NULL DEFAULT '[]',
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT,
UNIQUE(tenant_id, name, version)
);
CREATE INDEX idx_risk_profiles_tenant ON policy.risk_profiles(tenant_id);
CREATE INDEX idx_risk_profiles_active ON policy.risk_profiles(tenant_id, name, is_active)
WHERE is_active = TRUE;
-- Risk profile history (for audit trail)
CREATE TABLE IF NOT EXISTS policy.risk_profile_history (
id BIGSERIAL PRIMARY KEY,
risk_profile_id UUID NOT NULL REFERENCES policy.risk_profiles(id),
version INT NOT NULL,
thresholds JSONB NOT NULL,
scoring_weights JSONB NOT NULL,
exemptions JSONB NOT NULL,
changed_by TEXT,
changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
change_reason TEXT
);
CREATE INDEX idx_risk_profile_history_profile ON policy.risk_profile_history(risk_profile_id);
-- Evaluation runs table
CREATE TABLE IF NOT EXISTS policy.evaluation_runs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL,
project_id TEXT,
artifact_id TEXT,
pack_id UUID REFERENCES policy.packs(id),
pack_version INT,
risk_profile_id UUID REFERENCES policy.risk_profiles(id),
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'running', 'completed', 'failed')),
result TEXT CHECK (result IN ('pass', 'fail', 'warn', 'error')),
score NUMERIC(5,2),
findings_count INT NOT NULL DEFAULT 0,
critical_count INT NOT NULL DEFAULT 0,
high_count INT NOT NULL DEFAULT 0,
medium_count INT NOT NULL DEFAULT 0,
low_count INT NOT NULL DEFAULT 0,
input_hash TEXT,
duration_ms INT,
error_message TEXT,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
created_by TEXT
);
CREATE INDEX idx_evaluation_runs_tenant ON policy.evaluation_runs(tenant_id);
CREATE INDEX idx_evaluation_runs_project ON policy.evaluation_runs(tenant_id, project_id);
CREATE INDEX idx_evaluation_runs_artifact ON policy.evaluation_runs(tenant_id, artifact_id);
CREATE INDEX idx_evaluation_runs_created ON policy.evaluation_runs(tenant_id, created_at);
CREATE INDEX idx_evaluation_runs_status ON policy.evaluation_runs(status);
-- Explanations table (rule evaluation details)
CREATE TABLE IF NOT EXISTS policy.explanations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
evaluation_run_id UUID NOT NULL REFERENCES policy.evaluation_runs(id) ON DELETE CASCADE,
rule_id UUID REFERENCES policy.rules(id),
rule_name TEXT NOT NULL,
result TEXT NOT NULL CHECK (result IN ('pass', 'fail', 'skip', 'error')),
severity TEXT NOT NULL,
message TEXT,
details JSONB NOT NULL DEFAULT '{}',
remediation TEXT,
resource_path TEXT,
line_number INT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_explanations_run ON policy.explanations(evaluation_run_id);
CREATE INDEX idx_explanations_result ON policy.explanations(evaluation_run_id, result);
-- Exceptions table (policy exceptions/waivers)
CREATE TABLE IF NOT EXISTS policy.exceptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
rule_pattern TEXT,
resource_pattern TEXT,
artifact_pattern TEXT,
project_id TEXT,
reason TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'expired', 'revoked')),
expires_at TIMESTAMPTZ,
approved_by TEXT,
approved_at TIMESTAMPTZ,
revoked_by TEXT,
revoked_at TIMESTAMPTZ,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT,
UNIQUE(tenant_id, name)
);
CREATE INDEX idx_exceptions_tenant ON policy.exceptions(tenant_id);
CREATE INDEX idx_exceptions_status ON policy.exceptions(tenant_id, status);
CREATE INDEX idx_exceptions_expires ON policy.exceptions(expires_at)
WHERE status = 'active';
CREATE INDEX idx_exceptions_project ON policy.exceptions(tenant_id, project_id);
-- Audit log table
CREATE TABLE IF NOT EXISTS policy.audit (
id BIGSERIAL PRIMARY KEY,
tenant_id TEXT NOT NULL,
user_id UUID,
action TEXT NOT NULL,
resource_type TEXT NOT NULL,
resource_id TEXT,
old_value JSONB,
new_value JSONB,
correlation_id TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_audit_tenant ON policy.audit(tenant_id);
CREATE INDEX idx_audit_resource ON policy.audit(resource_type, resource_id);
CREATE INDEX idx_audit_created ON policy.audit(tenant_id, created_at);
-- Update timestamp function
CREATE OR REPLACE FUNCTION policy.update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Triggers
CREATE TRIGGER trg_packs_updated_at
BEFORE UPDATE ON policy.packs
FOR EACH ROW EXECUTE FUNCTION policy.update_updated_at();
CREATE TRIGGER trg_risk_profiles_updated_at
BEFORE UPDATE ON policy.risk_profiles
FOR EACH ROW EXECUTE FUNCTION policy.update_updated_at();