gitlab-glaz 1.2.0-aarch64-linux-gnu → 2.0.0-aarch64-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,113 +1,255 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "json"
4
+ require "uri"
4
5
 
5
6
  module Gitlab
6
7
  module Glaz
7
- # Wraps a native Glaz::Native::GovernPolicyEngine instance - the Rego
8
- # governance policy evaluator.
8
+ # Wraps a native Glaz::Native::GovernPolicyEngine - the Rego governance
9
+ # policy evaluator.
9
10
  #
10
- # The evaluator is a pure function over its arguments: it performs no
11
- # I/O, holds no state between calls, and executes no actions. The caller
12
- # supplies the policy's Rego source and the assembled context document,
13
- # and is responsible for executing the returned actions.
11
+ # Evaluation is trigger-keyed: the caller supplies an event trigger and
12
+ # the context document, and the engine fetches the applicable policies
13
+ # from the Policy Store REST API named at construction. Authentication
14
+ # is per request (+store_authorization+ on #evaluate), never per engine
15
+ # and never from the environment. The engine executes no actions; the
16
+ # caller does.
14
17
  #
15
- # +reasons+ and +actions+ are independent, not 1:1: +reasons+ reports why
16
- # the policy matched - one entry per `violation`/`deny` element the
17
- # policy produced; empty means it did not match - while +actions+
18
- # reports what to enforce as a result. Actions are conceptually owned by
19
- # the policy's configuration in the future central Policy Store, so any
20
- # match currently yields a single synthesized block action regardless of
21
- # how many reasons fired. +matched+ is a convenience boolean mirroring
22
- # "+actions+ is non-empty", for callers who don't want to infer that
23
- # from array emptiness themselves.
18
+ # #validate and #debug_evaluate never touch the store, so an engine
19
+ # built without one (the Policy Store itself) still serves them and
20
+ # fails #evaluate closed with an ArgumentError.
24
21
  #
25
- # #evaluate is the primary path: it always auto-discovers the policy's
26
- # `violation`/`deny`/`allow` rules (the native +evaluate+ path), returns
27
- # the hardened Hash shape described below on success, and raises on any
28
- # evaluation failure - the native call itself raises ArgumentError for
29
- # bad policy/input and RuntimeError for an engine-side fault; see
30
- # #evaluate's own doc comment.
31
- # #debug_evaluate is a separate, secondary method for debugging/testing a Rego query
32
- # directly: it performs no violation/deny/allow interpretation, does
33
- # not raise, and returns whatever the query evaluated to (plus any
34
- # error, in-band) with no guarantee about its shape.
22
+ # #evaluate releases the GVL around the store lookup. It cannot be
23
+ # interrupted from Ruby until it returns, which is bounded by the
24
+ # lookup timeouts plus the batch evaluation. Instances are safe to
25
+ # share across threads and across a fork.
35
26
  class GovernPolicyEngine
36
- def initialize
37
- @native = ::Glaz::Native::GovernPolicyEngine.new
27
+ # Argument checks, raising ArgumentError instead of letting a
28
+ # Google::Protobuf::TypeError or JSON error escape from the wire layer.
29
+ #
30
+ # @api private
31
+ module Validation
32
+ module_function
33
+
34
+ INVALID_STORE_BASE_URL_MESSAGE = "store_base_url must be an http(s) URL naming the Policy Store REST API " \
35
+ "root (e.g. \"https://gitlab.com/api/v4\"), without credentials, query or fragment, and with a port " \
36
+ "in 1..65535"
37
+ private_constant :INVALID_STORE_BASE_URL_MESSAGE
38
+
39
+ def store_base_url!(url)
40
+ string!(url, "store_base_url")
41
+
42
+ parsed = begin
43
+ URI.parse(url)
44
+ rescue URI::Error
45
+ nil
46
+ end
47
+ raise ArgumentError, INVALID_STORE_BASE_URL_MESSAGE unless valid_store_base_url?(parsed)
48
+
49
+ -url
50
+ end
51
+
52
+ def string!(value, name)
53
+ raise ArgumentError, "#{name} must be a String; got #{value.class}" unless value.is_a?(String)
54
+
55
+ value
56
+ end
57
+
58
+ # The message never echoes +value+: it is a credential.
59
+ def store_authorization!(value)
60
+ return value.to_s if value.nil? || value.is_a?(String)
61
+
62
+ raise ArgumentError, "store_authorization must be nil or a String; got a #{value.class}"
63
+ end
64
+
65
+ # The native side takes a u64 of milliseconds.
66
+ def timeout!(value, name)
67
+ return value if value.nil? || (value.is_a?(Integer) && value.positive? && value.bit_length <= 64)
68
+
69
+ raise ArgumentError, "#{name} must be nil or a positive Integer of at most 64 bits; got #{value.inspect}"
70
+ end
71
+
72
+ def json!(document, name)
73
+ raise ArgumentError, "#{name} must be a Hash; got #{document.class}" unless document.is_a?(Hash)
74
+
75
+ JSON.generate(document)
76
+ rescue JSON::JSONError => e
77
+ raise ArgumentError, "#{name} must serialize to JSON; #{e.message}"
78
+ end
79
+
80
+ def presence(string)
81
+ string.nil? || string.empty? ? nil : string
82
+ end
83
+
84
+ def valid_store_base_url?(parsed_uri)
85
+ parsed_uri.is_a?(URI::HTTP) && !parsed_uri.host.to_s.empty? &&
86
+ parsed_uri.userinfo.nil? && parsed_uri.query.nil? && parsed_uri.fragment.nil? &&
87
+ parsed_uri.port.between?(1, 65_535)
88
+ end
38
89
  end
