Gaps fill up, fixes, ui restructuring

This commit is contained in:
master
2026-02-19 22:10:54 +02:00
parent b5829dce5c
commit 04cacdca8a
331 changed files with 42859 additions and 2174 deletions

View File

@@ -0,0 +1,204 @@
-- Migration: 045_ReleaseControlBundleLifecycle
-- Purpose: Add release-control bundle lifecycle persistence for UI v2 shell contracts.
-- Sprint: SPRINT_20260219_008 (BE8-03)
-- ============================================================================
-- Bundle catalog
-- ============================================================================
CREATE TABLE IF NOT EXISTS release.control_bundles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
slug TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT NOT NULL DEFAULT 'system',
CONSTRAINT uq_control_bundles_tenant_slug UNIQUE (tenant_id, slug)
);
CREATE INDEX IF NOT EXISTS idx_control_bundles_tenant_name
ON release.control_bundles (tenant_id, name, id);
CREATE INDEX IF NOT EXISTS idx_control_bundles_tenant_updated
ON release.control_bundles (tenant_id, updated_at DESC, id);
COMMENT ON TABLE release.control_bundles IS
'Release-control bundle identities scoped per tenant.';
-- ============================================================================
-- Immutable bundle versions
-- ============================================================================
CREATE TABLE IF NOT EXISTS release.control_bundle_versions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
bundle_id UUID NOT NULL REFERENCES release.control_bundles(id) ON DELETE CASCADE,
version_number INT NOT NULL CHECK (version_number > 0),
digest TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'published' CHECK (status IN ('published', 'deprecated')),
components_count INT NOT NULL DEFAULT 0,
changelog TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
published_at TIMESTAMPTZ,
created_by TEXT NOT NULL DEFAULT 'system',
CONSTRAINT uq_control_bundle_versions_bundle_version UNIQUE (bundle_id, version_number)
);
CREATE INDEX IF NOT EXISTS idx_control_bundle_versions_tenant_bundle
ON release.control_bundle_versions (tenant_id, bundle_id, version_number DESC, id DESC);
CREATE INDEX IF NOT EXISTS idx_control_bundle_versions_tenant_digest
ON release.control_bundle_versions (tenant_id, digest);
COMMENT ON TABLE release.control_bundle_versions IS
'Immutable versions for release-control bundles.';
-- ============================================================================
-- Version components
-- ============================================================================
CREATE TABLE IF NOT EXISTS release.control_bundle_components (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
bundle_id UUID NOT NULL REFERENCES release.control_bundles(id) ON DELETE CASCADE,
bundle_version_id UUID NOT NULL REFERENCES release.control_bundle_versions(id) ON DELETE CASCADE,
component_version_id TEXT NOT NULL,
component_name TEXT NOT NULL,
image_digest TEXT NOT NULL,
deploy_order INT NOT NULL DEFAULT 0,
metadata_json JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_control_bundle_components_unique
UNIQUE (bundle_version_id, component_version_id, deploy_order)
);
CREATE INDEX IF NOT EXISTS idx_control_bundle_components_tenant_version
ON release.control_bundle_components (tenant_id, bundle_version_id, deploy_order, component_name, component_version_id);
CREATE INDEX IF NOT EXISTS idx_control_bundle_components_tenant_bundle
ON release.control_bundle_components (tenant_id, bundle_id, bundle_version_id);
COMMENT ON TABLE release.control_bundle_components IS
'Component manifests attached to immutable release-control bundle versions.';
-- ============================================================================
-- Materialization runs
-- ============================================================================
CREATE TABLE IF NOT EXISTS release.control_bundle_materialization_runs (
run_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
bundle_id UUID NOT NULL REFERENCES release.control_bundles(id) ON DELETE CASCADE,
bundle_version_id UUID NOT NULL REFERENCES release.control_bundle_versions(id) ON DELETE CASCADE,
status TEXT NOT NULL DEFAULT 'queued' CHECK (status IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')),
target_environment TEXT,
reason TEXT,
requested_by TEXT NOT NULL DEFAULT 'system',
idempotency_key TEXT,
requested_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_control_bundle_materialization_tenant_version
ON release.control_bundle_materialization_runs (tenant_id, bundle_id, bundle_version_id, requested_at DESC, run_id DESC);
CREATE INDEX IF NOT EXISTS idx_control_bundle_materialization_tenant_status
ON release.control_bundle_materialization_runs (tenant_id, status, requested_at DESC);
CREATE UNIQUE INDEX IF NOT EXISTS uq_control_bundle_materialization_idempotency
ON release.control_bundle_materialization_runs (tenant_id, bundle_id, bundle_version_id, idempotency_key)
WHERE idempotency_key IS NOT NULL;
COMMENT ON TABLE release.control_bundle_materialization_runs IS
'Auditable materialization runs for release-control bundle versions.';
-- ============================================================================
-- Row level security
-- ============================================================================
ALTER TABLE release.control_bundles ENABLE ROW LEVEL SECURITY;
ALTER TABLE release.control_bundle_versions ENABLE ROW LEVEL SECURITY;
ALTER TABLE release.control_bundle_components ENABLE ROW LEVEL SECURITY;
ALTER TABLE release.control_bundle_materialization_runs ENABLE ROW LEVEL SECURITY;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_policies
WHERE schemaname = 'release'
AND tablename = 'control_bundles'
AND policyname = 'control_bundles_tenant_isolation') THEN
CREATE POLICY control_bundles_tenant_isolation ON release.control_bundles
FOR ALL
USING (tenant_id = release_app.require_current_tenant())
WITH CHECK (tenant_id = release_app.require_current_tenant());
END IF;
END
$$;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_policies
WHERE schemaname = 'release'
AND tablename = 'control_bundle_versions'
AND policyname = 'control_bundle_versions_tenant_isolation') THEN
CREATE POLICY control_bundle_versions_tenant_isolation ON release.control_bundle_versions
FOR ALL
USING (tenant_id = release_app.require_current_tenant())
WITH CHECK (tenant_id = release_app.require_current_tenant());
END IF;
END
$$;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_policies
WHERE schemaname = 'release'
AND tablename = 'control_bundle_components'
AND policyname = 'control_bundle_components_tenant_isolation') THEN
CREATE POLICY control_bundle_components_tenant_isolation ON release.control_bundle_components
FOR ALL
USING (tenant_id = release_app.require_current_tenant())
WITH CHECK (tenant_id = release_app.require_current_tenant());
END IF;
END
$$;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_policies
WHERE schemaname = 'release'
AND tablename = 'control_bundle_materialization_runs'
AND policyname = 'control_bundle_materialization_runs_tenant_isolation') THEN
CREATE POLICY control_bundle_materialization_runs_tenant_isolation ON release.control_bundle_materialization_runs
FOR ALL
USING (tenant_id = release_app.require_current_tenant())
WITH CHECK (tenant_id = release_app.require_current_tenant());
END IF;
END
$$;
-- ============================================================================
-- Update triggers
-- ============================================================================
DROP TRIGGER IF EXISTS trg_control_bundles_updated_at ON release.control_bundles;
CREATE TRIGGER trg_control_bundles_updated_at
BEFORE UPDATE ON release.control_bundles
FOR EACH ROW
EXECUTE FUNCTION release.update_updated_at_column();
DROP TRIGGER IF EXISTS trg_control_bundle_materialization_runs_updated_at ON release.control_bundle_materialization_runs;
CREATE TRIGGER trg_control_bundle_materialization_runs_updated_at
BEFORE UPDATE ON release.control_bundle_materialization_runs
FOR EACH ROW
EXECUTE FUNCTION release.update_updated_at_column();

