Handle canonical Docker capability names

This commit is contained in:
fwazb 2026-07-23 13:27:38 -07:00
parent 2d0f10bb56
commit d0e8286636
2 changed files with 74 additions and 3 deletions

View file

@ -1156,10 +1156,16 @@ def _validate_starting_container(
"container_security", "container_security",
"container_cap_drop_mismatch", "container_cap_drop_mismatch",
) )
cap_add = host.get("CapAdd")
normalized_cap_add = (
[item.removeprefix("CAP_") for item in cap_add]
if isinstance(cap_add, list) and all(isinstance(item, str) for item in cap_add)
else None
)
_verification_require( _verification_require(
isinstance(host.get("CapAdd"), list) normalized_cap_add is not None
and all(isinstance(item, str) for item in host["CapAdd"]) and len(normalized_cap_add) == len(set(normalized_cap_add))
and sorted(host["CapAdd"]) == ["CHOWN", "SETGID", "SETPCAP", "SETUID"], and sorted(normalized_cap_add) == ["CHOWN", "SETGID", "SETPCAP", "SETUID"],
"container_security", "container_security",
"container_cap_add_mismatch", "container_cap_add_mismatch",
) )

View file

@ -725,6 +725,71 @@ def test_container_contract_failures_have_field_specific_bounded_codes(
assert caught.value.failure_reason == failure_reason assert caught.value.failure_reason == failure_reason
def test_container_cap_add_accepts_docker_28_canonical_names(tmp_path: Path) -> None:
bundle, release, image = release_bundle(tmp_path, "2")
paths = install_paths(tmp_path)
host = FakeHost(paths)
host.add_release(release, image)
installer.install_release(
bundle,
paths=paths,
source_binding=source_binding(),
runner=host,
sleeper=lambda _seconds: None,
execute_restart=True,
)
assert host.container is not None
host.container["HostConfig"]["CapAdd"] = [
"CAP_CHOWN",
"CAP_SETGID",
"CAP_SETPCAP",
"CAP_SETUID",
]
verification = installer.verify_running_release(
release,
runner=host,
paths=paths,
sleeper=lambda _seconds: None,
)
assert verification["container_id"] == host.container["Id"]
def test_container_cap_add_rejects_mixed_duplicate_names(tmp_path: Path) -> None:
bundle, release, image = release_bundle(tmp_path, "2")
paths = install_paths(tmp_path)
host = FakeHost(paths)
host.add_release(release, image)
installer.install_release(
bundle,
paths=paths,
source_binding=source_binding(),
runner=host,
sleeper=lambda _seconds: None,
execute_restart=True,
)
assert host.container is not None
host.container["HostConfig"]["CapAdd"] = [
"CHOWN",
"CAP_CHOWN",
"SETGID",
"SETPCAP",
"SETUID",
]
with pytest.raises(installer.VerificationError) as caught:
installer.verify_running_release(
release,
runner=host,
paths=paths,
sleeper=lambda _seconds: None,
)
assert caught.value.failure_stage == "container_security"
assert caught.value.failure_reason == "container_cap_add_mismatch"
def test_container_inspection_shape_has_bounded_code(tmp_path: Path) -> None: def test_container_inspection_shape_has_bounded_code(tmp_path: Path) -> None:
bundle, release, image = release_bundle(tmp_path, "2") bundle, release, image = release_bundle(tmp_path, "2")
paths = install_paths(tmp_path) paths = install_paths(tmp_path)