From c7c19ae06ea9b851a537ef2e5a6661faaedd48a7 Mon Sep 17 00:00:00 2001 From: imSp4rky Date: Tue, 22 Sep 2026 19:54:18 -0600 Subject: [PATCH] fix(dl): skip empty vault pushes and count cached keys once A licence that repeats vault keys no longer sends an empty InsertKeys, --cdm-only no longer logs "Cached N Keys to 0/0 Vaults", and a key two tracks both licensed counts once. --- tests/core/test_vault_bad_keys.py | 27 +++++++++++++++++++++++++++ unshackle/commands/dl.py | 11 +++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/tests/core/test_vault_bad_keys.py b/tests/core/test_vault_bad_keys.py index 1ff8df96..546831ce 100644 --- a/tests/core/test_vault_bad_keys.py +++ b/tests/core/test_vault_bad_keys.py @@ -332,6 +332,33 @@ def test_a_licence_key_clears_a_flag_from_an_earlier_run(tmp_path: Path, monkeyp assert local.get_key(KID, "SVC") == GOOD +def test_a_licence_with_no_new_keys_sends_no_vault_write(monkeypatch: pytest.MonkeyPatch) -> None: + """A PSSH KID the licence never answers forces a licence on every run; the vaults must not get an empty push.""" + vault = SimpleNamespace(no_push=False, add_keys=lambda *_: pytest.fail("empty push reached a vault")) + vaults = Vaults("SVC") + vaults.vaults = [vault] # type: ignore[list-item] + cmd = make_cmd(monkeypatch, vaults) + cmd.cache_keys_to_vaults({}) + assert cmd.vault_cache_tally is None + + +def test_the_cached_key_count_is_unique_and_skipped_without_vaults( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """Two tracks licensed in parallel can return the same key; --cdm-only loads no vaults at all.""" + other = UUID(int=9) + vaults = Vaults("SVC") + vaults.vaults = [SQLite("local", tmp_path / "local.db")] + cmd = make_cmd(monkeypatch, vaults) + cmd.cache_keys_to_vaults({KID: GOOD}) + cmd.cache_keys_to_vaults({KID: GOOD, other: GOOD}) + assert cmd.vault_cache_tally == ({KID, other}, 1) + + cmd = make_cmd(monkeypatch, Vaults("SVC")) + cmd.cache_keys_to_vaults({KID: GOOD}) + assert cmd.vault_cache_tally is None + + def test_bulk_add_refuses_a_flagged_pair_in_any_case_or_kid_form(tmp_path: Path) -> None: local = SQLite("local", tmp_path / "local.db") local.flag_bad_key("SVC", KID, BAD, "poisoned") diff --git a/unshackle/commands/dl.py b/unshackle/commands/dl.py index ae06452b..1a21e9ae 100644 --- a/unshackle/commands/dl.py +++ b/unshackle/commands/dl.py @@ -1236,7 +1236,7 @@ class dl: self.cdm_override = ctx.params.get("cdm_name") cdm_only = ctx.params.get("cdm_only") - self.vault_cache_tally: Optional[tuple[int, int]] = None + self.vault_cache_tally: Optional[tuple[set[UUID], int]] = None if cdm_only: self.vaults = Vaults(self.vault_service) @@ -4149,7 +4149,8 @@ class dl: if not (self.vault_cache_tally and self.vault_cache_tally[0]): self.vault_cache_tally = None return - keys, successful_caches = self.vault_cache_tally + kids, successful_caches = self.vault_cache_tally + keys = len(kids) self.vault_cache_tally = None self.log.info(f"Cached {keys} Key{'' if keys == 1 else 's'} to {successful_caches}/{len(self.vaults)} Vaults") @@ -4204,12 +4205,14 @@ class dl: def cache_keys_to_vaults(self, content_keys: dict[UUID, str]) -> None: """Store licence keys in every vault. A licence key clears a flag on its pair first: the flag came from a decode check that was wrong, and a local vault refuses a flagged pair.""" + if not content_keys or not self.vaults: + return for kid, key in content_keys.items(): if self.vaults.is_flagged(kid, key): self.vaults.unflag_bad_key(kid, key) successful_caches = self.vaults.add_keys(content_keys) - keys, caches = self.vault_cache_tally or (0, successful_caches) - self.vault_cache_tally = (keys + len(content_keys), min(caches, successful_caches)) + kids, caches = self.vault_cache_tally or (set(), successful_caches) + self.vault_cache_tally = (kids | content_keys.keys(), min(caches, successful_caches)) @classmethod def drm_lock(cls, drm: DRM_T) -> Lock: