google-cloud-bigquery 1.24.0 → 1.25.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32f4b672ccecbbd45bfb9790fc4110a22244a6459c459aa40bb1c1b4b77c1094
4
- data.tar.gz: 2ac69379fefad5547aac47be509a50945af647d7fe7b61e1653fc4dd9c9ca865
3
+ metadata.gz: ae4b6e4d7c37a945f027fe56425698b19b430f5e75451ce82f2156f2dae96719
4
+ data.tar.gz: d50284a47bf96d5221b574590a60b3af0f77b3a8943d201fd473d78f41a46670
5
5
  SHA512:
6
- metadata.gz: 9362e5d687de750ecdbdcbb131739116d3571c58db900fdf4748b6ce480f120670fce8901a8a9cfe83ddd53bbfd5e7866e396caff66e2151dc36a22dbabc3e7f
7
- data.tar.gz: f08197d575142c5c5c16ba4c09e9d96af5ccb5e92fd9b0c11b87fe8431a0cac72bc2462e57ec6080a8c2d8c45b2f92b25a908cdbab35c3116e33f41b46b82559
6
+ metadata.gz: 56c0b2d3214b385efb3866e502faa0b0c28c2fffc0c3d2ca3c5e1ad05f4d69e0638e68d59d8310c68d01c26c3db55b42225944379bfb8f6ad7a57eec558ced3a
7
+ data.tar.gz: 0562b98e65e880a40d634f541285241823354a966f4d05a559463a23eacca54addf8843f89b32731d313a56d91dfe2984f6098630c4126d7dbc97033d3dc6a81
@@ -1,5 +1,17 @@
1
1
  # Release History
2
2
 
3
+ ### 1.25.0 / 2020-11-16
4
+
5
+ #### Features
6
+
7
+ * Add routine (UDF) to Dataset::Access
8
+ * Add support for Table ACLS (IAM Policy)
9
+ * feat(bigquery): Add support for Table ACLS
10
+ * Add Bigquery::Policy
11
+ * Add Table#policy
12
+ * Add Table#test_iam_permissions
13
+ * Add Table#update_policy
14
+
3
15
  ### 1.24.0 / 2020-10-29
4
16
 
5
17
  #### Features
@@ -54,6 +54,7 @@ module Google
54
54
  "groupByEmail" => :group_by_email,
55
55
  "iam_member" => :iam_member,
56
56
  "iamMember" => :iam_member,
57
+ "routine" => :routine,
57
58
  "special" => :special_group,
58
59
  "special_group" => :special_group,
59
60
  "specialGroup" => :special_group,
@@ -212,6 +213,33 @@ module Google
212
213
  add_access_role_scope_value :reader, :special, group
213
214
  end
214
215
 
216
+ ##
217
+ # Add access to a routine from a different dataset. Queries executed
218
+ # against that routine will have read access to views/tables/routines
219
+ # in this dataset. Only UDF is supported for now. The role field is
220
+ # not required when this field is set. If that routine is updated by
221
+ # any user, access to the routine needs to be granted again via an
222
+ # update operation.
223
+ #
224
+ # @param [Google::Cloud::Bigquery::Routine] routine A routine object.
225
+ #
226
+ # @example
227
+ # require "google/cloud/bigquery"
228
+ #
229
+ # bigquery = Google::Cloud::Bigquery.new
230
+ # dataset = bigquery.dataset "my_dataset"
231
+ # other_dataset = bigquery.dataset "my_other_dataset", skip_lookup: true
232
+ #
233
+ # routine = other_dataset.routine "my_routine"
234
+ #
235
+ # dataset.access do |access|
236
+ # access.add_reader_routine routine
237
+ # end
238
+ #
239
+ def add_reader_routine routine
240
+ add_access_routine routine
241
+ end
242
+
215
243
  ##
216
244
  # Add reader access to a view.
217
245
  #
@@ -227,9 +255,9 @@ module Google
227
255
  #
228
256
  # bigquery = Google::Cloud::Bigquery.new
229
257
  # dataset = bigquery.dataset "my_dataset"
230
- # other_dataset = bigquery.dataset "my_other_dataset"
258
+ # other_dataset = bigquery.dataset "my_other_dataset", skip_lookup: true
231
259
  #
232
- # view = other_dataset.table "my_view"
260
+ # view = other_dataset.table "my_view", skip_lookup: true
233
261
  #
234
262
  # dataset.access do |access|
235
263
  # access.add_reader_view view
@@ -533,6 +561,28 @@ module Google
533
561
  remove_access_role_scope_value :reader, :special, group
534
562
  end
535
563
 
