14 Commits
Author SHA1 Message Date
Juan Denis 6296887bad Remove internal plan citations from app code
Comments, docstrings and a few strings cited plan numbers ("plan 29
#9", "plan 86 §B2") from a git-ignored folder, so they pointed at
nothing; one reached users in a bottleneck hint. Code and frontend
strings are unchanged apart from those citations (checked by AST and
token comparison). A vhost still carrying the old asset comment reads
as undrifted, and a guard test keeps new citations out.
2026-10-10 15:50:45 -04:00
Juan DenisandClaude Fable 5 0e60a0c2b2 chore: drop the imports the door migrations orphaned
Twenty-one imports whose last caller left during the plan-76/77 sweeps:
mostly 'import subprocess' in services now routed through the shared
runners, plus time/requests in the CachedRemoteIndex adopters, threading
in agent_gateway, os in api/system, User in api/bandwidth, run_privileged
in nginx_advanced_service, and the dead SENSITIVE_SETTING_PARTS alias in
audit_service (zero importers). Each removal AST-verified unused before
deletion; all modules compile and the app factory boots.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 10:10:40 -04:00
Juan DenisandClaude Fable 5 00eac38d5d feat(realtime): one room grammar + mirrored event constants (plan 77 E3)
app/sockets_rooms.py owns every Socket.IO room-name builder (the grammar
lived in ~25 scattered f-strings); app/constants.py SOCKET_EVENTS is
mirrored verbatim by frontend/src/constants/events.js and a contract
test parses the JS so a renamed event fails in CI instead of silently
killing a stream. sockets.py / agent_gateway / notification bus and the
two frontend components that hand-derived rooms now use the builders;
ratchet forbids new room f-strings in the realtime layer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 04:58:49 -04:00
Juan DenisandClaude Fable 5 745bc2b5d9 refactor(agent): transport-neutral handshake + state ingest doors (plan 77 A2)
agent_registry.authenticate_and_register owns the full handshake
(rate-limit -> HMAC -> allowed-IPs/anomaly -> new-IP -> version ->
register) and ingest_agent_state owns heartbeat/sysinfo/capability
side-effects; the WS namespace and long-poll endpoints become thin
adapters translating error codes to emit/disconnect vs jsonify/status.
The per-IP auth limiter moves to the registry (re-exported from the
gateway for existing callers/tests). Gate: parametrized ws/poll matrix
(bad HMAC, blocked IP, rate limit, new-IP anomaly) + a word-anchored
ratchet that the adapters never re-grow the sequence.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 02:04:29 -04:00
Juan DenisandClaude Fable 5 99d1c86ebb fix(agent): tunnel reconcile fires on both transports (plan 77 A1)
The WireGuard tunnel-reconcile hook lived only in the WS on_capabilities
handler, so an agent connected via the long-poll fallback never
self-healed its tunnels after a restart. Move the hook into
agent_registry.update_capabilities — the ingest path both transports
already share — and prove it with poll-path + registry-path tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 01:42:13 -04:00
Juan Denis 5fd04bbfb0 Add review rules and proxy/auth docs
Introduces a new `.coderabbit.yaml` with ServerKit-specific review guardrails, and expands env/security documentation for trusted proxy headers and per-IP login brute-force throttling. It also adds inline backend notes clarifying `request.remote_addr` behavior under ProxyFix for auth, cron, and pairing paths, and updates the frontend plugin manifest to remove the Tramo and K8s plugin entries.
2026-07-18 01:23:47 -04:00
Juan DenisandClaude Opus 4.8 e6bf4915b4 refactor(remote-access): extract WireGuard-tunnels backend into extension
Plan 47 Phase 2. The tunnels blueprint + broker/publish/netutil services move
into builtin-extensions/serverkit-remote-access/backend/ (entry_point tunnels:
tunnels_bp, url_prefix unchanged). Core no longer registers /api/v1/tunnels or
imports the services; the Tunnel/ExposedService models stay core (G2).

New reusable core->extension seam get_installed_extension_attr(slug, module,
attr): the agent gateway reaches TunnelBrokerService.schedule_reconcile through
it, so tunnel self-heal still fires when the extension is installed and no-ops
cleanly otherwise. Backend re-acquisition on upgrade is covered by the Phase-2
migration.

Tests: test_tunnel_netutil.py + test_tunnel_reconcile.py re-homed into
test_remote_access_extraction.py (17), which installs the extension and runs the
helpers/reconcile against its modules.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 22:27:02 -04:00
Juan DenisandClaude Opus 4.8 7cf8d4e18a feat(remote-access): NAT-traversing WireGuard tunnels to expose private services
Self-hosted tunneled reverse proxy: a service on a NAT'd host (e.g. a home
Jellyfin box) gets a public HTTPS hostname with no port-forwarding, by pairing
two agents over WireGuard. Implements Phases 0-3 of docs/REMOTE_ACCESS_ROADMAP.md.

