Commit Graph

1710 Commits

Author SHA1 Message Date
SaelixCode 5d798b36bf chore: merge main into fix/ui-polish, resolve StackRow conflict 2026-07-05 23:05:34 -04:00
SaelixCode 9cfb968081 fix: add fingerprint-based dismiss to post-deploy scan banner
Created useScanBannerDismiss hook following the usePreflightDismiss
pattern. The banner now persists dismissal in localStorage keyed to a
fingerprint of scan status + attemptedAt. Dismissal survives page
reloads for the same scan outcome, and the banner automatically
reappears when a new scan runs or the status changes.
2026-07-05 23:00:50 -04:00
Anso b3bc223c45 fix(deploy): selective compose recreate on Save and Deploy (#1565) (#1568)
* feat: move core Blueprint orchestration to Community tier

Blueprints CRUD, reconciliation, and drift modes are now available on
Community. Pin remains Admiral-only via Federation placement controls.

* test: update NodeCard cordon tests for Admiral-only tier gate

Cordon now requires both isPaid and node:manage permission, matching the
backend requirePaid + requirePermission guard. Three tests still used
isPaid:false but expected the menu to be visible.
2026-07-05 21:55:32 -04:00
Anso adcc27e2cf fix: update NodeCard cordon tests for paid-tier gate parity (#1571) 2026-07-05 06:05:05 -04:00
Anso a7e856f447 feat: enforce singleton local node per instance (#1567)
Only one local node is allowed. Creating a second local returns 409,
and the last local node cannot be deleted or converted to a remote type.
Existing duplicate local nodes from older versions are preserved and can
be cleaned up individually. Zero-local recovery auto-assigns the default
flag. Frontend delete surfaces and the Add Node form respect the new
invariant.

Enforced in DatabaseService (addNode/updateNode/deleteNode guards) and
routes (error translations). Legacy test fixtures use raw SQL helpers.
2026-07-05 05:30:56 -04:00
Anso 33231089c3 fix: truncate long sidebar stack names before trailing indicators clip (#1562)
Clamp the stack list width with ScrollArea block and min-w-0 on the row
flex chain so long names ellipsize instead of pushing update dots past the
sidebar edge. Add E2E layout coverage for trailing-indicator edge cases.
2026-07-05 04:57:59 -04:00
Anso f2b5c68d84 feat: add build-aware compose stack updates (#1561)
Detect services with build: in the update preview and run compose build --pull
plus pull --ignore-buildable when Update is triggered on those stacks, while
keeping the existing pull-only path for image-only stacks.
2026-07-05 04:45:45 -04:00
Anso 4077546492 feat: acknowledge Compose Doctor preflight findings per stack (#1560)
* feat: acknowledge Compose Doctor preflight findings per stack

Add node-scoped preflight acknowledgements with read-time filtering.

Supports four expiry modes and activeStatus for banner, tab dot, and readiness.

* fix: align preflight acknowledge UI with design system

Use Combobox, modal chrome, mono fields, and non-destructive clear confirm.

* fix: update test mocks to match new preflight field names

The preflight-acknowledgements feature renamed status-\>activeStatus and
highestSeverity-\>activeHighestSeverity in the preflight report shape. The
corresponding test mocks in three files still used the old field names,
causing 6 test failures across backend and frontend.

- backend: update-guard-service mock now passes activeStatus
- frontend PreflightPanel: Report interface and report() helper now include
  activeStatus, activeHighestSeverity, activeCount, acknowledgedCount
- frontend StackAnatomyPanel doctor: mock API response now includes
  activeHighestSeverity and activeStatus
2026-07-05 04:12:03 -04:00
Anso 122c1b8073 fix: stop Doctor exposing hash fragments as unset variables (#1558)
Classify Compose stderr unset-variable warnings into intentional references vs literal-dollar fragments from secret values. Adds env-literal-dollar preflight rule and safe remediation text. Fixes #1550.
2026-07-05 03:50:40 -04:00
Anso ecd757270f fix: parse LSIO volume :ro suffixes for App Store deploys (#1557)
LSIO encodes read-only mounts in volume path (e.g. /var/log:ro). Map
host_path and optional correctly so fail2ban and similar templates
generate valid compose specs.

Fixes #1554
2026-07-05 03:11:21 -04:00
Anso fbe98676cb feat: bound container health pane so logs stay visible on large stacks (#1556)
* feat: bound container health pane so logs stay visible on large stacks

On the stack overview page, multi-container stacks (8+ services) pushed the
logs pane off-screen because the Command Center card had shrink-0 and no
scroll mechanism. This reworks the desktop layout for stacks with more than
one container:

- The Command Center card is bounded at max-h-[42%] so it never consumes
  the full left column. The container list scrolls internally via Sencho's
  existing Radix ScrollArea.
- A summary strip shows total / running / paused / unhealthy counts above
  the list, with a Compact / Detailed density toggle. Detailed (default)
  shows CPU / Mem / Net sparklines; Compact hides them for a denser list.
- The logs pane has a guaranteed min-h-[180px] so it is always reachable.
- Single-container stacks are untouched: the card keeps its original
  shrink-0 behaviour, and no summary strip or density toggle appears.

Mobile is unaffected (it already uses segmented Health / Logs / Compose
panes).

* fix: key ContainersHealth by node+stack so density resets on navigation

The density toggle state (compact/detailed) is local to ContainersHealth.
Without a key, selecting Compact on one multi-container stack would persist
when navigating to a single-container stack, hiding sparklines while also
hiding the toggle itself. Keying by node+stack ensures a clean remount.

Also added test coverage for zero containers and density reset on remount.

* fix: remove unused rerender variable from ContainersHealth test
2026-07-05 02:53:26 -04:00
Anso bb35c1bc92 feat: add sidebar update indicator toggle and Stack Health badge (#1570)
* feat: add sidebar update indicator toggle and Stack Health badge

- Add image_update_sidebar_indicators setting (default off, node-scoped)
- Gate the Updates filter chip and sidebar status indicators on the setting
- Add "Update available" badge to Stack Health table (always visible)
- Extend ImageUpdateStatus with sidebarIndicators boolean
- Poll /api/image-updates/status alongside /detail in useImageUpdates
- React to SENCHO_SETTINGS_CHANGED for instant toggle propagation
- Reset sidebar state on node switch; generation-guard stale responses
- Disable toggle when status is null (loading) or field is absent (old node)
- Wire stackUpdates through ViewRouter → HomeDashboard → StackHealthTable
- Update settings registry, operator docs, and sidebar/dashboard docs

* fix: guard against stale node renders, memo drift, and cross-node error toasts

- Track owning node ID in useImageUpdates state so React never renders
  node B with node A's data before the passive effect resets (P2)
- Replace incorrect stackUpdates dependency with sidebarStackUpdates in
  chipFilteredFiles useMemo (P3)
- Guard the error toast in handleSidebarIndicatorsChange so a stale PATCH
  failure from node A does not surface while viewing node B (P3)

* fix: default sidebar update indicators to on (opt-out)

The sidebar indicators are a safe convenience that most users want.
Switching the default from off to on matches the opt-out convention
used by prune_on_update, reclaim_hero, and health_gate_enabled.
2026-07-05 02:52:17 -04:00
Anso c677b8bb66 fix: fall back to enroll token when pilot tunnel JWT is rejected (#1566)
* fix: fall back to enroll token when pilot tunnel JWT is rejected

On HTTP 401/404 upgrade rejection, delete stale pilot.jwt and retry with SENCHO_ENROLL_TOKEN.

* test: import pilot agent module after DATA_DIR is set in fallback test

The auth-fallback test statically imported pilot/agent, which freezes its
pilot.jwt path from DATA_DIR at module load, before setupTestDb redirects
DATA_DIR to a writable temp dir. On the Linux CI runner the path resolved
to a non-writable /app/data, so persistToken silently failed and the
round-trip assertion read null. Import the module dynamically in beforeAll
after setupTestDb, matching the sibling unit test.

* fix: remove unexpected-response listener that blocked pilot reconnect

The ws library skips abortHandshake when an unexpected-response listener
exists, so error and close never fire and the agent hangs in CONNECTING.
Detect auth rejection via the abortHandshake error message instead; the
close handler already performs enroll-token fallback and reconnect.
2026-07-05 01:03:09 -04:00
Anso fdbc1b1ebb feat: move Blueprint orchestration and Federation placement to Community tier (#1555)
* feat: move core Blueprint orchestration to Community tier

Blueprints CRUD, reconciliation, and drift modes are now available on
Community. Pin remains Admiral-only via Federation placement controls.

* feat: move Federation placement controls to Community tier

Remove requirePaid from cordon, uncordon, and blueprint pin routes. Ungate the Federation tab and gate cordon UI on node:manage only. Update licensing and fleet docs for the new tier split.
2026-07-04 21:20:20 -04:00
SaelixCode 5f8c0c8c97 fix: add aria-labels to schedule action buttons, update test selectors
Replaced native title attributes with aria-labels on Run now,
Execution history, Edit, and Delete buttons so the Radix tooltip
conversion does not break test selectors that relied on title.
Updated tests from findByTitle to findByRole.
2026-07-04 12:31:34 -04:00
SaelixCode 366add027b chore: merge main into fix/ui-polish 2026-07-04 04:05:57 -04:00
SaelixCode 23a52aedf0 fix: restore missing closing bracket on TabsTrigger tag 2026-07-04 01:02:37 -04:00
SaelixCode dedf19c9f2 fix: match Resources tab font size to Fleet and Security
Removed explicit text-xs from Resources TabsTrigger elements so they
use the default text-sm, matching Fleet and Security tab typography.
2026-07-04 01:00:45 -04:00
SaelixCode c9b3e578b6 fix: restructure Resources page tabs to match Fleet/Security pattern
Moved tab band out of the outer card into a standalone full-width
element. Replaced custom FilterToggle with Fleet-style Button
toggles. Added search inputs per tab. Wrapped each resource table
in a card container matching the Security Images table design.
2026-07-04 00:55:40 -04:00
SaelixCode 32b6f05866 fix: change tab highlight from neutral to brand color
Replaced bg-glass-highlight with bg-brand/20 on all TabsHighlight
instances and updated TabsTrigger active state to text-brand,
matching the SegmentedControl selected style. Works on both
dark and light themes.
2026-07-03 23:52:15 -04:00
Anso 1fac6f797f refactor: replace PNG logos with SVG (#1559)
Swap sencho-logo PNGs for SVGs in frontend/public. Update all references
in index.html, SidebarBrand.tsx, and README.md.
2026-07-03 23:29:27 -04:00
SaelixCode 9117ca13cf feat: add copy button to execution history details column
Replaced the plain truncated Details cell with a flex layout containing
a copy button. Users can now copy the full error/output text instead
of relying on the native title tooltip to read long messages.
2026-07-03 23:16:17 -04:00
SaelixCode dd6874f1ae fix: replace native title tooltips with Radix tooltips on Schedules and Settings pages
Converted Run now, Execution history, Edit, Delete buttons on Schedules;
Download/Delete on Cloud Backup; Send test/Edit/Delete on Notification
Routing; Reset 2FA on Users; and Edit/Remove suppression on
Suppressions panel. Skipped SettingsSection/Modal title props which
are React component props, not native HTML attributes.
2026-07-03 19:42:48 -04:00
SaelixCode 5a18be8667 fix: replace native title tooltips with Radix tooltips on Security page
Converted scanner info icon, exploitability n/a badge, and scan
image button from native HTML title attributes to the shared Radix
Tooltip component.
2026-07-03 19:35:13 -04:00
SaelixCode 717d956593 fix: replace native title tooltips with Radix tooltips on Resources page
Converted all actionable button tooltips (Open stack, Inspect image,
Scan, Browse volume, and delete buttons) plus the SenchoBadge
informational tooltip. Wrapped disabled protected-resource delete
buttons in span triggers so tooltips fire on disabled elements.
2026-07-03 19:27:18 -04:00
SaelixCode dd35f45062 fix: replace native title tooltip on Fleet Snapshots upload button 2026-07-03 19:15:59 -04:00
SaelixCode 244f10fcec fix: replace native title tooltips with Radix tooltips on Fleet toolbar
Converted Refresh, Export Dossier, Search, Sort direction, Node Update,
and Manage Nodes buttons from native HTML title attributes to the shared
Radix Tooltip component so they match the app-wide glass tooltip design.
2026-07-03 19:13:37 -04:00
Anso 4a350e7a0a feat: add Docker label audit across Fleet and Stack views (#1531) 2026-07-03 18:26:09 -04:00
SaelixCode 9546334946 fix: apply glass/blur design to shadcn tooltip component
Replaced the solid bg-foreground/text-background style with the app's
glass design: bg-popover, border-glass-border, backdrop-blur, and
text-popover-foreground. Kept the shadcn structure (Portal, Arrow,
slide/fade animations).
2026-07-03 15:40:50 -04:00
SaelixCode f0874862f0 fix: replace custom tooltip with shadcn/ui Radix tooltip
Replaced the glass/blur-styled tooltip with the standard shadcn/ui
pattern: bg-foreground/text-background, arrow pointer, proper
slide/fade animations, and w-fit max-w-xs sizing. This gives all
tooltips a consistent dark-solid look across the entire app.
2026-07-03 15:31:51 -04:00
SaelixCode ef85f57cf2 fix: bake standard tooltip styling into TooltipContent component
Added font-mono tabular-nums text-stat-value directly to the
TooltipContent base styles so every tooltip in the app inherits
the same look without per-instance wrappers. Removed the now-
redundant span from StackRow's RowTooltip.
2026-07-03 15:22:36 -04:00
SaelixCode f83f01417c Revert "fix: standardize all tooltips to match sidebar RowTooltip design"
This reverts commit 9e1d97d39e.
2026-07-03 15:21:35 -04:00
SaelixCode 9e1d97d39e fix: standardize all tooltips to match sidebar RowTooltip design
Wrapped every TooltipContent child in a font-mono text-xs
tabular-nums text-stat-value span so all tooltips across the app
share a consistent look. Previously some used plain text, others
used <p> elements with different fonts and sizes.
2026-07-03 14:45:48 -04:00
SaelixCode 8494e53e4c Revert "fix: remove custom tooltip styling, use standard TooltipContent defaults"
This reverts commit 209fbd2742.
2026-07-03 14:42:08 -04:00
SaelixCode 209fbd2742 fix: remove custom tooltip styling, use standard TooltipContent defaults
The RowTooltip wrapped its label in a font-mono text-stat-value span
instead of using the TooltipContent base styling (text-xs
text-popover-foreground) like every other tooltip in the app.
2026-07-03 14:28:10 -04:00
SaelixCode ff98eb3cd8 fix: standardize Blueprint empty state headings to font-heading
Replaced manual font-serif [font-style:var(--heading-style)] with the
font-heading class on the main heading and three step titles so the
Deployments empty state follows the same heading convention as the
rest of the app and respects the Calm/Signature theme toggle.
2026-07-03 14:16:52 -04:00
SaelixCode b0cb5b70d0 fix: replace Timeline/All tasks buttons with SegmentedControl
The two loose Button elements had indistinguishable selected/unselected
states (secondary vs ghost). Replaced with the SegmentedControl component
already used elsewhere on the same page, which has a clear active
highlight indicator.
2026-07-03 13:17:54 -04:00
SaelixCode 604c4a7705 fix: rename Notification Routing to Routing in settings sidebar 2026-07-03 09:13:52 -04:00
Anso 10fb93dcb1 feat(scheduler): schedule container restart, stop, and start (#1526)
* feat(scheduler): schedule container restart, stop, and start

Add container as a scheduled-task target type so operators can automate lifecycle actions against standalone containers by node and name, with matching UI pickers, validation, execution on local and remote nodes, and tests.

* fix(scheduler): stack service matching and container picker hygiene

Backfill Service on smartFallback containers so per-service stack restarts work when container_name is set. Match services by compose label and container name in stack routes and scheduled restarts. Exclude Sencho from GET /api/containers lists. Hide the Restart Stack service picker when a stack has only one service.

* test(scheduler): scope service checkbox assertion to Services block

The create dialog also has a Delete after run checkbox. Count checkboxes only inside the Services section so CI does not include unrelated form controls.

* fix(scheduler): narrow closest() result to HTMLElement in schedule test

The service-checkbox assertion passed an Element from closest() into
within(), which requires an HTMLElement, failing tsc -b in the frontend
build and Docker build stages. Use the closest<HTMLElement>() type
argument so the value type-checks without an unsafe cast.

* fix(scheduler): hide Sencho container on remote node picker lists

Remote container lists are proxied from peer Sencho instances, so id-only self filtering missed peers on older builds. Await SelfIdentity init, match ImageID, and drop official saelix/sencho images. Apply the same heuristic in the scheduled-operations UI and when the hub fetches remote containers for scheduled runs.

* test(monitor): add missing DatabaseService mocks for scan history cleanup

* test(scheduler): add missing markStaleScansAsFailed mock

SchedulerService.tick() calls db.markStaleScansAsFailed() to sweep stale
vulnerability scans. The scheduler-service test was missing this method in
its DatabaseService mock, causing TypeError failures during test initialization.

Added mockMarkStaleScansAsFailed to hoisted mocks and DatabaseService mock
object, returning safe default of 0 scans marked as failed.

* test(compose): add missing FileSystemService mocks for getStackContent/getEnvContent

* test(containers-route): mock SelfIdentityService to prevent initialize() crash

The excludeSelfContainers() helper calls SelfIdentityService.initialize(), which tries to access DockerController. Without a proper SelfIdentityService mock, the initialize() call fails silently, causing a 500 error on GET /api/containers.

Added SelfIdentityService mock with initialize(), isOwnContainer(), and isOwnImage() methods to prevent the crash.
2026-07-02 22:31:29 -04:00
Anso b65daf6845 feat: add notification suppression rules (#1525)
* feat: add notification suppression rules

* fix: restore label routing and routing test mocks for suppression

* fix: allow bell mute shortcuts for history-only notification categories

Suppression rule validation used the routable category whitelist, which rejected history-only categories such as update_started that appear in the bell during stack updates.

* feat: expand Mute Rules UX with compose-first entry points and activity badges

* fix: add missing NodeContext mocks for notification suppression tests
2026-07-02 15:26:48 -04:00
SaelixCode f9a80f30dc fix: wrap tooltip icon triggers in span for Radix compatibility
TooltipTrigger asChild requires a native element to forward props.
Lucide icon components did not reliably receive data-state and event
handlers, so tooltips on the check-failed and git-pending indicators
did not open. Wrapped each icon in a span.
2026-07-02 12:48:57 -04:00
SaelixCode ba702474bd fix: replace cursor-follow tooltip with standard Radix tooltip in sidebar rows
Replaced the Cursor/CursorFollow animate-ui primitives in StackRow
with the standard Radix Tooltip/TooltipTrigger/TooltipContent already
used throughout the app. The custom cursor dot that followed the mouse
is gone; tooltips now appear as static popovers on hover/touch.
2026-07-02 12:35:37 -04:00
SaelixCode ea02762f0a fix: improve masthead rail glow visibility
Replaced the invisible inset box-shadow glow (10px blur inside a 3px
element) with a white overlay that pulses opacity 0.15-0.55 over 4s.
Sped up glow animation from 5.5s to 4s for a more noticeable breath.
2026-07-02 12:19:07 -04:00
SaelixCode d42a30967d fix: reduce masthead rail opacity to match login page pattern
Changed all MastheadRail background classes from 100% to 70% opacity
(bg-brand → bg-brand/70, etc.) so the shimmer highlight reads as a surface
reflection rather than a detached floating bar. Matches the AuthCanvas
login card precedent.
2026-07-02 12:13:25 -04:00
SaelixCode 715cc88362 fix: increase masthead rail shimmer visibility
Bumped shimmer highlight opacity from 25% to 50% and reduced
animation duration from 11s to 5s, matching the login page
AuthCanvas shimmer precedent (via-white/60 at 4.5s).
2026-07-02 11:12:11 -04:00
sencho-quartermaster[bot] bc111d28f3 chore(main): release 0.93.4 (#1548) v0.93.4 2026-07-01 23:12:33 -04:00
Anso 98667e0d6f fix: make host memory usage ZFS ARC-aware (#1547) 2026-07-01 23:08:49 -04:00
sencho-quartermaster[bot] 0adc2b5eb2 chore(main): release 0.93.3 (#1536) v0.93.3 2026-07-01 22:56:46 -04:00
Anso aed173fa1d ci: stop posting PR comments from preview publish workflow (#1545)
Remove github-script comment step so repeated preview runs do not clutter the PR.
2026-07-01 20:00:43 -04:00
Anso c3dcf31cc8 fix: wrap auto-heal policy history in stack monitor sheet (#1538)
* fix: wrap auto-heal policy history in stack monitor sheet

Restructure PolicyRow history entries to stack vertically with break-words
so long container names and reasons stay inside the sheet width.

Fixes #1532

* fix: cap auto-heal policy history to a scrollable region

Recent activity could grow the policy row unbounded, pushing the
add-new-policy form far down the sheet when a policy accumulated many
history entries. Wrap the list in a fixed-height ScrollArea so it
scrolls internally instead.
2026-07-01 14:31:54 -04:00