90
+ private_constant :Validation
91
+
92
+ # Serializes .shared against .policy_store_url=: without it, a .shared
93
+ # call that read the old URL could finish after a reconfiguration and
94
+ # leave an engine for the old store memoized.
95
+ CONFIGURATION_LOCK = Mutex.new
96
+ private_constant :CONFIGURATION_LOCK
97
+
98
+ class << self
99
+ # @return [GovernPolicyEngine] a process-wide engine for
100
+ # +.policy_store_url+, built on first access and memoized until
101
+ # +.policy_store_url=+ next reconfigures it.
102
+ # @raise [ArgumentError] if +GLAZ_POLICY_STORE_URL+ is set but is not
103
+ # a valid Policy Store REST API root.
104
+ def shared
105
+ CONFIGURATION_LOCK.synchronize { @shared ||= new(store_base_url: policy_store_url) }
106
+ end
107
+
108
+ # @return [String, nil] the Policy Store REST API root the next
109
+ # +.shared+ call builds its engine with: an explicitly assigned URL
110
+ # (see +.policy_store_url=+) takes precedence, otherwise
111
+ # +GLAZ_POLICY_STORE_URL+; a blank value counts as unset (+nil+).
112
+ def policy_store_url
113
+ @policy_store_url || Validation.presence(ENV["GLAZ_POLICY_STORE_URL"]&.strip)
114
+ end
39
115
 
40
- # Evaluate a Rego governance policy against context.
116
+ # Point the shared engine at a Policy Store REST API root; the next
117
+ # .shared call rebuilds it. +nil+ falls back to the environment variable.
118
+ #
119
+ # @raise [ArgumentError] when +url+ is neither nil nor an http(s) URL
120
+ # without credentials, query or fragment.
121
+ def policy_store_url=(url)
122
+ validated = url.nil? ? nil : Validation.store_base_url!(url)
123
+ CONFIGURATION_LOCK.synchronize do
124
+ @policy_store_url = validated
125
+ @shared = nil
126
+ end
127
+ end
128
+ end
129
+
130
+ # @return [String, nil] the Policy Store REST API root; nil for an
131
+ # engine with no store.
132
+ attr_reader :store_base_url
133
+
134
+ # @param store_base_url [String, nil] the Policy Store REST API root,
135
+ # e.g. `"https://gitlab.com/api/v4"`; the lookup performs
136
+ # `GET {store_base_url}/organizations/{id}/security/policy_store?trigger_type={trigger}`.
137
+ # Redirects are never followed; `ALL_PROXY`/`HTTPS_PROXY`/`HTTP_PROXY`
138
+ # and `NO_PROXY` apply. +nil+ builds an engine with no store.
139
+ # @param connect_timeout_ms [Integer, nil] lookup connect timeout
140
+ # (default 500 ms).
141
+ # @param timeout_ms [Integer, nil] lookup total timeout (default 2 s).
142
+ # @raise [ArgumentError] for an invalid URL, or a timeout that is
143
+ # neither nil nor a positive 64-bit Integer.
144
+ def initialize(store_base_url: nil, connect_timeout_ms: nil, timeout_ms: nil)
145
+ @store_base_url = store_base_url.nil? ? nil : Validation.store_base_url!(store_base_url)
146
+ @connect_timeout_ms = Validation.timeout!(connect_timeout_ms, "connect_timeout_ms")
147
+ @timeout_ms = Validation.timeout!(timeout_ms, "timeout_ms")
148
+ @pid = Process.pid
149
+ @rebuild_lock = Mutex.new
150
+ @native = build_native
151
+ end
152
+
153
+ # Evaluate every governance policy that applies to an event trigger.
154
+ # +context+ must carry the evaluation scope at `organization.id` as a
155
+ # resource path (e.g. `"organizations/1"`).
41
156
  #
