Ensure that a workflow in Github Actions is only ever triggered once - workflow

I have workflow that is triggered when a specific file is changed. Is it possible to ensure that this workflow is only triggered the first time that file is changed?
The use case is:
a repository is created from a template repository
to initialize the README and other things in the repo, some variables can be set in a JSON config file
once that file is committed, the workflow runs, creates the README from a template etc.
I have tried to do let the workflow delete itself before it commits and pushes the changed files. That doesn't work: fatal: not in a git directory and fatal: unsafe repository ('/github/workspace' is owned by someone else).
What might work is adding a topic like initialized to the repo at the end of the workflow and check for the presence of this topic at the beginning of the workflow. However, this is feels like a hack in that I'm abusing topics for something they're probably not meant to do.
So my question remains: is there a good way to only run the workflow once?

With the help of the comment by frennky I managed to do solve this by using the GitHub CLI to disable the workflow.
Here is the step at the end of the workflow that does this:
- name: Disable this workflow
shell: bash
run: |
gh workflow disable -R $GITHUB_REPOSITORY "${{ github.workflow }}"
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

Related

Github actions incorrectly thinks variable is a secret and so does not set outputs

A step in my workflow file will return some IDs of EC2 instances in my aws account and then i set these IDs as a github output to be used in other jobs in my workflow file
I have done this in many workflows and step will return something like this:
["i-0d945b001544f2614","i-0b90ba69d37aad78c"]
However, in one workflow file github is masking the IDs as it thinks it is a secret for some reason, so it will return:
["i-***2d571abc6d7d***4ef","i-***186ce12c5cd8e744"]
Therefore i get this error message on the workflow job summary:
Skip output 'instanceIDs' since it may contain secret.
And so the other jobs in my workflow file that rely on this output will fail as github won't set an output.
I have tried to use base64 as suggested in this post but i haven't been able to get that to work
Is there any other work around?
Recently, GitHub released a new feature - configuration variables in workflows.
Configuration variables allow you to store your non sensitive data as plain text variables that can be reused across your workflows in your repository or organization.
You can define variables at Organization, Repository, or Environment level based on your requirement.
These variables are accessible from the workflow by vars context.
Example:
jobs:
display-variables:
runs-on: ${{ vars.RUNNER }}
steps:
- name: Use variables
run: |
echo "Repository variable : ${{ vars.REPOSITORY_VAR }}"
echo "Organization variable : ${{ vars.ORGANIZATION_VAR }}"
In this example, we have the following configuration variables: RUNNER, REPOSITORY_VAR, ORGANIZATION_VAR. As opposed to the repository secrets, the values of these variables won't be masked.
For more details, see the Defining configuration variables for multiple workflows.

Github Branch Protection rules vs. workflow permissions

I would like to implement the rule that every (human) user has to open a PR to change something on the protected branch while the workflow to release the new version is able to increase the version number on that same protected branch.
The branch protection is in place, also the "include administrators" checkbox is checked. So noone can accidentially push to that branch.
Now, when I want to push something from a workflow I get the same error message that I get as a user
name: Build pipeline
"on":
push:
branches:
- 'master'
defaults:
run:
shell: bash
jobs:
release:
runs-on:
- self-hosted
- default-runner
needs: []
steps:
- name: Checkout code
uses: actions/checkout#v2
with:
fetch-depth: 0
clean: true
- name: demo push
if: github.ref == 'refs/heads/dev'
run: |
git config --global user.email "runner#xxx.com"
git config --global user.name "Github Actions Runner"
# normally we would generate the release notes here etc, increase the version,... though lets keep the example simple
date >> test.txt
git add test.txt
git commit -m "test2" test.txt
git push
while setting up the job, the permission of the job are printed out:
GITHUB_TOKEN Permissions
Actions: write
Checks: write
Contents: write
Deployments: write
Discussions: write
Issues: write
Metadata: read
Packages: write
PullRequests: write
RepositoryProjects: write
SecurityEvents: write
Statuses: write
and then the step fails with the following output:
user.email=runner#xxx.com
user.name=Github Actions Runner
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
remote.origin.url=https://github.xxx.com/xx/xxx
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
gc.auto=0
http.https://github.xxx.com/.extraheader=AUTHORIZATION: basic ***
branch.dev.remote=origin
branch.dev.merge=refs/heads/dev
[dev 7ddff59] test2
1 file changed, 1 insertion(+)
create mode 100644 test.txt
remote: error: GH006: Protected branch update failed for refs/heads/dev.
remote: error: You're not authorized to push to this branch. Visit https://docs.github.com/enterprise/3.2/articles/about-protected-branches/ for more information.
To https://github.xxx.com/xx/xxx
! [remote rejected] dev -> dev (protected branch hook declined)
error: failed to push some refs to 'https://github.xxx.com/xx/xxx'
Error: Process completed with exit code 1.
So the question is: how can I enforce the human users to open a PR, let it reviewed and checked before it can be merged, while the workflows can directly manipulate the (protected) branch?
After some research I found out that there is currenly (June 2022) no straight forward solution (source).
There are two workarounds. One is to remove the zranch protection in the workflow and restore it afterwards. The risk is that the workflow breaks in between (e.g. when the workflow runner crashes) and the branch stays unprotected. Another risk is that it could happen that a user accidentially or deliberately pushes to the now unprotected branch. (E.g. trigger a release build wait until the branch protection is removed and push to that branch).
The alternative solution is to remove the admin rights from the human users so that they need a PR to change the protected branch. During a release build a PAT of a technical user with admin rights is used (not ${{ secrets.GITHUB_TOKEN }}). In the branch protection the "enforce admins" option is disabled.
Though there is a feature request covering this topic.

