Skip to content

Commit 96329ab

Browse files
authored
Merge branch 'main' into add-logs
2 parents 3b1f2cc + 1a34939 commit 96329ab

34 files changed

+300
-60
lines changed

.github/workflows/acceptance.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
ruby: [ '3.1.2', '3.2.2', '3.3.0', '3.3.1' ]
6161

6262
steps:
63-
- uses: ruby/setup-ruby@1198b074305f9356bd56dd4b311757cc0dab2f1c # pin@v1.175.1
63+
- uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # pin@v1.221.0
6464
with:
6565
bundler-cache: true
6666
ruby-version: ${{ matrix.ruby }}

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: checkout
2626
uses: actions/checkout@v4
2727

28-
- uses: ruby/setup-ruby@1198b074305f9356bd56dd4b311757cc0dab2f1c # pin@v1.175.1
28+
- uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # pin@v1.221.0
2929
with:
3030
bundler-cache: true
3131

.github/workflows/codeql-analysis.yml

Lines changed: 0 additions & 46 deletions
This file was deleted.

.github/workflows/lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
- name: checkout
2222
uses: actions/checkout@v4
2323

24-
- uses: ruby/setup-ruby@1198b074305f9356bd56dd4b311757cc0dab2f1c # pin@v1.175.1
24+
- uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # pin@v1.221.0
2525
with:
2626
ruby-version: ${{ matrix.ruby }}
2727
bundler-cache: true

.github/workflows/release.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ jobs:
2121
steps:
2222
- name: checkout
2323
uses: actions/checkout@v4
24+
with:
25+
persist-credentials: false
2426

25-
- uses: ruby/setup-ruby@1198b074305f9356bd56dd4b311757cc0dab2f1c # pin@v1.175.1
27+
- uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # pin@v1.221.0
2628
with:
27-
bundler-cache: true
29+
bundler-cache: false
2830

2931
- name: bootstrap
3032
run: script/bootstrap

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
- name: checkout
2222
uses: actions/checkout@v4
2323

24-
- uses: ruby/setup-ruby@1198b074305f9356bd56dd4b311757cc0dab2f1c # pin@v1.175.1
24+
- uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777 # pin@v1.221.0
2525
with:
2626
ruby-version: ${{ matrix.ruby }}
2727
bundler-cache: true

Gemfile.lock

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
entitlements-app (1.1.0)
4+
entitlements-app (1.2.0)
55
concurrent-ruby (~> 1.3, >= 1.3.1)
66
faraday (~> 2.0)
77
logger (~> 1.6)
@@ -33,6 +33,7 @@ GEM
3333
crack (1.0.0)
3434
bigdecimal
3535
rexml
36+
date (3.4.1)
3637
debug (1.8.0)
3738
irb (>= 1.5.0)
3839
reline (>= 0.3.1)
@@ -67,19 +68,20 @@ GEM
6768
parser (3.3.1.0)
6869
ast (~> 2.4.1)
6970
racc
70-
psych (5.1.2)
71+
psych (5.2.3)
72+
date
7173
stringio
7274
public_suffix (5.0.5)
7375
racc (1.8.0)
74-
rack (3.0.11)
76+
rack (3.0.16)
7577
rainbow (3.1.1)
7678
rake (13.2.1)
7779
rdoc (6.7.0)
7880
psych (>= 4.0.0)
7981
regexp_parser (2.9.2)
8082
reline (0.5.8)
8183
io-console (~> 0.5)
82-
rexml (3.3.9)
84+
rexml (3.4.2)
8385
rspec (3.8.0)
8486
rspec-core (~> 3.8.0)
8587
rspec-expectations (~> 3.8.0)
@@ -131,11 +133,11 @@ GEM
131133
simplecov (< 1.0)
132134
simplecov-html (0.12.3)
133135
simplecov_json_formatter (0.1.4)
134-
stringio (3.1.0)
136+
stringio (3.1.4)
135137
tzinfo (2.0.6)
136138
concurrent-ruby (~> 1.0)
137139
unicode-display_width (2.5.0)
138-
uri (0.13.0)
140+
uri (0.13.2)
139141
vcr (6.2.0)
140142
webmock (3.23.1)
141143
addressable (>= 2.8.0)

lib/entitlements/data/groups/calculated/yaml.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,28 @@ def description
3434
parsed_data.fetch("description", "")
3535
end
3636

