feat: add live config profile refresh
- Standardize built-in tool users for shared writable profile mounts - Mount canonical non-Git profile sources across compatible instances - Report restart-required outcomes and guard active profile deletion - Surface restart feedback in config profile editing Quality gates: frontend build passed; backend py_compile and LSP passed. Skipped: backend pytest/Ruff unavailable; Docker/manual checks not approved.
This commit is contained in:
@@ -532,6 +532,54 @@ class TestApplyResolvedProfile:
|
||||
assert Path(volumes[0]["source"]).name == "workspace_x_y"
|
||||
assert (Path(volumes[0]["source"]) / "z.json").exists()
|
||||
|
||||
def test_top_level_files_use_profile_scoped_direct_bind_mounts(self, tmp_path) -> None:
|
||||
"""Top-level files are shared safely without mounting over a workspace."""
|
||||
profile_id = uuid.uuid4()
|
||||
resolved = ResolvedProfile(
|
||||
profile_id=profile_id,
|
||||
profile_name="test",
|
||||
files={".tool/config.toml": "setting = true"},
|
||||
)
|
||||
|
||||
instance_root = tmp_path / "instances"
|
||||
_, files, volumes, _ = apply_resolved_profile(
|
||||
str(instance_root / "instance-a"),
|
||||
resolved,
|
||||
working_dir="/workspace/project",
|
||||
)
|
||||
|
||||
canonical_file = (
|
||||
instance_root / "config-profiles" / str(profile_id) / "files" / ".tool" / "config.toml"
|
||||
)
|
||||
assert files == {}
|
||||
assert volumes == [
|
||||
{
|
||||
"source": str(canonical_file),
|
||||
"target": "/workspace/project/.tool/config.toml",
|
||||
"type": "bind",
|
||||
"readonly": False,
|
||||
}
|
||||
]
|
||||
assert canonical_file.read_text() == "setting = true"
|
||||
|
||||
def test_instances_share_profile_scoped_mount_sources(self, tmp_path) -> None:
|
||||
"""Different instance paths resolve a profile to one canonical source."""
|
||||
profile_id = uuid.uuid4()
|
||||
resolved = ResolvedProfile(
|
||||
profile_id=profile_id,
|
||||
profile_name="test",
|
||||
mounts={"/app": ResolvedMount(target="/app", mode="rw", files={"config.ini": "x"})},
|
||||
)
|
||||
|
||||
instance_root = tmp_path / "instances"
|
||||
_, _, first_volumes, _ = apply_resolved_profile(str(instance_root / "instance-a"), resolved)
|
||||
_, _, second_volumes, _ = apply_resolved_profile(str(instance_root / "instance-b"), resolved)
|
||||
|
||||
assert first_volumes[0]["source"] == second_volumes[0]["source"]
|
||||
assert first_volumes[0]["source"] == str(
|
||||
instance_root / "config-profiles" / str(profile_id) / "mounts" / "app"
|
||||
)
|
||||
|
||||
def test_empty_mount_produces_no_volumes(self, tmp_path) -> None:
|
||||
"""A mount with no files should not produce any volume entries."""
|
||||
resolved = ResolvedProfile(
|
||||
@@ -579,7 +627,7 @@ class TestApplyResolvedProfile:
|
||||
|
||||
assert len(volumes) == 1
|
||||
assert volumes[0]["target"] == "/etc/app"
|
||||
assert volumes[0].get("readonly") is True
|
||||
assert volumes[0].get("readonly")
|
||||
|
||||
def test_writable_mount_does_not_set_readonly_flag(self, tmp_path) -> None:
|
||||
"""A mount with mode 'rw' should not set readonly on the volume entry."""
|
||||
@@ -598,7 +646,7 @@ class TestApplyResolvedProfile:
|
||||
|
||||
assert len(volumes) == 1
|
||||
assert volumes[0]["target"] == "/app"
|
||||
assert volumes[0].get("readonly") is False
|
||||
assert not volumes[0].get("readonly")
|
||||
|
||||
|
||||
class TestCheckIncludeCycle:
|
||||
|
||||
Reference in New Issue
Block a user