From dca233f9f2c158817f436a48268b477eb3a6eecc Mon Sep 17 00:00:00 2001 From: Lumpiasty Date: Thu, 28 May 2026 23:30:34 +0200 Subject: [PATCH] add renovate cronjob --- .woodpecker/renovate.yaml | 79 +++++++++++++++++++++++++++++++++++++++ Dockerfile | 6 ++- README.md | 60 +++++++++++++++++++++++++---- renovate.json | 23 ++++++++++++ 4 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 .woodpecker/renovate.yaml create mode 100644 renovate.json diff --git a/.woodpecker/renovate.yaml b/.woodpecker/renovate.yaml new file mode 100644 index 0000000..bd027a3 --- /dev/null +++ b/.woodpecker/renovate.yaml @@ -0,0 +1,79 @@ +# Self-hosted Renovate, run by Woodpecker on a schedule. +# +# Woodpecker has no native Renovate support, so we run the official +# renovate/renovate image as a one-shot job. The repo-level rules live in +# ./renovate.json; the GLOBAL/self-hosted settings (which platform, which repo, +# the API token) are provided here via environment so renovate.json stays a +# clean, portable repository config. +# +# SETUP (one-time): +# 1. In Gitea, create a bot user (e.g. "renovate") with write access to this +# repo, and generate a personal access token with at least: +# repo (read/write), issue (read/write), pull-request (read/write) +# 2. In Woodpecker repo settings -> Secrets, add a secret: +# name: renovate_token +# value: +# Make sure it is available to the "cron" event. +# 3. In Woodpecker repo settings -> Crons, add a cron: +# name: renovate +# branch: main # branch whose pipeline config is used +# schedule: "@daily" # or e.g. "0 6 * * 1" (Mondays 06:00) +# +# The step below only runs for the "cron" event named "renovate", so normal +# pushes/PRs never trigger Renovate. + +when: + - event: cron + cron: renovate + +skip_clone: true + +steps: + - name: Get renovate token from OpenBao + image: quay.io/openbao/openbao:2.5.4 + environment: + VAULT_ADDR: https://openbao.lumpiasty.xyz:8200 + ROLE_ID: + from_secret: renovate_role_id + SECRET_ID: + from_secret: renovate_secret_id + commands: + - bao write -field token auth/approle/login + role_id=$ROLE_ID + secret_id=$SECRET_ID > /woodpecker/.vault_id + - export VAULT_TOKEN=$(cat /woodpecker/.vault_id) + - bao kv get -mount secret -field RENOVATE_TOKEN renovate > /woodpecker/renovate_token + - bao kv get -mount secret -field GITHUB_COM_TOKEN renovate > /woodpecker/github_com_token + - name: renovate + # Renovate's built-in "woodpecker" manager tracks this image automatically. + image: renovate/renovate:43.194.0 + environment: + # --- platform / target --- + RENOVATE_PLATFORM: gitea + # Gitea API endpoint. Override to match your instance. + RENOVATE_ENDPOINT: https://gitea.lumpiasty.xyz/api/v1 + # Only operate on this repository. + RENOVATE_AUTODISCOVER: "false" + RENOVATE_REPOSITORIES: ${CI_REPO} + # Use the committed renovate.json; don't open an onboarding PR. + RENOVATE_ONBOARDING: "false" + RENOVATE_REQUIRE_CONFIG: "optional" + # Git identity for the branches/commits Renovate creates. + RENOVATE_GIT_AUTHOR: "Renovate Bot " + # GitHub token (read-only, no repo access) lets Renovate fetch release + # notes / changelogs and avoids GitHub API rate limits for the + # github-releases datasource (tailscale). Optional but recommended. + LOG_LEVEL: info + # Load tokens from OpenBao (written to /woodpecker by the first step) and + # run renovate. + commands: + - export RENOVATE_TOKEN=$(cat /woodpecker/renovate_token) + - export GITHUB_COM_TOKEN=$(cat /woodpecker/github_com_token) + - /usr/local/sbin/renovate-entrypoint.sh renovate + - name: Invalidate OpenBao token + image: quay.io/openbao/openbao:2.5.4 + environment: + VAULT_ADDR: https://openbao.lumpiasty.xyz:8200 + commands: + - export VAULT_TOKEN=$(cat /woodpecker/.vault_id) + - bao write -f auth/token/revoke-self diff --git a/Dockerfile b/Dockerfile index 27d6ae9..aa1f041 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,8 +19,9 @@ # ============================================================================= # Stage 1: Build Tailscale combined binary (cross-compiled, runs natively) # ============================================================================= -FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder +FROM --platform=$BUILDPLATFORM golang:1.26-alpine@sha256:91eda9776261207ea25fd06b5b7fed8d397dd2c0a283e77f2ab6e91bfa71079d AS builder +# renovate: datasource=github-releases depName=tailscale packageName=tailscale/tailscale ARG TAILSCALE_VERSION=v1.98.3 # Provided automatically by buildx for the target platform. @@ -137,8 +138,9 @@ RUN upx --lzma --best /out/tailscale.combined # This stage runs on the TARGET platform (no --platform override): gcc then # produces native target-arch binaries directly. Under buildx this is # transparently emulated via binfmt/QEMU for non-native targets. -FROM alpine:3.21 AS busybox +FROM alpine:3.21@sha256:48b0309ca019d89d40f670aa1bc06e426dc0931948452e8491e3d65087abc07d AS busybox +# renovate: datasource=docker depName=busybox versioning=docker ARG BUSYBOX_VERSION=1.37.0 RUN apk add --no-cache build-base linux-headers wget bzip2 perl upx diff --git a/README.md b/README.md index 7c08465..57004a0 100644 --- a/README.md +++ b/README.md @@ -265,21 +265,67 @@ Several measures are in place to avoid wearing out internal flash: ## Upgrading -Update the `TAILSCALE_VERSION` build arg and rebuild the image. The feature -allowlist in the Dockerfile carries forward automatically — any new -`ts_omit_*` tags introduced in the new version will be omitted by default. +Version bumps (Tailscale, busybox, base image digests) are normally proposed +automatically via Renovate — see +[Dependency pinning & automated updates](#dependency-pinning--automated-updates). +Merge the Renovate PR, then rebuild and redeploy. + +The feature allowlist in the Dockerfile carries forward automatically across +Tailscale versions — any new `ts_omit_*` tags introduced in a new release will +be omitted by default. + +To bump manually, edit `ARG TAILSCALE_VERSION` in the `Dockerfile` (so the pin +stays in version control) and rebuild: ```sh -TAG=v1.99.0 ./build.sh --tar # rebuild all arches with the new version -# or, single arch: +./build.sh --tar # rebuild all arches at the pinned version +# or, override at build time without editing the Dockerfile: docker buildx build --platform linux/arm64 \ - --build-arg TAILSCALE_VERSION=v1.99.0 \ - --load -t mikrotik-tailscale:v1.99.0-arm64 . + --build-arg TAILSCALE_VERSION=v1.100.0 \ + --load -t mikrotik-tailscale:arm64 . +``` + +## Dependency pinning & automated updates + +All upstream dependencies are version-pinned for reproducible builds: + +| Dependency | Where | Pinned form | +|---|---|---| +| Go toolchain | `Dockerfile` `FROM golang:…` | tag + `@sha256` digest | +| Alpine (busybox build base) | `Dockerfile` `FROM alpine:…` | tag + `@sha256` digest | +| Tailscale | `Dockerfile` `ARG TAILSCALE_VERSION` | git release tag | +| busybox | `Dockerfile` `ARG BUSYBOX_VERSION` | release version | +| Renovate runner | `.woodpecker/renovate.yaml` `image:` | tag | + +Updates are proposed automatically by [Renovate](https://docs.renovatebot.com/), +run **self-hosted** from a Woodpecker cron pipeline (Woodpecker has no native +Renovate support): + +- `renovate.json` — repository rules. All dependencies follow the latest + upstream releases (including major versions); each bump arrives as its own PR + that the multi-arch build validates before you merge. Base image tags also + get their `@sha256` digests refreshed via `pinDigests`. The one special rule: + - `tailscale` only follows **stable** releases — Tailscale uses even minor + versions for stable (`v1.98.x`) and odd for unstable (`v1.99.x`), so the + rule filters to even minors. +- `.woodpecker/renovate.yaml` — the scheduled job that runs `renovate/renovate` + against this repo. + +```sh +# Renovate repo config +docker run --rm -e RENOVATE_CONFIG_TYPE=repo -v "$PWD":/work -w /work \ + --entrypoint renovate-config-validator renovate/renovate + +# Woodpecker pipeline +docker run --rm -v "$PWD":/work -w /work \ + woodpeckerci/woodpecker-cli:v3 lint .woodpecker/renovate.yaml ``` ## References - [Tailscale: Smaller binaries for embedded devices](https://tailscale.com/docs/how-to/set-up-small-tailscale) +- [Renovate self-hosting](https://docs.renovatebot.com/getting-started/running/) +- [Woodpecker cron jobs](https://woodpecker-ci.org/docs/usage/cron) - [MikroTik Container documentation](https://help.mikrotik.com/docs/display/ROS/Container) - [Tailscale subnet routers](https://tailscale.com/kb/1019/subnets) - [Tailscale exit nodes](https://tailscale.com/kb/1103/exit-nodes) diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..a98185e --- /dev/null +++ b/renovate.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended", + ":dependencyDashboard", + ":semanticCommits" + ], + "labels": ["dependencies"], + "rebaseWhen": "behind-base-branch", + "dockerfile": { + "pinDigests": true + }, + "packageRules": [ + { + "matchDatasources": ["github-releases"], + "matchPackageNames": ["tailscale/tailscale"], + "description": "TAILSCALE_VERSION ARG: only stable releases. Tailscale uses EVEN minor versions for stable (v1.98.x); ODD minors (v1.99.x) are unstable, so filter to even minors and ignore pre-releases.", + "extractVersion": "^v(?\\d+\\.\\d+\\.\\d+)$", + "allowedVersions": "/^\\d+\\.\\d*[02468]\\.\\d+$/", + "ignoreUnstable": true + } + ] +}