This is the repository for a java-based REST service that adds branch protection rules to a Github repository. Branch protection rules allow you to define rules for your important repository branches that govern who can push to or delete branches, if pull requests and/or status checks are required, and other settings.
The service supports the following use cases:
- Automatically configure protected branch settings for all new repositories created in a Github organization.
- Retroactively apply protected branch settings to existing repositories in a Github organization.
The default branch protection rules that this service applies can be found here. This default file can be overridden with an environment variable.
The service has two primary endpoints (OpenAPI definition for this service can be found at {service-url}/swagger-ui.html):
- /repo/event_callback
- This can receive Github webhook
repoevents and if theactiontype iscreated, the service will:- Protect the default branch
- Add a new issue to the repo tagging users and teams to alert them to the branch protection rules applied to the repo
- Note: If a repository is empty when first created, Github will not create a default branch. Therefore, branch protection rules would not be applied. To ensure that all new repos have a protected branch, this endpoint will add a default README.md file to empty repositories.
- This can receive Github webhook
- /repo/protect
- This is used primarily for applying branch protection settings to existing repos. See Protecting Existing Repos for its use.
This service can be immediately deployed as a Docker container or to Kubernetes. Each approach is described in subsequent sections.
Before deploying the service, the following prerequisites should be met.
Before deploying the service, a Github personal access token is required.
This is used to make authenticated calls to Github APIs.
Create one now
with the repo scope selected:
To deploy using the Docker or Kubernetes examples below, first set the following environment variables in your shell,
replacing <YOUR TOKEN> with the Github personal access token created earlier
and <USERS_TO_ALERT> with a list of users and/or teams to alert (e.g, @bxtp4p,@deviantpoint/demo_team).
You also need to specify a SERVICE_SECRET, which will be used in the Webhook configuration
to ensure only authorized requests are processed.
export GH_API_TOKEN=<YOUR_TOKEN>
export ALERT_USERS=<USERS_TO_ALERT>
export SERVICE_SECRET=<SERVICE_SECRET>-
Set the environment variables as described in Environment Variables. Then run the following commands to run this service in a Docker container:
docker run --name protected-branch-settings-service -d -p 8080:8080 -e GH_API_TOKEN=${GH_API_TOKEN} -e ALERT_USERS=${ALERT_USERS} -e SERVICE_SECRET=${SERVICE_SECRET} bxtp4p/protected-branch-settings
-
Logs can be viewed as follows:
$ docker logs -f protected-branch-settings-service Setting Active Processor Count to 8 Calculating JVM memory based on 9053452K available memory Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx8456514K -XX:MaxMetaspaceSize=84937K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 9053452K, Thread Count: 250, Loaded Class Count: 12582, Headroom: 0%) Enabling Java Native Memory Tracking Adding 128 container CA certificates to JVM truststore Spring Cloud Bindings Enabled Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -XX:ActiveProcessorCount=8 -XX:MaxDirectMemorySize=10M -Xmx8456514K -XX:MaxMetaspaceSize=84937K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enable=true . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.6.3) 2022-02-08 03:36:26.992 INFO 1 --- [ main] c.t.g.GithubRepoEventsHandlerApplication : Starting GithubRepoEventsHandlerApplication v0.0.1-SNAPSHOT using Java 11.0.14 on d2aae8ae49ab with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace) 2022-02-08 03:36:27.001 INFO 1 --- [ main] c.t.g.GithubRepoEventsHandlerApplication : No active profile set, falling back to default profiles: default 2022-02-08 03:36:29.792 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2022-02-08 03:36:29.823 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2022-02-08 03:36:29.824 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.56] 2022-02-08 03:36:29.991 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2022-02-08 03:36:29.992 INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2805 ms 2022-02-08 03:36:31.143 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2022-02-08 03:36:31.164 INFO 1 --- [ main] c.t.g.GithubRepoEventsHandlerApplication : Started GithubRepoEventsHandlerApplication in 5.729 seconds (JVM running for 6.603)
-
The service should now be available on port 8080 (e.g., http://localhost:8080).
-
Proceed to configuring the webhook.
The Kubernetes resource manifest files can be found here. To deploy them, follow these steps:
-
Open a terminal and set up your environment variables.
-
Clone this repo and navigate to this project's root directory.
-
Run the following commands to create a Kubernetes Secret and ConfigMap containing the values from the environment variables:
$ kubectl create secret generic gh-api-secret --from-literal=api_token=${GH_API_TOKEN} secret/gh-api-secret created $ kubectl create secret generic service-secret --from-literal=service_secret=${SERVICE_SECRET} secret/service-secret created $ kubectl create configmap alert-users-config --from-literal=alert_users=${ALERT_USERS} configmap/alert-users-config created
-
Now, you can create the deployment and service from the resource manifest files:
$ cat ./deployment/kubernetes/*.yaml | kubectl apply -f - deployment.apps/protected-branch-settings created service/protected-branch-settings created
-
After a few moments, the pod should be running. Check to see the status of the pod is
Running:$ kubectl get pod NAME READY STATUS RESTARTS AGE protected-branch-settings-5c466cd749-9g82h 1/1 Running 0 8s
The service should now be available on port 8080 on the nodes Kubernetes scheduled the pods on.
-
Proceed to configuring the webhook.
In order to use this service to automatically add branch protection rules to newly created repos, you must configure the following in the Github Organization you want to enable this for.
- Navigate to your organization's settings page:

- Navigate to Webhook settings:

- Add a new webhook

- In the Add webhook form, apply the following configuration (leave everything else to their default values):
- Payload URL:
{Protected Branch Settings Service URL}/repo/event_callback- Note: This address needs to be publicly accessible. In the screenshot below, Local Tunnel is used to open a tunnel to allow the webhook data to be sent to the service container that wouldn't otherwise be available publicly.
- Content type:
application/json - Secret: the same value as the
SERVICE_SECRETset earlier - Events:
- Payload URL:
After the webhook is created, you can create a new repository to test if the branch protection rules are applied correctly.
If you already have existing repos in your org you'd like to protect,
you can use the /repo/protect endpoint to do so. This endpoint
expects an array of strings containing the full repo names to protect.
For example, this curl command tries to protect two repositories, deviantpoint/demo and deviantpoint/repo2:
curl -X POST http://localhost:8080/repo/protect \
-H 'Content-Type: application/json' \
-d '["deviantpoint/demo", "deviantpoint/repo2"]'The service supports additional environment variables in addition to the GH_API_TOKEN and ALERT_USERS environment variables
used earlier. The full list of environment variables are described in the table below.
| Environment Variable | Description |
|---|---|
| GH_API_TOKEN | The personal access token used to connect to the Github API. |
| ALERT_USERS | The users and teams to tag in the repo issue created to document the protection rules applied. |
| SERVICE_SECRET | The secret to use for the service. Used in setting up the Github webhook. |
| REPO_PROTECTION_TEMPLATE_FILE | The file to use to replace the default protection rules file. |
| REPO_ISSUE_BODY_TEMPLATE_FILE | The template file to use to output the body of the issue created. Replaces this default. |
| REPO_DEFAULT_README_FILE | The template file to use for the default README file that is optionally created. Replaces this default |
For example, to run this service using an alternate set of protection rules, you can run something like:
docker run --name protected-branch-settings-service -d -p 8080:8080 -v /opt/test/repo_protection_template_alternate.json:/opt/data/alternate.json -e GH_API_TOKEN=${GH_API_TOKEN} -e ALERT_USERS=${ALERT_USERS} -e REPO_PROTECTION_TEMPLATE_FILE=/opt/data/alternate.json bxtp4p/protected-branch-settingsThis will mount the contents of the /opt/test/repo_protection_template_alternate.json file into /opt/data/alternate.json of the container.
And the REPO_PROTECTION_TEMPLATE_FILE environment variable is then used to use the alernate file.
- https://gist.github.com/MaximeFrancoeur/bcb7fc2db08c704f322a
- This is used to validate the signature coming from the Github webhook event header
X-Hub-Signature-256.
- This is used to validate the signature coming from the Github webhook event header