View File

@@ -0,0 +1,71 @@
-- SPRINT_20260219_016 / PACK-ADM-02
-- Administration A6 trust and signing owner mutation persistence.
CREATE TABLE IF NOT EXISTS release.trust_keys (
id uuid PRIMARY KEY,
tenant_id uuid NOT NULL,
key_alias text NOT NULL,
algorithm text NOT NULL,
status text NOT NULL,
current_version integer NOT NULL DEFAULT 1,
metadata_json jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL,
updated_at timestamptz NOT NULL,
created_by text NOT NULL,
updated_by text NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS ux_release_trust_keys_tenant_alias
ON release.trust_keys (tenant_id, lower(key_alias));
CREATE INDEX IF NOT EXISTS ix_release_trust_keys_tenant_status
ON release.trust_keys (tenant_id, status);
CREATE TABLE IF NOT EXISTS release.trust_issuers (
id uuid PRIMARY KEY,
tenant_id uuid NOT NULL,
issuer_name text NOT NULL,
issuer_uri text NOT NULL,
trust_level text NOT NULL,
status text NOT NULL,
created_at timestamptz NOT NULL,
updated_at timestamptz NOT NULL,
created_by text NOT NULL,
updated_by text NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS ux_release_trust_issuers_tenant_uri
ON release.trust_issuers (tenant_id, lower(issuer_uri));
CREATE INDEX IF NOT EXISTS ix_release_trust_issuers_tenant_status
ON release.trust_issuers (tenant_id, status);
CREATE TABLE IF NOT EXISTS release.trust_certificates (
id uuid PRIMARY KEY,
tenant_id uuid NOT NULL,
key_id uuid NULL REFERENCES release.trust_keys(id) ON DELETE SET NULL,
issuer_id uuid NULL REFERENCES release.trust_issuers(id) ON DELETE SET NULL,
serial_number text NOT NULL,
status text NOT NULL,
not_before timestamptz NOT NULL,
not_after timestamptz NOT NULL,
created_at timestamptz NOT NULL,
updated_at timestamptz NOT NULL,
created_by text NOT NULL,
updated_by text NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS ux_release_trust_certificates_tenant_serial
ON release.trust_certificates (tenant_id, lower(serial_number));
CREATE INDEX IF NOT EXISTS ix_release_trust_certificates_tenant_status
ON release.trust_certificates (tenant_id, status);
CREATE TABLE IF NOT EXISTS release.trust_transparency_configs (
tenant_id uuid PRIMARY KEY,
log_url text NOT NULL,
witness_url text NULL,
enforce_inclusion boolean NOT NULL DEFAULT false,
updated_at timestamptz NOT NULL,
updated_by text NOT NULL
);