Rethinking the GitHub AT-AT Design: Balancing Simplicity and Extensibility for the Future
As I reflect on the design and functionality of the GitHub AT-AT, particularly the atat-application-environment module, I find myself at a crossroads. The module was originally created to fill a specific gap in the GitHub AT-AT setup, adding a layer between the GitHub root module and the core hosted components: the branch structure, source code (including GitHub Actions workflows), and environment variables at both the repository and environment levels. This module plays a key role in setting up the GitHub repository for AT-AT operations, but as the landscape has evolved, I am beginning to question whether this design still meets the growing needs of my infrastructure.
I have to decide whether to allow users to extend this setup with their own code and workflows or if I should make them work around the existing codebase. This decision will not only influence the future direction of this module but also shape how I approach the extensibility of similar modules.
Breaking up the GitHub Environment creation. I’ve often been wondering about the utility of the module that I created called atat-application-environment. It adds a layer between the GitHub AT-AT Root Module and the GitHub hosted bits — the Branch Structure, the Source Code (including the GitHub Actions Workflows) and the GitHub Environment Variables at the Repository and Environment level. The responsability of this module is essentially to setup the GitHub Repository for the AT-AT — as a result this individual module is tightly coupled with a specific codebase and a specific GitHub Actions Workflows. I have a decision that I have to make. Should I make the codebase a completely replaceable part — meaning should I require extension authors to work around the code and workflows I drop? or should I allow authors to replace the code and workflows I drop?
As you can see in the above diagram, this module sets up the Code (in blue), the GitHub Actions (in green), the GitHub Environments (in yellow), and the GitHub Variables (both Repository-level and Environment-level in yellow). For each environment we create some, where applicable, GitHub Actions Workflows — namely the Apply on Push and Plan on PR which require environment-specific triggers and we create a set of GitHub Variables at the Environment level which provides the Authentication Context, Backend Context and Execution Context for Terraform to perform its function.
Both the Source Code (blue) and the GitHub Actions (green) are essentially just source code files. I am distinguishing them by GitHub Actions being source code files that reside within the special .github\workflows folder and the “Source Code” Source Code (blue) being any other file within the source code root directory. In this opinionated implementation we reference a single, specific codebase which has a src\terraform directory with a simple Azure Terraform codebase that simply provisions an Azure Resource Group. This codebase, like the GitHub Actions YAML files have hard dependency on the GitHub Variables to be properly configured.
The culprit for Source Code’s main dependency takes the form of the application_name and environment_name input variables in the Terraform root module that is deployed by the GitHub Actions Workflows by its presence within the TERRAFORM_WORKING_DIRECTORY located at src\terraform. If a Terraform root module does not exist at this location in the source code repository, the module won’t work. If the GitHub Actions workflows do not supply values for these two input variables, Terraform’s execution will stall waiting for input from the end user that will never come. The GitHub Actions Workflow has a ton of dependencies on this setup — as one might expect.
- The GitHub AT-AT populates the Trigger with the appropriate branch name (develop, release, main) depending on the GitFlow operation being performed
- The GitHub AT-AT specifies the GitHub Environment the job should execute against. This grants the workflow access to the configuration stored in these variables which is the lifeblood of the operations it is about to perform.
- Through the GitHub Environment Variables it gets access to the Authentication Context, or in this case, the Azure Credential, which contains the Entra ID Tenant & Entra ID Application identifier as well as the Azure Subscription to target — all vary by the “Real” Application environment we are deploying to (i.e. DEV, TEST, PROD).
- Through the GitHub Environment Variables it also gets access to the Execution Context which is used to properly configure Terraform. This includes the application_name and environment_name input variables, the Terraform working directory path and the Terraform Version to use.
- Lastly, it gets access to the Backend Context which it uses to properly initialize Terraform state on terraform init.
The question is, if I want to support different codebases and additional or different GitHub Actions workflows that do more specific things I may need to decouple some of this stuff from the more specific Source Code solution.
For example, I want to create a GitHub AT-AT module that will create an Azure Functions “Core” environment with an active-active App Service Plan setup and an Azure Functions “App” environment that will provision Apps to each of the regions we have App Service Plans. In the Azure Functions GitHub AT-AT I want to setup opinionated .NET solution with unit testing and all the things so that I can spin up new Microservices based on Azure Functions with ease. This is a lot more complicated than just spinning up a single Azure Resource Group. I want my Azure Functions to have a GitHub Actions workflow that will dynamically create a new environment from scratch, run integration tests and destroy the environment.
This does not match with any of the existing GitFlow operations that I have built as they are all geared up for long-lived environments. I also want to include a CI/CD process where there is a .NET build and unit test process on the Pull Request. Currently we only have a “Plan on PR” workflow when a Pull Request is submitted. All of these things aren’t necessarily incompatible with what I already have — they just extend it. This is what is making me think that I should take an addative approach but I think it would be a better design decision to perform that addition in an integration module that is not individually published. It seems like a whole lot of GitHub repositories to maintain.
At this point, I am leaning towards an additive approach where I decouple some of the existing dependencies and allow for greater customization. However, I recognize that this may not be the most sustainable path forward. Instead, I am contemplating creating a series of integration modules within the root GitHub AT-AT module to encapsulate the more complex use cases, allowing for easy extension while maintaining the simplicity of the core atat-application-environment module. The challenge is balancing the desire for extensibility with the need for simplicity, and I am carefully weighing these considerations before making any changes.
In conclusion, the atat-application-environment module has served its purpose well, but the increasing complexity of use cases and the need for more flexibility in handling different scenarios have forced me to reconsider its design. While I am still at a crossroads, I believe that the right solution will involve a modular approach that allows for extensibility without sacrificing the simplicity that made the original design successful. The next steps will require careful planning and consideration of the long-term maintainability of the GitHub AT-AT, ensuring that it can scale to meet the needs of a growing and evolving infrastructure while maintaining its core principles.