withcache 0.8.4__tar.gz → 0.8.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. {withcache-0.8.4 → withcache-0.8.5}/PKG-INFO +1 -1
  2. {withcache-0.8.4 → withcache-0.8.5}/shim/build.zig.zon +1 -1
  3. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/__init__.py +1 -1
  4. {withcache-0.8.4 → withcache-0.8.5}/tests/test_withcache.py +54 -0
  5. {withcache-0.8.4 → withcache-0.8.5}/.gitignore +0 -0
  6. {withcache-0.8.4 → withcache-0.8.5}/LICENSE +0 -0
  7. {withcache-0.8.4 → withcache-0.8.5}/README.md +0 -0
  8. {withcache-0.8.4 → withcache-0.8.5}/deploy/Containerfile +0 -0
  9. {withcache-0.8.4 → withcache-0.8.5}/deploy/compose.yml +0 -0
  10. {withcache-0.8.4 → withcache-0.8.5}/hatch_build.py +0 -0
  11. {withcache-0.8.4 → withcache-0.8.5}/pyproject.toml +0 -0
  12. {withcache-0.8.4 → withcache-0.8.5}/shim/build.zig +0 -0
  13. {withcache-0.8.4 → withcache-0.8.5}/shim/shim.zig +0 -0
  14. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/_shim.py +0 -0
  15. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/client.py +0 -0
  16. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/curlwithcache.py +0 -0
  17. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/oras.py +0 -0
  18. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/server.py +0 -0
  19. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/static/bootstrap-icons.min.css +0 -0
  20. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/static/bootstrap.min.css +0 -0
  21. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/static/fonts/bootstrap-icons.woff +0 -0
  22. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/static/fonts/bootstrap-icons.woff2 +0 -0
  23. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/static/htmx.min.js +0 -0
  24. {withcache-0.8.4 → withcache-0.8.5}/src/withcache/wgetwithcache.py +0 -0
  25. {withcache-0.8.4 → withcache-0.8.5}/tests/test_differential.py +0 -0
  26. {withcache-0.8.4 → withcache-0.8.5}/tests/test_oras.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: withcache
3
- Version: 0.8.4
3
+ Version: 0.8.5
4
4
  Summary: Operator-curated, URL-keyed artifact cache for a small lab (CUDA/ROCm/DOCA/firmware)
5
5
  Project-URL: Homepage, https://github.com/safl/withcache
6
6
  Author-email: "Simon A. F. Lund" <safl@safl.dk>
@@ -2,7 +2,7 @@
2
2
  .name = .withcache_shim,
3
3
  // Zig requires a literal here; keep it in lockstep with the project's
4
4
  // single source (src/withcache/__init__.py) via `make bump` / `make version-check`.
5
- .version = "0.8.4",
5
+ .version = "0.8.5",
6
6
  .fingerprint = 0xd7d96c5ed212ccaa,
7
7
  .minimum_zig_version = "0.16.0",
8
8
  .paths = .{
@@ -17,6 +17,6 @@ All modules are stdlib-only and self-contained.
17
17
  from . import oras
18
18
  from .client import blob_url, cache_base, is_cached, serve_url
19
19
 
20
- __version__ = "0.8.4"
20
+ __version__ = "0.8.5"
21
21
 
22
22
  __all__ = ["__version__", "blob_url", "cache_base", "is_cached", "oras", "serve_url"]
@@ -31,6 +31,60 @@ from withcache import _shim, client, curlwithcache, server, wgetwithcache
31
31
  # --------------------------------------------------------------------------
32
32
  # Auth: signed-cookie round-trip, tamper + wrong-secret rejection, expiry
33
33
  # --------------------------------------------------------------------------
34
+ class TestResolveSecret(unittest.TestCase):
35
+ """resolve_secret is the whole basis of the cookie-auth trust
36
+ boundary: the HMAC key that signs session tokens. Three branches
37
+ -- env-set, file-persisted, fresh-generation -- and a
38
+ security-adjacent invariant claimed in its docstring: 'a blank
39
+ env value must NOT silently weaken signing'. Mirrors nbdmux's
40
+ TestResolveSecret since the two functions are the same shape."""
41
+
42
+ def setUp(self):
43
+ self.tmpdir = tempfile.mkdtemp()
44
+ self._saved = os.environ.get("WITHCACHE_SESSION_SECRET")
45
+
46
+ def tearDown(self):
47
+ if self._saved is None:
48
+ os.environ.pop("WITHCACHE_SESSION_SECRET", None)
49
+ else:
50
+ os.environ["WITHCACHE_SESSION_SECRET"] = self._saved
51
+
52
+ def test_env_set_wins(self):
53
+ os.environ["WITHCACHE_SESSION_SECRET"] = "operator-chosen-secret"
54
+ self.assertEqual(server.resolve_secret(self.tmpdir), b"operator-chosen-secret")
55
+
56
+ def test_env_blank_falls_through_to_fresh_generation(self):
57
+ """The docstring promises a blank env value must NOT silently
58
+ weaken signing. A fresh secret must land under data_dir and
59
+ NOT be the empty string."""
60
+ os.environ["WITHCACHE_SESSION_SECRET"] = " "
61
+ got = server.resolve_secret(self.tmpdir)
62
+ self.assertGreaterEqual(len(got), 32)
63
+ self.assertNotEqual(got, b"")
64
+ persisted = os.path.join(self.tmpdir, "session-secret")
65
+ self.assertTrue(os.path.exists(persisted))
66
+
67
+ def test_env_unset_generates_and_persists(self):
68
+ os.environ.pop("WITHCACHE_SESSION_SECRET", None)
69
+ got = server.resolve_secret(self.tmpdir)
70
+ self.assertGreaterEqual(len(got), 32)
71
+ with open(os.path.join(self.tmpdir, "session-secret"), "rb") as f:
72
+ self.assertEqual(f.read(), got)
73
+
74
+ def test_file_persisted_returned_on_second_call(self):
75
+ os.environ.pop("WITHCACHE_SESSION_SECRET", None)
76
+ first = server.resolve_secret(self.tmpdir)
77
+ second = server.resolve_secret(self.tmpdir)
78
+ self.assertEqual(first, second)
79
+
80
+ def test_persisted_file_permissions_are_private(self):
81
+ os.environ.pop("WITHCACHE_SESSION_SECRET", None)
82
+ server.resolve_secret(self.tmpdir)
83
+ path = os.path.join(self.tmpdir, "session-secret")
84
+ mode = os.stat(path).st_mode & 0o777
85
+ self.assertEqual(mode, 0o600)
86
+
87
+
34
88
  class TestAuth(unittest.TestCase):
35
89
  def test_token_roundtrip(self):
36
90
  a = server.Auth(b"secret-key", "pw")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes