Skip to content

Commit

Permalink
Automatically run renovate on a schedule (#366)
Browse files Browse the repository at this point in the history
* Run renovate on a schedule

* don't even need to check out the repo

* Use a GitHub App

* Update README.md

* add check to access ci script

* Make JWT generation more legible
  • Loading branch information
joecorall authored Jan 7, 2025
1 parent 4d05ff2 commit e0b4a3d
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 6 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/renovate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: run renovate

on:
workflow_dispatch:
# Monday mornings
schedule:
- cron: '15 1 * * 1'

env:
LOG_LEVEL: debug
RENOVATE_REPOSITORIES: islandora-devops/isle-buildkit
RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS: '["bash ci/update-sha.sh \"{{{depName}}}\" \"{{{currentVersion}}}\" \"{{{newVersion}}}\" \"{{{newDigest}}}\""]'
jobs:
run:
runs-on: ubuntu-24.04
timeout-minutes: 10

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
with:
node-version: 20

- name: run renovate
run: |
# fetch GitHub App token for this repo
echo "${{ secrets.GH_APP_PRIV_KEY }}" | base64 -d > private-key.pem
export RENOVATE_TOKEN=$(./ci/fetch-app-token.sh ${{ secrets.GH_APP_ID }} ${{ secrets.GH_APP_INSTALLATION_ID }} private-key.pem)
# run renovate with our token
npx renovate --platform=github
2 changes: 1 addition & 1 deletion .github/workflows/validate-renovate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ env:

jobs:
renovate-config-validator:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
timeout-minutes: 10

steps:
Expand Down
30 changes: 25 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -521,9 +521,10 @@ shasum -a 256 ${ALPACA_FILE}
#### Renovate

Several dependencies in this repo can be automatically updating using [renovate](https://www.mend.io/renovate/).
Several dependencies in this repo can be automatically updated using [renovate](https://www.mend.io/renovate/). Most dependencies are managed using [advanced capture](https://docs.renovatebot.com/modules/manager/regex/#advanced-capture) in the Dockerfile.

Currently these docker images have some depenencies managed by renovate:

Currently these docker images have some dependencies managed by renovate:

```
activemq
Expand All @@ -542,7 +543,28 @@ tomcat

Since renovate does not natively support the ability to extract a sha256 from a file, we need [a custom shell script](./ci/update-sha.sh) in the [postUpgradeTasks](https://docs.renovatebot.com/configuration-options/#postupgradetasks) to calculate the sha256 of our files and update our Dockerfile accordingly.

Post upgrade tasks can only run on self-hosted Renovate instances, so this forces us to run renovate on a properly configured runner (instead of using mend.io's free GitHub app to manage our dependencies). Getting renovate setup locally looks like
Post upgrade tasks can only run on self-hosted Renovate instances, so this forces us to run renovate on a properly configured runner (instead of using mend.io's free GitHub app to manage our dependencies).

##### Running renovate (automated)

We have [a GitHub Action](./.github/workflows/renovate.yml) that runs on a schedule (or can be triggered manually) to automate generating renovate updates.

That action requires a GitHub App (`isle-buildkit-renovate`) to be installed in the Islandora-Devops GitHub org. This app is needed to generate a GitHub access token to allow renovate to create PRs for us in the GitHub workflow. During installation, the app was restricted to only this repo. This is all configurable in the GitHub UI by Islandora-Devops admins.

The action requires three secrets.

- The `GH_APP_INSTALLATION_ID` secret is the number found in the URL on [the GitHub Apps installation page for the Islandora-Devops org](https://github.com/organizations/Islandora-Devops/settings/installations) for the `isle-buildkit-renovate` app

- The two other secrets `GH_APP_ID` and `GH_APP_PRIV_KEY` can be found on [the GitHub App settings](https://github.com/organizations/Islandora-Devops/settings/apps/isle-buildkit-renovate)
- The value of `GH_APP_ID` is shown at the top of the page at the above URL
- The value of `GH_APP_PRIV_KEY` is a base64 encoded string of a private key created at the bottom of the page in the above UI (i.e. app settings). Creating a new key will download the key to your local machine. You can then generate the value needed by the GitHub Action by running e.g. `base64 -i ~/Downloads/isle-buildkit-renovate.2025-01-06.private-key.pem` and pasting that value into https://github.com/Islandora-Devops/isle-buildkit/settings/secrets/actions/GH_APP_PRIV_KEY.

> [!IMPORTANT]
> The `GH_APP_PRIV_KEY` value is the only truly secret value out of the three secrets needed by the action. If this value is ever exposed it must be rotated by deleting the existing private key and generating a new key.
##### Running renovate (manually for debugging)

First, generate a GitHub token. Instructions can be found at https://docs.renovatebot.com/modules/platform/github/#running-using-a-fine-grained-token

```
npm install -g renovate
Expand All @@ -555,8 +577,6 @@ export RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS='["bash ci/update-sha.sh \"{{{depN
renovate --platform=github
```

Versions listed in GitHub tags or releases can use [advanced capture](https://docs.renovatebot.com/modules/manager/regex/#advanced-capture) in the Dockerfile to update the pinned version.


#### Updating Composer

Expand Down
64 changes: 64 additions & 0 deletions ci/fetch-app-token.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env bash

set -eou pipefail

if [[ $# -ne 3 ]]; then
echo "Usage: $0 <APP_ID> <INSTALL_ID> <PRIVATE_KEY_FILE_PATH>"
echo "e.g. ./ci/fetch-app-token.sh 123 456 /path/to/priv.pem"
exit 1
fi

APP_ID="$1"
INSTALL_ID="$2"
PRIVATE_KEY_FILE="$3"

if [[ ! -f "$PRIVATE_KEY_FILE" ]]; then
echo "Error: Private key file not found: $PRIVATE_KEY_FILE"
exit 1
fi

b64url_encode() {
base64 -w 0 | tr -d '=' | tr '/+' '_-' | tr -d '\n'
}

JWT_HEADER=$(jq -n \
'{
"alg": "RS256",
"typ": "JWT"
}' | b64url_encode
)

NOW=$(date +%s)
EXPIRATION=$((NOW + 300)) # 5m
JWT_PAYLOAD=$(jq -n \
--argjson iat "$NOW" \
--argjson exp "$EXPIRATION" \
--arg iss "$APP_ID" \
'{
"iat": $iat,
"exp": $exp,
"iss": $iss
}' | b64url_encode
)

JWT_SIGNATURE=$(echo -n "${JWT_HEADER}.${JWT_PAYLOAD}" \
| openssl dgst -sha256 -sign "$PRIVATE_KEY_FILE" \
| b64url_encode
)

JWT="${JWT_HEADER}.${JWT_PAYLOAD}.${JWT_SIGNATURE}"

RESPONSE=$(curl -s -X POST \
"https://api.github.com/app/installations/${INSTALL_ID}/access_tokens" \
-H "Authorization: Bearer $JWT" \
-H "Accept: application/vnd.github+json")

if echo "$RESPONSE" | jq -e '.token' > /dev/null; then
# this token has a TTL of 60m
# see https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app#generating-an-installation-access-token
echo "$RESPONSE" | jq -r '.token'
else
echo "Error:" >&2
echo "$RESPONSE" | jq >&2
exit 1
fi

0 comments on commit e0b4a3d

Please sign in to comment.