migrations/0007_forgejo_hubs.sql: table forgejo_hubs, auto-populated via a BEFORE INSERT trigger on phase_manifests that reads repo_hub/ repo_hub_uri straight out of the manifest JSONB (no top-level columns needed). ON CONFLICT DO NOTHING -- a hub already seen is left alone; correcting a URI is a SECURITY DEFINER governance action (correct_forgejo_hub_uri), not a plain UPDATE, matching every other governance-action pattern in this project. Thin Python wrappers added to registry.py. tests/test_forgejo_hubs.py (6 Docker-gated tests) and tests/test_reference_docs.py (13 tests, no Docker needed -- smoke-tests every real specs/policies/specs/profiles/ file, not just the two exercised incidentally by T03's Control Plane tests). All seven WP-0015 tasks done; workplan marked finished. Final suite: 94 passing offline, 183 passing under the service extras venv. No stray Docker containers left running. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
84 lines
3.2 KiB
PL/PgSQL
84 lines
3.2 KiB
PL/PgSQL
-- WP-0015-T05 (specs/PhaseProvenanceSpecAddendum.md §4): the Forgejo
|
|
-- hub -> service URI registry.
|
|
-- Depends on migrations/0001_registries.sql (phase_manifests).
|
|
--
|
|
-- Per WP-0012-T02's accepted decision: target-revenue is the generic
|
|
-- framework, not a specific deployment's list of repos it monetizes, so
|
|
-- this mapping is hosted Trust Service data (parallel to
|
|
-- licensor_identities, migrations/0005_licensor_credentials.sql), never
|
|
-- a file in this git repo. A Phase Manifest stays fully self-describing
|
|
-- and offline-verifiable regardless -- it already carries
|
|
-- repo_hub_uri/repo_name directly at registration time
|
|
-- (specs/PhaseLifecycleUseCases.md use case 9). This table exists purely
|
|
-- as an admin/repair convenience: if a hub's URI ever changes, there is
|
|
-- one row to correct rather than every affected Phase Manifest.
|
|
|
|
BEGIN;
|
|
|
|
CREATE TABLE IF NOT EXISTS forgejo_hubs (
|
|
hub_slug text PRIMARY KEY,
|
|
service_uri text NOT NULL,
|
|
first_seen_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
GRANT SELECT, INSERT ON forgejo_hubs TO trf_app;
|
|
-- No UPDATE/DELETE grant for trf_app -- correcting a hub's URI after the
|
|
-- fact is a governance action (correct_forgejo_hub_uri() below), same
|
|
-- pattern as set_extension_status()/revoke_credential(), not a route
|
|
-- the application's ordinary write path can take.
|
|
|
|
-- Auto-populate on first sight of a repo_hub during Phase registration --
|
|
-- registry.register_phase_manifest() never needs to know this table
|
|
-- exists; the trigger reads repo_hub/repo_hub_uri straight out of the
|
|
-- manifest JSONB it was already given, mirroring
|
|
-- ensure_licensor_identity()'s auto-create-on-first-INSERT pattern.
|
|
-- ON CONFLICT DO NOTHING: a hub already seen is left alone here -- URI
|
|
-- corrections go through correct_forgejo_hub_uri() below, not a silent
|
|
-- overwrite on the next unrelated Phase registration.
|
|
CREATE OR REPLACE FUNCTION ensure_forgejo_hub() RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $$
|
|
DECLARE
|
|
v_hub_slug text := NEW.manifest #>> '{phase,milestone_release,repo_hub}';
|
|
v_hub_uri text := NEW.manifest #>> '{phase,milestone_release,repo_hub_uri}';
|
|
BEGIN
|
|
IF v_hub_slug IS NOT NULL AND v_hub_uri IS NOT NULL THEN
|
|
INSERT INTO forgejo_hubs (hub_slug, service_uri)
|
|
VALUES (v_hub_slug, v_hub_uri)
|
|
ON CONFLICT (hub_slug) DO NOTHING;
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
DROP TRIGGER IF EXISTS phase_manifests_ensure_forgejo_hub ON phase_manifests;
|
|
CREATE TRIGGER phase_manifests_ensure_forgejo_hub
|
|
BEFORE INSERT ON phase_manifests
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION ensure_forgejo_hub();
|
|
|
|
-- Correcting a hub's URI after the fact (a domain move, etc.) is a
|
|
-- recorded governance action, not an ordinary UPDATE -- trf_app has no
|
|
-- UPDATE grant on forgejo_hubs at all.
|
|
CREATE OR REPLACE FUNCTION correct_forgejo_hub_uri(
|
|
p_hub_slug text,
|
|
p_new_uri text
|
|
) RETURNS void
|
|
LANGUAGE plpgsql
|
|
SECURITY DEFINER
|
|
AS $$
|
|
BEGIN
|
|
UPDATE forgejo_hubs
|
|
SET service_uri = p_new_uri,
|
|
updated_at = now()
|
|
WHERE hub_slug = p_hub_slug;
|
|
IF NOT FOUND THEN
|
|
RAISE EXCEPTION 'unknown forgejo hub: %', p_hub_slug;
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
GRANT EXECUTE ON FUNCTION correct_forgejo_hub_uri(text, text) TO trf_app;
|
|
|
|
COMMIT;
|