From 77a28fcefc7918119569fd31d6ecc86e2c1979cc Mon Sep 17 00:00:00 2001 From: Timothy Date: Sat, 27 Jun 2026 01:07:52 +0200 Subject: [PATCH 1/2] build: adopt Central Package Management (Directory.Packages.props) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move all 154 PackageReference versions (96 distinct packages) out of the 14 project files into a single central Directory.Packages.props with ManagePackageVersionsCentrally=true. No version changes — every package was already pinned identically across projects (no conflicts detected), so this is a pure relocation: updates become one-line and cross-project version drift is structurally impossible. Also copy Directory.Packages.props into the Docker image build before restore: with CPM the csproj carry no versions, so the image's `dotnet restore` fails without the central manifest (verified: NU1015 across every project). Restore + Release build verified locally, plus a simulation of the image's restore layer under linux-x64 (0 errors; only the pre-existing NCalcSync/SQLitePCLRaw advisories remain, demoted to warnings, tracked in #8). Part of #14. Co-Authored-By: Claude Opus 4.8 --- Directory.Build.targets | 1 - Directory.Packages.props | 104 ++++++++++++++++++ .../ErsatzTV.Application.csproj | 18 +-- .../ErsatzTV.Core.Tests.csproj | 32 +++--- ErsatzTV.Core/ErsatzTV.Core.csproj | 42 +++---- .../ErsatzTV.FFmpeg.Tests.csproj | 16 +-- ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj | 12 +- .../ErsatzTV.Infrastructure.MySql.csproj | 6 +- .../ErsatzTV.Infrastructure.Sqlite.csproj | 8 +- .../ErsatzTV.Infrastructure.Tests.csproj | 16 +-- .../ErsatzTV.Infrastructure.csproj | 48 ++++---- .../ErsatzTV.Scanner.Tests.csproj | 18 +-- ErsatzTV.Scanner/ErsatzTV.Scanner.csproj | 30 ++--- ErsatzTV.Tests/ErsatzTV.Tests.csproj | 8 +- ErsatzTV/ErsatzTV.csproj | 52 ++++----- docker/Dockerfile | 8 +- 16 files changed, 262 insertions(+), 157 deletions(-) create mode 100644 Directory.Packages.props diff --git a/Directory.Build.targets b/Directory.Build.targets index 2e906ed8e..bb539cbf2 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -6,7 +6,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 000000000..a3750c7fd --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,104 @@ + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ErsatzTV.Application/ErsatzTV.Application.csproj b/ErsatzTV.Application/ErsatzTV.Application.csproj index df10c6035..8d4a2baeb 100644 --- a/ErsatzTV.Application/ErsatzTV.Application.csproj +++ b/ErsatzTV.Application/ErsatzTV.Application.csproj @@ -10,15 +10,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj index 87a7309a0..ac3a24095 100644 --- a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj +++ b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj @@ -7,22 +7,22 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/ErsatzTV.Core/ErsatzTV.Core.csproj b/ErsatzTV.Core/ErsatzTV.Core.csproj index 342e03ab3..d89b45f03 100644 --- a/ErsatzTV.Core/ErsatzTV.Core.csproj +++ b/ErsatzTV.Core/ErsatzTV.Core.csproj @@ -10,27 +10,27 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj b/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj index edb5e6a38..b0481bd77 100644 --- a/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj +++ b/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj @@ -8,14 +8,14 @@ - - - - - - - - + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj b/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj index 068391dc3..ae249a3d3 100644 --- a/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj +++ b/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj @@ -11,12 +11,12 @@ - - - - - - + + + + + + diff --git a/ErsatzTV.Infrastructure.MySql/ErsatzTV.Infrastructure.MySql.csproj b/ErsatzTV.Infrastructure.MySql/ErsatzTV.Infrastructure.MySql.csproj index 723beea5d..352dcf8c0 100644 --- a/ErsatzTV.Infrastructure.MySql/ErsatzTV.Infrastructure.MySql.csproj +++ b/ErsatzTV.Infrastructure.MySql/ErsatzTV.Infrastructure.MySql.csproj @@ -16,9 +16,9 @@ - - - + + + diff --git a/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj b/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj index 37a4476e2..d1cabae48 100644 --- a/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj +++ b/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj @@ -12,10 +12,10 @@ - - - - + + + + diff --git a/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj b/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj index 6e9575e54..a7d6125c7 100644 --- a/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj +++ b/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj @@ -9,20 +9,20 @@ - - - - - + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + diff --git a/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj b/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj index eead7978f..1613bf6fd 100644 --- a/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj +++ b/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj @@ -12,33 +12,33 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - + + + + + + + + + + + diff --git a/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj b/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj index 2ceee7724..ceb7fe688 100644 --- a/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj +++ b/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj @@ -9,21 +9,21 @@ - - - - - - + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + diff --git a/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj b/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj index 626120a71..677e3e8d8 100644 --- a/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj +++ b/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj @@ -21,21 +21,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/ErsatzTV.Tests/ErsatzTV.Tests.csproj b/ErsatzTV.Tests/ErsatzTV.Tests.csproj index abe870896..5581d1eaf 100644 --- a/ErsatzTV.Tests/ErsatzTV.Tests.csproj +++ b/ErsatzTV.Tests/ErsatzTV.Tests.csproj @@ -11,13 +11,13 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/ErsatzTV/ErsatzTV.csproj b/ErsatzTV/ErsatzTV.csproj index 68c9683da..853503151 100644 --- a/ErsatzTV/ErsatzTV.csproj +++ b/ErsatzTV/ErsatzTV.csproj @@ -29,38 +29,38 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - + + + + + + + + diff --git a/docker/Dockerfile b/docker/Dockerfile index a311ed4a3..f468b1703 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -25,9 +25,11 @@ COPY scripts/scripted-schedules/. /app/scripted-schedules/ # copy csproj and restore as distinct layers COPY *.sln . # repo-wide build config (MSBuild props/targets incl. NuGet-audit warning -# exemptions, SDK pin, analyzer severities) must be present before restore so the -# image build matches local/CI builds -COPY Directory.Build.props Directory.Build.targets global.json .editorconfig ./ +# exemptions, SDK pin, analyzer severities, and the Central Package Management +# version manifest) must be present before restore so the image build matches +# local/CI builds. Directory.Packages.props is REQUIRED here: with CPM the csproj +# carry no versions, so restore fails without the central manifest. +COPY Directory.Build.props Directory.Build.targets Directory.Packages.props global.json .editorconfig ./ COPY artwork/* ./artwork/ COPY ErsatzTV/*.csproj ./ErsatzTV/ COPY ErsatzTV.Application/*.csproj ./ErsatzTV.Application/ -- 2.47.3 From 2fa79edfdc94fa15d5fc8b4c7ac1c0d46d8f0ae2 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sat, 27 Jun 2026 01:07:52 +0200 Subject: [PATCH 2/2] ci: add scheduled NuGet vulnerability scan A Gitea-native stand-in for Dependabot (#14): a weekly (cron) + workflow_dispatch job running `dotnet list package --vulnerable --include-transitive` over the full solution, failing the run when advisories are present (the command itself exits 0, so the marker line is parsed). Detection only; automated update PRs are tracked in server-management#484 (self-hosted Renovate). Expect RED until #8 clears the current NCalcSync/SQLitePCLRaw advisories; after that a red run signals a NEW advisory. Part of #14. Co-Authored-By: Claude Opus 4.8 --- .gitea/workflows/dependency-scan.yml | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .gitea/workflows/dependency-scan.yml diff --git a/.gitea/workflows/dependency-scan.yml b/.gitea/workflows/dependency-scan.yml new file mode 100644 index 000000000..c2c68ab29 --- /dev/null +++ b/.gitea/workflows/dependency-scan.yml @@ -0,0 +1,58 @@ +name: Dependency vulnerability scan + +# Scheduled NuGet advisory scan — a Gitea-native stand-in for Dependabot (ersatztv#14). +# Surfaces vulnerable direct/transitive packages on a schedule instead of only when a +# `dotnet restore` happens to break. This is DETECTION ONLY; automated update PRs are +# tracked separately (self-hosted Renovate — server-management#484). +# +# Scans the FULL solution (including the Scanner project, which the image build strips) +# so coverage isn't narrower than the code we ship. +# +# NOTE: Gitea runs `schedule` triggers only from the default branch (main); the workflow +# must be merged to main before the cron registers. Use `workflow_dispatch` to run on demand. + +on: + workflow_dispatch: + schedule: + # Mondays 06:00 UTC + - cron: '0 6 * * 1' + +# Independent of the build pipeline's concurrency group; a stale scan can be cancelled. +concurrency: + group: ersatztv-depscan + cancel-in-progress: true + +jobs: + scan: + name: NuGet vulnerable packages + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + + - name: Restore + run: dotnet restore ErsatzTV.sln + + - name: Scan for vulnerable packages (direct + transitive) + # bash + `set -euo pipefail` so a failing `dotnet list` (e.g. the audit source + # is unreachable while restore served from cache) fails the job instead of + # falling through to a false "no vulnerable packages" green. + shell: bash + run: | + set -euo pipefail + echo "Running: dotnet list package --vulnerable --include-transitive" + dotnet list ErsatzTV.sln package --vulnerable --include-transitive 2>&1 | tee depscan.txt + # `dotnet list package --vulnerable` exits 0 even when advisories exist, so detect + # findings by the report marker and fail the run if any are present. Expect this to + # be RED until ersatztv#8 clears the current NCalcSync / SQLitePCLRaw advisories; + # after that, a red run means a NEW advisory has appeared. + if grep -q "has the following vulnerable packages" depscan.txt; then + echo "::error::Vulnerable NuGet packages detected — see report above (tracked: ersatztv#8)." + exit 1 + fi + echo "No vulnerable packages found." -- 2.47.3