37+
# Standard interface: Get the schema version of this group.
38+
#
39+
# Takes no arguments.
40+
# Examples: "entitlements/v1", "entitlements/v1.2.3", "entitlements/1.2.3"
41+
# Format: namespace/major.minor.patch
42+
#
43+
# Returns a String with the schema version (k8s-style), or "entitlements/v1" if undefined.
44+
Contract C::None => String
45+
def schema_version
46+
schema_version = parsed_data.fetch("schema_version", "entitlements/v1").to_s
47+
48+
namespace, version = schema_version.split("/")
49+
50+
unless namespace.match?(/\A[a-zA-Z0-9]+\z/) && version.match?(/\A(v?\d+(\.\d+){0,2})\z/)
51+
raise "Invalid schema version format: #{schema_version} - Expected format is '<namespace>/<version>' " \
52+
"- Examples: entitlements/v1, entitlements/v1.2.3, entitlements/1.2.3"
53+
end
54+
55+
# rebuild the schema version string to ensure it's in the correct format and return it
56+
return "#{namespace}/#{version}"
57+
end
58+
3759
# Files can support modifiers that act independently of rules.
3860
# This returns the modifiers from the file as a hash.
3961
#

lib/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
module Entitlements
44
module Version
5-
VERSION = "1.1.0"
5+
VERSION = "1.2.0"
66
end
77
end

spec/unit/entitlements/data/groups/calculated/yaml_spec.rb

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# frozen_string_literal: true
22
require_relative "../../../../spec_helper"
33

4+
# NOTE: The test suite mocks all dates with allow(Time).to receive(:now).and_return(Time.utc(2018, 4, 1, 12, 0, 0))
5+
46
describe Entitlements::Data::Groups::Calculated::YAML do
57
let(:people_obj) { Entitlements::Data::People::YAML.new(filename: fixture("people.yaml")) }
68
let(:cache) { { people_obj: people_obj } }
@@ -35,6 +37,57 @@
3537
end
3638
end
3739

40+
describe "#schema_version" do
41+
it "returns the version string when one is set" do
42+
filename = fixture("ldap-config/filters/no-filters-with-schema-version.yaml")
43+
subject = described_class.new(filename: filename)
44+
expect(subject.schema_version).to eq("entitlements/1.2.3")
45+
end
46+
47+
it "returns the version string when one is set without the patch" do
48+
filename = fixture("ldap-config/filters/no-filters-with-schema-version-no-patch.yaml")
49+
subject = described_class.new(filename: filename)
50+
expect(subject.schema_version).to eq("entitlements/1.2")
51+
end
52+
53+
it "returns the version string when one is set with just the major version" do
54+
filename = fixture("ldap-config/filters/no-filters-with-schema-version-major.yaml")
55+
subject = described_class.new(filename: filename)
56+
expect(subject.schema_version).to eq("entitlements/1")
57+
end
58+
59+
it "returns the version string when one is set with just the major version (with v prefix)" do
60+
filename = fixture("ldap-config/filters/no-filters-with-schema-version-major-with-v.yaml")
61+
subject = described_class.new(filename: filename)
62+
expect(subject.schema_version).to eq("entitlements/v1")
63+
end
64+
65+
66+
it "returns the version string when one is set (with v prefix)" do
67+
filename = fixture("ldap-config/filters/no-filters-with-schema-version-with-v.yaml")
68+
subject = described_class.new(filename: filename)
69+
expect(subject.schema_version).to eq("entitlements/v1.2.3")
70+
end
71+
72+
it "returns the default version when schema_version is undefined" do
73+
filename = fixture("ldap-config/filters/no-filters-description.yaml")
74+
subject = described_class.new(filename: filename)
75+
expect(subject.schema_version).to eq("entitlements/v1")
76+
end
77+
78+
it "throws an error when an invalid schema_version string is provided" do
79+
filename = fixture("ldap-config/filters/no-filters-with-bad-schema-version.yaml")
80+
subject = described_class.new(filename: filename)
81+
expect { subject.schema_version }.to raise_error(RuntimeError, /Invalid schema version format/)
82+
end
83+
84+
it "throws an error when the version string is missing the namespace" do
85+
filename = fixture("ldap-config/filters/no-filters-with-missing-version-namespace.yaml")
86+
subject = described_class.new(filename: filename)
87+
expect { subject.schema_version }.to raise_error(RuntimeError, /Invalid schema version format/)
88+
end
89+
end
90+
3891
describe "#initialize_filters" do
3992
it "returns the default filter hash when no filters are defined" do
4093
filename = fixture("ldap-config/filters/no-filters.yaml")
@@ -232,7 +285,12 @@
232285
context "complex structure" do
233286
let(:filename) { fixture("ldap-config/yaml/expiration-complex.yaml") }
234287

