-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
Copy pathghe-org-permissions-report.rb
118 lines (103 loc) · 4.32 KB
/
ghe-org-permissions-report.rb
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
#!/usr/bin/env ruby
# Generates a CSV report listing all organizations, their repositories,
# collaborators, effective permissions, teams, and team permissions
#
# Set OCTOKIT_ACCESS_TOKEN to a token with read:org scope owned by a site admin
# and OCTOKIT_API_ENDPOINT to http(s)://[your-hostname]/api/v3/
#
# Use `ghe-org-admin-promote` to make a site admin an owner of all
# organizations
require 'octokit'
ghe = Octokit::Client.new
PERMISSION_LEVELS = [:admin, :push, :pull]
def get_repo_teams(ghe, repo_full_name)
teams = []
ghe.repo_teams(repo_full_name).each do |t|
teams << [t, ghe.team_members(t.id).map(&:login)]
end
teams
rescue Octokit::NotFound
[]
end
def get_org_role(ghe, org_name, user_login)
ghe.org_membership(org_name, user: user_login).role
rescue Octokit::NotFound
'outside-collaborator'
end
permission_list = []
ghe.orgs(ghe.user).each do |org|
# We shouldn't try to get the org permissions if we're not an admin,
# they'll be wrong or misleading
if get_org_role(ghe, org.login, ghe.user.login) != 'admin'
STDERR.puts "Skipping #{org.login} - not an organization admin"
next
end
ghe.org_repos(org.login).each do |repo|
# Fetch the collaborators on this repo (which includes their permissions).
# This gives us the effective permissions that the user has, regardless of
# how they've gotten those perms.
collaborators = ghe.collabs(repo.full_name)
# Find the teams that include the repo.
teams = get_repo_teams(ghe, repo.full_name)
collaborators.each do |collab|
# Check the collaborator's role in the organization. If they're an admin,
# they'll have admin access on all repos even if they're not in any teams.
org_role = get_org_role(ghe, org.login, collab.login)
perms = PERMISSION_LEVELS.find { |m| collab.permissions.send(m) }
repo_access = [org.login, repo.name, collab.login, org_role, perms.to_s]
team_memberships = []
teams.each do |team, members|
# For each team, see if the current collaborator is a member, and if so,
# add the team and the permissions it would grant (which may not be the
# user's effective permissions) to the list.
# members = ghe.team_members(team.id).map(&:login)
next unless members.include?(collab.login)
team_memberships << [
team.name,
team.permission,
ghe.team_membership(team.id, collab.login).role
]
end
# Try to identify the source of the collaborator's effective permission.
# We can say for sure where it's being granted in these cases:
#
# - User is org admin: they'll always have admin perms, and the source
# is their org role.
# - User is outside collaborator: They can't be a team member, so the
# source is the org assignment.
# - User is org member and permissions are better than any team grants
# (e.g. effective permission is write, but team only grants read):
# source must be the default repo perms on the org.
#
# However, if the permissions are equal to those assigned by a team,
# they may be granted by just the team, or by both the team and the
# default repo perms. Since the orgs API doesn't tell us what the
# default repo perms are, we can't say for sure. This could cause
# confusion for an admin who wants to know "what do I need to do to
# revoke this user's push access", but we'll just do the best we can and
# say "team" in this case.
best_team_permission = team_memberships.map do |tm|
PERMISSION_LEVELS.index(tm[1].to_sym)
end.sort.first
perm_source =
if org_role == 'admin'
'org-admin'
elsif org_role == 'outside-collaborator'
'org-collaborator'
elsif best_team_permission.nil? || PERMISSION_LEVELS.index(perms) < best_team_permission
'org-default-permission'
else
'team'
end
if team_memberships.count > 0
team_memberships.each do |m|
permission_list << repo_access + [perm_source] + m
end
else
permission_list << repo_access + [perm_source]
end
end
end
end
puts 'Organization,Repository,User,Organization Role,Effective Permissions,Permissions Source,Team Name,Team Permission,Team Role'
permission_list.each { |p| puts p.join(',') }