Using env variable github.ref_name doesn't give me branch name

When I use in my workflow github.ref_name it doesn't provide me a branch name from where I triggered this workflow. I get 16/merge. Why? When I use github.ref_type I clearly see that my ref type is branch so why I don't get branch name?
Also it's showing when I use $GITHUB_REF or git symbolic-ref HEAD (and separating refs/heads/ off). Ah and I tried github.event.push.ref but it's not showing me anything.
How to get always branch name from where I triggered the workflow?
For following code:
Run echo running on branch ${GITHUB_REF##*/} ${GITHUB_REF}
When your workflow runs becuase of push event you will get:
running on branch main refs/heads/main
But for pulr request event it would be:
running on branch merge refs/pull/3/merge
Why's that?
If the repository is on GitHub and you have any Pull Requests that have been opened, you’ll get these references that are prefixed with refs/pull/. These are basically branches, but since they’re not under refs/heads/ you don’t get them normally when you clone or fetch from the server — the process of fetching ignores them normally.
You can also check this question here

Within what limits Github actions/cache work?

I don't quite understand the extent to which Github actions/cache works, what I mean:
Caching works fine if I make a pull request and then in the same pull request I add 1 more commit, but if I create a new pull request in the same branch - the caching is reset and starts again, but why?
Is there any way to extend file caching to all yml files and so that each pull request uses existing caching?
Because to speed up the work it turns out - that developers always need to pour their work into one branch, and it somehow sounds like some nonsense.
Info
My caching key is formed as follows
- uses: actions/cache#v2
id: composer-cache
with:
path: .github/docker/development/php-cli/composer/cache
key: ${{ runner.os }}-develop-composer-${{ hashFiles('src/composer.lock') }}
restore-keys: |
${{ runner.os }}-develop-composer-
Yeah, GitHub's cache action has unintuitive behavior across branches. Pull request workflows don't share, and tag workflows never get a cache hit.
Per the docs (useful bit made bold):
A workflow can access and restore a cache created in the current branch, the base branch (including base branches of forked repositories), or the default branch (usually main). For example, a cache created on the default branch would be accessible from any pull request. Also, if the branch feature-b has the base branch feature-a, a workflow triggered on feature-b would have access to caches created in the default branch (main), feature-a, and feature-b.
So the solution then is to make a separate workflow triggered by pushes to main — plus any base branches you like — just to keep a fresh cache available to pull requests and tags.

GitHub Actions: Are there security concerns using an external action in a workflow job?

I have a workflow that FTPs files by using an external action from someuser:
- name: ftp deploy
uses: someuser/ftp-action#master
with:
config: ${{ secrets.FTP_CONFIG }}
Is this a security concern? For example could someuser change ftp-action#master to access my secrets.FTP_CONFIG? Should I copy/paste their action into my workflow instead?
If you use ftp-action#master then every time your workflow runs it will fetch the master branch of the action and build it. So yes, I believe it would be possible for the owner to change the code to capture secrets and send them to an external server under their control.
What you can do to avoid this is use a specific version of the action and review their code. You can use a commit hash to refer to the exact version you want, such as ftp-action#efa82c9e876708f2fedf821563680e2058330de3. You could use a tag if it has release tags. e.g. ftp-action#v1.0.0
Although, this is maybe not as secure because tags can be changed.
Alternatively, and probably the most secure, is to fork the action repository and reference your own copy of it. my-fork/ftp-action#master.
The GitHub help page does mention:
Anyone with write access to a repository can read and use secrets.
If someuser does not have write access to the repository, there should be no security issue.
As commented below, you should specify the exact commit of the workflow you are using, in order to make sure it does not change its behavior without your knowledge.