feat(mqtt): MQTT subscription management in the instance console#2
Merged
Conversation
Adds an "MQTT" tab to the instance console that manages an Arc instance's MQTT ingest subscriptions. Arc owns all state; Launchpad drives Arc's /api/v1/mqtt/* API through the existing instance proxy — no new Launchpad tables or routes. - ArcClient: MQTT types + methods (health, list/get/create/update/delete, start/stop/pause/restart, stats). Passwords are write-only; reads expose only has_password. id path segments are encodeURIComponent'd. - MqttSubscriptions.svelte: list with live stats + status badges, create/edit dialog (broker/topics/QoS/database/auth/TLS/topic-mapping/tuning), lifecycle actions, disabled-MQTT and no-access empty states, edit-while-running guard. - Console: new MQTT tab between Alerts and Tokens. Proxy hardening (default-closed authorization): - The proxy injects the instance admin token, so every proxied request is admin-privileged on Arc. Plain members are now restricted to a read-only allowlist (query/databases/measurements/metrics/logs/health); everything else — all mutations and admin routes (mqtt, retention, delete, rbac, backup, tokens, …) — requires org owner/admin. New Arc admin routes are locked down by default rather than viewer-reachable. - Paths are canonicalized (collapse //, resolve ./ and ../, lowercase) BEFORE the role check, matching how Arc normalizes, so slash/dot spellings can't smuggle an admin path past the gate. Client-side role gating in the component is UX only; the proxy check is authoritative. Verified end-to-end against a mock Arc: owner full CRUD+lifecycle, viewer blocked on every admin path and normalization-bypass variant (403) while retaining read/query access. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Security (HIGH):
- Remove api/v1/logs from the member read allowlist — Arc guards it with
withAdminAuth (it leaks SQL, internal IPs, tokens), so a viewer must not
reach it through the proxy's injected admin token. Verified each allowlist
entry against Arc's actual per-route auth (databases GET/measurements/query/
metrics are non-admin; logs is admin-only). Owners/admins still reach logs.
- Forward the CANONICAL path (the one we authorize) upstream instead of the
raw params.path, so the gated string and the routed string are byte-identical
— closes any residual raw-vs-canonical normalization gap.
Component correctness:
- parseTopicMapping: split on the LAST '=' (a database name can't contain '=',
but a topic legally can) — fixes silent topic/db corruption for '='-topics.
- parseTopics: newline-only (a comma is a legal topic char) + de-dupe to avoid
double-subscribe on copy-paste.
- toInt: strict digits-only parse — reject "60abc"/"1e9"/"1.5"/"0x10" (parseInt
silently truncated these, sending values the user never intended) → fallback.
- arcClient: get/create/update/stats now throw on a malformed (missing-key) 200
instead of returning undefined typed as the interface.
UX regression from the proxy tightening:
- Retention / Continuous Queries / Tokens tabs now show a clean "Admin access
required" message to viewers instead of a raw {"error":"Forbidden"} banner.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
xe-nvdk
pushed a commit
that referenced
this pull request
Jul 10, 2026
Bump package + Helm chart to 0.2.0 for the release. Highlights since v0.1.2: - Security hardening: auth, SSRF (byte-level guard + DNS pinning), secrets, multi-tenant proxy authorization (#1) - MQTT subscription management in the instance console (#2) - Private/localhost Arc endpoints: actionable error + docs + opt-in flag (#3) - Fix connecting to a local/private Arc: legacy schema migration + dual-stack IP fallback (#4) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an MQTT tab to the instance console for managing an Arc instance's MQTT ingest subscriptions. Ports the MQTT management capability from Arc into Launchpad. Arc owns all state (its own SQLite, lifecycle, AES-encrypted passwords); Launchpad drives Arc's
/api/v1/mqtt/*API through the existing instance proxy — no new Launchpad tables or routes.src/lib/arcClient.ts): MQTT types + methods — health, list/get/create/update/delete, start/stop/pause/restart, stats. Passwords are write-only (reads expose onlyhas_password);idpath segments areencodeURIComponent'd.MqttSubscriptions.svelte: list with live stats + status badges, create/edit dialog (broker, topics, QoS, database, auth, TLS, topic→db mapping, tuning), lifecycle actions, disabled-MQTT + no-access empty states, edit-while-running guard, numeric-field coercion.Proxy hardening (default-closed authorization)
The proxy injects the instance admin token, so every proxied request is admin-privileged on Arc. This PR flips the proxy to default-closed:
query,databases,measurements,metrics,logs,health); everything else — all mutations and admin routes (mqtt,retention,delete,rbac,backup,tokens, …) — requires org owner/admin. New Arc admin routes are locked down by default instead of viewer-reachable.//, resolve./and../, lowercase) before the role check, matching how Arc (fasthttp) normalizes — soapi/v1//mqttorapi/v1/./mqttcan't smuggle an admin path past the gate.Test plan
npm run check— 0 errors; production build succeeds/api/v1/mqtt/*contract, with real Launchpad session cookies:has_password:true), start → stats (live counters) → start-again 409, delete → 404, duplicate-name 409mqttlist/create/start,retention,delete,rbac,backup) and on normalization-bypass variants (//mqtt,./mqtt,mqtt/../mqtt); retains GET reads + POSTquery; POST to a read path (databases) correctly 403//mqttvariant (200)Notes
[mqtt] enabled = true) — the tab detects the disabled state and shows guidance.ARC_ENCRYPTION_KEYon the Arc side; the UI surfaces Arc's error if unset.🤖 Generated with Claude Code