Keep future Coulomb release evidence directories private
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a18e2d-f513-7742-b8e7-12af0b744ff3
This commit is contained in:
parent
d795120f98
commit
904dcb3ce3
4 changed files with 99 additions and 2 deletions
|
|
@ -2,6 +2,8 @@
|
|||
import copy
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import stat
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock
|
||||
|
|
@ -66,6 +68,48 @@ def test_mutable_staging_is_frozen_before_live_work(tmp_path, monkeypatch):
|
|||
assert (instance.journal / "receipt.json").is_file()
|
||||
|
||||
|
||||
def test_nested_capsule_and_release_root_stay_private_under_normal_umask(tmp_path, monkeypatch):
|
||||
root, _ = capsule(tmp_path)
|
||||
nested = root / "charts/coulomb/templates/deployment.yaml"
|
||||
nested.parent.mkdir(parents=True)
|
||||
nested.write_bytes(b"synthetic chart")
|
||||
plan = {"files": {str(p.relative_to(root)): release.sha(p.read_bytes())
|
||||
for p in root.rglob("*") if p.is_file() and p.name != "manifest.json"}}
|
||||
(root / "manifest.json").write_text(json.dumps(plan))
|
||||
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
|
||||
monkeypatch.setattr(release, "JOURNAL_ROOT", tmp_path / "journal")
|
||||
previous = os.umask(0o022)
|
||||
try:
|
||||
instance = release.Release(root, "sha256:" + release.sha(release.canonical(plan)))
|
||||
finally:
|
||||
os.umask(previous)
|
||||
for path in [tmp_path / "journal", *(tmp_path / "journal").rglob("*")]:
|
||||
assert stat.S_IMODE(path.stat().st_mode) == (0o700 if path.is_dir() else 0o600)
|
||||
assert (instance.root / nested.relative_to(root)).read_bytes() == b"synthetic chart"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("problem", ["broad", "link", "ancestor_link", "file"])
|
||||
def test_unsafe_release_parent_is_refused_without_changing_it(tmp_path, monkeypatch, problem):
|
||||
root, digest = capsule(tmp_path)
|
||||
journal = tmp_path / "journal"
|
||||
if problem == "broad":
|
||||
journal.mkdir(mode=0o755)
|
||||
elif problem == "file":
|
||||
journal.write_text("untouched")
|
||||
elif problem == "link":
|
||||
journal.symlink_to(root, target_is_directory=True)
|
||||
else:
|
||||
alias = tmp_path / "alias"
|
||||
alias.symlink_to(root, target_is_directory=True)
|
||||
journal = alias / "journal"
|
||||
monkeypatch.setattr(release.os, "geteuid", lambda: 0)
|
||||
monkeypatch.setattr(release, "JOURNAL_ROOT", journal)
|
||||
before = {str(p): p.lstat() for p in tmp_path.rglob("*")}
|
||||
with pytest.raises((release.Refused, OSError)):
|
||||
release.Release(root, digest)
|
||||
assert before == {str(p): p.lstat() for p in tmp_path.rglob("*")}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("field", ["business_rows_sha256", "content_files_sha256", "migration_rows_sha256"])
|
||||
def test_dataset_drift_is_not_accepted(field):
|
||||
instance = object.__new__(release.Release)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue