Ctrl K
ComunidadGuías…

scripts/__tests__/test_check_brokers_lock.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
from __future__ import annotations

import importlib.util
import pathlib
import sys
import textwrap
import tomllib
from importlib import metadata

import pytest

REPO = pathlib.Path(__file__).resolve().parents[2]
SHA = "a" * 64


def _load_checker():
    spec = importlib.util.spec_from_file_location("check_brokers_lock", REPO / "scripts" / "check-brokers-lock.py")
    module = importlib.util.module_from_spec(spec)
    sys.modules[spec.name] = module
    spec.loader.exec_module(module)
    return module


def _write_inputs(tmp_path: pathlib.Path, *, notes: str) -> tuple[pathlib.Path, pathlib.Path, pathlib.Path]:
    brokers_lock = tmp_path / "brokers.lock"
    requirements_lock = tmp_path / "requirements.lock"
    uv_lock = tmp_path / "uv.lock"
    brokers_lock.write_text(
        textwrap.dedent(
            f"""
            [[broker]]
            name = "dhanhq"
            version = "2.2.0"
            sha256 = "{SHA}"
            licence = "MIT"
            licence_source = "dhanhq-2.2.0.dist-info/LICENSE"
            sandbox_tested = "2026-05-23"
            approved_by = "maintainers"
            notes = "{notes}"
            """
        ).strip(),
        encoding="utf-8",
    )
    requirements_lock.write_text(
        textwrap.dedent(
            f"""
            dhanhq==2.2.0 \\
                --hash=sha256:{SHA}
            """
        ).strip(),
        encoding="utf-8",
    )
    uv_lock.write_text("version = 1\n", encoding="utf-8")
    return brokers_lock, requirements_lock, uv_lock


def test_brokers_lock_accepts_current_activated_sdk_entry(tmp_path, monkeypatch, capsys) -> None:
    checker = _load_checker()
    brokers_lock, requirements_lock, uv_lock = _write_inputs(
        tmp_path,
        notes="repo-managed through flinttrade-gateway dependency and requirements.lock",
    )
    monkeypatch.setattr(checker, "BROKERS_LOCK", brokers_lock)
    monkeypatch.setattr(checker, "REQUIREMENTS_LOCK", requirements_lock)
    monkeypatch.setattr(checker, "UV_LOCK", uv_lock)

    assert checker.main() == 0
    assert capsys.readouterr().err == ""


def test_brokers_lock_rejects_stale_placeholder_note(tmp_path, monkeypatch, capsys) -> None:
    checker = _load_checker()
    brokers_lock, requirements_lock, uv_lock = _write_inputs(
        tmp_path,
        notes="hash pending from initial SDK import",
    )
    monkeypatch.setattr(checker, "BROKERS_LOCK", brokers_lock)
    monkeypatch.setattr(checker, "REQUIREMENTS_LOCK", requirements_lock)
    monkeypatch.setattr(checker, "UV_LOCK", uv_lock)

    assert checker.main() == 1
    assert "stale placeholder text in notes" in capsys.readouterr().err


