From b41ea1ce96105891add1f43390ccd87609f14215 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Wed, 16 Sep 2026 17:54:19 +0300 Subject: [PATCH] Restore Renovate runner and test runtime before upgrades --- .github/renovate.json | 1 + .github/workflows/renovate-smoke-test.yml | 36 +++-------- .github/workflows/renovate.yml | 4 +- bin/renovate-smoke-test.sh | 74 +++++++++++++++++++++++ docs/README.md | 4 +- docs/renovate.md | 25 ++++++++ 6 files changed, 114 insertions(+), 30 deletions(-) create mode 100755 bin/renovate-smoke-test.sh create mode 100644 docs/renovate.md diff --git a/.github/renovate.json b/.github/renovate.json index dcc8e86ab..9ebaea40a 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -106,6 +106,7 @@ "matchDepNames": [ "matrix-renovate-runner" ], + "allowedVersions": "!/^44\\.64\\.0$/", "automerge": true, "automergeType": "branch" }, diff --git a/.github/workflows/renovate-smoke-test.yml b/.github/workflows/renovate-smoke-test.yml index b2b0945d0..e16ca9be4 100644 --- a/.github/workflows/renovate-smoke-test.yml +++ b/.github/workflows/renovate-smoke-test.yml @@ -11,11 +11,13 @@ on: # yamllint disable-line rule:truthy - '.github/renovate.json' - '.github/workflows/renovate-smoke-test.yml' - '.github/workflows/renovate.yml' + - 'bin/renovate-smoke-test.sh' pull_request: paths: - '.github/renovate.json' - '.github/workflows/renovate-smoke-test.yml' - '.github/workflows/renovate.yml' + - 'bin/renovate-smoke-test.sh' workflow_dispatch: permissions: @@ -23,8 +25,9 @@ permissions: jobs: validate: - name: Validate config with the pinned Renovate image + name: Validate config and runtime with the pinned Renovate image runs-on: ubuntu-latest + timeout-minutes: 10 # Same-repository pull requests already run via the push event; # run pull_request jobs only for pull requests from forks. @@ -34,32 +37,9 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false - - name: Resolve the pinned Renovate version - id: renovate_version + - name: Validate configuration and extract repository dependencies shell: bash - run: | - set -euo pipefail - - mapfile -t versions < <( - sed -n "s/^ MATRIX_RENOVATE_VERSION: '\([^']*\)'$/\1/p" \ - .github/workflows/renovate.yml - ) - - if (( ${#versions[@]} != 1 )) || [[ -z "${versions[0]}" ]]; then - echo 'Could not resolve exactly one pinned Renovate version' >&2 - exit 1 - fi - - echo "version=${versions[0]}" >> "$GITHUB_OUTPUT" - - - name: Validate the Renovate configuration - env: - RENOVATE_VERSION: ${{ steps.renovate_version.outputs.version }} - run: | - docker run --rm \ - --volume "$GITHUB_WORKSPACE:/workspace:ro" \ - --workdir /workspace \ - --entrypoint renovate-config-validator \ - "ghcr.io/renovatebot/renovate:$RENOVATE_VERSION" \ - --strict + run: bin/renovate-smoke-test.sh diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index 8b521ef80..5ae699edf 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -43,7 +43,7 @@ env: MATRIX_RENOVATE_AUTOMATION_ENABLED: 'true' # renovate: datasource=docker depName=matrix-renovate-runner packageName=ghcr.io/renovatebot/renovate - MATRIX_RENOVATE_VERSION: '44.64.0' + MATRIX_RENOVATE_VERSION: '44.61.6' jobs: preflight: @@ -146,6 +146,8 @@ jobs: renovate-version: ${{ env.MATRIX_RENOVATE_VERSION }} env: LOG_LEVEL: ${{ inputs.log_level || 'info' }} + # Renovate's rejection handler can log a startup crash and still exit 0. + NODE_OPTIONS: --unhandled-rejections=strict RENOVATE_DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run && 'full' || '' }} # Permit the self-hosted App to adopt branches created by the Mend-hosted App. RENOVATE_GIT_IGNORED_AUTHORS: '["29139614+renovate[bot]@users.noreply.github.com"]' diff --git a/bin/renovate-smoke-test.sh b/bin/renovate-smoke-test.sh new file mode 100755 index 000000000..6fe4bbb64 --- /dev/null +++ b/bin/renovate-smoke-test.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: 2026 Slavi Pantaleev +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +set -euo pipefail + +repo_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" + +# An optional image version lets maintainers reproduce failures before changing the pin. +mapfile -t versions < <( + sed -n "s/^ MATRIX_RENOVATE_VERSION: '\([^']*\)'$/\1/p" \ + "$repo_dir/.github/workflows/renovate.yml" +) +if (( ${#versions[@]} != 1 )) || [[ -z "${versions[0]}" ]]; then + echo 'Could not resolve exactly one pinned Renovate version' >&2 + exit 1 +fi +version="${1:-${versions[0]}}" +image="ghcr.io/renovatebot/renovate:$version" +log_file="$(mktemp)" +trap 'rm -f -- "$log_file"' EXIT + +# Use the image's normal entrypoint for extraction, loading the real runtime. +# No credentials or network are needed for validation and dependency extraction. +docker_args=( + --rm + --network none + --volume "$repo_dir:/workspace:ro" + --workdir /workspace + --env NODE_OPTIONS=--unhandled-rejections=strict +) + +echo "Validating configuration with $image" +docker run "${docker_args[@]}" \ + --entrypoint renovate-config-validator \ + "$image" --strict + +echo "Extracting dependencies with $image" +docker run "${docker_args[@]}" \ + --env LOG_LEVEL=info \ + --env LOG_FORMAT=json \ + "$image" --platform=local --dry-run=extract \ + | tee "$log_file" + +# Exit status alone is insufficient: 44.64.0 crashed at startup but exited 0. +# Require completion and useful results from every manager used by this repository. +# The missing-token warning is expected: extraction needs no GitHub API access. +if ! jq --slurp --exit-status ' + all(.[]; .level < 50) + and any(.[]; .msg == "Repository finished" and .repository == "local") + and any(.[]; + .msg == "Dependency extraction complete" + and (.stats.managers as $managers + | all(["ansible-galaxy", "dockerfile", "github-actions", "mise", "nix", "pip_requirements", "pre-commit", "regex"][]; + $managers[.].depCount > 0)) + ) + and any(.[]; + .msg == "Extracted dependencies" + and any(.packageFiles["ansible-galaxy"][]?; + .packageFile == "requirements.yml" and (.deps | length) > 0) + and any(.packageFiles.regex[]?; + (.packageFile | startswith("roles/custom/")) and (.deps | length) > 0) + and any(.packageFiles.regex[]?; + .packageFile == "molecule-shared/vars.yml" and (.deps | length) > 0) + and any(.packageFiles.regex[]?.deps[]?; + .depName == "matrix-renovate-runner" and .datasource == "docker") + ) +' "$log_file"; then + echo 'Renovate did not complete dependency extraction successfully' >&2 + exit 1 +fi + +echo "Renovate $version passed configuration validation and dependency extraction" diff --git a/docs/README.md b/docs/README.md index d3aabd2dc..ad51d38f3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,5 @@ + +# Maintaining the Renovate runner + +The self-hosted runner version is pinned in [`.github/workflows/renovate.yml`](../.github/workflows/renovate.yml). Renovate updates this pin and automerges passing updates according to [`.github/renovate.json`](../.github/renovate.json). + +The `Renovate smoke test` workflow tests the candidate image on branch pushes and fork pull requests. It validates configuration and starts the real Renovate runtime to extract dependencies from the checked-out repository. It requires results from all eight managers currently used here, including the custom managers that update role versions, Molecule helper images, and Renovate itself, and rejects errors or missing completion logs. The containers have no network access, receive no credentials, and mount the checkout read-only. + +Run the same check locally with Docker, Bash, and jq installed: + +```sh +bin/renovate-smoke-test.sh +# Reproduce the broken image without changing the workflow pin: +bin/renovate-smoke-test.sh 44.64.0 +``` + +Version `44.64.0` is deliberately excluded from runner updates: its APK datasource imports `tar`, which was only declared as a development dependency and is missing from the production image. It passed configuration validation and `--version`, then crashed at startup with exit code 0 ([incident log](https://github.com/spantaleev/matrix-docker-ansible-deploy/actions/runs/35090923781/job/104776805727)). The runner was reverted to `44.61.6`. Both production and the smoke test set `NODE_OPTIONS=--unhandled-rejections=strict` so unhandled startup failures return a failing exit code. + +Upstream corrected the packaging in [Renovate PR #45699](https://github.com/renovatebot/renovate/pull/45699). A runner that crashes before processing the repository cannot discover its own replacement, so recovery requires manually changing the pin to a working version. + +This smoke test would have blocked that upgrade. It does not exercise registry lookups, GitHub authentication, or branch/PR writes. For live integration checks, manually dispatch the `Renovate` workflow on `master` with `dry_run` enabled and `log_level` set to `debug`. That tests the pin already on `master`; it is not a pre-merge test of a candidate branch. Check the smoke-test result when manually merging runner upgrades too.