Skip to content

Private Landing v1.5.0

Choose a tag to compare

@vhscom vhscom released this 01 Mar 10:41
· 17 commits to main since this release
1.5.0
c4dd088

🔭 Observability Plugin & Operational Surface

This release introduces a removable observability plugin with structured security event capture, adaptive proof-of-work challenges, an agent-authenticated /ops API for incident response, and a Go TUI for exercising it — all without modifying the core authentication services.


What's New

  • 📡 Structured Event Capture
    Security-relevant actions (login, logout, password change, rate-limit rejection, challenge escalation, agent auth failure) are persisted to a security_event table with actor attribution and fire-and-forget semantics — event emission never blocks authentication (ADR-008)

  • ⚡ Adaptive Proof-of-Work Challenges
    The login endpoint escalates SHA-256 PoW difficulty after repeated failures from the same IP (3+ failures → difficulty 3, 6+ → difficulty 5). Complements rate limiting by raising per-request cost without CAPTCHA infrastructure. Fails open on DB error.

  • 🤖 Agent Identity & /ops API
    Non-human agents authenticate with 256-bit API keys (SHA-256 hashed, not PBKDF2 — high-entropy keys don't need stretching). Trust levels (read/write) enforce least privilege. Provisioning is gated by a separate infrastructure secret. All /ops/* routes cloak behind 404 when the provisioning secret is absent.

  • 🖥️ plctl CLI
    Go TUI (Bubble Tea) for interactive session, event, and agent management via the /ops API. Zero runtime dependency on the Node/Bun toolchain.

  • 🪞 Mirrored Session Service
    createMirroredSessionService decorator ensures SQL visibility for /ops/sessions when cache is the authoritative session store — best-effort SQL mirror never blocks auth (ADR-007)

  • 🔌 Fully Removable
    Delete packages/observability and comment the two [obs-plugin] lines in app.ts to restore the core auth system. CI verifies the core build and tests pass with the plugin removed.


Fixes

  • 🔒 timingSafeEqual length leak closed (OBS-4) — both inputs padded to max length before HMAC comparison, eliminating a timing side-channel that leaked the byte-length of the compared secret
  • 🔒 CLI path traversal (OBS-1) — agent name now escaped with url.PathEscape before URL concatenation
  • 🔒 CLI query injection (OBS-2) — string concatenation replaced with net/url.Values for query parameters
  • 🔒 SELECT * removed (OBS-3)/ops/events uses an explicit column list to avoid auto-exposing future sensitive columns
  • plctl enter key on empty events — no longer panics when pressing enter with no event selected

Documentation

  • ADR-007: session dual-write decision record
  • ADR-008: adaptive challenges, operational surface, agent identity, CLI tooling
  • Security audit (Feb 28, 2026): OBS-1 through OBS-4 findings and remediations
  • STRIDE threat model: observability plugin attack surface added (entries 19–27); repudiation gap (#9) marked mitigated; brute-force residual risk (#13) updated for adaptive challenges
  • 90-day event pruning command documented in ADR-008
  • Stale app.ts line references corrected in threat model and flow diagrams

Test Coverage

  • 426 unit tests, 63 integration tests (489 total)
  • Observability plugin: middleware, router, adaptive flow, config, schema, event processing, agent key auth
  • Mirrored session service: dual-write, consistency, limit enforcement
  • plctl: API client, input handling

Packages (v1.5.0)

  • @private-landing/core
  • @private-landing/infrastructure
  • @private-landing/observability (new)
  • @private-landing/schemas
  • @private-landing/types
  • @private-landing/cloudflare-workers

Intended Use

Private Landing is intended for:

  • Education & learning around modern authentication systems
  • Reference architecture for Cloudflare Workers
  • Bootstrapping custom authentication implementations
  • Security review and discussion

It is not a turnkey production authentication service.


Stability

v1.5.0 is fully backward compatible. The observability plugin ships enabled but is removable — commenting the two [obs-plugin] lines in app.ts disables it. The timingSafeEqual fix is a correctness improvement with no API surface change. All existing tests continue to pass with or without the plugin.