@pytest.mark.parametrize(
    "missing_field",
    [
        "source_commit",
        "source_tree",
        "release_version",
        "release_tag",
        "release_commit",
        "release_tree",
        "release_wheel_sha256",
        "release_sdist_sha256",
        "licence_sha256",
    ],
)
def test_kotak_git_pin_requires_both_runtime_and_release_evidence(
    tmp_path,
    monkeypatch,
    capsys,
    missing_field: str,
) -> None:
    checker = _load_checker()
    fields = {
        "source_commit": "5bb34fae39c4a52a0e6b59d7e2d17090cafc340c",
        "source_tree": "bb8f8ab64b39ef7a650f1547f5def044cceadd61",
        "release_version": "3.0.7",
        "release_tag": "v3.0.7",
        "release_commit": "53cccc45fe56a193b30ffce3c03c71c5c0378538",
        "release_tree": "c45da6af1223cdeb211ea680ff3582edcbbbc6c9",
        "release_wheel_sha256": "71b661634a88e83859f86a38822ebae69f529d3fbf1246f1a53505092da41d2f",
        "release_sdist_sha256": "4c47aa09bc8c6f348f9280f95c9205609206b69fa7e91f0569d7c1e6302bc80b",
        "licence_sha256": "1baead7c445324d04c894f4499c790d8d6e93ad2b821192034ec11fb3c3d737a",
    }
    fields.pop(missing_field)
    lock = tmp_path / "brokers.lock"
    lock.write_text(
        '[[broker]]\nname = "kotakneoapi"\nversion = "3.0.7"\n'
        f'sha256 = "{"a" * 64}"\nlicence = "MIT"\n'
        'licence_source = "kotakneoapi-3.0.7.dist-info/licenses/LICENSE"\n'
        'sandbox_tested = "2026-09-20"\napproved_by = "maintainer"\n'
        + "".join(f'{key} = "{value}"\n' for key, value in fields.items()),
        encoding="utf-8",
    )
    req = tmp_path / "requirements.lock"
    req.write_text("", encoding="utf-8")
    uv = tmp_path / "uv.lock"
    uv.write_text(
        '[[package]]\nname = "kotakneoapi"\nversion = "3.0.7"\n'
        'source = { git = "https://github.com/Kotak-Neo/kotak-neo-python.git?rev='
        '5bb34fae39c4a52a0e6b59d7e2d17090cafc340c#5bb34fae39c4a52a0e6b59d7e2d17090cafc340c" }\n',
        encoding="utf-8",
    )
    monkeypatch.setattr(checker, "BROKERS_LOCK", lock)
    monkeypatch.setattr(checker, "REQUIREMENTS_LOCK", req)
    monkeypatch.setattr(checker, "UV_LOCK", uv)

    assert checker.main() == 1
    assert missing_field in capsys.readouterr().err


def test_repo_kotak_pin_is_the_reviewed_runtime_and_release() -> None:
    entries = tomllib.loads((REPO / "brokers.lock").read_text(encoding="utf-8"))["broker"]
    neo = next(entry for entry in entries if entry["name"] == "kotakneoapi")
    uv_lock = tomllib.loads((REPO / "uv.lock").read_text(encoding="utf-8"))
    runtime = next(package for package in uv_lock["package"] if package["name"] == "kotakneoapi")

    assert neo["version"] == "3.0.9"
    assert neo["release_version"] == "3.0.9"
    assert neo["source_commit"] == "0ba71b7f7c295652d4c3ea2b5ce5a88849db18a3"
    assert neo["source_tree"] == "b4a597ca4fb3a2c1a591907e00e80e35a7ee1533"
    assert neo["release_tag"] == "v3.0.9"
    assert neo["release_commit"] == "0ba71b7f7c295652d4c3ea2b5ce5a88849db18a3"
    assert neo["release_tree"] == "b4a597ca4fb3a2c1a591907e00e80e35a7ee1533"
    assert runtime["source"]["git"] == (
        "https://github.com/Kotak-Neo/kotak-neo-python.git?rev="
        "0ba71b7f7c295652d4c3ea2b5ce5a88849db18a3#0ba71b7f7c295652d4c3ea2b5ce5a88849db18a3"
    )


