GitHub: signing commit in a workflow
Committing in your workflow can normally be done using git commands or other actions that perform commits for you. However, if your repository requires commit signing, it is difficult to manage securely a GPG keys and set up GitHub Runner to sign your commit. Fortunately, this can be done through the GitHub GraphQL API.
GraphQL Mutation
Github provides a GraphQL Mutation createcommitonbranch which creates a commit. Commits made using this mutation are automatically signed by GitHub and will be marked as verified in the user interface.
For better reusability, we can define a GraphQL mutation in a file .github/api/createCommitOnBranch.gql
:
mutation (
$githubRepository: String!,
$branchName: String!,
$expectedHeadOid: GitObjectID!
$commitMessage: String!
$files: [FileAddition!]!
) {
createCommitOnBranch(
input: {
branch:
{
repositoryNameWithOwner: $githubRepository,
branchName: $branchName
},
message: {headline: $commitMessage},
fileChanges: {
additions: $files
}
expectedHeadOid: $expectedHeadOid
}
){
commit {
url
}
}
}
The following input fields must be set when you call this mutation:
githubRepository
branchName
expectedHeadOid
commitMessage
files
Usage with gh CLI
The mutation can now be called using gh
CLI:
gh api graphql \
-F $githubRepository="owner/repo" \
-F branchName="main" \
-F expectedHeadOid=$(git rev-parse HEAD) \
-F commitMessage="chore: commit file" \
-F files[][path]="README.md" -F files[][contents]=$(base64 -w0 README.md) \
-F files[][path]="HELLO.md" -F files[][contents]=$(base64 -w0 HELLO.md) \
-F 'query=@.github/api/createCommitOnBranch.gql'
Warning: files
is an array of FileAddition
, but fortunately, the gh
CLI allows defining nested objects in fields.
Usage in a GitHub Workflow
In order to sign a new commit in your workflow, you can add a step to call the mutation using the gh
CLI:
permissions:
checks: write
statuses: write
contents: write
jobs:
committing:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
- name: edit file
run: |
echo "hello" >> README.md
- name: commit
run: |
gh api graphql \
-F $githubRepository=$GITHUB_REPOSITORY \
-F branchName=$BRANCH \
-F expectedHeadOid=$(git rev-parse HEAD) \
-F commitMessage="chore: commit file" \
-F files[][path]="README.md" -F files[][contents]=$(base64 -w0 README.md) \
-F files[][path]="HELLO.md" -F files[][contents]=$(base64 -w0 HELLO.md) \
-F 'query=@.github/api/createCommitOnBranch.gql'
env:
GH_TOKEN: ${{ github.token }}
BRANCH: "main"
This commit will be signed by github-actions[bot]
.