---
description: >-
  Describes how to setup the GitHub VCS integration on Spacelift, as well as the
  features supported by the integration.
---

# GitHub

One of the things we're most proud of at Spacelift is the deep integration with everyone's favorite version control system - GitHub. This integration is typically setup automatically for users who have selected GitHub as their login source, but if you are logging into Spacelift using a different identity provider (e.g. Google, GitLab, or another SSO provider), and do not have GitHub configured as a VCS Provider, see the following section on [setting up the integration](#setting-up-the-integration). This is also applicable for users who want to connect Spacelift to their GitHub Enterprise instance.

## Setting up the integration

In order to set up the integration from the Spacelift side, navigate to the VCS Providers section of the Account Settings page in your Spacelift account, then click the _Set up_ button next to the GitHub (custom App) option:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LshwwDZmA4HXN0k9e8O%2Fuploads%2FpZ0bTMgsUBYog4mXJyzd%2FScreen%20Shot%202022-04-20%20at%204.25.49%20PM.png?alt=media\&token=d3ec5285-a5a9-4e05-bc4c-f2ab1121a081)

This should open a form like this one:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LshwwDZmA4HXN0k9e8O%2Fuploads%2FYUA7kLHPFNroHSIylUas%2FScreen%20Shot%202022-04-20%20at%204.28.27%20PM.png?alt=media\&token=f959071d-6603-4c09-8aea-8371e71a5b7a)

### Create a GitHub App

Before you can complete this step you need to create a GitHub App within GitHub. Start by navigating to the _GitHub Apps_ page in the _Developer Settings_ for your account/organization, and clicking on _New GitHub App._

You will need the Webhook endpoint and Webhook secret while creating your App, so take a note of them.

You can either create the App in an individual user account or within an organization accoun&#x74;_:_

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-M_Q-aIWbZ8IVVb3LMCj%2F-M_QXzJ3PjodBKstkUIw%2Fimage.png?alt=media\&token=f206ef04-410a-4341-a30b-0fda6d9edb1f)

Give your app a name and homepage URL (these are only used for informational purposes within GitHub):

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-M_Q-aIWbZ8IVVb3LMCj%2F-M_QYkBcZzxkDf3EcUND%2Fimage.png?alt=media\&token=138455aa-b8f4-421e-8ff0-d016781be5ae)

Enter your Webhook URL and secret:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-M_Q-aIWbZ8IVVb3LMCj%2F-M_QZNPpbwbhpgmTM6Nj%2Fimage.png?alt=media\&token=0a84e9e4-8ac8-485d-9735-0a060c39e467)

**Set the following Repository permissions:**

| Permission      | Access       |
| --------------- | ------------ |
| Checks          | Read & write |
| Contents        | Read-only    |
| Deployments     | Read & write |
| Metadata        | Read-only    |
| Pull requests   | Read & write |
| Webhooks        | Read & write |
| Commit statuses | Read & write |

**Set the following Organization permissions:**

| Permission | Access    |
| ---------- | --------- |
| Members    | Read-only |

**Subscribe to the following events:**

* Organization
* Pull request
* Push
* Repository

Finally, choose whether you want to allow the App to be installed on any account or only on the account it is being created in and click on _Create GitHub App:_

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-M_Q-aIWbZ8IVVb3LMCj%2F-M_Qa9RR9OAWylviuHVL%2Fimage.png?alt=media\&token=da181cc8-ae6e-495d-8888-03e9e5910977)

Once your App has been created, make a note of the _App ID_ in the _About_ section:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-M_Q-aIWbZ8IVVb3LMCj%2F-M_QaSa8ccCC4xiokr9U%2Fimage.png?alt=media\&token=f546cc25-0b15-402b-b206-8b77ed86ffb5)

Now scroll down to the _Private keys_ section of the page and click on _Generate a private key:_

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-M_Q-aIWbZ8IVVb3LMCj%2F-M_QaiEQLqx0RoPTTgDo%2Fimage.png?alt=media\&token=3e231917-c353-48e2-ab09-d0fa7bdbacfa)