@pytest.mark.parametrize(
    ("mutation", "message"),
    [
        (None, None),
        ("missing-release-version", "release_version"),
        ("invalid-release-version", "release_version"),
        ("release-tag", "release_tag"),
        ("runtime-version", "uv.lock"),
        ("release-licence-path", "licence_source"),
        ("release-wheel-hash", "release_wheel_sha256"),
    ],
)
def test_lock_checks_runtime_and_release_versions_separately(tmp_path, monkeypatch, capsys, mutation, message):
    checker = _load_checker()
    fields = {
        "name": "kotakneoapi",
        "version": "3.0.8",
        "release_version": "3.0.7",
        "sha256": "a" * 64,
        "licence": "MIT",
        "licence_sha256": "f" * 64,
        "licence_source": "kotakneoapi-3.0.8.dist-info/licenses/LICENSE",
        "sandbox_tested": "2026-09-20",
        "approved_by": "maintainer",
        "source_commit": "b" * 40,
        "source_tree": "c" * 40,
        "release_tag": "v3.0.7",
        "release_commit": "d" * 40,
        "release_tree": "e" * 40,
        "release_wheel_sha256": "a" * 64,
        "release_sdist_sha256": "0" * 64,
    }
    if mutation == "missing-release-version":
        fields.pop("release_version")
    elif mutation == "invalid-release-version":
        fields["release_version"] = "3.0.7rc1"
    elif mutation == "release-tag":
        fields["release_tag"] = "v3.0.8"
    elif mutation == "runtime-version":
        fields["version"] = "3.0.9"
        fields["licence_source"] = "kotakneoapi-3.0.9.dist-info/licenses/LICENSE"
    elif mutation == "release-licence-path":
        fields["licence_source"] = "kotakneoapi-3.0.7.dist-info/licenses/LICENSE"
    elif mutation == "release-wheel-hash":
        fields["sha256"] = "1" * 64
    lock = tmp_path / "brokers.lock"
    lock.write_text("[[broker]]\n" + "".join(f'{key} = "{value}"\n' for key, value in fields.items()))
    requirements = tmp_path / "requirements.lock"
    requirements.write_text("")
    uv = tmp_path / "uv.lock"
    uv.write_text(
        '[[package]]\nname = "kotakneoapi"\nversion = "3.0.8"\n'
        f'source = {{ git = "https://github.com/Kotak-Neo/kotak-neo-python.git?rev={"b" * 40}#{"b" * 40}" }}\n'
    )
    monkeypatch.setattr(checker, "BROKERS_LOCK", lock)
    monkeypatch.setattr(checker, "REQUIREMENTS_LOCK", requirements)
    monkeypatch.setattr(checker, "UV_LOCK", uv)

    def missing_distribution(_name):
        raise metadata.PackageNotFoundError

    monkeypatch.setattr(metadata, "distribution", missing_distribution)
    assert checker.main() == (0 if mutation is None else 1)
    failures = capsys.readouterr().err
    if message is None:
        assert failures == ""
    else:
        assert message in failures


def test_licence_gate_rejects_changed_installed_kotak_mit_file(tmp_path, monkeypatch, capsys) -> None:
    checker = _load_checker()
    lock = tmp_path / "brokers.lock"
    lock.write_text(
        '[[broker]]\nname = "kotakneoapi"\nversion = "3.0.7"\n'
        'release_version = "3.0.7"\n'
        f'sha256 = "{"a" * 64}"\nlicence = "MIT"\n'
        'licence_source = "kotakneoapi-3.0.7.dist-info/licenses/LICENSE"\n'
        'sandbox_tested = "2026-09-20"\napproved_by = "maintainer"\n'
        f'source_commit = "{"b" * 40}"\nsource_tree = "{"c" * 40}"\n'
        f'release_tag = "v3.0.7"\nrelease_commit = "{"d" * 40}"\nrelease_tree = "{"e" * 40}"\n'
        f'release_wheel_sha256 = "{"a" * 64}"\nrelease_sdist_sha256 = "{"f" * 64}"\n'
        f'licence_sha256 = "{"0" * 64}"\n',
        encoding="utf-8",
    )
    req = tmp_path / "requirements.lock"
    req.write_text("", encoding="utf-8")
    uv = tmp_path / "uv.lock"
    uv.write_text(
        '[[package]]\nname = "kotakneoapi"\nversion = "3.0.7"\n'
        f'source = {{ git = "https://github.com/Kotak-Neo/kotak-neo-python.git?rev={"b" * 40}#{"b" * 40}" }}\n',
        encoding="utf-8",
    )

    licence = tmp_path / "LICENSE"
    licence.write_bytes(b"MIT licence content")

    class InstalledDistribution:
        def locate_file(self, _name: str) -> pathlib.Path:
            return licence

    monkeypatch.setattr(checker, "BROKERS_LOCK", lock)
    monkeypatch.setattr(checker, "REQUIREMENTS_LOCK", req)
    monkeypatch.setattr(checker, "UV_LOCK", uv)
    monkeypatch.setattr(metadata, "distribution", lambda _name: InstalledDistribution())

    assert checker.main() == 1
    assert "licence_sha256" in capsys.readouterr().err