build: Central Package Management + scheduled vulnerability scan (#14) #17

Merged
timothy merged 2 commits from foundations/14-central-package-management into main 2026-06-27 01:20:55 +02:00
Owner

Refs #14 (issue closed via the Task Completion Protocol once the main image build + smoke is verified green).

Central Package Management

  • Adds Directory.Packages.props (ManagePackageVersionsCentrally=true) and strips the Version= attribute from every <PackageReference> across the 14 solution projects + Directory.Build.targets.
  • No version changes. Survey found 154 PackageReference elements → 96 distinct packages with zero version conflicts (every package already pinned identically everywhere), so this is a pure relocation. Range/lock/prerelease syntaxes preserved exactly (MediatR [12.5.0], EF Core [9.0.12,10), Lucene.Net 4.8.0-beta00017, …).
  • Dockerfile: Directory.Packages.props is now copied into the image build before dotnet restore — without it the versionless csproj fail restore (NU1015). Verified by simulating the image's linux-x64 restore layer, plus a negative test reproducing the failure.

Scheduled vulnerability scan

  • New .gitea/workflows/dependency-scan.yml: weekly cron + workflow_dispatch, runs dotnet list package --vulnerable --include-transitive over the full solution and fails the run when advisories are present (the command exits 0 even with findings, so the marker line is parsed; bash -euo pipefail so a failing dotnet list can't false-green).
  • Separate workflow file (not a job in docker-build.yml) because it's cron-triggered and shouldn't share the build pipeline's triggers/concurrency.
  • Expected RED until #8 clears the current NCalcSync/SQLitePCLRaw advisories — after that, red = a new advisory.

Out of scope / related

  • Renovate (real Dependabot replacement, multi-repo, opens update PRs) filed as infra: server-management#484.
  • .mcp/ (gitignored vendored tool) gets a local-only CPM opt-out — not in this PR.

Verification

  • dotnet restore + dotnet build -c Release → 0 errors (only the expected #8 advisory warnings).
  • Image restore-layer simulation under linux-x64 → green; negative test (no manifest) → NU1015 as expected.
  • Reproduced the CI test-job Scanner-strip path under CPM → 0 errors.
  • Adversarial self-review of the full diff → SHIP (no version drift; one workflow nit fixed).
  • PR test job (run #132) → green.

PR runs the test job only; full image build + smoke runs on merge to main.

Refs #14 (issue closed via the Task Completion Protocol once the `main` image build + smoke is verified green). ## Central Package Management - Adds `Directory.Packages.props` (`ManagePackageVersionsCentrally=true`) and strips the `Version=` attribute from every `<PackageReference>` across the 14 solution projects + `Directory.Build.targets`. - **No version changes.** Survey found 154 PackageReference elements → **96 distinct packages with zero version conflicts** (every package already pinned identically everywhere), so this is a pure relocation. Range/lock/prerelease syntaxes preserved exactly (`MediatR [12.5.0]`, EF Core `[9.0.12,10)`, `Lucene.Net 4.8.0-beta00017`, …). - **Dockerfile:** `Directory.Packages.props` is now copied into the image build before `dotnet restore` — without it the versionless csproj fail restore (`NU1015`). Verified by simulating the image's `linux-x64` restore layer, plus a negative test reproducing the failure. ## Scheduled vulnerability scan - New `.gitea/workflows/dependency-scan.yml`: weekly cron + `workflow_dispatch`, runs `dotnet list package --vulnerable --include-transitive` over the **full** solution and fails the run when advisories are present (the command exits 0 even with findings, so the marker line is parsed; `bash -euo pipefail` so a failing `dotnet list` can't false-green). - Separate workflow file (not a job in `docker-build.yml`) because it's cron-triggered and shouldn't share the build pipeline's triggers/concurrency. - **Expected RED until #8** clears the current NCalcSync/SQLitePCLRaw advisories — after that, red = a new advisory. ## Out of scope / related - Renovate (real Dependabot replacement, multi-repo, opens update PRs) filed as infra: **server-management#484**. - `.mcp/` (gitignored vendored tool) gets a local-only CPM opt-out — not in this PR. ## Verification - `dotnet restore` + `dotnet build -c Release` → 0 errors (only the expected #8 advisory warnings). - Image restore-layer simulation under `linux-x64` → green; negative test (no manifest) → NU1015 as expected. - Reproduced the CI `test`-job Scanner-strip path under CPM → 0 errors. - Adversarial self-review of the full diff → **SHIP** (no version drift; one workflow nit fixed). - PR `test` job (run #132) → **green**. PR runs the `test` job only; full image build + smoke runs on merge to `main`.
timothy added 2 commits 2026-06-27 01:16:34 +02:00
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 <noreply@anthropic.com>
ci: add scheduled NuGet vulnerability scan
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 2m7s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 2m14s
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 5m16s
2fa79edfdc
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 <noreply@anthropic.com>
timothy merged commit 2fa79edfdc into main 2026-06-27 01:20:55 +02:00
timothy deleted branch foundations/14-central-package-management 2026-06-27 01:20:55 +02:00
Sign in to join this conversation.