Agent (Go):
- new internal/wireguard package: Manager interface + kernel backend (wg/ip)
  and a userspace netstack backend (wireguard-go + gVisor) so Windows/macOS
  peers need no driver/admin; in-process keygen returns only the public key
  (private keys never leave the host)
- wireguard:keygen/interface/peer/status/forward/unforward + firewall
  :allow_port/:deny_port commands; wireguard + firewall capability probes
- TCP forwarder (tnet.ListenTCP / net.Listen -> dial localhost) carries
  traffic to the real service behind a netstack peer

Backend (Python):
- Tunnel + ExposedService models; tunnel_netutil (subnet allocator, health);
  tunnel_broker_service (keygen->up->peer->verify, firewall open, reconcile-on-
  reconnect); tunnel_publish_service (forward -> nginx -> DNS -> auth -> cert)
- nginx remote-upstream vhost (WebSocket + proxy_buffering off)
- /api/v1/tunnels CRUD + /<id>/services publish/unpublish
- panel-authoritative reconcile hooked into the agent gateway on reconnect

Frontend (React):
- Remote Access page (tunnels + exposed services, status, teardown) and an
  "Expose a Local Service" wizard; new services/api/tunnels.js

Verified: go build (win/linux) + vet + go tests (forwarder + no-leak parsers);
py_compile + pytest (netutil, reconcile, nginx template); create_app boot;
eslint + npm run build. Live multi-host run pending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 23:20:00 -04:00
Juan DenisandClaude Opus 4.8 a01ccc4aee fix(agent): fail-closed agent registration + surface stuck-command errors
Two correctness defects from the deep-dive review.