This will download a file onto your machine containing the private key for your GitHub app. The file will be named `<app-name>.<date>.private-key.pem`, for example `spacelift.2021-05-11.private-key.pem`.

Now that your GitHub App has been created, go back to the integration configuration screen in Spacelift, and enter your _API host URL_ (the URL to your GitHub server), the _App ID_, and paste the contents of your private key file into the Private key box:

{% hint style="info" %}
If you are using github.com set your API host URL as:  [https://api.github.com](https://api.github.com)
{% endhint %}

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LshwwDZmA4HXN0k9e8O%2Fuploads%2F0LpY1mRpFqQuoBOxpH3p%2FScreen%20Shot%202022-04-20%20at%204.30.53%20PM.png?alt=media\&token=715011bb-ff1c-484a-a006-f533347100dd)

Click on the Save button to save your integration settings.

### Installing your GitHub App

Now that you've created a GitHub App and configured it in Spacelift, the last step is to install your App in one or more accounts in your GitHub account. To do this, go back to GitHub, find your App in the GitHub Apps page in your account settings, and click on the _Edit_ button next to it:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-M_Q-aIWbZ8IVVb3LMCj%2F-M_Qd81qpDfLcetHRReS%2Fimage.png?alt=media\&token=0134b47e-b4be-425e-924b-d08b604f86d3)

Go to the _Install App_ section, and click on the _Install_ button next to the account your want Spacelift to access:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-M_Q-aIWbZ8IVVb3LMCj%2F-M_QdQqWiU3ulvim7xp0%2Fimage.png?alt=media\&token=de04d67f-c8c1-41a8-abdb-171c02bfa4f8)

Choose whether you want to allow Spacelift access to all the repositories in the account, or only certain ones:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-M_Q-aIWbZ8IVVb3LMCj%2F-M_QdbDwDo9bH97PhiFZ%2Fimage.png?alt=media\&token=c60feae3-e8c7-47a5-b0fc-ae80787ea208)

Congrats, you've just linked your GitHub account to Spacelift!

## Unlinking the Integration

If you no-longer need the integration, you can remove it via the _Unlink_ button on the VCS Providers page:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LshwwDZmA4HXN0k9e8O%2Fuploads%2Fr0Mh56KPMZzoRtRm4c6F%2FScreen%20Shot%202022-04-21%20at%2012.31.50%20PM.png?alt=media\&token=e959081f-02d8-4b9a-885d-5711077f7449)

Please note that unlinking the integration in Spacelift will not remove the GitHub App or its permissions from within GitHub. You will need to do that yourself

## Using GitHub with stacks and modules

If your Spacelift account is integrated with GitHub, the stack or module creation and editing forms will show a dropdown from which you can choose the VCS provider to use. GitHub will always come first, assuming that you've integrated it with Spacelift for a good reason:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LshwwDZmA4HXN0k9e8O%2Fuploads%2FepcsT8VqTGxGEskXtBTX%2FScreen%20Shot%202022-04-21%20at%2012.43.09%20PM.png?alt=media\&token=ca7fb84f-c5d7-45b4-8c46-2e404e9c68e7)