564
+ ##
565
+ # Remove reader access from a routine from a different dataset.
566
+ #
567
+ # @param [Google::Cloud::Bigquery::Routine] routine A routine object.
568
+ #
569
+ # @example
570
+ # require "google/cloud/bigquery"
571
+ #
572
+ # bigquery = Google::Cloud::Bigquery.new
573
+ # dataset = bigquery.dataset "my_dataset"
574
+ # other_dataset = bigquery.dataset "my_other_dataset", skip_lookup: true
575
+ #
576
+ # routine = other_dataset.routine "my_routine", skip_lookup: true
577
+ #
578
+ # dataset.access do |access|
579
+ # access.remove_reader_routine routine
580
+ # end
581
+ #
582
+ def remove_reader_routine routine
583
+ remove_access_routine routine
584
+ end
585
+
536
586
  ##
537
587
  # Remove reader access from a view.
538
588
  #
@@ -548,9 +598,9 @@ module Google
548
598
  #
549
599
  # bigquery = Google::Cloud::Bigquery.new
550
600
  # dataset = bigquery.dataset "my_dataset"
551
- # other_dataset = bigquery.dataset "my_other_dataset"
601
+ # other_dataset = bigquery.dataset "my_other_dataset", skip_lookup: true
552
602
  #
553
- # view = other_dataset.table "my_view"
603
+ # view = other_dataset.table "my_view", skip_lookup: true
554
604
  #
555
605
  # dataset.access do |access|
556
606
  # access.remove_reader_view view
@@ -849,6 +899,32 @@ module Google
849
899
  lookup_access_role_scope_value :reader, :special, group
850
900
  end
851
901
 
902
+ ##
903
+ # Checks access for a routine from a different dataset. Queries executed
904
+ # against that routine will have read access to views/tables/routines
905
+ # in this dataset. Only UDF is supported for now. The role field is
906
+ # not required when this field is set. If that routine is updated by
907
+ # any user, access to the routine needs to be granted again via an
908
+ # update operation.
909
+ #
910
+ # @param [Google::Cloud::Bigquery::Routine] routine A routine object.
911
+ #
912
+ # @example
913
+ # require "google/cloud/bigquery"
914
+ #
915
+ # bigquery = Google::Cloud::Bigquery.new
916
+ # dataset = bigquery.dataset "my_dataset"
917
+ # other_dataset = bigquery.dataset "my_other_dataset", skip_lookup: true
918
+ #
919
+ # routine = other_dataset.routine "my_routine", skip_lookup: true
920
+ #
921
+ # access = dataset.access
922
+ # access.reader_routine? routine #=> false
923
+ #
924
+ def reader_routine? routine
925
+ lookup_access_routine routine
926
+ end
927
+
852
928
  ##
853
929
  # Checks reader access for a view.
854
930
  #
@@ -864,9 +940,9 @@ module Google
864
940
  #
865
941
  # bigquery = Google::Cloud::Bigquery.new
866
942
  # dataset = bigquery.dataset "my_dataset"
867
- # other_dataset = bigquery.dataset "my_other_dataset"
943
+ # other_dataset = bigquery.dataset "my_other_dataset", skip_lookup: true
868
944
  #
869
- # view = other_dataset.table "my_view"
945
+ # view = other_dataset.table "my_view", skip_lookup: true
870
946
  #
871
947
  # access = dataset.access
872
948
  # access.reader_view? view #=> false
@@ -1121,12 +1197,22 @@ module Google
1121
1197
  @rules << Google::Apis::BigqueryV2::Dataset::Access.new(opts)
1122
1198
  end
1123
1199
 
1200
+ # @private
1201
+ def add_access_routine routine
1202
+ value = routine.routine_ref
1203
+ # Remove existing routine rule, if any
1204
+ @rules.reject!(&find_by_scope_and_resource_ref(:routine, value))
1205
+ # Add new rule for this role, scope, and value
1206
+ opts = { routine: value }
1207
+ @rules << Google::Apis::BigqueryV2::Dataset::Access.new(opts)
1208
+ end
1209
+
1124
1210
  # @private
1125
1211
  def add_access_view value
1126
1212
  # scope is view, make sure value is in the right format
1127
1213
  value = validate_view value
1128
1214
  # Remove existing view rule, if any
1129
- @rules.reject!(&find_view(value))
1215
+ @rules.reject!(&find_by_scope_and_resource_ref(:view, value))
1130
1216
  # Add new rule for this role, scope, and value
1131
1217
  opts = { view: value }
1132
1218
  @rules << Google::Apis::BigqueryV2::Dataset::Access.new(opts)
@@ -1144,12 +1230,18 @@ module Google
1144
1230
  )
1145
1231
  end
1146
1232
 
1233
+ # @private
1234
+ def remove_access_routine routine
1235
+ # Remove existing routine rule, if any
1236
+ @rules.reject!(&find_by_scope_and_resource_ref(:routine, routine.routine_ref))
1237
+ end
1238
+
1147
1239
  # @private
1148
1240
  def remove_access_view value
1149
1241
  # scope is view, make sure value is in the right format
1150
1242
  value = validate_view value
1151
1243
  # Remove existing view rule, if any
