Skip to content

Commit 94f8e48

Browse files
Merge pull request #28 from github/jasonmacgowan/ignore_not_found
Support ignoring 404s when user is not found in GitHub instance
2 parents 62f8827 + 7f71f60 commit 94f8e48

File tree

17 files changed

+204
-55
lines changed

17 files changed

+204
-55
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
entitlements-github-plugin (0.4.4)
4+
entitlements-github-plugin (0.5.0)
55
contracts (~> 0.17.0)
66
faraday (~> 2.0)
77
faraday-retry (~> 2.0)

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Any plugins defined in `lib/entitlements-and-plugins` will be loaded and used at
5656
dir: github.com/github/org
5757
org: github
5858
token: <%= ENV["GITHUB_ORG_TOKEN"] %>
59+
ignore_not_found: false # optional argument to ignore users who are not found in the GitHub instance
5960
type: "github_org"
6061
```
6162
@@ -72,6 +73,7 @@ Any plugins defined in `lib/entitlements-and-plugins` will be loaded and used at
7273
dir: github.com/github/teams
7374
org: github
7475
token: <%= ENV["GITHUB_ORG_TOKEN"] %>
76+
ignore_not_found: false # optional argument to ignore users who are not found in the GitHub instance
7577
type: "github_team"
7678
```
7779

lib/entitlements/backend/github_org/controller.rb

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,13 @@ def apply(action)
120120
Contract String, C::HashOf[String => C::Any] => nil
121121
def validate_config!(key, data)
122122
spec = COMMON_GROUP_CONFIG.merge({
123-
"base" => { required: true, type: String },
124-
"addr" => { required: false, type: String },
125-
"org" => { required: true, type: String },
126-
"token" => { required: true, type: String },
127-
"features" => { required: false, type: Array },
128-
"ignore" => { required: false, type: Array }
123+
"base" => { required: true, type: String },
124+
"addr" => { required: false, type: String },
125+
"org" => { required: true, type: String },
126+
"token" => { required: true, type: String },
127+
"features" => { required: false, type: Array },
128+
"ignore" => { required: false, type: Array },
129+
"ignore_not_found" => { required: false, type: [FalseClass, TrueClass] },
129130
})
130131
text = "GitHub organization group #{key.inspect}"
131132
Entitlements::Util::Util.validate_attr!(spec, data, text)

lib/entitlements/backend/github_org/provider.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ def initialize(config:)
2525
org: config.fetch("org"),
2626
addr: config.fetch("addr", nil),
2727
token: config.fetch("token"),
28-
ou: config.fetch("base")
28+
ou: config.fetch("base"),
29+
ignore_not_found: config.fetch("ignore_not_found", false)
2930
)
3031
@role_cache = {}
3132
end

lib/entitlements/backend/github_org/service.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,15 @@ def sync(implementation, role)
4444
Contract String, String => C::Bool
4545
def add_user_to_organization(user, role)
4646
Entitlements.logger.debug "#{identifier} add_user_to_organization(user=#{user}, org=#{org}, role=#{role})"
47-
new_membership = octokit.update_organization_membership(org, user:, role:)
47+
48+
begin
49+
new_membership = octokit.update_organization_membership(org, user:, role:)
50+
rescue Octokit::NotFound => e
51+
raise e unless ignore_not_found
52+
53+
Entitlements.logger.warn "User #{user} not found in GitHub instance #{identifier}, ignoring."
54+
return false
55+
end
4856

4957
# Happy path
5058
if new_membership[:role] == role

lib/entitlements/backend/github_team/controller.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ def validate_config!(key, data)
110110
"base" => { required: true, type: String },
111111
"addr" => { required: false, type: String },
112112
"org" => { required: true, type: String },
113-
"token" => { required: true, type: String }
113+
"token" => { required: true, type: String },
114+
"ignore_not_found" => { required: false, type: [FalseClass, TrueClass] },
114115
})
115116
text = "GitHub group #{key.inspect}"
116117
Entitlements::Util::Util.validate_attr!(spec, data, text)

lib/entitlements/backend/github_team/provider.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ def initialize(config:)
2323
org: config.fetch("org"),
2424
addr: config.fetch("addr", nil),
2525
token: config.fetch("token"),
26-
ou: config.fetch("base")
26+
ou: config.fetch("base"),
27+
ignore_not_found: config.fetch("ignore_not_found", false)
2728
)
2829

