cf7e0396f0
ci / build-test (push) Successful in 1m13s
The instance had no idea what version it was: VERSION drives tagging and the image publish, but was never stamped into the assemblies, so a running build reported 1.0.0 forever. Directory.Build.props now stamps it into every project. The dashboard compares that against the newest tag in the source repository and shows a banner when behind. A plain GET of a public tag list -- nothing about the instance is sent -- cached six hours, failing quiet. Two things it deliberately does not do. It never blocks a render: the banner paints from the cached answer and refreshes after first render, so a cold start or an unreachable repository costs nothing rather than holding the dashboard open for an HTTP timeout. And it never guesses: an unknown version on either side shows no banner at all, because a banner that cannot clear trains people to ignore the next real one. Version comparison is numeric on exactly three components, not System.Version and not string order. Tags are written vX.Y.Z, the assembly reports X.Y.Z with a +commithash suffix, and "0.10.0" sorts below "0.9.0" as a string -- each of those is a way the banner sticks or never appears. Prerelease suffixes compare equal to their release so an rc tag does not nag. Gitea does not promise semver ordering, so the highest tag wins rather than the first. The command shown depends on the install: the LXC has `update`, a container is replaced by pulling an image, and telling container users to run `update` sends them after a command that does not exist. No update *button*. The UI has no authentication and the LXC runs the app as root, and `update` builds whatever is on master, so a click would be an unauthenticated path to arbitrary code execution for anything on the LAN. The README now states the no-auth position plainly rather than leaving it implied. Tests cover the parse and ordering cases that would strand a banner, the Gitea payload shape captured from the live API, unreachable and garbage responses, and that the VERSION file actually reaches the assembly -- read from MeterVault's own assembly rather than GetEntryAssembly(), which under `dotnet test` is the test host and reported a confident wrong answer. The suite makes no outbound request: the app factory disables the check. Claude-Session: https://claude.ai/code/session_01V6joyergfvVLFEizH1hJLd
64 lines
2.9 KiB
C#
64 lines
2.9 KiB
C#
namespace MeterVault.Infrastructure.Options;
|
|
|
|
/// <summary>
|
|
/// Root application options, bound from the "MeterVault" configuration section.
|
|
/// Secrets (broker tokens etc.) live on individual endpoints by reference, not here.
|
|
/// </summary>
|
|
public sealed class MeterVaultOptions
|
|
{
|
|
public const string SectionName = "MeterVault";
|
|
|
|
/// <summary>IANA timezone used for local-midnight bucketing and display (SDD §10).</summary>
|
|
public string TimeZone { get; set; } = "Europe/Berlin";
|
|
|
|
public string Currency { get; set; } = "EUR";
|
|
|
|
/// <summary>Default UI locale: 'en' (OSS default) or 'de'.</summary>
|
|
public string Locale { get; set; } = "en";
|
|
|
|
/// <summary>Run EF migrations on startup. Disable for tests that migrate out-of-band.</summary>
|
|
public bool RunMigrationsAtStartup { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Load the bundled Energiebilanz reference dataset on startup if the database has none yet
|
|
/// (idempotent — guarded by a marker meter). Off by default; set <c>MeterVault__SeedReferenceData=true</c>
|
|
/// for a one-command populated demo/test instance.
|
|
/// </summary>
|
|
public bool SeedReferenceData { get; set; }
|
|
|
|
/// <summary>Start the MQTT/Home Assistant ingestion workers. Disable for tests.</summary>
|
|
public bool EnableLiveIngestion { get; set; } = true;
|
|
|
|
/// <summary>How long full-resolution raw readings are retained (SDD §5.5, default 3 years).</summary>
|
|
public int RawRetentionDays { get; set; } = 1095;
|
|
|
|
/// <summary>
|
|
/// Compare the running build against the newest published release and show a banner when behind.
|
|
/// Set false for an air-gapped instance, or one that should make no outbound requests at all.
|
|
/// </summary>
|
|
public bool UpdateCheckEnabled { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Tag listing consulted by the update check. Points at the project's own Gitea, not a vendor
|
|
/// endpoint — nothing about the instance is sent, it is a plain GET of a public tag list.
|
|
/// Repoint it at a fork, or blank it to disable the check as surely as the flag above.
|
|
/// </summary>
|
|
public string UpdateCheckUrl { get; set; } =
|
|
"https://git.finalfactory.de/api/v1/repos/FinalFactory/MeterVault/tags?limit=50";
|
|
|
|
/// <summary>
|
|
/// API keys accepted on the <c>X-Api-Key</c> header for the REST API (SDD §9). Provide via env
|
|
/// (e.g. <c>MeterVault__ApiKeys__0=...</c>). Empty means the API is open (dev only).
|
|
/// </summary>
|
|
public IList<string> ApiKeys { get; set; } = [];
|
|
|
|
/// <summary>Honour <c>X-Forwarded-User</c>/<c>Remote-User</c> from a trusted reverse proxy (SDD §10).</summary>
|
|
public bool ReverseProxyTrust { get; set; }
|
|
|
|
/// <summary>
|
|
/// Allow the REST API without any API key. Off by default: with no keys configured the API is
|
|
/// closed (401) rather than open, so an unconfigured deployment doesn't expose export/import.
|
|
/// </summary>
|
|
public bool AllowAnonymousApi { get; set; }
|
|
}
|