mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-09 10:21:03 +00:00
61bac08027
* 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.
71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react';
|
|
import { apiFetch } from '@/lib/api';
|
|
import type { TrivyStatus, TrivyUpdateCheck } from '@/types/security';
|
|
|
|
const INITIAL_STATUS: TrivyStatus = {
|
|
available: false,
|
|
version: null,
|
|
source: 'none',
|
|
autoUpdate: false,
|
|
busy: false,
|
|
};
|
|
|
|
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,
|
|
});
|
|
} catch (err) {
|
|
console.error('Failed to fetch Trivy status:', err);
|
|
}
|
|
}, []);
|
|
|
|
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 };
|
|
}
|