1152
- @rules.reject!(&find_view(value))
1244
+ @rules.reject!(&find_by_scope_and_resource_ref(:view, value))
1153
1245
  end
1154
1246
 
1155
1247
  # @private
@@ -1162,12 +1254,18 @@ module Google
1162
1254
  !(!@rules.detect(&find_by_role_and_scope_and_value(role, scope, value)))
1163
1255
  end
1164
1256
 
1257
+ # @private
1258
+ def lookup_access_routine routine
1259
+ # Detect routine rule, if any
1260
+ !(!@rules.detect(&find_by_scope_and_resource_ref(:routine, routine.routine_ref)))
1261
+ end
1262
+
1165
1263
  # @private
1166
1264
  def lookup_access_view value
1167
1265
  # scope is view, make sure value is in the right format
1168
1266
  value = validate_view value
1169
1267
  # Detect view rule, if any
1170
- !(!@rules.detect(&find_view(value)))
1268
+ !(!@rules.detect(&find_by_scope_and_resource_ref(:view, value)))
1171
1269
  end
1172
1270
 
1173
1271
  # @private
@@ -1186,11 +1284,11 @@ module Google
1186
1284
  end
1187
1285
  end
1188
1286
 
1189
- # @private
1190
- def find_view value
1287
+ # @private Compare hash representations to find table_ref, routine_ref.
1288
+ def find_by_scope_and_resource_ref scope, value
1191
1289
  lambda do |a|
1192
1290
  h = a.to_h
1193
- h[:view].to_h == value.to_h
1291
+ h[scope].to_h == value.to_h
1194
1292
  end
1195
1293
  end
1196
1294
  end
