mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-22 08:06:42 +00:00
feat(images): Trivy-powered vulnerability scanning (#635)
* feat(images): Trivy-powered vulnerability scanning Scan container images for known CVEs via Trivy. On-demand scanning and severity badges are available on every tier; scheduled scans, scan policies, SBOM generation, and scan history are gated to Skipper+. - New TrivyService (binary detection, per-image scan, SBOM, digest cache) - Three new tables: vulnerability_scans, vulnerability_details, scan_policies - 12 routes under /api/security (scan, results, summaries, SBOM, policies, compare) - Post-deploy async scans wired into all five deploy paths, with a per-deploy opt-out toggle in the App Store deploy sheet - "scan" action type added to SchedulerService for fleet-wide recurring scans - Frontend: severity badges in Resources Hub with animated cursor detail, scan results drawer with vulnerability table and filters, and a new Security section in Settings for scan policy CRUD - Policy threshold violations dispatch a warning or critical alert based on the policy's block_on_deploy flag; deploys themselves are never blocked * fix(security): compute scan age in useEffect to satisfy react-hooks/purity
This commit is contained in:
@@ -16,7 +16,7 @@ import { SENCHO_SETTINGS_CHANGED } from '@/lib/events';
|
||||
import type { SenchoSettingsChangedDetail } from '@/lib/events';
|
||||
import {
|
||||
Shield, Activity, Bell, Code, Server, Package, X,
|
||||
Info, Crown, Webhook, Users, Zap, Database, LifeBuoy, Lock, Tag, Route,
|
||||
Info, Crown, Webhook, Users, Zap, Database, LifeBuoy, Lock, Tag, Route, ShieldCheck,
|
||||
} from 'lucide-react';
|
||||
import { NodeManager } from './NodeManager';
|
||||
import { useNodes } from '@/context/NodeContext';
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
NotificationsSection,
|
||||
NotificationRoutingSection,
|
||||
WebhooksSection,
|
||||
SecuritySection,
|
||||
DeveloperSection,
|
||||
AppStoreSection,
|
||||
SupportSection,
|
||||
@@ -44,7 +45,8 @@ import type { PatchableSettings, SectionId } from './settings';
|
||||
|
||||
const GLOBAL_ONLY_SECTIONS: ReadonlySet<SectionId> = new Set<SectionId>([
|
||||
'account', 'license', 'users', 'sso', 'api-tokens', 'registries',
|
||||
'labels', 'notifications', 'notification-routing', 'webhooks', 'nodes', 'appstore',
|
||||
'labels', 'notifications', 'notification-routing', 'webhooks', 'security',
|
||||
'nodes', 'appstore',
|
||||
]);
|
||||
|
||||
interface SettingsModalProps {
|
||||
@@ -305,6 +307,8 @@ export function SettingsModal({ isOpen, onClose, initialSection }: SettingsModal
|
||||
return <NotificationRoutingSection />;
|
||||
case 'webhooks':
|
||||
return <WebhooksSection isPaid={isPaid} />;
|
||||
case 'security':
|
||||
return <SecuritySection isPaid={isPaid} />;
|
||||
case 'developer':
|
||||
return (
|
||||
<DeveloperSection
|
||||
@@ -395,6 +399,9 @@ export function SettingsModal({ isOpen, onClose, initialSection }: SettingsModal
|
||||
{!isRemote && (
|
||||
<NavButton section="webhooks" icon={<Webhook className="w-4 h-4 mr-2" />} label="Webhooks" locked={!isPaid} />
|
||||
)}
|
||||
{!isRemote && isAdmin && (
|
||||
<NavButton section="security" icon={<ShieldCheck className="w-4 h-4 mr-2" />} label="Security" locked={!isPaid} />
|
||||
)}
|
||||
<NavButton
|
||||
section="developer"
|
||||
icon={<Code className="w-4 h-4 mr-2" />}
|
||||
|
||||
Reference in New Issue
Block a user