Over the past month, I have been working on surface-security which is an open source security intelligence and automation platform.
One of the things I wanted to review was the projects’ CI/CD Pipelines, to ensure we could confidently merge changes from outsiders (when we eventually get there), but also to ensure we stay dynamic, nimble and running smooth. In addition, the workflows were “old”, 1 year old that is, and it was enough to experience compatibility issues between OSes and action versions.
GitHub Actions are composed by Workflows, which are a set of Jobs, which are a group of Steps in itself. Steps can be composed of external Actions or your own actions.
From the docs:
An action is a custom application for the GitHub Actions platform that performs a complex but frequently repeated task. Use an action to help reduce the amount of repetitive code that you write in your workflow files.
Actions are a Vendor Lock-in Mechanism
Actions can be obtained from the marketplace, where we can find official ones (GitHub owned) or made by the community. On paper, they sound good, avoid repetitive code and such, but I do not see that with this high regard. The most surprising case for me was
But the same goes when we want to prepare an environment for the language our project needs. There’s
setup-python, and more alike.
This really highlights the purpose of this post. Delegating the preparation of your build environment to third-party components, whether official or by the community, is shooting yourself in the foot because you loose control of that environment, you are exposing your project to the risk of supply chain attacks, and it feels really unnecessary just to spare a few lines of code to setup the environment. But are you really sparing that many lines of code? Ultimately, you’re going to have to declare what your environment needs so other developers can contribute to the project anyway, so why not simply write a bash script to take care of that for you?
The Whole Thing is a Massive Lock-in System
GitHub Actions were essentially built to have people writing their CI/CD systems (which are key to build, ship and distribute apps) based on a system (GitHub) that does not work elsewhere - thus the vendor lock-in. You cannot take your actions and reproduce it elsewhere, not even locally. The underlying principal of re-using actions (
use: actions/checkout@v4, for instance) makes a change to another system a highly expensive one, because it’s not about doing a couple tweaks, like adding a
git checkout call in your new system - one would have to design the entire system from scratch because you would be missing a awful lot of these steps along the way in your CI/CD process.
I was surprised to find so many public and private projects using this system without considering making its backbone simple, reproducible bash scripts. Despite the recommendation of using actions from the marketplace, the DevOps engineer has the option to write bash scripts and use those instead of re-usable actions. Advantages? Well:
- No vendor lock-in in regards to your CI/CD system - if in the future you need to change, you take your bash scripts with you and make that work, instead of redesigning the whole system again;
- Reproducible builds (developers can build the project locally and debug anything that comes up - and it will happen!) and I’m surprised people are not experiencing too much of this;
- No third party dependencies by not importing code you do not own (it doesn’t matter if it is open source or not, official or from the community);
Disadvantages? More code to write? Is it really though? As mentioned above, you’re probably already writing some from of reproducible builds for your devs, like
nix or something - why not leverage those instead?
I remember when GitHub Actions were mostly a paid system, where users had 2000 minutes for free each month. I don’t recall what was the syntax like at the time, but I would really love to dig down the rabbit hole and find out if this action re-usability concept came after that or not.
Hope you enjoyed reading this mild rant I’m writing after completing a phase 1 of a project that required learning and reworking on the CI/CD Pipelines for a list of 20 projects. An after-thought that emerged very quickly was to create bash scripts to use further down the road - which I think is the way to go to create secure, reproducible and vendor free CI/CD pipelines for your projects, whether on a commercial or open source setting.
Thanks for reading, I’ll see you next time.