NCalcSync 5.11.0 -> 6.3.2 clears CVE-2026-55254 / GHSA-3w5p-95mh-gq75 (the
factorial-DoS advisory on NCalc.Core/NCalcSync). NCalc 6 split its assemblies and
renamed the custom-function API, so port OpacityExpressionHelper:
FunctionArgs -> FunctionEventArgs, and args.Parameters[i].Evaluate() ->
args.Parameters.Evaluate(i) (FunctionData.Count / Evaluate(index)). Add a
regression test covering the migrated opacity wiring (the feature had no tests).
NCalc 6 transitively requires Microsoft.Extensions.Logging.Abstractions >= 10.0.7,
so bump the centrally-pinned Microsoft.Extensions.* family 10.0.2 -> 10.0.7 to
avoid the NU1605 downgrade error (a .NET 10 servicing patch bump).
SQLitePCLRaw: EF Core 9's Sqlite provider pulls the vulnerable bundle 2.1.10
(GHSA-2m69-gcr7-jv3q, outdated bundled SQLite). Directly pin
SQLitePCLRaw.bundle_e_sqlite3 3.0.3 in Infrastructure.Sqlite to override the
transitive version with the patched native (lib.e_sqlite3 3.50.3); core 3.0.3
satisfies Microsoft.Data.Sqlite's >= 2.1.10 requirement under EF Core 9.
Verified: `dotnet list package --vulnerable --include-transitive` reports 0
vulnerable projects; restore + Release build clean; full test suite green under
UTC. (2 pre-existing PlayoutModeSchedulerBase filler tests fail only under
non-UTC local timezones, unrelated to these deps; they pass in CI.)
Refs #8
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Renovate is now live (PR #18/#19): self-hosted weekly Gitea Actions job that
opens dependency-update + OSV vuln-fix PRs and a Dependency Dashboard, with
patch-level auto-merge scoped to test/dev-only packages. Document it under
docs/ci-cd.md → Dependency management, plus a CLAUDE.md conventions pointer.
refs server-management#484
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two follow-ups to the initial Renovate setup (merged in PR #18):
- Gitea reserves the GITHUB_ secret-name prefix (same as GitHub Actions), so the
GITHUB_COM_TOKEN secret was rejected (HTTP 400). Rename to GH_COM_TOKEN and map
it to RENOVATE_GITHUB_COM_TOKEN in the workflow.
- Pin renovate/renovate:43 (current major; 41 was already stale — latest is 43.x).
refs server-management#484
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stand up Renovate for this repo via a scheduled Gitea Actions workflow on the
shared act_runner. Managers: nuget (Central Package Management) + github-actions.
Dockerfile/docker-compose managers deferred until the HTTP Gitea-registry
handling is verified.
- renovate.json: config:recommended, dependency dashboard, OSV vulnerability
alerts, family grouping (Microsoft.Extensions/AspNetCore/EF Core/Serilog/
Refit/Lucene.Net), and patch-level auto-merge scoped to test/dev-only packages
(NUnit/NSubstitute/Shouldly/coverlet/Test.Sdk/Testably/threading analyzer).
- .gitea/workflows/renovate.yml: weekly cron + workflow_dispatch (defaults to a
safe dry run); bot identity + tokens from repo Actions secrets.
Supersedes the *proposing* half that dependency-scan.yml (ersatztv#14) left out;
the scan stays as a cheap in-repo detector for now.
refs server-management#484
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- ci-cd.md: new "Dependency management" section (CPM, NuGet audit, scheduled
dependency-scan.yml); Dockerfile notes now list Directory.Packages.props and
why it's required before restore.
- CLAUDE.md: dependency convention (edit central Directory.Packages.props, never
re-add Version=); correct the test framework note (NUnit, not xUnit).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>
Re-trigger: Gitea dropped the run records for the prior push/tag of this
same tree (runner online, workflow active, but no ActionRun created).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Document upstream's vYY.<release-seq>.<patch> scheme (year, sequential
release-in-year, patch) in docs/ci-cd.md + CLAUDE.md so we follow it going
forward: <release-seq> is NOT the calendar month (v25.2.0 shipped in June,
v26.3.0 in Feb), it's a per-year counter that resets each January. v26.3.1
= our infra-only rebuild of upstream 26.3.0; v26.4.0 reserved for the first
release with app changes. Also notes the [skip ci]-on-a-tagged-commit gotcha.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add concurrency group so the single jazz runner can't run the
push-main-then-push-tag release flow in parallel (shared :buildcache
+ smoke container would collide).
- Add pull_request trigger running the test job only (PRs had no gate);
skip the build job on PRs.
- Only push images from main or a v* tag (workflow_dispatch from other
refs now builds without publishing, instead of clobbering :latest/:prod).
- Replace the log-grep smoke check with a real HTTP readiness probe
(docker exec python3 -> http://localhost:8409/), unique container name,
and trap-based cleanup to avoid leaks on cancel.
- dotnet test now runs -c Release --no-build (was rebuilding in Debug).
- Directory.Build.props: WarningsAsErrors=NU1904 so critical NuGet
advisories block in every project, not just ones with
TreatWarningsAsErrors.
- Dockerfile copies global.json + .editorconfig too, so the image build
matches CI's SDK pin and analyzer severities.
- Remove dead .github/dependabot.yml + FUNDING.yml (upstream-pointed).
- Rewrite docs/ci-cd.md to the implemented pipeline.
Refs #4, #3, #8.
ErsatzTV logs via Serilog and never emits Kestrel's 'Now listening on'
line, so the smoke test grep never matched even though the app booted
fully in ~6s. Match ErsatzTV's actual startup logs instead ('… service
started', 'Located ffmpeg'). The image build itself was already passing.
Refs #4.
.NET 10's NuGet audit promotes vulnerable transitive packages to NU1901-1904
warnings during restore; the app projects set TreatWarningsAsErrors=true, so
restore failed on NCalcSync 5.11.0 (moderate) and SQLitePCLRaw 2.1.10 (high).
Demote NU1901/NU1902/NU1903 to warnings in Directory.Build.props (NU1904
critical still errors). Also COPY Directory.Build.props/.targets in the
Dockerfile before restore so the image build honors the same props as
local/CI builds (it previously copied only the .sln). Underlying deps tracked
in #8.
Refs #4, #8.
Adds .gitea/workflows/docker-build.yml: a test-gated, amd64-only Docker
build that pushes the fork's own image to the Gitea container registry
(192.168.1.95:3000). The .NET test job gates the image build; the build
job stamps INFO_VERSION from git, uses buildx registry layer caching, and
smoke-tests that the built image boots before finishing.
Tagging:
- push to main -> :latest + :<short-sha> (test image; prod untouched)
- push tag v* -> :prod + :<version> + :<short-sha> (prod release)
Updates docker/Dockerfile to pull the FFmpeg base image from our Gitea
registry (192.168.1.95:3000/timothy/ersatztv-ffmpeg:7.1.1) instead of the
archived upstream ghcr.io image.
Removes the upstream .github/workflows/* — they target GHCR/DockerHub and
Azure/Apple signing secrets we don't have, call reusable workflows at dead
ersatztv/ersatztv@main paths, and were running as noise (incl. a daily
stale-issue cron) on the Gitea runner. Upstream is archived, so there are
no future merges to preserve them for.
Refs #4, #3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Live Host-header test against the running container proves tvg-logo follows
the request Host header — there is no hardcoded localhost in the M3U/XMLTV
path (the localhost in GenerateChannelLogoUrl only feeds the FFmpeg watermark
overlay). Record the confirmed cause, the operational vs. durable fixes, and
the key architectural fact for future work: ErsatzTV has no advertised/base-URL
setting, so every absolute URL derives from the request Host; ConfigElement is
key/value so adding a setting needs no EF migration. Code fix for #1 deferred
until CI/CD test/prod envs (#3, #4) exist.
Refs #1
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Moves ci-cd.md (59 lines) from Claude memory into docs/ alongside
existing architecture docs. Slims MEMORY.md from 42 to 18 lines by
removing sections duplicated in CLAUDE.md (Tech Stack, Key Patterns,
Architecture Docs index).
Total memory load per session: 101 → 18 lines.
Fixes#7
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace informal implementer workflow with structured 7-step protocol
including mandatory root cause analysis for bug fixes. References /done
skill for automated enforcement.
Part of adversarial-reviewer #260.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Document channel architecture, M3U/XMLTV integration with Jellyfin,
and fork maintenance strategy for the archived upstream. Also includes
CLAUDE.md updates for implementer workflow and project boundaries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CLAUDE.md with architecture overview and development guide
- .mcp.json with docker, ssh, gitea, csharp-lsp, and nuget MCP servers
- Skills for ersatztv and jellyfin
- .gitignore: exclude .mcp/ (built MCP tools)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add instance id support
* actually use env variable for instance ID
* Default to ersatztv.org for instance id
* simplify
* fix ordering
* update changelog
---------
Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
* Add Polish localization for MainLayout
* Add Polish language option to UI settings
* Add Polish to supported UI cultures
* Add Polish localization for channel UI
Added Polish translations for channel-related UI elements.
* Add Polish translation for 'Rows per Page' label
* Update Polish translation for rows per page label
---------
Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>
* Add Polish localization for MainLayout
* Add Polish language option to UI settings
* Add Polish to supported UI cultures
---------
Co-authored-by: Jason Dove <1695733+jasongdove@users.noreply.github.com>