The rest of the process is exactly the same as with [creating a GitHub-backed stack](../../../concepts/stack/creating-a-stack#integrate-vcs) or module, so we won't go into further details.

## Team-based access

In order to spare you the need to separately manage access to Spacelift, you can reuse GitHub's native teams. If you're using GitHub as your identity provider (which is the default), upon login, Spacelift uses GitHub API to determine organization membership level and team membership within an organization and persists it in the session token which is valid for one hour. Based on that you can set up [login policies](../../concepts/policy/login-policy) to determine who can log in to your Spacelift account, and [stack access policies](../../concepts/policy/stack-access-policy) that can grant an appropriate level of access to individual [Stacks](../../concepts/stack).

{% hint style="info" %}
The list of teams is empty for individual/private GitHub accounts.
{% endhint %}

## Notifications

### Commit status notifications

Commit status notifications are triggered for [_proposed_ runs](../../concepts/run/proposed) to provide feedback on the proposed changes to your stack - running a preview command (eg. `terraform plan` for Terraform) with the source code of a short-lived feature branch with the state and config of the stack that's pointing to another, long-lived branch. Here's what such a notification looks like:

...when the run is in progress ([initializing](../../../concepts/run#initializing)):

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-Lv5hqUqEvFvcKwoDHL3%2F-Lv5p8wnJFOlGLWjIJy0%2FTest_a_change_by_marcinwyszynski_%C2%B7_Pull_Request__6_%C2%B7_spacelift-io_marcinw-end-to-end.png?alt=media\&token=afc66baf-5fce-49a2-af00-74b8b93004cf)

...when it succeeds _without changes_:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-Lv5hqUqEvFvcKwoDHL3%2F-Lv5qCDIuD-BHMTIyyKO%2FTest_a_change_by_marcinwyszynski_%C2%B7_Pull_Request__6_%C2%B7_spacelift-io_marcinw-end-to-end.png?alt=media\&token=92592b7e-7774-4e38-82ef-22137a2a6e7d)

...when it succeeds _with changes_:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-Lv5hqUqEvFvcKwoDHL3%2F-Lv5pHTVngcKktOSFZ3P%2FTest_a_change_by_marcinwyszynski_%C2%B7_Pull_Request__6_%C2%B7_spacelift-io_marcinw-end-to-end.png?alt=media\&token=6d6cb4a9-f36f-4d8b-a2d1-3065a8b062e7)

...and when it fails:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-Lv5hqUqEvFvcKwoDHL3%2F-Lv5qSfba3mblEVHiGfw%2FTest_a_change_by_marcinwyszynski_%C2%B7_Pull_Request__6_%C2%B7_spacelift-io_marcinw-end-to-end.png?alt=media\&token=79fe50d7-a67b-4389-a035-695cefc7a685)

In each case, clicking on the _Details_ link will take you to the GitHub check view showing more details about the run:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-MgFckk_eTrfAwIORto1%2F-MgFegSyT7hNF3ak3GZ6%2FAdd_Azure_integration_variables_by_adamconnelly_%C2%B7_Pull_Request__561_%C2%B7_spacelift-io_infra.png?alt=media\&token=88f88d73-d6a1-491f-9213-e723c5c085af)

The Check view provides high-level information about the changes introduced by the push, including the list of changing resources, including cost data if [Infracost](../../vendors/terraform/infracost) is set up.

From this view you can also perform two types of Spacelift actions:

* **Preview** - execute a [proposed run](../../concepts/run/proposed) against the tested commit;
* **Deploy** - execute a tracked run against the tested commit;

#### PR (Pre-merge) Deployments

The _Deploy_ functionality has been introduced in response to customers used to the Atlantis approach, where the deployment happens from within a Pull Request itself rather than on merge, which we see as the default and most typical workflow.

If you want to prevent users from deploying directly from GitHub, you can add a simple [push policy](../../concepts/policy/git-push-policy) to that effect, based on the fact that the run trigger always indicates GitHub as the source (the exact format is `github/$username`).

```perl
package spacelift

deny["Do not deploy from GitHub"] {
  input.spacelift.run.type == "TRACKED"
  startswith(input.spacelift.run.triggered_by, "github/")
}
```

The effect is as follows:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-MgFckk_eTrfAwIORto1%2F-MgFieGE2ntTTOP-vwhu%2FUpdate_README_md_%C2%B7_Private_worker_pool.png?alt=media\&token=9674b641-f008-4063-afc7-dd841de0afc3)

#### Using Spacelift checks to protect branches

You can use commit statuses to protect your branches tracked by Spacelift stacks by ensuring that _proposed_ runs succeed before merging their Pull Requests:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-Lv5hqUqEvFvcKwoDHL3%2F-Lv5rNJkT5RVo80sU3od%2FNew_branch_protection_rule.png?alt=media\&token=64c97f09-b838-46b3-bff1-0d54f077407b)

