Changelog¶
Notable changes in this fork of Keygate, newest first. Versions before 0.1.2 are inherited from upstream Keygate; the entries below cover what this fork adds on top.
0.1.5 — UI polish & developer experience¶
Changed
- Entitlement editor adapts to the value type. The Value field in the plan and add-on entitlement dialogs now matches the selected type — an Enabled/Disabled toggle for booleans, number inputs for integers and quotas, and a text input for strings. Quotas are labelled Limit with a 0 = unlimited hint, and switching the type resets the value instead of leaving a stray
true. - Softer theme. Restored a light default border color (Tailwind v4 had defaulted bare borders to near-black) so cards, tables, and inputs use subtle separators; cards now use a soft shadow for a cleaner, elevated look.
Added
- Demo-data seeder (
cmd/seed,make seed): populates a local database with sample products, plans (entitlements across every value type), and licenses for quick manual testing. Idempotent.
0.1.4 — Offline & air-gapped licensing¶
Added
- Offline (air-gapped) license issuance. Admins can mint a perpetual, machine-bound license file (
.lic) for devices that never connect to the internet —POST /admin/licenses/:id/offline-token, plus an "Offline license" action in the admin license view. The token is Ed25519-signed, verified fully offline, and bound to the device via its fingerprint. See Air-gapped Licensing. - Self-service offline activation. From the customer portal, a license owner (or accepted seat) can activate one air-gapped machine and download its license file. Switching machines requires an admin to clear the activation — enforced as one offline activation per license (partial unique index). Hidden for SaaS products.
- Docs: new Air-gapped Licensing integration page, including the machine-code contract and the reconnect / revocation semantics.
Fixed
- Postgres 18 container failing to start because the data volume was mounted at
/var/lib/postgresql/datainstead of/var/lib/postgresql.
0.1.3 — Theming & security hardening¶
Added
- Dedicated favicon setting (
favicon_url) separate from the logo, plus brand-color tints derived from a single primary color so admins don't hand-pick a palette.
Security
- Close open OTP signup with
OTP_REQUIRE_EXISTING_USER— codes go only to existing accounts (admins bypass); unknown emails get an identical response, so the endpoint can't enumerate accounts. - Pin JWT verification to HS256, removing the algorithm-confusion class.
- Restrict CORS to
BASE_URL(plus localhost outside production); unknown origins are rejected. Closes a credentialed-CORS hole on internet-reachable non-production deployments. See Security. - Enumeration-safe wording on the login OTP step.
Fixed
- Custom-logo favicon now updates every
<link rel="icon">, not just the first.
0.1.2 — License expiration & paid support (first fork release)¶
Added
- License expiration (
valid_until). Set or clear a fixed expiry per license (admin API + UI); licenses with no expiry show as Perpetual. Dates are interpreted as end-of-day in the admin's timezone. - Support window (perpetual + paid support).
licenses.support_untilandplans.support_daysimplement the JetBrains-style "perpetual fallback": the license never expires, but access to newer releases is gated on the paid support window.support_untilis surfaced in the verify/activate response and the signed offline token (sup), with reminder and lapse emails and alicense.support_endedwebhook. See The Support Window. - Self-serve Stripe support renewal.
POST /license/support/checkoutextendssupport_until(per-plansupport_renewal_price_id), fires alicense.support_renewedwebhook, and emails a confirmation. - Portal device-activation management — customers free their own activation slots without a support ticket.
Changed
- Rebranded fork. Docker images and the in-app update check point at
kurtjacobson/keygate; upstream sponsorship links removed.
Fixed
- SMTP compatibility fixes for Office 365 / Exchange Online (AUTH negotiation and envelope sender).