Skip to content

Check publication privileges before creating one - #59

Open
teknogeek0 wants to merge 1 commit into
mainfrom
feat/pgoutput-publication-preflight
Open

Check publication privileges before creating one#59
teknogeek0 wants to merge 1 commit into
mainfrom
feat/pgoutput-publication-preflight

Conversation

@teknogeek0

Copy link
Copy Markdown
Collaborator

Problem

With --plugin pgoutput (the default since #58), pgcopydb creates its own publication. CREATE PUBLICATION needs CREATE on the database, and CREATE PUBLICATION ... FOR TABLE needs ownership of every published table. Managed Postgres services often grant neither to a migration role.

The run failed mid-flight with a bare server error and no guidance:

ERROR [SOURCE 96659] ERROR:  permission denied for database railway
ERROR snapshot.c:742  Failed to create publication "pgcopydb"

Change

Check both privileges before the DDL and report every way forward in one pass:

ERROR Role "migration_user" has no CREATE privilege on database "railway"
ERROR Role "migration_user" does not own 180 of the 180 tables to publish,
      such as public.invoice owned by app_owner
INFO  1. GRANT CREATE ON DATABASE "railway" TO "migration_user";
INFO  2. CREATE PUBLICATION "pgcopydb" FOR ALL TABLES;  -- needs a superuser
INFO     pgcopydb ... --publication "pgcopydb"
INFO  3. pgcopydb ... --plugin wal2json

Both causes are reported together, so fixing one does not reveal the other on the next run.

  • Ownership uses pg_has_role(current_user, c.relowner, 'USAGE'), matching the server's own check, so membership in the owning role counts and superusers pass.
  • The table-list query is extracted into publication_append_table_query(), shared by the check and the CREATE. The check counts exactly the tables the publication would list, filters included.
  • Also fixes a silent failure: an empty table list produced CREATE PUBLICATION "pgcopydb" with no FOR TABLE, which decodes no change at all. It now fails with an explanation.

No CLI or docs change.

Test

New tests/pgoutput-privileges suite, four phases:

  1. No CREATE, no ownership: fails, reports both causes and all three options, leaves no publication or slot behind.
  2. CREATE granted, ownership missing: fails, reports only ownership.
  3. Membership in the owning role granted: succeeds, publication covers the 3 tables.
  4. --publication given: used as-is, pgcopydb creates none of its own.

Added to tests/Makefile and the CI integration matrix.

Results

Full PG18 suite run locally. All suites pass except exclude-extension, which is a pre-existing failure unrelated to this change: tests/exclude-extension/Dockerfile:1 defaults PGCOPYDB_IMAGE to pgcopydb:pg16 and its compose file passes no build arg, so it only works on PG16. It is not in the CI matrix.

Style check passes (citus_indent --check).

CREATE PUBLICATION needs CREATE on the database and ownership of every
published table. Many managed Postgres services grant neither to a
migration role, so pgcopydb failed mid-run with a bare permission error.

Check both up front and report the ways forward: grant the privilege,
pre-create the publication and pass --publication, or use wal2json.
Ownership uses pg_has_role(), so role membership counts.

Also fail when the table list is empty, instead of creating a publication
that decodes no change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant