Skip to content

Commit ff4977b

Browse files
committed
Add support for security_manager role to entitlements-github-plugin
1 parent 58bd1f9 commit ff4977b

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

lib/entitlements/backend/github_org/provider.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,15 @@ def role_name(role_identifier)
104104
# Returns an Entitlements::Models::Group object.
105105
Contract String => Entitlements::Models::Group
106106
def role_to_group(role)
107-
members = github.org_members.keys.select { |username| github.org_members[username] == role }
107+
# The security_manager role is a special case because it is not a role that is
108+
# part of the org membership API. Instead, it is a role that is assigned to users via
109+
# the org role API.
110+
if role == "security_manager"
111+
members = github.users_with_role(role)
112+
else
113+
members = github.org_members.keys.select { |username| github.org_members[username] == role }
114+
end
115+
108116
Entitlements::Models::Group.new(
109117
dn: role_dn(role),
110118
members: Set.new(members),

lib/entitlements/backend/github_org/service.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,23 @@ def sync(implementation, role)
3535

3636
private
3737

38+
Contract String, String => C::HashOf[Symbol, C::Any]
39+
def add_user_to_role(user, role)
40+
if role == "security_manager"
41+
octokit.add_role_to_user(user, role)
42+
43+
# This is a hack to get around the fact that the GitHub API
44+
# has two different concepts of organization roles,
45+
# and the one we want to use is not present in organization memberships.
46+
#
47+
# If we get here, we know that the user is already member of the organization,
48+
# and we know that the user has been successfully granted the role.
49+
{ user:, role:, state: "active" }
50+
else
51+
octokit.update_organization_membership(org, user:, role:)
52+
end
53+
end
54+
3855
# Upsert a user with a role to the organization.
3956
#
4057
# user: A String with the (GitHub) username of the person to add or modify.
@@ -46,10 +63,21 @@ def add_user_to_organization(user, role)
4663
Entitlements.logger.debug "#{identifier} add_user_to_organization(user=#{user}, org=#{org}, role=#{role})"
4764

4865
begin
49-
new_membership = octokit.update_organization_membership(org, user:, role:)
66+
new_membership = add_role_to_user(user, role)
5067
rescue Octokit::NotFound => e
5168
raise e unless ignore_not_found
5269

70+
Entitlements.logger.warn "User #{user} not found in GitHub instance #{identifier}, ignoring."
71+
return false
72+
rescue Octokit::UnprocessableEntity => e
73+
# Two conditions can cause this:
74+
# - If the role is not enabled, we'll get a 422.
75+
# - If the user is not a member of the organization, we'll get a 422.
76+
77+
# We'll loop this under ignore_not_found
78+
# since this affects the case where we want to add a user to security_manager role
79+
raise e unless ignore_not_found
80+
5381
Entitlements.logger.warn "User #{user} not found in GitHub instance #{identifier}, ignoring."
5482
return false
5583
end

lib/entitlements/service/github.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,32 @@ def max_graphql_results
394394
MAX_GRAPHQL_RESULTS
395395
end
396396
# :nocov:
397+
398+
Contract C::None => C::ArrayOf[Hash]
399+
def org_roles
400+
Entitlements.cache[:github_org_roles][org_signature] ||= begin
401+
octokit.get("/orgs/#{@org}/organization-roles")
402+
end
403+
end
404+
405+
Contract String => C::Maybe[Hash]
406+
def org_role(role)
407+
org_roles.find { |r| r[:name] == role }
408+
end
409+
410+
Contract String, String => C::Any
411+
def add_role_to_user(user, role)
412+
role_id = org_role(role)[:id]
413+
octokit.put("/orgs/#{org_name}/organization-roles/users/#{user}/#{role_id}")
414+
end
415+
416+
Contract String => C::ArrayOf[Hash]
417+
def users_with_role(role)
418+
role_id = org_role(role)[:id]
419+
Entitlements.cache[:github_org_role_users][org_signature][role] ||= begin
420+
octokit.get("/orgs/#{org_name}/organization-roles/#{role_id}/users")
421+
end
422+
end
397423
end
398424
end
399425
end

0 commit comments

Comments
 (0)