/** * Verifies the `scanners_used` dimension of the digest cache key. * * A vuln-only row must not satisfy a lookup for a vuln+secret scan; otherwise * a secret-scan request would silently reuse a stale finding set. */ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { setupTestDb, cleanupTestDb } from './helpers/setupTestDb'; let tmpDir: string; let DatabaseService: typeof import('../services/DatabaseService').DatabaseService; beforeAll(async () => { tmpDir = await setupTestDb(); ({ DatabaseService } = await import('../services/DatabaseService')); }); afterAll(() => { cleanupTestDb(tmpDir); }); function seedScan(overrides: Partial<{ scanners_used: string; scanned_at: number }> = {}): number { const db = DatabaseService.getInstance(); return db.createVulnerabilityScan({ node_id: 1, image_ref: 'alpine:3.19', image_digest: 'sha256:deadbeef', scanned_at: overrides.scanned_at ?? Date.now(), total_vulnerabilities: 0, critical_count: 0, high_count: 0, medium_count: 0, low_count: 0, unknown_count: 0, fixable_count: 0, secret_count: 0, misconfig_count: 0, scanners_used: overrides.scanners_used ?? 'vuln', highest_severity: null, os_info: 'alpine 3.19', trivy_version: '0.56.0', scan_duration_ms: 1200, triggered_by: 'manual', status: 'completed', error: null, stack_context: null, }); } describe('getLatestScanByDigest scanners scoping', () => { it('returns null for a vuln+secret lookup when only a vuln row exists', () => { const db = DatabaseService.getInstance(); seedScan({ scanners_used: 'vuln' }); expect( db.getLatestScanByDigest('sha256:deadbeef', 'vuln,secret'), ).toBeNull(); }); it('returns the matching row when scanners_used matches exactly', () => { const db = DatabaseService.getInstance(); const id = seedScan({ scanners_used: 'vuln,secret', scanned_at: Date.now() + 10 }); const row = db.getLatestScanByDigest('sha256:deadbeef', 'vuln,secret'); expect(row?.id).toBe(id); }); it('falls back to latest completed row when scannersUsed omitted', () => { const db = DatabaseService.getInstance(); const row = db.getLatestScanByDigest('sha256:deadbeef'); expect(row).not.toBeNull(); }); it('returns null for digest with no completed scans', () => { const db = DatabaseService.getInstance(); expect(db.getLatestScanByDigest('sha256:notreal', 'vuln')).toBeNull(); }); });