GitHub Enterprise is a self-hosted version of GitHub that provides organizations with the flexibility to manage their own development environment. In this blog, we will cover the basics of setting up a repository, including branch protection rules and other security settings, as well as how to integrate GitHub Enterprise with Amazon Web Services(AWS) using GitHub Actions.
To get started with GitHub Enterprise, the first step is to set up a new repository. A repository is essentially a container for your project, including all the code, documentation, and other files that you need to develop and maintain your software.
When setting up a new repository in GitHub Enterprise, it is important to consider the security settings you will use to protect your code. This can include things like branch protection rules, which prevent unauthorized changes to certain branches of your repository. You can also configure other security settings like two-factor authentication and access controls to ensure that only authorized users have access to your code.
Developers can often end up working in a GH Enterprise since it offers a closed space to the owners of the project. Specifically, when project owners choose to adopt GitHub Enterprise, they are required to create an organization. This organization serves as a container for all repositories associated with the project. In this blog, we will focus on setting up a repository within the organization, without covering organizational settings that developers are less likely to encounter.
2.1 Creating a New Repository in GitHub Enterprise
At the organization home page navigate to the Repositories tab and click New Repository.
Proceed with choosing a name for the repository. Visibility of the repository should be Internal, but that depends on the use case of the repository. Click on Create repository and follow instructions to locally initialize the repository.
2.2 Adding and Managing Collaborators
To add collaborators or teams to your specific repository, navigate to the Settings tab and click on Collaborators and teams on the sidebar. It is important to adhere to the principle of least privilege (POLP). That means that we should limit collaborator’s access rights to only those that are strictly required to do their jobs. In the example below, Marin is a developer so that means he only needs the ‘Write’ role to be able to do his job.
2.3 Branching Strategy
Standard practice for branching strategy is to use certain branches as environments. These environments should correspond to ‘Production’, ‘Stage’ and ‘Development’. However, it all depends on the project’s use case. For this blog, we will use ‘production’, ‘stage’ and ‘development’ branches.
The ‘development’ branch is used to test a recently developed feature; if tests are successful on the ‘development’ branch, then the feature can proceed to the ‘stage’ branch.
The ‘stage’ branch is a second stop for a feature to be tested. Typically, the ‘stage’ branch is a replica of the ‘production’ branch, with the same configurations and infrastructure, allowing developers and testers to test their changes in an environment that closely resembles the production environment. If the tests are successful on the ‘stage’ branch, then the feature can proceed to the ‘production’ branch.
The ‘production’ branch is where the feature gets officially deployed. At this point, the feature is stable and safe for the production environment.
A branching strategy impacts how we can integrate the repository with AWS. In this case, we can designate one account for each environment branch in our repository. For example, let’s say that in this repository developers are developing CloudFormation templates which are used for deployment through GitHub Actions. If they push a feature to the ‘development’ branch, that CloudFormation template would get deployed to the development AWS account; if the feature were pushed to the ‘stage’ branch, it would get deployed to the stage AWS account, etc.
2.4 Development Strategy
We have covered environment branches so far, now it’s time to see how we will develop new features. The best practice for feature development would be to create a separate branch that could be called ‘feature/description-of-the-feature’ (we’ll refer to this branch as feature branch throughout the blog). Feature branches such as this one should be created from one of the environment branches, in some cases that might be ‘production’ or ‘development’ – this is usually defined along with the branching strategy, since this depends on the use case.
Let’s say we have created a feature branch and we have developed a feature on it. Now it is time to push to the ‘development’ branch. We should do that by creating a pull request from the feature branch to the ‘development’ branch.
A pull request (PR) is the best practice because it provides an overview of the feature that we are trying to merge to the environment branch. It also contains an overview of test results for that feature. We will cover more of this later.
2.5 Secrets and Variables
Organization secrets and variables are accessible by all repositories within an organization. Repository secrets and variables are only accessible by the repository where they are defined (though they can also be passed to other repositories). That will not be covered in this blog.
Environment secrets and variables, on the other hand, are specific to a particular environment, and we will cover them in the next section.
2.6 Environment Setup
Located in Settings, there is an ‘Environments’ tab. Environments are useful because we can create a set of rules, secrets, and variables for a specific environment.
For example, we can create three environments called ‘development’, ‘stage’, ‘production’. Let’s say that we want to have a variable called AWS_ROLE which is different across environments, and we want to avoid having three variables in code where each would have the same purpose but different value. In that case we can specify AWS_ROLE in all three environments and assign a different value for each environment.
This is useful when GitHub workflows are created, then we can specify in which environment job is running, so when we use a variable, it will use the value from the specified environment. For example, if we define that the job is running in the ‘production’ environment, then if we use the AWS_ROLE variable in that job, the workflow will know that it should grab the value from the ‘production’ environment.
Furthermore, Environments are also useful when we want to specify which branch can deploy to the environment. If we define that only ‘feature/*’, meaning, branches starting with “feature/” can deploy to the environment, it will automatically deny any other branches which would try to deploy to it.
In GitHub, CODEOWNERS is a feature that lets you define individuals or teams responsible for code within a repository. This feature is particularly useful in large projects where many contributors are working on the codebase. Code owners can be defined for any file or folder within a repository. When a pull request is opened that modifies a file or folder that has a CODEOWNERS file associated with it, the individuals or teams defined in the CODEOWNERS file will be notified and asked to review the pull request.
Code owners can be defined in the file CODEOWNERS in the root of the repository or any subdirectory. The CODEOWNERS file follows a simple syntax where each line represents a file or folder path, followed by a space or tab, and then the list of code owners (GitHub usernames or team names) for that file or folder.
In this example, user ‘sukyca’ is the owner of “.github/workflows” directory and if any change occurs, that user will be asked to review that change in a pull request.
2.8 Branch Protection Rules
GitHub branch protection rules are a powerful tool for ensuring that the code in your repository is of high quality and adheres to the team’s standards. These rules can be applied to specific branches and can enforce a wide variety of requirements. Some common examples of branch protection rules include requiring pull requests to be reviewed by multiple team members, preventing force pushes to a branch, and requiring certain status checks to pass before changes can be merged.
If we have a branch named ‘production’ and we want to protect it by using Branch Protection Rules, we need to navigate to Settings and click on Branches. Click ‘Add rule’ and make sure that the rule name is the same as the name of the branch, otherwise the rule will not apply to the branch. In this case, we would create a rule called ‘production’.
It is a good idea to check “Require a pull request before merging” rule as it will enforce developers to use pull requests instead of pushing directly to the branch.
We can also specify how many approvals we require before the pull request can be valid. This will force responsible users (Codeowners) to check the code before it is released into the environment.
Furthermore, we can check “Require status checks to pass before merging” rule, which will disable the pull request from being merged until the specified jobs are ran successfully.
For example, we have a ‘pr_opened.yml’ workflow which has ‘build’ job in it, if we specify that ‘build’ job is required to pass, then the pull request will wait for it to execute successfully, otherwise it will not let the pull request to get merged.
These were some of the most common rules to be applied to a branch. Of course, this all depends on the project use case, so feel free to explore.
This blog has provided insights into key features and practices of GitHub Enterprise that can greatly enhance collaboration, security, and development processes within your organization. By leveraging these tools and strategies effectively, teams can optimize their workflows and achieve greater productivity and success in their software development endeavors.
Certainly, our DevSecOps team is readily available to assist you in designing, managing, and building such infrastructures within GitHub Enterprise. Don't hesitate to reach out to us or share your thoughts here.
We're here to help!
Also, we're excited to announce that this blog will have a sequel where we'll delve into the connectivity between GH Enterprise repositories and AWS using GitHub Actions. Stay tuned for the upcoming article!