2930
@github_team_cache = {}

lib/entitlements/backend/github_team/service.rb

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ class TeamNotFound < RuntimeError; end
2828
addr: C::Maybe[String],
2929
org: String,
3030
token: String,
31-
ou: String
31+
ou: String,
32+
ignore_not_found: C::Bool,
3233
] => C::Any
33-
def initialize(addr: nil, org:, token:, ou:)
34+
def initialize(addr: nil, org:, token:, ou:, ignore_not_found: false)
3435
super
3536
Entitlements.cache[:github_team_members] ||= {}
3637
Entitlements.cache[:github_team_members][org] ||= {}
@@ -436,8 +437,16 @@ def add_user_to_team(user:, team:, role: "member")
436437
end
437438
Entitlements.logger.debug "#{identifier} add_user_to_team(user=#{user}, org=#{org}, team_id=#{team.team_id}, role=#{role})"
438439
validate_team_id_and_slug!(team.team_id, team.team_name)
439-
result = octokit.add_team_membership(team.team_id, user, role:)
440-
result[:state] == "active" || result[:state] == "pending"
440+
441+
begin
442+
result = octokit.add_team_membership(team.team_id, user, role:)
443+
result[:state] == "active" || result[:state] == "pending"
444+
rescue Octokit::NotFound => e
445+
raise e unless ignore_not_found
446+
447+
Entitlements.logger.warn "User #{user} not found in GitHub instance #{identifier}, ignoring."
448+
false
449+
end
441450
end
442451

443452
# Remove user from team.

lib/entitlements/service/github.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class GitHub
1717
MAX_GRAPHQL_RETRIES = 3
1818
WAIT_BETWEEN_GRAPHQL_RETRIES = 1
1919

20-
attr_reader :addr, :org, :token, :ou
20+
attr_reader :addr, :org, :token, :ou, :ignore_not_found
2121

2222
# Constructor.
2323
#
@@ -31,14 +31,16 @@ class GitHub
3131
addr: C::Maybe[String],
3232
org: String,
3333
token: String,
34-
ou: String
34+
ou: String,
35+
ignore_not_found: C::Bool,
3536
] => C::Any
36-
def initialize(addr: nil, org:, token:, ou:)
37+
def initialize(addr: nil, org:, token:, ou:, ignore_not_found: false)
3738
# Save some parameters for the connection but don't actually connect yet.
3839
@addr = addr
3940
@org = org
4041
@token = token
4142
@ou = ou
43+
@ignore_not_found = ignore_not_found
4244

4345
# This is a global cache across all invocations of this object. GitHub membership
4446
# need to be obtained only one time per organization, but might be used multiple times.

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 = "0.4.4"
5+
VERSION = "0.5.0"
66
end
77
end

spec/unit/entitlements/backend/github_org/controller_spec.rb

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
let(:backend_config) { base_backend_config }
1010
let(:base_backend_config) do
1111
{
12-
"org" => "kittensinc",
13-
"token" => "CuteAndCuddlyKittens",
14-
"type" => "github_org",
15-
"base" => "ou=kittensinc,ou=GitHub,dc=github,dc=com"
12+
"org" => "kittensinc",
13+
"token" => "CuteAndCuddlyKittens",
14+
"type" => "github_org",
15+
"base" => "ou=kittensinc,ou=GitHub,dc=github,dc=com",
16+
"ignore_not_found" => false
1617
}
1718
end
1819
let(:group_name) { "foo-githuborg" }
@@ -98,9 +99,10 @@
9899
it "logs expected output and returns expected actions" do
99100
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
100101
.with("foo-githuborg", {
101-
"base" => "ou=kittensinc,ou=GitHub,dc=github,dc=com",
102-
"org" => "kittensinc",
103-
"token" => "CuteAndCuddlyKittens"
102+
"base" => "ou=kittensinc,ou=GitHub,dc=github,dc=com",
103+
"org" => "kittensinc",
104+
"token" => "CuteAndCuddlyKittens",
105+
"ignore_not_found" => false
104106
}).and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
105107
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
106108
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -179,7 +181,8 @@
179181
end
180182

