From 6f9fc6eab12d4c74c0b4309d31e458947be4c134 Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Wed, 12 Oct 2022 15:58:36 -0700 Subject: [PATCH 1/4] Use gh CLI to make (verified) commit --- action.yml | 33 +++++++++++++++++++++++++++++++++ update-flake-lock.sh | 10 ++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 81f92f7..1527412 100644 --- a/action.yml +++ b/action.yml @@ -9,6 +9,10 @@ inputs: description: 'GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT)' required: false default: ${{ github.token }} + commit-with-token: + description: 'Set to true to produce a verified commit with token' + required: false + default: false commit-msg: description: 'The message provided with the commit' required: false @@ -119,6 +123,35 @@ runs: TARGETS: ${{ inputs.inputs }} COMMIT_MSG: ${{ inputs.commit-msg }} PATH_TO_FLAKE_DIR: ${{ inputs.path-to-flake-dir }} + COMMIT_WITH_TOKEN: ${{ inputs.commit-with-token }} + + - name: Commit changes + if: ${{ inputs.commit-with-token == 'true' }} + env: + GITHUB_TOKEN: ${{ inputs.token }} + FILE_TO_COMMIT: flake.lock + DESTINATION_BRANCH: ${{ inputs.branch }} + shell: bash + run: | + set -x + export CONTENT=$( base64 -i $FILE_TO_COMMIT ) + export BASE=$DESTINATION_BRANCH + if gh api --method GET /repos/:owner/:repo/git/refs/heads/$DESTINATION_BRANCH; then + git fetch origin $DESTINATION_BRANCH + else + export BASE=$(gh repo view --json defaultBranchRef --template '{{ .defaultBranchRef.name }}' ${{github.repository}}) + gh api --method POST /repos/:owner/:repo/git/refs \ + --field ref=refs/heads/$DESTINATION_BRANCH \ + --field sha=$BASE_SHA + fi + export BASE_SHA=$( git rev-parse origin/$BASE ) + export SHA=$( git rev-parse origin/$BASE:$FILE_TO_COMMIT ) + gh api --method PUT /repos/:owner/:repo/contents/$FILE_TO_COMMIT \ + --field message="${{inputs.commit-msg}}" \ + --field content="$CONTENT" \ + --field encoding="base64" \ + --field branch="$DESTINATION_BRANCH" \ + --field sha="$SHA" - name: Save PR Body as file uses: DamianReeves/write-file-action@v1.1 with: diff --git a/update-flake-lock.sh b/update-flake-lock.sh index e33a199..bf90d73 100755 --- a/update-flake-lock.sh +++ b/update-flake-lock.sh @@ -5,12 +5,18 @@ if [[ -n "$PATH_TO_FLAKE_DIR" ]]; then cd "$PATH_TO_FLAKE_DIR" fi +commitArg="" + +if [[ "$COMMIT_WITH_TOKEN" != true ]]; then + commitArg="--commit-lock-file " +fi + if [[ -n "$TARGETS" ]]; then inputs=() for input in $TARGETS; do inputs+=("--update-input" "$input") done - nix flake lock "${inputs[@]}" --commit-lock-file --commit-lockfile-summary "$COMMIT_MSG" + nix flake lock "${inputs[@]}" $commitArg --commit-lockfile-summary "$COMMIT_MSG" else - nix flake update --commit-lock-file --commit-lockfile-summary "$COMMIT_MSG" + nix flake update $commitArg --commit-lockfile-summary "$COMMIT_MSG" fi From 1ee5a6cee54df82068385bdfb6dc0a1d311e4843 Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Wed, 19 Oct 2022 12:47:05 -0700 Subject: [PATCH 2/4] Create the branch only if needed --- action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/action.yml b/action.yml index 1527412..25f05ee 100644 --- a/action.yml +++ b/action.yml @@ -140,6 +140,7 @@ runs: git fetch origin $DESTINATION_BRANCH else export BASE=$(gh repo view --json defaultBranchRef --template '{{ .defaultBranchRef.name }}' ${{github.repository}}) + export BASE_SHA=$( git rev-parse origin/$BASE ) gh api --method POST /repos/:owner/:repo/git/refs \ --field ref=refs/heads/$DESTINATION_BRANCH \ --field sha=$BASE_SHA From 8e2a4ea6d8c9bd87b3c40107089ad171bcd6d08c Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Fri, 28 Oct 2022 17:29:10 -0700 Subject: [PATCH 3/4] Document how to get compliant updates --- README.md | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d2b5b7..a04ada9 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,44 @@ jobs: token: ${{ secrets.GH_TOKEN_FOR_UPDATES }} ``` +### Authenticating via a Github App + +A Github App can both produce verified commits _and_ create pull requests that will trigger further Github Actions. + +Create a stub Github App in your organization. Disable webhooks, add Content write and Pull Request write permissions, and make it available only within your organization. Install the App in the Organization (possibly restricting only to relevant repos). Copy the App secret into an Actions secret, along with the App ID. + +Set up your workflow like this: + +```yaml +name: update-flake-lock +on: + workflow_dispatch: # allows manual triggering + schedule: + - cron: '0 0 * * 1,4' # Run twice a week + +jobs: + lockfile: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - name: Install Nix + uses: cachix/install-nix-action@v17 + - name: Get Updater Token + uses: tibdex/github-app-token@v1 + id: generate-token + with: + app_id: ${{ secrets.UPDATE_APP_ID}} + private_key: ${{secrets.UPDATE_APP_KEY}} + - name: Update flake.lock + uses: DeterminateSystems/update-flake-lock@vX + with: + token: ${{ steps.generate-token.outputs.token }} + commit-with-token: true + ``` + +``` + ## With GPG commit signing It's possible for the bot to produce GPG signed commits. Associating a GPG public key to a github user account is not required but it is necessary if you want the signed commits to appear as verified in Github. This can be a compliance requirement in some cases. @@ -175,7 +213,7 @@ You can follow [Github's guide on creating and/or adding a new GPG key to an use For the bot to produce signed commits, you will have to provide the GPG private keys to this action's input parameters. You can safely do that with [Github secrets as explained here](https://github.com/crazy-max/ghaction-import-gpg#prerequisites). -When using commit signing, the commit author name and email for the commits produced by this bot would correspond to the ones associated to the GPG Public Key. +When using commit signing, the commit author name and email for the commits produced by this bot would correspond to the ones associated to the GPG Public Key. If you want to sign using a subkey, you must specify the subkey fingerprint using the `gpg-fingerprint` input parameter. From caae4dc74add9d29b625390f70f61c54660290de Mon Sep 17 00:00:00 2001 From: Judson Lester Date: Fri, 4 Nov 2022 10:21:23 -0700 Subject: [PATCH 4/4] CI feedback --- action.yml | 4 ++-- update-flake-lock.sh | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/action.yml b/action.yml index 25f05ee..9ecc894 100644 --- a/action.yml +++ b/action.yml @@ -10,9 +10,9 @@ inputs: required: false default: ${{ github.token }} commit-with-token: - description: 'Set to true to produce a verified commit with token' + description: 'Set to "true" to produce a verified commit with token' required: false - default: false + default: '' commit-msg: description: 'The message provided with the commit' required: false diff --git a/update-flake-lock.sh b/update-flake-lock.sh index bf90d73..512d875 100755 --- a/update-flake-lock.sh +++ b/update-flake-lock.sh @@ -6,9 +6,9 @@ if [[ -n "$PATH_TO_FLAKE_DIR" ]]; then fi commitArg="" - -if [[ "$COMMIT_WITH_TOKEN" != true ]]; then - commitArg="--commit-lock-file " +if [[ "$COMMIT_WITH_TOKEN" != "true" ]]; then + # Commit happening in next step + commitArg="suppress" fi if [[ -n "$TARGETS" ]]; then @@ -16,7 +16,7 @@ if [[ -n "$TARGETS" ]]; then for input in $TARGETS; do inputs+=("--update-input" "$input") done - nix flake lock "${inputs[@]}" $commitArg --commit-lockfile-summary "$COMMIT_MSG" + nix flake lock "${inputs[@]}" ${commitArg:+"--commit-lock-file"} --commit-lockfile-summary "$COMMIT_MSG" else - nix flake update $commitArg --commit-lockfile-summary "$COMMIT_MSG" + nix flake update ${commitArg:+"--commit-lock-file"} --commit-lockfile-summary "$COMMIT_MSG" fi