mirror of
https://github.com/MAKS-IT-COM/maksit-certs-ui.git
synced 2026-06-10 08:36:40 +02:00
173 lines
16 KiB
Markdown
173 lines
16 KiB
Markdown
# Changelog
|
|
|
|
All notable changes to this project will be documented in this file.
|
|
|
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
|
## [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:** **`Persistance`** → **`Persistence`**; **`CertsLinq2DbMapping`** → **`CertsUILinq2DbMapping`**.
|
|
- **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, **`VersionInfo` → `version_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](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 **`certsUIEngineConfiguration`** → **`certsEngineConfiguration`**, 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.
|