One of the best practices of using GitHub Actions is to fork all actions that you want to use to your internal actions organization. If often use organizationname-actions
for that, just like I am doing for my own personal setup here: rajbos-actions.
After forking the repositories I always get the question:
This post describes my way of working, and how I set up a GitHub Actions Marketplace.
The reasons for forking are plentiful, for example:
Want to know more? Check out a previous user group session on it here or my 2021 session on GitHub Universe 2021!
After setting the internal marketplace up (see below) that will host the ‘blessed’ actions, we also need to prevent any other actions from being used in our production organization. You have control over this in the organization settings:
The reason for having an internal actions marketplace is to have a central location for all the actions that can be used inside our production organization. This is to prevent any actions from the public marketplace from being used in our production organization, without being checked for security risks first.
The process for adding actions to the marketplace is as follows:
security-check
security-approved
I’ve setup a (start of a) example project github-actions-requests that is used to request actions to be added to the internal marketplace.
To do so:
security-check
A DevOps engineer can check out the actions repository and review the code. This is done by:
github.com
domain for anything, or does it use the GITHUB_API_URL
environment variable?)For the security validation you can use your own internal setup. You need something that runs a Software Composition Analysis (SCA) scan and from that get security alerts for any dependencies that have them.
There are lots of tools available for this, for example Black Duck or White Source. GitHub already has Dependabot available that can be used for free on public repos. Since a fork is already a public repo, you can use it to scan the actions source code as well.
For our final setup I want to have it automated as much as we can, so I’ll be describing that process here. After the initial validation is completed and satisfies internal requirements, I want to label the repository with security-validation
and run automated security validation on it. More on that below, but I am setting that up as well in the example repo here.
The results from the checks will be added to the issue as badges from the different systems, with deep links into those systems to check the analysis. That can then be used for the final checks.
For Software Composition Analysis, we can use Dependabot to scan the actions source code for the packages that it uses. You can see the results of one of my actions in the repositories Dependency Graph:
Here you find the direct dependencies (in this case from the packages.json
file of the repository) and all the ‘transient’ dependencies. A transient dependency is a dependency used by one of your direct dependencies. And since the transient dependency can have its own dependencies… it can be a long list. This is why some research shows that 70% of the code you deploy, was never created by you, but pulled in through a dependency. This is of course why a Software Composition Analysis (SCA) is so important to know about the dependencies that you have and match them to a known vulnerability database, also called a ‘Common Vulnerabilities and Exposures’ or ‘CVE’. Some examples of these databases are the National Vulnerability Database from NIST or the CVE database from Mitre.
GitHub has its own GitHub Advisory Database as well, with lots of vulnerabilities listed in it:
After Dependabot has scanned the actions source code, it knows which dependencies are being used. Next, it will generate a list of security advisories for the packages that it found. It can even generate pull requests to the repository to update the vulnerable packages to a non-vulnerable version. Since we’re using it here on a public fork, we don’t use it ourselves. The action publisher should use it on their end to fix the issues found. You could of course use it on your fork and then send a Pull Request to the parent repo to fix the issues, and let the publisher know that they can use these features as well.
In this setup we can use the findings from the Dependabot scan to validate if we can use the action without large vulnerabilities in the packages used.
CodeQL is a tool that can be used to scan the actions source code for vulnerabilities and available for free on public repositories, which our forks are. You configure it as a workflow like I’ve done here. It will use action minutes for its execution.
Be aware that it by default scans the entire repository. In my case, I have a Typescript based action. That means that the Typescript is transpiled to JavaScript and then uploaded to the repository. So CodeQL will then scan everything. This meant that I found an issue in moment.js
through the JavaScript in the repository. Only checking the Typescript code doesn’t find that for example of course, since it is not in that part of the code.
The CodeQL workflow will upload its scan results to GitHub, that can be found by going to ‘Security’ and then ‘Code scanning alerts’:
You can then review the vulnerability listed and check the recommendation.
Since the Actions can also be run as a container, we need to check those dependencies as well. That means scanning the container from the image setting in the action.yaml. This setting can also refer to a Dockerfile in the root of the repository:
# action.yml
name: 'Hello World'
description: 'Greet someone and record the time'
inputs:
who-to-greet: # id of input
description: 'Who to greet'
required: true
default: 'World'
outputs:
time: # id of output
description: 'The time we greeted you'
runs:
using: 'docker'
image: 'Dockerfile'
args:
- $
Scanning the containers can be done by using something like Trivy or Anchore.
When you have done all the security checks, we can do a formal approval of the action and on board it to our own actions organization on GitHub. Labeling the issue as security-approved
will trigger a workflow that:
organization-actions
organizationNow that we have forked the action, it’s up to us to maintain it, update it with the latest changes from the parent repo and fix any issues that might arise (and send those back to the parent repo!). Keeping everything up to date with incoming changes from the parent repo is something that I blogged about earlier here.
Now that we have all that setup, we need to have a good way to discover the actions that are available within our actions organization. We can use the default repo overview page, but that doesn’t feel very user friendly. We want a searchable list of actions, with more information then the default repository description. Since there is nothing available out of the box, I created something myself.
With the setup from actions-marketplace I’ve created an actions marketplace out of the box: you can fork it, configure it and use GitHub Pages to host your website. With it your internal users have a central place to search for internal actions. I also want to include links in it to the internal workflows that use the actions, so you can find examples easily. For the Marketplace maintainers, this will also give them a way to track the actions internal usage: if the action is no longer used in any workflow, you might want to remove it from the Marketplace and save you some maintenance work.
The marketplace repo has been setup with three main components:
The get-action-data.yml
workflow loads all the repositories from an organization it has access to, checks the root directory for an action.yml
or action.yaml
file and parses it for information. The result will be a json file stored in the target repository with a specific branch named gh-pages
.
The get-action-usages.yml
workflow loads all the repositories from an organization (can be a different one then the other step) it has access to, checks the workflows directory for all files with a .yml
extension and parses it for information. The result will be a json file stored in the target repository with a specific branch named gh-pages
.
In this post I’ve given you a way to get started with an Internal Marketplace for GitHub Actions, to take back responsibility for the usage and maintenance of the actions. I also shown how to incorporate some security checks and some examples of setting all this up.
Got any feedback or more questions on how to set things up? Please let me know!
Currently the github-actions-request
:
organization-actions
organization (hardcoded in the workflow at the moment)Since the ‘organization-actions’ organization has been setup to enable the Dependency Graph and Dependabot alerts, I don’t need to do that in the workflow. I just need a way (after a certain amount of time) to check if there are any alerts and included that back into the issue information.