maksit-certs-ui/CHANGELOG.md

16 KiB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[3.5.0] - 2026-05-24

Release status: 3.3.4 is the last published release. 3.5.0 consolidates all changes since 3.3.4 (HA, Engine/Vault alignment, client libraries, Web UI shared packages).

Breaking

  • HA / interactive ACME: Removed IPrimaryReplicaWorkload, PrimaryReplicaGate, PrimaryReplicaShutdownHostedService, and CertsFlowPrimaryReplica. All replicas may run configure-client, init, orders, challenge completion, certificate download, apply, and revoke. The API no longer returns HTTP 503 with urn:maksit:certs-ui:primary-replica-required. Clients that retried on that signal should use normal error semantics only.
  • HTTP-01 challenge: AcmeChallengeAsync no longer writes tokens under AcmeFolder or reads legacy on-disk files. Challenge text is served from PostgreSQL only; ingress must reach GET /.well-known/acme-challenge/{token} on this app (or equivalent).
  • Startup / filesystem: Removed the shared init marker under DataFolder, AcmeFolder, and DataFolder settings, and default server acme/data PVC mounts. Followers wait until the database reports at least one user.
  • Configuration: CertsUIEngineConfiguration renamed to CertsEngineConfiguration in appsettings, Helm values.yaml, and secrets templates.
  • Engine layout: PersistancePersistence; CertsLinq2DbMappingCertsUILinq2DbMapping.
  • Engine query ports (Vault-style): IUserQueryService, IApiKeyQueryService, and IApiKeyEntityScopeQueryService use synchronous Search / Count with optional Expression<Func<TDto, bool>>? predicates, skip / limit, and Result types — not async paged Search…Async with string filters.
  • ACME session persistence: IAcmeSessionStore, AcmePostgresSessionStore, AcmeSessionSnapshot, and AcmeSessionJsonSerializer removed. ILetsEncryptService depends on IAcmeSessionPersistenceService (AcmeSessionPersistenceServiceLinq2Db) for acme_sessions JSON load/save.
  • ICertsFlowDomainService: Constructor takes IRegistrationCacheDomainService instead of IRegistrationCachePersistenceService.
  • Web UI: Removed the in-repo shared UI stack (layout, DataTable, form editors, deep/enum helpers, local toast). The SPA depends on @maks-it.com/webui-core, webui-components, and webui-contracts (private npm registry; src/MaksIT.WebUI/.npmrc).
  • E2E tests: CertsUiApiKeyE2ETests removed from MaksIT.CertsUI.Tests; API-key E2E lives in MaksIT.CertsUI.Client.Tests (Category=E2E).
  • Terms of Service API: Interactive ACME uses only GET /api/certs/{sessionId}/terms-of-service (stateless isStaging variant removed).
  • Startup migrations: Removed legacy EF-era baseline, VersionInfoversion_info rename repair, PascalCase → snake_case column repair, and RunMigrationsService.BaselineVersion. MigrateUp expects schema managed only by in-process FluentMigrator migrations.
  • Database: users.JwtTokensJson removed; sessions live in jwt_tokens only (no duplicate JSON on users).
  • Deprecated host: Removed legacy MaksIT.Webapi and MaksIT.Webapi.Tests in favor of MaksIT.CertsUI / MaksIT.CertsUI.Tests.