@@ -0,0 +1,431 @@
1
+ # Copyright 2020 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require "google/apis/bigquery_v2"
17
+
18
+ module Google
19
+ module Cloud
20
+ module Bigquery
21
+ ##
22
+ # # Policy
23
+ #
24
+ # Represents a Cloud IAM Policy for BigQuery resources.
25
+ #
26
+ # A Policy is a collection of bindings. A {Policy::Binding} binds one or more members to a single role. Member
27
+ # strings can describe user accounts, service accounts, Google groups, and domains. A role string represents a
28
+ # named list of permissions; each role can be an IAM predefined role or a user-created custom role.
29
+ #
30
+ # @see https://cloud.google.com/iam/docs/managing-policies Managing Policies
31
+ # @see https://cloud.google.com/bigquery/docs/table-access-controls-intro Controlling access to tables
32
+ #
33
+ # @attr [String] etag Used to check if the policy has changed since the last request. When you make a request with
34
+ # an `etag` value, Cloud IAM compares the `etag` value in the request with the existing `etag` value associated
35
+ # with the policy. It writes the policy only if the `etag` values match.
36
+ # @attr [Array<Binding>] bindings The bindings in the policy, which may be mutable or frozen depending on the
37
+ # context. See [Understanding Roles](https://cloud.google.com/iam/docs/understanding-roles) for a list of
38
+ # primitive and curated roles. See [BigQuery Table ACL
39
+ # permissions](https://cloud.google.com/bigquery/docs/table-access-controls-intro#permissions) for a list of
40
+ # values and patterns for members.
41
+ #
42
+ # @example
43
+ # require "google/cloud/bigquery"
44
+ #
45
+ # bigquery = Google::Cloud::Bigquery.new
46
+ # dataset = bigquery.dataset "my_dataset"
47
+ # table = dataset.table "my_table"
48
+ # policy = table.policy
49
+ #
50
+ # policy.frozen? #=> true
51
+ # binding_owner = policy.bindings.find { |b| b.role == "roles/owner" }
52
+ #
53
+ # binding_owner.role #=> "roles/owner"
54
+ # binding_owner.members #=> ["user:owner@example.com"]
55
+ # binding_owner.frozen? #=> true
56
+ # binding_owner.members.frozen? #=> true
57
+ #
58
+ # @example Update mutable bindings in the policy.
59
+ # require "google/cloud/bigquery"
60
+ #
61
+ # bigquery = Google::Cloud::Bigquery.new
62
+ # dataset = bigquery.dataset "my_dataset"
63
+ # table = dataset.table "my_table"
64
+ #
65
+ # table.update_policy do |p|
66
+ # p.grant role: "roles/viewer", members: "user:viewer@example.com"
67
+ # p.revoke role: "roles/editor", members: "user:editor@example.com"
68
+ # p.revoke role: "roles/owner"
69
+ # end
70
+ #
71
+ # @example Iterate over frozen bindings.
72
+ # require "google/cloud/bigquery"
73
+ #
74
+ # bigquery = Google::Cloud::Bigquery.new
75
+ # dataset = bigquery.dataset "my_dataset"
76
+ # table = dataset.table "my_table"
77
+ # policy = table.policy
78
+ #
79
+ # policy.frozen? #=> true
80
+ # policy.bindings.each do |b|
81
+ # puts b.role
82
+ # puts b.members
83
+ # end
84
+ #
85
+ # @example Update mutable bindings.
86
+ # require "google/cloud/bigquery"
87
+ #
88
+ # bigquery = Google::Cloud::Bigquery.new
89
+ # dataset = bigquery.dataset "my_dataset"
90
+ # table = dataset.table "my_table"
91
+ #
92
+ # table.update_policy do |p|
93
+ # p.bindings.each do |b|
94
+ # b.members.delete_if { |m| m.include? "@example.com" }
95
+ # end
96
+ # end
97
+ #
98
+ class Policy
99
+ attr_reader :etag, :bindings
100
+
101
+ # @private
102
+ def initialize etag, bindings
103
+ @etag = etag.freeze
104
+ @bindings = bindings
105
+ end
106
+
107
+ ##
108
+ # Convenience method adding or updating a binding in the policy. See [Understanding
109
+ # Roles](https://cloud.google.com/iam/docs/understanding-roles) for a list of primitive and curated roles. See
110
+ # [BigQuery Table ACL
111
+ # permissions](https://cloud.google.com/bigquery/docs/table-access-controls-intro#permissions) for a list of
112
+ # values and patterns for members.
113
+ #
114
+ # @param [String] role The role that is bound to members in the binding. For example, `roles/viewer`,
115
+ # `roles/editor`, or `roles/owner`. Required.
116
+ # @param [String, Array<String>] members Specifies the identities requesting access for a Cloud Platform
117
+ # resource. `members` can have the following values. Required.
118
+ #
119
+ # * `allUsers`: A special identifier that represents anyone who is on the internet; with or without a Google
120
+ # account.
121
+ # * `allAuthenticatedUsers`: A special identifier that represents anyone who is authenticated with a Google
122
+ # account or a service account.
123
+ # * `user:<emailid>`: An email address that represents a specific Google account. For example,
124
+ # `alice@example.com`.
125
+ # * `serviceAccount:<emailid>`: An email address that represents a service account. For example,
126
+ # `my-other-app@appspot.gserviceaccount.com`.
127
+ # * `group:<emailid>`: An email address that represents a Google group. For example, `admins@example.com`.
128
+ # * `deleted:user:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a user
129
+ # that has been recently deleted. For example, `alice@example.com?uid=123456789012345678901`. If the user
130
+ # is recovered, this value reverts to `user:<emailid>` and the recovered user retains the role in the
131
+ # binding.
132
+ # * `deleted: serviceAccount:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing
133
+ # a service account that has been recently deleted. For example,
134
+ # `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. If the service account is undeleted,
135
+ # this value reverts to `serviceAccount:<emailid>` and the undeleted service account retains the role in
136
+ # the binding.
137
+ # * `deleted:group:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a Google
138
+ # group that has been recently deleted. For example, `admins@example.com?uid=123456789012345678901`. If the
139
+ # group is recovered, this value reverts to `group:<emailid>` and the recovered group retains the role in
140
+ # the binding.
141
+ # * `domain:<domain>`: The G Suite domain (primary) that represents all the users of that domain. For example,
142
+ # `google.com` or `example.com`.
143
+ #
144
+ # @return [nil]
145
+ #
146
+ # @example Grant a role to a member.
147
+ # require "google/cloud/bigquery"
148
+ #
149
+ # bigquery = Google::Cloud::Bigquery.new
150
+ # dataset = bigquery.dataset "my_dataset"
151
+ # table = dataset.table "my_table"
152
+ #
153
+ # table.update_policy do |p|
154
+ # p.grant role: "roles/viewer", members: "user:viewer@example.com"
155
+ # end
156
+ #
157
+ def grant role:, members:
158
+ existing_binding = bindings.find { |b| b.role == role }
159
+ if existing_binding
160
+ existing_binding.members.concat Array(members)
161
+ existing_binding.members.uniq!
162
+ else
163
+ bindings << Binding.new(role, members)
164
+ end
165
+ nil
166
+ end
167
+
168
+ ##
169
+ # Convenience method for removing a binding or bindings from the policy. See
170
+ # [Understanding Roles](https://cloud.google.com/iam/docs/understanding-roles) for a list of primitive and
171
+ # curated roles. See [BigQuery Table ACL
172
+ # permissions](https://cloud.google.com/bigquery/docs/table-access-controls-intro#permissions) for a list of
173
+ # values and patterns for members.
174
+ #
175
+ # @param [String] role A role that is bound to members in the policy. For example, `roles/viewer`,
176
+ # `roles/editor`, or `roles/owner`. Optional.
177
+ # @param [String, Array<String>] members Specifies the identities receiving access for a Cloud Platform
178
+ # resource. `members` can have the following values. Optional.
179
+ #
180
+ # * `allUsers`: A special identifier that represents anyone who is on the internet; with or without a Google
181
+ # account.
182
+ # * `allAuthenticatedUsers`: A special identifier that represents anyone who is authenticated with a Google
183
+ # account or a service account.
184
+ # * `user:<emailid>`: An email address that represents a specific Google account. For example,
185
+ # `alice@example.com`.
186
+ # * `serviceAccount:<emailid>`: An email address that represents a service account. For example,
187
+ # `my-other-app@appspot.gserviceaccount.com`.
188
+ # * `group:<emailid>`: An email address that represents a Google group. For example, `admins@example.com`.
189
+ # * `deleted:user:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a user
190
+ # that has been recently deleted. For example, `alice@example.com?uid=123456789012345678901`. If the user
191
+ # is recovered, this value reverts to `user:<emailid>` and the recovered user retains the role in the
192
+ # binding.
193
+ # * `deleted: serviceAccount:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing
194
+ # a service account that has been recently deleted. For example,
195
+ # `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. If the service account is undeleted,
196
+ # this value reverts to `serviceAccount:<emailid>` and the undeleted service account retains the role in
197
+ # the binding.
198
+ # * `deleted:group:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a Google
199
+ # group that has been recently deleted. For example, `admins@example.com?uid=123456789012345678901`. If the
200
+ # group is recovered, this value reverts to `group:<emailid>` and the recovered group retains the role in
201
+ # the binding.
202
+ # * `domain:<domain>`: The G Suite domain (primary) that represents all the users of that domain. For example,
203
+ # `google.com` or `example.com`.
204
+ #
205
+ # @return [nil]
206
+ #
207
+ # @example Revoke a role for a member or members.
208
+ # require "google/cloud/bigquery"
209
+ #
210
+ # bigquery = Google::Cloud::Bigquery.new
211
+ # dataset = bigquery.dataset "my_dataset"
212
+ # table = dataset.table "my_table"
213
+ #
214
+ # table.update_policy do |p|
215
+ # p.revoke role: "roles/viewer", members: "user:viewer@example.com"
216
+ # end
217
+ #
218
+ # @example Revoke a role for all members.
219
+ # require "google/cloud/bigquery"
220
+ #
221
+ # bigquery = Google::Cloud::Bigquery.new
222
+ # dataset = bigquery.dataset "my_dataset"
223
+ # table = dataset.table "my_table"
224
+ #
225
+ # table.update_policy do |p|
226
+ # p.revoke role: "roles/viewer"
227
+ # end
228
+ #
229
+ # @example Revoke all roles for a member or members.
230
+ # require "google/cloud/bigquery"
231
+ #
232
+ # bigquery = Google::Cloud::Bigquery.new
233
+ # dataset = bigquery.dataset "my_dataset"
234
+ # table = dataset.table "my_table"
235
+ #
236
+ # table.update_policy do |p|
237
+ # p.revoke members: ["user:viewer@example.com", "user:editor@example.com"]
238
+ # end
239
+ #
240
+ def revoke role: nil, members: nil
241
+ bindings_for_role = role ? bindings.select { |b| b.role == role } : bindings
242
+ bindings_for_role.each do |b|
243
+ if members
244
+ b.members -= Array(members)
245
+ bindings.delete b if b.members.empty?
246
+ else
247
+ bindings.delete b
248
+ end
249
+ end
250
+ nil
251
+ end
252
+
253
+ ##
254
+ # @private Convert the Policy to a Google::Apis::BigqueryV2::Policy.
255
+ def to_gapi
256
+ Google::Apis::BigqueryV2::Policy.new(
257
+ bindings: bindings_to_gapi,
258
+ etag: etag,
259
+ version: 1
260
+ )
261
+ end
262
+
263
+ ##
264
+ # @private Deep freeze the policy including its bindings.
265
+ def freeze
266
+ super
267
+ @bindings.each(&:freeze)
268
+ @bindings.freeze
269
+ self
270
+ end
271
+
272
+ ##
273
+ # @private New Policy from a Google::Apis::BigqueryV2::Policy object.
274
+ def self.from_gapi gapi
275
+ bindings = Array(gapi.bindings).map do |binding|
276
+ Binding.new binding.role, binding.members.to_a
277
+ end
278
+ new gapi.etag, bindings
279
+ end
280
+
281
+ ##
282
+ # # Policy::Binding
283
+ #
284
+ # Represents a Cloud IAM Binding for BigQuery resources within the context of a {Policy}.
285
+ #
286
+ # A binding binds one or more members to a single role. Member strings can describe user accounts, service
287
+ # accounts, Google groups, and domains. A role is a named list of permissions; each role can be an IAM
288
+ # predefined role or a user-created custom role.
289
+ #
290
+ # @see https://cloud.google.com/bigquery/docs/table-access-controls-intro Controlling access to tables
291
+ #
292
+ # @attr [String] role The role that is assigned to `members`. For example, `roles/viewer`, `roles/editor`, or
293
+ # `roles/owner`. Required.
294
+ # @attr [Array<String>] members Specifies the identities requesting access for a Cloud Platform resource.
295
+ # `members` can have the following values. Required.
296
+ #
297
+ # * `allUsers`: A special identifier that represents anyone who is on the internet; with or without a Google
298
+ # account.
299
+ # * `allAuthenticatedUsers`: A special identifier that represents anyone who is authenticated with a Google
300
+ # account or a service account.
301
+ # * `user:<emailid>`: An email address that represents a specific Google account. For example,
302
+ # `alice@example.com`.
303
+ # * `serviceAccount:<emailid>`: An email address that represents a service account. For example,
304
+ # `my-other-app@appspot.gserviceaccount.com`.
305
+ # * `group:<emailid>`: An email address that represents a Google group. For example, `admins@example.com`.
306
+ # * `deleted:user:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a user
307
+ # that has been recently deleted. For example, `alice@example.com?uid=123456789012345678901`. If the user
308
+ # is recovered, this value reverts to `user:<emailid>` and the recovered user retains the role in the
309
+ # binding.
310
+ # * `deleted: serviceAccount:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing
311
+ # a service account that has been recently deleted. For example,
312
+ # `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. If the service account is undeleted,
313
+ # this value reverts to `serviceAccount:<emailid>` and the undeleted service account retains the role in
314
+ # the binding.
315
+ # * `deleted:group:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a Google
316
+ # group that has been recently deleted. For example, `admins@example.com?uid=123456789012345678901`. If the
317
+ # group is recovered, this value reverts to `group:<emailid>` and the recovered group retains the role in
318
+ # the binding.
319
+ # * `domain:<domain>`: The G Suite domain (primary) that represents all the users of that domain. For example,
320
+ # `google.com` or `example.com`.
321
+ #
322
+ # @example
323
+ # require "google/cloud/bigquery"
324
+ #
325
+ # bigquery = Google::Cloud::Bigquery.new
326
+ # dataset = bigquery.dataset "my_dataset"
327
+ # table = dataset.table "my_table"
328
+ #
329
+ # policy = table.policy
330
+ # binding_owner = policy.bindings.find { |b| b.role == "roles/owner" }
331
+ #
332
+ # binding_owner.role #=> "roles/owner"
333
+ # binding_owner.members #=> ["user:owner@example.com"]
334
+ #
335
+ # binding_owner.frozen? #=> true
336
+ # binding_owner.members.frozen? #=> true
337
+ #
338
+ # @example Update mutable bindings.
339
+ # require "google/cloud/bigquery"
340
+ #
341
+ # bigquery = Google::Cloud::Bigquery.new
342
+ # dataset = bigquery.dataset "my_dataset"
343
+ # table = dataset.table "my_table"
344
+ #
345
+ # table.update_policy do |p|
346
+ # binding_owner = p.bindings.find { |b| b.role == "roles/owner" }
347
+ # binding_owner.members.delete_if { |m| m.include? "@example.com" }
348
+ # end
349
+ #
350
+ class Binding
351
+ attr_accessor :role
352
+ attr_reader :members
353
+
354
+ # @private
355
+ def initialize role, members
356
+ members = Array(members).uniq
357
+ raise ArgumentError, "members cannot be empty" if members.empty?
358
+ @role = role
359
+ @members = members
360
+ end
361
+
362
+ ##
363
+ # Sets the binding members.
364
+ #
365
+ # @param [Array<String>] new_members Specifies the identities requesting access for a Cloud Platform resource.
366
+ # `new_members` can have the following values. Required.
367
+ #
368
+ # * `allUsers`: A special identifier that represents anyone who is on the internet; with or without a Google
369
+ # account.
370
+ # * `allAuthenticatedUsers`: A special identifier that represents anyone who is authenticated with a Google
371
+ # account or a service account.
372
+ # * `user:<emailid>`: An email address that represents a specific Google account. For example,
373
+ # `alice@example.com`.
374
+ # * `serviceAccount:<emailid>`: An email address that represents a service account. For example,
375
+ # `my-other-app@appspot.gserviceaccount.com`.
376
+ # * `group:<emailid>`: An email address that represents a Google group. For example, `admins@example.com`.
377
+ # * `deleted:user:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a user
378
+ # that has been recently deleted. For example, `alice@example.com?uid=123456789012345678901`. If the user
379
+ # is recovered, this value reverts to `user:<emailid>` and the recovered user retains the role in the
380
+ # binding.
381
+ # * `deleted: serviceAccount:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier)
382
+ # representing a service account that has been recently deleted. For example,
383
+ # `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. If the service account is
384
+ # undeleted, this value reverts to `serviceAccount:<emailid>` and the undeleted service account retains
385
+ # the role in the binding.
386
+ # * `deleted:group:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a
387
+ # Google group that has been recently deleted. For example,
388
+ # `admins@example.com?uid=123456789012345678901`. If the group is recovered, this value reverts to
389
+ # `group:<emailid>` and the recovered group retains the role in the binding.
390
+ # * `domain:<domain>`: The G Suite domain (primary) that represents all the users of that domain. For
391
+ # example, `google.com` or `example.com`.
392
+ #
393
+ def members= new_members
394
+ @members = Array(new_members).uniq
395
+ end
396
+
397
+ ##
398
+ # @private Convert the Binding to a Google::Apis::BigqueryV2::Binding.
399
+ def to_gapi
400
+ Google::Apis::BigqueryV2::Binding.new role: role, members: members
401
+ end
402
+
403
+ ##
404
+ # @private Deep freeze the policy including its members.
405
+ def freeze
406
+ super
407
+ role.freeze
408
+ members.each(&:freeze)
409
+ members.freeze
410
+ self
411
+ end
412
+
413
+ ##
414
+ # @private New Binding from a Google::Apis::BigqueryV2::Binding object.
415
+ def self.from_gapi gapi
416
+ new gapi.etag, gapi.members.to_a
417
+ end
418
+ end
419
+
420
+ protected
421
+
422
+ def bindings_to_gapi
423
+ @bindings.compact.uniq.map do |b|
424
+ next if b.members.empty?
425
+ b.to_gapi
426
+ end
427
+ end
428
+ end
429
+ end
430
+ end
431
+ end
@@ -182,6 +182,34 @@ module Google
182
182
  end