42
- # @param policy_rego [String] Rego policy text (max 64 KiB).
43
- # @param context [Hash] the host-assembled context, passed to the
44
- # policy as the Rego `input` document (max 1 MiB as JSON).
45
- # @param data [Hash] optional precomputed Rego `data` document (e.g.
46
- # cached settings or scan results). Top-level keys must not collide
47
- # with the policy's package path.
48
- # @raise [ArgumentError] for a caller-fixable evaluation failure -
49
- # malformed policy, oversized documents, an unrecognized
50
- # violation/deny/allow shape, and so on.
51
- # @raise [RuntimeError] for an engine-side fault, e.g. the Rego
52
- # evaluation time budget was exceeded - not the caller's fault.
53
- # Callers can rely on a successful return meaning the policy
54
- # evaluated cleanly; there is no in-band error to check.
55
- # @return [Hash] `{ matched: Boolean, actions: Array<Hash>, reasons:
56
- # Array<Hash> }`. `matched` is `true` exactly when `actions`
57
- # (equivalently `reasons`) is non-empty - a convenience so callers
58
- # don't have to infer "did the policy fire" from array emptiness.
59
- # It is not itself an allow/deny decision: today every action is
60
- # `"block"`, so `matched` and "should deny" coincide, but a future
61
- # Policy Store action type (e.g. `"log"`) could match without
62
- # implying denial - check `actions` for enforcement decisions. Each
63
- # action is `{ action_type: String, message: String | nil, params:
64
- # Hash }`; each reason is `{ message: String | nil, details: Hash
65
- # }`. Empty +actions+ means the policy allows the operation.
66
- def evaluate(policy_rego:, context:, data: {})
157
+ # @param trigger [String] the event, e.g. "deployment_requested".
158
+ # @param context [Hash] the Rego `input` document for every policy in
159
+ # the batch (max 1 MiB as JSON).
160
+ # @param principal [String] who the decision is about, as an opaque
161
+ # path-style identifier string (e.g. `"users/42"`); the caller owns
162
+ # the naming scheme. Trimmed of surrounding whitespace; must not be
163
+ # blank, contain a newline, or exceed 64 KiB once trimmed.
164
+ # @param resource [String] what the decision is about, as an opaque
165
+ # path-style identifier string (e.g.
166
+ # `"organizations/1/deployments/9"`). Same validation as
167
+ # +principal+.
168
+ # @param data [Hash, nil] optional Rego `data` document shared by the
169
+ # batch. It must not define a policy's own decision rules
170
+ # (`violation`/`deny`/`allow`); the engine reports that on the
171
+ # policy's +error+.
172
+ # @param store_authorization [String, nil] the `Authorization` header
173
+ # value the lookup presents to the Policy Store, verbatim (target
174
+ # scheme `"Bearer <jwt>"`). nil sends no header. Never logged or
175
+ # echoed in errors.
176
+ # @raise [ArgumentError] for a caller fault: wrong argument types, a
177
+ # document that does not serialize to JSON, a blank trigger, a blank
178
+ # +principal+ or +resource+ (or one exceeding 64 KiB or carrying a
179
+ # newline), missing organization scope, an oversized input document,
180
+ # or an engine constructed without a store.
181
+ # @raise [RuntimeError] for a backend fault: the store lookup failed
182
+ # or was rejected, or resolved more policies than the per-trigger
183
+ # cap. Never an empty batch, which would read as "nothing to
184
+ # enforce".
185
+ # @return [Hash] `{ decisions: Array<Hash>, undecided_policy_ids:
186
+ # Array<Integer>, identifier: String }`. +decisions+ has one entry
187
+ # per resolved, in-scope policy, in lookup order; empty means
188
+ # nothing applies. Each decision is `{ policy_id: Integer, matched:
189
+ # Boolean, actions: Array<Hash>, reasons: Array<Hash>, error: String
190
+ # | nil }`; each action `{ action_type: String, message: String |
191
+ # nil, params: Hash, gating: Boolean }`; each reason `{ message:
192
+ # String | nil, details: Hash }`. +actions+ are exactly those the
193
+ # store configured on the policy, emitted when it matched. A non-nil
194
+ # +error+ means the policy could not be decided (broken, or over the
195
+ # per-evaluation time budget); +matched+ is then false and its id is
196
+ # listed in +undecided_policy_ids+. +identifier+ is the stable
197
+ # decision identifier derived from (+principal+, +trigger+,
198
+ # +resource+): the same subject always yields the same identifier,
199
+ # so callers can key journaling, action deduplication, and approval
200
+ # correlation on it.
201
+ #
202
+ # Verdict: deny when any action is gating or any policy is
203
+ # undecided, allow otherwise. +matched+ alone decides nothing.
204
+ def evaluate(trigger:, context:, principal:, resource:, data: nil, store_authorization: nil)
205
+ if @store_base_url.nil?
206
+ raise ArgumentError, "this engine has no Policy Store to resolve policies from: pass store_base_url: to " \
207
+ "Gitlab::Glaz::GovernPolicyEngine.new, or for the shared engine assign " \
208
+ "Gitlab::Glaz::GovernPolicyEngine.policy_store_url or set GLAZ_POLICY_STORE_URL " \
209
+ "(e.g. \"https://gitlab.com/api/v4\")"
210
+ end
211
+
67
212
  encoded = ::Glaz::Govern::V1::EvaluateGovernPolicyRequest.encode(
68
213
  ::Glaz::Govern::V1::EvaluateGovernPolicyRequest.new(
69
- policy_rego: policy_rego,
70
- input_json: context.to_json,
71
- data_json: data.nil? || data.empty? ? "" : data.to_json
214
+ trigger: Validation.string!(trigger, "trigger"),
215
+ input_json: Validation.json!(context, "context"),
216
+ data_json: data.nil? ? "" : Validation.json!(data, "data"),
217
+ principal: Validation.string!(principal, "principal"),
218
+ resource: Validation.string!(resource, "resource"),
219
+ store_authorization: Validation.store_authorization!(store_authorization)
72
220
  )
73
221
  )
