Files
DevRunbook-Public/packages/db/migrations/0005_luxuriant_changeling.sql
T
DevRunbook release export cfd2804e27
Managed validation / full (push) Successful in 3m18s
Publish DevRunbook source
2026-09-03 04:09:17 +02:00

75 lines
4.6 KiB
PL/PgSQL

CREATE TABLE "playbook_package_files" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"playbook_version_id" uuid NOT NULL,
"path" text NOT NULL,
"role" text NOT NULL,
"content" "bytea" NOT NULL,
"size_bytes" bigint NOT NULL,
"sha256" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "playbook_package_files_version_path_uq" UNIQUE("playbook_version_id","path"),
CONSTRAINT "playbook_package_files_path_check" CHECK (length("playbook_package_files"."path") between 1 and 512 and "playbook_package_files"."path" = btrim("playbook_package_files"."path") and "playbook_package_files"."path" !~ '(^/|\\|//|(^|/)\.\.?(/|$))'),
CONSTRAINT "playbook_package_files_role_check" CHECK ("playbook_package_files"."role" in ('manifest', 'template', 'partial', 'documentation', 'changelog', 'example', 'evaluation', 'resource', 'run-pack-resource')),
CONSTRAINT "playbook_package_files_size_check" CHECK ("playbook_package_files"."size_bytes" between 0 and 5242880 and octet_length("playbook_package_files"."content") = "playbook_package_files"."size_bytes"),
CONSTRAINT "playbook_package_files_sha256_check" CHECK ("playbook_package_files"."sha256" ~ '^[0-9a-f]{64}$' and encode(digest("playbook_package_files"."content", 'sha256'), 'hex') = "playbook_package_files"."sha256")
);
--> statement-breakpoint
ALTER TABLE "playbook_versions" ADD COLUMN "draft_revision" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
ALTER TABLE "playbook_versions" ADD COLUMN "draft_digest" text DEFAULT repeat('0', 64) NOT NULL;--> statement-breakpoint
ALTER TABLE "playbook_versions" ADD COLUMN "draft_validation_json" jsonb DEFAULT '{"valid":true,"issues":[]}'::jsonb NOT NULL;--> statement-breakpoint
DROP TRIGGER "playbook_versions_published_immutable_trg" ON "playbook_versions";--> statement-breakpoint
UPDATE "playbook_versions" SET "draft_digest" = "content_digest";--> statement-breakpoint
CREATE TRIGGER playbook_versions_published_immutable_trg
BEFORE UPDATE ON "playbook_versions"
FOR EACH ROW
WHEN (OLD."published_at" IS NOT NULL)
EXECUTE FUNCTION devrunbook_reject_immutable_update();--> statement-breakpoint
ALTER TABLE "playbook_package_files" ADD CONSTRAINT "playbook_package_files_version_fk" FOREIGN KEY ("playbook_version_id") REFERENCES "public"."playbook_versions"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "playbook_package_files_version_idx" ON "playbook_package_files" USING btree ("playbook_version_id");--> statement-breakpoint
ALTER TABLE "playbook_versions" ADD CONSTRAINT "playbook_versions_draft_revision_check" CHECK ("playbook_versions"."draft_revision" > 0);--> statement-breakpoint
ALTER TABLE "playbook_versions" ADD CONSTRAINT "playbook_versions_draft_digest_check" CHECK ("playbook_versions"."draft_digest" ~ '^[0-9a-f]{64}$');--> statement-breakpoint
ALTER TABLE "playbook_versions" ADD CONSTRAINT "playbook_versions_draft_validation_check" CHECK (jsonb_typeof("playbook_versions"."draft_validation_json") = 'object');--> statement-breakpoint
CREATE FUNCTION normalize_playbook_version_draft_digest() RETURNS trigger
LANGUAGE plpgsql AS $$
BEGIN
IF NEW.draft_digest = repeat('0', 64) THEN
NEW.draft_digest := NEW.content_digest;
END IF;
RETURN NEW;
END;
$$;--> statement-breakpoint
CREATE TRIGGER playbook_versions_normalize_draft_digest
BEFORE INSERT ON playbook_versions
FOR EACH ROW EXECUTE FUNCTION normalize_playbook_version_draft_digest();--> statement-breakpoint
CREATE FUNCTION reject_published_playbook_file_mutation() RETURNS trigger
LANGUAGE plpgsql AS $$
DECLARE
target_version_id uuid;
target_published_at timestamptz;
BEGIN
target_version_id := CASE WHEN TG_OP = 'DELETE' THEN OLD.playbook_version_id ELSE NEW.playbook_version_id END;
SELECT published_at INTO target_published_at
FROM playbook_versions
WHERE id = target_version_id
FOR SHARE;
IF target_published_at IS NOT NULL THEN
RAISE EXCEPTION 'published playbook package files are immutable'
USING ERRCODE = '55000';
END IF;
IF TG_OP = 'UPDATE' AND OLD.playbook_version_id <> NEW.playbook_version_id THEN
SELECT published_at INTO target_published_at
FROM playbook_versions
WHERE id = OLD.playbook_version_id
FOR SHARE;
IF target_published_at IS NOT NULL THEN
RAISE EXCEPTION 'published playbook package files are immutable'
USING ERRCODE = '55000';
END IF;
END IF;
RETURN CASE WHEN TG_OP = 'DELETE' THEN OLD ELSE NEW END;
END;
$$;--> statement-breakpoint
CREATE TRIGGER playbook_package_files_immutable_when_published
BEFORE INSERT OR UPDATE OR DELETE ON playbook_package_files
FOR EACH ROW EXECUTE FUNCTION reject_published_playbook_file_mutation();