Added

  • MaksIT.CertsUI.Client: HTTP client library with API key auth (ICertsUIClient, CertsUIClient, ServiceCollectionExtensions, CertsUIApiException).
  • MaksIT.CertsUI.Contracts: Shared wire types (AccountResponse, HostnameResponse, RuntimeInstanceIdResponse).
  • MaksIT.CertsUI.Client.PowerShell: Binary module (Connect-CertsUI, Get-CertsUIAccounts, Invoke-CertsUICreateAccount, etc.; requires PowerShell 7 on .NET 10).
  • MaksIT.CertsUI.Client.Tests: Unit tests plus relocated API-key E2E suite.
  • PowerShell E2E: src/e2e-tests/ scenarios and Test-CertsUiApiKeyE2E.ps1 / .bat (Vault-style CERTSUI_E2E_CREDENTIALS).
  • Docs: assets/docs/POWERSHELL_CLIENT_MODULE.md, assets/docs/ARCHITECTURE_LAYERING.md, HA and login architecture docs; CONTRIBUTING.md links layering doc and dotnet test guidance.
  • New backend host: MaksIT.CertsUI WebAPI with controllers, JWT and JWT-or-API-key authorization, hosted services, and mapping/configuration abstractions.
  • Engine platform: Domain-oriented MaksIT.CertsUI.Engine (Domain, Dto, DomainServices, Persistence, QueryServices, Infrastructure, FluentMigrations) with Linq2Db mappings and migration services.
  • Engine (Vault parity): EntityScopeBase; UserAuthorization / ApiKeyAuthorization aggregates; split UserEntityScope / ApiKeyEntityScope; IdentityDomainService / ApiKeyDomainService refactor aligned with MaksIT.Vault.
  • ExpressionCompose for composing nested Linq2Db predicates.
  • IRegistrationCacheDomainService / RegistrationCacheDomainService, RegistrationCachePayloadDocument, and RegistrationCachePayloadJsonTests.
  • IAcmeSessionPersistenceService, AcmeSessionPersistenceServiceLinq2Db, and AcmeSessionPayloadMapper for PostgreSQL-backed ACME State.
  • PostgresStartupWait — waits for PostgreSQL and retries FluentMigrator MigrateUp on transient startup failures.
  • API / RBAC: GetActingJwtTokenData maps API keys to a synthetic JwtTokenData principal; RbacHelpers.EnsureActorMayAssignGlobalAdmin / EnsureActorMayPatchGlobalAdminFlag.
  • HA runtime coordination: DB-backed HTTP-01 challenge persistence and runtime leases (acme_http_challenges, app_runtime_leases, acme_sessions, terms_of_service_cache); coordinated bootstrap and renewal execution.
  • Kubernetes: Per-component Helm replicaCount, PodDisruptionBudget support, health endpoints (/health/live, /health/ready), optional kubernetesUpstreamHosts for in-cluster YARP upstreams.
  • LetsEncrypt: Per-host ACME rate-limit cooldown on RegistrationCache; AcmeProblemKind enumeration; in-memory AcmeSessionStore (later superseded by PostgreSQL persistence); partial LetsEncryptService files; State.TryGetAccountKey; LetsEncrypt.Tests for retry parsing and cooldown JSON.
  • Frontend: Users/API Keys pages and forms; identity/API-key UX with list/filter/paging (later migrated to webui-* packages).
  • Test suite: MaksIT.CertsUI.Tests and MaksIT.CertsUI.Engine.Tests with Postgres/WebAPI fixtures.
  • Release tooling: DotNetDockerPush per-image versionEnvFiles (temporary VITE_APP_VERSION rewrite) and optional per-image contextPath (upstreamed to maksit-repoutils 1.0.11).
  • Helm / config: certsEngineConfiguration.autoSyncSchema (default true) for add-only column sync on startup.

