diff --git a/PUBLIC_SOURCE_EXPORT.md b/PUBLIC_SOURCE_EXPORT.md index 40503a2..6290110 100644 --- a/PUBLIC_SOURCE_EXPORT.md +++ b/PUBLIC_SOURCE_EXPORT.md @@ -1,3 +1,3 @@ # Public source export -This source snapshot was generated from the private canonical repository at revision `4e5a8f24881de4bde2ef649d3bf3817715241e9d`. It contains no private Git history or operational evidence. Changes are published from the canonical repository. +This source snapshot was generated from the private canonical repository at revision `b619192999975e4ac44b14e43df48ae75bd745b2`. It contains no private Git history or operational evidence. Changes are published from the canonical repository. diff --git a/PUBLIC_SOURCE_MANIFEST.json b/PUBLIC_SOURCE_MANIFEST.json index 403cb51..5ca01f8 100644 --- a/PUBLIC_SOURCE_MANIFEST.json +++ b/PUBLIC_SOURCE_MANIFEST.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, - "sourceRevision": "4e5a8f24881de4bde2ef649d3bf3817715241e9d", + "sourceRevision": "b619192999975e4ac44b14e43df48ae75bd745b2", "files": [ { "path": ".dockerignore", @@ -1659,8 +1659,8 @@ }, { "path": "backend/tests/test_runner_fleet_specialize.py", - "sha256": "bdd7ac3ba94ddb2fc73e6db5744aa1ed363961631408bd8552077b3f0cc66199", - "bytes": 198961 + "sha256": "2d692ef97b2414c9ac114f25d4337b58e6989e719dc6643a3635fa3fab5288e5", + "bytes": 200698 }, { "path": "backend/tests/test_runner_fleet_v2_execution_surface.py", diff --git a/backend/tests/test_runner_fleet_specialize.py b/backend/tests/test_runner_fleet_specialize.py index 002e94b..490b76d 100644 --- a/backend/tests/test_runner_fleet_specialize.py +++ b/backend/tests/test_runner_fleet_specialize.py @@ -285,8 +285,12 @@ def test_source_image_archive_is_verified_and_same_fd_pinned_before_any_load( replacement.chmod(0o600) replacement.replace(archive) elif fault == "changed_fd": + before = archive.stat() with archive.open("r+b") as writer: writer.write(b"X") + # This case tests metadata drift. Two fast writes can share the + # filesystem's timestamp tick, so make that injected drift explicit. + os.utime(archive, ns=(before.st_atime_ns, before.st_mtime_ns + 1_000_000_000)) return SimpleNamespace(returncode=0) verified = [] @@ -389,6 +393,8 @@ def _build_probe_inspect(specialize, record, *, container_id=None, changes=None) "CapAdd": [], "CapDrop": [], "SecurityOpt": ["seccomp=unconfined", "systempaths=unconfined"], + "MaskedPaths": [], + "ReadonlyPaths": [], "Devices": [{ "PathOnHost": "/dev/net/tun", "PathInContainer": "/dev/net/tun", @@ -2995,7 +3001,7 @@ def test_build_probe_container_inspect_accepts_only_fixed_private_build_job(spec {"PathOnHost": "/dev/sda", "PathInContainer": "/dev/sda", "CgroupPermissions": "rwm"}, ]}), ("HostConfig", {"Mounts": [{"Type": "bind", "Source": "/host", "Target": "/host"}]}), - ("HostConfig", {"SecurityOpt": ["seccomp=unconfined"]}), + ("HostConfig", {"SecurityOpt": ["seccomp=unconfined"], "MaskedPaths": ["/proc/kcore"]}), ("Config", {"Env": [*environment, "DOCKER_HOST=tcp://shared-dind:2375"]}), ("Config", {"Image": "localhost/itworx-ci-build:latest"}), ): @@ -3020,6 +3026,29 @@ def test_build_probe_rejects_foreign_or_shared_data_mount(specialize, field, val assert not specialize._validate_build_probe_container(item, record, image_environment=environment) +@pytest.mark.parametrize("security_options", [ + ["seccomp=unconfined"], + ["seccomp=unconfined", "systempaths=unconfined"], +]) +def test_build_probe_accepts_only_verified_effective_unconfined_system_paths(specialize, security_options): + record = _build_probe_record(specialize, container_id="e" * 64, status="created") + item, environment = _build_probe_inspect(specialize, record) + item["HostConfig"]["SecurityOpt"] = security_options + assert specialize._validate_build_probe_container(item, record, image_environment=environment) + for field in ("MaskedPaths", "ReadonlyPaths"): + for value in (None, ["/proc/kcore"], "", {}): + changed = copy.deepcopy(item) + changed["HostConfig"][field] = value + assert not specialize._validate_build_probe_container(changed, record, image_environment=environment) + missing = copy.deepcopy(item) + del missing["HostConfig"][field] + assert not specialize._validate_build_probe_container(missing, record, image_environment=environment) + for options in (None, [], ["systempaths=unconfined"], ["seccomp=unconfined", "apparmor=unconfined"]): + changed = copy.deepcopy(item) + changed["HostConfig"]["SecurityOpt"] = options + assert not specialize._validate_build_probe_container(changed, record, image_environment=environment) + + def test_build_probe_volume_identity_detects_same_name_recreation(specialize, monkeypatch): name = "9" * 64 volume = {