mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-28 11:17:07 +00:00
feat: open security basics, manual fleet ops, and basic fleet management to Community (#930)
Realign tier guards to the user-stated philosophy: Community covers
deploy/monitor at scale plus security basics, Skipper adds automation
and advanced fleet management, Admiral keeps enterprise control.
Community now includes:
- Trivy install / uninstall / update from the Settings Hub (admin role)
- CVE suppressions CRUD (admin role; replicates fleet-wide)
- Manual image scan with vuln, secret, and misconfig results
- Stack-config scan, scan comparison
- Manual fleet snapshots: create, list, view, restore, delete
- Per-node Sencho self-update (Check Updates + per-node Update)
- Fleet Overview search, sort, filters, node-card expand, auto-refresh
Stays paid:
- Scan policies with block_on_deploy enforcement (Skipper+)
- SBOM (SPDX, CycloneDX), SARIF export (Skipper+)
- Bulk Update All across the fleet (Skipper+)
- Scheduled snapshot create (now Skipper, was Admiral)
- Trivy auto-update toggle, fleet-wide policy push (Admiral)
The Settings -> Security tab is unhidden by setting the registry tier to
null. The SecuritySection no longer early-returns a PaidGate; the policy
list, Add Policy button, and policy dialogs are wrapped in {isPaid && }.
The Fleet view drops isPaid gates on the Snapshots tab, Check Updates
button, per-node update handlers, OverviewToolbar grid controls, the
NodeCard expand affordance, and the auto-refresh notice. The
NodeUpdatesSheet receives a canBulkUpdate prop and gates the Update All
button on it. useFleetUpdateStatus and useFleetPolling drop their isPaid
guards so polling runs for Community; useFleetOverview drops the isPaid
wrap on the filter and sort path.
Backend route guards are flipped per the matrix above. The scheduler
tick and requireScheduledTaskTier add 'snapshot' to the Skipper+ branch.
Backend test assertions are inverted for the now-Community endpoints
and a positive Skipper-snapshot-task test is added.
Documentation across features/, api-reference/, and operations/ is
updated to reflect the new tier mapping.
This commit is contained in:
@@ -34,11 +34,10 @@ export function FleetView({ onNavigateToNode }: FleetViewProps) {
|
||||
const experimental = useExperimental();
|
||||
|
||||
const { prefs, updatePrefs } = useFleetPreferences();
|
||||
const updateStatus = useFleetUpdateStatus({ isPaid });
|
||||
const updateStatus = useFleetUpdateStatus();
|
||||
const overview = useFleetOverview({ isPaid, prefs, updatePrefs, updateStatuses: updateStatus.updateStatuses });
|
||||
|
||||
useFleetPolling({
|
||||
isPaid,
|
||||
fetchOverview: overview.fetchOverview,
|
||||
fetchUpdateStatus: updateStatus.fetchUpdateStatus,
|
||||
updateStatuses: updateStatus.updateStatuses,
|
||||
@@ -69,13 +68,11 @@ export function FleetView({ onNavigateToNode }: FleetViewProps) {
|
||||
<TabsHighlightItem value="overview">
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
</TabsHighlightItem>
|
||||
{isPaid && (
|
||||
<TabsHighlightItem value="snapshots">
|
||||
<TabsTrigger value="snapshots">
|
||||
<Camera className="w-4 h-4 mr-1.5" />Snapshots
|
||||
</TabsTrigger>
|
||||
</TabsHighlightItem>
|
||||
)}
|
||||
<TabsHighlightItem value="snapshots">
|
||||
<TabsTrigger value="snapshots">
|
||||
<Camera className="w-4 h-4 mr-1.5" />Snapshots
|
||||
</TabsTrigger>
|
||||
</TabsHighlightItem>
|
||||
{isAdmiral && experimental && (
|
||||
<TabsHighlightItem value="routing">
|
||||
<TabsTrigger value="routing">
|
||||
@@ -114,17 +111,15 @@ export function FleetView({ onNavigateToNode }: FleetViewProps) {
|
||||
</TabsHighlight>
|
||||
</TabsList>
|
||||
<div className="flex items-center gap-2">
|
||||
{isPaid && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={updateStatus.checkUpdates}
|
||||
className="gap-2"
|
||||
>
|
||||
<Search className="w-4 h-4" />
|
||||
Check Updates
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={updateStatus.checkUpdates}
|
||||
className="gap-2"
|
||||
>
|
||||
<Search className="w-4 h-4" />
|
||||
Check Updates
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@@ -155,22 +150,19 @@ export function FleetView({ onNavigateToNode }: FleetViewProps) {
|
||||
labelFilters={overview.labelFilters}
|
||||
onLabelFiltersChange={overview.setLabelFilters}
|
||||
onClearFilters={overview.clearFilters}
|
||||
isPaid={isPaid}
|
||||
fleetStackLabelMap={overview.fleetStackLabelMap}
|
||||
updateStatusMap={overview.updateStatusMap}
|
||||
onNavigateToNode={onNavigateToNode}
|
||||
onUpdate={isPaid ? updateStatus.triggerNodeUpdate : undefined}
|
||||
onUpdate={updateStatus.triggerNodeUpdate}
|
||||
updatingNodeId={updateStatus.updatingNodeId}
|
||||
onRetryUpdate={isPaid ? updateStatus.retryNodeUpdate : undefined}
|
||||
onDismissUpdate={isPaid ? updateStatus.dismissNodeUpdate : undefined}
|
||||
onRetryUpdate={updateStatus.retryNodeUpdate}
|
||||
onDismissUpdate={updateStatus.dismissNodeUpdate}
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
{isPaid && (
|
||||
<TabsContent value="snapshots">
|
||||
<FleetSnapshots />
|
||||
</TabsContent>
|
||||
)}
|
||||
<TabsContent value="snapshots">
|
||||
<FleetSnapshots />
|
||||
</TabsContent>
|
||||
{isAdmiral && experimental && (
|
||||
<TabsContent value="routing">
|
||||
<AdmiralGate>
|
||||
@@ -233,6 +225,7 @@ export function FleetView({ onNavigateToNode }: FleetViewProps) {
|
||||
retryNodeUpdate={updateStatus.retryNodeUpdate}
|
||||
dismissNodeUpdate={updateStatus.dismissNodeUpdate}
|
||||
triggerUpdateAll={updateStatus.triggerUpdateAll}
|
||||
canBulkUpdate={isPaid}
|
||||
/>
|
||||
|
||||
<LocalUpdateConfirmDialog
|
||||
|
||||
Reference in New Issue
Block a user