Avoid loading targets metadata twice

When traversing the delegations tree looking for targets,
avoid re-loading already verified targets metadata.

Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
This commit is contained in:
Teodora Sechkova 2021-09-24 17:00:12 +03:00
parent acb201d6cc
commit 4db4737504
No known key found for this signature in database
GPG key ID: 65F78F613EA1914E
2 changed files with 33 additions and 0 deletions

View file

@ -6,11 +6,13 @@
"""Test ngclient Updater using the repository simulator.
"""
import builtins
import os
import sys
import tempfile
import unittest
from typing import Optional, Tuple
from unittest.mock import MagicMock, Mock, patch
from tests import utils
from tests.repository_simulator import RepositorySimulator
@ -230,6 +232,32 @@ def test_snapshot_rollback_with_local_snapshot_hash_mismatch(self):
with self.assertRaises(BadVersionNumberError):
self._run_refresh()
@patch.object(builtins, "open", wraps=builtins.open)
def test_not_loading_targets_twice(self, wrapped_open: MagicMock):
# Do not load targets roles more than once when traversing
# the delegations tree
# Add new delegated targets, update the snapshot
spec_version = ".".join(SPECIFICATION_VERSION)
targets = Targets(1, spec_version, self.sim.safe_expiry, {}, None)
self.sim.add_delegation("targets", "role1", targets, False, ["*"], None)
self.sim.update_snapshot()
# Run refresh, top-level roles are loaded
updater = self._run_refresh()
# Clean up calls to open during refresh()
wrapped_open.reset_mock()
# First time looking for "somepath", only 'role1' must be loaded
updater.get_targetinfo("somepath")
wrapped_open.assert_called_once_with(
os.path.join(self.metadata_dir, "role1.json"), "rb"
)
wrapped_open.reset_mock()
# Second call to get_targetinfo, all metadata is already loaded
updater.get_targetinfo("somepath")
wrapped_open.assert_not_called()
if __name__ == "__main__":
if "--dump" in sys.argv:

View file

@ -370,6 +370,11 @@ def _load_snapshot(self) -> None:
def _load_targets(self, role: str, parent_role: str) -> Metadata[Targets]:
"""Load local (and if needed remote) metadata for 'role'."""
# Avoid loading 'role' more than once during "get_targetinfo"
if role in self._trusted_set:
return self._trusted_set[role]
try:
data = self._load_local_metadata(role)
delegated_targets = self._trusted_set.update_delegated_targets(