This is is an important part of our proposed workflow - please refer to [this section](#proposed-workflow) for more details.

### Deployment status notifications

[Deployments](https://developer.github.com/v3/guides/delivering-deployments/) and their associated statuses are created by tracked runs to indicate that changes are being made to the Terraform state. A GitHub deployment is created and marked as _Pending_ when the [planning](../../../concepts/run/proposed#planning) phase detects changes and a [tracked run](../../concepts/run/tracked) either transitions to [Unconfirmed](../../../concepts/run/tracked#unconfirmed) state or automatically starts [applying](../../../concepts/run/tracked#applying) the diff:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-LuPPxqbmIG1WEOdBaeG%2F-LuRmVB1nke6QPJG43ie%2FDeployments_%C2%B7_spacelift-io_marcinw-end-to-end.png?alt=media\&token=0b7ef8ce-8836-4176-8ac8-dd2eb547f2b5)

If the user does not like the proposed changes during the manual review and [discards](../../../concepts/run#discarded) the [tracked run](../../concepts/run/tracked), its associated GitHub deployment is immediately marked as a _Failure_. Same happens when the user [confirms](../../../concepts/run#confirmed) the [tracked run](../../concepts/run/tracked) but the [Applying](../../../concepts/run/tracked#applying) phase fails:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-LuPPxqbmIG1WEOdBaeG%2F-LuRny8dL3H5hKwnB9vI%2FDeployments_%C2%B7_spacelift-io_marcinw-end-to-end.png?alt=media\&token=455c5585-ef37-4229-8f09-8b3d08e68bb8)

If the [Applying](../../../concepts/run/tracked#applying) phase succeeds (fingers crossed!), the deployment is marked as _Active_:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-LuPPxqbmIG1WEOdBaeG%2F-LuRlyTIoU2TjPLXH53P%2FDeployments_%C2%B7_spacelift-io_marcinw-end-to-end.png?alt=media\&token=d3847441-6a3b-4908-98f4-ae5e76500665)

The whole deployment history broken down by stack can be accessed from your repo's _Environments_ section - a previously obscure feature that's recently getting more and more love from GitHub:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-MRynlyahAZnetTS9lyP%2F-MRyoA5q8DcTgjixOhDR%2Fspacelift-io_infra__Infrastructure_definitions_for_Spacelift.png?alt=media\&token=d8287a7b-f8ff-4de6-b2eb-0592fbe51bcc)

That's what it looks like for our test repo, with just a singe stack pointing at it:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-Lv5hqUqEvFvcKwoDHL3%2F-Lv5u0IGjjjZu2jar6tY%2FDeployments_%C2%B7_spacelift-io_marcinw-end-to-end.png?alt=media\&token=f2e00aed-ef64-4a32-bf8f-491ac73a890f)

{% hint style="info" %}
The _Deployed_ links lead to their corresponding Spacelift [tracked runs](../../concepts/run/tracked).
{% endhint %}

## Pull Requests

In order to help you keep track of all the pending changes to your infrastructure, Spacelift also has a PRs tab that lists all the active Pull Request against your tracked branch. Each of the entries shows the current status of the change as determined by Spacelift, and a link to the most recent Run responsible for determining that status:

![](https://3862190545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LshwwDZmA4HXN0k9e8O%2F-Lyhurhmhdga9DL4KQBs%2F-Lyhx9yjx2-moLnh3iwV%2FPull_Requests_%C2%B7_Spacelift_development.png?alt=media\&token=087bd4e2-3d5b-4517-8689-867e4baf3eef)

Note that this view is read-only - you can't change a Pull Request through here, but clicking on the name will take you to GitHub where you can make changes.

Once a Pull Request is closed, whether with or merging or without merging, it disappears from this list.

## Proposed workflow

In this section, we'd like to propose a workflow that has worked for us and many other DevOps professionals working with infrastructure-as-code. Its simplest version is based on a single stack tracking a long-lived branch like _main_, and short-lived feature branches temporarily captured in Pull Requests. A more sophisticated version can involve multiple stacks and a process like [GitFlow](https://datasift.github.io/gitflow/IntroducingGitFlow.html).

{% hint style="info" %}
These are mere suggestions and Spacelift will fit pretty much any Git workflow. If you find a different process or a distinct variation of one of the described approaches works better for you, please [let us know](https://forms.gle/eFEcsLr5gaiWxSE5A).
{% endhint %}

### Single stack version

Let's say you have a single stack called _Infra_. Let's have it track the default `master` branch in the repository called... `infra`. Let's say you want to introduce some changes - define an S3 bucket, for example. What we suggest is opening a short-lived feature branch, making your change there, and opening a Pull Request from that branch to `master`.

At this point, a proposed run is triggered by the push notification, and the result of running `terraform plan` with the new code but existing state and config is reported to the Pull Request. First, we should ensure that the Pull Request does not get merged to master without a successful run, so we'd protect the branch by **requiring a successful status check** from your stack.

Second, we can decide whether we just need a tick from Spacelift, or we'd rather **require a manual review**. We generally believe that more eyes is always better, but sometimes that's not practicable. Still, it's possible to protect the tracked branch in a way that requires manual Pull Request approval before merging.

We're almost there, but let's also consider a scenario where our coworkers are also busy modifying the same stack. One way of preventing snafus as a team and get meaningful feedback from Spacelift is to **require that branches are up to date before merging**. If the current feature branch is behind the PR target branch, it needs to be rebased, which triggers a fresh Spacelift run that will ultimately produce the newest and most relevant commit status.

### Multi-stack version

One frequent type of setup involves two similar or even identical environments - for example, _staging_ and _production_. One approach would be to have them in a single repository but in different directories, setting [`project_root`](../../../concepts/configuration/runtime-configuration#project_root-setting) runtime configuration accordingly. This approach means changing the _staging_ directory a lot and using as much or as little duplication as necessary to keep things moving, and a lot of commits will necessarily be no-ops for the _production_ stack. This is a very flexible approach, and we generally like it, but it leaves Git history pretty messy and some people really don't like that.

If you're in that group, you can create two long-lived Git branches, each linked to a different stack - the default `staging` branch linked to the _staging_ stack, and a `production` branch linked to the _production_ stack. Most development thus occurs on the staging branch and once the code is perfected there over a few iterations, a Pull Request can be opened from the `staging` to `production` branch, incorporating all the changes. That's essentially how we've seen most teams implement [GitFlow](https://datasift.github.io/gitflow/IntroducingGitFlow.html). This approach keeps the history of the `production` branch clear and allows plenty of experimentation in the `staging` branch.

With the above GitFlow-like setup, we propose protecting both `staging` and `production` branches in GitHub. To maximize flexibility, `staging` branch may require a green commit status from its associated stack but not necessarily a manual review. In the meantime, `production` branch should probably require both a manual approval and a green commit status from its associated stack.

## Webhook integrations

Below is the list of some of the GitHub webhooks we subscribe to with a brief explanation of what we do with those.

### Push events

Any time we receive a repository code push notification, we match it against Spacelift repositories and - if necessary - [create runs](../../../concepts/run#where-do-runs-come-from). We'll also _stop proposed runs_ that have been superseded by a newer commit on their branch.

### App installation created or deleted

When the Spacelift GitHub app is installed on an account, we create a corresponding Spacelift account. When the installation is deleted, we deleted the corresponding Spacelift account and all its data.

### Organization renamed

If a GitHub organization name is changed, we change the name of the corresponding account in Spacelift.&#x20;

{% hint style="warning" %}
This is only applicable for accounts that were created using GitHub originally.
{% endhint %}

### Pull Request events

Whenever a Pull Request is opened or reopened, we generate a record in our database to show it on the Stack's _PRs_ page. When it's closed, we delete that record. When it's synchronized (eg. new push) or renamed, we update the record accordingly. This way, what you see in Spacelift should be consistent with what you see in GitHub.

### Repository renamed

If a GitHub repository is renamed, we update its name in all the [stacks](../../../concepts/stack#repository-and-branch) pointing to it.
