Commit Graph

116 Commits

Author SHA1 Message Date
Anso 2d6b4c233d fix(security): pre-launch security hardening audit & remediation (#320)
- Webhook HMAC: capture raw request bytes via express.json verify callback
  instead of re-serializing with JSON.stringify
- AES-256-GCM: use NIST-recommended 12-byte IV (backward compatible with
  existing 16-byte IVs)
- Node proxy tokens: add 1-year default expiry (previously no expiry)
- Host console env filtering: pattern-based approach blocking SECRET,
  PASSWORD, TOKEN, KEY, CREDENTIAL keywords (previously only 4 explicit keys)
- CORS: deny cross-origin requests when FRONTEND_URL is unset in production
  (previously fell back to allowing all origins)
2026-04-01 20:50:43 -04:00
Anso e1a6db1044 docs: refresh screenshots (#319) 2026-04-01 20:20:01 -04:00
Anso b28ebfa6ff feat(api): add global rate limiter for all API endpoints (#317)
Apply a global rate limit of 100 requests/min per IP to all /api/ routes
in production, configurable via API_RATE_LIMIT env var. Auth endpoints
retain their existing stricter limits which stack independently.
Returns 429 Too Many Requests when exceeded.
2026-04-01 20:12:30 -04:00
Anso 19f9a1c804 docs: refresh screenshots (#316) 2026-04-01 19:50:00 -04:00
Anso 1ab04be235 fix(security): enforce stack name validation on all routes (#314)
Audit found 11 routes with no stackName validation and 2 using a weaker
manual check. All 13 now use the canonical isValidStackName() guard
(^[a-zA-Z0-9_-]+$), returning 400 with { error: 'Invalid stack name' }.
2026-04-01 19:43:11 -04:00
Anso b9680d696d docs: refresh screenshots (#313) 2026-04-01 19:31:58 -04:00
Anso e4c32e4e78 docs: refresh screenshots (#299) 2026-04-01 00:34:45 -04:00
Anso 28c7a8fd54 feat(auto-update): add auto-update policies and fix image update detection (#297)
* feat(auto-update): add auto-update policies and fix image update detection

Auto-Update Policies (Skipper+ tier):
- New scheduled task action type 'update' for check-then-update flow
- Dedicated AutoUpdatePoliciesView with CRUD, cron presets, and run history
- Conditional tier gating: Skipper gets auto-update, Admiral gets full scheduled ops
- Backend executeUpdate: checks digests, pulls only if newer, atomic redeploy

Image Update Detection fixes (all tiers):
- Fix stack name key mismatch: use working_dir label instead of project label
- Add 5-minute periodic frontend polling for background check results
- Replace fixed 3s timeout with polling-based manual refresh via /api/image-updates/status
- Clear update status after successful stack update

* fix(ui): remove Skipper tier badge from Auto-Update Policies header

* fix(ui): remove auto-update action from Scheduled Operations view

Admiral users have a dedicated Auto-Update view — showing update tasks
in Scheduled Operations too was confusing duplication. Each view now
owns a distinct, non-overlapping set of action types.

* fix(auto-update): fix node-stack linking and add All Stacks option

- Stack dropdown now re-fetches when node selection changes using
  fetchForNode, and resets the selected stack
- Node selector moved above stack selector with stack disabled until
  a node is picked
- Added "All Stacks" wildcard option that checks and updates every
  stack on the selected node
- Backend executeUpdate refactored to iterate over all stacks when
  target_id is "*", with per-stack error isolation

* refactor(ui): replace Select dropdowns with searchable Combobox component

Add a reusable Combobox component with inline search and use it for
Node/Stack selectors in both Auto-Update Policies and Scheduled
Operations dialogs. Also fixes node-stack linking bug where changing
node didn't update the stack list.

* fix(ui): resolve CI TypeScript errors in Combobox and ScheduledOperationsView

Add missing searchPlaceholder prop to ComboboxProps interface and remove
dead 'update' action filter that conflicted with the narrowed type union.

* fix(ui): use Geist Sans font in toast component

The toast renders via React portal on document.body, bypassing the app's
font inheritance. Add explicit font-family declaration using var(--font-sans)
to match Sencho's design system.
2026-04-01 00:22:47 -04:00
Anso 8d988d6b08 docs: disable API playground for self-hosted compatibility (#295)
Sencho is self-hosted so the Mintlify "Try it" playground can never
reach a user's instance (CORS + localhost). Switch to "simple" mode
which keeps the endpoint URL/method as a copyable reference without
the misleading Send button.
2026-03-31 18:57:38 -04:00
Anso eae83c997b docs: add OpenAPI 3.1 spec and API Reference tab (#294)
Add a complete OpenAPI 3.1 specification covering ~55 public API endpoints
across 8 categories (Stacks, Containers, API Tokens, Webhooks, Nodes, Fleet,
Scheduled Tasks, Health). Wire it into Mintlify via native OpenAPI rendering
with an interactive "Try It" playground and a dedicated API Reference tab.

Includes an API overview page documenting authentication, token scopes,
node routing, error format, license tier requirements, and WebSocket endpoints.
2026-03-31 16:13:07 -04:00
Anso e587256086 feat(multi-node): warn when configuring remote node with plain HTTP URL (#292)
Show an inline warning banner in the Add Node form when the user enters
an http:// URL, recommending HTTPS or VPN for public internet connections.
HTTP remains fully supported for private networks (LAN, VPN, VPC).

Also returns an optional `warning` field in POST/PUT /api/nodes responses
for API-only consumers, and expands the multi-node security documentation
with concrete deployment guidance (reverse proxy, VPN, private network).
2026-03-31 12:45:07 -04:00
Anso 2d7115e33f docs: refresh screenshots (#291) 2026-03-31 11:02:18 -04:00
Anso 71ce6b3e1b fix(fleet): navigate to editor instead of dashboard on "Open in Editor" click (#289)
The Fleet View's "Open in Editor" button on container rows was navigating
to the dashboard instead of opening the stack in the editor. Fixed by
threading the stackName through the callback chain and using a pending
ref to survive the node-switch effect reset.
2026-03-31 10:45:54 -04:00
Anso 50c29b4248 docs: refresh screenshots (#288) 2026-03-31 10:26:31 -04:00
Anso eccdd1b879 feat(scheduled-ops): add failure notifications, granular targeting, and history export (#286)
- Dispatch error alerts via NotificationService when scheduled tasks fail,
  with info-level recovery notifications when a previously-failing task succeeds
- Per-service restart targeting: scheduled stack restarts can target specific
  services instead of restarting the entire stack
- Prune label filter: scheduled prune operations can be scoped to resources
  matching a specific Docker label
- CSV export button in the execution history panel for one-click download
- Fix: prune_targets was silently dropped on task creation (missing in INSERT)
2026-03-31 09:51:53 -04:00
Anso 633208185d docs: refresh screenshots (#285) 2026-03-30 17:57:19 -04:00
Anso 36ebd5a9c1 fix(docker): upgrade Compose v2.40.3 → v5.1.1 to remediate dependency CVEs (#283)
Compose v2.40.3 was compiled with Go 1.24.9, grpc 1.74.2, and
x/crypto 0.38.0 — all below the minimum safe versions identified
in the March 2026 security audit. Upgrading to v5.1.1 (Go 1.25.8,
x/crypto 0.46.0) resolves CVE-2025-68121, CVE-2025-61726,
CVE-2025-61729, CVE-2026-25679, and CVE-2025-47913.

CVE-2026-33186 (grpc ≥1.79.3) remains unresolved — no upstream
Docker CLI or Compose release includes grpc past 1.78.0 yet.

CVE-2026-33671 (picomatch) and CVE-2026-33747/33748 (buildkit) were
already patched in prior releases.
2026-03-30 17:46:44 -04:00
Anso 20b09b03b1 docs: refresh screenshots (#282) 2026-03-30 17:25:30 -04:00
Anso 3fb6d93a16 docs: refresh screenshots (#279) 2026-03-30 16:57:06 -04:00
Anso b5d3f497cb feat(host-console): gate Host Console behind Admiral tier (#277)
* feat(host-console): gate Host Console behind Admiral tier

Move the Host Console from the Community (free) tier to Admiral,
enforcing the gate at every layer: UI nav visibility, AdmiralGate
wrapper, POST /api/system/console-token endpoint, and the WebSocket
upgrade handler for /api/system/host-console.

* test(auth): mock Admiral license for console-token test

The console-token endpoint now requires Admiral tier. Mock
LicenseService in the test to return pro/team so the happy-path
test passes in CI where no license is activated.
2026-03-30 15:56:58 -04:00
Anso ccf6062473 docs: refresh screenshots (#276) 2026-03-30 12:58:23 -04:00
Anso cd4aa746ab docs: refresh screenshots (#273) 2026-03-30 00:07:43 -04:00
Anso a334d714ce docs: refresh screenshots (#270) 2026-03-29 23:35:26 -04:00
Anso 8eff3fe876 docs: refresh screenshots (#267) 2026-03-29 22:41:01 -04:00
Anso e8c87fdc05 docs: refresh screenshots (#263) 2026-03-29 21:51:18 -04:00
Anso 116f15dae9 fix(stacks): resolve permission denied error on stack deletion (#261)
* fix(stacks): resolve permission denied error when deleting stacks with root-owned files

When Docker Compose creates files as root inside a stack directory, the
non-root Sencho process cannot remove them. This adds a Docker-based
fallback: if fsPromises.rm fails with EACCES/EPERM, Sencho spawns a
short-lived Alpine container to clean up the root-owned files.

Also enhances docker compose down with --volumes --remove-orphans to let
Docker clean up its own resources before filesystem deletion.

* docs: clarify that pre-existing root-owned stacks can be deleted

* fix(stacks): include Docker stderr in fallback deletion error message

Fixes CI lint failure: 'stderr' was assigned but never read in
forceDeleteViaDocker(). Now surfaces Docker stderr output in the error
message when the fallback cleanup fails.
2026-03-29 21:32:05 -04:00
Anso f760ea6563 docs: refresh screenshots (#260) 2026-03-29 20:26:22 -04:00
Anso d586ce393a feat(audit-log): add configurable retention, export, Auditor role, and enhanced filtering (#258)
- Configurable retention: audit_retention_days setting (1-365 days, default 90)
  replaces hardcoded 90-day retention, exposed in Settings > Data Retention
- Export: one-click CSV/JSON export of filtered audit data via new
  GET /api/audit-log/export endpoint (capped at 10,000 entries)
- Auditor role: read-only role with system:audit permission for viewing
  and exporting audit logs without admin privileges (Admiral tier)
- Enhanced filtering: full-text search across summaries/paths/usernames,
  date range picker, and expandable row details showing request path,
  IP address, node ID, and entry ID
2026-03-29 20:18:51 -04:00
Anso c328b7f49a refactor: rename Personal Pro to Skipper and Team Pro to Admiral (#256)
Align paid tier names with Sencho's nautical identity. Internal variant
values ('personal'/'team') remain unchanged in code, database, and
Lemon Squeezy integration — only user-facing display names updated.

- Backend: requireTeamPro → requireAdmiral, TEAM_PRO_REQUIRED → ADMIRAL_REQUIRED
- Frontend: TeamProGate.tsx → AdmiralGate.tsx, TierBadge labels updated
- Website: PricingSection tier names and nautical descriptions
- Docs: all 11 affected pages renamed, nautical footnote added to licensing
2026-03-29 18:00:29 -04:00
Anso 7838d6c32a docs: refresh screenshots (#255) 2026-03-29 17:10:22 -04:00
Anso 8380fbad4b feat(rbac): add Deployer & Node Admin roles with scoped permissions (Team Pro) (#253)
* feat(rbac): add Deployer & Node Admin roles with scoped permissions (Team Pro)

Add intermediate RBAC roles gated to Team Pro tier:
- Deployer: can deploy/restart/stop/start stacks but cannot edit compose files, delete stacks, or access system settings
- Node Admin: full stack and node management within scope, no system settings access
- Scoped permissions: assign roles per-stack or per-node for fine-grained access control
- Permission engine with checkPermission/requirePermission guards replacing requireAdmin on stack/node routes
- Frontend can() function with /api/permissions/me endpoint for client-side permission checks
- User management UI updated with 4-role selector and scoped permission editor
- Documentation updated with permission matrix, scoped permission docs, and screenshots

* fix(rbac): remove unused RoleAssignment import to fix lint error
2026-03-29 17:02:56 -04:00
Anso 37701d5281 docs: refresh screenshots (#245) 2026-03-29 18:50:54 +00:00
Anso 244c83a0c3 feat(registries): add private registry credential management (Team Pro) (#240)
Add centralized credential storage for private Docker registries with
support for Docker Hub, GHCR, AWS ECR, and self-hosted registries.

- New `registries` table with AES-256-GCM encrypted secrets
- RegistryService with CRUD, test connectivity, Docker config generation
- 5 API endpoints gated by requireTeamPro + requireAdmin
- ComposeService injects credentials via temp DOCKER_CONFIG on deploy/pull
- ImageUpdateService passes stored credentials for private registry checks
- AWS ECR just-in-time token refresh via @aws-sdk/client-ecr
- RegistriesSection UI in Settings Hub with type-aware form
- Documentation with screenshots
2026-03-29 12:56:30 -04:00
Anso 362b4a43d0 docs: refresh screenshots (#239) 2026-03-29 07:17:18 +00:00
Anso b7e7ee8f55 feat(ui): redesign top bar with three-zone navigation layout (#237)
Replace flat row of 10 individual buttons with a structured three-zone
layout: node context pill (left), animated navigation group (center),
and utility actions (right). Uses the Highlight component from
animate-ui for a spring-animated sliding indicator between nav items.

Responsive: icon+text labels at xl, icons-only at md, sheet drawer
for mobile. Navigation is data-driven via a permission-aware array
that conditionally includes admin and Team Pro items.
2026-03-29 03:04:31 -04:00
Anso 40c09cce23 docs: refresh screenshots (#236) 2026-03-29 05:33:10 +00:00
Anso 330eec4bff fix(scheduled-ops): audit log text, run attribution, prune targets, and pagination (#234)
- Fix "Run Now" audit log showing "Created scheduled task" instead of "Triggered scheduled task" by adding wildcard-based route matching with specificity sorting
- Add triggered_by column to track whether runs were started by the scheduler or manually via Run Now
- Add configurable prune targets (containers, images, networks, volumes) with checkbox UI
- Add pagination to execution history with offset-based navigation
- Document Run Now behavior on disabled tasks and add screenshots
2026-03-29 01:01:45 -04:00
Anso e756620e29 docs: refresh screenshots (#233) 2026-03-29 04:05:40 +00:00
Anso 31e1795af0 feat(scheduled-ops): add scheduled operations for Team Pro users (#231)
Adds the ability to schedule recurring Docker operations (stack restarts,
fleet snapshots, system prunes) via cron expressions with full execution
history logging. Includes Run Now for on-demand execution.
2026-03-28 23:56:37 -04:00
Anso 89c4a9cb77 docs: refresh screenshots (#230) 2026-03-29 02:19:35 +00:00
Anso 5b607de227 fix(api-tokens): harden scope enforcement and block sensitive endpoints (#228)
* fix(api-tokens): harden scope enforcement and add expiration support

- Fix deploy-only allowlist to match actual routes (deploy, down, restart,
  stop, start, update) instead of non-existent /up, /pull, /compose/* paths
- Block API tokens from auth-sensitive routes (password change, node token
  generation) that bypass scope enforcement middleware
- Add WebSocket scope enforcement: read-only/deploy-only tokens can only
  access logs and notifications, not host console or container exec
- Prevent API token self-replication: tokens cannot create, list, or revoke
  other tokens regardless of scope
- Map deploy-only tokens to admin role so they pass requireAdmin on deploy
  routes (scope middleware still restricts which endpoints they can reach)
- Add optional token expiration (30, 60, 90, 365 days or no expiry)
- Add token name length validation (max 100 characters)
- Surface fetchTokens errors in frontend instead of swallowing silently
- Fix docs: correct deploy-only scope description and GitHub Actions example

* fix(api-tokens): block all sensitive management endpoints from API tokens

User management, SSO configuration, node management, license management,
and console access are now human-session-only. Add comprehensive unit
tests for scope enforcement, blocked endpoints, expiration, and revocation.

* fix(api-tokens): fix TS18048 possibly-undefined in test
2026-03-28 22:14:22 -04:00
Anso 26c74f2aad docs: refresh screenshots (#227) 2026-03-28 21:29:56 +00:00
Anso 133ea0e9ab docs: refresh screenshots (#226) 2026-03-28 21:19:49 +00:00
Anso 954994cdc0 fix(api-tokens): harden scope enforcement and add expiration support (#224)
- Fix deploy-only allowlist to match actual routes (deploy, down, restart,
  stop, start, update) instead of non-existent /up, /pull, /compose/* paths
- Block API tokens from auth-sensitive routes (password change, node token
  generation) that bypass scope enforcement middleware
- Add WebSocket scope enforcement: read-only/deploy-only tokens can only
  access logs and notifications, not host console or container exec
- Prevent API token self-replication: tokens cannot create, list, or revoke
  other tokens regardless of scope
- Map deploy-only tokens to admin role so they pass requireAdmin on deploy
  routes (scope middleware still restricts which endpoints they can reach)
- Add optional token expiration (30, 60, 90, 365 days or no expiry)
- Add token name length validation (max 100 characters)
- Surface fetchTokens errors in frontend instead of swallowing silently
- Fix docs: correct deploy-only scope description and GitHub Actions example
2026-03-28 17:15:05 -04:00
Anso 88cd1fe571 docs: refresh screenshots (#223) 2026-03-28 19:49:42 +00:00
Anso 618647ffc2 docs: refresh screenshots (#222) 2026-03-28 19:42:51 +00:00
Anso 8d8118c963 feat(api-tokens): add scoped API tokens for CI/CD automation (Team Pro) (#220)
Add long-lived API tokens with three permission scopes (read-only,
deploy-only, full-admin) for CI/CD pipelines, scripts, and automation.

- Database: api_tokens table with SHA-256 hashed storage
- Auth: extend middleware to authenticate Bearer API tokens
- Scope enforcement: middleware restricts actions per token scope
- API: CRUD endpoints gated behind Team Pro + admin
- UI: ApiTokensSection in Settings Hub with create/revoke/copy flows
- Docs: new api-tokens.mdx with usage examples and screenshots
2026-03-28 15:37:54 -04:00
Anso e2da1bf43d docs: refresh screenshots (#219) 2026-03-28 08:42:47 +00:00
Anso 7294d9c6ba docs: refresh screenshots (#218) 2026-03-28 08:27:58 +00:00
Anso f99abe907d fix(license): default 14-day trial to Personal Pro instead of Team Pro (#216)
Trial users now get Personal Pro features only. Team Pro features
(SSO, audit log, unlimited accounts) require a Team Pro license.
2026-03-28 04:23:28 -04:00