Skip to content

Commit 5a5765b

Browse files
committed
Improve error message on corrupt PrivateJsonFile
1 parent 5cddb33 commit 5a5765b

File tree

2 files changed

+31
-16
lines changed

2 files changed

+31
-16
lines changed

openeo/rest/auth/config.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
oschmod = None
2727

2828

29-
_PRIVATE_PERMS = stat.S_IRUSR | stat.S_IWUSR
29+
PRIVATE_PERMISSIONS = stat.S_IRUSR | stat.S_IWUSR
3030

3131
log = logging.getLogger(__name__)
3232

@@ -51,7 +51,7 @@ def assert_private_file(path: Path):
5151
mode = get_file_mode(path)
5252
if (mode & stat.S_IRWXG) or (mode & stat.S_IRWXO):
5353
message = "File {p} could be readable by others: mode {a:o} (expected: {e:o}).".format(
54-
p=path, a=mode & (stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO), e=_PRIVATE_PERMS
54+
p=path, a=mode & (stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO), e=PRIVATE_PERMISSIONS
5555
)
5656
if platform.system() == "Windows":
5757
log.info(message)
@@ -100,16 +100,19 @@ def load(self, empty_on_file_not_found=True) -> dict:
100100
assert_private_file(self._path)
101101
log.debug("Loading private JSON file {p}".format(p=self._path))
102102
# TODO: add file locking to avoid race conditions?
103-
with self._path.open("r", encoding="utf8") as f:
104-
return json.load(f)
103+
try:
104+
with self._path.open("r", encoding="utf8") as f:
105+
return json.load(f)
106+
except Exception as e:
107+
raise RuntimeError(f"Failed to load {type(self).__name__} from {self._path!r}: {e!r}") from e
105108

106109
def _write(self, data: dict):
107110
"""Write whole data to file."""
108111
log.debug("Writing private JSON file {p}".format(p=self._path))
109112
# TODO: add file locking to avoid race conditions?
110113
with self._path.open("w", encoding="utf8") as f:
111114
json.dump(data, f, indent=2)
112-
set_file_mode(self._path, mode=_PRIVATE_PERMS)
115+
set_file_mode(self._path, mode=PRIVATE_PERMISSIONS)
113116
assert_private_file(self._path)
114117

115118
def get(self, *keys, default=None) -> Union[dict, str, int]:

tests/rest/auth/test_config.py

+23-11
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
PrivateJsonFile,
1313
RefreshTokenStore,
1414
get_file_mode,
15+
set_file_mode,
16+
PRIVATE_PERMISSIONS,
1517
)
1618

1719

@@ -34,28 +36,26 @@ def test_provide_file_path(self, tmp_path):
3436
assert private.path.exists()
3537
assert [p.name for p in tmp_path.iterdir()] == ["my_data.secret"]
3638

37-
def test_permissions(self, tmp_path):
39+
def test_permissions_on_create(self, tmp_path):
3840
private = PrivateJsonFile(tmp_path)
3941
assert not private.path.exists()
4042
private.set("foo", "bar", value=42)
4143
assert private.path.exists()
4244
st_mode = get_file_mode(private.path)
4345
assert st_mode & 0o777 == 0o600
4446

45-
def test_wrong_permissions(self, tmp_path, caplog):
46-
private = PrivateJsonFile(tmp_path)
47-
with private.path.open("w") as f:
47+
def test_wrong_permissions_on_load(self, tmp_path, caplog):
48+
path = tmp_path / "my_data.secret"
49+
with path.open("w") as f:
4850
json.dump({"foo": "bar"}, f)
49-
assert private.path.stat().st_mode & 0o077 > 0
51+
assert path.stat().st_mode & 0o077 > 0
52+
53+
private = PrivateJsonFile(path)
5054

5155
if platform.system() != "Windows":
52-
with pytest.raises(
53-
PermissionError, match="readable by others.*expected: 600"
54-
):
56+
with pytest.raises(PermissionError, match="readable by others.*expected: 600"):
5557
private.get("foo")
56-
with pytest.raises(
57-
PermissionError, match="readable by others.*expected: 600"
58-
):
58+
with pytest.raises(PermissionError, match="readable by others.*expected: 600"):
5959
private.set("foo", value="lol")
6060
else:
6161
regex = re.compile("readable by others.*expected: 600")
@@ -93,6 +93,18 @@ def test_remove(self, tmp_path):
9393
private.remove()
9494
assert not private.path.exists()
9595

96+
def test_load_corrupt_content(self, tmp_path):
97+
path = tmp_path / "my_data.secret"
98+
path.write_text("{\nInvalid JSON here!")
99+
set_file_mode(path, mode=PRIVATE_PERMISSIONS)
100+
101+
private = PrivateJsonFile(path=path)
102+
with pytest.raises(
103+
RuntimeError, match=r"Failed to load PrivateJsonFile from .*my_data\.secret.*JSONDecodeError.*line 2"
104+
):
105+
private.load()
106+
107+
96108

97109
class TestAuthConfig:
98110

0 commit comments

Comments
 (0)