mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-07-26 11:49:16 +00:00
c01f2479b94b2214a949ae736a3c5141cc52b5be
28 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c01f2479b9 |
fix(ui): lower-overhead Reduced effects for constrained GPUs (#1616)
* fix(ui): lower-overhead Reduced effects path for constrained GPUs Disable backdrop-filter glass and solidify chrome fills when data-effects is reduced (Calm default), with Appearance warning and docs for constrained rendering devices. Related to #1614. * test(ui): harden Reduced effects glass e2e and docs wording Parse Color Level 4 slash alpha so opacity asserts are not vacuously true, cover dialog/toast/overlay both ways with stable data-sn hooks, and soften troubleshooting copy that overstated the unmeasured diagnosis. * docs(ui): lead constrained-GPU guidance with Reduced Motion Rename the troubleshooting section to neutral GPU framing, point Appearance and docs at Reduced Motion first, and show the callout whenever Motion is off so Calm or Reduced effects alone do not hide the validated workaround. |
||
|
|
e12602091a |
fix: repin semver compose tags during fleet self-update (#1587)
* fix: repin semver compose tags during fleet self-update Fleet updates failed when docker-compose.yml pinned a semver tag because recreate reused the on-disk pin. Pull the target image first, rewrite semver pins via the update helper, and block digest or unresolved pins with fast 409s. * fix: update OFFLINE_META shape in capability and node-registry meta tests |
||
|
|
cd9247db1e |
docs: retire the public-beta label and document v0.92.0 capabilities (#1398)
Sencho exits public beta after a clean v0.92.0 QA pass. Replace the global "public beta on the path to v1.0" callout with scoped maturity language across the README, KNOWN_LIMITATIONS, quickstart, troubleshooting, upgrade, and the security-architecture reference. The copy stays honestly pre-1.0 and avoids a blanket "stable" claim. Reframe the Scale limitations to credit QA, audit, and end-to-end validation while keeping the honest caveat that large-scale performance is not yet benchmarked. Fold the new v0.92.0 capabilities into the README sections: Compose Doctor preflight checks, health-gated updates with stalled-update recovery, file move/rename in the explorer, ordered multi-file Compose for Git sources, the Security overview, on-demand node-wide scans, the Compose network inspector with an exposure-intent guard, scan policy packs, documentation-drift flags, and configurable image-update cadence with registry/source links. |
||
|
|
ce08a593d7 |
feat(settings): reorganize the settings hub into domain groups (#1321)
* refactor(settings): split System Limits and regroup the hub System Limits had grown into a grab-bag of host alert thresholds, Docker cleanup, and mesh data-plane controls under one mislabeled section. Split it into Host Alerts, Docker & Storage, and Fleet Mesh, and split Developer into Developer Diagnostics and Data Retention. Reorganize the sidebar into ten domain groups: Personal, Access, Infrastructure, Monitoring, Notifications, Automation, Organization, Security, Operations, Help. Each section now saves only its own keys, so a concurrent edit in one section no longer clobbers another. Data Retention sends the audit-log window only on a paid plan, matching the field's existing visibility, so a Community save no longer fails on a key the operator cannot set. NumberChip moves to a shared module and the toggle reuses the existing shared component. The /settings API is unchanged. * test(settings): cover registry structure and per-section save payloads Add structural invariants for the ten-group registry (every item maps to a real group, ids are unique, the System Limits and Developer splits land in the right groups with the right gates, renamed labels and the Registries paid gate hold) and per-section payload tests asserting each split section patches only its own keys, including the Community path where Data Retention omits the paid audit-log key. * docs(settings): document the regrouped settings hub Rewrite the settings reference for the ten-group layout, replace the System Limits page with Host Alerts, Docker & Storage, and Fleet Mesh, and document the prune-on-update, reclaimable-space banner, and mesh auto-recreate settings that were previously undocumented. Update the Settings navigation breadcrumbs across the feature docs and refresh the affected screenshots. * fix(settings): show Access sections as instance-global, not operator-scoped License, Users, SSO, and API Tokens are instance-global settings but the masthead scope label rendered them as operator-scoped because it keyed off the old Identity group. Only Personal sections (account, appearance) are operator/browser-scoped now; everything else reads as global. Also add a compile-time exhaustiveness guard to the section switch so a future SectionId added without a matching case fails the build instead of silently rendering a blank panel. * docs(settings): remap remaining settings breadcrumbs to the new groups Update the navigation breadcrumbs that still pointed at the removed Identity, Alerts, and Advanced groups: API Tokens and Users now sit under Access, Webhooks under Automation, Labels under Organization, App Store under Infrastructure, Appearance under Personal, and scan policies under Security > Vulnerability Scanning. Correct the settings reference scope note so Access reads as global. * docs(settings): remap renamed-section breadcrumbs across feature docs Sweep every feature, operations, getting-started, and reference page for navigation paths that still named the renamed settings sections, and point them at the current ones: Security becomes Security > Vulnerability Scanning, Notifications becomes Notifications > Channels, Routing becomes Notifications > Notification Routing, and Developer becomes Operations > Developer Diagnostics (with its retention windows under Operations > Data Retention). App Store moves under Infrastructure and the four-group overview in the getting-started intro is rewritten to the ten groups. Separators each page already used are preserved. |
||
|
|
865d792874 |
feat(pricing): collapse to two tiers (#1309)
* feat(pricing): collapse to two tiers (Community + Admiral) Collapse Sencho's pricing from three tiers (Community / Skipper / Admiral) to two: a generous free Community tier and a single paid Admiral tier. The Skipper tier is removed. Now free in Community: auto-heal, auto-update, scheduled operations, webhooks, notification routing, Fleet Actions and bulk operations, SSO preset providers (Google / GitHub / Okta), unlimited users with admin and viewer roles, and deploy safety (atomic deploys, auto-rollback, and one-click rollback). Admiral (paid) is focused on running and governing a fleet: blueprints, Fleet Secrets, deploy enforcement, vulnerability report export, audit log, host console, private registries, mesh networking, node cordon, managed cloud backup, LDAP / Active Directory SSO, and the advanced RBAC roles (deployer, node-admin, auditor) with per-resource scoped assignments. Internally the license variant distinction is removed so tier is binary (community / paid). License validation still verifies the Lemon Squeezy store and product before granting paid status. Docs and the contributor guide are updated to the two-tier model. * docs(pricing): correct licensing page to two-tier pricing and tidy stale tier wording The licensing docs page kept the old Admiral pricing plus a Founder Lifetime column and an Enterprise paragraph after the two-tier collapse. Update it to $12/month or $99/year, drop the lifetime and Enterprise content, and link to the pricing page for current pricing. Also fix stale "Skipper" wording in CLA.md, SUPPORT.md, one test title, and three test comments. Historical CHANGELOG entries and the retired-Skipper license-guard test are intentionally left as-is. * docs: align licensing and SSO pages with the two-tier model Correct the SSO overview so the Google, GitHub, and Okta presets read as available on every tier, matching the provider table; only LDAP and Active Directory require Sencho Admiral. Remove the lifetime-plan references from the licensing, settings, and troubleshooting pages so they reflect subscription-only Admiral pricing. * fix(rbac): omit scoped permissions from /me on the Community tier Scoped role assignments only take effect on the paid tier, but GET /api/permissions/me returned them unconditionally, so a downgraded instance with leftover assignments rendered per-resource affordances the API then rejected with 403. The endpoint now mirrors the permission middleware and includes scoped permissions only on the paid tier. Adds a regression test covering the downgrade case. * docs: use custom-pricing wording on the contact page The two-tier model has no Enterprise tier; reword the contact page's enterprise pricing/deals to custom pricing/deals so it does not imply a tier that no longer exists. |
||
|
|
02f98ab90a |
docs: add recovery guide and link it from README, quickstart, and troubleshooting (#1283)
Add a consolidated Recovery page that answers "what do I do if Sencho breaks?" in one place. It covers getting back to a working state when Sencho itself fails, a stack deploy fails, an admin is locked out of sign-in, Docker is unavailable, or a remote node is unreachable, and summarizes each path with a link to the authoritative detail page rather than duplicating it. The page opens by stating the core safety fact: Sencho keeps its state in DATA_DIR and COMPOSE_DIR and treats compose files on disk as the source of truth, so recovery is mostly file-level and running containers are unaffected by a Sencho outage. It points to Backup & Restore as the prerequisite. Link the guide from the README documentation section, the quickstart "where to next" cards, and the top of the troubleshooting page. |
||
|
|
f32b6372a1 |
docs: pre-1.0 readiness pass for public beta launch (#1225)
Close the trust-blocking items from the pre-v1.0 readiness audit so the repository is ready for the first public posting. No backend or frontend code changes; no tier gates move. README: - Add a single beta-status GitHub [!NOTE] callout below the dashboard image. Beta status also appears in selected install-flow docs (Quickstart, Known Limitations, Security Architecture, Upgrade, Troubleshooting) so install-flow readers are not surprised. - Add a "Before you install" subsection that names the docker.sock privilege model with the Portainer / Dockge / Komodo comparison. - Fix the docker run example: add the missing /opt/docker:/opt/docker mount that COMPOSE_DIR=/opt/docker depends on. - Reword the two "no exposed Docker socket" sentences so the claim is scoped to remote / cross-node exposure. - Reword "transparent HTTPS proxy" to "authenticated HTTP and WebSocket proxy" with a TLS / VPN reminder. - Fix the RBAC bullet: the role set is admin, viewer, deployer, node-admin, auditor. There is no "editor" role. - Add tier markers to the Capabilities list (matrix sentence plus per-bullet (Skipper) / (Admiral) markers), verified against the route guards in backend/src/routes/. - Fix the broken notification-routing link to point at the existing alerts-notifications#notification-routing anchor. - Soften the BSL paraphrase to point at LICENSE plus the license FAQ. - Add a "Telemetry and data handling" section: no telemetry, no analytics, no crash reports; license validation only when a paid key is activated. - Add a "What Sencho is not (yet)" section so the scope boundaries are visible above Capabilities. Templates: - PR template: drop the contradictory CHANGELOG checkbox; release-please owns CHANGELOG. - Bug report template: update the stale 0.2.2 version placeholder to 0.86.6 and add fields for compose snippet, container logs, browser console, and an involved-subsystems checkbox. Docs: - docs/operations/trivy-setup.mdx: replace both sencho/sencho:latest occurrences with the published image saelix/sencho:latest. - docs/reference/settings.mdx: rewrite the API Tokens Note (no tier gate in code; admin role only) and the Stack Labels Note (basic CRUD is free; only bulk actions require Skipper or Admiral). - Add the shared beta-status Note callout to docs/getting-started/ quickstart.mdx, docs/operations/upgrade.mdx, docs/operations/ troubleshooting.mdx, and docs/reference/security.mdx. CONTRIBUTING: - Replace the public link to the in-repo coding-rules file with a pointer to docs.sencho.io for architecture deep-dives. - Fix the sample clone URL case (Sencho.git becomes sencho.git). New files: - SUPPORT.md: where to ask, response-time expectations, in / out of scope. - KNOWN_LIMITATIONS.md: scale, platform, architecture, and feature limits documented for the beta audience; scale numbers marked "not benchmarked yet" pending real benchmarking. |
||
|
|
66b84932e0 |
feat(notifications): move Notification Routing to Skipper tier (#1145)
* feat(notifications): move Notification Routing to Skipper tier Notification routing is automation (route alerts to channels by rules), not enterprise compliance. Aligning the gate with Skipper makes the tier boundary read consistently with the rest of the automation surface (webhooks, auto-update, auto-heal, scheduled tasks). Backend: requireAdmiral -> requirePaid on the five /api/notification-routes endpoints. Dashboard configuration-status now exposes the routing-rules row to any paid tier. Frontend: settings registry tier flipped to skipper; the Admiral wrapper around NotificationRoutingSection is removed (the inner CapabilityGate stays, preserving forward-compat with older remote nodes). Tests: added a tier-enforcement describe block covering Skipper (200) and Community (403 PAID_REQUIRED on all five endpoints). Docs: refreshed alerts-notifications, licensing, overview, dashboard, troubleshooting, and reference/settings; cleaned one fence-spec line per Directive 31. * fix(notifications): address audit findings on tier-move PR Docs: rewrite three lines that survived the initial sweep. The dashboard "you do not see a locked placeholder" clause and the settings.mdx "hidden on Community and Skipper" phrase were Directive 31 fence-spec. The alerts-notifications troubleshooting note still said "an Admiral routing rule" and contradicted the tier move. Tests: the Community-negative cases on POST/PUT/DELETE/POST :id/test could not distinguish requirePaid from a stray requireAdmiral, because Community fails on the tier check before variant is read. Adding Skipper-positive coverage per endpoint locks the gate identity in. Replace the leaky mockReturnValueOnce with a per-test mockReturnValue plus an afterEach restore so spies cannot bleed across tests. |
||
|
|
ed553f1f19 |
feat: change default listen port from 3000 to 1852 (#756)
Updates the backend listen port, Vite dev proxy target, Docker EXPOSE, compose port mapping, .env.example default, GitHub Actions smoke-test default, healthcheck URLs, and every doc/example reference. Test fixtures that include example URLs were updated for consistency, though their assertions are port-agnostic. The rate-limit value of 3000 in middleware/rateLimiters.ts and the 3000 entry in WEB_UI_PORTS (which detects user containers like Grafana) are intentionally untouched. |
||
|
|
d6b744e8e6 |
feat(license): replace local auto-trial with Lemon Squeezy hosted trial flow (#755)
Fresh installs land on the Community tier. The 14-day Admiral trial is now issued by Lemon Squeezy via their hosted checkout: the user enters email + card, receives a license key by email, and pastes it into the existing Settings > License activation field. Backend changes: - LicenseService.initialize() no longer auto-creates a license_status='trial' row on first boot. It now only ensures an instance_id exists and starts periodic validation. - Drop the TRIAL_DURATION_DAYS constant. - Drop the status='trial' early-return in getVariant() so LS-issued trials resolve through the normal variant metadata path (variant_name / product_name). - Trial branches in getTier() and getLicenseInfo() are retained for future work that may detect trial state from Lemon Squeezy metadata; they are currently unreachable via the Sencho code paths. Frontend changes: - Settings > License surfaces a new "Try Admiral free for 14 days" CTA block with Start monthly trial and Start annual trial buttons that open Lemon Squeezy hosted checkout. The CTA is visible only when the user has no paid access and is not already on a trial. - Reserve the Admiral upgrade card for the Skipper-active upgrade path so unlicensed users see one Admiral path (the trial CTA) instead of two. - Pull the inline Lemon Squeezy checkout URLs into named module constants so the Skipper, Admiral monthly, and Admiral annual endpoints are defined in one place. Test changes: - license-service.test.ts covers the no-auto-trial startup path and updates the trial-variant test to reflect the metadata-driven resolution. - afterAll in the initialize() describe block calls destroy() so the 72-hour validation interval does not leak into sibling test files. Docs: - Rewrite the Free trial section in features/licensing.mdx to document the new LS checkout flow (email + card required, auto-converts on day 14 unless cancelled). - Add an operations/troubleshooting entry for cases where the trial license key email does not arrive. |
||
|
|
b2f341b43d |
feat: docker run to compose converter (#623)
* feat(convert): harden /api/convert endpoint with auth, validation, and tests Applies authMiddleware to the docker run to compose endpoint, validates that the payload is a non-empty string within an 8192 character budget, rejects inputs containing null bytes, and wraps composerize in a try/catch that surfaces a 422 with a clear message when the library cannot produce a services block. Adds a Vitest suite covering the auth gate, happy path, common flag coverage, boundary and null byte placement variants, and malformed command handling. * feat(editor): add From Docker Run tab to create stack dialog Introduces a third tab in the Create New Stack dialog that accepts a docker run command, calls the converter endpoint, and previews the returned compose YAML before writing it to a new stack directory. Uses the defensive toast pattern, clears the stale preview when the input changes, and rolls back the empty stack directory if saving the converted YAML fails so the user never ends up with an orphan stack. * docs(stack-management): document docker run to compose converter Adds a Convert from a docker run command section to the stack management page covering how to use the new tab, the list of supported flags, and troubleshooting for unparseable inputs. Screenshots show the empty tab, a successful conversion with the compose preview, the resulting stack in the editor, and the error toast surfaced when the input cannot be converted. Appends a matching entry to the troubleshooting page. |
||
|
|
4950cd0bd0 |
fix(updates): scan all filesystem stacks for image updates (#514)
ImageUpdateService previously discovered stacks by iterating Docker containers, which meant stacks without containers (e.g. after docker compose down) were silently excluded from update checks. Switch to a hybrid discovery approach: enumerate stacks from the filesystem via FileSystemService.getStacks(), parse compose files for image refs with .env variable resolution, then augment with container-based image discovery for running stacks. Also cleans up stale stack_update_status entries when stacks are deleted or no longer exist on disk, and replaces the plain update-available tooltip with an animated cursor follow pattern. |
||
|
|
023e962a26 |
fix(fleet): forward host bind mounts to self-update helper container (#509)
The self-update helper container runs `docker compose up -d --force-recreate` to recreate the main Sencho container. Previously it only mounted the docker socket, the compose working directory, and the data directory. If the user's docker-compose.yml references env_file, configs, or secrets at paths outside the compose working directory (e.g. /opt/docker/env/globals.env), the helper could not resolve them and compose failed with "env file not found". Now during initialize(), SelfUpdateService collects all host bind mounts from the container inspect data (filtered to Type=bind). In triggerUpdate(), these are forwarded to the helper as read-only mounts at their original host paths (source:source:ro), skipping the socket, data dir, and compose working dir which are already mounted explicitly. This lets docker compose resolve any host-path reference the user has configured, without needing to parse compose files for specific directives. |
||
|
|
9eb945a6f0 |
fix: run as root by default to eliminate stack-folder permission failures (#501)
Every filesystem operation against user compose folders (save, create, deploy, update, rollback, template install, fleet snapshot restore) previously failed with EACCES whenever a stack container had chowned its own bind mount to another UID, which is extremely common with linuxserver/* images and anything that runs as root by default. Running Sencho as root eliminates the entire class of permission bugs at the source and matches the default posture of Portainer, Dockge, Komodo, and Yacht. Mounting /var/run/docker.sock is already equivalent to root-on-host, so the previous non-root hardening provided essentially no additional isolation while breaking real features. Changes: - docker-entrypoint.sh: default path stays root, no GID dance, no privilege drop. Opt-out via SENCHO_USER=sencho restores the legacy behavior bit-for-bit (chown data dir, match Docker socket GID, su-exec to the user). Fails fast if SENCHO_USER names a nonexistent account. Kubernetes / OpenShift forced-non-root compat preserved via the existing id -u = 0 guard. - FileSystemService: delete forceDeleteViaDocker (the ~40-line helper that shelled out to an alpine container to work around EACCES during deleteStack) and simplify deleteStack to a single fsPromises.rm call. Tests updated accordingly. - Dockerfile: keep the sencho user+group pre-created so the opt-out path works out of the box; comments updated to document the new default. - Docs: new "Container user" section in configuration.mdx documenting the root default and the SENCHO_USER opt-out; troubleshooting and self-hosting updated to match. |
||
|
|
c0c321227b |
perf: unify caching behind a single CacheService and enable HTTP compression (#468)
Replaces five ad-hoc in-process caches (project name map, templates, latest version, fleet update status, remote node meta) with a single internal CacheService that provides TTL, inflight-promise deduplication to protect against thundering herd, stale-on-error fallback, and per-namespace hit/miss/stale/size counters for observability. Wraps the hot-path dashboard endpoints in the cache with write-path invalidation: /api/stats (2s), /api/system/stats (3s), and /api/stacks/statuses (3s). Keys are namespaced by nodeId so switching nodes never serves another node's data. Every route that mutates container or stack state calls invalidateNodeCaches(nodeId), which also drops the global project-name-map, so user actions stay instantly reflected in the UI. For /api/system/stats the cheap per-request network rx/tx block is kept outside the cache so live-updating charts stay smooth while the expensive systeminformation.currentLoad() CPU sample (~200ms) is reused across the TTL. Adds admin-only GET /api/system/cache-stats returning per-namespace counters for operators who want to observe cache effectiveness. Enables the compression middleware site-wide for JSON responses. Large payloads like /api/templates shrink roughly 5x on the wire. SSE endpoints are explicitly excluded via a Content-Type filter so live log tails and metric streams are not buffered. Bumps vitest hookTimeout to match testTimeout (15s) so parallel fork workers do not hit the default 10s hook limit under CPU contention. Adds 35 new tests (26 unit for CacheService, 9 integration for cached endpoints) covering TTL expiry, inflight dedup, stale-on-error, namespace invalidation, entry-cap safety guard, and write-path invalidation end-to-end through Express routes. |
||
|
|
662bc1a210 |
fix(resources): unify container/resource classification with multi-fallback resolution (#425)
* fix(sidebar): add service name and config_files fallbacks for container-to-stack matching Containers that predate Sencho's reorganization of compose files into subdirectories carry stale Docker labels where the project name is set to the COMPOSE_DIR basename (e.g. "compose") rather than the stack directory name. The existing project name map and working_dir fallbacks from PR #416 did not cover this case. Added two new fallback strategies to getBulkStackStatuses: - Match by com.docker.compose.service label against known stack names - Extract stack name from com.docker.compose.project.config_files path Also reused the existing isPathWithinBase utility for path containment checks and hoisted path.resolve(COMPOSE_DIR) out of the per-container loop. * fix(resources): unify container/resource classification with multi-fallback resolution Extract shared helpers (resolveContainerStack, resolveProjectLabel, buildAbsDirMap) and apply them consistently across getClassifiedResources, pruneManagedOnly, getDiskUsageClassified, and getBulkStackStatuses. Fixes incorrect "External" tagging in Resources Hub for images, volumes, and networks belonging to stacks that predate Sencho's compose file reorganization. Also fixes the "active" plural on the dashboard Containers card. |
||
|
|
88011e1b16 |
fix(sidebar): resolve stacks showing unknown status when compose name field is set (#416)
* fix(sidebar): resolve stacks showing unknown status when compose name field is set The bulk status endpoint matched containers to stacks using the com.docker.compose.project Docker label, assuming it equals the stack directory name. When a compose file declares a top-level name: field, Docker Compose uses that as the project name instead, causing the label lookup to miss those containers entirely. The fix parses each stack's compose file to build a project-name-to- directory mapping (cached with 60s TTL to avoid re-parsing on every poll), with a fallback to the working_dir label for edge cases. Also extracts compose file name variants into a shared constant and fixes an ordering inconsistency in smartFallback. * docs: add troubleshooting entry for stack status mismatch with name field |
||
|
|
8ba4532995 |
fix(fleet): resolve version detection using package.json over stale generated constant (#410)
* fix(fleet): resolve stuck update states and improve update UX The fleet node update flow had several bugs: the in-memory update tracker never cleared terminal states (timeout, failed, completed), leaving nodes permanently stuck with no way to retry or dismiss. The Recheck button only re-fetched stale state without clearing it, and the POST trigger rejected retries with 409 even after timeout. Backend fixes: - Add DELETE endpoints (single node + batch) to clear tracker entries - Fix 409 race: detect expired timeouts and clear terminal states before re-triggering - Populate error messages in the tracker for timeouts and failures - Include error field in the update-status API response - Auto-expire completed entries after 60 seconds Frontend fixes: - Add retry (RotateCcw) and dismiss (X) buttons on failed/timed-out badges - Show error details via animated cursor hover (CursorFollow pattern) - Recheck button now batch-clears all terminal states before fetching - Recheck shows loading spinner and disables while checking - Extract NodeCardProps interface for readability * fix(fleet): detect update completion via process start time Remote nodes that cannot report their version (e.g. older builds) caused updates to always time out because completion detection relied solely on version comparison. The gateway now tracks the remote node's process start time from /api/meta and detects container restarts by comparing it across polls. Also extracts a createTracker() factory to eliminate repeated object construction across 5 call sites. * docs: add troubleshooting for first-update timeout on old nodes Adds a new troubleshooting entry explaining why the first remote update on nodes running pre-v0.40.0 always times out (neither version nor process start time can be detected). Documents the fix: dismiss, recheck, and confirm the node updated. Also adds a screenshot of the timed-out state with retry/dismiss buttons to the remote updates feature page. * fix(fleet): detect update completion via offline detection and error reporting The update completion detection relied on version change and process start time, both of which fail on nodes running older Sencho versions that report "unknown" and lack the startedAt field. This caused every update to time out after 5 minutes. Add three-signal detection: version change, process restart (startedAt), and offline/online detection (node went unreachable during update and came back). Also add a 90-second early failure heuristic for when the remote image pull fails silently, and surface pull errors from SelfUpdateService via /api/meta so the gateway can report them immediately. * fix(deps): bump vite to 8.0.5 to resolve high severity vulnerabilities Fixes GHSA-4w7w-66w2-5vf9, GHSA-v2wj-q39q-566r, GHSA-p9ff-h696-f583. * fix(deps): bump vite in backend lockfile to resolve audit failures Vitest pulls in vite as a transitive dependency. Bumps to 8.0.5. * fix(fleet): resolve version detection using package.json over stale generated constant resolveVersion() previously returned the build-time SENCHO_VERSION constant without checking the root package.json. When a branch fell behind a release-please version bump, the generated constant was stale, causing remote nodes to show "unknown" version and false "Update available" badges. The function now walks up to the root package.json first (authoritative source) and falls back to the generated constant only if the walk fails. |
||
|
|
cc2da99d6f |
fix(fleet): resolve stuck update states and improve detection (#405)
* fix(fleet): resolve stuck update states and improve update UX The fleet node update flow had several bugs: the in-memory update tracker never cleared terminal states (timeout, failed, completed), leaving nodes permanently stuck with no way to retry or dismiss. The Recheck button only re-fetched stale state without clearing it, and the POST trigger rejected retries with 409 even after timeout. Backend fixes: - Add DELETE endpoints (single node + batch) to clear tracker entries - Fix 409 race: detect expired timeouts and clear terminal states before re-triggering - Populate error messages in the tracker for timeouts and failures - Include error field in the update-status API response - Auto-expire completed entries after 60 seconds Frontend fixes: - Add retry (RotateCcw) and dismiss (X) buttons on failed/timed-out badges - Show error details via animated cursor hover (CursorFollow pattern) - Recheck button now batch-clears all terminal states before fetching - Recheck shows loading spinner and disables while checking - Extract NodeCardProps interface for readability * fix(fleet): detect update completion via process start time Remote nodes that cannot report their version (e.g. older builds) caused updates to always time out because completion detection relied solely on version comparison. The gateway now tracks the remote node's process start time from /api/meta and detects container restarts by comparing it across polls. Also extracts a createTracker() factory to eliminate repeated object construction across 5 call sites. * docs: add troubleshooting for first-update timeout on old nodes Adds a new troubleshooting entry explaining why the first remote update on nodes running pre-v0.40.0 always times out (neither version nor process start time can be detected). Documents the fix: dismiss, recheck, and confirm the node updated. Also adds a screenshot of the timed-out state with retry/dismiss buttons to the remote updates feature page. * fix(fleet): detect update completion via offline detection and error reporting The update completion detection relied on version change and process start time, both of which fail on nodes running older Sencho versions that report "unknown" and lack the startedAt field. This caused every update to time out after 5 minutes. Add three-signal detection: version change, process restart (startedAt), and offline/online detection (node went unreachable during update and came back). Also add a 90-second early failure heuristic for when the remote image pull fails silently, and surface pull errors from SelfUpdateService via /api/meta so the gateway can report them immediately. * fix(deps): bump vite to 8.0.5 to resolve high severity vulnerabilities Fixes GHSA-4w7w-66w2-5vf9, GHSA-v2wj-q39q-566r, GHSA-p9ff-h696-f583. * fix(deps): bump vite in backend lockfile to resolve audit failures Vitest pulls in vite as a transitive dependency. Bumps to 8.0.5. |
||
|
|
f841c402b2 |
fix(licensing): resolve Admiral variant detection and lifetime license handling (#376)
* fix(licensing): resolve Admiral variant detection and lifetime license handling The Lemon Squeezy variant name for Admiral licenses contains "Admiral" (not "Team"), but getVariant() only checked for "team" and "personal". This caused Admiral licenses to be misidentified as Skipper, locking all Admiral-exclusive features. - Map "admiral" variant names to internal "team" value, "skipper" to "personal" - Add isLifetime field to LicenseInfo API response - Hide "Manage Subscription" button for lifetime licenses (no billing portal) - Show "Duration: Lifetime" instead of empty renewal date - Hide upgrade cards for active Admiral users - Add 23 unit tests covering variant resolution, tier computation, and lifetime detection - Add troubleshooting entries for wrong tier label, locked features, and billing portal errors * fix(licensing): address code review findings - Fix nested ternary in LicenseSection JSX; restore conditional rendering to avoid showing an empty "N/A" row for non-subscription states - Clean up test file: use shared svc variable, remove redundant comments, add trialDaysRemaining assertions, rename describe block |
||
|
|
a1804c8fbe |
docs: comprehensive review and refresh of all documentation (#374)
* docs: comprehensive review and refresh of all documentation pages Reviewed every doc page against the current app state after the v0.38 dashboard redesign. Updated content, fixed inaccuracies, and refreshed all screenshots at 1920x1080. Pages updated: - introduction: expanded feature list to 25 items across 6 subsections - quickstart: fixed docker run command (Docker Hub, auto JWT, COMPOSE_DIR) - configuration: replaced personal paths with generic /home/user/docker - sso-quickstart: fixed Settings navigation reference - sso: added SSO_LDAP_DISPLAY_NAME env var - overview: added 8 missing feature sections (labels, API tokens, schedules, etc.) - dashboard: complete rewrite for new health bar, gauges, stack health table - stack-management: updated for UP/DN indicators, rollback button, split actions - editor: rewritten for two-column layout, inline stats, embedded terminal - resources: updated Quick Clean docs, added network topology and inspect - app-store: updated categories, deploy sheet details, permission gate, settings - openapi.yaml: fixed YAML parsing error on line 1831 Screenshots refreshed: 14 images across 6 feature areas. * docs: review and update observability, console, multi-node, and compatibility pages - Global Observability: fix log format fields, add download button docs, split display limits into memory buffer vs rendered rows, correct settings labels - Host Console: remove internal implementation details per security docs policy, add stack directory behavior, expand header bar docs, remove unverified scrollback claim - Multi-Node: add Compose Directory field, document connection test details panel, fix edit/delete node behavior, simplify token security section, remove internal details - Node Compatibility: add missing self-update capability, remove internal endpoint paths and cache TTL, move from Features to Reference group in navigation - Refresh all screenshots for the redesigned UI (7 images) * docs: review and refresh fleet, remote updates, labels, alerts, routing, and webhooks pages - Fleet View: added node updates modal, container detail, version/update/critical badges, Tags filter - Remote Updates: removed internal details, added capability cross-link, fast polling - Stack Labels: three creation methods, two assignment methods, 10 colors, bulk actions screenshot - Alerts & Notifications: fixed metric labels, added notification popover detail, status banner - Notification Routing: HTTPS requirement, rule card layout, channel terminology fix - Webhooks: corrected license tier to Admiral, matched action labels to UI, removed internal security details, added local-only note - Troubleshooting: centralized entries from remote-updates, stack-labels, notification-routing - Refreshed all screenshots at 1920x1080, removed 11 orphaned images * docs: review and refresh RBAC, user management, and atomic deployments pages - RBAC: added missing Auditor role (5th role), updated permission matrix, fixed license tier references, documented username/password validation rules, self-deletion protection - Atomic Deployments: added "Which operations are protected" section covering webhooks/schedules/app store, removed internal backup path, fixed license tier to Skipper/Admiral - Screenshots: cropped to dialog element per updated strategic cropping guideline, removed 2 orphaned images * docs: review and refresh fleet-wide backups and audit log pages Update fleet-backups page to reflect current inline create form, add scheduled snapshots section, document the detail view and restore dialog, expand RBAC table to all five roles. Update audit log page to document expanded row detail fields, pagination, refresh button, and data retention screenshot. Replace all screenshots with fresh captures at 1920x720. * docs: review and refresh API tokens and private registries pages - API Tokens: clarify Full Admin scope, add Managing tokens section with card details, document revocation confirmation dialog, add usage tracking to security model, refresh screenshot - Private Registries: add Managing registries section with card details and action buttons, document edit behavior, fix URL auto-fill description, remove encryption algorithm name per security policy, fix grammar, refresh both screenshots * docs: review and refresh auto-update policies, scheduled operations, and SSO pages - Auto-Update Policies: document all 8 table columns, expand action buttons, add "All Stacks" wildcard option, fix field labels, add CSV export and pagination details, refresh screenshots - Scheduled Operations: fix System Prune target description, add Task List table columns, restructure create dialog fields with action-specific annotations, rewrite execution history with column table, refresh screenshots - SSO: remove encryption algorithm name per security policy, add LDAP and OIDC configuration field tables, document provider card controls (Save, Test Connection, Remove, Active badge), refresh screenshots - Move SSO troubleshooting entries to centralized troubleshooting page * docs: review and refresh licensing & billing page Update upgrade card feature lists to match actual tier gating (Skipper: fleet view, webhooks, labels, atomic deployments, backups, auto-update policies; Admiral: scoped RBAC, SSO, audit log, host console, API tokens, private registries, scheduled operations). Add flex layout to align upgrade card buttons at the bottom. Replace stale screenshot with fresh community and active license captures. Add feature breakdown subsection and profile menu billing shortcut to docs. * docs: review and refresh settings reference and security advisories pages Settings Reference: add 5 missing sections (SSO, API Tokens, Registries, Labels, Routing), expand Users from 2 to 5 roles, fix System Limits and Developer field labels to match UI, restructure Developer into Streaming and Data Retention sub-tables, update App Store and Support sections, refresh overview screenshot. Security Advisories: restructure into versioned sections (v0.25.x hardening and v0.19-v0.24 CVE remediation), expand from 3 bullet points to 10 specific improvements, fix GitHub URL from SaelixCode to AnsoCode, redact internal details per security docs policy. Remove "Sencho Pro" product name from all three pages, replaced with tier names (Community, Skipper, Admiral). * docs: review and refresh troubleshooting page, remove architecture and development guides - Rewrote forgotten password section to remove exposed SQL and table names - Updated all Settings navigation paths to Profile > Settings > X - Fixed network topology from "tab" to "view mode", added Pro license note - Updated Prune Networks to current "Prune Dead Networks" label - Corrected update check cooldown from vague to 2 minutes - Consolidated two network creation error sections into one - Removed hardcoded version reference (v0.34.0) - Replaced em dashes throughout - Deleted architecture.mdx (exposes internal implementation details) - Deleted development.mdx (contributor guide belongs in repo, not public docs) - Removed both pages from docs.json navigation * docs: review and refresh operations pages (backup, upgrade, self-hosting, troubleshooting) Backup & Restore: - Added missing encryption.key to all backup/restore procedures - Added Warning about restoring db without matching encryption key - Added cross-reference to Fleet-Wide Backups for paid tiers - Removed false claim about no built-in backup scheduler - Updated cron example to include encryption key copy Upgrading Sencho: - Removed internal migration details (table names, column specs, encryption algorithm) - Replaced with high-level migration summary per security docs policy - Added encryption.key to pre-upgrade backup command - Updated version pinning example from 0.25.3 to 0.38.0 - Added Remote Updates cross-reference for Skipper/Admiral users Self-Hosting Best Practices: - Removed JWT_SECRET from env var table (auto-generated, not an env var) - Removed PORT from env var table (hardcoded to 3000, not configurable) - Added API_RATE_LIMIT to env var table (actually exists in code) - Fixed listen port description from "configurable" to "fixed" - Updated resource recommendations based on measured footprint audit - Removed su-exec reference (internal implementation detail) - Upgraded data directory Note to Warning with file names Troubleshooting: - Fixed "Pro features" heading to "Paid features" with correct tier names |
||
|
|
55d3b8ca1d |
feat(stacks): state-aware sidebar context menu and Open App action (#368)
* feat(stacks): state-aware sidebar context menu and Open App action - Context menu now adapts to stack state: running stacks show Stop/Restart/Update, stopped stacks show Deploy only - Added "Open App" shortcut to open a stack's web UI directly from the sidebar (visible when running with a published port) - Backend bulk status endpoint enriched with mainPort detection - Reduced manual image update check cooldown from 10 to 2 minutes - Rate limit error message now derives from the configured constant * fix(stacks): use const for bulkPorts (prefer-const lint) |
||
|
|
6c26ae3f50 |
feat(license): distributed license enforcement across multi-node setups (#359)
* feat(license): distributed license enforcement across multi-node setups The primary instance's license tier is now asserted to remote nodes on every proxied HTTP and WebSocket request via trusted headers. Remote nodes honor the assertion only when the request carries a valid node_proxy JWT, preventing unauthorized elevation from browsers or API tokens. Falls back to local license tier for direct access. * fix(test): remove unused vi import in distributed-license tests |
||
|
|
24299a0115 |
feat(resources): add network management with create, inspect, and topology (#338)
* feat(resources): add network management with create, inspect, and topology visualization
Add full Docker network CRUD: create networks with custom drivers, subnets,
and IPAM config; inspect network details including connected containers and
IP addresses; interactive topology graph visualization (Pro-gated to
Skipper/Admiral tiers). Includes backend routes, DockerController methods,
unit tests, documentation with screenshots, and updated changelog.
* refactor(resources): address code review findings for network management
- Add batch GET /api/system/networks/topology endpoint to eliminate N+1
HTTP calls from the topology view
- Export DockerNetwork type from ResourcesView, remove duplicate in
NetworkTopologyView
- Wire up isInspectLoading state to Eye button (spinner + disabled)
- Remove unnecessary wrapper div around FilterToggle
- NetworkTopologyView is now self-contained (fetches from batch endpoint,
no longer needs networks prop)
* fix(resources): align pre-existing UI with design system standards
- Replace hardcoded red-500 on image/volume delete buttons with
text-destructive/60 hover:bg-destructive tokens
- Replace shadow-sm with shadow-card-bevel on all cards (Disk Footprint,
Quick Clean, Resource Tabs, Unmanaged Containers)
- Add strokeWidth={1.5} to all action button Trash2 icons
- Type network drivers as union type instead of raw strings (backend
NetworkDriver type + frontend NETWORK_DRIVERS constant)
* fix(resources): add generic type args to useNodesState/useEdgesState
Fixes TS2345 build error in CI where tsc -b (strict mode via
tsconfig.app.json) infers never[] from untyped empty array literals
passed to React Flow hooks.
* fix(resources): replace explicit any in catch blocks with unknown narrowing
ESLint no-explicit-any errors in CI for three catch blocks added by the
network management feature.
* test(resources): add network management edge case tests and fix bugs
Fix topology route using unclassified networks (missing managedStatus),
fix inspect route returning 500 instead of 404 for missing networks,
add driver validation and array-type labels rejection on create route,
replace all any types with proper unknown narrowing, and add comprehensive
edge case tests for createNetwork and inspectNetwork.
* fix(tests): add nullish guard for Containers in inspectNetwork test
Dockerode types NetworkInspectInfo.Containers as potentially undefined,
causing TS2769 under strict mode when passed directly to Object.keys().
* refactor(resources): replace Select with Combobox for network driver picker
Use the existing reusable Combobox component (same as Auto-Update and
Scheduled Task modals) for the driver selection in Create Network dialog.
Provides inline search filtering and consistent UX across all modals.
|
||
|
|
6f7415351f |
feat(stack-management): add scan stacks folder button (#332)
* feat(stack-management): add scan stacks folder button to detect manually-placed compose files Users who place Docker Compose files directly into the stacks directory (via SCP, file manager, etc.) can now click the folder-search icon next to "Create Stack" to immediately discover and surface those stacks in the sidebar without a full page reload. * docs(troubleshooting): add scan stacks folder troubleshooting section Covers common issues: compose file not in subdirectory, unrecognized filenames, empty directories, and already-tracked stacks. |
||
|
|
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. |
||
|
|
32a7d53b2b |
feat: RBAC, atomic deployments, fleet backups, and licensing (Pro) (#185)
* feat: add RBAC viewer accounts, atomic deployments, and fleet-wide backups (Pro) Introduces three Pro-tier features: - RBAC: Multi-user system with admin/viewer roles, user management UI, automatic migration from single-admin credentials, viewer restrictions across the entire UI (read-only editor, hidden action buttons) - Atomic Deployments: Pre-deploy file backup to .sencho-backup/, automatic rollback on health probe failure, manual rollback button, health probes added to stack updates, webhook-triggered deploys use atomic rollback - Fleet-Wide Backups: Point-in-time snapshots of compose files across all nodes (local + remote), stored centrally in SQLite, per-stack restore with optional redeploy, graceful handling of offline nodes * fix(settings): use correct ProGate prop name in UsersSection * fix(settings): remove unused isPro prop from UsersSection * fix(auth): fetch user info after login and setup so isAdmin is set correctly * feat(pricing): revise pricing strategy and enforce variant-based seat limits Raise Personal Pro from $49/yr to $69/yr with 3 viewer seats (up from 1). Add $15/mo billing option for Team Pro. Mark lifetime pricing as a 90-day early-adopter offer. Store Lemon Squeezy variant_name on activation/validation and enforce seat limits server-side per variant. * feat(licensing): add Lemon Squeezy checkout, webhook, and billing portal integration Server-side checkout URL generation (POST /api/checkout) with admin email pre-fill and instance_id custom data. HMAC-SHA256 verified webhook endpoint (POST /api/webhooks/lemonsqueezy) handling order, subscription, and payment lifecycle events for automatic license activation. Customer billing portal link stored from webhook events and exposed via GET /api/billing/portal. In-app checkout buttons in Settings with manual license key fallback. * fix(licensing): exempt Lemon Squeezy webhook from auth middleware The catch-all auth middleware on /api/* was blocking the public webhook endpoint. Added /webhooks/lemonsqueezy to the exemption list alongside /auth/* and /webhooks/:id/trigger. * feat(pricing): update pricing to final live rates Personal Pro: $7.99/month, $69.99/year, $249 lifetime. Team Pro: $49.99/month, $499.99/year, $1,499 lifetime. Added personal_monthly checkout variant across backend, frontend, and website. * refactor(licensing): remove server-side checkout/webhook for self-hosted model Sencho is self-hosted — each user runs their own instance, so there is no central server to receive webhooks or hold the store API key. Replaced in-app checkout buttons with a "View Pricing" redirect to sencho.io and kept manual license key activation as the primary flow. - Delete LemonSqueezyService (checkout, webhook, HMAC verification) - Remove POST /api/checkout, GET /api/billing/portal, POST /api/webhooks/lemonsqueezy - Remove raw body parser and auth exemption for webhook route - Remove all LEMONSQUEEZY_* env vars from .env.example - Replace checkout buttons in SettingsModal with single "View Pricing" button - Simplify LicenseContext checkout to open sencho.io pricing page - Update licensing docs to reflect website-based purchase flow * chore: normalize em-dashes to hyphens across codebase (linter) * chore: remove accidentally tracked directories from index |
||
|
|
932e7780ea |
docs: add Tier 3 reference and operations pages
- reference/settings: complete settings hub reference (all 7 tabs — Account, System Limits, Notifications, Appearance, Developer, Nodes, App Store) - operations/troubleshooting: 1:1 path rule failures, Docker socket permissions, login errors, WebSocket proxy config, offline remote nodes, password reset, health endpoint, container logs - operations/backup: what to back up (DATA_DIR SQLite + COMPOSE_DIR), hot backup via sqlite3, cron example, restore steps, host migration walkthrough - mint.json: populate Reference and Operations nav groups |