diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/17_plus/allowed_privs.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/17_plus/sql/allowed_privs.json similarity index 100% rename from web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/17_plus/allowed_privs.json rename to web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/17_plus/sql/allowed_privs.json diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/17_plus/allowed_privs.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/17_plus/sql/allowed_privs.json similarity index 100% rename from web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/17_plus/allowed_privs.json rename to web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/17_plus/sql/allowed_privs.json diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/17_plus/allowed_privs.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/17_plus/sql/allowed_privs.json similarity index 100% rename from web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/17_plus/allowed_privs.json rename to web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/17_plus/sql/allowed_privs.json diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/ppas/17_plus/allowed_privs.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/ppas/17_plus/sql/allowed_privs.json similarity index 100% rename from web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/ppas/17_plus/allowed_privs.json rename to web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/ppas/17_plus/sql/allowed_privs.json diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv_msql.sql new file mode 100644 index 00000000000..c92eb9d341c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv_msql.sql @@ -0,0 +1,2 @@ +REVOKE ALL ON TABLE public."testmview_$%{}[]()&*^!/@`#" FROM ; +GRANT INSERT, SELECT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_msql.sql new file mode 100644 index 00000000000..bdf4b291a36 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_msql.sql @@ -0,0 +1 @@ +GRANT INSERT, SELECT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv_msql.sql new file mode 100644 index 00000000000..81ce5fe812e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv_msql.sql @@ -0,0 +1,2 @@ +REVOKE ALL ON TABLE public."testmview_$%{}[]()&*^!/@`#" FROM enterprisedb; +GRANT INSERT, SELECT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_msql.sql new file mode 100644 index 00000000000..bdf4b291a36 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_msql.sql @@ -0,0 +1 @@ +GRANT INSERT, SELECT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py new file mode 100644 index 00000000000..cc036ee894f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py @@ -0,0 +1,54 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2026, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Verify that the PG17+ allowed_privs.json for views/materialized views +resolves via the versioned template loader (issue #10350). It previously +lived directly under the 17_plus bucket instead of under a sql/ +subdirectory like every other bucket, so it was never found and the +MAINTAIN privilege ('m') silently fell back to the default bucket's list, +which lacks it. +""" + +import json + +from flask import render_template + +from pgadmin.utils.route import BaseTestGenerator + +# PG17 in pgAdmin's version-number-times-10000 scheme. +PG17 = 170000 + +_ALLOWED_PRIVS_JSON = 'sql/allowed_privs.json' + + +class AllowedPrivsJsonPathTestCase(BaseTestGenerator): + """Loading allowed_privs.json for PG17+ must pick up the 17_plus + bucket's list (with MAINTAIN), not silently fall back to default. + """ + + scenarios = [ + ('views on pg', dict(base_template='views/pg/#{0}#')), + ('views on ppas', dict(base_template='views/ppas/#{0}#')), + ('materialized views on pg', dict( + base_template='mviews/pg/#{0}#')), + ('materialized views on ppas', dict( + base_template='mviews/ppas/#{0}#')), + ] + + def setUp(self): + pass + + def runTest(self): + template_path = self.base_template.format(PG17) + with self.app.app_context(): + rendered = render_template( + '/'.join([template_path, _ALLOWED_PRIVS_JSON]) + ) + allowed_acls = json.loads(rendered) + self.assertIn('m', allowed_acls['datacl']['acl'])