diff --git a/examples/client/client b/examples/client/client index eeab472d3e..883fd52cba 100755 --- a/examples/client/client +++ b/examples/client/client @@ -38,9 +38,6 @@ def init_tofu(base_url: str) -> bool: metadata_dir = build_metadata_dir(base_url) - if not os.path.isdir(metadata_dir): - os.makedirs(metadata_dir) - response = urllib3.request("GET", f"{base_url}/metadata/1.root.json") if response.status != 200: print(f"Failed to download initial root {base_url}/metadata/1.root.json") @@ -81,9 +78,6 @@ def download(base_url: str, target: str) -> bool: print(f"Using trusted root in {metadata_dir}") - if not os.path.isdir(DOWNLOAD_DIR): - os.mkdir(DOWNLOAD_DIR) - try: # NOTE: initial root should be provided with ``bootstrap`` argument: # This examples uses unsafe Trust-On-First-Use initialization so it is diff --git a/tests/test_updater_top_level_update.py b/tests/test_updater_top_level_update.py index f4342f5f97..68a2a74eaf 100644 --- a/tests/test_updater_top_level_update.py +++ b/tests/test_updater_top_level_update.py @@ -12,6 +12,7 @@ import tempfile import unittest from datetime import timezone +from pathlib import Path from typing import TYPE_CHECKING from unittest.mock import MagicMock, call, patch @@ -57,8 +58,6 @@ def setUp(self) -> None: self.temp_dir = tempfile.TemporaryDirectory() self.metadata_dir = os.path.join(self.temp_dir.name, "metadata") self.targets_dir = os.path.join(self.temp_dir.name, "targets") - os.mkdir(self.metadata_dir) - os.mkdir(self.targets_dir) self.sim = RepositorySimulator() @@ -134,7 +133,8 @@ def test_cached_root_missing_without_bootstrap(self) -> None: self._run_refresh(skip_bootstrap=True) # Metadata dir is empty - self.assertFalse(os.listdir(self.metadata_dir)) + with self.assertRaises(FileNotFoundError): + os.listdir(self.metadata_dir) def test_trusted_root_expired(self) -> None: # Create an expired root version @@ -166,6 +166,7 @@ def test_trusted_root_expired(self) -> None: def test_trusted_root_unsigned_without_bootstrap(self) -> None: # Cached root is not signed, bootstrap root is not used + Path(self.metadata_dir).mkdir(parents=True) root_path = os.path.join(self.metadata_dir, "root.json") md_root = Metadata.from_bytes(self.sim.signed_roots[0]) md_root.signatures.clear() diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index a40c1fca32..020f67a298 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -58,6 +58,7 @@ import os import shutil import tempfile +from pathlib import Path from typing import TYPE_CHECKING, cast from urllib import parse @@ -267,6 +268,7 @@ def download_target( if filepath is None: filepath = self._generate_target_file_path(targetinfo) + Path(filepath).parent.mkdir(exist_ok=True, parents=True) if target_base_url is None: if self._target_base_url is None: @@ -332,10 +334,9 @@ def _persist_root(self, version: int, data: bytes) -> None: The metadata is stored with version prefix (e.g. "root_history/1.root.json"). """ - rootdir = os.path.join(self._dir, "root_history") - with contextlib.suppress(FileExistsError): - os.mkdir(rootdir) - self._persist_file(os.path.join(rootdir, f"{version}.root.json"), data) + rootdir = Path(self._dir, "root_history") + rootdir.mkdir(exist_ok=True, parents=True) + self._persist_file(str(rootdir / f"{version}.root.json"), data) def _persist_file(self, filename: str, data: bytes) -> None: """Write a file to disk atomically to avoid data loss."""