235-
it "constructs the correct rule set" do
288+
it "constructs the correct rule set with complex nested expiration" do
289+
# Expected results based on expiration-complex.yaml:
290+
# - username: peterbald (no expiration) -> kept
291+
# - and: group foo/bar (Sept 2018, not expired) and foo/baz (March 2018, expired) -> only foo/bar kept
292+
# - or: all usernames expired (March 2018) -> empty array
293+
# - or: cheetoh (March 2018, expired) and nebelung (Sept 2018, not expired) -> only nebelung kept
236294
answer = {
237295
"or"=>[
238296
{"username"=>"peterbald"},
@@ -245,6 +303,104 @@
245303
expect(result).to eq(answer)
246304
end
247305
end
306+
307+
context "individual username expiration" do
308+
let(:filename) { fixture("ldap-config/yaml/expiration-individual-usernames.yaml") }
309+
310+
it "filters out expired usernames while keeping non-expired ones" do
311+
answer = {
312+
"or" => [
313+
{ "username" => "alice" },
314+
{ "username" => "charlie" },
315+
{ "username" => "diana" }
316+
]
317+
}
318+
result = subject.send(:rules)
319+
expect(result).to eq(answer)
320+
end
321+
end
322+
323+
context "group expiration" do
324+
let(:filename) { fixture("ldap-config/yaml/expiration-groups.yaml") }
325+
326+
it "filters out expired groups while keeping non-expired ones" do
327+
answer = {
328+
"or" => [
329+
{ "group" => "team/active" },
330+
{ "group" => "team/future" },
331+
{ "username" => "standalone" }
332+
]
333+
}
334+
result = subject.send(:rules)
335+
expect(result).to eq(answer)
336+
end
337+
end
338+
339+
context "mixed expiration with nested structures" do
340+
let(:filename) { fixture("ldap-config/yaml/expiration-mixed-nested.yaml") }
341+
342+
it "correctly handles expiration in nested and/or structures" do
343+
answer = {
344+
"or" => [
345+
{ "username" => "always-active" },
346+
{ "and" => [
347+
{ "group" => "team/core" }
348+
]
349+
},
350+
{ "or" => [
351+
{ "username" => "still-active" }
352+
]
353+
}
354+
]
355+
}
356+
result = subject.send(:rules)
357+
expect(result).to eq(answer)
358+
end
359+
end
360+
361+
context "all individual entries expired" do
362+
let(:filename) { fixture("ldap-config/yaml/expiration-all-individual-expired.yaml") }
363+
364+
it "returns empty arrays for containers with all expired entries" do
365+
answer = {
366+
"or" => []
367+
}
368+
result = subject.send(:rules)
369+
expect(result).to eq(answer)
370+
end
371+
end
372+
373+
context "expired entries but expirations are disabled" do
374+
let(:filename) { fixture("ldap-config/yaml/expiration-ignore-test.yaml") }
375+
376+
it "ignores all expiration dates when ignore_expirations is true" do
377+
begin
378+
Entitlements.config["ignore_expirations"] = true
379+
380+
answer = {
381+
"or" => [
382+
{ "username" => "active-user" },
383+
{ "username" => "expired-user" },
384+
{ "group" => "expired-group" }
385+
]
386+
}
387+
result = subject.send(:rules)
388+
expect(result).to eq(answer)
389+
ensure
390+
Entitlements.config.delete("ignore_expirations")
391+
end
392+
end
393+
end
394+
395+
context "invalid expiration date" do
396+
let(:filename) { fixture("ldap-config/yaml/expiration-invalid-date.yaml") }
397+
398+
it "raises an error for invalid expiration date format" do
399+
expect do
400+
subject.send(:rules)
401+
end.to raise_error(ArgumentError, /Invalid expiration date "not-a-date"/)
402+
end
403+
end
248404
end
249405
end
250406
end

0 commit comments

Comments
 (0)