mirror of
https://github.com/MAKS-IT-COM/maksit-certs-ui.git
synced 2026-05-16 04:48:12 +02:00
16 KiB
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.3.19] - 2026-04-26
Changed
- FluentMigrator / PostgreSQL: Version metadata table is
public.version_infowith snake_case columnsversion,applied_on,descriptionand unique indexuc_version, configured viaCertsFluentMigratorVersionTableMetaDataandWithVersionTableon the runner (aligned with the rest of the schema naming).
Removed
- Startup migrations: Removed legacy compatibility paths:
VersionInfo→version_inforename, PascalCase → snake_case column repair on the version table, and the EF-era baseline that created or seededversion_infowhenusersalready existed (andRunMigrationsService.BaselineVersion).
Upgrade notes
- Breaking: Recreate the Certs engine database (or use a new empty database). The app no longer upgrades in place from
VersionInfo, mixed column casing, or pre–FluentMigrator-baseline layouts;MigrateUpexpects a clean or fully FluentMigrator-managed schema.
[3.3.18] - 2026-04-26
Changed
- Docker Compose:
docker-compose.override.ymlsets the sameReverseProxy__Clusters__*__Destinations__d1__Addressenvironment variables as Kubernetes (http://server:5000//http://client:5173/on the Compose network), so YARP behavior does not depend only on baked-inappsettings.json. - Helm: Optional
components.reverseproxy.kubernetesUpstreamHosts(defaulttrue) toggles injection of in-cluster upstream URLs; setfalseonly for custom Service naming. Single-replica and HA clusters use the same DNS pattern.
Fixed
- Helm / reverseproxy: YARP upstreams defaulted to Compose hostnames
server/client, which do not resolve in Kubernetes. The chart setsReverseProxy__Clusters__*__Destinations__d1__Addresstohttp://<release-fullname>-server:<port>/andhttp://<release-fullname>-client:<port>/whenkubernetesUpstreamHostsis enabled (ports fromcomponents.server.service.portandcomponents.client.service.port).
[3.3.17] - 2026-04-26
Changed
- HA / API: Non-primary replicas return
Result.ServiceUnavailablewith stable markerurn:maksit:certs-ui:primary-replica-requiredfor ACME orchestration; the host maps that to HTTP 503,Retry-After, and RFC 7807ProblemDetails(replacing ad-hoc 429-style overload semantics for this case). - Helm: Default
components.server.service.sessionAffinity(ClientIP, configurable timeout),terminationGracePeriodSeconds, and a shortpreStopsleep so rolling updates drain connections before the primary lease TTL window. Disable or tune undercomponents.serverif your ingress already pins API traffic.
[3.3.16] - 2026-04-26
Changed
- HA / primary replica: A single elected instance holds Postgres lease
certs-ui-primary(RuntimeLeaseNames.PrimaryReplica), renews it periodically, and is the only instance withIPrimaryReplicaWorkload.IsPrimaryafter startup. It runs coordination DDL, identity bootstrap, all ACME domain flows (CertsFlowDomainService), andAutoRenewal. Other replicas serve HTTP (identity, health, etc.) andAcmeChallengeAsync(HTTP-01 token materialization for ingress). Followers reject ACME orchestration at the domain layer until they become primary after failover. - Startup: Removed separate
certs-ui-bootstraplease; primary lease serializes first-time admin creation.PrimaryReplicaShutdownHostedService(registered last) releases the primary lease on shutdown.
[3.3.15] - 2026-04-26
Fixed
- Startup / HA:
InitializationHostedServiceno longer takes the bootstrap lease when PostgreSQL already has users. Only the empty-database path waits on the lease (single-writer default admin). Extra replicas used to block on the lease until Kubernetes canceledStartAsync, surfacing asTaskCanceledExceptionat startup while the first replica held the lease. - Startup: Retry backoff treats
OperationCanceledExceptionwhen the host is stopping as shutdown (no misleading “initialization failed” loop); cooperative cancel still ends startup.
[3.3.14] - 2026-04-26
Fixed
- Identity / PostgreSQL: Removed redundant
users.JwtTokensJson(historical JSON blob of sessions on the user row). Server-side session allowlist semantics are unchanged: issued sessions remain rows injwt_tokensand are validated the same way as in Vault’s persistedJwtTokenmodel—only the duplicate JSON encoding was dropped. Newusersinserts no longer hit23502on that column. FluentMigratorDropUsersJwtTokensJson(20260426140000) drops the column when present; the baseline no longer creates it;JwtTokensTableMigrateFromJsoncopies from JSON only if that column still exists (upgrades from older DBs).
Changed
- FluentMigrator:
RestoreUsersJwtTokensJsonIfDropped(20260426120000) is now a no-op (revision kept for databases that already applied it). Session material is stored only injwt_tokens, not duplicated as JSON onusers.
[3.3.13] - 2026-04-26
Fixed
- HA lease /
42P01: AddedCoordinationTableProvisionerwith explicitpublic.*DDL;InitializationHostedServicecalls it immediately before bootstrap lease acquire (idempotent, same as post-migrate repair).RuntimeLeaseServiceNpgsqlnow usespublic.app_runtime_leasesin SQL so a non-defaultsearch_pathcannot miss the table. Post-migrate verification requirespublic.app_runtime_leasesplususersor"VersionInfo".
Upgrade notes (Kubernetes / Helm)
- Pin container tags to the app semver (e.g.
3.3.13for server, client, reverseproxy) viaglobal.image.tagand/orcomponents.*.image.tag. The chart resolves the effective tag withglobal.image.tagwhen set (seesrc/helm/templates/_helpers.tpl). - Do not rely on
latest+imagePullPolicy: IfNotPresentalone — nodes keep the first pulled digest, so you can run an old server binary while the OCI chart is already3.3.13. Use an explicit semver tag and/orpullPolicy: Always(or bumpglobal.rolloutNonce/global.rollmeper chart NOTES) when upgrading. - Push all three images for the tag you pin (
certs-ui/server,certs-ui/client,certs-ui/reverseproxy) so every deployment can pull successfully.
[3.3.12] - 2026-04-26
Fixed
- FluentMigrator: Use
.ScanIn(…).For.All()instead of.For.Migrations()so in-process discovery matches FluentMigrator guidance (avoids “no migrations” / incomplete runner behavior in some versions). - FluentMigrator: Throw if the engine connection string is empty when registering the runner — a null/empty
WithGlobalConnectionStringputs the processor in connectionless/preview mode (SQL logged, nothing committed), which matches reports of empty databases with no errors. - Migrations: Log host/database (no password) and count of
[Migration]types beforeMigrateUp; after coordination DDL, verifypublic.usersorpublic."VersionInfo"exists or fail with an actionable error (wrongDatabase=, permissions, or preview mode). - Database bootstrap: If the role cannot open a maintenance connection to database
postgres(common for locked-down app users), log a warning and skip automaticCREATE DATABASEinstead of failing the whole migration step.
[3.3.11] - 2026-04-26
Added
- Database: FluentMigrator
RestoreUsersJwtTokensJsonIfDropped(20260426120000) initially re-addedusers.JwtTokensJsonwithADD COLUMN IF NOT EXISTSfor databases that had dropped it under an olderJwtTokensTableMigrateFromJsonrevision. Superseded in 3.3.14: that revision is a no-op andDropUsersJwtTokensJsondrops the column; tokens stay injwt_tokensonly. - Helm / config:
certsServerConfig.configuration.certsUIEngineConfiguration.autoSyncSchema(defaulttrue) is rendered into serverappsettings.jsonso add-only schema sync runs on every startup unless explicitly disabled.
Changed
- Startup schema policy: Documented expand-only expectations — FluentMigrator
Up()should add tables/columns; avoid dropping renamed columns in routineUp()without an explicit follow-up plan.JwtTokensTableMigrateFromJsonno longer dropsJwtTokensJsonin that revision’sUp()(tokens are normalized intojwt_tokens). 3.3.14 removesJwtTokensJsonfrom the live schema viaDropUsersJwtTokensJson. - Schema sync:
AutoSyncSchemadefaults to true in repoappsettings.json;SchemaSyncServicedesired map includesusers.IsActiveandTwoFactorSharedKey. 3.3.14 stops treatingJwtTokensJsonas a desired column. Still ADD COLUMN IF NOT EXISTS only (no DROP in sync). - ICertsEngineConfiguration / ISchemaSyncService: Clarified that add-only sync is recommended and describes the no-DROP guarantee.
[3.3.10] - 2026-04-26
Fixed
- Database: After FluentMigrator
MigrateUp,RunMigrationsServiceapplies idempotentCREATE TABLE IF NOT EXISTS/CREATE INDEX IF NOT EXISTSforacme_http_challengesandapp_runtime_leases. IfVersionInfoalready records the migration but tables are missing (restore drift, partial apply, manual DB edits), FluentMigrator would skipUp()and the bootstrap lease would fail with42P01; this repair aligns schema with runtime needs.
[3.3.9] - 2026-04-26
Fixed
- Startup / database: FluentMigrator (
EnsureCertsEngineMigratedAsync) now runs inProgram.csimmediately afterWebApplication.Build()and beforeRunAsync, so schema (includingapp_runtime_leases) exists before anyIHostedServicestarts.InitializationHostedServiceonly performs bootstrap lease + identity init.
[3.3.8] - 2026-04-26
Fixed
- Startup / database:
InitializationHostedServicenow runs FluentMigrator (EnsureCertsEngineMigratedAsync) before acquiring the bootstrap PostgreSQL lease, soapp_runtime_leasesexists on an empty database (same ordering idea as Vault: migrate first, then coordination). - Startup: While waiting for the bootstrap lease, migrations are not re-run on every poll interval (
migrationsAppliedguard).
Changed
- Container image:
MaksIT.CertsUIDockerfile installslibgssapi-krb5-2so Npgsql can load GSS/Kerberos support without missing-library warnings on slimaspnetimages.
[3.3.7] - 2026-04-25
Added
- HA runtime coordination: Added DB-backed HTTP-01 challenge persistence and runtime lease infrastructure (
acme_http_challenges,app_runtime_leases) plus coordinated startup/renewal execution. - Kubernetes readiness model: Added per-component Helm
replicaCount+ PodDisruptionBudget support and health endpoints (/health/live,/health/ready) for probes. - New backend host: Added
MaksIT.CertsUIWebAPI host with controllers, authorization filters (JWT and JWT-or-API-key), hosted services, and mapping/configuration abstractions. - Engine platform expansion: Added a domain-oriented
MaksIT.CertsUI.Enginestructure (Domain,Dto,DomainServices,Persistance,QueryServices,Infrastructure,FluentMigrations) with linq2db mappings and migration services. - Frontend identity/api-key UX: Added Users/API Keys pages and forms (
CreateUser,EditUser,SearchUser,CreateApiKey) with reusable list/filter/paging components. - Test suite: Added
MaksIT.CertsUI.Testswith service and integration coverage plus shared Postgres/WebAPI fixtures.
Changed
- Namespace and solution layout: Standardized around
MaksIT.CertsUI*and moved responsibilities into clearer host/engine layers. - Engine model organization: Reorganized ACME and related contracts from legacy top-level
Entities/ModelsintoDomainandDto. - Helm/runtime behavior: Updated deployment templates to support
env.valueFrom, pod-name-based holder identity, and probe wiring for live/ready endpoints. - Documentation: Updated README architecture references and linked HA architecture guidance.
- WebUI contracts: Aligned identity/API-key request/response and paged-search models with updated backend endpoints.
Removed
- Deprecated host: Removed legacy
MaksIT.Webapiproject and its old controllers/services/background services. - Legacy engine layout: Removed obsolete top-level engine files (
Entities,Models, previous ACME helper locations, old project.vscodefiles). - Old test project: Removed
MaksIT.Webapi.Testsin favor ofMaksIT.CertsUI.Tests.
[3.3.6] - 2026-04-13
Added
- LetsEncrypt: Per-host ACME rate-limit cooldown on
RegistrationCache(AcmeRenewalNotBeforeUtcByHostname), with HTTPRetry-Afterand problem-detail parsing (AcmeRetryAfterParser), structured logging, andResult.TooManyRequestswhen the CA returnsrateLimited. - LetsEncrypt:
AcmeProblemKindas anEnumeration(RFC 8555 problemtypeURIs) instead of ad hoc strings;LetsEncrytExceptionexposesProblemKind,RetryAfterUtc, and optional rate-limit hostname. - LetsEncrypt:
AcmeSessionStorefor per-sessionStatein memory;LetsEncryptServicesplit into partial files (LetsEncryptService.Helpers.cs) for HTTP/JWS/error helpers. - LetsEncrypt:
State.TryGetAccountKeyfor a single place to validate account key material afterInit. - LetsEncrypt.Tests: Unit tests for retry parsing, problem-kind resolution, and cooldown JSON round-trip.
Changed
- AutoRenewal: Skips hostnames that are still in an ACME cooldown window (with debug logs for skipped hosts).
- Certs flow: Persists registration cache after failed full certificate flows when a session exists so cooldown metadata is saved.
- LetsEncrypt: Broader nullable reference annotations on ACME DTOs (
Problem,AcmeDirectory,AuthorizationChallengeError, etc.) and explicit null guards inLetsEncryptService.
Fixed
- LetsEncrypt: Certificate PEM loading uses
X509Certificate2.CreateFromPeminstead of the obsoleteX509Certificate2(byte[])constructor (SYSLIB0057). - LetsEncrypt:
RevokeCertificatenow fails correctly on non-success responses (missingreturn), uses the same problem-document handling as other ACME calls, and disposes the HTTP response on successful revoke. - LetsEncrypt:
NewOrderauthorization error log line now logs the authorization status, not the order status.
[3.3.5] - 2026-04-12
Changed
CachedHostnamenow uses a C# 12 primary constructor (same public construction as before).
Fixed
RegistrationCacheloads cached PEM certificates viaX509CertificateLoader.LoadCertificateand disposes them withusingwhere certificates are parsed for expiry and host listing.RegistrationCache.TryGetCachedCertificatereturnsfalsewhen the cached entry has no private key blob, avoiding a null argument when importing key material.
[3.3.4] - 2026-04-01
Added
MaksIT.Webapi.Tests: service-level unit tests (settings, cache, identity, agent, account, certs flow) and domain tests forSettings.- Postman collections under
src/Postmanupdated to match currentMaksIT.Webapiroutes, JWT flow, and cache endpoints.
Fixed
- WebUI Terms of Service (Let's Encrypt): PDF viewer loads
pdfjs-distworker 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.PatchAccountAsyncreturns 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.