entitlements-github-plugin 0.0.2 → 0.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 +4 -4
- data/lib/entitlements/backend/github_org/controller.rb +5 -5
- data/lib/entitlements/backend/github_org/service.rb +2 -2
- data/lib/entitlements/backend/github_team/controller.rb +3 -3
- data/lib/entitlements/backend/github_team/models/team.rb +1 -1
- data/lib/entitlements/backend/github_team/provider.rb +2 -2
- data/lib/entitlements/backend/github_team/service.rb +60 -11
- data/lib/entitlements/service/github.rb +3 -3
- data/lib/version.rb +7 -0
- metadata +20 -26
- data/VERSION +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c768cc8f03a6eae9aaf1350173a59274b53d51cb38b7df20e798ea2e49b049e9
|
|
4
|
+
data.tar.gz: 1d66f2116e098a02cd81ca0f9a50c98995cda306ff3aceba0e2f37fc705f3b93
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 47b00156083eabe37d014eaccbca358c291e7c0ebd4d48f0da8225f347526fdd6cef79969ec152d14db258a8412dc4ab73b1aa35742cf904e135206c85cca51b
|
|
7
|
+
data.tar.gz: c9f604456245070f5b6ff2dd89b63a16bd36f052f8b489aad4c72b0d85e06782789b5697099053e0f2176a90884c303b5c75e28c9d5c4fb2944267619fde5e25
|
|
@@ -83,7 +83,7 @@ module Entitlements
|
|
|
83
83
|
validate_no_dupes! # calls read() for each group
|
|
84
84
|
|
|
85
85
|
if changes.any?
|
|
86
|
-
print_differences(key: group_name, added: [], removed: [], changed: changes, ignored_users:
|
|
86
|
+
print_differences(key: group_name, added: [], removed: [], changed: changes, ignored_users:)
|
|
87
87
|
@actions.concat(changes)
|
|
88
88
|
else
|
|
89
89
|
logger.debug "UNCHANGED: No GitHub organization changes for #{group_name}"
|
|
@@ -398,11 +398,11 @@ module Entitlements
|
|
|
398
398
|
if removed.key?(member.downcase)
|
|
399
399
|
# Already removed from a previous role. Therefore this is a move to a different role.
|
|
400
400
|
removed.delete(member.downcase)
|
|
401
|
-
moved[member.downcase] = { member
|
|
401
|
+
moved[member.downcase] = { member:, role: }
|
|
402
402
|
else
|
|
403
403
|
# Not removed from a previous role. Suspect this is an addition to the org (if we later spot a removal
|
|
404
404
|
# from a role, then the code below will update that to be a move instead).
|
|
405
|
-
added[member.downcase] = { member
|
|
405
|
+
added[member.downcase] = { member:, role: }
|
|
406
406
|
end
|
|
407
407
|
end
|
|
408
408
|
|
|
@@ -414,12 +414,12 @@ module Entitlements
|
|
|
414
414
|
else
|
|
415
415
|
# Not added to a previous role. Suspect this is a removal from the org (if we later spot an addition
|
|
416
416
|
# to another role, then the code above will update that to be a move instead).
|
|
417
|
-
removed[member.downcase] = { member
|
|
417
|
+
removed[member.downcase] = { member:, role: }
|
|
418
418
|
end
|
|
419
419
|
end
|
|
420
420
|
end
|
|
421
421
|
|
|
422
|
-
{ added
|
|
422
|
+
{ added:, removed:, moved: }
|
|
423
423
|
end
|
|
424
424
|
|
|
425
425
|
# Admins or members who are both `invited` and `pending` do not need to be re-invited. We're waiting for them
|
|
@@ -44,7 +44,7 @@ module Entitlements
|
|
|
44
44
|
Contract String, String => C::Bool
|
|
45
45
|
def add_user_to_organization(user, role)
|
|
46
46
|
Entitlements.logger.debug "#{identifier} add_user_to_organization(user=#{user}, org=#{org}, role=#{role})"
|
|
47
|
-
new_membership = octokit.update_organization_membership(org, user
|
|
47
|
+
new_membership = octokit.update_organization_membership(org, user:, role:)
|
|
48
48
|
|
|
49
49
|
# Happy path
|
|
50
50
|
if new_membership[:role] == role
|
|
@@ -70,7 +70,7 @@ module Entitlements
|
|
|
70
70
|
Contract String => C::Bool
|
|
71
71
|
def remove_user_from_organization(user)
|
|
72
72
|
Entitlements.logger.debug "#{identifier} remove_user_from_organization(user=#{user}, org=#{org})"
|
|
73
|
-
result = octokit.remove_organization_membership(org, user:
|
|
73
|
+
result = octokit.remove_organization_membership(org, user:)
|
|
74
74
|
|
|
75
75
|
# If we removed the user, remove them from the cache of members, so that any GitHub team
|
|
76
76
|
# operations in this organization will ignore this user.
|
|
@@ -61,12 +61,12 @@ module Entitlements
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
if diff[:metadata] && diff[:metadata][:create_team]
|
|
64
|
-
added << Entitlements::Models::Action.new(team_slug, provider.read(group), group, group_name, ignored_users:
|
|
64
|
+
added << Entitlements::Models::Action.new(team_slug, provider.read(group), group, group_name, ignored_users:)
|
|
65
65
|
else
|
|
66
|
-
changed << Entitlements::Models::Action.new(team_slug, provider.read(group), group, group_name, ignored_users:
|
|
66
|
+
changed << Entitlements::Models::Action.new(team_slug, provider.read(group), group, group_name, ignored_users:)
|
|
67
67
|
end
|
|
68
68
|
end
|
|
69
|
-
print_differences(key: group_name, added
|
|
69
|
+
print_differences(key: group_name, added:, removed: [], changed:)
|
|
70
70
|
|
|
71
71
|
@actions = added + changed
|
|
72
72
|
end
|
|
@@ -27,7 +27,7 @@ module Entitlements
|
|
|
27
27
|
@team_id = team_id
|
|
28
28
|
@team_name = team_name.downcase
|
|
29
29
|
@team_dn = ["cn=#{team_name.downcase}", ou].join(",")
|
|
30
|
-
super(dn: @team_dn, members: Set.new(members.map { |m| m.downcase }), metadata:
|
|
30
|
+
super(dn: @team_dn, members: Set.new(members.map { |m| m.downcase }), metadata:)
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
end
|
|
@@ -127,7 +127,7 @@ module Entitlements
|
|
|
127
127
|
# Create the new team and invalidate the cache
|
|
128
128
|
if github_team.nil?
|
|
129
129
|
team_name = entitlement_group.cn.downcase
|
|
130
|
-
github.create_team(entitlement_group:
|
|
130
|
+
github.create_team(entitlement_group:)
|
|
131
131
|
github.invalidate_predictive_cache(entitlement_group)
|
|
132
132
|
@github_team_cache.delete(team_name)
|
|
133
133
|
github_team = github.read_team(entitlement_group)
|
|
@@ -168,7 +168,7 @@ module Entitlements
|
|
|
168
168
|
team_name: entitlement_group.cn.downcase,
|
|
169
169
|
members: Set.new,
|
|
170
170
|
ou: github.ou,
|
|
171
|
-
metadata:
|
|
171
|
+
metadata:
|
|
172
172
|
)
|
|
173
173
|
end
|
|
174
174
|
|
|
@@ -4,6 +4,7 @@ require_relative "models/team"
|
|
|
4
4
|
require_relative "../../service/github"
|
|
5
5
|
|
|
6
6
|
require "base64"
|
|
7
|
+
require "set"
|
|
7
8
|
|
|
8
9
|
module Entitlements
|
|
9
10
|
class Backend
|
|
@@ -77,7 +78,7 @@ module Entitlements
|
|
|
77
78
|
team_id: -1,
|
|
78
79
|
team_name: team_identifier,
|
|
79
80
|
members: cached_members,
|
|
80
|
-
ou
|
|
81
|
+
ou:,
|
|
81
82
|
metadata: team_metadata
|
|
82
83
|
)
|
|
83
84
|
|
|
@@ -107,11 +108,11 @@ module Entitlements
|
|
|
107
108
|
team_id: teamdata[:team_id],
|
|
108
109
|
team_name: team_identifier,
|
|
109
110
|
members: Set.new(teamdata[:members]),
|
|
110
|
-
ou
|
|
111
|
+
ou:,
|
|
111
112
|
metadata: team_metadata
|
|
112
113
|
)
|
|
113
114
|
rescue TeamNotFound
|
|
114
|
-
Entitlements.logger.warn "Team #{team_identifier} does not exist in this GitHub.com organization"
|
|
115
|
+
Entitlements.logger.warn "Team #{team_identifier} does not exist in this GitHub.com organization. If applied, the team will be created."
|
|
115
116
|
return nil
|
|
116
117
|
end
|
|
117
118
|
|
|
@@ -196,14 +197,56 @@ module Entitlements
|
|
|
196
197
|
end
|
|
197
198
|
end
|
|
198
199
|
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
desired_team_members = Set.new(desired_state.member_strings.map { |u| u.downcase })
|
|
201
|
+
current_team_members = Set.new(current_state.member_strings.map { |u| u.downcase })
|
|
202
|
+
|
|
203
|
+
added_members = desired_team_members - current_team_members
|
|
204
|
+
removed_members = current_team_members - desired_team_members
|
|
201
205
|
|
|
202
206
|
added_members.select! { |username| add_user_to_team(user: username, team: current_state) }
|
|
203
207
|
removed_members.select! { |username| remove_user_from_team(user: username, team: current_state) }
|
|
204
208
|
|
|
209
|
+
added_maintainers = Set.new
|
|
210
|
+
removed_maintainers = Set.new
|
|
211
|
+
unless desired_metadata["team_maintainers"] == current_metadata["team_maintainers"]
|
|
212
|
+
if desired_metadata["team_maintainers"].nil?
|
|
213
|
+
# We will not delete ALL maintainers from a team and leave it without maintainers.
|
|
214
|
+
Entitlements.logger.debug "sync_team(#{current_state.team_name}=#{current_state.team_id}): IGNORING GitHub Team Maintainer DELETE"
|
|
215
|
+
else
|
|
216
|
+
desired_maintainers_str = desired_metadata["team_maintainers"] # not nil, we tested that above
|
|
217
|
+
desired_maintainers = Set.new(desired_maintainers_str.split(",").map { |u| u.strip.downcase })
|
|
218
|
+
unless desired_maintainers.subset?(desired_team_members)
|
|
219
|
+
maintainer_not_member = desired_maintainers - desired_team_members
|
|
220
|
+
Entitlements.logger.warn "sync_team(#{current_state.team_name}=#{current_state.team_id}): Maintainers must be a subset of team members. Desired maintainers: #{maintainer_not_member.to_a} are not members. Ignoring."
|
|
221
|
+
desired_maintainers = desired_maintainers.intersection(desired_team_members)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
current_maintainers_str = current_metadata["team_maintainers"]
|
|
225
|
+
current_maintainers = Set.new(
|
|
226
|
+
current_maintainers_str.nil? ? [] : current_maintainers_str.split(",").map { |u| u.strip.downcase }
|
|
227
|
+
)
|
|
228
|
+
# We ignore any current maintainer who is not a member of the team according to the team spec
|
|
229
|
+
# This avoids messing with teams who have been manually modified to add a maintainer
|
|
230
|
+
current_maintainers = current_maintainers.intersection(desired_team_members)
|
|
231
|
+
added_maintainers = desired_maintainers - current_maintainers
|
|
232
|
+
removed_maintainers = current_maintainers - desired_maintainers
|
|
233
|
+
if added_maintainers.empty? && removed_maintainers.empty?
|
|
234
|
+
Entitlements.logger.debug "sync_team(#{current_state.team_name}=#{current_state.team_id}): Textual change but no semantic change in maintainers. It is remains: #{current_maintainers.to_a}."
|
|
235
|
+
else
|
|
236
|
+
Entitlements.logger.debug "sync_team(#{current_state.team_name}=#{current_state.team_id}): Maintainer members change found - From #{current_maintainers.to_a} to #{desired_maintainers.to_a}"
|
|
237
|
+
added_maintainers.select! { |username| add_user_to_team(user: username, team: current_state, role: "maintainer") }
|
|
238
|
+
|
|
239
|
+
## We only touch previous maintainers who are actually still going to be members of the team
|
|
240
|
+
removed_maintainers = removed_maintainers.intersection(desired_team_members)
|
|
241
|
+
## Downgrade membership to default (role: "member")
|
|
242
|
+
removed_maintainers.select! { |username| add_user_to_team(user: username, team: current_state, role: "member") }
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
|
|
205
248
|
Entitlements.logger.debug "sync_team(#{current_state.team_name}=#{current_state.team_id}): Added #{added_members.count}, removed #{removed_members.count}"
|
|
206
|
-
added_members.any? || removed_members.any? || changed_parent_team
|
|
249
|
+
added_members.any? || removed_members.any? || added_maintainers.any? || removed_maintainers.any? || changed_parent_team
|
|
207
250
|
end
|
|
208
251
|
|
|
209
252
|
# Create a team
|
|
@@ -337,7 +380,7 @@ module Entitlements
|
|
|
337
380
|
break
|
|
338
381
|
end
|
|
339
382
|
|
|
340
|
-
{ members: result, team_id
|
|
383
|
+
{ members: result, team_id:, parent_team_name: }
|
|
341
384
|
end
|
|
342
385
|
|
|
343
386
|
# Ensure that the given team ID actually matches up to the team slug on GitHub. This is in place
|
|
@@ -366,17 +409,23 @@ module Entitlements
|
|
|
366
409
|
#
|
|
367
410
|
# user - String with the GitHub username
|
|
368
411
|
# team - Entitlements::Backend::GitHubTeam::Models::Team object for the team.
|
|
412
|
+
# role - optional (default: "member") String with the role to assign to the user: either "member" or "maintainer"
|
|
369
413
|
#
|
|
370
|
-
# Returns true if the user was added to the team
|
|
414
|
+
# Returns true if the user was added to the team or role changed; false if user was already on team with same role
|
|
371
415
|
Contract C::KeywordArgs[
|
|
372
416
|
user: String,
|
|
373
417
|
team: Entitlements::Backend::GitHubTeam::Models::Team,
|
|
418
|
+
role: C::Optional[String]
|
|
374
419
|
] => C::Bool
|
|
375
|
-
def add_user_to_team(user:, team:)
|
|
420
|
+
def add_user_to_team(user:, team:, role: "member")
|
|
376
421
|
return false unless org_members.include?(user.downcase)
|
|
377
|
-
|
|
422
|
+
unless role == "member" || role == "maintainer"
|
|
423
|
+
# :nocov:
|
|
424
|
+
raise "add_user_to_team role mismatch: team_id=#{team.team_id} user=#{user} expected role=maintainer/member got=#{role}"
|
|
425
|
+
end
|
|
426
|
+
Entitlements.logger.debug "#{identifier} add_user_to_team(user=#{user}, org=#{org}, team_id=#{team.team_id}, role=#{role})"
|
|
378
427
|
validate_team_id_and_slug!(team.team_id, team.team_name)
|
|
379
|
-
result = octokit.add_team_membership(team.team_id, user)
|
|
428
|
+
result = octokit.add_team_membership(team.team_id, user, role:)
|
|
380
429
|
result[:state] == "active" || result[:state] == "pending"
|
|
381
430
|
end
|
|
382
431
|
|
|
@@ -82,7 +82,7 @@ module Entitlements
|
|
|
82
82
|
member_count = result.count { |_, role| role == "member" }
|
|
83
83
|
Entitlements.logger.debug "Currently #{org} has #{admin_count} admin(s) and #{member_count} member(s)"
|
|
84
84
|
|
|
85
|
-
{ cache
|
|
85
|
+
{ cache:, value: result }
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
Entitlements.cache[:github_org_members][org_signature][:value]
|
|
@@ -354,9 +354,9 @@ module Entitlements
|
|
|
354
354
|
data = JSON.parse(response.body)
|
|
355
355
|
if data.key?("errors")
|
|
356
356
|
Entitlements.logger.error "Errors reported: #{data['errors'].inspect}"
|
|
357
|
-
return { code: 500, data:
|
|
357
|
+
return { code: 500, data: }
|
|
358
358
|
end
|
|
359
|
-
{ code: response.code.to_i, data:
|
|
359
|
+
{ code: response.code.to_i, data: }
|
|
360
360
|
rescue JSON::ParserError => e
|
|
361
361
|
Entitlements.logger.error "#{e.class} #{e.message}: #{response.body.inspect}"
|
|
362
362
|
{ code: 500, data: { "body" => response.body } }
|
data/lib/version.rb
ADDED
metadata
CHANGED
|
@@ -1,49 +1,43 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: entitlements-github-plugin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GitHub, Inc. Security Ops
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-08-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: contracts
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
17
|
- - '='
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 0.
|
|
19
|
+
version: 0.17.0
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - '='
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 0.
|
|
26
|
+
version: 0.17.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: faraday
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '3'
|
|
34
|
-
- - ">="
|
|
31
|
+
- - "~>"
|
|
35
32
|
- !ruby/object:Gem::Version
|
|
36
|
-
version: '
|
|
33
|
+
version: '2.0'
|
|
37
34
|
type: :runtime
|
|
38
35
|
prerelease: false
|
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
40
37
|
requirements:
|
|
41
|
-
- - "
|
|
42
|
-
- !ruby/object:Gem::Version
|
|
43
|
-
version: '3'
|
|
44
|
-
- - ">="
|
|
38
|
+
- - "~>"
|
|
45
39
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '
|
|
40
|
+
version: '2.0'
|
|
47
41
|
- !ruby/object:Gem::Dependency
|
|
48
42
|
name: faraday-retry
|
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -73,19 +67,19 @@ dependencies:
|
|
|
73
67
|
- !ruby/object:Gem::Version
|
|
74
68
|
version: '4.25'
|
|
75
69
|
- !ruby/object:Gem::Dependency
|
|
76
|
-
name:
|
|
70
|
+
name: entitlements
|
|
77
71
|
requirement: !ruby/object:Gem::Requirement
|
|
78
72
|
requirements:
|
|
79
73
|
- - '='
|
|
80
74
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 0.
|
|
75
|
+
version: 0.2.0
|
|
82
76
|
type: :development
|
|
83
77
|
prerelease: false
|
|
84
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
85
79
|
requirements:
|
|
86
80
|
- - '='
|
|
87
81
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: 0.
|
|
82
|
+
version: 0.2.0
|
|
89
83
|
- !ruby/object:Gem::Dependency
|
|
90
84
|
name: rake
|
|
91
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -204,14 +198,14 @@ dependencies:
|
|
|
204
198
|
requirements:
|
|
205
199
|
- - '='
|
|
206
200
|
- !ruby/object:Gem::Version
|
|
207
|
-
version: 0.1
|
|
201
|
+
version: 1.0.1
|
|
208
202
|
type: :development
|
|
209
203
|
prerelease: false
|
|
210
204
|
version_requirements: !ruby/object:Gem::Requirement
|
|
211
205
|
requirements:
|
|
212
206
|
- - '='
|
|
213
207
|
- !ruby/object:Gem::Version
|
|
214
|
-
version: 0.1
|
|
208
|
+
version: 1.0.1
|
|
215
209
|
- !ruby/object:Gem::Dependency
|
|
216
210
|
name: vcr
|
|
217
211
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -240,13 +234,12 @@ dependencies:
|
|
|
240
234
|
- - '='
|
|
241
235
|
- !ruby/object:Gem::Version
|
|
242
236
|
version: 3.4.2
|
|
243
|
-
description:
|
|
237
|
+
description: Entitlements plugin to manage GitHub Orgs and Team memberships and access
|
|
244
238
|
email: security@github.com
|
|
245
239
|
executables: []
|
|
246
240
|
extensions: []
|
|
247
241
|
extra_rdoc_files: []
|
|
248
242
|
files:
|
|
249
|
-
- VERSION
|
|
250
243
|
- lib/entitlements/backend/github_org.rb
|
|
251
244
|
- lib/entitlements/backend/github_org/controller.rb
|
|
252
245
|
- lib/entitlements/backend/github_org/provider.rb
|
|
@@ -257,11 +250,12 @@ files:
|
|
|
257
250
|
- lib/entitlements/backend/github_team/provider.rb
|
|
258
251
|
- lib/entitlements/backend/github_team/service.rb
|
|
259
252
|
- lib/entitlements/service/github.rb
|
|
253
|
+
- lib/version.rb
|
|
260
254
|
homepage: https://github.com/github/entitlements-github-plugin
|
|
261
255
|
licenses:
|
|
262
256
|
- MIT
|
|
263
257
|
metadata: {}
|
|
264
|
-
post_install_message:
|
|
258
|
+
post_install_message:
|
|
265
259
|
rdoc_options: []
|
|
266
260
|
require_paths:
|
|
267
261
|
- lib
|
|
@@ -276,8 +270,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
276
270
|
- !ruby/object:Gem::Version
|
|
277
271
|
version: '0'
|
|
278
272
|
requirements: []
|
|
279
|
-
rubygems_version: 3.
|
|
280
|
-
signing_key:
|
|
273
|
+
rubygems_version: 3.3.7
|
|
274
|
+
signing_key:
|
|
281
275
|
specification_version: 4
|
|
282
276
|
summary: GitHub dotcom provider for entitlements-app
|
|
283
277
|
test_files: []
|
data/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.0.2
|