feat: Heimdall license integration (LNNT key format) #16

Closed
opened 2026-04-06 13:11:42 -07:00 by pyr0ball · 0 comments
Owner

Wire Linnet to the Heimdall license server for tier enforcement.

Requirements:

  • Key format: CFG-LNNT-XXXX-XXXX-XXXX
  • License check at session start (offline-capable, 30-day refresh per Heimdall spec)
  • Tier gates: Free (local only), Paid (cloud STT, TTS, DeepL, session pinning)
  • BYOK path: user provides their own DeepL key — bypasses Paid tier gate for translation only
  • Heimdall endpoint: /validate (standard across all CF products)

Implemented

app/tiers.py — replaced naive prefix check with real Heimdall validation:

  • Self-hosted: LINNET_LICENSE_KEY/v1/licenses/verify
  • Cloud mode: user_id from X-CF-Session/admin/cloud/resolve (requires HEIMDALL_ADMIN_TOKEN)
  • 30-minute in-process cache per (key or user_id) — survives brief Heimdall outages
  • Network errors do NOT cache (retry on next request)
  • require_paid(byok_deepl=True) skips gate for BYOK translation path

app/api/sessions.pyPOST /session/start and GET /session/{id} now resolve and return tier in response

app/config.py — added HEIMDALL_ADMIN_TOKEN and LINNET_LICENSE_KEY settings

compose.cloud.yml — updated env var docs; clarified that cloud mode uses admin token, not per-instance key

tests/test_tiers.py — 17 tests covering both paths, caching, BYOK bypass, and error handling; all 52 suite tests passing

Wire Linnet to the Heimdall license server for tier enforcement. Requirements: - Key format: `CFG-LNNT-XXXX-XXXX-XXXX` - License check at session start (offline-capable, 30-day refresh per Heimdall spec) - Tier gates: Free (local only), Paid (cloud STT, TTS, DeepL, session pinning) - BYOK path: user provides their own DeepL key — bypasses Paid tier gate for translation only - Heimdall endpoint: `/validate` (standard across all CF products) --- ## Implemented **`app/tiers.py`** — replaced naive prefix check with real Heimdall validation: - Self-hosted: `LINNET_LICENSE_KEY` → `/v1/licenses/verify` - Cloud mode: `user_id` from `X-CF-Session` → `/admin/cloud/resolve` (requires `HEIMDALL_ADMIN_TOKEN`) - 30-minute in-process cache per (key or user_id) — survives brief Heimdall outages - Network errors do NOT cache (retry on next request) - `require_paid(byok_deepl=True)` skips gate for BYOK translation path **`app/api/sessions.py`** — `POST /session/start` and `GET /session/{id}` now resolve and return `tier` in response **`app/config.py`** — added `HEIMDALL_ADMIN_TOKEN` and `LINNET_LICENSE_KEY` settings **`compose.cloud.yml`** — updated env var docs; clarified that cloud mode uses admin token, not per-instance key **`tests/test_tiers.py`** — 17 tests covering both paths, caching, BYOK bypass, and error handling; all 52 suite tests passing
pyr0ball added this to the Interaction — v1.0 milestone 2026-04-06 13:11:42 -07:00
pyr0ball added the
enhancement
infrastructure
backlog
labels 2026-04-06 13:11:42 -07:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Circuit-Forge/linnet#16
No description provided.