Build ErsatzTV Image / CI toolchain image resolves (push) Successful in 7s
Build ErsatzTV Image / Delimiter ban (release path) (push) Successful in 25s
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 8m41s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 6m21s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (push) Successful in 5m58s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Skipped
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Skipped
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 4m8s
Closes #786 and #789, bundled because working either alone would build the artifact the other removes. Every job in all six tracked workflows declares `env.CI_JOB_ROLE` (guard/report-only/none); the `docker-build.yml` jobs also declare `env.CI_EXECUTION_CLASS` (toolchain/bare-runner). Both guard populations derive from those markers; the `TOOLCHAIN_JOBS`/`BARE_RUNNER_JOBS` literals are deleted. A missing or unrecognised marker is a hard failure in both checkers. #789's literal had a real justification — set equality between two DERIVED sets is blind to a member leaving both at once — so the marker is the anchor that replaces it, and the cost (proximity to the `container:` block) is paid by a THIRD derivation from each job's own steps, which is also the only check that sees the failure #789 filed: a .NET step moved into a bare-runner job, where no set changes. The residual is disclosed: drop the block, flip the marker AND hide the tool behind a script and all three go blind, bounded by the failure mode being a loud missing-binary crash. #786's guard jobs join a machine-checked population: a new `test_workflow_job_guards.py` asserts set equality both ways against a new "Workflow-job guards" table, and the four jobs with no dropped-step guard each carry a recorded decision. Two issue claims were refuted by measurement: #789's "editing docker-build.yml re-points the pin" (the pathspec is `docker/ci` only) and #786's job count (17, not 15). Four cold adversarial review rounds across two model families; rounds 1-3 BLOCKED, all findings fixed and each fix demonstrated by reproducing the reviewer's own test. The recurring defect class was prose drifting from code, including a mechanism claim in the decision record that execution refuted. All five mutation proofs redden when their shipped detector is disarmed. New decision record: `testing.workflow-declares-its-own-job-metadata`. Co-authored-by: Timothy <timothy@noreply.gitea.tblindustries.be>
85 lines
3.8 KiB
YAML
85 lines
3.8 KiB
YAML
name: Renovate
|
|
|
|
# Self-hosted Renovate for the ErsatzTV fork (server-management#484).
|
|
#
|
|
# Opens dependency-update PRs against this repo (managers: nuget via CPM, github-actions).
|
|
# Runs on the shared Gitea act_runner (bumblebee). It supersedes the *proposing* half that
|
|
# the dependency-scan.yml (ersatztv#14) deliberately left out — that scan stays as a cheap
|
|
# in-repo detector for now.
|
|
#
|
|
# Config: repo-root renovate.json (package rules, grouping, automerge policy).
|
|
# Bot identity + tokens are injected from repo Actions secrets:
|
|
# RENOVATE_TOKEN — PAT of the dedicated `renovate` Gitea bot (write:repository,
|
|
# read:user, write:issue, read:organization)
|
|
# GH_COM_TOKEN — no-scope github.com PAT for changelog/release-note fetching
|
|
# (Renovate needs this on non-GitHub platforms; optional, degrades
|
|
# gracefully to anonymous if unset). Named GH_, not GITHUB_, because
|
|
# Gitea reserves the GITHUB_ secret-name prefix.
|
|
#
|
|
# NOTE: Gitea runs `schedule` triggers ONLY from the default branch (main); this file must
|
|
# be on main before the cron registers. Use workflow_dispatch to run on demand — it defaults
|
|
# to a DRY RUN (logs only, no PRs); dispatch with "Dry run" cleared to create real PRs.
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
dryRun:
|
|
description: 'Dry run (full = log only, no PRs; clear for a live run)'
|
|
type: choice
|
|
options:
|
|
- 'full'
|
|
- ''
|
|
default: 'full'
|
|
logLevel:
|
|
description: 'Log level'
|
|
type: choice
|
|
options:
|
|
- 'info'
|
|
- 'debug'
|
|
default: 'info'
|
|
schedule:
|
|
# Mondays 03:00 UTC — ahead of the 06:00 vulnerability scan
|
|
- cron: '0 3 * * 1'
|
|
|
|
concurrency:
|
|
group: ersatztv-renovate
|
|
cancel-in-progress: false
|
|
|
|
# Explicit token scope (ersatztv#748) so the owner-level Actions default can move to Restricted
|
|
# (server-management#714). Declaring `permissions:` is EXHAUSTIVE, not additive: a unit omitted here
|
|
# is NOT granted, and that holds at any owner default — it is not conditional on Restricted being on.
|
|
# Only `review-verdict.yml` needs write; it declares that at the job and says why there. Full
|
|
# rationale and the per-workflow credential audit: docs/ci-cd.md -> "Workflow token scope".
|
|
# This workflow has no checkout step and never uses the injected GITEA_TOKEN for anything. Renovate's
|
|
# own branch/PR writes go through RENOVATE_TOKEN, a dedicated bot PAT the Actions default does not
|
|
# govern, and its container image comes from Docker Hub. Read-only is declared to STATE that the
|
|
# injected token is unused, not because any step needs it.
|
|
permissions:
|
|
code: read
|
|
|
|
jobs:
|
|
renovate:
|
|
name: Renovate
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: renovate/renovate:43
|
|
env:
|
|
CI_JOB_ROLE: none
|
|
steps:
|
|
- name: Run Renovate
|
|
env:
|
|
RENOVATE_PLATFORM: gitea
|
|
RENOVATE_ENDPOINT: http://192.168.1.95:3000/api/v1
|
|
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
|
|
RENOVATE_GITHUB_COM_TOKEN: ${{ secrets.GH_COM_TOKEN }}
|
|
RENOVATE_REPOSITORIES: timothy/ersatztv
|
|
RENOVATE_AUTODISCOVER: 'false'
|
|
RENOVATE_GIT_AUTHOR: 'Renovate Bot <renovate@tblindustries.be>'
|
|
# Let the dockerfile manager query our HTTP-only Gitea container registry for the
|
|
# ersatztv-ffmpeg base image. Creds (reused from the image-push secrets) + insecureRegistry
|
|
# live here, NOT in renovate.json, so they stay out of the committed config.
|
|
RENOVATE_HOST_RULES: '[{"matchHost":"192.168.1.95:3000","hostType":"docker","username":"${{ secrets.REGISTRY_USER }}","password":"${{ secrets.REGISTRY_PASSWORD }}","insecureRegistry":true}]'
|
|
RENOVATE_DRY_RUN: ${{ inputs.dryRun }}
|
|
LOG_LEVEL: ${{ inputs.logLevel || 'info' }}
|
|
run: renovate
|