privileges.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. # Copyright Materialize, Inc. and contributors. All rights reserved.
  2. #
  3. # Use of this software is governed by the Business Source License
  4. # included in the LICENSE file at the root of this repository.
  5. #
  6. # As of the Change Date specified in that file, in accordance with
  7. # the Business Source License, use of this software will be governed
  8. # by the Apache License, Version 2.0.
  9. from textwrap import dedent
  10. from materialize.checks.actions import Testdrive
  11. from materialize.checks.checks import Check
  12. class Privileges(Check):
  13. def _create_objects(self, i: int, expensive: bool = False) -> str:
  14. s = dedent(
  15. f"""
  16. $ postgres-execute connection=postgres://materialize@${{testdrive.materialize-sql-addr}}
  17. CREATE DATABASE privilege_db{i}
  18. CREATE SCHEMA privilege_schema{i}
  19. CREATE CONNECTION privilege_kafka_conn{i} FOR KAFKA {self._kafka_broker()}
  20. CREATE CONNECTION privilege_csr_conn{i} FOR CONFLUENT SCHEMA REGISTRY URL '${{testdrive.schema-registry-url}}'
  21. CREATE TYPE privilege_type{i} AS LIST (ELEMENT TYPE = text)
  22. CREATE TABLE privilege_t{i} (c1 int, c2 privilege_type{i})
  23. CREATE INDEX privilege_i{i} ON privilege_t{i} (c2)
  24. CREATE VIEW privilege_v{i} AS SELECT * FROM privilege_t{i}
  25. CREATE MATERIALIZED VIEW privilege_mv{i} AS SELECT * FROM privilege_t{i}
  26. CREATE SECRET privilege_secret{i} AS 'MY_SECRET'
  27. """
  28. )
  29. if expensive:
  30. s += dedent(
  31. f"""
  32. $ postgres-execute connection=postgres://materialize@${{testdrive.materialize-sql-addr}}
  33. CREATE SOURCE privilege_source{i} FROM LOAD GENERATOR COUNTER
  34. $ postgres-execute connection=postgres://materialize@${{testdrive.materialize-sql-addr}}
  35. CREATE SINK privilege_sink{i} FROM privilege_mv{i} INTO KAFKA CONNECTION privilege_kafka_conn{i} (TOPIC 'sink-sink-privilege{i}') FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION privilege_csr_conn{i} ENVELOPE DEBEZIUM
  36. CREATE CLUSTER privilege_cluster{i} REPLICAS (privilege_cluster_r{i} (SIZE '4'))
  37. """
  38. )
  39. return s
  40. def _grant_privileges(self, role: str, i: int, expensive: bool = False) -> str:
  41. s = dedent(
  42. f"""
  43. $ postgres-execute connection=postgres://materialize@${{testdrive.materialize-sql-addr}}
  44. GRANT ALL PRIVILEGES ON DATABASE privilege_db{i} TO {role}
  45. GRANT ALL PRIVILEGES ON SCHEMA privilege_schema{i} TO {role}
  46. GRANT ALL PRIVILEGES ON CONNECTION privilege_kafka_conn{i} TO {role}
  47. GRANT ALL PRIVILEGES ON CONNECTION privilege_csr_conn{i} TO {role}
  48. GRANT ALL PRIVILEGES ON TYPE privilege_type{i} TO {role}
  49. GRANT ALL PRIVILEGES ON TABLE privilege_t{i} TO {role}
  50. GRANT ALL PRIVILEGES ON TABLE privilege_v{i} TO {role}
  51. GRANT ALL PRIVILEGES ON TABLE privilege_mv{i} TO {role}
  52. GRANT ALL PRIVILEGES ON SECRET privilege_secret{i} TO {role}
  53. """
  54. )
  55. if expensive:
  56. s += dedent(
  57. f"""
  58. GRANT ALL PRIVILEGES ON TABLE privilege_source{i} TO {role}
  59. GRANT ALL PRIVILEGES ON CLUSTER privilege_cluster{i} TO {role}
  60. """
  61. )
  62. return s
  63. def _revoke_privileges(self, role: str, i: int, expensive: bool = False) -> str:
  64. s = dedent(
  65. f"""
  66. $ postgres-execute connection=postgres://materialize@${{testdrive.materialize-sql-addr}}
  67. REVOKE ALL PRIVILEGES ON DATABASE privilege_db{i} FROM {role}
  68. REVOKE ALL PRIVILEGES ON SCHEMA privilege_schema{i} FROM {role}
  69. REVOKE ALL PRIVILEGES ON CONNECTION privilege_kafka_conn{i} FROM {role}
  70. REVOKE ALL PRIVILEGES ON CONNECTION privilege_csr_conn{i} FROM {role}
  71. REVOKE ALL PRIVILEGES ON TYPE privilege_type{i} FROM {role}
  72. REVOKE ALL PRIVILEGES ON TABLE privilege_t{i} FROM {role}
  73. REVOKE ALL PRIVILEGES ON TABLE privilege_v{i} FROM {role}
  74. REVOKE ALL PRIVILEGES ON TABLE privilege_mv{i} FROM {role}
  75. REVOKE ALL PRIVILEGES ON SECRET privilege_secret{i} FROM {role}
  76. """
  77. )
  78. if expensive:
  79. s += dedent(
  80. f"""
  81. REVOKE ALL PRIVILEGES ON TABLE privilege_source{i} FROM {role}
  82. REVOKE ALL PRIVILEGES ON CLUSTER privilege_cluster{i} FROM {role}
  83. """
  84. )
  85. return s
  86. def _drop_objects(
  87. self, i: int, expensive: bool = False, success: bool = True
  88. ) -> str:
  89. cmds = []
  90. # Drop the sink first so we can drop the materialized view without CASCADE.
  91. if expensive:
  92. cmds += [
  93. f"DROP SOURCE privilege_source{i}",
  94. f"DROP SINK privilege_sink{i}",
  95. f"DROP CLUSTER privilege_cluster{i}",
  96. ]
  97. cmds += [
  98. f"DROP SECRET privilege_secret{i}",
  99. f"DROP MATERIALIZED VIEW privilege_mv{i}",
  100. f"DROP VIEW privilege_v{i}",
  101. f"DROP INDEX privilege_i{i}",
  102. f"DROP TABLE privilege_t{i}",
  103. f"DROP TYPE privilege_type{i}",
  104. f"DROP CONNECTION privilege_csr_conn{i}",
  105. f"DROP CONNECTION privilege_kafka_conn{i}",
  106. f"DROP SCHEMA privilege_schema{i}",
  107. f"DROP DATABASE privilege_db{i}",
  108. ]
  109. return (
  110. "$ postgres-execute connection=postgres://materialize@${testdrive.materialize-sql-addr}/materialize\n"
  111. + "\n".join(cmds)
  112. + "\n"
  113. )
  114. def initialize(self) -> Testdrive:
  115. return Testdrive(
  116. dedent(
  117. """
  118. $ postgres-execute connection=postgres://mz_system@${testdrive.materialize-internal-sql-addr}
  119. GRANT CREATEROLE ON SYSTEM TO materialize
  120. > CREATE ROLE role_1
  121. > CREATE ROLE role_2
  122. """
  123. )
  124. + self._create_objects(1, expensive=True)
  125. + self._grant_privileges("role_1", 1, expensive=True)
  126. + self._grant_privileges("role_2", 1, expensive=True)
  127. )
  128. def manipulate(self) -> list[Testdrive]:
  129. return [
  130. Testdrive(s)
  131. for s in [
  132. dedent(
  133. """
  134. $ postgres-execute connection=postgres://mz_system@${testdrive.materialize-internal-sql-addr}
  135. GRANT CREATEROLE ON SYSTEM TO materialize
  136. """
  137. )
  138. + self._revoke_privileges("role_2", 1, expensive=True)
  139. + self._create_objects(2)
  140. + self._grant_privileges("role_1", 2)
  141. + self._grant_privileges("role_2", 2),
  142. dedent(
  143. """
  144. $ postgres-execute connection=postgres://mz_system@${testdrive.materialize-internal-sql-addr}
  145. GRANT CREATEROLE ON SYSTEM TO materialize
  146. """
  147. )
  148. + self._revoke_privileges("role_2", 2)
  149. + self._create_objects(3)
  150. + self._grant_privileges("role_1", 3)
  151. + self._grant_privileges("role_1", 3),
  152. ]
  153. ]
  154. def validate(self) -> Testdrive:
  155. return Testdrive(
  156. self._revoke_privileges("role_2", 3)
  157. + self._create_objects(4)
  158. + self._grant_privileges("role_1", 4)
  159. + self._grant_privileges("role_2", 4)
  160. + self._revoke_privileges("role_2", 4)
  161. + dedent(
  162. """
  163. > SELECT name, unnest(privileges)::text FROM mz_databases WHERE name LIKE 'privilege_db%'
  164. privilege_db1 materialize=UC/materialize
  165. privilege_db2 materialize=UC/materialize
  166. privilege_db3 materialize=UC/materialize
  167. privilege_db4 materialize=UC/materialize
  168. privilege_db1 mz_support=U/materialize
  169. privilege_db2 mz_support=U/materialize
  170. privilege_db3 mz_support=U/materialize
  171. privilege_db4 mz_support=U/materialize
  172. privilege_db1 role_1=UC/materialize
  173. privilege_db2 role_1=UC/materialize
  174. privilege_db3 role_1=UC/materialize
  175. privilege_db4 role_1=UC/materialize
  176. > SELECT name, unnest(privileges)::text FROM mz_schemas WHERE name LIKE 'privilege_schema%'
  177. privilege_schema1 materialize=UC/materialize
  178. privilege_schema2 materialize=UC/materialize
  179. privilege_schema3 materialize=UC/materialize
  180. privilege_schema4 materialize=UC/materialize
  181. privilege_schema1 mz_support=U/materialize
  182. privilege_schema2 mz_support=U/materialize
  183. privilege_schema3 mz_support=U/materialize
  184. privilege_schema4 mz_support=U/materialize
  185. privilege_schema1 role_1=UC/materialize
  186. privilege_schema2 role_1=UC/materialize
  187. privilege_schema3 role_1=UC/materialize
  188. privilege_schema4 role_1=UC/materialize
  189. > SELECT name, unnest(privileges)::text FROM mz_tables WHERE name LIKE 'privilege_t%'
  190. privilege_t1 materialize=arwd/materialize
  191. privilege_t2 materialize=arwd/materialize
  192. privilege_t3 materialize=arwd/materialize
  193. privilege_t4 materialize=arwd/materialize
  194. privilege_t1 role_1=arwd/materialize
  195. privilege_t2 role_1=arwd/materialize
  196. privilege_t3 role_1=arwd/materialize
  197. privilege_t4 role_1=arwd/materialize
  198. > SELECT name, unnest(privileges)::text FROM mz_views WHERE name LIKE 'privilege_v%'
  199. privilege_v1 materialize=r/materialize
  200. privilege_v2 materialize=r/materialize
  201. privilege_v3 materialize=r/materialize
  202. privilege_v4 materialize=r/materialize
  203. privilege_v1 role_1=r/materialize
  204. privilege_v2 role_1=r/materialize
  205. privilege_v3 role_1=r/materialize
  206. privilege_v4 role_1=r/materialize
  207. > SELECT name, unnest(privileges)::text FROM mz_materialized_views WHERE name LIKE 'privilege_mv%'
  208. privilege_mv1 materialize=r/materialize
  209. privilege_mv2 materialize=r/materialize
  210. privilege_mv3 materialize=r/materialize
  211. privilege_mv4 materialize=r/materialize
  212. privilege_mv1 role_1=r/materialize
  213. privilege_mv2 role_1=r/materialize
  214. privilege_mv3 role_1=r/materialize
  215. privilege_mv4 role_1=r/materialize
  216. > SELECT name, unnest(privileges)::text FROM mz_types WHERE name LIKE 'privilege_type%'
  217. privilege_type1 =U/materialize
  218. privilege_type1 materialize=U/materialize
  219. privilege_type1 role_1=U/materialize
  220. privilege_type2 =U/materialize
  221. privilege_type2 materialize=U/materialize
  222. privilege_type2 role_1=U/materialize
  223. privilege_type3 =U/materialize
  224. privilege_type3 materialize=U/materialize
  225. privilege_type3 role_1=U/materialize
  226. privilege_type4 =U/materialize
  227. privilege_type4 materialize=U/materialize
  228. privilege_type4 role_1=U/materialize
  229. > SELECT name, unnest(privileges)::text FROM mz_secrets WHERE name LIKE 'privilege_secret%'
  230. privilege_secret1 materialize=U/materialize
  231. privilege_secret2 materialize=U/materialize
  232. privilege_secret3 materialize=U/materialize
  233. privilege_secret4 materialize=U/materialize
  234. privilege_secret1 role_1=U/materialize
  235. privilege_secret2 role_1=U/materialize
  236. privilege_secret3 role_1=U/materialize
  237. privilege_secret4 role_1=U/materialize
  238. > SELECT name, unnest(privileges)::text FROM mz_sources WHERE name LIKE 'privilege_source%' AND type = 'load-generator'
  239. privilege_source1 materialize=r/materialize
  240. privilege_source1 role_1=r/materialize
  241. ! SELECT name, unnest(privileges)::text FROM mz_sinks WHERE name LIKE 'privilege_sink%'
  242. contains: column "privileges" does not exist
  243. > SELECT name, unnest(privileges)::text FROM mz_clusters WHERE name LIKE 'privilege_cluster%'
  244. privilege_cluster1 mz_support=U/materialize
  245. privilege_cluster1 materialize=UC/materialize
  246. privilege_cluster1 role_1=UC/materialize
  247. > SELECT name, unnest(privileges)::text FROM mz_connections WHERE name LIKE 'privilege_%'
  248. privilege_csr_conn1 materialize=U/materialize
  249. privilege_csr_conn2 materialize=U/materialize
  250. privilege_csr_conn3 materialize=U/materialize
  251. privilege_csr_conn4 materialize=U/materialize
  252. privilege_csr_conn1 role_1=U/materialize
  253. privilege_csr_conn2 role_1=U/materialize
  254. privilege_csr_conn3 role_1=U/materialize
  255. privilege_csr_conn4 role_1=U/materialize
  256. privilege_kafka_conn1 materialize=U/materialize
  257. privilege_kafka_conn2 materialize=U/materialize
  258. privilege_kafka_conn3 materialize=U/materialize
  259. privilege_kafka_conn4 materialize=U/materialize
  260. privilege_kafka_conn1 role_1=U/materialize
  261. privilege_kafka_conn2 role_1=U/materialize
  262. privilege_kafka_conn3 role_1=U/materialize
  263. privilege_kafka_conn4 role_1=U/materialize
  264. """
  265. )
  266. + self._drop_objects(4)
  267. )