-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathprovider.rb
More file actions
145 lines (129 loc) · 4.97 KB
/
provider.rb
File metadata and controls
145 lines (129 loc) · 4.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# frozen_string_literal: true
require_relative "service"
require "set"
require "uri"
module Entitlements
class Backend
class GitHubOrg
class Provider < Entitlements::Backend::BaseProvider
include ::Contracts::Core
C = ::Contracts
attr_reader :github
# Constructor.
#
# config - Configuration provided for the controller instantiation
Contract C::KeywordArgs[
config: C::HashOf[String => C::Any],
] => C::Any
def initialize(config:)
@github = Entitlements::Backend::GitHubOrg::Service.new(
org: config.fetch("org"),
addr: config.fetch("addr", nil),
token: config.fetch("token"),
ou: config.fetch("base"),
ignore_not_found: config.fetch("ignore_not_found", false)
)
@role_cache = {}
end
# Read in a github organization and enumerate its members and their roles. Results are cached
# for future runs. The organization is defined per-entitlement as the `.org` method of the
# github object.
#
# role_identifier - String with the role (a key from Entitlements::Backend::GitHubOrg::ORGANIZATION_ROLES) or a group.
#
# Returns a Entitlements::Models::Group object.
Contract C::Or[String, Entitlements::Models::Group] => Entitlements::Models::Group
def read(role_identifier)
role_cn = role_name(role_identifier)
@role_cache[role_cn] ||= role_to_group(role_cn)
end
# Commit changes.
#
# action - An Entitlements::Models::Action object.
#
# Returns true if a change was made, false if no change was made.
Contract Entitlements::Models::Action => C::Bool
def commit(action)
# `false` usually means "What's going on, there are changes but nothing to apply!" Here it is
# more routine that there are removals that are not processed (because adding to one role removes
# from the other), so `true` is more accurate.
return true unless action.implementation
github.sync(action.implementation, role_name(action.updated))
end
# Invalidate the predictive cache.
#
# Takes no arguments.
#
# Returns nothing.
Contract C::None => nil
def invalidate_predictive_cache
@role_cache = {}
github.invalidate_org_members_predictive_cache
nil
end
# Pending members.
#
# Takes no arguments.
#
# Returns Set of usernames.
Contract C::None => C::SetOf[String]
def pending_members
github.pending_members
end
private
# Determine the role name from a string or a group (with validation).
#
# role_identifier - String (a key from Entitlements::Backend::GitHubOrg::ORGANIZATION_ROLES) or a group.
#
# Returns a string with the role name.
Contract C::Or[String, Entitlements::Models::Group] => String
def role_name(role_identifier)
role = Entitlements::Util::Util.any_to_cn(role_identifier)
return role if Entitlements::Backend::GitHubOrg::ORGANIZATION_ROLES.key?(role)
supported = Entitlements::Backend::GitHubOrg::ORGANIZATION_ROLES.keys.join(", ")
message = "Invalid role #{role.inspect}. Supported values: #{supported}."
raise ArgumentError, message
end
# Construct an Entitlements::Models::Group from a given role.
#
# role - A String with the role name.
#
# Returns an Entitlements::Models::Group object.
Contract String => Entitlements::Models::Group
def role_to_group(role)
# The security_manager role is a special case because it is not a role that is
# part of the org membership API. Instead, it is a role that is assigned to users via
# the org role API.
if role == "security_manager"
members = github.users_with_role(role)
else
members = github.org_members.keys.select { |username| github.org_members[username] == role }
end
Entitlements::Models::Group.new(
dn: role_dn(role),
members: Set.new(members),
description: role_description(role)
)
end
# Default description for a given role.
#
# role - A String with the role name.
#
# Returns a String with the default description for the role.
Contract String => String
def role_description(role)
"Users with role #{role} on organization #{github.org}"
end
# Default distinguished name for a given role.
#
# role - A String with the role name.
#
# Returns a String with the distinguished name for the role.
Contract String => String
def role_dn(role)
"cn=#{role},#{github.ou}"
end
end
end
end
end