mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-07-27 20:29:10 +00:00
08caa914ce
* docs(atomic-deployments): refresh page around current UI and behavior
Rewrites the page to match the v1 docs refresh template. Corrects
several factual errors against the current code, fills in missing
detail, and adds a screenshot of the rollback overflow menu.
Notable corrections:
- Scheduled tasks do not run atomically; only stack editor Deploy and
Update, App Store installs, webhook triggers, and image auto-updates
pass the atomic flag through to ComposeService.
- Rollback lives in the stack editor's More actions overflow menu, not
on the action bar directly. The backup timestamp renders as a
sub-line of the menu item.
- Health probe is a 3-second window with an exit-code check on every
container labelled with the compose project name; describe this
exactly rather than as 'waits briefly'.
- Document where backups live (DATA_DIR/backups/<stack>/), why they
are kept outside the compose folder, and that the slot is one per
stack with overwrite semantics.
- Document the four streamed log markers users see in the deploy
progress modal during the atomic flow.
- Add a troubleshooting accordion group covering missing menu entry,
late crashes outside the probe window, manual-intervention message,
and the single-slot retention edge case.
* docs(deploy-enforcement): refresh page for v1 and align with current enforcement paths
Update the page to match the current pre-flight gate behavior, the v1 modal chrome on the
block dialog, and the AccordionGroup troubleshooting pattern used across the v1 docs.
Drift items corrected:
- Replace the broken vulnerability-scanning/deploy-blocked-dialog.png reference with three
fresh captures under docs/images/deploy-enforcement/ (policy list, policy editor, block
dialog).
- Drop "Recreate from the stack actions menu" and the git-source apply pre-flight claim;
neither path runs the gate.
- Add bulk label deploy and the auto-update scheduler to the enforced code paths, with a
dedicated subsection for the auto-update interaction (alert-and-skip, not 409).
- Drop the false claim that severity chips in the block dialog are clickable; the dialog
is informational.
- Document the compose-parse-fails-closed branch with its synthetic violation label.
- Refresh dialog copy to reflect the v1 ModalDestructiveHeader (kicker, title, button
variants).
- Convert the troubleshooting Q&A into AccordionGroup blocks and add accordions for the
compose-parse-error case and the auto-update-skipped case.
- Quote the verbatim audit-log summary format.
* docs(blueprints): refresh against v1 UI and add federation/state-review coverage
* docs(git-sources): refresh page against v1 UI and current behavior
Rewrites the page against the v1 docs refresh template (Note tier-gate,
sectioned anatomy, AccordionGroup troubleshooting), aligning prose with
the live UI labels and the current code paths.
Corrections:
- Authentication toggle reads "Public (no auth)" / "Personal Access
Token" (not "None"), and apply mode "Auto-write files" (not
"Auto-write").
- Diff dialog kicker is GIT . PULL PREVIEW; local-edits state opens an
Overwrite local edits? confirmation modal whose primary button is
Overwrite and apply.
- Sidebar pending indicator is a small GitBranch icon, not a brand-color
dot, and the image-update dot takes priority over it on the same row.
- Pending update banner appears in the panel; Review re-fetches the
commit and opens the diff (no client-side payload caching).
Adds coverage for:
- Anatomy of the panel (pending banner, form, last-applied stat strip,
footer actions).
- 10-second webhook debounce window.
- Pending compose/env content is encrypted at rest in the database, not
just the token.
- Auth/host failures map to HTTP 400, never 401, so they do not sign
the user out.
- Per-stack lock serializes pull, apply, and create-from-git so a
webhook firing during a manual apply waits rather than racing.
- Compose validation has a 10-second budget; clone fetches have a
30-second timeout.
- New troubleshooting accordion for Pending commit has changed since
this pull was fetched.
Recaptures all five screenshots from the v0.74.x production node,
signed in as admin: panel, create-from-git tab, pull-preview diff
dialog, sidebar GitBranch pending icon, webhook Action select with
Git source sync highlighted.
* docs(stack-labels): refresh page for v1 sidebar grouping and fleet-action surface
- Lead with the v1 behavior the previous page did not cover: the sidebar
groups stacks under collapsible label headers (PINNED first, label
buckets sorted by stack count desc then name asc, UNLABELED last)
with a count chip per group. Trailing colored dots on each row
(max 3 + N overflow, paid-only) supplement the headers.
- Drop the stale claim that a label-pill filter bar lives between
search and the stack list; that UI no longer exists.
- Drop the right-click-on-pill bulk actions table (Deploy all / Stop
all / Restart all). The legacy per-node action endpoint stays in
the backend but no longer has a UI binding, so the page documents
only what users can click today.
- Document the two Skipper+ Fleet Action cards: Stop fleet by label
(name match across nodes, autocomplete, per-node breakdown,
HTTP 429 on per-node concurrency) and Bulk label assign (per-node,
replace semantics, clear on empty selection).
- Document the inline 'New label' form inside the stack right-click /
three-dot Labels submenu, the Settings - Advanced - Labels masthead
N/50 stat, the LABELS - NEW / EDIT modal kickers, and the
LABELS - DELETE - IRREVERSIBLE confirmation copy verbatim.
- Document the Fleet Overview Tags multi-select filter (filters by
stack labels aggregated across nodes), with cross-link to fleet-view.
- Capture every screenshot fresh from production signed in as admin:
sidebar-grouping, context-menu-labels, inline-create-form,
settings-labels, create-label-dialog, fleet-tags-filter,
fleet-actions. Drop the now-stale sidebar-with-labels,
sidebar-filtered, and bulk-actions-menu captures.
* docs(dashboard): refresh page for v1 layout (status masthead, gauges, fleet heartbeat, restart map)
Aligns docs/features/dashboard.mdx with the redesigned Home tab. Replaces the obsolete
Recent Activity feed coverage with the actual DashboardActivityCard split (Fleet Heartbeat
when remote nodes are registered, Stack Restarts (7d) otherwise) and recaptures every
screenshot from the v0.74.x production node.
* docs(global-search): refresh page for v1 palette
- Note tier and role gating on the Pages list (Auto-Update, Console,
Schedules, Audit) so the prose matches what the top bar exposes.
- Document the ACTIVE chip on the currently active node row.
- Document the 50-result cap counter and the Searching... loading state.
- Mention the ~250 ms debounce and clarify that filename matching
includes the file extension.
- Replace stack screenshot with a redesigned capture and add empty-state
Pages and Nodes captures showing the ACTIVE chip.
* docs(global-observability): refresh page for v1 layout (masthead, signal rail, filter strip, paused-resume chip)
Full rewrite against the current Logs tab and the v1 docs refresh template
(hero Frame, sectioned anatomy, AccordionGroup troubleshooting, refresh-cadence table).
Replaces the single overview screenshot with seven captures under
docs/images/global-observability/ (overview, masthead, signal-rail,
filter-strip, feed-bands, paused-resume-chip, error-only-filter), all from
the v0.75.x production node signed in as admin with PII scrubbed
(profile chip patched to AD, in-feed LAN IPs and third-party hostnames
substituted via DOM injection while the stream was paused).
Aligns prose with the actual UI labels and code:
- Masthead kicker reads LIVE LOGS · NODE · <NAME> with LOCAL for the
local node; state word toggles Streaming / Idle / Offline; SESSION
uses uppercase letter suffixes (1H 43M / 0M 12S) per formatUptime.
- Signal rail tile counts are scoped to the 2000-entry buffer and reset
with Clear; CONTAINERS is buffer-bound, not a monotonic accumulator.
- Filter strip controls quoted verbatim (Stacks · All / Stacks · n,
segmented controls All / Out / Err and All / Info / Warn / Error).
- Feed row anatomy: severity dot, timestamp, brand-cyan container name
with stack/container tooltip, message tinted by source. Row tint
follows detected level, which is regex-based, so an STDOUT line
containing ERROR: still classifies as ERROR.
- Day bands: NOW, Nm AGO, Nh AGO, calendar date.
- Empty states: two-tier kicker over caption (Awaiting events / No matches).
- Pause keeps the SSE buffer filling up to the 2000-entry cap; resume pill
reads <n> NEW · RESUME and counts the queue, not total arrivals during
the pause.
- Download filename and row format quoted: sencho-logs-<ISO8601>.txt and
[<ISO>] [<stack>/<container>] <LEVEL>: <message>.
Documents behavior the previous page never covered:
- Active-node scoping; node switch resets the stream and the buffer.
- SSE primary transport with 30-second server heartbeat and a 5-second
polling fallback against /api/logs/global (server-capped at 500 lines
per snapshot).
- Initial replay of the last 500 lines per container when the SSE
connection opens, so the feed has context immediately.
- Display limits (2000 client buffer, 300 rendered rows, Showing last
300 of N overflow notice).
- Refresh cadence table covering UI tick, flush cadence, polling
cadence, SSE heartbeat, sparkline window, and the Idle threshold.
Adds a seven-accordion troubleshooting block (Offline state, gray Idle
dot, ERROR-without-tint, growing Resume pill, Clear-cutoff lag,
node-switch buffer drop, fleet-wide aggregation expectations).
Tightens the closing Note so it makes clear that Notification Log
Retention does not govern this live container stream.
* docs(alerts-notifications): refresh page for v1 and absorb notification-routing
Full v1 template rewrite of /features/alerts-notifications. Bundles in
the entire Notification Routing page so a reader sees channels, routing,
per-stack rules, and retention in one place; deletes the standalone
notification-routing.mdx and points all five cross-link sites at the new
in-page anchor.
* docs(alerts-notifications): drop "What's not in scope" section
The page should describe what Sencho does, not enumerate what it does
not ship. Users find missing integrations through the Webhook section
and the routing matcher reference; the explicit disclaimer added noise
without adding guidance.
* docs(audit-log): refresh page for v1 layout, expanded action list, troubleshooting accordion
- Clarify that the search/method/date filter strip lives in Table view only.
Stream view always shows the unfiltered chronological feed.
- Fold the total-entries readout into the card subtitle wording where it
actually renders, instead of describing it as a separate header element.
- Sharpen the Peak hour off-hours window to the literal 08:00 to 17:59
working window the tile keys off, plus the 5% / 20% failure-rate tints.
- Note that the Actors tile names a sample actor alongside the new-IP count.
- Expand the example actions list to cover surfaces that have shipped since
the last edit: per-service stack lifecycle, node cordon/uncordon, fleet
replica role changes, Sencho Cloud Backup operations, Fleet Secrets, and
blueprint federation pin updates.
- Correct the Settings path: Settings · Developer · Data retention card,
Audit log input, Save settings button.
- Add a Troubleshooting AccordionGroup matching the rest of the v1-refresh
pages: missing tab, filter scope, anomaly thresholds, export cap, and
retention pruning.
- Replace all four screenshots with fresh captures of the current UI.
* docs(multi-node): refresh page for v1 layout, pilot agent mode, refreshed table columns
Rewrites docs/features/multi-node.mdx against the current product. The previous page predated the v1 Settings hub redesign and the Pilot Agent enrollment model, so it documented only the Distributed API Proxy add-node flow and missed the new Mode, Endpoint, and Labels columns on the Nodes table.
Restructures the page into 13 sections: intro, How it works, the local node, Choose a remote mode (decision table comparing Pilot Agent vs Distributed API Proxy), Add a remote node: Pilot Agent (three steps plus re-enrollment), Add a remote node: Distributed API Proxy (three steps), Switching between nodes, the Nodes table (full column reference), What Settings apply per node (verified against settings/registry.ts), License enforcement across nodes, Editing and deleting nodes, Security (token security, transport encryption, why no application-layer TLS), and Troubleshooting (AccordionGroup matching the v1 template used on audit-log, atomic-deployments, and deploy-progress pages).
Refreshes seven screenshots against the production node signed in as admin, scrubbing IPs and usernames before capture: full Nodes panel overview, Generate Node Token card with a placeholder token, Add node modal in Pilot Agent mode, Add node modal in Distributed API Proxy mode (with the inline plain-HTTP warning visible), Edit modal showing the Regenerate enrollment token card for a pilot agent, Pilot enrollment modal with the docker run command, refreshed node switcher popover, and a close-up of the table columns. Drops the obsolete add-node-form.png, http-warning.png, and per-node-scheduling/ folder.
* docs(fleet-view): refresh page for v1 layout, expanded tabs, cordon, sheet-based updates
- Aligns the Overview, Status, and Node Updates content with today's UI:
the masthead's `The fleet` headline plus CPU / MEM / CONTAINERS stat tiles,
the eight-tab strip (Overview, Snapshots, Status, Deployments, Traffic,
Federation, Fleet Actions, Secrets) with per-tier visibility, and the
Check Updates surface that is now a system sheet rather than a modal.
- Documents the toolbar (search, sort, filter popover with Status / Type /
Severity / Tags sections) and the Grid / Topology segmented control
including the topology graph's status pill (Online / Critical / Offline),
connector colouring, ReactFlow controls and minimap.
- Documents the per-card surfaces that were missing from the prior page:
Cordoned badge with cross-reference to Fleet Federation, fleet stack
label dots in the drill-down, container drill-down rows (state dot,
badge, image, status, open-in-editor hover button), and the Admiral
three-dot Node actions menu for cordon / uncordon.
- Documents the Node Updates sheet anatomy (Recheck and Update all (n)
header actions, four summary cards, node table columns, Update flow,
reconnecting overlay timing, admin enforcement) and the GitHub Releases
with Docker Hub fallback resolution path with its 30-minute cache.
- Replaces every stale screenshot with a fresh capture (overview,
topology, drill-down, status tab, node updates sheet) and removes the
obsolete files plus the empty docs/images/fleet/ folder.
- Reformats troubleshooting as an AccordionGroup matching dashboard,
multi-node, and audit-log refreshes.
* docs(fleet-backups): refresh page for redesigned fleet and settings UI
Replace all six screenshots with current production captures. Update
content to reflect the new fleet header card, eight-tab layout, full-
page Cloud Backup settings with header stats, and corrected navigation
paths. Add cloud backup rows to the access control table.
* docs(fleet-backups): convert troubleshooting to AccordionGroup pattern
Match the foldable-accordion pattern used across the v1 docs refresh
batch. Merges the standalone Cloud Backup troubleshooting subsection
into a single Troubleshooting section at the bottom of the page with
seven accordions covering skipped nodes, two restore failure modes,
three cloud-upload failure modes, and a diagnostic logging entry.
* docs(remote-updates): refresh page for v1 sheet, accordion troubleshooting, factual fixes
Rewrites the page against the v1 docs refresh template (Note tier gate,
sectioned mechanism deep-dive, Frame screenshots with detailed alt text,
inline AccordionGroup troubleshooting), bringing it in line with the
recently-refreshed fleet-view, fleet-backups, dashboard, and audit-log
pages.
The page is repositioned as the mechanism deep-dive (prerequisites, what
runs on a node during an update, completion and failure detection,
recovery actions). The full UI tour for the Node updates sheet remains in
fleet-view so the two pages stop overlapping; remote-updates now links
into fleet-view#node-updates instead of restating the table anatomy.
Captures three screenshots from the production node, signed in as admin:
fleet-node-updates.png shows the Node updates sheet with eight nodes and
seven remote updates available; local-update-confirm.png shows the
LOCAL · UPDATE alert dialog with the Cancel and Update & restart buttons;
node-card-update-available.png shows the Opsix card with the Update
available pill and the Update to v0.76.7 outline button.
Corrects several factual claims that no longer matched the current code:
- The remote early-fail threshold is about 3 minutes, matching
EARLY_FAIL_MS in backend/src/routes/fleet.ts, not 90 seconds.
- The Recheck button sits in the sheet header, not the footer.
- The component is a SystemSheet, so the page now consistently calls it
the Node updates sheet instead of a dialog, with lowercase "Node
updates" and lowercase "Update all (n)" matching the live UI.
- Reconnecting overlay polls /api/health every 3 seconds, not "every few
seconds".
- The local Failed badge surfaces as soon as the helper writes its error
file, by the 3-minute mark at the latest.
Documents the LocalUpdateConfirmDialog kicker, title, body, and CTA
verbatim, the Triggering... loading state on the Update buttons, the
four completion signals the gateway accepts (version change, process
startedAt change, offline-then-online transition, version at or above
the comparison target after 15 seconds), and the 60-second auto-clear
of the Updated badge.
Drops references to two screenshots that never existed
(fleet-node-updating.png, fleet-node-failed.png); the in-flight and
failed states are described in prose instead, the same way fleet-view
handles them.
* docs(scheduled-operations): refresh page for v1 timeline, fleet-wide update action, sheet-based run history
Rewrites the Scheduled Operations page against the v1 template
(Note tier gate, sectioned anatomy, Frame screenshots, AccordionGroup
troubleshooting) applied to sibling pages in this batch. Captures
seven fresh screenshots against the production node signed in as
admin (timeline, all-tasks, action-picker, create-restart,
create-prune, create-scan, run-history) and removes every legacy
PNG.
Documents the new "Auto-update All Stacks" action that was absent
from the page, extends the Skipper allow-list to all four Skipper
actions (Auto-update Stack, Auto-update All Stacks, Fleet Snapshot,
Vulnerability Scan) and clarifies that the action picker hides
operations the active tier cannot run.
Corrects several factual claims that no longer matched the code:
- Scheduled scan completion is `info`/`scan_finding` on a clean run
and `warning`/`scan_finding` when findings are present (not
`info`/`system` as previously stated). Cross-link now points at
`alerts-notifications#vulnerability-scanning`.
- Lifecycle actions (auto_backup, auto_stop, auto_down, auto_start)
execute against the local Sencho instance only; only Auto-update
Stack / All Stacks have a remote-proxy code path. The page
reinstates the guidance to schedule remote lifecycle operations
from that node's own UI.
- Run history lives in a right-side sheet with a "Schedules ›
<task> › Runs" breadcrumb and a Download CSV secondary action.
- Timeline masthead is described in terms of the v1 visual
(`NEXT 24 HOURS` kicker, italic display heading, monospace date
range, right-anchored Next pill with countdown, glowing cyan now
rail, six-tick bottom axis).
* docs(rbac): refresh RBAC & user management page against v1 template
Bring /features/rbac onto the v1 docs refresh template (Note tier gate,
sectioned anatomy, Frame screenshots, AccordionGroup troubleshooting).
Recapture five screenshots from the production node signed in as admin
and remove the three stale captures under docs/images/rbac/.
Corrections vs. the prior page:
- Deployer no longer claims node:read in the permission matrix; the
backend grants only stack:read and stack:deploy.
- Add the system:registries row (container registry management).
- Document the form as inline below the Add user button (not a modal).
- Note the (you) marker on the signed-in admin's row and the disabled
delete icon on that row.
Additions:
- Settings nav location and hub-only visibility.
- 2FA reset row action with verbatim modal kicker, title, and body.
- Five-failure / 15-minute MFA lockout behavior and admin reset recovery.
- Token-version session-security table covering deletion, role change,
password change, and admin 2FA reset.
- SSO password-fields-hidden line quoted verbatim and the per-provider
Require MFA toggle.
- Audit-log emissions list for every user-management mutation.
- API tokens cross-link explaining the user-vs-machine boundary.
- Scoped permissions section retightened: scoped role picker is
Deployer / Node Admin / Admin only; resource type is Stack or Node.
AccordionGroup with eight troubleshooting entries covering missing nav,
greyed role options, seat-limit errors, unexpected sign-outs, scoped
deployer mismatches, missing shield icon, re-locking MFA accounts, and
SSO role drift at provisioning.
* docs(2fa): refresh two-factor authentication and admin guide against v1 template
Bring /features/two-factor-authentication and /operations/two-factor-admin
onto the v1 docs refresh template (Note tier gate, sectioned anatomy, Frame
screenshots with descriptive alt text, AccordionGroup troubleshooting,
verbatim modal copy with kicker callouts). Recapture every screenshot under
docs/images/two-factor-auth/ from a fresh session and add six new captures
for surfaces the prior page did not document.
Corrections vs the prior pages:
- Panel rename: Settings -> Account & Security is now Settings -> Account,
under the Identity group of the settings sidebar. Replaced every
occurrence on both pages.
- Enrol dialog titles match the current modal: Pair your authenticator,
Confirm the pairing, Save your recovery codes (was: Set up 2FA, Confirm,
Save your backup codes). Step rail 01 PAIR / 02 CONFIRM / 03 ARCHIVE
documented.
- Manual-entry affordance is the always-visible Secret manual entry row
with a copy icon, not the toggleable Can't scan Show secret key link.
- Confirm step auto-submits on the sixth digit; no submit button. Verified
in MfaChallenge.tsx and MfaEnrollDialog.tsx and called out explicitly.
- Authenticator-app list trimmed to match in-app copy (1Password, Bitwarden,
Google Authenticator, or any TOTP app). Authy and Microsoft Authenticator
dropped because the dialog does not mention them.
- Disable dialog: kicker SECURITY MFA DISABLE, title Turn off two-factor,
destructive header, Disable button. Replaces the prior Disable 2FA
paragraph that did not describe the dialog chrome.
- Regenerate dialog: two-step flow with kicker SECURITY BACKUP CODES, Confirm
identity then New recovery codes, with the verbatim PREVIOUS CODES HAVE
BEEN INVALIDATED warn rail on the show step. Documented that the dialog
only accepts a TOTP, not a backup code.
- Per-user SSO toggle label corrected: Require 2FA on SSO sign-in (was:
Require 2FA even when signing in via SSO). Added the per-provider vs
per-user distinction on both pages (admins can also enable Require MFA
on the SSO provider config, which is independent of the per-user toggle).
- Admin reset modal: verbatim USERS RESET 2FA kicker, Reset 2FA for
<username> title, full-body copy reproduced. Documented that the reset
bumps the target's token version and invalidates active sessions.
Additions:
- Sign-in throttle: five failed verifications lock the account for 15
minutes, server returns 423 with Retry-After, UI shows the Retry in MM:SS
countdown plus Rate limited label. Lockout recovery section explains
that the counter only clears on a successful sign-in, so retries after
the window expires re-lock immediately.
- Account panel anatomy section enumerates the three rows (Authenticator
app, Backup codes, Require 2FA on SSO sign-in) plus the destructive
Disable 2FA link, and the masthead 2FA on / BACKUP N left chips.
- Recovery codes section now covers all three count states (3 plus, 1 to 2,
0) with verbatim helper text, tone, and the standalone No backup codes
left callout that renders at zero. New screenshots for the 2-remaining
and 0-remaining states.
- Cross-references to the admin operations page (CLI fallback, token version
rotation, what a reset changes in the DB), the SSO page, and the RBAC
page (per-provider Require MFA toggle, SSO auto-provisioning).
Troubleshooting on the feature page rewritten as an AccordionGroup with
nine entries: clock drift, wrong account selected, QR will not scan, lost
phone with no codes, lost codes with authenticator, ran out of codes,
unexpected SSO prompt (with both toggle causes), repeated lockout after
the window expires, missing shield icon on Users panel.
The admin operations page also gains the SSO + 2FA two-toggles table so
administrators can answer the per-user vs per-provider question without
context-switching between pages.
Six new images added; six existing images replaced. Total 14 captures.
* docs(rbac,host-console): drop enforcement-boundary detail from tier-gate notes
Operator-facing docs should state tier or role requirements once, in plain
customer-facing language, and leave the enforcement chain to the source.
Two surfaces on the v1-refreshed pages over-specified the gate:
- `features/rbac.mdx::Scoped permissions`: the Note enumerated both the UI
hide on Skipper and the `/api/users/:id/roles` write rejection. The first
half ("Scoped permissions require Admiral.") is the operator-relevant
fact; the rest reads as a fence specification, which is awkward for an
open-core product where the gate is readable in source anyway. Trimmed
to just the tier claim.
- `features/host-console.mdx::Availability`: the paragraph already says
who can use the console and that the Console tab is hidden on Community
or Skipper. The trailing "Attempting to access the console endpoint
directly without the correct license or role is rejected" is the same
bypass-prevention coda. Dropped.
No functional behavior change; the gates themselves are untouched.
* docs(sso): refresh SSO & LDAP authentication page against v1 template
Rewrites docs/features/sso.mdx against the v1 docs refresh template (intro
+ tier callout, sectioned Configuration anatomy, Frame screenshots,
AccordionGroup troubleshooting), bringing it in line with the previously
refreshed two-factor-authentication and rbac pages on this branch.
Recaptures all four screenshots from the production node signed in as
admin: sso-settings (overview with the five collapsible provider cards),
sso-settings-ldap (LDAP form expanded), sso-settings-oidc (Google form
expanded), sso-settings-custom-oidc (Custom OIDC form expanded with all
eleven fields).
Refreshes the Settings UI section to match the redesigned panel: each
provider is a collapsible card with an Active badge on the header, an
enable / disable toggle pill, and a footer with Save, Test Connection
(green check or red X next to the button), and Remove (only after a
config has been saved). Documents the static callback-URL helper that
sits below all five cards.
Clarifies that the per-OIDC claim mapping environment variables
(SSO_OIDC_*_ID_CLAIM, *_USERNAME_CLAIM, *_EMAIL_CLAIM) are accepted for
Google, GitHub, and Okta, not just Custom OIDC. The Settings UI hides
those fields on the presets because the defaults match.
Converts the troubleshooting section to an AccordionGroup with five
entries (Test Connection discovery failure, issuer validation error,
wrong username or missing email after sign-in, invalid redirect URI,
SSO buttons missing on the login page). Cross-links the operations
troubleshooting page for setup-time errors.
Tightens the LDAP TLS env var note to spell out the literal string
'false' requirement. Syncs the Combining SSO with 2FA section to use
the live toggle label 'Require 2FA on SSO sign-in'.
* docs(sso): drop the Community-tier Custom OIDC workaround tip
The Tip walked through how a Community-tier operator could integrate
Google, GitHub, or Okta by pointing Custom OIDC at the provider's
discovery URL, bypassing the Skipper preset gate. Operator docs should
state the tier rule once and stop; they should not describe how to
circumvent it.
The tier matrix above the removed block already names which providers
are paid; the Custom OIDC row already lists "any spec-compliant OIDC
provider" as its scope. That is enough.
* docs(vulnerability-scanning): refresh page for v1 UI and corrected tier mapping
The page was last revised before the v1 visual redesign and before the
tier-mapping changes shipped in v0.81.2 (open Community access to
secret scanning, compose misconfig scanning, scan history, and scan
comparison). This refresh:
- Rewrites the tier matrix to match the shipped Community / Skipper /
Admiral split. Secret detection, compose misconfig scanning, scan
history, scan comparison, and misconfig acknowledgements are now
correctly marked as Community. Scheduled fleet scans, scan policies
with block_on_deploy, SBOM, SARIF, and Trivy auto-update stay paid.
- Drops two stale Notes that said secret detection and compose
misconfig scanning required Skipper or Admiral. The page now states
each tier requirement once, in plain language.
- Refreshes all six existing screenshots from the production node:
resources-badges, scan-details-sheet, scan-history-sheet,
scan-compare-sheet, security-settings, app-store-toggle.
- Adds a new scan-config-button screenshot showing the stack-page
overflow menu where Scan config now lives.
- Describes the scan drawer header accurately: Re-scan + Compare + CSV
+ SARIF as top-level buttons, with SBOM as a separate button below
the summary.
- Updates the compose misconfig flow to point at the stack overflow
menu (not the Deploy controls).
- Converts the troubleshooting section to a single AccordionGroup per
the v1 template, and audits each entry for legacy phrasing and the
removed tier claims.
- Adds a TRIVY_BIN reference to the How it works section so operators
know about the host-binary override.
* docs(cve-suppressions): refresh page for v1 UI and corrected suppression specifics
- Recapture all three screenshots from the production node signed in
as admin under `docs/images/cve-suppressions/` (`settings-panel`,
`create-dialog`, `suppressed-row`). The previous file referenced
three image paths that did not exist in the repo.
- Align prose with the actual UI labels:
- Dialog kicker `SUPPRESSIONS . NEW`, title `New suppression`.
- Field labels match the form: `CVE or advisory ID`, `Package
(optional)`, `Image pattern (optional)`, `Reason`, `Expires in
(days, optional)`.
- Remove confirmation reads `Remove suppression` with kicker
`SUPPRESSIONS . REMOVE . IRREVERSIBLE`.
- Factual corrections:
- Fleet sync truncation cap is 5,000 rows (not 10,000).
- State the admin-role requirement once in the lead Note.
- Drop references to a `Fleet . Sync status` page and a `Reanchor`
button; neither exists in the UI. The reanchor flow is an admin
API call and is documented in /features/fleet-sync.
- Sharpen the specificity scoring section (package + image scores
3, package only 2, image only 1, neither 0) so the order matches
the read-time filter logic.
- Note that the image-pattern glob is case-sensitive.
- New coverage:
- Suppressing directly from a scan result, including which fields
are read-only in that inline flow and when to fall back to
Settings to broaden scope.
- The `replicated` and `expired` row badges in the panel.
- Hovering the package column on a suppressed row to surface the
Reason.
- Two distinct read-only modes: viewing a remote node from the hub
(panel hidden, banner shown) versus signing into a replica
instance (panel visible, read-only).
- SARIF export carries suppressions through as
`kind: external, status: accepted`, cross-linked to the
Vulnerability Scanning page.
- Convert troubleshooting to AccordionGroup with six entries; update
the truncation entry to reflect the 5,000-row cap.
* docs(private-registries): refresh page for v1 UI and fleet-wide credential model
Rewrites the page against the v1 docs template (Note tier gate, opening Frame,
sectioned anatomy, AccordionGroup troubleshooting) and replaces every
screenshot with a fresh capture taken against the current product.
Corrects several factual claims that no longer matched the current code:
- Registries are stored once on the control instance and applied fleet-wide,
not configured per node. The old Multi-node behavior section and the
matching troubleshooting entry described a per-node model that the product
no longer has.
- The Registries section is hidden on remote nodes (global scope) and on
Sencho versions that do not surface the feature. New troubleshooting
entries explain both visibility states.
- The feature is admin-only on Admiral. Non-admin operators do not see the
section even on Admiral; previous copy implied any Admiral license user
could manage credentials.
- Registry endpoints are not reachable from API tokens; only an admin
browser session can manage credentials. The Security section now states
this without naming internal route paths.
Documents UI behavior the previous page omitted: the inline form (not modal),
the four type-specific form variants, the Docker Hub read-only URL field, the
destructive delete confirmation with its stack-pull warning, the masthead
REGISTRIES count, and the empty-state callout copy.
Screenshots replaced:
- registries-overview.png: section with one configured GHCR card and the
masthead stat at one.
- registries-empty.png: empty state with the Add registry button and callout.
- registries-add-form.png: inline form with the Docker Hub default and the
read-only URL field.
- registries-ecr-form.png: form switched to ECR, showing the AWS Region
field and the relabelled AWS credential inputs.
- registries-card-detail.png: card close-up with the three action icons and
the metadata row.
- registries-delete-confirm.png: destructive ConfirmModal with the kicker,
title, and stack-pull warning body.
- registries-with-entry.png removed (superseded by registries-overview.png
and registries-card-detail.png).
* docs(auto-update): refresh readiness page for v1 redesign
Bring the Auto-Update Readiness doc in line with the shipped UI:
- Replace the hero screenshot with a fresh capture of the redesigned
board (italic-display hero, brand-cyan accent, per-node groups with
local/remote pills, dashed-border changelog separator).
- Rewrite the card-anatomy list. Drop the rollback-target bullet (the
field exists in the backend payload but is not rendered). Add the
"Rebuild available" inline label and the primary-image / multi-service
count line.
- Rewrite the risk-tags table as a risk-badges table using the actual
badge labels and colors emitted by the UI (Safe / Review / Blocked
with the corresponding icons; Digest rebuild for non-semver tags).
- Add an Empty state section and document the per-node group header.
- Tighten the hero subtitle paragraph to match the actual UI string
(only major-bump count is surfaced separately; preview failures are
not).
- Fix workflow step 4: major-bump apply path is the stack lifecycle
Update action, not the Schedules editor (a scheduled task hits the
same block).
- Add the 2-minute manual-refresh cooldown to the Recheck workflow.
- Remove the broken cross-link to the non-existent
/features/image-update-detection page and inline the 6-hour cadence
fact from ImageUpdateService.INTERVAL_MS.
- Convert troubleshooting to AccordionGroup format per the troubleshoot
ing convention used on /features/deploy-progress.
- Sync the Auto-Update entry in /features/overview.mdx to the new
badge labels and the corrected hero-counter description.
* docs(auto-update): fix Auto-Update entry point in Workflow step 1
Workflow step 1 said "Open the Auto-Update view from the sidebar." The
Auto-Update view is opened from the top nav strip (alongside Home,
Fleet, Resources, App Store, Logs, Schedules, Console, Audit). The
sidebar carries the stack list and the per-stack right-click / kebab
context menu that toggles auto-updates on or off; it does not house
the Auto-Update top-level view.
* docs(auto-update): trim enforcement detail from per-stack control note
State the tier requirement once and stop, per Directive 27. The
"The toggle does not appear on Community" sentence enumerates the
enforcement effect of the gate, which the source already reflects;
operator docs do not need to narrate it.
* docs(auto-heal): refresh page for v1 UI and policy hardening
Rewrite Auto-Heal Policies docs against the current Stack Monitor
sheet: corrects the Max restarts / hr field label, documents the
per-policy enable toggle, the consecutive-failures pill, the full
Recent activity action set (including Docker unavailable), the 30s
evaluation cadence, multi-node behavior, notification dispatches,
and the dashboard Configuration status counter.
Replaces the broken /images/auto-heal-policies/policy-sheet.png
reference with three fresh screenshots captured against a live
node: the sheet on the Auto-heal tab, a single policy row, and
the expanded Recent activity panel.
* docs(webhooks): refresh page for v1 UI, correct tier and add Git source sync
- Fix tier note: gate is Skipper or Admiral, management is admin-only.
- Update Settings path to Settings -> Alerts -> Webhooks; document the
read-only Node field and the green secret-reveal callout.
- Add the missing Git source sync action and the git-pull override value.
- Refresh the configured-webhooks card description: action/stack/node
badges, On/Off toggle, copy URL, and the Recent executions disclosure.
- Tighten the trigger section with a constant-time signature check note
and a status/body/meaning response table.
- Add an Accordion troubleshooting block covering common signature
failures, the 404 case, no-op actions on 202, and git-pull prereqs.
- Re-capture all three screenshots from the v1 UI.
* docs(webhooks): wrap troubleshooting accordions in AccordionGroup
* docs(sidebar): refresh page for v1 redesign with filter chips, bulk mode, row anatomy, and troubleshooting
Rewrites the Stack Sidebar page against the live v1 sidebar and the v1
docs refresh template (Frame screenshots, Note tier callouts,
AccordionGroup troubleshooting). Recaptures all four existing
screenshots and adds three new captures: filter chips, row anatomy,
and bulk mode.
Adds coverage for features the previous page omitted entirely: the
ALL / UP / DOWN / UPDATES filter chips with their counts cap and
collapse toggle; bulk mode (B key, sticky toolbar with Start / Stop /
Restart, and Update gated on Skipper or Admiral); stack-row anatomy
(status pill, label dots with +N overflow, image-update dot vs Git
source icon priority, hover kebab); the Auto-update toggle, Schedule
task, and Open App entries in the context menu; the B shortcut for
bulk mode.
Corrects three claims that no longer matched the code or UI:
Auto-Heal is gated on Skipper or Admiral, not universal; the global
Ctrl+K opens the command palette, not the sidebar search box; the
activity footer kicker reads LIVE / IDLE with the verbatim copy from
SidebarActivityTicker. Documents the in-menu ↗ and L › glyphs as
visual hints rather than global keybindings to match
useStackKeyboardShortcuts.ts.
* docs(sidebar): trim enforcement-effect sentence from context-menu tier note
State the Skipper / Admiral requirement once and stop, per Directive 27.
The "They do not appear in the menu on Community" clause described the
enforcement effect alongside the gate, which the directive bans in
operator-facing docs.
* docs(host-console): refresh page for v1 UI and clarify shell metadata
Rewrite the Host Console page to match the current Cockpit layout
(masthead + terminal well + chip strip), replace the legacy PowerShell
screenshot with a fresh bash capture, and document the masthead tone
states, kicker, metadata pills, and session/heartbeat behavior. Trim
the security section to state the tier and role rule once.
* docs(licensing): refresh page for v1 UI, corrected pricing, and trial flow
Rewrites the Licensing & Billing page to match the redesigned v1
Settings layout. The previous draft still described the legacy
Settings Hub: in-app "Upgrade your plan" Skipper/Admiral cards,
"Start monthly trial" / "Start annual trial" buttons, the
"Have a license key?" field, "Manage Subscription" with a capital S,
"Deactivate License" as the button label, and the license-active.png
asset rendering the literal "Sencho Pro" string in the card title.
None of that exists in the current product.
- Refreshes the Plans table to the live pricing on sencho.io/pricing
and adds an Enterprise mention with the floor price ($3,500/year).
Skipper now $11.99 annual / $14.99 monthly / $449 lifetime, Admiral
now $69.99 annual / $89.99 monthly / $2,499 lifetime.
- Rebuilds the Feature breakdown from a code-level audit of every
requirePaid, requireAdmiral, requireScheduledTaskTier, and
requireTierForSsoProvider call site in backend/src/routes, not
from the marketing page. Notable code-grounded items: CVE
suppressions on Community (no requirePaid guard), manual fleet
snapshots on Community (scheduled snapshots on Skipper),
Sencho Mesh under Admiral (entire mesh.ts router is requireAdmiral),
and scheduled-task tiering names update/scan/snapshot as the
Skipper subset with everything else under Admiral.
- Rewrites the Free trial flow end to end. The previous steps told
operators to click in-app "Start monthly trial" or "Start annual
trial" buttons; no such buttons exist. The new flow starts on
sencho.io/pricing, switches to the Annual or Monthly tab, clicks
"Start 14-day trial" on the Admiral card, completes the Lemon
Squeezy checkout (card-required, no charge before day 14), and
pastes the issued key into Settings -> License -> License key.
- Adds a new "The Plan section" anatomy block describing the masthead
SCOPE / PLAN / DURATION (or RENEWS, TRIAL, STATUS) stat pills and
the Plan card fields (Customer, Product, masked License key, status
helper).
- Adds a new "License states" reference table covering
Community / Trial / Active subscription / Active lifetime /
Expired / Disabled, what each surface renders, and which of the
Plan / Activate / Pricing sections is visible in each state.
- Corrects every UI label that drifted: section heading is Activate,
field label is License key (not "Have a license key?"), buttons are
Manage subscription (lowercase s) and Deactivate (not "Deactivate
License"), and the action-row hint reads "Lemon Squeezy manages
billing".
- Documents the redesigned profile dropdown: identity header with
initials chip, role badge, and tier badge, then Settings,
conditional Billing, Documentation, Feedback, an Appearance
segmented control, and Log Out. Billing only appears when the
license is an active non-lifetime subscription.
- Replaces all four screenshots under docs/images/licensing/:
license-admiral-active.png (production Admiral lifetime view),
profile-menu.png (redesigned popover), and two new captures for
the Community-tier surfaces (license-activate-section.png,
license-community.png). Removes the stale license-active.png
(legacy "Sencho Pro" card) and profile-billing.png (legacy
dropdown).
* docs(settings-reference): refresh page for v1 UI with new sections and masthead
Rewrites docs/reference/settings.mdx against the current Settings Hub so a reader
encounters an accurate map of every section. Adds the previously missing **Cloud
Backup** and **Security** sections, restructures **System Limits** into Host
thresholds and Docker hygiene subsections (GiB units, "Global crash capture"
toggle), fixes the Account password minimum to 8 chars and documents the
two-factor subsection, refreshes License/Routing/Webhooks/App Store with the
field labels actually rendered today, and documents the masthead pills
(SCOPE/NODE, EDITED, plus the per-section stats like 2FA, PLAN, CHANNELS, ROUTES,
WEBHOOKS, LABELS, TRIVY, POLICIES, PROVIDER, USED, SNAPSHOTS, DEV MODE).
Replaces five existing screenshots that predated the v1 redesign and adds five
new captures: Account with the 2FA card, License panel, System Limits with both
subsections, Security with the Trivy installer, and Cloud Backup with Sencho
Cloud Backup provisioned. All shots taken against the production node.
* docs(licensing): drop billing-provider name from operator-facing copy
The previous draft named the third-party billing provider in nine
places (checkout, receipt email, error toast verbatim, Customer /
Product field descriptions, the action-row hint, the billing portal,
and the validation API). Operator docs don't need to advertise which
vendor sits behind the checkout, billing portal, and validation
calls. Rewrite each instance to describe what the operator sees and
does without naming the upstream service.
* docs(node-compatibility): refresh page for v1 UI with lock card visuals and current capability list
- Replaces the legacy "dim + blur + pill overlay" description with the
current CapabilityGate behavior: a centered lock card with an Unplug
icon, title "<feature> is not available on this node", and a body line
that names the node and its running version.
- Corrects the tier-interaction section: on the wrong tier the entry
point is hidden entirely, so the lock card only appears for users who
already cleared the license gate.
- Documents the public /api/meta endpoint, the 5-minute success cache,
the 30-second failure cache, and the lazy-fetch behavior visible in
the switcher (the version pill appears once a node has been visited).
- Refreshes the capability table against the current CapabilityRegistry
list, adding container-exec and vulnerability-scanning, with a note
that vulnerability-scanning is only advertised when Trivy is installed.
- Adds three production screenshots captured on the live fleet:
switcher popover with mixed-version pills (one node on v0.76.9, rest
on v0.81.11), a real lock card on an older pilot agent, and the
Connection Details panel from Settings · Nodes.
* docs(security): refresh security architecture page for v1 UI
Add Fleet Secrets and Webhook signatures cards plus tier-matrix rows for
shipped-but-undocumented features. Rename SSO presets from "one-click" to
"preset providers" (presets still require OAuth-app provisioning on the
upstream IdP). Update settings paths to the v1 middle-dot convention:
Settings · Users, Settings · Account, Settings · Developer · Data retention.
Extend the encryption-at-rest list with registry credentials and Fleet
Secrets bundle payloads (both sealed with the same AES-256-GCM data key)
and clarify the password section with bcrypt cost factor 10.
Add a Webhook signature authentication subsection covering the per-webhook
HMAC-SHA256 secret, one-shot display, masked preview thereafter, and
constant-time comparison on inbound triggers.
Replace the API Tokens screenshot with a fresh capture against the v1
Settings · Identity · API Tokens panel.
* docs(security-advisories): retire reference page
The reference/security-advisories page does not survive the v1 docs
refresh:
- Misuses the term "Security Advisories", which industry-wide refers to
published notices for confirmed product CVEs (ID, severity, affected
versions, fix version, remediation). The retired page was a narrative
changelog of internal hardening work between v0.19 and v0.25.2.
- The narrative is also frozen at v0.25.2 (April 2026) while current
release is v0.81.11. Refreshing it would require backfilling ~56
release entries' worth of hardening copy.
- The framing is uniformly "improved from prior behavior" (minimum 8
characters up from 6, 1-year token expiry previously without expiry,
CORS previously allowed all origins, users should upgrade promptly).
Sencho has not shipped publicly; there are no users to address as
upgraders.
All operationally relevant content already lives elsewhere: the
security architecture page covers the current posture, verifying-images
covers the supply-chain attestations, cve-suppressions covers operator
acknowledgment, vulnerability-scanning covers the in-app scanner, and
contact + the security architecture page both surface the disclosure
path. Published Sencho-product advisories, when any exist, will appear
on the GitHub Security tab, which is already linked from those pages.
Inbound-link audit returned a single hit on the nav entry itself; no
other doc, README, or operator artifact deep-links the slug.
* docs: rewrite Pilot Agent page with deep architecture and operations reference
Reframes docs/features/pilot-agent.mdx as the architecture-and-operations
companion to the operator walkthrough in Multi-Node Management. Adds a
mental model section, an explicit security and trust model, a full agent
env-var reference, an honest limitations list, and a 5-item FAQ. Verifies
every constant and label against the current backend source. Refreshes
four production screenshots (admin login, scrubbed) and resolves the
previously-broken /images/pilot-agent/enrollment-dialog.png reference.
Adjacent edits keep the cross-linking coherent:
- multi-node.mdx adds a one-line forward link to the rewritten page
- security.mdx adds a Pilot Agent tunnel credentials subsection
* docs(fleet-federation): deep rewrite with production screenshots
Rewrites the Fleet Federation page against the v1 docs refresh template
following the recent fleet-view, pilot-agent, and multi-node refreshes.
Doubles the page length (92 to 204 lines) while keeping the cut-line v1
MVP scope: operator-driven placement controls (cordon + pin) for
Blueprints, no expansion into mesh/sync/pilot territory.
What changed:
- Adds four production-captured screenshots under docs/images/fleet-federation/:
the Federation tab with a cordoned node populated, the node-card kebab
menu showing the Cordon node entry, the cordon confirmation dialog
with a reason filled in, and a node card displaying the Cordoned pill.
- Expands the page to eleven sections: opening summary, philosophy
(kept), key capabilities, prerequisites, step-by-step usage with
embedded screenshots, behaviour and lifecycle table, security and
audit, limitations and non-goals (expanded), practical workflows (new:
OS patching, host-to-host migration, gateway pinning), troubleshooting
(eight accordions, up from five), and a Where Federation fits
cross-link table.
- Documents the exact production UI strings observed: the cordon
dialog description, the uncordon confirmation copy, the reason field
cap (256 chars), and the audit log action names (node.cordon,
node.uncordon, blueprint.pin).
- Documents the audit visibility surface so operators know how to
filter the Audit view for cordon and pin history.
- Adds eight cross-links to sibling pages (Fleet View, Multi-Node,
Pilot Agent, Mesh, Fleet Actions, Fleet Sync, Blueprints, Licensing)
with one-line scope contrasts so newcomers can place Federation in
the broader fleet picture.
- Tightens lifecycle table to operator-relevant terms (no DB column
names) and audit section to operator-facing wording (no middleware
names), keeping the page operator-focused rather than
implementation-focused.
Validation:
- Captured screenshots against the production node logged in as admin,
using Playwright MCP. Cordoned and pinned actions reverted; audit log
confirmed the matched cordon/uncordon pair.
- Verified every cross-link target exists in the v1-refresh worktree
(/features/fleet-view, /features/multi-node, /features/pilot-agent,
/features/sencho-mesh, /features/fleet-actions, /features/fleet-sync,
/features/blueprint-model, /features/licensing).
- Compliance: no em dashes, no PII, no "previously"/"used to" framing,
no fence-spec language, tier rule stated once in plain language.
* docs(fleet-federation): drop fence-spec phrasing in the open-core context
Sencho is open-core: anyone can clone the repo and read the tier gate.
Operator docs that name exactly where the UI gate sits ("hidden at the
Community and Skipper tiers", "lower-tier users do not see the toggle",
"only the Federation tab is gated") work as a dig-target for a
tech-savvy reader and undercut the open-core posture. Directive 27
already bans enforcement-chain spelling; the open-core threat model
makes the same phrasings risky even when they describe UI surfaces
rather than route guards.
Removes three instances of the pattern on this page:
- Top Note callout: drops "The tab is hidden at the Community and
Skipper tiers." Keeps the one-line requirement: "Federation is an
Admiral feature. Cordon and pin actions require an admin user role."
- Security and audit section: drops the sentence enumerating which UI
affordances are hidden from which tiers. Keeps the customer-visible
behavior (the Cordoned pill stays visible at every tier as a
read-only signal).
- Troubleshooting "Federation tab is not visible" accordion: rewrites
to lead with the requirement and the role check, drops the
"Federation is hidden by design" and "only the toggle and the
Federation tab are gated" phrasings.
Other claims on the page unchanged; rule is still stated once in plain
language at the top of the page.
* docs(fleet-sync): deep rewrite with production screenshots
Replace fleet-sync.mdx with a verified end-to-end reference. The previous
page named two replicated resources but the code syncs three, described a
sync-status panel and a fleet-vs-node scope picker that do not exist in
the shipped UI, and was missing prerequisites and several edge cases.
Highlights of the rewrite:
- Names all three replicated resources (scan policies, CVE suppressions,
misconfig acknowledgements) and treats them uniformly.
- Drops the sync-status-panel and node-scope-picker UI claims; both move
to the Limitations section as honest caveats.
- Adds prerequisites covering the paid-tier requirement on the control,
admin-role requirement, proxy-mode remotes, and reachability.
- Expands lifecycle coverage: per-node serialised pushes, add-node
backfill, monotonic pushedAt, per-resource watermarks, identity-drift
notifications, the 5000-row truncation cap, stale-target warnings,
audit-log entries on the replica.
- New "Where Fleet Sync fits" closing table cross-linking to Fleet View,
Multi-Node Management, Pilot Agent, Vulnerability Scanning, CVE
Suppressions, Fleet Federation, Fleet Actions, and Licensing.
- Two fresh production screenshots: control Security panel and the
"Scanner is per-node" callout shown when proxying to a remote.
* docs(fleet-actions): deep rewrite with production screenshots
Three cards are documented end to end: Stop fleet by label, Bulk label
assign, and Prune Docker resources fleet-wide. Adds the execution-path
distinction (control-orchestrated fan-out vs single-node proxy), per-card
behaviour and partial-failure semantics, prerequisites, limitations,
practical workflows, an Accordion troubleshooting section, and a Where
Fleet Actions fits comparison table linking the surrounding Fleet view
features.
Corrects the prior page's tab-neighborhood claim, confirm-dialog wording,
autocomplete-vs-request scope, and missing batch ceiling. Replaces the
ten-day-old single screenshot with five fresh production captures under
docs/images/fleet-actions/.
* docs(fleet-secrets): deep rewrite with production screenshots
Full rewrite of /features/fleet-secrets matching the fleet-actions
structure. Replaces the sparse v1 page (no Frames, inline Q&A) with a
gold-standard layout: opening Frame, single Note for the tier gate,
'What it covers' table, mental model, prerequisites, create + edit +
versions + push (Target / Preview / Results) sections each with a
production Frame, Import from stack section, behaviour and lifecycle
table, audit-trail mapping with the six exact audit strings,
limitations and non-goals, practical workflows, AccordionGroup
troubleshooting, and a Where-it-fits cross-link table.
Adds six fresh production screenshots under
docs/images/fleet-secrets/ : overview, create, versions, target,
preview, and results.
Documents the Import-from-stack flow (depends on the bundle editor's
new Import action) and uses the post-rename 'Send' wording on the
bundle-row action (depends on the aria-label fix).
Corrects three factual drifts vs the code: env-key regex described as
'letter or underscore, then letters/digits/underscores; case-
sensitive' to match ^[A-Za-z_][A-Za-z0-9_]*$ ; documents only the
'ok' and 'failed' status pills (the 'skipped' enum value is unused);
replaces the bogus 'stack not found' troubleshooting entry with the
real 'env file not declared' cause.
Drops the fence-spec phrasing 'The tab is hidden on Community.' per
Directive 31; the tier requirement is now stated once in plain
language.
* docs(sencho-mesh): deep rewrite with mental model, lifecycle, security, screenshots
Replace the feature-reference page with a deep product + technical guide.
Adds:
- Opening hook framing audience and problem (cross-node service-to-service
without a separate VPN or service-mesh sidecar).
- Mental model: three moving parts (sencho_mesh bridge, alias registry,
cross-node transport) with direction-of-flow described in prose.
- Key capabilities, prerequisites, step-by-step usage with inline screenshots.
- Full lifecycle section covering opt-in, opt-out, sticky stack-stopped state,
peer reconnect, and the proxy-mode bridge with its real default (persistent,
env-override for idle).
- Security and trust boundaries split into authentication, inbound exposure,
encryption, audit, and app-layer caveats.
- Limitations and non-goals: one-alias-per-port, port 1852 reserved,
central-relay for remote-to-remote, shared 1024-stream pool with the Pilot
tunnel, no L7, host-network unsupported, in-memory activity log.
- Three concrete workflow examples and a complete troubleshooting accordion
(every data-plane reason, every probe stage, every unreachable cause) plus
a Common questions FAQ.
- Where Mesh fits CardGroup linking Pilot Agent, Multi-Node, Federation,
Licensing.
Corrections vs prior text:
- Tab is labelled Traffic in the UI (not Routing); all navigation references
updated.
- Proxy-mode bridge default is no idle close (env-overridable to opt into idle
teardown); prior 5-minute-teardown claim removed.
- Audit trail scope tightened: only opt-in / opt-out write durable rows;
tunnel-state and probe events live in the in-memory activity log.
Adds seven production screenshots under docs/images/sencho-mesh covering
Table view, opt-in sheet, graph (Tunnels and Aliases edge modes), Diagnostics,
activity log, and per-stack topology.
* docs(blueprints): add missing detail-state-review screenshot
Captures the Blueprint detail sheet with a deployment row in the
"Awaiting confirmation" status (stateful first-deploy gate), to fix the
broken image referenced at blueprint-model.mdx:132. mint broken-links
now reports zero broken references.
* docs(blueprints): deep rewrite with mental model, lifecycle, security, prerequisites
Restructures the Blueprints page against the v1-refresh template used by the
recently-refreshed mesh, secrets, and atomic-deployments pages. Adds a mental
model, prerequisites table, lifecycle and status-transition map, security and
trust boundaries section, practical workflows, common questions accordion,
and a Where Blueprints fits CardGroup. Removes the internal-style rollout
and watch-plan section. Replaces all nine production screenshots with fresh
captures against the production node signed in as admin, and adds two new
captures (federation pin policy table, stateless eviction dialog). Rewrites
the tier-gate Note to drop the fence-spec phrasing that violated Directive
31. Every retained claim is anchored to current backend or frontend code.
* docs(pilot-agent): recapture enrollment dialog with compose payload
Replaces the pre-0.84 docker-run capture with the current dialog (Compose
file, two-step instructions, "Copy compose file" button) and refines the
alt text to describe the captured content. URL and token redacted to
placeholder values during capture.
452 lines
34 KiB
Plaintext
452 lines
34 KiB
Plaintext
---
|
||
title: "Vulnerability Scanning"
|
||
description: "Scan container images and stack compose files for CVEs, secrets, and misconfigurations. Surface severity badges in the Resources Hub, compare scans over time, and gate deploys on policy violations."
|
||
---
|
||
|
||
Sencho integrates with [Trivy](https://trivy.dev) to scan container images and Compose files for vulnerabilities (CVEs), hardcoded secrets, and misconfigurations. Findings surface as severity badges in the Resources Hub and as drillable reports in the scan drawer. Manual scanning, secret and misconfig detection, scan history, comparison, and CVE suppressions are available on every tier. Skipper and Admiral add scheduled fleet scans, policy enforcement, SBOM, and SARIF exports.
|
||
|
||
<Frame>
|
||
<img src="/images/vulnerability-scanning/resources-badges.png" alt="Resources Hub Images table with severity badges (CRITICAL, HIGH, MEDIUM) on managed image rows alongside the Scan history button" />
|
||
</Frame>
|
||
|
||
## Prerequisites
|
||
|
||
The Trivy CLI must be available on the machine running Sencho. Trivy is not bundled with the Sencho Docker image; see [Installing Trivy](/operations/trivy-setup) for mount and installation options. Sencho checks for Trivy on startup and hides scanning UI when the binary is not available.
|
||
|
||
<Note>
|
||
Trivy is installed independently on each Sencho instance. When you select a remote node, **Settings → Security** shows only the scanner status for that node; install, update, or uninstall Trivy from there to manage the remote's binary. Scan policies, CVE suppressions, and misconfig acknowledgements are managed on the control instance and replicate fleet-wide.
|
||
</Note>
|
||
|
||
## Tier availability
|
||
|
||
| Feature | Community | Skipper | Admiral |
|
||
|---------|:---------:|:-------:|:-------:|
|
||
| Install / update / uninstall Trivy from Settings | ✓ | ✓ | ✓ |
|
||
| On-demand image vulnerability scanning | ✓ | ✓ | ✓ |
|
||
| Full scan (vulnerabilities + secrets) | ✓ | ✓ | ✓ |
|
||
| Compose file misconfiguration scanning | ✓ | ✓ | ✓ |
|
||
| Severity badges in the Resources Hub | ✓ | ✓ | ✓ |
|
||
| Scan results drawer with grouped tabs | ✓ | ✓ | ✓ |
|
||
| Post-deploy automated scanning | ✓ | ✓ | ✓ |
|
||
| Scan history sheet | ✓ | ✓ | ✓ |
|
||
| Scan comparison | ✓ | ✓ | ✓ |
|
||
| CVE suppressions | ✓ | ✓ | ✓ |
|
||
| Misconfig acknowledgements | ✓ | ✓ | ✓ |
|
||
| Scheduled fleet scans (all images on a node) | | ✓ | ✓ |
|
||
| Scan policies with `block_on_deploy` enforcement | | ✓ | ✓ |
|
||
| SBOM generation (SPDX, CycloneDX) | | ✓ | ✓ |
|
||
| SARIF export (code scanning integration) | | ✓ | ✓ |
|
||
| Auto-update of the managed Trivy binary | | | ✓ |
|
||
|
||
## On-demand scanning
|
||
|
||
Open the **Resources** tab and switch to the **Images** panel. When Trivy is available, every image row shows a shield icon alongside the inspect and delete actions. Click it and the menu offers two scan modes:
|
||
|
||
- **Scan (vulnerabilities)**: the fast path. Trivy reads package metadata only.
|
||
- **Full scan (vulnerabilities + secrets)**: also walks the image filesystem looking for hardcoded credentials, tokens, and keys. Slower because of the filesystem traversal.
|
||
|
||
A spinner replaces the shield while the scan runs. Most vulnerability scans finish in 10 to 60 seconds depending on image size and whether the Trivy database is cached. Full scans add the time needed to read the filesystem. When the scan completes, a severity badge appears in the row's Status column. Click the badge to open the results drawer.
|
||
|
||
### Reading severity badges
|
||
|
||
Hovering a badge reveals the breakdown by severity and the scan timestamp. The badge color reflects the highest severity found:
|
||
|
||
| Badge | Meaning |
|
||
|-------|---------|
|
||
| **CRITICAL** (red) | At least one vulnerability with a CVSS score of 9.0 or higher |
|
||
| **HIGH** (orange) | At least one high-severity vulnerability |
|
||
| **MEDIUM** (blue) | Only medium and lower vulnerabilities |
|
||
| **LOW** (muted) | Only low-severity vulnerabilities |
|
||
| **Clean** (green) | Scan completed with zero findings |
|
||
|
||
Scan results are cached by image digest. If the same digest is scanned again within 24 hours, Sencho returns the cached result instantly instead of re-running Trivy. To force a fresh scan, open the drawer and click **Re-scan**.
|
||
|
||
## The scan results drawer
|
||
|
||
The drawer opens as a right-side sheet with the breadcrumb `Security › Scans › <image-ref>`. The header surfaces the primary scan actions, the summary header reports severity counts and fixable findings, and the body groups findings across three tabs: **Vulnerabilities**, **Secrets**, and **Misconfigs**.
|
||
|
||
<Frame>
|
||
<img src="/images/vulnerability-scanning/scan-details-sheet.png" alt="Vulnerability scan drawer for lscr.io/linuxserver/swag:latest showing the Re-scan, Compare, CSV, and SARIF header actions, the severity summary (2 CRITICAL, 51 HIGH, 65 MEDIUM, 1 LOW), an SBOM download button, the severity filter pills, and a paged CVE table tinted by severity" />
|
||
</Frame>
|
||
|
||
### Header actions
|
||
|
||
- **Re-scan**: kick off a fresh scan, ignoring the digest cache.
|
||
- **Compare**: pick a baseline scan from the dropdown to diff against this one.
|
||
- **CSV**: export the full vulnerability list for offline review.
|
||
- **SARIF**: download the full scan (vulnerabilities, secrets, and misconfigs) as SARIF 2.1.0 for upload to GitHub code scanning or any SARIF-aware tool. Skipper or Admiral required.
|
||
|
||
The summary header below the actions reports the per-severity counts, the total, how many findings have a fix available, when the scan ran, and what triggered it. An **SBOM** button below the summary downloads a Software Bill of Materials in SPDX JSON or CycloneDX format (Skipper or Admiral).
|
||
|
||
### Vulnerabilities tab
|
||
|
||
Severity filter pills narrow the table, and the paginated list shows every CVE found with these columns:
|
||
|
||
- **CVE ID**: links to [cve.org](https://www.cve.org) for `CVE-…` identifiers and to the [GitHub Advisory Database](https://github.com/advisories) for `GHSA-…` identifiers.
|
||
- **Package**: the affected package name and installed version.
|
||
- **Severity**: badge matching the row tint.
|
||
- **Fixed**: the version that contains the fix, with a green checkmark when an upgrade is available.
|
||
|
||
Critical and high rows carry a left accent rail so the entries that need attention catch the eye even before you read the severity column. If the scan was evaluated against a [scan policy](#scan-policies) and the highest severity meets or exceeds the policy threshold, a destructive **Policy violation** banner appears at the top of the drawer naming the policy and the threshold it crossed.
|
||
|
||
### Secrets tab
|
||
|
||
Hardcoded credentials or keys detected in the image filesystem, with severity, rule id, title, and the file path including the line number range when available. Secret values are redacted: only the first eight characters of the match are stored, so exporting or comparing a scan cannot leak the underlying credential.
|
||
|
||
### Misconfigs tab
|
||
|
||
Misconfiguration findings with severity, check id, title, target file, and a suggested fix. Image scans typically have an empty Misconfigs tab; stack-config scans (see [Compose misconfiguration scanning](#compose-misconfiguration-scanning)) populate it.
|
||
|
||
## Post-deploy automated scanning
|
||
|
||
When Trivy is available, Sencho scans every deployed image in the background after a successful deploy. This applies to all deploy paths:
|
||
|
||
- Stack deploy and redeploy
|
||
- Stack update
|
||
- Template deploy from the App Store
|
||
- Git source apply
|
||
- Git source create
|
||
|
||
The deploy itself is never blocked by scanning. Scans run asynchronously and surface their results via the severity badges in the Resources Hub. If high or critical findings appear, an alert is dispatched through your configured [notification channels](/features/alerts-notifications).
|
||
|
||
### Opting out per deployment
|
||
|
||
The App Store deploy sheet has a **Security** section with a **Scan images for vulnerabilities after deploy** checkbox, enabled by default. Uncheck it to skip the post-deploy scan for that single deployment. This does not disable scan policies; it simply opts that deployment out of post-deploy scanning.
|
||
|
||
<Frame>
|
||
<img src="/images/vulnerability-scanning/app-store-toggle.png" alt="App Store deploy sheet Security section with the auto-scan checkbox enabled" />
|
||
</Frame>
|
||
|
||
## Scheduled fleet scans
|
||
|
||
<Note>
|
||
Scheduled fleet scans require a **Skipper** or **Admiral** license.
|
||
</Note>
|
||
|
||
You can run recurring scans of every image on a node through the standard [Scheduled Operations](/features/scheduled-operations) system. Create a scheduled task with action **Scan** and a cron expression. The scheduler iterates every image on the target node with a short delay between scans and records the result in the task's run history.
|
||
|
||
Use scheduled scans to keep badge counts fresh even for images that are rarely redeployed. A nightly cron like `0 3 * * *` is a sensible default for most fleets.
|
||
|
||
### Completion notifications
|
||
|
||
When a scheduled scan finishes, Sencho dispatches an alert through your configured [notification channels](/features/alerts-notifications). The alert names the task and summarises scanned, cached, and failed image counts:
|
||
|
||
- **Info** when every image scanned successfully.
|
||
- **Warning** when at least one image failed to scan.
|
||
|
||
Failures are usually transient (registry timeouts, missing credentials) and never stop the rest of the run from completing. The task's run history holds the detailed output.
|
||
|
||
## Scan policies
|
||
|
||
<Note>
|
||
Scan policies require a **Skipper** or **Admiral** license.
|
||
</Note>
|
||
|
||
Policies define severity thresholds that govern whether a stack can deploy. A policy with **Block on deploy** enabled runs a pre-flight scan on every image in the stack before `docker compose up` executes; if any image meets or exceeds the threshold, the deploy is rejected with a dialog listing the offending images. Policies with **Block on deploy** disabled still evaluate every post-deploy and scheduled scan and dispatch warning alerts when the threshold is exceeded.
|
||
|
||
See [Deploy Enforcement](/features/deploy-enforcement) for the full pre-flight flow, admin bypass path, and audit-log behavior.
|
||
|
||
<Frame>
|
||
<img src="/images/vulnerability-scanning/security-settings.png" alt="Settings Security page showing the masthead with Node, Policies, and Trivy status, the Vulnerability Scanner card with Auto-update Trivy toggle, an Add Policy button, and the No scan policies configured empty state" />
|
||
</Frame>
|
||
|
||
### Creating a policy
|
||
|
||
Go to **Settings → Security** and click **Add Policy**.
|
||
|
||
| Field | Description |
|
||
|-------|-------------|
|
||
| **Name** | A descriptive label (e.g. `prod-critical-block`). |
|
||
| **Stack pattern** | Optional glob against stack names (e.g. `prod-*`). Leave empty to match every stack. |
|
||
| **Max severity** | The threshold. If a scan finds any vulnerability at or above this severity, the policy fires. |
|
||
| **Block on deploy** | When enabled, deploys are rejected before `docker compose up` runs if any image violates the threshold. When disabled, the policy still evaluates post-deploy and scheduled scans and dispatches warning alerts on violations. |
|
||
| **Enabled** | Disabled policies are skipped during evaluation. |
|
||
|
||
### Policy scoping
|
||
|
||
When multiple policies match a deploy, Sencho picks the most specific one:
|
||
|
||
1. Policies scoped to a specific node win over global policies.
|
||
2. Policies with a stack pattern win over wildcard policies.
|
||
3. Disabled policies are never applied.
|
||
|
||
Only one policy is evaluated per deploy. Use a single tight pattern rather than overlapping policies for clarity.
|
||
|
||
<Note>
|
||
Policies created on a control instance replicate to every remote in the fleet automatically. See [Fleet Sync](/features/fleet-sync) for the replication, push retry, and replica demote behavior.
|
||
</Note>
|
||
|
||
### Example policies
|
||
|
||
**Block criticals and highs in production.** A tight gate that keeps known vulnerable base images out of your production fleet.
|
||
|
||
- **Name:** `prod-high-gate`
|
||
- **Stack pattern:** `prod-*`
|
||
- **Max severity:** `HIGH`
|
||
- **Block on deploy:** On
|
||
- **Enabled:** On
|
||
|
||
**Alert on criticals in staging, never block.** Lets engineers iterate without friction while still surfacing critical findings for triage.
|
||
|
||
- **Name:** `staging-critical-alert`
|
||
- **Stack pattern:** `staging-*`
|
||
- **Max severity:** `CRITICAL`
|
||
- **Block on deploy:** Off
|
||
- **Enabled:** On
|
||
|
||
### Creating a policy via the API
|
||
|
||
Policy CRUD endpoints are documented in the [Security API reference](/api-reference/security). A typical create call from CI looks like this:
|
||
|
||
```bash
|
||
curl -X POST https://your-sencho-instance:1852/api/security/policies \
|
||
-H "Authorization: Bearer YOUR_API_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"name": "prod-high-gate",
|
||
"stack_pattern": "prod-*",
|
||
"max_severity": "HIGH",
|
||
"block_on_deploy": 1,
|
||
"enabled": 1
|
||
}'
|
||
```
|
||
|
||
## Secret detection
|
||
|
||
Full scans ask Trivy to walk the image filesystem for patterns that look like hardcoded credentials, API tokens, cloud access keys, or private keys. Detection rules cover the common providers (AWS, GCP, GitHub, Slack, Stripe) plus generic high-entropy strings.
|
||
|
||
Trigger a full scan from the shield-icon menu on any image row with **Full scan (vulnerabilities + secrets)**. Findings appear on the **Secrets** tab of the drawer:
|
||
|
||
| Column | Description |
|
||
|--------|-------------|
|
||
| **Severity** | Trivy-assigned severity for the rule that matched. |
|
||
| **Rule** | The detection rule identifier (e.g. `aws-access-key-id`). |
|
||
| **Title** | A short description of what was detected. The second line shows a redacted excerpt of the match. |
|
||
| **Target** | The file path inside the image filesystem, including the line number range when available. |
|
||
|
||
Only the first eight characters of any matched secret are persisted. The full value is never written to the database, so exporting a scan or comparing two scans cannot leak the underlying credential.
|
||
|
||
Full scans take longer than vulnerability-only scans because Trivy reads every file in the image. If runtime is a concern, schedule full scans overnight and keep deploy-time scans on the default vulnerability-only setting.
|
||
|
||
## Compose misconfiguration scanning
|
||
|
||
Beyond package CVEs, Sencho can run `trivy config` against a stack's Compose file to flag insecure defaults before you deploy. Typical checks cover privileged containers, missing resource limits, host networking, mounted Docker sockets, and overly broad capabilities.
|
||
|
||
From any stack page, open the **More actions** overflow menu next to the Update button and select **Scan config**. Sencho runs the scanner against the stack's working directory and opens the scan drawer on the **Misconfigs** tab.
|
||
|
||
<Frame>
|
||
<img src="/images/vulnerability-scanning/scan-config-button.png" alt="Plex stack page with the More actions overflow menu open, showing the Scan config item with a shield icon and the Delete item below" />
|
||
</Frame>
|
||
|
||
The Misconfigs tab columns:
|
||
|
||
| Column | Description |
|
||
|--------|-------------|
|
||
| **Severity** | Rule severity (CRITICAL / HIGH / MEDIUM / LOW). |
|
||
| **Check** | Rule id or AVD identifier for the violated check. |
|
||
| **Title** | Short summary, linked to the upstream advisory when available. The second line shows Trivy's detailed message. |
|
||
| **Target** | The file that triggered the finding. |
|
||
| **Fix** | The recommended resolution. |
|
||
|
||
Config scans are stored in the same history as image scans with an `image_ref` of `stack:<name>`, so they appear on the Scan history sheet and can be exported as CSV.
|
||
|
||
## Misconfig acknowledgements
|
||
|
||
Some misconfigurations are intentional. A reverse proxy legitimately needs root to bind privileged ports; a network monitor might require host networking; an `--privileged` mount of the Docker socket might be exactly what your janitor service expects. Sencho lets admins acknowledge a rule so it stops triggering alerts on that stack without lowering the policy bar for every other stack.
|
||
|
||
Acknowledgements are applied at read time and never modify stored findings. Deleting an acknowledgement immediately resurfaces the underlying finding wherever it appears.
|
||
|
||
### Acknowledging from a scan result
|
||
|
||
1. Open a stack-config scan that contains the finding.
|
||
2. Click the shield-check icon at the right edge of the misconfig row. The dialog opens with the rule id prefilled and the stack pattern set to the current stack name, so a single click acknowledges *only this stack*. That is the narrowest possible scope by default.
|
||
3. Add a reason explaining why the misconfiguration is accepted. The reason is stored locally and replicates fleet-wide; it never appears in audit-log summaries to avoid leaking incident-tracker IDs or vendor secrets.
|
||
4. Optionally set an expiry in days. After expiry the acknowledgement stops applying and the finding resurfaces.
|
||
|
||
Acknowledged rows render dimmed with a strikethrough title; hovering surfaces the recorded reason.
|
||
|
||
### Managing acknowledgements
|
||
|
||
**Settings → Security** has a Misconfig Acknowledgements panel listing every acknowledgement on this control: rule id, optional stack pattern (glob), creator, expiry date, and a delete button. The same `replicated` badge that appears on CVE suppressions appears here for rows pushed from the control to a replica.
|
||
|
||
Replicas show the panel read-only; write operations return 403 with a "managed by control" message so configuration drift cannot accumulate on the leaf nodes.
|
||
|
||
### Scope and matching
|
||
|
||
An acknowledgement matches a misconfig finding when:
|
||
|
||
- `rule_id` equals the finding's `rule_id` (exact match), and
|
||
- `stack_pattern` is null **or** matches the scan's stack name via the same glob syntax used elsewhere (e.g. `traefik`, `web-*`), and
|
||
- the acknowledgement has not expired.
|
||
|
||
When more than one acknowledgement could match, Sencho picks the most specific: a stack-pinned ack beats a fleet-wide ack for the same rule.
|
||
|
||
### SARIF emission
|
||
|
||
Acknowledged misconfigs are emitted in the SARIF export with a `suppressions` entry of kind `external` and status `accepted`, mirroring CVE suppressions. Code-scanning dashboards that respect SARIF suppressions dismiss them with the recorded justification.
|
||
|
||
## SBOM generation
|
||
|
||
<Note>
|
||
SBOM generation requires a **Skipper** or **Admiral** license.
|
||
</Note>
|
||
|
||
A Software Bill of Materials (SBOM) is a machine-readable inventory of every package in a container image. SBOMs satisfy security frameworks (SLSA, Executive Order 14028, EU Cyber Resilience Act) and support offline supply-chain analysis.
|
||
|
||
From the scan results drawer, click **SBOM** below the summary and choose a format:
|
||
|
||
| Format | Use case |
|
||
|--------|----------|
|
||
| **SPDX JSON** | Widely supported, best for tooling integration. |
|
||
| **CycloneDX** | Richer dependency metadata, better for supply-chain analysis. |
|
||
|
||
The download starts immediately and uses the image's digest (when available) in the filename.
|
||
|
||
## SARIF export
|
||
|
||
<Note>
|
||
SARIF export requires a **Skipper** or **Admiral** license.
|
||
</Note>
|
||
|
||
SARIF (Static Analysis Results Interchange Format) is the standard format supported by GitHub code scanning, Microsoft Defender for Cloud, and most security dashboards. Sencho generates SARIF 2.1.0 documents from the stored scan results, so the download matches what you see in the drawer (same findings, same suppression state) without re-running Trivy.
|
||
|
||
From the scan drawer header, click **SARIF** to download the report. The file is named after the image reference with a `.sarif.json` extension.
|
||
|
||
What the export contains:
|
||
|
||
- **Vulnerabilities**: one SARIF result per CVE, with `security-severity` scored 9.8 (CRITICAL), 7.5 (HIGH), 5.0 (MEDIUM), 2.5 (LOW), or 0.0 (UNKNOWN). The affected package appears as a logical location (`<pkg>@<version>`).
|
||
- **Secrets**: rule ids are namespaced as `SECRET:<rule>`. Results point at the file and line number where the match was found.
|
||
- **Misconfigs**: rule ids are namespaced as `MISCONFIG:<rule>`. Results point at the Compose file that triggered the check.
|
||
- **Suppressions**: CVEs you have suppressed in Sencho are emitted with a SARIF `suppressions` entry of kind `external` and status `accepted`, so code-scanning dashboards dismiss them with the justification you recorded.
|
||
- **Acknowledged misconfigs**: misconfigs you have acknowledged in Sencho are emitted with the same `suppressions` shape so dashboards apply the same dismissal logic.
|
||
|
||
Each finding type is capped at 5000 rows to bound memory and serialisation time on pathological scans. When any type trips the cap, the SARIF run carries `properties.truncated = true`, `properties.row_limit`, and a `properties.totals` object with the original counts so downstream tooling can flag the export as partial.
|
||
|
||
Typical upload flow for GitHub code scanning:
|
||
|
||
```yaml
|
||
- name: Upload SARIF to GitHub
|
||
uses: github/codeql-action/upload-sarif@v3
|
||
with:
|
||
sarif_file: sencho-scan.sarif.json
|
||
```
|
||
|
||
## Scan history
|
||
|
||
Every scan Sencho runs is stored with its full vulnerability detail. Scan records are pruned automatically after 90 days to keep the database compact. The history powers two things: digest caching (skip re-scanning a digest already scanned within 24 hours) and trend insight (compare a new scan to its predecessor to see what changed).
|
||
|
||
Click **Scan history** from the top of the Resources Hub to open the scan history sheet over the current page. The sheet lists completed scans grouped by image, lets you search by image reference, and lets you tick two scans to compare. Close the sheet with Escape, by clicking the overlay, or by clicking the close button in the header.
|
||
|
||
<Frame>
|
||
<img src="/images/vulnerability-scanning/scan-history-sheet.png" alt="Scan history sheet over the Resources Hub showing 361 scans across 29 images, the Compare primary action enabled with two scans ticked, a search box, pagination, and scans grouped by image reference" />
|
||
</Frame>
|
||
|
||
## Comparing scans
|
||
|
||
Compare any two completed scans for an image to see what changed.
|
||
|
||
**From the scan history sheet**: tick two scans (one baseline, one newer) and click **Compare**. Selecting a third scan replaces the oldest selection.
|
||
|
||
**From an open scan**: click **Compare** in the drawer header, then pick a baseline scan from the dropdown. Only completed scans for the same image appear.
|
||
|
||
The comparison sheet shows:
|
||
|
||
- A **delta ribbon** summarizing the net change per severity (CRITICAL, HIGH, MEDIUM, LOW). Net-positive deltas on CRITICAL render in destructive red so a regression on the worst tier is immediately visible.
|
||
- Filter pills to switch between **Added** (new findings since the baseline), **Removed** (resolved findings), and **Unchanged** (findings present in both).
|
||
- A sorted table of CVEs with severity, affected package, and direct links to the upstream advisory. CVE-prefixed identifiers resolve to [cve.org](https://www.cve.org); GHSA identifiers resolve to the [GitHub Advisory Database](https://github.com/advisories). Critical and high rows carry the same left-rail tint as the scan drawer for visual continuity.
|
||
|
||
Comparisons are scoped to a single node; scans taken on different nodes cannot be compared against each other.
|
||
|
||
Cross-image comparisons (picking scans from two different image references) are allowed but flagged with a warning, since package-level changes may reflect image differences rather than CVE drift. In that mode, the **Unchanged** pill is relabeled to **Shared** to reflect that same CVE + package matches across different images are not necessarily the same finding.
|
||
|
||
Up to 1000 findings per scan are loaded for comparison. When a scan exceeds this limit, the sheet shows a truncation banner indicating the comparison may be incomplete.
|
||
|
||
<Frame>
|
||
<img src="/images/vulnerability-scanning/scan-compare-sheet.png" alt="Compare scans sheet diffing two profilarr scans, with baseline and current row, a truncation banner, a delta ribbon (HIGH -79, MEDIUM +79), Added/Removed/Unchanged filter pills, and a diff table tinted by severity" />
|
||
</Frame>
|
||
|
||
## How it works
|
||
|
||
1. On startup, Sencho looks for the `trivy` binary on `PATH` (and the path configured by `TRIVY_BIN` if set) and caches its availability.
|
||
2. When a scan is triggered, Sencho resolves the image digest via Docker and checks the 24-hour cache. If a completed scan exists for that digest, it is returned instantly.
|
||
3. Otherwise, Sencho spawns `trivy image --format json --quiet <image-ref>` and parses the JSON output into the vulnerability database.
|
||
4. Private registry credentials are forwarded automatically by writing a temporary `DOCKER_CONFIG` for the Trivy subprocess, then deleting it when the scan completes.
|
||
5. Scan status, counts per severity, and the full vulnerability list are persisted for display in the drawer and for policy evaluation.
|
||
|
||
## Troubleshooting
|
||
|
||
<AccordionGroup>
|
||
<Accordion title="Scan button is not visible">
|
||
Sencho hides scanning UI when the Trivy binary is not detected. Check **Settings → Security** for the scanner status, then follow [Installing Trivy](/operations/trivy-setup) if it is missing.
|
||
</Accordion>
|
||
<Accordion title="Scans time out">
|
||
The default scan timeout is 5 minutes. Very large images (2 GB or more) over a slow connection may exceed this; pre-pulling the image to the host speeds up the scan significantly because Trivy then works against the local image store.
|
||
</Accordion>
|
||
<Accordion title="Private registry images fail to scan">
|
||
Sencho forwards the same registry credentials configured under **Settings → Registries** to Trivy. If a pull works in Sencho but a scan fails, make sure the image has been pulled at least once so Trivy can work against the cached local image.
|
||
</Accordion>
|
||
<Accordion title="Badge is out of date after an image update">
|
||
Post-deploy scanning only runs on deploy actions. For long-running images that aren't redeployed, schedule a recurring scan (Skipper or Admiral) or click the shield icon in the Resources Hub to re-scan on demand.
|
||
</Accordion>
|
||
<Accordion title="A scan shows in progress for a long time">
|
||
Scans have a 5-minute internal timeout. The scheduler sweeps every tick and marks any scan stuck `in_progress` for more than 15 minutes as failed, so the UI always recovers on its own. Wait for the sweep, then click the shield icon again to trigger a fresh scan.
|
||
</Accordion>
|
||
<Accordion title="Trivy is not detected after installing it">
|
||
Sencho re-checks for the Trivy binary every ten minutes from the scheduler. Install Trivy on the host, wait for the next window, and the scanning UI lights up automatically.
|
||
</Accordion>
|
||
<Accordion title="Collecting diagnostic logs for support">
|
||
Enable **Developer Mode** under **Settings → Developer** and trigger the failing scan again. The backend logs verbose `[Trivy:diag]` entries covering detection timing, cache hits, Trivy invocation, and parse statistics. Attach these lines when filing a support issue. Turn Developer Mode off once you have captured the output.
|
||
</Accordion>
|
||
<Accordion title="Post-deploy scan failure notifications">
|
||
When a post-deploy scan fails for a specific image (for example because Trivy could not resolve a private registry pull), Sencho dispatches a warning-level alert through your configured notification channels. The deploy itself is never blocked by a scan failure.
|
||
</Accordion>
|
||
<Accordion title="A deploy was blocked by a policy I did not expect">
|
||
The block dialog names the policy that fired and lists every image that violated the threshold. Open **Settings → Security** and review the matching policy: check the stack pattern glob and the max severity. If the policy should not apply, tighten the pattern (for example `staging-*` instead of `*`) or turn **Block on deploy** off to keep the evaluation in alert-only mode. Admins can bypass a single deploy with the **Deploy anyway** button; every bypass is recorded in the [Audit Log](/features/audit-log) with the actor, policy, and violation list.
|
||
</Accordion>
|
||
<Accordion title="Trivy is not installed and a deploy with a block policy went through">
|
||
Sencho fails open when Trivy is not installed on the target node, so operators are never locked out by tooling state. A warning alert is dispatched through your configured notification channels with the message `Pre-deploy scan for "<stack>" skipped: Trivy not installed on this node`. Install Trivy from **Settings → Security** to enforce the policy; see [Installing Trivy](/operations/trivy-setup) for options.
|
||
</Accordion>
|
||
<Accordion title="Compare button is disabled in the scan history sheet">
|
||
The Compare primary action enables only after exactly two scans are ticked. Selecting zero, one, or three scans leaves it disabled. If you have only one scan for an image, trigger a second scan from the Resources Hub (or wait for a scheduled scan), then return to Scan history and tick both.
|
||
</Accordion>
|
||
<Accordion title="Comparison shows unexpected results">
|
||
Two common causes:
|
||
|
||
- **Cross-image comparison.** When the Baseline and Current rows at the top of the sheet point at different image references, a warning banner appears and the "Unchanged" pill is labeled "Shared". Items in that bucket match on CVE + package name but may not be the same finding across two distinct images. Stick to scans of the same image reference for apples-to-apples drift analysis.
|
||
- **Truncated scans.** When either scan has more than 1000 stored findings, the sheet shows a truncation banner. Items past the 1000-row cap do not contribute to the Added / Removed / Unchanged buckets and totals may be misleading. Re-run the scan with a tighter image or scope the investigation to the most severe findings to avoid truncation.
|
||
</Accordion>
|
||
<Accordion title="An older scan is missing from Scan history">
|
||
The Scan history sheet uses server-driven pagination. If you know the scan exists but cannot see it, use the search box to filter by image reference, or page forward with the arrows in the card header. Scans older than 90 days are pruned automatically to keep the database compact.
|
||
</Accordion>
|
||
<Accordion title="Scan policies are missing on one of my nodes">
|
||
Scan policies are managed from the control Sencho instance and replicate to every remote. On a replica, **Settings → Security** shows a banner explaining that rules are managed upstream. See [Fleet Sync](/features/fleet-sync) for how replication works and how to investigate push failures.
|
||
</Accordion>
|
||
<Accordion title="I suppressed a CVE but the scan badge count is unchanged">
|
||
Badge counts reflect raw findings so alerting and policy evaluation stay accurate. Open the scan drawer to confirm the row is dimmed with a shield-off icon. See [CVE Suppressions](/features/cve-suppressions) for how the filter is applied across the drawer, compare sheet, and other read surfaces.
|
||
</Accordion>
|
||
<Accordion title="The Secrets tab is empty on an image I expect to contain credentials">
|
||
Secret detection matches against Trivy's built-in rule set, which focuses on well-known provider patterns. Plain text passwords, custom token formats, or values that do not match any published rule will not appear. Make sure you picked **Full scan (vulnerabilities + secrets)** from the shield-icon menu; a plain vulnerability scan does not walk the filesystem.
|
||
</Accordion>
|
||
<Accordion title="Compose misconfiguration scan returns 404">
|
||
The scanner needs a Compose file in the stack directory. If the stack was created outside Sencho and the working directory does not contain a file named `compose.yml`, `compose.yaml`, `docker-compose.yml`, or `docker-compose.yaml`, the scan returns 404. Name the file accordingly or keep the stack under Sencho's managed compose directory.
|
||
</Accordion>
|
||
<Accordion title="SARIF download returns 409 Scan not complete">
|
||
SARIF export requires a completed scan. If a scan failed, timed out, or is still running, the button downloads nothing and the server returns a 409. Trigger a fresh scan from the Resources Hub or the stack page, wait for the drawer to populate, then export again.
|
||
</Accordion>
|
||
<Accordion title="SARIF download is missing findings I see in the drawer">
|
||
Each finding type (vulnerabilities, secrets, misconfigs) is capped at 5000 rows in the SARIF export. When any type trips the cap, the SARIF run includes `properties.truncated: true` along with the original counts, and the server logs a warning. The drawer paginates beyond 5000 so it shows everything, but the export is bounded for memory safety. If you need every row, narrow the scope (per-stack scan, per-image scan) before exporting.
|
||
</Accordion>
|
||
<Accordion title="Acknowledge button is missing on a misconfig finding">
|
||
The button is admin-only and hidden on replica nodes. Replicas read acknowledgements from the control via fleet sync; mutations happen on the control. If you are an admin on the control and still do not see the button, the row is likely already acknowledged. Look for the dimmed strikethrough rendering and hover for the recorded reason.
|
||
</Accordion>
|
||
<Accordion title="Findings reappeared after deleting a CVE suppression or misconfig acknowledgement">
|
||
Suppressions and acknowledgements are applied at read time and never modify stored finding rows. Removing one immediately resurfaces the underlying finding everywhere it appears (drawer, compare sheet, badge counts, SARIF export). The behavior is intentional: deleting an acknowledgement is meant to revert the operator decision, not to mask history.
|
||
</Accordion>
|
||
<Accordion title="Outbound traffic to ghcr.io and aquasecurity from the scanner host">
|
||
Trivy fetches its CVE and secret-rule database from public registries on first scan and refreshes periodically; that egress is required for vulnerability scanning to work. Sencho does not emit telemetry of its own. If your environment forbids egress, see Trivy's [air-gapped scanning guide](https://trivy.dev/latest/docs/advanced/air-gap/) for how to pre-seed the database and run scans with `--offline-scan`.
|
||
</Accordion>
|
||
<Accordion title="Compose stack scan returns 409 Already scanning this stack">
|
||
Sencho deduplicates concurrent scans of the same stack so two simultaneous calls cannot double-process the result. Wait for the in-flight scan to finish (its row appears in Scan history with status `in_progress` and flips to `completed` or `failed` shortly after) and trigger again.
|
||
</Accordion>
|
||
</AccordionGroup>
|