74
222
 
75
223
  response = ::Glaz::Govern::V1::EvaluateGovernPolicyResponse.decode(
76
- @native.evaluate(encoded)
224
+ native.evaluate_policies(encoded)
77
225
  )
78
226
 
79
227
  {
80
- matched: response.matched,
81
- reasons: response.reasons.map { |reason| reason_hash(reason) },
82
- actions: response.actions.map { |action| action_hash(action) }
228
+ decisions: response.decisions.map { |decision| decision_hash(decision) },
229
+ undecided_policy_ids: response.undecided_policy_ids.to_a,
230
+ identifier: response.identifier
83
231
  }
84
232
  end
85
233
 
86
- # Validate a Rego policy at save time without evaluating it against input.
234
+ # Parse and compile a Rego policy without evaluating it. A policy that
235
+ # fails to parse is not an error: it comes back as
236
+ # `{ valid: false, errors: [...] }` so the Policy Store can surface
237
+ # actionable feedback.
87
238
  #
88
- # Parses and compiles the policy source. A policy that fails to parse is
89
- # not an error - it is returned as `{ valid: false, errors: [...] }` so
90
- # the Policy Store can surface actionable feedback without treating a user
91
- # mistake as an exceptional condition.
92
- #
93
- # @param policy_rego [String] Rego policy source text (UTF-8, max 64 KiB).
94
- # Must be a valid UTF-8 string; raises `Encoding::InvalidByteSequenceError`
95
- # if the string contains invalid byte sequences.
96
- # @return [Hash] `{ valid: Boolean, errors: Array<Hash> }`.
97
- # `valid` is `true` when the policy parsed and compiled successfully.
98
- # `errors` is empty when valid; each entry is
99
- # `{ message: String, location: String }` where `location` is a
100
- # source-location hint in `"LINE:COL"` format (e.g. `"2:1"`) when the
101
- # engine surfaces one, or `""` when no separate location is available.
239
+ # @param policy_rego [String] Rego source (max 64 KiB).
240
+ # @raise [ArgumentError] when +policy_rego+ is not a String.
241
+ # @return [Hash] `{ valid: Boolean, errors: Array<Hash> }`; each error
242
+ # is `{ message: String, location: String }` with +location+ in
243
+ # `"LINE:COL"` format, or `""` when none is available.
102
244
  def validate(policy_rego:)
