Complete WP-0015: forgejo_hubs migration + closeout (T05/T07)
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>
This commit is contained in:
parent
eaea89e125
commit
de308f8947
6 changed files with 419 additions and 5 deletions
84
migrations/0007_forgejo_hubs.sql
Normal file
84
migrations/0007_forgejo_hubs.sql
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
-- 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;
|
||||
Loading…
Add table
Add a link
Reference in a new issue