Changed

  • Identity / API key controllers: Use GetActingJwtTokenData instead of JWT-only GetJwtTokenData for user and API-key CRUD/search.
  • IdentityService / ApiKeyService: Build predicates and call Count + Search on query services; thin-search wiring (Pattern B).
  • Web UI: Migrated to @maks-it.com/webui-* packages; createWebUiHttpClient; apiRoutes.ts; pages under src/pages/; webUi/dataSources.ts; models reorganized under domain folders aligned with webui-contracts. Earlier step: axiosConfig helpers return { payload, status, ok }.
  • ACME sessions: Let's Encrypt client State persisted in PostgreSQL acme_sessions so any replica can continue after load balancing.
  • LetsEncrypt / HttpClient: ConfigureClient uses absolute ACME directory URL instead of assigning BaseAddress on the shared client.
  • CertsFlowDomainService: PurgeStaleHttpChallengesAsync (HTTP-01 cleanup); AutoRenewal calls it before renewal work; skips hostnames in ACME cooldown window.
  • LetsEncryptService: Uses IAcmeSessionPersistenceService; dropped Newtonsoft.Json from Engine (STJ-only JSON paths).
  • CacheService: Thin façade over IRegistrationCacheDomainService.
  • Bootstrap / renewal: InitializationHostedService acquires certs-ui-bootstrap (RuntimeLeaseNames.BootstrapCoordinator) for empty-database admin creation, then releases. AutoRenewal acquires certs-ui-renewal-sweep (RuntimeLeaseNames.RenewalSweep) per sweep. Lease name certs-ui-primary replaced by bootstrap and renewal sweep constants.
  • HA / ToS cache: Terms of Service PDF caching moved from pod filesystem to PostgreSQL terms_of_service_cache with TTL/HTTP validators.
  • FluentMigrator: Standard VersionInfo table and columns; .ScanIn(…).For.All() discovery; migrations run in Program.cs after Build() before hosted services; logged host/database and migration count; coordination DDL repair after MigrateUp when tables missing despite applied version.
  • Schema sync: AutoSyncSchema add-only (ADD COLUMN IF NOT EXISTS; no DROP); desired map includes users.IsActive, TwoFactorSharedKey.
  • Docker Compose / Helm: YARP upstream env vars for in-cluster vs Compose hostnames; components.server.service.sessionAffinity defaults to false (stateless LB); certsClientRuntime.apiUrl defaults to /api; optional preStop sleep and terminationGracePeriodSeconds for rolling updates.
  • Container image: MaksIT.CertsUI Dockerfile installs libgssapi-krb5-2 for Npgsql GSS support on slim images.
  • Namespace and solution layout: Standardized around MaksIT.CertsUI* host/engine split; ACME contracts moved from legacy Entities/Models into Domain / Dto.
  • LetsEncrypt: Broader nullable annotations; CachedHostname primary constructor; certificate loading via X509Certificate2.CreateFromPem / X509CertificateLoader.LoadCertificate.
  • Integration tests: InMemoryUserStore, CacheServiceTests, CertsFlowServiceTests, ApiKeyQueryServiceIntegrationTests, AccountServicePatchAccountIntegrationTests aligned with new ports.
  • README: Architecture references, HA guidance, E2E instructions for dotnet test and PowerShell scenarios.

Fixed

  • Startup / HA: Bootstrap lease no longer blocks extra replicas when users already exist; cooperative cancel on host shutdown; CoordinationTableProvisioner with explicit public.* DDL; RuntimeLeaseServiceNpgsql uses public.app_runtime_leases; post-migrate verification for coordination tables.
  • FluentMigrator: Empty connection string no longer puts runner in connectionless/preview mode; throw when engine connection string missing; maintenance DB bootstrap warns instead of failing when role cannot CREATE DATABASE.
  • Identity / PostgreSQL: users.JwtTokensJson column dropped; new inserts no longer hit 23502; token rows normalized into jwt_tokens.
  • Helm / reverseproxy: YARP upstreams no longer default to unresolvable Compose hostnames in Kubernetes when kubernetesUpstreamHosts is enabled.
  • LetsEncrypt: RevokeCertificate fails correctly on non-success; disposes HTTP response on success; NewOrder logs authorization status; TryGetCachedCertificate returns false when private key blob missing.
  • AccountService.PatchAccountAsync: Returns account built from cache after reload, not stale in-memory instance.
  • WebUI Terms of Service: PDF worker loaded from Vite-bundled asset (pdf.worker.min.mjs?url) for dev and production.

Removed

  • CertsFlowPrimaryReplica, PrimaryReplicaRequiredObjectResult, CertsFlowResultExtensions / ToCertsFlowActionResult; CertsFlowController uses ToActionResult().
  • Web UI (local): DataTable, FormLayout, Layout, LazyLoadTable, editor components, Toast, Offcanvas, useFormState, localStorage/identity, legacy functions/ / models/ trees superseded by webui-* packages.
  • Web UI: Primary-replica 503 auto-retry in axiosConfig.ts.
  • Configuration / Helm: AcmeFolder, DataFolder, default acme/data PVC mounts; AddMemoryCache() host registration (unused).
  • Legacy engine layout: Obsolete top-level engine files, old .vscode project files.