183
183
  end
184
184
 
185
+ ##
186
+ # Returns Google::Apis::BigqueryV2::Policy
187
+ def get_table_policy dataset_id, table_id
188
+ policy_options = API::GetPolicyOptions.new requested_policy_version: 1
189
+ execute do
190
+ service.get_table_iam_policy table_path(dataset_id, table_id),
191
+ API::GetIamPolicyRequest.new(options: policy_options)
192
+ end
193
+ end
194
+
195
+ ##
196
+ # @param [Google::Apis::BigqueryV2::Policy] new_policy
197
+ def set_table_policy dataset_id, table_id, new_policy
198
+ execute do
199
+ service.set_table_iam_policy table_path(dataset_id, table_id),
200
+ API::SetIamPolicyRequest.new(policy: new_policy)
201
+ end
202
+ end
203
+
204
+ ##
205
+ # Returns Google::Apis::BigqueryV2::TestIamPermissionsResponse
206
+ def test_table_permissions dataset_id, table_id, permissions
207
+ execute do
208
+ service.test_table_iam_permissions table_path(dataset_id, table_id),
209
+ API::TestIamPermissionsRequest.new(permissions: permissions)
210
+ end
211
+ end
212
+
185
213
  ##
186
214
  # Deletes the table specified by tableId from the dataset.
