gitlab-labkit 4.3.0 → 4.4.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63bc67bcb0041f919748393e6ace8e96d29bcd88e2c5b0e08b8baad8968670b1
4
- data.tar.gz: 5bd9b55ece983433e125c7cd087030d740647101a48e9af1f97f1aa68ed51db4
3
+ metadata.gz: f25b6fb5022dbe4d1740df490b991da48f8d2d9432926a0c23ec41dcc566b1c0
4
+ data.tar.gz: 8e1fb5578809e9a87726e95d181fec9426c67c64aa5862e1ab6afd08d4ac5d20
5
5
  SHA512:
6
- metadata.gz: 61d298ae9cb7c584d6e9979fbdb25fc112b705a8f1c0022825192e2759356408cbe6c03caf339ae5140220e325dc90532f24775a1f76decf1eb1547269cf3aba
7
- data.tar.gz: 3755c6de56d994d081210d1cae48430d9938420c6ac33932ce672f3c20eee86457742ce75966bbd2163c09807a4b4e4c72e82579f8eba262e25cb1b79204ce1f
6
+ metadata.gz: dad133ba83a3e8e9b60825936befc9af2586bc80685b227c0517553c32681bd89ac42c0c9c2d7d68b3dd5865e2f54672ca4882711f7b71d92f67442af98abbb7
7
+ data.tar.gz: d0c781167401e351f2c0989cbdbb2d761886cc5f27b723d96d99228f33bb1a4f04b52af3669c8c655b512378f37842c09d920628abb9284212bf17a1e57d9b9e
@@ -174,10 +174,17 @@ A `match` hash gates whether a rule applies. Each value is normalised through
174
174
  | `Regexp` | `re` | `match: { endpoint: %r{\A/api/} }` |
175
175
  | `{ eq: <value> }` | `eq` | `match: { method: { eq: "POST" } }` (YAML-friendly) |
176
176
  | `{ re: <source> }`| `re` | `match: { endpoint: { re: '\A/api/' } }` (YAML-friendly) |
177
+ | `{ oneOf: <Array> }` | `oneOf` | `match: { user: { oneOf: ["7", "42"] } }` (YAML-friendly) |
177
178
 
178
179
  `re` coerces the identifier value via `#to_s` before matching, so it can be
179
180
  used against non-String values (e.g. matching a 503 status against `{ re: '^5' }`).
180
181
 
182
+ `oneOf` is set membership via `Set#include?` (`eql?`/`hash` equality, no
183
+ coercion): it agrees with `eq` for Strings, Symbols, booleans, nil, and
184
+ same-class numerics, but cross-type numerics differ (`1 == 1.0`, yet
185
+ `{ oneOf: [1] }` does not match `1.0`). A bare Array is rejected; membership must
186
+ be spelled `{ oneOf: [...] }` explicitly.
187
+
181
188
  Glob and prefix matchers are intentionally out of scope.
182
189
 
183
190
  ### Evaluation flow
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "set"
4
+
3
5
  module Labkit
4
6
  module RateLimit
5
7
  # Matcher is the internal representation of a single key/value predicate in
@@ -11,6 +13,14 @@ module Labkit
11
13
  # - a Regexp instance -> :re matcher (Ruby convenience)
12
14
  # - { eq: <value> } -> :eq matcher (canonical, YAML-compatible)
13
15
  # - { re: <String|Regexp> } -> :re matcher (canonical, YAML-compatible)
16
+ # - { oneOf: <Array> } -> :oneOf matcher (set membership, YAML-compatible)
17
+ #
18
+ # A bare Array is rejected rather than treated as :oneOf, so a value that
19
+ # was meant as a single matcher hash but arrived as an Array fails loudly
20
+ # instead of silently becoming a membership test.
21
+ #
22
+ # :oneOf membership is Set#include? (eql?/hash equality), not :eq's ==, so
23
+ # cross-type numerics differ (1 == 1.0, but {oneOf: [1]} does not match 1.0).
14
24
  #
15
25
  # Hash-key naming follows the metrics-catalog selector pattern. Glob,
16
26
  # prefix, and other matcher kinds are intentionally out of scope here; see
@@ -20,7 +30,7 @@ module Labkit
20
30
  # the regex, so callers can match non-String identifier values such as
21
31
  # Integer status codes (e.g. {status: { re: "^5" }} against status: 503).
22
32
  class Matcher < Data.define(:type, :value)
23
- KNOWN_HASH_KEYS = %i[eq re].freeze
33
+ KNOWN_HASH_KEYS = %i[eq re oneOf].freeze
24
34
  MAX_REGEX_SOURCE_LENGTH = 200
25
35
  ERROR_INSPECT_LIMIT = 80
26
36
 
@@ -42,18 +52,14 @@ module Labkit
42
52
  when Hash
43
53
  from_hash(input)
44
54
  when Array
45
- raise ArgumentError,
46
- "rate-limit match value must be a single-key Hash like {re: \"...\"} or {eq: ...}, got #{truncate_for_error(input)}"
55
+ raise ArgumentError, invalid_shape_error(input)
47
56
  else
48
57
  new(type: :eq, value: input)
49
58
  end
50
59
  end
51
60
 
52
61
  def self.from_hash(input)
53
- if input.size != 1
54
- raise ArgumentError,
55
- "rate-limit match value must be a single-key Hash like {re: \"...\"} or {eq: ...}, got #{truncate_for_error(input)}"
56
- end
62
+ raise ArgumentError, invalid_shape_error(input) if input.size != 1
57
63
 
58
64
  type, source = input.first
59
65
  type_sym = type.to_sym
@@ -71,6 +77,13 @@ module Labkit
71
77
  case type_sym
72
78
  when :eq
73
79
  new(type: :eq, value: source)
80
+ when :oneOf
81
+ unless source.is_a?(Array)
82
+ raise ArgumentError,
83
+ "rate-limit match value {oneOf: ...} must be an Array, got #{truncate_for_error(source)}"
84
+ end
85
+
86
+ new(type: :oneOf, value: Set.new(source).freeze)
74
87
  when :re
75
88
  if source.to_s.length > MAX_REGEX_SOURCE_LENGTH
76
89
  raise ArgumentError,
@@ -113,6 +126,12 @@ module Labkit
113
126
 
114
127
  private_class_method :with_match_timeout
115
128
 
129
+ def self.invalid_shape_error(input)
130
+ "rate-limit match value must be a single-key Hash like {re: \"...\"}, {eq: ...} or {oneOf: [...]}, " \
131
+ "got #{truncate_for_error(input)}"
132
+ end
133
+ private_class_method :invalid_shape_error
134
+
116
135
  def self.truncate_for_error(value)
117
136
  s = value.inspect
118
137
  s.length > ERROR_INSPECT_LIMIT ? "#{s[0, ERROR_INSPECT_LIMIT]}...(truncated)" : s
@@ -123,6 +142,8 @@ module Labkit
123
142
  case type
124
143
  when :eq
125
144
  value == identifier_value
145
+ when :oneOf
146
+ value.include?(identifier_value)
126
147
  when :re
127
148
  value.match?(identifier_value.to_s)
128
149
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-labkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.0
4
+ version: 4.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Newdigate