from pathlib import Path import sys import pytest sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'app')) import docker_shadow import scanner @pytest.mark.parametrize('partial', [ {'warnings': ['synthetic warning']}, {'degraded': True}, {'scan_meta': {'docker_layer_scope': {'coverage_complete': False}}}, {'scan_meta': {'docker_full_recovery': {'coverage_complete': False}}}, ]) def test_full_reference_rejects_incomplete_without_false_regression(monkeypatch, partial, capsys): class DB: def docker_adaptive_shadow_control_identities(self, _scan_id): return {('fixture', 'a' * 64)}, set() result = {'findings': [], 'errors': [], 'retryable': False, **partial} monkeypatch.setattr(scanner, 'scan_docker_image', lambda *a, **k: result) monkeypatch.setattr(scanner.docker_token_manager, 'get_next_config', lambda: None) metrics = docker_shadow.private_full_side_metrics( DB(), {'target_scan_id': 1, 'normalized_target': 'private-synthetic-target'}, {'timeout_sec': 5}) assert metrics['failure_count'] == 1 assert metrics['diagnostic_full_incomplete'] == 1 assert metrics['safety_regression_count'] == 0 assert result == {} assert 'private-synthetic-target' not in capsys.readouterr().out def test_successful_full_recovery_is_a_valid_reference(monkeypatch): class DB: def docker_adaptive_shadow_control_identities(self, _scan_id): return set(), set() result = {'findings': [], 'errors': [], 'scan_meta': {'docker_full_recovery': {'coverage_complete': True}}} monkeypatch.setattr(scanner, 'scan_docker_image', lambda *a, **k: result) monkeypatch.setattr(scanner.docker_token_manager, 'get_next_config', lambda: None) metrics = docker_shadow.private_full_side_metrics( DB(), {'target_scan_id': 1, 'normalized_target': 'offline/fixture'}, {'timeout_sec': 5}) assert metrics['failure_count'] == metrics['safety_regression_count'] == 0