Module licensing

Module licensing 

Source
Expand description

Enterprise licensing gate (DW-032).

The edition boundary as a runtime value: a LicenseGate holds an optional verified license and answers the two questions every enterprise feature asks before it engages — “are we in enterprise mode?” (LicenseGate::is_enterprise) and “does this license grant feature X?” (LicenseGate::has_feature). OSS builds (the default, no ent cargo feature) compile a stub gate that is always LicenseGate::none: every enterprise feature is inert by construction, and no licensing-core dependency is pulled in.

§Verification model

When the ent feature is compiled in, LicenseGate::from_file reads a license file, verifies its Ed25519 signature against the product’s public key, and checks expiry. The public key is NEVER user-configurable in the YAML (an operator must not be able to substitute their own key to forge a license): it comes from the DWARA_LICENSE_PUBLIC_KEY environment variable or, when unset, the compiled-in development key (local/CI only — production MUST set the env var). The product ID is pinned to "dwara" so a license issued for another ShristiLabs product cannot be replayed here.

§Grace period

A license that has passed its expires_at timestamp is not immediately fatal. For a configurable grace window (default 7 days, 0..=30) after expiry, enterprise features keep working and a warning is logged — the operator has a buffer to renew. After the grace window the gate degrades to OSS: LicenseGate::is_enterprise returns false and every enterprise feature falls back to its OSS behavior. This is the done-when: “Invalid/expired license degrades to OSS feature set gracefully.”

§Startup vs reload

The gate is built once at startup (dwara-bin) and rebuilt on every config reload that carries a license block. A signature-invalid license REFUSES to start (exit 1) at cold start; on reload, a signature-invalid license keeps the running generation serving (the same atomic-not-publish rollback as every other reload failure). A missing license file refuses to start at cold start and keeps serving on reload.

§Feature claim flags

The license’s features vector carries claim strings. The gate checks them by exact string match. The current enterprise features and their claim strings:

  • redis_rate_limiter — DW-031 (not yet implemented; the gate provides the check, the feature will call it).
  • config_convergence — DW-054 (not yet implemented; same).
  • redis_cache — SCALE-04 (#183): Redis-backed shared response cache.

Future enterprise features add their claim string here and call LicenseGate::has_feature at their config-validation site.

Structs§

LicenseGate
The enterprise licensing gate.

Enums§

LicenseLoadError
Error produced while loading or verifying a license.
LicenseStatus
The runtime status of the license gate, mirrored by the dwara_license_status metric (0..=3).

Constants§

DEFAULT_GRACE_PERIOD_DAYS
Default grace period (days) after a license expires before the gate degrades to OSS. Configurable via gateway.license.grace_period_days (0..=30); 0 means no grace (immediate degradation on expiry). The canonical value lives in crate::config::limits (the lowest domain) so both this module and snapshot::validate read the same number without an upward import; this re-export is the convenience path for gate consumers.
FEATURE_CONFIG_CONVERGENCE
License claim string for config convergence (DW-054).
FEATURE_FIPS
License claim string for FIPS 140-3 mode (DW-111). A license that carries this claim REQUIRES the gateway to be running in FIPS mode (the fips cargo feature compiled in and the self-test passed). When the license grants this claim but the gateway is NOT in FIPS mode, the license is invalid (config-time check).
FEATURE_REDIS_CACHE
License claim string for the Redis shared response cache (SCALE-04, #183). A license that carries this claim enables the Redis-backed response cache so a fleet of N instances shares one cache and achieves fleet-wide hit ratios instead of N x cold caches.
FEATURE_REDIS_QUOTAS
License claim string for the Redis distributed quota backend (DW-155). A license that carries this claim enables the Redis-backed quota checker so a fleet of N instances shares one counter per (consumer, budget, window) and enforces the CONFIGURED cap.
FEATURE_REDIS_RATE_LIMITER
License claim string for the Redis rate-limiter backend (DW-031).
MAX_GRACE_PERIOD_DAYS
Maximum configurable grace period (days). Re-exported from crate::config::limits for the same reason as DEFAULT_GRACE_PERIOD_DAYS.
PRODUCT_ID
The product ID this gateway verifies licenses for. Pinned so a license issued for another ShristiLabs product cannot be replayed against dwara even in the unlikely event of key reuse.
PUBLIC_KEY_ENV_VAR
The environment variable holding the base64-encoded Ed25519 public key for license verification. When unset, the compiled-in development key is used (local/CI only; production MUST set this).