def test_recursive_redaction_covers_connection_secrets():
    from app.core.data_source.redaction import redact_mapping

    value = {
        "name": "warehouse",
        "password": "plain",
        "options": {
            "api_key": "key",
            "url": "postgresql://user:secret@db:5432/app",
        },
    }

    assert redact_mapping(value) == {
        "name": "warehouse",
        "password": "[redacted]",
        "options": {
            "api_key": "[redacted]",
            "url": "postgresql://[redacted]@db:5432/app",
        },
    }


def test_exception_sanitization_removes_url_credentials_and_is_bounded():
    from app.core.data_source.redaction import sanitize_exception

    error = RuntimeError(
        "failed postgresql://reader:secret@db:5432/app " + ("x" * 2000)
    )

    sanitized = sanitize_exception(error)

    assert "reader" not in sanitized
    assert "secret" not in sanitized
    assert "postgresql://[redacted]@db:5432/app" in sanitized
    assert len(sanitized) <= 1000


def test_strip_sensitive_fields_removes_names_as_well_as_values():
    from app.core.data_source.redaction import strip_sensitive_fields

    value = {
        "uid": "source-1",
        "username": "reader",
        "password": "secret",
        "nested": {"credential_ref": "credential-1", "name": "safe"},
    }

    assert strip_sensitive_fields(value) == {
        "uid": "source-1",
        "nested": {"name": "safe"},
    }
