From 4ede030b084adf0d2dfdf6828a86d63cf53bc909 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 10 Nov 2026 19:49:08 +0000 Subject: [PATCH] ci: accept relocated cost map pins in trusted guards --- ci_cd/cost_map_guard.py | 14 +++++++++++--- tests/unit/test_cost_map_guard.py | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/ci_cd/cost_map_guard.py b/ci_cd/cost_map_guard.py index d5fd755ba18..c9bcf6e3278 100644 --- a/ci_cd/cost_map_guard.py +++ b/ci_cd/cost_map_guard.py @@ -28,8 +28,13 @@ from typing import Final COST_MAP_PATH: Final = "model_prices_and_context_window.json" BACKUP_PATH: Final = "litellm/model_prices_and_context_window_backup.json" PINS_PATH: Final = "ci_cd/cost_map_pins.json" +PINS_PATHS: Final = ( + "litellm/scripts/ci_cd/cost_map_pins.json", + "scripts/ci_cd/cost_map_pins.json", + "ci_cd/cost_map_pins.json", +) GUARDED_PATHS: Final = (COST_MAP_PATH, BACKUP_PATH) -CHECKED_PATHS: Final = (*GUARDED_PATHS, PINS_PATH) +CHECKED_PATHS: Final = (*GUARDED_PATHS, *PINS_PATHS) BOT_BRANCH_PREFIX: Final = "litellm_cost_map_sync_" PRICE_SYNC_BRANCH_PREFIX: Final = "litellm-providers/price-sync" TARGET_ENV: Final = "COST_MAP_GUARD_TARGET" @@ -193,7 +198,7 @@ def _bot_failures(base: Snapshot, head_map: CostMap, changed_files: Sequence[str def pin_author_failures(head_ref: str, author_type: str, changed_files: Sequence[str]) -> tuple[str, ...]: - if PINS_PATH not in changed_files: + if not any(path in changed_files for path in PINS_PATHS): return () if head_ref.startswith(PRICE_SYNC_BRANCH_PREFIX): return (f"price sync PRs may not change {PINS_PATH}; a pin moves only in a human PR with new evidence",) @@ -252,7 +257,10 @@ def _git(*args: str) -> str | None: def snapshot(revision: str) -> Snapshot: - return Snapshot(*(_git("show", f"{revision}:{path}") or "" for path in CHECKED_PATHS)) + return Snapshot( + *(_git("show", f"{revision}:{path}") or "" for path in GUARDED_PATHS), + next((text for path in PINS_PATHS if (text := _git("show", f"{revision}:{path}")) is not None), ""), + ) def merged_tree(merge_base: str, target: str, head: str) -> str | MergeFailed | None: diff --git a/tests/unit/test_cost_map_guard.py b/tests/unit/test_cost_map_guard.py index 2602149b623..d553237bbbe 100644 --- a/tests/unit/test_cost_map_guard.py +++ b/tests/unit/test_cost_map_guard.py @@ -355,6 +355,25 @@ def test_checked_in_pins_hold_in_the_checked_in_cost_map() -> None: assert guard.pin_failures(pins, cost_map) == () +@pytest.mark.parametrize("pins_path", guard.PINS_PATHS) +@pytest.mark.parametrize("pins", (PINS, "", "not JSON")) +def test_relocated_pins_keep_the_same_validation(tmp_path: Path, pins_path: str, pins: str) -> None: + subprocess.run(("git", "init", "-q", str(tmp_path)), check=True) + base: Final = _commit(tmp_path, BASE_MAP, "base", pins=PINS) + destination: Final = tmp_path / pins_path + destination.parent.mkdir(parents=True, exist_ok=True) + (tmp_path / guard.PINS_PATH).rename(destination) + destination.write_text(pins) + head: Final = _git_commit(tmp_path, "relocate pins") + result: Final = _run_guard(tmp_path, base, head, "litellm_fix_pricing") + assert result.returncode == (0 if pins == PINS else 1), result.stdout + result.stderr + + +@pytest.mark.parametrize("pins_path", guard.PINS_PATHS) +def test_relocated_pins_cannot_be_changed_by_bots(pins_path: str) -> None: + assert guard.pin_author_failures("litellm_fix_pricing", "Bot", (pins_path,)) == (BOT_AUTHOR_PIN_FAILURE,) + + def _commit(repo: Path, cost_map: dict[str, object], message: str, pins: str | None = None) -> str: text = _serialize(cost_map) pins_file = repo / guard.PINS_PATH