B. register_agent left a stale in-memory "online" entry when the DB write
   failed. The except block rolled back the session but kept the
   ConnectedAgent in _agents, so the gateway still emitted auth_ok and
   command routing targeted an agent with no backing AgentSession row
   (online/offline desync). register_agent now returns Optional[str]: on DB
   failure it removes its own in-memory entry (guarded on identity so a
   concurrent reconnect isn't clobbered) and returns None. Both callers —
   the WS gateway (on_auth) and the poll /connect endpoint — now emit
   auth_fail / HTTP 500 instead of reporting a connected agent. A stale
   'online' server row with no in-memory agent is self-corrected by the
   heartbeat reaper.

C. send_command swallowed the final command-record DB update on the
   timeout/result path: a failed commit left the row stuck in 'running'
   with no log line, making it invisible. Now logs the exception (the row
   is still left for a future sweep, but it's now diagnosable).

Adds a regression test that register_agent returns None and rolls back the
in-memory registration when the session write fails.

Full backend suite: 89 passed, 12 skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 16:08:13 -04:00
Juan DenisandClaude Opus 4.8 9867380737 fix(agent): harden gateway — locked rate limiter, safe stream/ack, nonce ordering
Cluster of lower-severity agent-gateway defects from the deep-dive review.

agent_gateway.py:
- _check_auth_rate_limit was an unlocked read-modify-write of a module dict
  under async_mode='threading' (on_auth + poll /connect race it), and the
  dict grew without bound from one-off IPs. Now guarded by a threading.Lock
  with a periodic sweep that drops aged-out buckets.
- on_stream crashed with AttributeError on a malformed/partial frame with a
  null/non-string channel (precisely what the poll fallback exists to
  tolerate). Guard the channel type and the container_id split; drop the
  bad frame instead of killing the handler.
- on_credential_update_ack swallowed exceptions without db.session.rollback(),
  leaving a poisoned SQLAlchemy session for the next user on the worker.
- Replaced all print() with module logging (info/warning/exception), so
  auth/IP-block/rotation events are level-controllable and structured.

agent_registry.verify_agent_auth:
- Consume the replay nonce ONLY after the HMAC signature is verified.
  Previously the nonce was recorded first, so a forged request (valid
  agent_id+prefix+nonce, bogus signature) burned the nonce and locked the
  real agent out when it next presented it. Reordered; added a regression
  test (test_failed_signature_does_not_consume_nonce).
- Fixed the misleading "5 minute window" comment (the check is 60s) and
  documented that the 60s window is the only replay guard for the nonce-less
  HTTP-poll transport.

NOT changed (deliberately, to avoid breaking agents):
- Nonce is left optional. The HTTP-poll transport signs agent_id:timestamp
  with no nonce (auth.Sign, "nonce":""); requiring it would lock out every
  poll-fallback agent. Making it mandatory needs a coordinated Go-agent
  change and is tracked in SECURITY.md.
- Per-message session-token validation remains a documented TODO; it
  requires a protocol change on both the Go agent and backend.

Full backend suite: 84 passed, 12 skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 15:34:50 -04:00
Juan Denis a93697c7f6 Add agent capability probing and reporting
Probe and report agent feature capabilities (cron, docker, systemd, nginx, etc.) so the panel can gate target pickers without extra round-trips.

Key changes:
- Add agent/internal/capabilities: probes host for features and platform/distro, returns protocol.CapabilitiesMessage cached at agent startup.
- Agent: store probed capabilities, send them on every transport reconnect (sendCapabilities) and include them when using poll transport.
- Protocol: introduce TypeCapabilities and CapabilitiesMessage (map[string]bool + platform/distro fields).
- Poll transport: accept CapabilitiesMessage in Send(), serialize to raw payload and queue for next /poll; support one-shot capabilities in poll body.
- Backend: handle capabilities from socket (on_capabilities) and poll endpoint; persist capabilities in in-memory ConnectedAgent (agent_registry) with helpers get_capabilities/has_capability; include capabilities/platform info in servers API.
- New fleet API (GET /api/v1/fleet/targets): list runnable targets (local + connected agents) and optionally filter agents by a requested feature using the advertised capability map.

Rationale: make agent feature availability explicit and discoverable to the panel so UI pickers can show only applicable agents without asking agents on every UI interaction.
2026-05-01 00:37:48 -04:00
Juan Denis f6f08ae9d1 Fleet monitor + security and agent hardening
Adds cross-server Fleet Monitor endpoints and models, plus broad security and robustness improvements across agent, backend, and tooling.

Key changes:
- New fleet monitor API (endpoints for heatmap, comparison, alerts, thresholds, anomalies, forecast, search, exports, and Prometheus) and service skeleton.
- New DB models for ServerAlertThreshold and MetricAlert to support metric alerts.
- Agent discovery/registration hardening: HMAC-signed discovery requests, signature/timestamp validation, minimal discovery responses, HMAC-based unregister headers, and enforced command timeout cap in agent command handling.
- WebSocket and agent client TLS handling gated by SERVERKIT_INSECURE_TLS env var; added auth rate limiting on agent gateway.
- Docker-compose: parameterize agent image via AGENT_VERSION and avoid running as root by adding docker group access.
- Backend security & policy: tightened CSP script/style sources, request size limit, 2FA pending-token rejection on non-2FA endpoints, registration flow/guards, admin-only SSO admin routes via middleware, rate limits on sensitive endpoints, and logging for auth/2FA events.
- Database service hardening: identifier validation, avoid passing passwords on CLI (use env vars), safer subprocess usage, and docker exec handling improvements.
- CronService: command validation to prevent shell injection and run commands without shell=True; build_service and other subprocess usages updated similarly.
- Misc: .env.example notes clarified for encryption key generation, invitation token generation improved, agent registry timestamp window reduced, various logging and input validations added, frontend FleetMonitor page and styles stubbed in, and Vite/config/style updates.

Overall this commit implements fleet monitoring scaffolding and a set of security, validation, and operational improvements to make agent discovery, registration, command execution, and backend services safer and more robust.
2026-03-23 01:58:28 -04:00
Juan Denis bca7e29b57 Implement security features: key rotation, IP allowlist, anomaly detection
Adds API key rotation, IP allowlisting, anomaly detection, and replay protection to the ServerKit agent system. Backend changes include new endpoints, models, and services for security alerts, nonce tracking, and anomaly detection, as well as updates to the server model and agent authentication logic. The agent now supports credential rotation and replay protection via nonces. Frontend updates add UI and API methods for managing allowed IPs, viewing security alerts, and rotating API keys. Documentation and environment setup instructions are included.
2026-01-22 18:11:22 -05:00
Juan Denis 009fb12435 Add multi-server management and agent gateway
Introduces backend models, API endpoints, and services for remote server and agent management, including WebSocket agent gateway, server CRUD, metrics, command history, and remote Docker operations. Updates frontend to support server listing, detail pages, and related UI components and styles.
2026-01-21 22:47:42 -05:00