This blog post will not reveal any secrets in AL-Go for GitHub:-)
Instead, it will elaborate ways for you to store secrets, which are used for AL-Go for GitHub. In almost every DevOps setup, you will have to store some keys, passwords, tokens or like. In GitHub, these are called secrets and AL-Go will gaze for a set of secrets by their name.
This blog post will also touch upon how you can use GitHub organizations and environments with your customer initiatives.
GitHub secrets vs. Azure KeyVault
AL-Go for GitHub helps 2 ways of storing your secrets, GitHub secrets or Azure KeyVault. If you store your secrets in an Azure KeyVault you need to provide entry to the Azure KeyVault using a GitHub secret. This is done by following this guideline including the Add a position task step. The location of the GitHub secret created determines the entry to the KeyVault, meaning that you can have and use multiple KeyVaults if you like.
GitHub secrets can be repository secrets, created for a single repository, they can be organization secrets, created 1 or more repositories in the organization or they can be environment secrets, created for a single environment.
You can set GitHub secrets through the GitHub API (or GH command line), but you cannot entry the secrets from your native machine.
Repository secrets
Repository secrets are available to all repositories (private or public, personal or organizational). If a secret is created for a repository, it is only accessible inside GitHub actions for that repository. Repository secrets are not included when forking a repository (obviously).
For repositories created under your personal account, this is really the only place you can store secrets for the workflows. For repositories created under an organization, you can also use organization secrets.
Organization secrets
If a secret is created for an organization, you can select which repositories the secret should be available for:
The InsiderSasToken is a fine example of an organization secret, which typically is available to all repositories and when you renew the value of the token every 6 months, it routinely renews for all repos.
The LicenseFileUrl is an example of an organization secret, which typically will be available to a selected number of repositories. If you have 2 different License files, which each should be available to a number of repositories, you specify which secret to use in the settings of the individual repository. More about this later.
Environment secrets
If a secret is created for an environment, the secret is only available during deployment to that environment. Environments (and thus also environment secrets) are only available for public repositories or for repositories in organizations with Teams or Enterprise subscription.
Currently, you can place 3 secrets under the environment:
- EnvironmentName contains the actual Business Central Environment name. If not specified, the name of the environment in GitHub is used.
- AuthContext contains the authorization context for the environment.
- Projects is only used if the repository is multi-project. The secret contains a comma separated list of the initiatives to be revealed to the environment. Default is all. (Note that every project can have multiple apps, which are all included)
If you are using a private repository in a free GitHub subscription, where environments are not available, you can create environments in the settings file and you can create these secrets as <environmentname>_EnvironmentName and <environmentname>_AuthContext.
At the time writing this blog post, you cannot specify initiatives until using environment secrets. In a prospective version, it will be possible to specify initiatives as a setting instead.
Priority order
If secrets exist in multiple places, the order of priority is
- Environment secret
- Repository secret
- Organization secret
- Azure KeyVault specified in environment secret
- Azure KeyVault specified in repository secret
- Azure KeyVault specified in organization secret
As earlier stated, environment secrets are only available during deployment to the specific environment.
Forks
If you fork a GitHub repository to your personal or organization account, you obviously do NOT get a copy of the secrets from that repository. GitHub actions in the main repository, also cannot entry the secrets while operating a CI/CD workflow based on a Pull Request from a fork (An evil PR could reveal the secrets).
This means that if your repository contains an AppSource App (which currently always requires a license file URL), you will always get this error during the CI/CD workflow run on the Pull Request from a fork:
and in the details:
If you review the code and choose to merge anyway, the CI/CD workflow will re-run based on the commit and will now have entry to the secrets.
For this and other causes, the recommendation is to use feature branches, from which the Pull Request will have entry to the necessary secrets and the ability to construct, publish and test your app.
In a prospective version AL-Go we will modify the CI/CD workflow to nonetheless perform the compile during the Pull Request but skip the publish step and the test run step and replace the error with a warning stated that the app has not been revealed and examined.
Named secrets
AL-Go for GitHub uses settings and secrets to enable functionality.
If the Code Sign certificates secrets are available, then the CI/CD workflow routinely signs your app, if the LicenseFileUrl secret is available, it is used during construct, if a StorageContext secret is available, the CI/CD workflow will routinely publish construct artifacts to a storage account, etc. etc.
Below is a list of named secrets you can create in order to get and use additional functionality.
GhTokenWorkflow | Whenever you run the Update AL-Go System Files workflow, you will need a secret called GhTokenWorkflow containing a personal entry token with workflow permissions, like described here. |
InsiderSasToken | The Insider Sas Token is available for companions on https://aka.ms/collaborate to allow entry to insider (prospective) builds of Business Central. This secret is desired for the Test Next Minor and Test Next Major workflows. |
LicenseFileUrl | For AppSource apps, you need to specify a direct download URL to your license file in this secret. |
CodeSignCertificateUrl and CodeSignCertificatePassword |
For AppSource apps, you need to specify a code signing certificates. The secret named CodeSignCertificateUrl needs to contain a direct download URL to your code signing certificates in .pfx format and a secret named CodeSignCertificatePassword needs to contain the pfx password. |
KeyVaultCertificateUrl, KeyVaultCertificatePassword and KeyVaultClientId |
If your AppSource app needs KeyVault entry, you need to provide these 3 secrets according to the requirements described here. |
StorageContext | If you specify a StorageContext secret, your app artifacts are copied to a storage account using the specs in the StorageContext secret. |
<environmentName>_AuthContext <environmentName>-AuthContext AuthContext |
If your authorization context is specified as an environment secret, it can be named AuthContext, else you need to create a secret with the environment name followed by underscore or dash and AuthContext, like described here. |
<environmentName>_EnvironmentName <environmentName>-EnvironmentName EnvironmentName |
If your actual environment name is different from the environment name in AL-Go for GitHub, you need an EnvironmentName secret as described here. |
When adding new functionality to AL-Go for GitHub, more secrets might be added.
Secret name indirections
As already mentioned, secrets are located by name and secrets can be shared between multiple repositories. Let’s say you have 2 License files. One license file should be used for 5 of your repositories and another license file should be used for another 5 of your repositories. You can however not create 2 organization secrets called LicenseFileUrl and assign them to 5 repositories each and you don’t really want to add the secrets to the individual repositories, as this means you would have to modify every single repo when you have an update to the secret.
For this, you can use secret name indirections. In the individual repository, you can create a setting called LicenseFileUrlSecretName containing the value ContosoLicenseFile, then the secret called ConsotoLicenseFile is used as LicenseFileUrl in this repository.
The same mechanism can be used for all secrets. Create a setting in the repository called <secretname>SecretName and your secret will be read from that name instead.
Recommendations
My recommendation when it comes to organizations and secrets are as follows:
- One GitHub organization per partner (use Teams or Enterprise subscription)
- for IP owned by the partner
- Use organizational secrets for developer license, certificates etc.
- Use environment secrets for authorization to customer environments
- Setup self-hosted brokers for the organization to improve construct performance
- One GitHub organization per customer (Free or Teams license)
- for IP owned by or shared with the customer
- use organization secrets for authorization to customer environments
- Optionally use self-hosted brokers for performance
Hope this helps
Freddy Kristiansen
Technical Evangelist