103
245
  encoded = ::Glaz::Govern::V1::ValidateGovernPolicyRequest.encode(
104
246
  ::Glaz::Govern::V1::ValidateGovernPolicyRequest.new(
105
- policy_rego: policy_rego
247
+ policy_rego: Validation.string!(policy_rego, "policy_rego")
106
248
  )
107
249
  )
108
250
 
109
251
  response = ::Glaz::Govern::V1::ValidateGovernPolicyResponse.decode(
110
- @native.validate(encoded)
252
+ native.validate(encoded)
111
253
  )
112
254
 
113
255
  {
@@ -117,55 +259,87 @@ module Gitlab
117
259
  end
118
260
 
119
261
  # Evaluate a Rego query directly, with no `violation`/`deny`/`allow`
120
- # interpretation. A debugging/testing escape hatch for exercising a
121
- # policy's Rego directly; prefer #evaluate for the primary path.
122
- # Unlike #evaluate, this does not raise on failure - +error+ stays
123
- # in-band, since this method is meant for inspecting raw results
124
- # (including failures) while developing a policy, not for production
125
- # decision-making.
262
+ # interpretation and no policy lookup. A debugging escape hatch for
263
+ # policy development: evaluation failures stay in-band on +error+
264
+ # rather than raising.
126
265
  #
127
- # @param policy_rego [String] Rego policy text (max 64 KiB).
128
- # @param context [Hash] the host-assembled context, passed to the
129
- # policy as the Rego `input` document (max 1 MiB as JSON).
130
- # @param query [String] Rego query to evaluate (e.g.
131
- # "data.mypackage.violation"); must not be blank.
132
- # @param data [Hash] optional precomputed Rego `data` document.
133
- # @return [Hash] `{ result: Object, error: String | nil }` - `result`
134
- # is exactly whatever `query` evaluated to (parsed JSON), with no
135
- # guarantee about its shape. A non-nil `error` means evaluation
136
- # failed; `result` is then `nil`.
137
- def debug_evaluate(policy_rego:, context:, query:, data: {})
266
+ # @param policy_rego [String] Rego source (max 64 KiB).
267
+ # @param context [Hash] the Rego `input` document (max 1 MiB as JSON).
268
+ # @param query [String] e.g. "data.mypackage.violation"; must not be
269
+ # blank.
270
+ # @param data [Hash, nil] optional Rego `data` document, merged as
271
+ # given.
272
+ # @raise [ArgumentError] for wrong argument types or a document that
273
+ # does not serialize to JSON.
274
+ # @return [Hash] `{ result: Object, error: String | nil }`. +result+ is
275
+ # whatever the query evaluated to (parsed JSON, String keys); nil
276
+ # when +error+ is set.
277
+ def debug_evaluate(policy_rego:, context:, query:, data: nil)
138
278
  encoded = ::Glaz::Govern::V1::EvaluateGovernPolicyDebugRequest.encode(
139
279
  ::Glaz::Govern::V1::EvaluateGovernPolicyDebugRequest.new(
140
- policy_rego: policy_rego,
141
- query: query.to_s,
142
- input_json: context.to_json,
143
- data_json: data.nil? || data.empty? ? "" : data.to_json
280
+ policy_rego: Validation.string!(policy_rego, "policy_rego"),
281
+ query: Validation.string!(query, "query"),
282
+ input_json: Validation.json!(context, "context"),
283
+ data_json: data.nil? ? "" : Validation.json!(data, "data")
144
284
  )
145
285
  )
146
286
 
147
- response = JSON.parse(@native.debug_evaluate(encoded), symbolize_names: true)
287
+ response = JSON.parse(native.debug_evaluate(encoded), max_nesting: false)
148
288
 
149
289
  {
150
- result: response[:result],
151
- error: response[:error].nil? || response[:error].empty? ? nil : response[:error]
290
+ result: response["result"],
291
+ error: Validation.presence(response["error"])
152
292
  }
153
293
  end
154
294
 
155
295
  private
156
296
 
297
+ # A forked child inherits the parent's engine and its pooled HTTP
298
+ # sockets, so the first call after a fork rebuilds it. The lock is only
299
+ # taken on that path, so concurrent first calls in the child (a Puma
300
+ # worker's request threads) share one rebuild. Ruby releases a mutex
301
+ # whose owner did not survive the fork, so the child cannot inherit it
302
+ # locked.
303
+ def native
304
+ return @native if @pid == Process.pid
305
+
306
+ @rebuild_lock.synchronize do
307
+ if @pid != Process.pid
308
+ @native = build_native
309
+ @pid = Process.pid
310
+ end
311
+ end
312
+ @native
313
+ end
314
+
315
+ def build_native
316
+ ::Glaz::Native::GovernPolicyEngine.new(@store_base_url, @connect_timeout_ms, @timeout_ms)
317
+ end
318
+
319
+ def decision_hash(decision)
320
+ {
321
+ policy_id: decision.policy_id,
322
+ matched: decision.matched,
323
+ actions: decision.actions.map { |action| action_hash(action) },
324
+ reasons: decision.reasons.map { |reason| reason_hash(reason) },
325
+ error: Validation.presence(decision.error)
326
+ }
327
+ end
328
+
329
+ # The native layer already bounds nesting, so parse without a limit.
157
330
  def action_hash(action)
158
331
  {
159
332
  action_type: action.action_type,
160
- message: action.message.empty? ? nil : action.message,
161
- params: JSON.parse(action.params_json)
333
+ message: Validation.presence(action.message),
334
+ params: JSON.parse(action.params_json, max_nesting: false),
335
+ gating: action.gating
162
336
  }
163
337
  end
164
338
 
165
339
  def reason_hash(reason)
166
340
  {
167
- message: reason.message.empty? ? nil : reason.message,
168
- details: JSON.parse(reason.details_json)
341
+ message: Validation.presence(reason.message),
342
+ details: JSON.parse(reason.details_json, max_nesting: false)
169
343
  }
170
344
  end
171
345
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  module Glaz
5
- VERSION = "1.2.0"
5
+ VERSION = "2.0.0"
6
6
  end
7
7
  end
data/lib/gitlab/glaz.rb CHANGED
@@ -24,12 +24,12 @@ module Gitlab
24
24
  end.freeze
25
25
  end
26
26
 
27
- # Returns the shared Gitlab::Glaz::GovernPolicyEngine instance, memoized
28
- # across calls. Evaluate Rego governance policies via
29
- # +govern_policy_engine.evaluate+; see GovernPolicyEngine#evaluate for
30
- # the full contract.
27
+ # Returns GovernPolicyEngine.shared, the engine configured through
28
+ # GovernPolicyEngine.policy_store_url= / GLAZ_POLICY_STORE_URL. It is
29
+ # rebuilt when that configuration changes, so call this each time rather
30
+ # than caching the result.
31
31
  def govern_policy_engine
32
- @govern_policy_engine ||= GovernPolicyEngine.new
32
+ GovernPolicyEngine.shared
33
33
  end
34
34
  end
35
35
  end
@@ -5,7 +5,7 @@
5
5
  require 'google/protobuf'
6
6
 
7
7
 
8
- descriptor_data = "\n\x12proto/govern.proto\x12\x0eglaz.govern.v1\"z\n\x1bEvaluateGovernPolicyRequest\x12\x1f\n\x0bpolicy_rego\x18\x01 \x01(\tR\npolicyRego\x12\x1d\n\ninput_json\x18\x02 \x01(\tR\tinputJson\x12\x1b\n\tdata_json\x18\x03 \x01(\tR\x08dataJson\"\x95\x01\n EvaluateGovernPolicyDebugRequest\x12\x1f\n\x0bpolicy_rego\x18\x01 \x01(\tR\npolicyRego\x12\x14\n\x05query\x18\x02 \x01(\tR\x05query\x12\x1d\n\ninput_json\x18\x03 \x01(\tR\tinputJson\x12\x1b\n\tdata_json\x18\x04 \x01(\tR\x08dataJson\"j\n\x0cGovernAction\x12\x1f\n\x0baction_type\x18\x01 \x01(\tR\nactionType\x12\x18\n\x07message\x18\x02 \x01(\tR\x07message\x12\x1f\n\x0bparams_json\x18\x03 \x01(\tR\nparamsJson\"K\n\x0cGovernReason\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\x12!\n\x0cdetails_json\x18\x02 \x01(\tR\x0bdetailsJson\"\xa8\x01\n\x1cEvaluateGovernPolicyResponse\x126\n\x07actions\x18\x01 \x03(\x0b2\x1c.glaz.govern.v1.GovernActionR\x07actions\x126\n\x07reasons\x18\x02 \x03(\x0b2\x1c.glaz.govern.v1.GovernReasonR\x07reasons\x12\x18\n\x07matched\x18\x03 \x01(\x08R\x07matched\">\n\x1bValidateGovernPolicyRequest\x12\x1f\n\x0bpolicy_rego\x18\x01 \x01(\tR\npolicyRego\"M\n\x15GovernValidationError\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\x12\x1a\n\x08location\x18\x02 \x01(\tR\x08location\"s\n\x1cValidateGovernPolicyResponse\x12\x14\n\x05valid\x18\x01 \x01(\x08R\x05valid\x12=\n\x06errors\x18\x02 \x03(\x0b2%.glaz.govern.v1.GovernValidationErrorR\x06errorsb\x06proto3"
8
+ descriptor_data = "\n\x12proto/govern.proto\x12\x0eglaz.govern.v1\"m\n EvaluateGovernPolicyDebugRequest\x12\x13\n\x0bpolicy_rego\x18\x01 \x01(\t\x12\r\n\x05query\x18\x02 \x01(\t\x12\x12\n\ninput_json\x18\x03 \x01(\t\x12\x11\n\tdata_json\x18\x04 \x01(\t\"Y\n\x0cGovernAction\x12\x13\n\x0b\x61\x63tion_type\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x13\n\x0bparams_json\x18\x03 \x01(\t\x12\x0e\n\x06gating\x18\x04 \x01(\x08\"5\n\x0cGovernReason\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x14\n\x0c\x64\x65tails_json\x18\x02 \x01(\t\"2\n\x1bValidateGovernPolicyRequest\x12\x13\n\x0bpolicy_rego\x18\x01 \x01(\t\":\n\x15GovernValidationError\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x10\n\x08location\x18\x02 \x01(\t\"d\n\x1cValidateGovernPolicyResponse\x12\r\n\x05valid\x18\x01 \x01(\x08\x12\x35\n\x06\x65rrors\x18\x02 \x03(\x0b\x32%.glaz.govern.v1.GovernValidationError\"\x97\x01\n\x1b\x45valuateGovernPolicyRequest\x12\x0f\n\x07trigger\x18\x01 \x01(\t\x12\x12\n\ninput_json\x18\x02 \x01(\t\x12\x11\n\tdata_json\x18\x03 \x01(\t\x12\x11\n\tprincipal\x18\x04 \x01(\t\x12\x10\n\x08resource\x18\x05 \x01(\t\x12\x1b\n\x13store_authorization\x18\x06 \x01(\t\"]\n\x19ListGovernPoliciesRequest\x12\x0f\n\x07trigger\x18\x01 \x01(\t\x12\x12\n\ninput_json\x18\x02 \x01(\t\x12\x1b\n\x13store_authorization\x18\x03 \x01(\t\"\x97\x01\n\x13PolicyApplicability\x12\x11\n\tpolicy_id\x18\x01 \x01(\x04\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x34\n\rapplicability\x18\x03 \x01(\x0e\x32\x1d.glaz.govern.v1.Applicability\x12\x1a\n\x12missing_dimensions\x18\x04 \x03(\t\x12\r\n\x05\x65rror\x18\x05 \x01(\t\"S\n\x1aListGovernPoliciesResponse\x12\x35\n\x08policies\x18\x01 \x03(\x0b\x32#.glaz.govern.v1.PolicyApplicability\"\xa1\x01\n\x0ePolicyDecision\x12\x11\n\tpolicy_id\x18\x01 \x01(\x04\x12\x0f\n\x07matched\x18\x02 \x01(\x08\x12-\n\x07\x61\x63tions\x18\x03 \x03(\x0b\x32\x1c.glaz.govern.v1.GovernAction\x12-\n\x07reasons\x18\x04 \x03(\x0b\x32\x1c.glaz.govern.v1.GovernReason\x12\r\n\x05\x65rror\x18\x05 \x01(\t\"Q\n\x10GovernDiagnostic\x12,\n\x04kind\x18\x01 \x01(\x0e\x32\x1e.glaz.govern.v1.DiagnosticKind\x12\x0f\n\x07message\x18\x02 \x01(\t\"\xba\x01\n\x1c\x45valuateGovernPolicyResponse\x12\x31\n\tdecisions\x18\x01 \x03(\x0b\x32\x1e.glaz.govern.v1.PolicyDecision\x12\x1c\n\x14undecided_policy_ids\x18\x02 \x03(\x04\x12\x35\n\x0b\x64iagnostics\x18\x03 \x03(\x0b\x32 .glaz.govern.v1.GovernDiagnostic\x12\x12\n\nidentifier\x18\x04 \x01(\t*\x8a\x01\n\rApplicability\x12\x1d\n\x19\x41PPLICABILITY_UNSPECIFIED\x10\x00\x12\x19\n\x15\x41PPLICABILITY_APPLIES\x10\x01\x12 \n\x1c\x41PPLICABILITY_NOT_APPLICABLE\x10\x02\x12\x1d\n\x19\x41PPLICABILITY_MIGHT_APPLY\x10\x03*\x83\x01\n\x0e\x44iagnosticKind\x12\x1f\n\x1b\x44IAGNOSTIC_KIND_UNSPECIFIED\x10\x00\x12*\n&DIAGNOSTIC_KIND_INPUT_SCHEMA_VIOLATION\x10\x01\x12$\n DIAGNOSTIC_KIND_SCHEMA_NOT_FOUND\x10\x02\x42?Z=gitlab.com/gitlab-org/govern/glaz-client-go/governv1;governv1b\x06proto3"
9
9
 
10
10
  pool = ::Google::Protobuf::DescriptorPool.generated_pool
11
11
  pool.add_serialized_file(descriptor_data)
@@ -13,14 +13,21 @@ pool.add_serialized_file(descriptor_data)
13
13
  module Glaz
14
14
  module Govern
15
15
  module V1
16
- EvaluateGovernPolicyRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.EvaluateGovernPolicyRequest").msgclass
17
16
  EvaluateGovernPolicyDebugRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.EvaluateGovernPolicyDebugRequest").msgclass
18
17
  GovernAction = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.GovernAction").msgclass
19
18
  GovernReason = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.GovernReason").msgclass
20
- EvaluateGovernPolicyResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.EvaluateGovernPolicyResponse").msgclass
21
19
  ValidateGovernPolicyRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.ValidateGovernPolicyRequest").msgclass
22
20
  GovernValidationError = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.GovernValidationError").msgclass
23
21
  ValidateGovernPolicyResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.ValidateGovernPolicyResponse").msgclass
22
+ EvaluateGovernPolicyRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.EvaluateGovernPolicyRequest").msgclass
23
+ ListGovernPoliciesRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.ListGovernPoliciesRequest").msgclass
24
+ PolicyApplicability = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.PolicyApplicability").msgclass
25
+ ListGovernPoliciesResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.ListGovernPoliciesResponse").msgclass
26
+ PolicyDecision = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.PolicyDecision").msgclass
27
+ GovernDiagnostic = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.GovernDiagnostic").msgclass
28
+ EvaluateGovernPolicyResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.EvaluateGovernPolicyResponse").msgclass
29
+ Applicability = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.Applicability").enummodule
30
+ DiagnosticKind = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("glaz.govern.v1.DiagnosticKind").enummodule
24
31
  end
25
32
  end
26
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-glaz
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: aarch64-linux-gnu
6
6
  authors:
7
7
  - group::authorization
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-04 00:00:00.000000000 Z
11
+ date: 2026-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-protobuf