diff --git a/src/taintline/cli.py b/src/taintline/cli.py index 01b6a39..0db8feb 100644 --- a/src/taintline/cli.py +++ b/src/taintline/cli.py @@ -3,6 +3,7 @@ from __future__ import annotations import argparse +from importlib.metadata import PackageNotFoundError, version from taintline.detectors import ALL, run_all from taintline.ingest import load_trace @@ -13,6 +14,14 @@ FORMATS = ("text", "json", "sarif") +def get_version() -> str: + """Return installed package version with fallback.""" + try: + return version("taintline") + except PackageNotFoundError: + return "0.0.1" + + def render(verdict: Verdict) -> str: """Deterministic textual report. Findings are already contract-sorted.""" return to_text(verdict) @@ -50,6 +59,12 @@ def _parse_fail_on(raw: str) -> frozenset[str]: def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(prog="taintline") + parser.add_argument( + "-v", + "--version", + action="version", + version=f"%(prog)s {get_version()}", + ) sub = parser.add_subparsers(dest="cmd", required=True) chk = sub.add_parser("check", help="run detectors; exit non-zero on a hit (CI gate)") chk.add_argument("trace", help="OTel trace file (or Strands AgentResult export)") diff --git a/tests/test_smoke.py b/tests/test_smoke.py index 98d1835..058be38 100644 --- a/tests/test_smoke.py +++ b/tests/test_smoke.py @@ -1,7 +1,28 @@ -"""Smoke test: the package imports and exposes its version.""" +"""Smoke test: the package imports and exposes its version, CLI version flag.""" + +import pytest import taintline +from taintline.cli import get_version, main def test_import() -> None: assert taintline.__version__ + + +def test_cli_version_flag(capsys: pytest.CaptureFixture[str]) -> None: + with pytest.raises(SystemExit) as exc_info: + main(["--version"]) + assert exc_info.value.code == 0 + captured = capsys.readouterr() + assert get_version() in captured.out + assert "taintline" in captured.out + + +def test_cli_short_version_flag(capsys: pytest.CaptureFixture[str]) -> None: + with pytest.raises(SystemExit) as exc_info: + main(["-v"]) + assert exc_info.value.code == 0 + captured = capsys.readouterr() + assert get_version() in captured.out + assert "taintline" in captured.out