Add topology auth policies + journey findings notes

Concelier:
- Register Topology.Read, Topology.Manage, Topology.Admin authorization
  policies mapped to OrchRead/OrchOperate/PlatformContextRead/IntegrationWrite
  scopes. Previously these policies were referenced by endpoints but never
  registered, causing System.InvalidOperationException on every topology
  API call.

Gateway routes:
- Simplified targets/environments routes (removed specific sub-path routes,
  use catch-all patterns instead)
- Changed environments base route to JobEngine (where CRUD lives)
- Changed to ReverseProxy type for all topology routes

KNOWN ISSUE (not yet fixed):
- ReverseProxy routes don't forward the gateway's identity envelope to
  Concelier. The regions/targets/bindings endpoints return 401 because
  hasPrincipal=False — the gateway authenticates the user but doesn't
  pass the identity to the backend via ReverseProxy. Microservice routes
  use Valkey transport which includes envelope headers. Topology endpoints
  need either: (a) Valkey transport registration in Concelier, or
  (b) Concelier configured to accept raw bearer tokens on ReverseProxy paths.
  This is an architecture-level fix.

Journey findings collected so far:
- Integration wizard (Harbor + GitHub App): works end-to-end
- Advisory Check All: fixed (parallel individual checks)
- Mirror domain creation: works, generate-immediately fails silently
- Topology wizard Step 1 (Region): blocked by auth passthrough issue
- Topology wizard Step 2 (Environment): POST to JobEngine needs verify
- User ID resolution: raw hashes shown everywhere

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-03-16 08:12:39 +02:00
parent 602df77467
commit da76d6e93e
223 changed files with 24763 additions and 489 deletions

View File

@@ -58,3 +58,72 @@ $$;
-- Analytics schema
CREATE SCHEMA IF NOT EXISTS analytics;
-- ── Regions (bootstrap fallback for release.regions) ──
CREATE TABLE IF NOT EXISTS release.regions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES shared.tenants(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
display_name VARCHAR(255) NOT NULL,
description TEXT,
crypto_profile VARCHAR(50) NOT NULL DEFAULT 'international',
sort_order INT NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','decommissioning','archived')),
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID,
UNIQUE(tenant_id, name)
);
-- ── Infrastructure Bindings (bootstrap fallback) ──
CREATE TABLE IF NOT EXISTS release.infrastructure_bindings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES shared.tenants(id) ON DELETE CASCADE,
integration_id UUID,
scope_type TEXT NOT NULL CHECK (scope_type IN ('tenant','region','environment')),
scope_id UUID,
binding_role TEXT NOT NULL CHECK (binding_role IN ('registry','vault','settings_store')),
priority INT NOT NULL DEFAULT 0,
config_overrides JSONB NOT NULL DEFAULT '{}',
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID
);
-- ── Topology Point Status (bootstrap fallback) ──
CREATE TABLE IF NOT EXISTS release.topology_point_status (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
target_id UUID,
gate_name TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('pending','pass','fail','skip')),
message TEXT,
details JSONB NOT NULL DEFAULT '{}',
checked_at TIMESTAMPTZ,
duration_ms INT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ── Pending Deletions (bootstrap fallback) ──
CREATE TABLE IF NOT EXISTS release.pending_deletions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
entity_type TEXT NOT NULL CHECK (entity_type IN ('tenant','region','environment','target','agent','integration')),
entity_id UUID NOT NULL,
entity_name TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('pending','confirmed','executing','completed','cancelled')),
cool_off_hours INT NOT NULL,
cool_off_expires_at TIMESTAMPTZ NOT NULL,
cascade_summary JSONB NOT NULL DEFAULT '{}',
reason TEXT,
requested_by UUID NOT NULL,
requested_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
confirmed_by UUID,
confirmed_at TIMESTAMPTZ,
executed_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);