mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-10 10:49:35 +00:00
feat(security): one-click managed Trivy install (#643)
* feat(security): one-click managed Trivy install Add a Vulnerability Scanner card to Settings, Security with install, update, uninstall, and auto-update controls (Admiral-only). The installer downloads a verified Trivy release into the existing data volume at /app/data/bin/trivy and defaults the cache to /app/data/trivy-cache, so no host mounts or extra env vars are required. Detection probes the managed path, a TRIVY_BIN override, and the host PATH, distinguishing managed vs host installs. A daily scheduled check surfaces available Trivy updates, installs them automatically when opted in, and dedupes notifications per version. * fix(frontend): silence react-hooks/set-state-in-effect in useTrivyStatus The initial status fetch and managed-source update check both call setState from the effect body. Match the existing pattern used in useDashboardData / SSOSection and disable the rule at the call site.
This commit is contained in:
@@ -1,28 +1,70 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { apiFetch } from '@/lib/api';
|
||||
import type { TrivyStatus } from '@/types/security';
|
||||
import type { TrivyStatus, TrivyUpdateCheck } from '@/types/security';
|
||||
|
||||
export function useTrivyStatus(): TrivyStatus {
|
||||
const [status, setStatus] = useState<TrivyStatus>({ available: false, version: null });
|
||||
const INITIAL_STATUS: TrivyStatus = {
|
||||
available: false,
|
||||
version: null,
|
||||
source: 'none',
|
||||
autoUpdate: false,
|
||||
busy: false,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
apiFetch('/security/trivy-status')
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((d) => {
|
||||
if (cancelled || !d) return;
|
||||
setStatus({
|
||||
available: !!d.available,
|
||||
version: typeof d.version === 'string' ? d.version : null,
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Failed to fetch Trivy status:', err);
|
||||
export interface UseTrivyStatusResult {
|
||||
status: TrivyStatus;
|
||||
updateCheck: TrivyUpdateCheck | null;
|
||||
refresh: () => Promise<void>;
|
||||
refreshUpdateCheck: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function useTrivyStatus(): UseTrivyStatusResult {
|
||||
const [status, setStatus] = useState<TrivyStatus>(INITIAL_STATUS);
|
||||
const [updateCheck, setUpdateCheck] = useState<TrivyUpdateCheck | null>(null);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
try {
|
||||
const r = await apiFetch('/security/trivy-status');
|
||||
if (!r.ok) return;
|
||||
const d = await r.json();
|
||||
setStatus({
|
||||
available: !!d.available,
|
||||
version: typeof d.version === 'string' ? d.version : null,
|
||||
source: d.source === 'managed' || d.source === 'host' ? d.source : 'none',
|
||||
autoUpdate: !!d.autoUpdate,
|
||||
busy: !!d.busy,
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch Trivy status:', err);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return status;
|
||||
const refreshUpdateCheck = useCallback(async () => {
|
||||
try {
|
||||
const r = await apiFetch('/security/trivy-update-check');
|
||||
if (!r.ok) {
|
||||
setUpdateCheck(null);
|
||||
return;
|
||||
}
|
||||
const d = (await r.json()) as TrivyUpdateCheck;
|
||||
setUpdateCheck(d);
|
||||
} catch {
|
||||
setUpdateCheck(null);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
void refresh();
|
||||
}, [refresh]);
|
||||
|
||||
useEffect(() => {
|
||||
if (status.source === 'managed') {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
void refreshUpdateCheck();
|
||||
} else {
|
||||
setUpdateCheck(null);
|
||||
}
|
||||
}, [status.source, refreshUpdateCheck]);
|
||||
|
||||
return { status, updateCheck, refresh, refreshUpdateCheck };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user