"""Test security gate enforcement in CI/CD pipeline.

This test verifies that security vulnerabilities and violations properly fail
the pipeline instead of being ignored with continue-on-error flags.
"""

from pathlib import Path

import pytest
import yaml


class TestSecurityGateEnforcement:
    """Test security gate enforcement configuration."""

    @pytest.mark.unit
    def test_pipeline_yaml_exists(self) -> None:
        """Test that pipeline.yaml exists and is readable."""
        pipeline_path = Path(".github/workflows/pipeline.yaml")
        assert pipeline_path.exists(), "Pipeline configuration file must exist"

        with open(pipeline_path, encoding="utf-8") as f:
            content = f.read()
        assert content, "Pipeline configuration must not be empty"

    @pytest.mark.unit
    def test_security_tools_fail_on_vulnerabilities(self) -> None:
        """Test that security tools are configured to fail the pipeline on findings.

        This test verifies that safety, pip-audit, and semgrep do NOT have
        continue-on-error: true for their enforcement steps.
        """
        pipeline_path = Path(".github/workflows/pipeline.yaml")

        with open(pipeline_path, encoding="utf-8") as f:
            pipeline_config = yaml.safe_load(f)

        # Find the security-scan job
        jobs = pipeline_config.get("jobs", {})
        security_job = jobs.get("security-scan", {})
        assert security_job, "security-scan job must exist in pipeline"

        steps = security_job.get("steps", [])
        assert steps, "security-scan job must have steps"

        # Check that enforcement steps do NOT have continue-on-error: true
        problematic_steps = []

        for step in steps:
            step_name = step.get("name", "")

            # Check for enforcement steps (not report generation steps)
            if any(
                keyword in step_name.lower()
                for keyword in [
                    "run safety check (enforced)",
                    "run pip-audit (enforced)",
                    "run semgrep scan (enforced)",
                ]
            ):
                # These enforcement steps should NOT have continue-on-error: true
                if step.get("continue-on-error") is True:
                    problematic_steps.append(step_name)

        assert not problematic_steps, (
            f"Security enforcement steps should not use continue-on-error: true. "
            f"Found problematic steps: {problematic_steps}"
        )

    @pytest.mark.unit
    def test_bandit_enforcement_configured(self) -> None:
        """Test that Bandit is configured to fail on medium/high severity issues."""
        pipeline_path = Path(".github/workflows/pipeline.yaml")

        with open(pipeline_path, encoding="utf-8") as f:
            pipeline_config = yaml.safe_load(f)

        # Find the security-scan job
        security_job = pipeline_config["jobs"]["security-scan"]
        steps = security_job["steps"]

        # Look for Bandit enforcement step
        bandit_enforcement_found = False

        for step in steps:
            step_name = step.get("name", "")
            if "bandit" in step_name.lower() and "enforced" in step_name.lower():
                bandit_enforcement_found = True
                # Should not have continue-on-error
                assert step.get("continue-on-error") is not True, (
                    "Bandit enforcement step should not use continue-on-error"
                )

                # Should use -ll flag for medium/high severity only
                run_command = step.get("run", "")
                assert "-ll" in run_command, (
                    "Bandit should use -ll flag to fail on medium/high severity issues"
                )

        assert bandit_enforcement_found, "Bandit enforcement step not found in security-scan job"

    @pytest.mark.unit
    def test_report_generation_vs_enforcement_separation(self) -> None:
        """Test that report generation and enforcement are properly separated.

        Report generation should have continue-on-error: true to ensure reports
        are always generated, but enforcement should not.
        """
        pipeline_path = Path(".github/workflows/pipeline.yaml")

        with open(pipeline_path, encoding="utf-8") as f:
            pipeline_config = yaml.safe_load(f)

        security_job = pipeline_config["jobs"]["security-scan"]
        steps = security_job["steps"]

        report_steps = []
        enforcement_steps = []

        for step in steps:
            step_name = step.get("name", "").lower()

            if "generate" in step_name and "report" in step_name:
                report_steps.append(step)
            elif any(
                keyword in step_name
                for keyword in [
                    "run safety check (enforced)",
                    "run pip-audit (enforced)",
                    "run semgrep scan (enforced)",
                    "run bandit security scan (enforced)",
                ]
            ):
                enforcement_steps.append(step)

        # Report generation steps should have continue-on-error: true
        for step in report_steps:
            assert step.get("continue-on-error") is True, (
                f"Report generation step '{step.get('name')}' should use continue-on-error: true"
            )

        # Enforcement steps should NOT have continue-on-error: true
        for step in enforcement_steps:
            step_name = step.get("name")
            if step.get("continue-on-error") is True:
                pytest.fail(
                    f"Enforcement step '{step_name}' should not use continue-on-error: true"
                )
