A tool to manage GitHub repo collaborators with files
- The problem to solve
- How GitHub Collaborator Manager solves this
- Security implications
- Prerequisites
- One time setup
- Enabling collaborator manager on a repo
collaborators.yaml
format- Why don't we have to configure which GitHub webhooks to trigger on?
You've got a group of people who you want to collaborate with in multiple private repositories but you don't want to pay for GitHub organizations (which would be $135/month for 15 people). You also don't want to manually go and either add new collaborators or remove existing collaborators from all the different private repos, instead you want to be able to manage groups of collaborators and associate each private repo with one of those groups. You also want to enable all of your contributors to manage who is and isn't a collaborator.
GitHub Collaborator Manager (GCM) allows you to create a file in each of your private repos which lists the collaborators that that repo should have. These collaborator files can list either GitHub users, or other repos which have collaborator files in them so that you can set a repo to have the same collaborators as another repo.
Each time a collaborator file is updated, AWS Lambda updates the GitHub settings for that repo (and all dependent repos) to reflect the added or removed collaborators.
For private repos on which you enable GCM, GCM intentionally grants any user who can already push code to that repo the ability to add and remove collaborators.
- A paid GitHub user ($7/month) who can create private repos
- A free Amazon Web Services (AWS) account. This requires a credit card but GCM will not incur any charges as it uses exclusively services in their free tier.
-
Provision a GitHub personal token with
repo
scope permissions. -
Create a
config.yaml
with GitHub personal token. The file would look like this:github_token: 0123456789abcdef0123456789abcdef01234567
-
Zip up github_collaborator_manager, it's dependencies and the
config.yaml
tmpdir=`mktemp -d` pip install agithub PyYAML python-dateutil --target "$tmpdir" cwd=`pwd` pushd "$tmpdir" zip -r "${cwd}/github_collaborator_manager.zip" * popd rm -rf "$tmpdir" zip --junk-paths github_collaborator_manager.zip github_collaborator_manager/__init__.py chmod 644 github_collaborator_manager/config.yaml;zip --junk-paths github_collaborator_manager.zip github_collaborator_manager/config.yaml;chmod 600 github_collaborator_manager/config.yaml
-
Create an AWS IAM role to be used by a AWS Lambda function with
LambdaBasicExecution
echo '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":["lambda.amazonaws.com"]},"Action":["sts:AssumeRole"]}]}' | aws iam create-role --role-name github-collaborator-manager --assume-role-policy-document file:///dev/stdin aws iam attach-role-policy --role-name github-collaborator-manager --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
-
Deploy the zip artifact to Lambda
role_arn="`aws iam get-role --role-name github-collaborator-manager --output text --query 'Role.Arn'`" lambda_arn="`aws lambda create-function --function-name github-collaborator-manager --runtime python2.7 --timeout 30 --role $role_arn --handler __init__.lambda_handler --zip-file fileb://github_collaborator_manager.zip --query 'FunctionArn' --output text`" echo "Created Lambda function $lambda_arn"
-
Create SNS Topic
topic_arn=`aws sns create-topic --name GithubWebhookTopic --output text --query 'TopicArn'` aws sns create-topic --name GithubWebhookTopic --output table --query '{"Sns topic":TopicArn}' a=(${topic_arn//:/ });echo "Sns region : ${a[3]}"
-
Update Lambda function resource policy to grant SNS rights to invoke it
aws lambda add-permission --function-name github-collaborator-manager --statement-id GiveSNSPermissionToInvokeFunction --action lambda:InvokeFunction --principal sns.amazonaws.com --source-arn $topic_arn
-
Subscribe the Lambda function to the SNS topic
aws sns subscribe --topic-arn $topic_arn --protocol lambda --notification-endpoint $lambda_arn
-
Create IAM User to be used by GitHub
aws iam create-user --user-name github-sns-publisher echo "{\"Version\": \"2012-10-17\",\"Statement\": [{\"Action\": [\"sns:Publish\"],\"Resource\": [\"${topic_arn}\"],\"Effect\": \"Allow\"}]}" | aws iam put-user-policy --user-name github-sns-publisher --policy-name PublishToSNS --policy-document file:///dev/stdin aws iam create-access-key --user-name github-sns-publisher --output table --query 'AccessKey.{"Aws Key":AccessKeyId, "Aws secret":SecretAccessKey}'
-
Configure GitHub SNS integration using the AWS IAM user API keys generated above by browsing to the repo you want to enable, clicking "Settings", clicking "Integrations & services" in the left column, clicking the "Add service" button, typing "SNS" in the filter field to search for "Amazon SNS"
- Enter the
Aws key
,Sns topic
,Sns region
andAws secret
created above in each repo you want managed
- Enter the
-
Create a
.well-known/collaborators.yaml
file in the repo and the collaborator manager will process the file when it's created (or updated)
collaborators:
- octocat
- mojombo
The collaborators.yaml
file which is located in any repo at .well-known/collaborators.yaml
contains a map with at least one key, collaborators
. The value for that key is a
list of GitHub usernames that you want to be the collaborators on the repo.
In addtion to GitHub usernames in the collaborators
list, you can add
references to other GitHub repos that you would like to inherit a collaborators
list from.
For example if you created a collaborators file in your repo and added a line like
collaborators:
- octocat
- mojombo
- octocat/Spoon-Knife
the collaborator manager would not only add octocat
and mojobo
as
collaborators it would also fetch the collaborator file
https://github.com/octocat/Spoon-Knife/blob/master/.well-known/collaborators.yaml
and add all of the collaborates in that file as collaborators on your repo.
It would also traverse any other repos referenced in the octocat/Spoon-Knife
collaborator file.
Additionally, if later, the octocat/Spoon-Knife
collaborator file was updated
those added or removed users would also be added or removed from your repo that
references that collaborator file.
If you reference a collaborator file, make sure to also update the referenced
repository to link back using a child_repos
key.
octocat/Fork-Chopstick | octocat/Spoon-Knife |
---|---|
collaborators:
- octocat
- mojombo
- octocat/Spoon-Knife
|
collaborators:
- defunkt
- pjhyett
child_repos:
- octocat/Fork-Chopstick
|
By default push
is the
one action that a webhook is enabled for so nothing needs to be done to enable
this webhook action when the GitHub Amazon SNS integration is enabled. If
this weren't the case you'd need to add the action via the API because it
can't be done through the GitHub web UI. Here's example python code to do it
using the API. To do so you'll need a GitHub personal token with the
write:repo_hook
permission
from agithub.GitHub import GitHub
g = GitHub(token=GITHUB_TOKEN_WITH_WRITE_REPO_HOOK_PERMISSIONS)
status, hooks = g.repos[OWNER][REPO_NAME].hooks.get()
new_event = 'push'
for hook in [x for x in hooks if x['name'] == 'amazonsns']:
if new_event not in hook['events']:
status, result = g.repos[OWNER][REPO_NAME].hooks[hook['id']].patch(add_events=[new_event])