181183
it "logs expected output and returns expected actions" do
182-
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all).with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
184+
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
185+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
183186
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
184187
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
185188
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -263,7 +266,8 @@
263266
end
264267

265268
it "logs expected output and returns expected actions" do
266-
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all).with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
269+
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
270+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
267271
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
268272
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
269273
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -328,7 +332,7 @@
328332

329333
it "does not run actions" do
330334
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
331-
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
335+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
332336
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
333337
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
334338
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -374,7 +378,7 @@
374378

375379
it "handles removals and role changes but does not invite" do
376380
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
377-
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>%w[remove], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
381+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>%w[remove], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
378382
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
379383
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
380384
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -437,7 +441,7 @@
437441

438442
it "reports as a no-op" do
439443
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
440-
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>%w[remove], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
444+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>%w[remove], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
441445
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
442446
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
443447
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -486,7 +490,7 @@
486490

487491
it "handles removals and role changes but does not invite" do
488492
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
489-
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>%w[invite], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
493+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>%w[invite], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
490494
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
491495
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
492496
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -555,7 +559,7 @@
555559

556560
it "reports as a no-op" do
557561
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
558-
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>%w[invite], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
562+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>%w[invite], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
559563
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
560564
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
561565
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -591,9 +595,8 @@
591595
cache[:predictive_state] = { by_dn: { org1_admin_dn => { members: admins, metadata: nil }, org1_member_dn => { members:, metadata: nil } }, invalid: Set.new }
592596

593597
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
594-
.with("foo-githuborg", {
595-
"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"
596-
}).and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
598+
.with("foo-githuborg", { "base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
599+
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
597600

598601
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
599602
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -663,7 +666,7 @@
663666

664667
it "handles removals and role changes but does not invite" do
665668
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
666-
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>[], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
669+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>[], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
667670
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
668671
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
669672
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -726,7 +729,7 @@
726729

727730
it "reports as a no-op" do
728731
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
729-
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>[], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
732+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "features"=>[], "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
730733
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
731734
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_admin_dn).and_return(org1_admin_group)
732735
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(org1_member_dn).and_return(org1_member_group)
@@ -837,7 +840,7 @@
837840
describe "#validate_github_org_ous!" do
838841
it "raises if an admin or member group is missing" do
839842
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
840-
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
843+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
841844
.and_return(Set.new(%w[member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
842845

843846
github_double = instance_double(Entitlements::Backend::GitHubOrg::Provider)
@@ -857,7 +860,7 @@
857860
dns = %w[admin member kittens cats].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }
858861

859862
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
860-
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens"})
863+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
861864
.and_return(Set.new(dns))
862865

863866
allow(Entitlements::Backend::GitHubOrg::Service).to receive(:new).and_return(service)
@@ -897,11 +900,8 @@
897900

898901
it "raises due to duplicate users" do
899902
allow(Entitlements::Data::Groups::Calculated).to receive(:read_all)
900-
.with("foo-githuborg", {
901-
"base" => "ou=kittensinc,ou=GitHub,dc=github,dc=com",
902-
"org" => "kittensinc",
903-
"token" => "CuteAndCuddlyKittens"
904-
}).and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
903+
.with("foo-githuborg", {"base"=>"ou=kittensinc,ou=GitHub,dc=github,dc=com", "org"=>"kittensinc", "token"=>"CuteAndCuddlyKittens", "ignore_not_found"=>false})
904+
.and_return(Set.new(%w[admin member].map { |cn| "cn=#{cn},ou=kittensinc,ou=GitHub,dc=github,dc=com" }))
905905
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(admin_dn).and_return(admin_group)
906906
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(member_dn).and_return(member_group)
907907
allow(Entitlements::Data::Groups::Calculated).to receive(:read).with(member_dn).and_return(member_group)

spec/unit/entitlements/backend/github_org/provider_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
addr: "https://github.fake/api/v3",
88
org: "kittensinc",
99
token: "GoPackGo",
10-
ou: "ou=kittensinc,ou=GitHub,dc=github,dc=fake"
10+
ou: "ou=kittensinc,ou=GitHub,dc=github,dc=fake",
11+
ignore_not_found: false
1112
}
1213
end
1314

0 commit comments

Comments
 (0)