"""Comprehensive tests for ``muse annotate`` CLI hardening. Audit findings addressed ------------------------ Security - ANSI injection in reviewer names (from disk and from user input) now blocked by sanitize_display() at output time and sanitize_provenance() at input validation time. - Control characters in reviewer names rejected before storage. - Commit references resolved via resolve_commit_ref (safe glob-prefix scan) — raw user strings no longer passed directly to read_commit. - Error messages routed to stderr; stdout carries only data. - SystemExit(1) replaced with ExitCode enum values. Performance - ORSet reconstruction removed from mutation path — replaced with pure set union (O(n) set operations vs. O(n) ORSet token generation for every existing reviewer on every mutation). Correctness - Short commit IDs (prefix scan) now work: muse annotate abc1234. - HEAD~N references work through resolve_commit_ref. - Multiple --reviewed-by flags (action='append') work without comma sep. - --remove-reviewer removes from stored list. - --dry-run shows prospective state without writing. Agent UX - --json flag emits complete, stable _AnnotateJson schema. - JSON always present and always contains all fields. Coverage tiers -------------- - Unit: _validate_reviewer, _parse_reviewer_list, _commit_to_json - Integration: run show, add, remove, test-run, dry-run, combination - Security: ANSI in names, control chars, stderr routing, no tracebacks - E2E: full CLI invocation, JSON schema, exit codes - Stress: 100 reviewers, 50 annotations, concurrent isolated repos """ from __future__ import annotations import argparse import datetime import json import pathlib import threading from typing import TYPE_CHECKING from unittest.mock import patch import pytest from muse.core.ids import hash_commit, hash_snapshot from muse.core.commits import ( CommitRecord, read_commit, write_commit, ) from muse.core.errors import ExitCode from muse.core.types import NULL_COMMIT_ID from muse.core.paths import heads_dir, muse_dir, ref_path from tests.cli_test_helper import CliRunner, InvokeResult if TYPE_CHECKING: from muse.cli.commands.annotate import _AnnotateJson runner = CliRunner() cli = None # argparse migration — CliRunner ignores this # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- def _make_repo(tmp_path: pathlib.Path) -> pathlib.Path: """Create a minimal Muse repo layout.""" muse = muse_dir(tmp_path) for sub in ("commits", "snapshots", "refs/heads", "objects"): (muse / sub).mkdir(parents=True, exist_ok=True) (muse / "HEAD").write_text("ref: refs/heads/main", encoding="utf-8") (muse / "repo.json").write_text( json.dumps({"repo_id": "test-repo"}), encoding="utf-8" ) return tmp_path def _write_commit( root: pathlib.Path, message: str = "test commit", branch: str = "main", ) -> CommitRecord: """Write a content-addressed CommitRecord and update the branch ref.""" committed_at = datetime.datetime(2026, 3, 1, tzinfo=datetime.timezone.utc) snap_id = hash_snapshot({}) cid = hash_commit( parent_ids=[], snapshot_id=snap_id, message=message, committed_at_iso=committed_at.isoformat(), author="test-author", ) record = CommitRecord( commit_id=cid, branch=branch, snapshot_id=snap_id, message=message, committed_at=committed_at, author="test-author", ) write_commit(root, record) (ref_path(root, branch)).write_text(cid, encoding="utf-8") return record def _invoke(root: pathlib.Path, *args: str) -> InvokeResult: """Run ``muse annotate `` inside *root*.""" return runner.invoke( cli, ["annotate", *args], env={"MUSE_REPO_ROOT": str(root)}, ) def _parse_json(result: InvokeResult) -> "_AnnotateJson": """Extract and parse the first JSON blob from *result.output*.""" from muse.cli.commands.annotate import _AnnotateJson start = result.output.index("{") blob = result.output[start:] depth = 0 end = 0 for i, ch in enumerate(blob): if ch == "{": depth += 1 elif ch == "}": depth -= 1 if depth == 0: end = i + 1 break raw = json.loads(blob[:end]) assert isinstance(raw, dict) reviewed_by = raw.get("reviewed_by", []) assert isinstance(reviewed_by, list) str_reviewed: list[str] = [str(r) for r in reviewed_by] return _AnnotateJson( commit_id=str(raw.get("commit_id", "")), message=str(raw.get("message", "")), branch=str(raw.get("branch", "")), author=str(raw.get("author", "")), committed_at=str(raw.get("committed_at", "")), reviewed_by=str_reviewed, test_runs=int(raw.get("test_runs", 0)), changed=bool(raw.get("changed", False)), dry_run=bool(raw.get("dry_run", False)), ) # --------------------------------------------------------------------------- # Unit — _validate_reviewer # --------------------------------------------------------------------------- class TestValidateReviewer: def test_valid_name_returns_unchanged(self) -> None: from muse.cli.commands.annotate import _validate_reviewer assert _validate_reviewer("alice") == "alice" assert _validate_reviewer("agent-x") == "agent-x" assert _validate_reviewer("ci-bot-v2") == "ci-bot-v2" def test_empty_name_exits_user_error(self) -> None: from muse.cli.commands.annotate import _validate_reviewer with pytest.raises(SystemExit) as exc: _validate_reviewer("") assert exc.value.code == ExitCode.USER_ERROR.value def test_name_with_ansi_exits_user_error(self) -> None: from muse.cli.commands.annotate import _validate_reviewer with pytest.raises(SystemExit) as exc: _validate_reviewer("\x1b[31mmalicious\x1b[0m") assert exc.value.code == ExitCode.USER_ERROR.value def test_name_with_null_byte_exits_user_error(self) -> None: from muse.cli.commands.annotate import _validate_reviewer with pytest.raises(SystemExit) as exc: _validate_reviewer("foo\x00bar") assert exc.value.code == ExitCode.USER_ERROR.value def test_name_with_newline_exits_user_error(self) -> None: from muse.cli.commands.annotate import _validate_reviewer with pytest.raises(SystemExit) as exc: _validate_reviewer("alice\nbob") assert exc.value.code == ExitCode.USER_ERROR.value def test_overlong_name_exits_user_error(self) -> None: from muse.cli.commands.annotate import _validate_reviewer, _MAX_REVIEWER_LEN with pytest.raises(SystemExit) as exc: _validate_reviewer("a" * (_MAX_REVIEWER_LEN + 1)) assert exc.value.code == ExitCode.USER_ERROR.value def test_exact_max_length_accepted(self) -> None: from muse.cli.commands.annotate import _validate_reviewer, _MAX_REVIEWER_LEN name = "a" * _MAX_REVIEWER_LEN assert _validate_reviewer(name) == name # --------------------------------------------------------------------------- # Unit — _parse_reviewer_list # --------------------------------------------------------------------------- class TestParseReviewerList: def test_single_name(self) -> None: from muse.cli.commands.annotate import _parse_reviewer_list assert _parse_reviewer_list(["alice"]) == ["alice"] def test_comma_separated(self) -> None: from muse.cli.commands.annotate import _parse_reviewer_list result = _parse_reviewer_list(["alice,bob"]) assert "alice" in result assert "bob" in result def test_multiple_flags(self) -> None: from muse.cli.commands.annotate import _parse_reviewer_list result = _parse_reviewer_list(["alice", "bob"]) assert "alice" in result assert "bob" in result def test_deduplication(self) -> None: from muse.cli.commands.annotate import _parse_reviewer_list result = _parse_reviewer_list(["alice", "alice"]) assert result.count("alice") == 1 def test_empty_list(self) -> None: from muse.cli.commands.annotate import _parse_reviewer_list assert _parse_reviewer_list([]) == [] def test_whitespace_stripped(self) -> None: from muse.cli.commands.annotate import _parse_reviewer_list result = _parse_reviewer_list([" alice , bob "]) assert "alice" in result assert "bob" in result def test_empty_segments_skipped(self) -> None: from muse.cli.commands.annotate import _parse_reviewer_list result = _parse_reviewer_list(["alice,,bob"]) assert "alice" in result assert "bob" in result assert "" not in result def test_invalid_name_raises(self) -> None: from muse.cli.commands.annotate import _parse_reviewer_list with pytest.raises(SystemExit): _parse_reviewer_list(["\x1b[31mmalicious\x1b[0m"]) # --------------------------------------------------------------------------- # Unit — _commit_to_json # --------------------------------------------------------------------------- class TestCommitToJson: def _record(self) -> CommitRecord: committed_at = datetime.datetime(2026, 3, 1, tzinfo=datetime.timezone.utc) snap_id = hash_snapshot({}) cid = hash_commit( parent_ids=[], snapshot_id=snap_id, message="msg", committed_at_iso=committed_at.isoformat(), author="alice", ) return CommitRecord( commit_id=cid, branch="main", snapshot_id=snap_id, message="msg", committed_at=committed_at, author="alice", reviewed_by=["bob"], test_runs=3, ) def test_all_fields_present(self) -> None: from muse.cli.commands.annotate import _commit_to_json rec = self._record() j = _commit_to_json(rec, changed=True, dry_run=False) for field in ( "commit_id", "message", "branch", "author", "committed_at", "reviewed_by", "test_runs", "changed", "dry_run", ): assert field in j, f"Missing field: {field}" def test_changed_and_dry_run_flags(self) -> None: from muse.cli.commands.annotate import _commit_to_json rec = self._record() j = _commit_to_json(rec, changed=True, dry_run=True) assert j["changed"] is True assert j["dry_run"] is True def test_reviewed_by_is_list(self) -> None: from muse.cli.commands.annotate import _commit_to_json rec = self._record() j = _commit_to_json(rec, changed=False, dry_run=False) assert isinstance(j["reviewed_by"], list) assert "bob" in j["reviewed_by"] # --------------------------------------------------------------------------- # Integration — show mode (no mutation flags) # --------------------------------------------------------------------------- class TestShowMode: def test_show_no_reviewers(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, c.commit_id) assert result.exit_code == 0 assert "reviewed-by: (none)" in result.output def test_show_existing_reviewers(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--reviewed-by", "alice", c.commit_id) result = _invoke(repo, c.commit_id) assert result.exit_code == 0 assert "alice" in result.output def test_show_test_runs(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--test-run", c.commit_id) result = _invoke(repo, c.commit_id) assert result.exit_code == 0 assert "test-runs: 1" in result.output def test_show_head_default(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) _write_commit(repo) result = _invoke(repo) assert result.exit_code == 0 assert "reviewed-by" in result.output def test_show_json_schema(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--json", c.commit_id) assert result.exit_code == 0 data = _parse_json(result) assert data["commit_id"] == c.commit_id assert data["changed"] is False assert data["dry_run"] is False assert isinstance(data["reviewed_by"], list) assert isinstance(data["test_runs"], int) def test_show_json_has_message_and_branch(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo, message="feat: some feature") result = _invoke(repo, "--json", c.commit_id) data = _parse_json(result) assert data["message"] == "feat: some feature" assert data["branch"] == "main" def test_unknown_commit_exits_not_found(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) result = _invoke(repo, "deadbeef") assert result.exit_code == ExitCode.NOT_FOUND.value def test_unknown_commit_no_traceback(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) result = _invoke(repo, "deadbeef") assert "Traceback" not in result.output # --------------------------------------------------------------------------- # Integration — add reviewer (--reviewed-by) # --------------------------------------------------------------------------- class TestAddReviewer: def test_single_reviewer_added(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--reviewed-by", "alice", c.commit_id) assert result.exit_code == 0 rec = read_commit(repo, c.commit_id) assert rec is not None assert "alice" in rec.reviewed_by def test_comma_separated_reviewers(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--reviewed-by", "alice,bob", c.commit_id) assert result.exit_code == 0 rec = read_commit(repo, c.commit_id) assert rec is not None assert "alice" in rec.reviewed_by assert "bob" in rec.reviewed_by def test_multiple_reviewed_by_flags(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke( repo, "--reviewed-by", "alice", "--reviewed-by", "bob", c.commit_id, ) assert result.exit_code == 0 rec = read_commit(repo, c.commit_id) assert rec is not None assert "alice" in rec.reviewed_by assert "bob" in rec.reviewed_by def test_orset_idempotent(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--reviewed-by", "alice", c.commit_id) _invoke(repo, "--reviewed-by", "alice", c.commit_id) rec = read_commit(repo, c.commit_id) assert rec is not None assert rec.reviewed_by.count("alice") == 1 def test_reviewer_added_message_shown(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--reviewed-by", "alice", c.commit_id) assert "alice" in result.output assert "Added" in result.output def test_no_changes_when_reviewer_already_present( self, tmp_path: pathlib.Path ) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--reviewed-by", "alice", c.commit_id) result = _invoke(repo, "--reviewed-by", "alice", c.commit_id) assert result.exit_code == 0 assert "no changes" in result.output def test_json_reflects_new_reviewer(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--reviewed-by", "alice", "--json", c.commit_id) assert result.exit_code == 0 data = _parse_json(result) assert "alice" in data["reviewed_by"] assert data["changed"] is True def test_json_changed_false_when_no_change(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--reviewed-by", "alice", c.commit_id) result = _invoke(repo, "--reviewed-by", "alice", "--json", c.commit_id) data = _parse_json(result) assert data["changed"] is False # --------------------------------------------------------------------------- # Integration — remove reviewer (--remove-reviewer) # --------------------------------------------------------------------------- class TestRemoveReviewer: def test_remove_existing_reviewer(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--reviewed-by", "alice", c.commit_id) result = _invoke(repo, "--remove-reviewer", "alice", c.commit_id) assert result.exit_code == 0 rec = read_commit(repo, c.commit_id) assert rec is not None assert "alice" not in rec.reviewed_by def test_remove_absent_reviewer_warns_to_stderr( self, tmp_path: pathlib.Path ) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--remove-reviewer", "nobody", c.commit_id) assert result.exit_code == 0 assert "⚠️" in result.stderr or "not present" in result.stderr def test_remove_one_preserves_others(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--reviewed-by", "alice,bob", c.commit_id) _invoke(repo, "--remove-reviewer", "alice", c.commit_id) rec = read_commit(repo, c.commit_id) assert rec is not None assert "alice" not in rec.reviewed_by assert "bob" in rec.reviewed_by def test_remove_json_reflects_change(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--reviewed-by", "alice", c.commit_id) result = _invoke( repo, "--remove-reviewer", "alice", "--json", c.commit_id ) data = _parse_json(result) assert "alice" not in data["reviewed_by"] assert data["changed"] is True # --------------------------------------------------------------------------- # Integration — test-run counter # --------------------------------------------------------------------------- class TestTestRun: def test_test_run_increments(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--test-run", c.commit_id) _invoke(repo, "--test-run", c.commit_id) rec = read_commit(repo, c.commit_id) assert rec is not None assert rec.test_runs == 2 def test_test_run_shown_in_output(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--test-run", c.commit_id) assert result.exit_code == 0 assert "Test run recorded" in result.output def test_test_run_json_schema(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--test-run", "--json", c.commit_id) assert result.exit_code == 0 data = _parse_json(result) assert data["test_runs"] == 1 assert data["changed"] is True # --------------------------------------------------------------------------- # Integration — dry-run # --------------------------------------------------------------------------- class TestDryRun: def test_dry_run_does_not_write(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--reviewed-by", "alice", "--dry-run", c.commit_id) rec = read_commit(repo, c.commit_id) assert rec is not None assert "alice" not in rec.reviewed_by def test_dry_run_shows_prospective_state(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--reviewed-by", "alice", "--dry-run", c.commit_id) assert result.exit_code == 0 assert "dry-run" in result.output.lower() or "[dry-run]" in result.output def test_dry_run_json_reflects_prospective_state( self, tmp_path: pathlib.Path ) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke( repo, "--reviewed-by", "alice", "--dry-run", "--json", c.commit_id ) data = _parse_json(result) assert "alice" in data["reviewed_by"] # prospective assert data["dry_run"] is True assert data["changed"] is True # Verify disk was NOT modified rec = read_commit(repo, c.commit_id) assert rec is not None assert "alice" not in rec.reviewed_by def test_dry_run_test_run_not_incremented(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--test-run", "--dry-run", c.commit_id) rec = read_commit(repo, c.commit_id) assert rec is not None assert rec.test_runs == 0 # --------------------------------------------------------------------------- # Integration — commit reference resolution # --------------------------------------------------------------------------- class TestCommitRefResolution: def test_full_commit_id(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, c.commit_id) assert result.exit_code == 0 def test_short_prefix_resolves(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) prefix = c.commit_id.removeprefix("sha256:")[:8] result = _invoke(repo, prefix) assert result.exit_code == 0 def test_head_default_resolves(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) _write_commit(repo) result = _invoke(repo) assert result.exit_code == 0 def test_head_tilde_resolves(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c1 = _write_commit(repo, message="first") # Write a second commit with c1 as parent committed_at = datetime.datetime(2026, 3, 2, tzinfo=datetime.timezone.utc) snap_id = hash_snapshot({}) cid2 = hash_commit( parent_ids=[c1.commit_id], snapshot_id=snap_id, message="second", committed_at_iso=committed_at.isoformat(), author="test-author", ) c2 = CommitRecord( commit_id=cid2, branch="main", snapshot_id=snap_id, message="second", committed_at=committed_at, author="test-author", parent_commit_id=c1.commit_id, ) write_commit(repo, c2) (heads_dir(repo) / "main").write_text( cid2, encoding="utf-8" ) result = _invoke(repo, "HEAD~1") assert result.exit_code == 0 def test_nonexistent_commit_exits_not_found( self, tmp_path: pathlib.Path ) -> None: repo = _make_repo(tmp_path) result = _invoke(repo, NULL_COMMIT_ID) assert result.exit_code == ExitCode.NOT_FOUND.value # --------------------------------------------------------------------------- # Security # --------------------------------------------------------------------------- class TestAnnotateSecurity: _ANSI = "\x1b[31mmalicious\x1b[0m" def test_ansi_in_reviewer_name_rejected(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--reviewed-by", self._ANSI, c.commit_id) assert result.exit_code == ExitCode.USER_ERROR.value def test_ansi_not_stored_in_reviewed_by(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) _invoke(repo, "--reviewed-by", self._ANSI, c.commit_id) rec = read_commit(repo, c.commit_id) assert rec is not None for r in rec.reviewed_by: assert "\x1b" not in r def test_ansi_in_existing_reviewer_stripped_on_display( self, tmp_path: pathlib.Path ) -> None: """Even if a legacy record has ANSI in reviewed_by, output is sanitized.""" repo = _make_repo(tmp_path) c = _write_commit(repo) # Force-write a record with ANSI in reviewed_by (simulating legacy data). from muse.core.commits import overwrite_commit c.reviewed_by = [self._ANSI] overwrite_commit(repo, c) result = _invoke(repo, c.commit_id) assert result.exit_code == 0 assert "\x1b[" not in result.output def test_null_byte_in_reviewer_rejected(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--reviewed-by", "foo\x00bar", c.commit_id) assert result.exit_code == ExitCode.USER_ERROR.value def test_commit_not_found_error_to_stderr_not_traceback( self, tmp_path: pathlib.Path ) -> None: repo = _make_repo(tmp_path) result = _invoke(repo, "nosuchcommit") assert result.exit_code != 0 assert "Traceback" not in result.output def test_invalid_reviewer_control_char_rejected( self, tmp_path: pathlib.Path ) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--reviewed-by", "alice\x07bell", c.commit_id) assert result.exit_code == ExitCode.USER_ERROR.value def test_overlong_reviewer_rejected(self, tmp_path: pathlib.Path) -> None: from muse.cli.commands.annotate import _MAX_REVIEWER_LEN repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke( repo, "--reviewed-by", "a" * (_MAX_REVIEWER_LEN + 1), c.commit_id ) assert result.exit_code == ExitCode.USER_ERROR.value def test_json_output_on_stdout_errors_on_stderr( self, tmp_path: pathlib.Path ) -> None: """JSON consumers must not see errors on stdout.""" repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--reviewed-by", "alice", "--json", c.commit_id) assert result.exit_code == 0 # First non-whitespace char on stdout should be '{' (start of JSON) stripped = result.output.lstrip() assert stripped.startswith("{"), f"Expected JSON, got: {result.output[:80]!r}" # --------------------------------------------------------------------------- # E2E — full CLI invocations # --------------------------------------------------------------------------- class TestE2E: def test_json_schema_all_fields_present(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke(repo, "--json", c.commit_id) assert result.exit_code == 0 data = _parse_json(result) for field in ( "commit_id", "message", "branch", "author", "committed_at", "reviewed_by", "test_runs", "changed", "dry_run", ): assert field in data, f"Missing field in JSON: {field}" def test_combination_reviewer_and_test_run( self, tmp_path: pathlib.Path ) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) result = _invoke( repo, "--reviewed-by", "alice", "--test-run", c.commit_id, ) assert result.exit_code == 0 rec = read_commit(repo, c.commit_id) assert rec is not None assert "alice" in rec.reviewed_by assert rec.test_runs == 1 def test_head_tilde_used_for_annotation(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c1 = _write_commit(repo, message="first") committed_at = datetime.datetime(2026, 3, 2, tzinfo=datetime.timezone.utc) snap_id = hash_snapshot({}) cid2 = hash_commit( parent_ids=[c1.commit_id], snapshot_id=snap_id, message="second", committed_at_iso=committed_at.isoformat(), author="test-author", ) c2 = CommitRecord( commit_id=cid2, branch="main", snapshot_id=snap_id, message="second", committed_at=committed_at, author="test-author", parent_commit_id=c1.commit_id, ) write_commit(repo, c2) (heads_dir(repo) / "main").write_text( cid2, encoding="utf-8" ) # Annotate the first (parent) commit via HEAD~1 result = _invoke(repo, "HEAD~1", "--reviewed-by", "alice") assert result.exit_code == 0 rec = read_commit(repo, c1.commit_id) assert rec is not None assert "alice" in rec.reviewed_by def test_short_prefix_annotates_correct_commit( self, tmp_path: pathlib.Path ) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) prefix = c.commit_id[:10] result = _invoke(repo, prefix, "--reviewed-by", "bot") assert result.exit_code == 0 rec = read_commit(repo, c.commit_id) assert rec is not None assert "bot" in rec.reviewed_by def test_help_text_shows_new_flags(self, tmp_path: pathlib.Path) -> None: result = runner.invoke(cli, ["annotate", "--help"]) assert result.exit_code == 0 assert "--remove-reviewer" in result.output assert "--dry-run" in result.output assert "--json" in result.output # --------------------------------------------------------------------------- # Stress # --------------------------------------------------------------------------- class TestStress: def test_100_reviewers_stored_correctly( self, tmp_path: pathlib.Path ) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) # Add 100 reviewers in a single comma-separated call names = [f"reviewer-{i:03d}" for i in range(100)] csv = ",".join(names) result = _invoke(repo, "--reviewed-by", csv, c.commit_id) assert result.exit_code == 0 rec = read_commit(repo, c.commit_id) assert rec is not None assert len(rec.reviewed_by) == 100 for name in names: assert name in rec.reviewed_by def test_50_test_run_increments(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) c = _write_commit(repo) for _ in range(50): r = _invoke(repo, "--test-run", c.commit_id) assert r.exit_code == 0 rec = read_commit(repo, c.commit_id) assert rec is not None assert rec.test_runs == 50 def test_concurrent_overwrite_isolated_repos( self, tmp_path: pathlib.Path ) -> None: """Eight threads each call overwrite_commit on isolated repos. Tests the core mutation layer for thread-safety without going through the CliRunner (whose env patching is not thread-safe). """ from muse.core.commits import overwrite_commit errors: list[str] = [] def worker(idx: int) -> None: try: repo = _make_repo(tmp_path / f"repo{idx}") c = _write_commit(repo) c.reviewed_by = [f"agent-{idx}"] overwrite_commit(repo, c) # Read back and verify rec = read_commit(repo, c.commit_id) if rec is None: errors.append(f"Thread {idx}: read_commit returned None") return if f"agent-{idx}" not in rec.reviewed_by: errors.append(f"Thread {idx}: reviewer not found in {rec.reviewed_by!r}") except Exception as exc: errors.append(f"Thread {idx}: {exc}") threads = [threading.Thread(target=worker, args=(i,)) for i in range(8)] for t in threads: t.start() for t in threads: t.join() assert errors == [], f"Concurrent annotation failures: {errors}" def test_concurrent_validate_reviewer(self) -> None: """Eight threads validating names concurrently — no shared mutable state.""" from muse.cli.commands.annotate import _validate_reviewer errors: list[str] = [] def worker(idx: int) -> None: try: name = f"reviewer-{idx:03d}" result = _validate_reviewer(name) if result != name: errors.append(f"Thread {idx}: got {result!r}") except Exception as exc: errors.append(f"Thread {idx}: {exc}") threads = [threading.Thread(target=worker, args=(i,)) for i in range(8)] for t in threads: t.start() for t in threads: t.join() assert errors == [], f"Concurrent validation failures: {errors}" class TestRegisterFlags: """Argparse registration tests for ``muse annotate``.""" def _parse(self, *args: str) -> argparse.Namespace: from muse.cli.commands.annotate import register p = argparse.ArgumentParser() sub = p.add_subparsers() register(sub) return p.parse_args(["annotate", *args]) def test_default_json_out_is_false(self) -> None: ns = self._parse() assert ns.json_out is False def test_json_flag_sets_json_out(self) -> None: ns = self._parse("--json") assert ns.json_out is True def test_j_shorthand_sets_json_out(self) -> None: ns = self._parse("-j") assert ns.json_out is True def test_dry_run_default(self) -> None: ns = self._parse() assert ns.dry_run is False def test_dry_run_flag(self) -> None: ns = self._parse("--dry-run") assert ns.dry_run is True def test_dry_run_n_shorthand(self) -> None: ns = self._parse("-n") assert ns.dry_run is True def test_commit_arg_default(self) -> None: ns = self._parse() assert ns.commit_arg is None def test_reviewed_by_default(self) -> None: ns = self._parse() assert ns.reviewed_by is None