187
215
  # If the table contains data, all the data will be deleted.
@@ -508,6 +536,11 @@ module Google
508
536
 
509
537
  protected
510
538
 
539
+ # Creates a formatted table path.
540
+ def table_path dataset_id, table_id
541
+ "projects/#{@project}/datasets/#{dataset_id}/tables/#{table_id}"
542
+ end
543
+
511
544
  # Generate a random string similar to the BigQuery service job IDs.
512
545
  def generate_id
513
546
  SecureRandom.urlsafe_base64 21
@@ -23,6 +23,7 @@ require "google/cloud/bigquery/external"
23
23
  require "google/cloud/bigquery/insert_response"
24
24
  require "google/cloud/bigquery/table/async_inserter"
25
25
  require "google/cloud/bigquery/convert"
26
+ require "google/cloud/bigquery/policy"
26
27
  require "google/apis/bigquery_v2"
27
28
 
28
29
  module Google
@@ -1274,6 +1275,107 @@ module Google
1274
1275
  Array(udfs_gapi).map { |udf| udf.inline_code || udf.resource_uri }
1275
1276
  end
1276
1277
 
1278
+ ##
1279
+ # Gets the Cloud IAM access control policy for the table. The latest policy will be read from the service. See
1280
+ # also {#update_policy}.
1281
+ #
1282
+ # @see https://cloud.google.com/iam/docs/managing-policies Managing Policies
1283
+ # @see https://cloud.google.com/bigquery/docs/table-access-controls-intro Controlling access to tables
1284
+ #
1285
+ # @return [Policy] The frozen policy for the table.
1286
+ #
1287
+ # @example
1288
+ # require "google/cloud/bigquery"
1289
+ #
1290
+ # bigquery = Google::Cloud::Bigquery.new
1291
+ # dataset = bigquery.dataset "my_dataset"
1292
+ # table = dataset.table "my_table"
1293
+ #
1294
+ # policy = table.policy
1295
+ #
1296
+ # policy.frozen? #=> true
1297
+ # binding_owner = policy.bindings.find { |b| b.role == "roles/owner" }
1298
+ # binding_owner.role #=> "roles/owner"
1299
+ # binding_owner.members #=> ["user:owner@example.com"]
1300
+ # binding_owner.frozen? #=> true
1301
+ # binding_owner.members.frozen? #=> true
1302
+ #
1303
+ def policy
1304
+ raise ArgumentError, "Block argument not supported: Use #update_policy instead." if block_given?
1305
+ ensure_service!
1306
+ gapi = service.get_table_policy dataset_id, table_id
1307
+ Policy.from_gapi(gapi).freeze
1308
+ end
1309
+
1310
+ ##
1311
+ # Updates the Cloud IAM access control policy for the table. The latest policy will be read from the service.
1312
+ # See also {#policy}.
1313
+ #
1314
+ # @see https://cloud.google.com/iam/docs/managing-policies Managing Policies
1315
+ # @see https://cloud.google.com/bigquery/docs/table-access-controls-intro Controlling access to tables
1316
+ #
1317
+ # @yield [policy] A block for updating the policy. The latest policy will be read from the service and passed to
1318
+ # the block. After the block completes, the modified policy will be written to the service.
1319
+ # @yieldparam [Policy] policy The mutable Policy for the table.
1320
+ #
1321
+ # @return [Policy] The updated and frozen policy for the table.
1322
+ #
1323
+ # @example Update the policy by passing a block.
1324
+ # require "google/cloud/bigquery"
1325
+ #
1326
+ # bigquery = Google::Cloud::Bigquery.new
1327
+ # dataset = bigquery.dataset "my_dataset"
1328
+ # table = dataset.table "my_table"
1329
+ #
1330
+ # table.update_policy do |p|
1331
+ # p.grant role: "roles/viewer", members: "user:viewer@example.com"
1332
+ # p.revoke role: "roles/editor", members: "user:editor@example.com"
1333
+ # p.revoke role: "roles/owner"
1334
+ # end # 2 API calls
1335
+ #
1336
+ def update_policy
1337
+ raise ArgumentError, "A block updating the policy must be provided" unless block_given?
1338
+ ensure_service!
1339
+ gapi = service.get_table_policy dataset_id, table_id
1340
+ policy = Policy.from_gapi gapi
1341
+ yield policy
1342
+ # TODO: Check for changes before calling RPC
1343
+ gapi = service.set_table_policy dataset_id, table_id, policy.to_gapi
1344
+ Policy.from_gapi(gapi).freeze
1345
+ end
1346
+
1347
+ ##
1348
+ # Tests the specified permissions against the [Cloud
1349
+ # IAM](https://cloud.google.com/iam/) access control policy.
1350
+ #
1351
+ # @see https://cloud.google.com/iam/docs/managing-policies Managing Policies
1352
+ #
1353
+ # @param [String, Array<String>] permissions The set of permissions
1354
+ # against which to check access. Permissions must be of the format
1355
+ # `bigquery.resource.capability`.
1356
+ # See https://cloud.google.com/bigquery/docs/access-control#bigquery.
1357
+ #
1358
+ # @return [Array<String>] The frozen array of permissions held by the caller.
1359
+ #
1360
+ # @example
1361
+ # require "google/cloud/bigquery"
1362
+ #
1363
+ # bigquery = Google::Cloud::Bigquery.new
1364
+ # dataset = bigquery.dataset "my_dataset"
1365
+ # table = dataset.table "my_table"
1366
+ #
1367
+ # permissions = table.test_iam_permissions "bigquery.tables.get",
1368
+ # "bigquery.tables.delete"
1369
+ # permissions.include? "bigquery.tables.get" #=> true
1370
+ # permissions.include? "bigquery.tables.delete" #=> false
1371
+ #
1372
+ def test_iam_permissions *permissions
1373
+ permissions = Array(permissions).flatten
1374
+ ensure_service!
1375
+ gapi = service.test_table_permissions dataset_id, table_id, permissions
1376
+ gapi.permissions.freeze
1377
+ end
1378
+
1277
1379
  ##
1278
1380
  # Retrieves data from the table.
1279
1381
  #
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Bigquery
19
- VERSION = "1.24.0".freeze
19
+ VERSION = "1.25.0".freeze
20
20
  end
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-bigquery
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.24.0
4
+ version: 1.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Moore
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-10-29 00:00:00.000000000 Z
12
+ date: 2020-11-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: concurrent-ruby
@@ -257,6 +257,7 @@ files:
257
257
  - lib/google/cloud/bigquery/load_job.rb
258
258
  - lib/google/cloud/bigquery/model.rb
259
259
  - lib/google/cloud/bigquery/model/list.rb
260
+ - lib/google/cloud/bigquery/policy.rb
260
261
  - lib/google/cloud/bigquery/project.rb
261
262
  - lib/google/cloud/bigquery/project/list.rb
262
263
  - lib/google/cloud/bigquery/query_job.rb