Upgrade notes (from 3.3.4)

3.3.4 is the last published release. 3.5.0 uses a new host, PostgreSQL-backed registration cache, and FluentMigrator schema — there is no in-place migration of Let's Encrypt account material from 3.3.4. Use backup → install → restore:

  1. On 3.3.4 (before upgrade): Sign in to the Web UI, open Utilities, and Download cache files (full registration-cache ZIP). Store the file safely — it contains your Let's Encrypt account keys and cached certificate data. Optionally export Postman/API backups of any other settings you rely on.
  2. Prepare 3.5.0: Provision a new empty PostgreSQL database (or drop and recreate the engine database). Update Helm/secrets: rename certsUIEngineConfigurationcertsEngineConfiguration, set ConnectionString, and remove legacy acme / data bind mounts from docker-compose.override.yml if present.
  3. Deploy 3.5.0: Install the new server, client, and reverse-proxy images (pin tags to 3.5.0, not latest). On first start, FluentMigrator creates the schema; bootstrap creates the default admin when the database has no users.
  4. Restore accounts: Sign in on 3.5.0, open Utilities, and Upload cache files with the ZIP from step 1. Verify accounts and certificates in the UI before decommissioning 3.3.4.
  5. Re-create operators: Users, API keys, and JWT sessions from 3.3.4 are not migrated automatically — recreate users/API keys in 3.5.0 as needed.

Also check when upgrading:

  • Operations: Retarget alerts from lease certs-ui-primary to certs-ui-bootstrap and certs-ui-renewal-sweep.
  • Web UI build: Configure npm auth for @maks-it.com/* (see src/MaksIT.WebUI/.npmrc) when building the client image locally.
  • E2E: dotnet test on MaksIT.CertsUI.Client.Tests with Category=E2E; set CERTSUI_E2E_EXPECT_MIN_DISTINCT_INSTANCES=2 for HA (PowerShell E2E defaults to 1 for Docker Compose).
  • Repo utils: utils/ refreshed from maksit-repoutils 1.0.14 (engines/, plugins/, modules/, tools/). Run utils\Invoke-ReleasePackage.bat for release; utils\Invoke-TestEngine.bat for tests and coverage badges; refresh via utils\Update-RepoUtils.bat (set dryRun: false in utils/tools/Update-RepoUtils/scriptSettings.json).

[3.3.4] - 2026-04-01

Added

  • MaksIT.Webapi.Tests: service-level unit tests (settings, cache, identity, agent, account, certs flow) and domain tests for Settings.
  • Postman collections under src/Postman updated to match current MaksIT.Webapi routes, JWT flow, and cache endpoints.

Fixed

  • WebUI Terms of Service (Let's Encrypt): PDF viewer loads pdfjs-dist worker from a Vite-bundled asset (pdf.worker.min.mjs?url) so rendering works in dev and production instead of failing on missing or wrong worker URLs.
  • AccountService.PatchAccountAsync returns the account built from the cache after reload, not a stale in-memory instance.

[3.3.3] - 2025-12-20

Changed

  • Relicensed project from GPL-3.0 to Apache-2.0.

[3.3.2] - 2025-12-20

Changed

  • Minimal Helm chart and documentation improvements.

[3.3.1] - 2025-11-22

Changed

  • Public release following the v3.3.0 pre-release.

[3.3.0] - 2025-11-15

Changed

  • Pre-release of the v3.3.x line.

[3.2.0] - 2025-09-11

Added

  • New WebUI with authentication.

[3.1.0] - 2024-08-11

Changed

  • Stabilized release following v3.0.0.

[3.0.0] - 2024-05-31

Added

  • WebAPI and containerization.

[2.0.0] - 2019-11-01

Changed

  • Dependency injection pattern implementation.

[1.0.0] - 2019-06-29

Added

  • Initial release.