mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-09 18:32:52 +00:00
dc8370f5a4
* fix(security): harden Trivy scan lifecycle, logging, and docs - Call TrivyService.initialize() at startup so capability state is accurate before first request; add periodic re-detect to the scheduler so newly installed Trivy binaries light up without a restart. - Add markStaleScansAsFailed sweep (+ idx_vuln_scans_status index) to recover any scan row left in_progress after a crash or timeout; sweep runs before the paid-tier gate so every tier self-heals. - Split scanImage persistence into beginScan/finishScan so the manual scan route owns a single code path and can return a scanId synchronously while work continues asynchronously. - Validate image refs on /api/security/scan and /sbom via new utility; defense-in-depth against shell-metacharacter payloads. - Dispatch a warning-level alert when a post-deploy scan fails so the operator has a user-visible path to the failure instead of a silent log. - Share DIGEST_CACHE_TTL_MS and severity ordering across service and route layers; remove dead invalidateDetection(). - Add [Trivy:diag] logging gated behind developer_mode for support diagnostics; production logs unchanged. - Frontend: defensive toast fallback chain, sr-only SheetDescription, and a truncation badge when the 500-item detail fetch is capped. - Tests: extend trivy-service and vulnerability-db suites; add image-ref and severity unit tests. - Docs: expand vulnerability-scanning troubleshooting with recovery, re-detect, and diagnostic-log guidance; link Dockerfile comment to trivy-setup. * fix(security): drop unnecessary escape in image-ref forbidden-char regex
40 lines
1.7 KiB
TypeScript
40 lines
1.7 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { severityRank, isSeverityAtLeast, SEVERITY_ORDER } from '../utils/severity';
|
|
|
|
describe('severityRank', () => {
|
|
it('orders severities CRITICAL > HIGH > MEDIUM > LOW > UNKNOWN', () => {
|
|
expect(severityRank('CRITICAL')).toBeGreaterThan(severityRank('HIGH'));
|
|
expect(severityRank('HIGH')).toBeGreaterThan(severityRank('MEDIUM'));
|
|
expect(severityRank('MEDIUM')).toBeGreaterThan(severityRank('LOW'));
|
|
expect(severityRank('LOW')).toBeGreaterThan(severityRank('UNKNOWN'));
|
|
});
|
|
|
|
it('returns -1 for null/undefined so missing severities sort below UNKNOWN', () => {
|
|
expect(severityRank(null)).toBe(-1);
|
|
expect(severityRank(undefined)).toBe(-1);
|
|
expect(severityRank(null)).toBeLessThan(severityRank('UNKNOWN'));
|
|
});
|
|
|
|
it('exports a SEVERITY_ORDER array that covers every known severity', () => {
|
|
expect(SEVERITY_ORDER).toEqual(['UNKNOWN', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL']);
|
|
});
|
|
});
|
|
|
|
describe('isSeverityAtLeast', () => {
|
|
it('returns true when actual meets or exceeds the threshold', () => {
|
|
expect(isSeverityAtLeast('CRITICAL', 'HIGH')).toBe(true);
|
|
expect(isSeverityAtLeast('HIGH', 'HIGH')).toBe(true);
|
|
expect(isSeverityAtLeast('MEDIUM', 'LOW')).toBe(true);
|
|
});
|
|
|
|
it('returns false when actual is below the threshold', () => {
|
|
expect(isSeverityAtLeast('LOW', 'HIGH')).toBe(false);
|
|
expect(isSeverityAtLeast('MEDIUM', 'CRITICAL')).toBe(false);
|
|
});
|
|
|
|
it('returns false for missing severities regardless of threshold', () => {
|
|
expect(isSeverityAtLeast(null, 'LOW')).toBe(false);
|
|
expect(isSeverityAtLeast(undefined, 'UNKNOWN')).toBe(false);
|
|
});
|
|
});
|