1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2025-12-25 04:46:25 +00:00

Fix docker_config check for add-ons (#6119)

* Fix docker_config check to ignore Docker VOLUME mounts

Only validate /media and /share mounts that are explicitly configured
in add-on map_volumes, not those created by Docker VOLUME statements.

* Check and test with custom map targets
This commit is contained in:
Stefan Agner
2025-08-22 10:38:41 +02:00
committed by GitHub
parent 9740de7a83
commit 1fb15772d7
2 changed files with 219 additions and 5 deletions

View File

@@ -37,6 +37,33 @@ def _make_mock_container_get(bad_config_names: list[str], folder: str = "media")
return mock_container_get
def _make_mock_container_get_with_volume_mount(
bad_config_names: list[str], folder: str = "media"
):
"""Make mock of container get with VOLUME mount (not managed by supervisor)."""
# This simulates a Docker VOLUME mount with wrong propagation
# but NOT created by supervisor configuration
mount = {
"Type": "bind",
"Source": f"/var/lib/docker/volumes/something_{folder}/_data", # Docker volume source
"Destination": f"/{folder}",
"Mode": "rw",
"RW": True,
"Propagation": "rprivate", # Wrong propagation, but not our mount
}
def mock_container_get(name):
out = MagicMock()
out.status = "running"
out.attrs = {"State": {}, "Mounts": []}
if name in bad_config_names:
out.attrs["Mounts"].append(mount)
return out
return mock_container_get
async def test_base(coresys: CoreSys):
"""Test check basics."""
docker_config = CheckDockerConfig(coresys)
@@ -119,6 +146,160 @@ async def test_check(
)
@pytest.mark.parametrize("folder", ["media", "share"])
async def test_addon_volume_mount_not_flagged(
docker: DockerAPI, coresys: CoreSys, install_addon_ssh: Addon, folder: str
):
"""Test that add-on with VOLUME mount to media/share but not in config is not flagged."""
# Create an add-on that doesn't have media/share in its mapping configuration
# Remove the mapping from the addon configuration
install_addon_ssh.data["map"] = [
{"type": "config", "read_only": False},
{"type": "ssl", "read_only": True},
] # No media/share
# Mock container that has VOLUME mount to media/share with wrong propagation
docker.containers.get = _make_mock_container_get_with_volume_mount(
["addon_local_ssh"], folder
)
await coresys.core.set_state(CoreState.SETUP)
with patch.object(DockerInterface, "is_running", return_value=True):
await coresys.plugins.load()
await coresys.homeassistant.load()
await coresys.addons.load()
docker_config = CheckDockerConfig(coresys)
assert not coresys.resolution.issues
assert not coresys.resolution.suggestions
# Run check - should NOT create issue for add-on since mount wasn't requested
await docker_config.run_check()
# Should not create addon issue for VOLUME mounts not in config
addon_issues = [
issue
for issue in coresys.resolution.issues
if issue.context == ContextType.ADDON and issue.reference == "local_ssh"
]
assert len(addon_issues) == 0, (
"Add-on should not be flagged for VOLUME mounts not in config"
)
# No system issue should be created either if no containers have issues
system_issues = [
issue
for issue in coresys.resolution.issues
if issue.context == ContextType.SYSTEM
]
assert len(system_issues) == 0
@pytest.mark.parametrize("folder", ["media", "share"])
async def test_addon_configured_mount_still_flagged(
docker: DockerAPI, coresys: CoreSys, install_addon_ssh: Addon, folder: str
):
"""Test that add-on with configured media/share mount is still flagged when propagation wrong."""
# Keep the original configuration which includes media/share
# SSH addon config already has media:rw and share:rw
# Mock container that has supervisor-managed mount with wrong propagation
mount = {
"Type": "bind",
"Source": f"/mnt/data/supervisor/{folder}", # Supervisor-managed source
"Destination": f"/{folder}",
"Mode": "rw",
"RW": True,
"Propagation": "rprivate", # Wrong propagation
}
def mock_container_get(name):
out = MagicMock()
out.status = "running"
out.attrs = {"State": {}, "Mounts": []}
if name == "addon_local_ssh":
out.attrs["Mounts"].append(mount)
return out
docker.containers.get = mock_container_get
await coresys.core.set_state(CoreState.SETUP)
with patch.object(DockerInterface, "is_running", return_value=True):
await coresys.plugins.load()
await coresys.homeassistant.load()
await coresys.addons.load()
docker_config = CheckDockerConfig(coresys)
assert not coresys.resolution.issues
# Run check - should create issue for add-on since mount was requested in config
await docker_config.run_check()
# Should have addon issue since the mount was configured
addon_issues = [
issue
for issue in coresys.resolution.issues
if issue.context == ContextType.ADDON and issue.reference == "local_ssh"
]
assert len(addon_issues) == 1, (
"Add-on should be flagged for configured mounts with wrong propagation"
)
@pytest.mark.parametrize("folder", ["media", "share"])
async def test_addon_custom_target_path_flagged(
docker: DockerAPI, coresys: CoreSys, install_addon_ssh: Addon, folder: str
):
"""Test that add-on with custom target path for media/share is properly checked."""
# Configure add-on with custom target path
custom_path = f"/custom/{folder}"
mapping_type = "media" if folder == "media" else "share"
install_addon_ssh.data["map"] = [
{"type": mapping_type, "read_only": False, "path": custom_path},
]
def mock_container_get(name: str) -> MagicMock:
"""Mock container get with custom target path mount."""
out = MagicMock()
out.status = "running"
out.attrs = {"State": {}, "Mounts": []}
# Add mount with custom target path and wrong propagation
mount = {
"Source": f"/mnt/data/supervisor/{folder}",
"Destination": custom_path, # Custom target path
"Propagation": "rprivate", # Wrong propagation
}
if name == "addon_local_ssh":
out.attrs["Mounts"].append(mount)
return out
docker.containers.get = mock_container_get
await coresys.core.set_state(CoreState.SETUP)
with patch.object(DockerInterface, "is_running", return_value=True):
await coresys.plugins.load()
await coresys.homeassistant.load()
await coresys.addons.load()
docker_config = CheckDockerConfig(coresys)
assert not coresys.resolution.issues
# Run check - should create issue for add-on with custom target path
await docker_config.run_check()
# Should have addon issue since the mount with custom path was configured
addon_issues = [
issue
for issue in coresys.resolution.issues
if issue.context == ContextType.ADDON and issue.reference == "local_ssh"
]
assert len(addon_issues) == 1, (
"Add-on should be flagged for configured mounts with custom paths and wrong propagation"
)
async def test_did_run(coresys: CoreSys):
"""Test that the check ran as expected."""
docker_config = CheckDockerConfig(coresys)