Skip to content

Commit d4f71e8

Browse files
vuanhphungIsaac
andcommitted
Include ctime in the CA file signature
An in-place rewrite that keeps the size and mtime (cp -p, rsync -t) left the key unchanged until the TTL expired; ctime cannot be preserved that way. Signed-off-by: Vu Anh Phung <vu.phung@databricks.com> Co-authored-by: Isaac <no-reply@databricks.com>
1 parent c1fd8c6 commit d4f71e8

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎src/databricks/sql/common/ssl_context_cache.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ def _file_signature(path) -> Optional[Tuple]:
3535
st = os.stat(path)
3636
except (OSError, TypeError, ValueError):
3737
return (path, None)
38-
return (path, st.st_ino, st.st_size, st.st_mtime_ns)
38+
# ctime too: in-place rewrites that preserve mtime (cp -p, rsync -t) still change it.
39+
return (path, st.st_ino, st.st_size, st.st_mtime_ns, st.st_ctime_ns)
3940

4041

4142
def _cache_key(kind: str, ssl_options: "SSLOptions") -> tuple:

‎tests/unit/test_ssl_context_cache.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import ssl
3+
import sys
34
import threading
45
import time
56
from types import SimpleNamespace
@@ -94,6 +95,29 @@ def test_rewritten_ca_file_gets_a_new_context(self, tmp_path):
9495
assert before is not after
9596
assert ssl_context_cache.get_ssl_context("k", options, build) is after
9697

98+
@pytest.mark.skipif(
99+
sys.platform == "win32", reason="st_ctime is the creation time on Windows"
100+
)
101+
def test_in_place_rewrite_keeping_mtime_gets_a_new_context(self, tmp_path):
102+
ca_file = tmp_path / "ca.pem"
103+
ca_file.write_text("old")
104+
original = ca_file.stat()
105+
options = SSLOptions(tls_trusted_ca_file=str(ca_file))
106+
build, built = counting_builder()
107+
before = ssl_context_cache.get_ssl_context("k", options, build)
108+
109+
time.sleep(0.05) # filesystem timestamps can be jiffy-granular
110+
ca_file.write_text("new") # same inode and size, like `cp -p`
111+
os.utime(ca_file, ns=(original.st_atime_ns, original.st_mtime_ns))
112+
rewritten = ca_file.stat()
113+
114+
assert (rewritten.st_ino, rewritten.st_size, rewritten.st_mtime_ns) == (
115+
original.st_ino,
116+
original.st_size,
117+
original.st_mtime_ns,
118+
)
119+
assert ssl_context_cache.get_ssl_context("k", options, build) is not before
120+
97121
def test_default_bundle_env_change_gets_a_new_context(self, tmp_path, monkeypatch):
98122
bundle = tmp_path / "bundle.pem"
99123
bundle.write_text("x")

0 commit comments

Comments
 (0)