fix(security): stage multi-platform runtime image
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 1m16s
CD Pipeline / build-and-deploy (push) Failing after 4m9s
CD Pipeline / post-deploy-checks (push) Has been skipped

This commit is contained in:
ogt
2026-07-15 09:22:14 +08:00
parent dcaecb6801
commit 41c069875c
3 changed files with 135 additions and 13 deletions

View File

@@ -80,6 +80,19 @@
"name": "local-path-provisioner",
"container": "local-path-provisioner"
}
},
{
"asset_id": "runtime-image:sealed-secrets-controller-0.26.0-canary",
"source_index_digest": "sha256:74cd190f424b591dd82a234685c8c81d50b33af807e03470bc12b23d202e0106",
"platform_digest": "sha256:1827b36853e124ac0dd2554f7cd55c04952ecb7c38ff19a4a8d93d633811ed68",
"source_config_digest": "sha256:bbfc8314cb4978b252fb313b84e1d51a7b0c040befd79ecc903ea952485a3348",
"push_ref": "registry.wooo.work/awoooi/runtime-mirror/sealed-secrets-controller:0.26.0-linux-amd64",
"workload": {
"kind": "deployment",
"namespace": "kube-system",
"name": "sealed-secrets-controller",
"container": "sealed-secrets-controller"
}
}
]
}

View File

@@ -603,9 +603,25 @@ def _registry_descriptor(image_ref: str) -> RegistryDescriptor | None:
)
def _local_config_digest(image_ref: str) -> str:
output = _run(["docker", "image", "inspect", "--format={{.Id}}", image_ref]).stdout
return _require_digest((output or "").strip(), "local_config_digest")
def _local_platform_digest(image_ref: str, platform: str) -> str:
output = _run(
[
"docker",
"image",
"inspect",
"--platform",
platform,
"--format={{json .Descriptor}}",
image_ref,
]
).stdout
try:
descriptor = json.loads(output or "{}")
except json.JSONDecodeError as exc:
raise ControllerError("local_platform_descriptor_invalid") from exc
if not isinstance(descriptor, dict):
raise ControllerError("local_platform_descriptor_invalid")
return _require_digest(descriptor.get("digest"), "local_platform_digest")
def _local_image_present(image_ref: str) -> bool:
@@ -675,14 +691,30 @@ def mirror_images(
if not _archive_contains_digest(archive, image.platform_digest):
raise ControllerError("runtime_cache_export_digest_missing")
_run(
["docker", "load", "--input", str(archive)],
[
"docker",
"load",
"--platform",
policy.platform,
"--input",
str(archive),
],
quiet=True,
)
_run(
["docker", "tag", source_ref, image.push_ref],
quiet=True,
)
_run(["docker", "push", image.push_ref], quiet=True)
_run(
[
"docker",
"push",
"--platform",
policy.platform,
image.push_ref,
],
quiet=True,
)
finally:
_remove_local_image(image.push_ref)
if not source_preexisting:
@@ -763,17 +795,40 @@ def stage_images(
cache.export(source_ref, archive)
if not _archive_contains_digest(archive, image.platform_digest):
raise ControllerError("runtime_cache_export_digest_missing")
if not _archive_contains_digest(archive, source_config_digest):
raise ControllerError(
"runtime_cache_export_config_digest_missing"
)
_run(
["docker", "load", "--input", str(archive)],
[
"docker",
"load",
"--platform",
policy.platform,
"--input",
str(archive),
],
quiet=True,
)
if _local_config_digest(source_ref) != source_config_digest:
raise ControllerError("local_image_config_digest_mismatch")
if (
_local_platform_digest(source_ref, policy.platform)
!= image.platform_digest
):
raise ControllerError("local_image_platform_digest_mismatch")
_run(
["docker", "tag", source_ref, image.push_ref],
quiet=True,
)
_run(["docker", "push", image.push_ref], quiet=True)
_run(
[
"docker",
"push",
"--platform",
policy.platform,
image.push_ref,
],
quiet=True,
)
finally:
_remove_local_image(image.push_ref)
if not source_preexisting:

View File

@@ -238,7 +238,7 @@ class RuntimeImageMirrorControllerTest(unittest.TestCase):
self.assertEqual(policy.work_item_id, "AIA-P0-006-02B")
self.assertEqual(policy.risk_level, "high")
self.assertEqual(len(policy.images), 5)
self.assertEqual(len(policy.images), 6)
by_asset = {image.asset_id: image for image in policy.images}
self.assertEqual(
set(by_asset),
@@ -247,6 +247,7 @@ class RuntimeImageMirrorControllerTest(unittest.TestCase):
"runtime-image:local-path-provisioner-0.0.34-canary",
"runtime-image:metrics-server-0.8.1-canary",
"runtime-image:redis-8.2.3-canary",
"runtime-image:sealed-secrets-controller-0.26.0-canary",
"runtime-image:vpa-recommender-1.6.0-canary",
},
)
@@ -335,6 +336,32 @@ class RuntimeImageMirrorControllerTest(unittest.TestCase):
self.assertEqual(local_path.workload.name, "local-path-provisioner")
self.assertEqual(local_path.workload.container, "local-path-provisioner")
self.assertEqual(local_path.workload.container_kind, "container")
sealed_secrets = by_asset[
"runtime-image:sealed-secrets-controller-0.26.0-canary"
]
self.assertEqual(
sealed_secrets.source_index_digest,
"sha256:74cd190f424b591dd82a234685c8c81d50b33af807e03470bc12b23d202e0106",
)
self.assertEqual(
sealed_secrets.platform_digest,
"sha256:1827b36853e124ac0dd2554f7cd55c04952ecb7c38ff19a4a8d93d633811ed68",
)
self.assertEqual(
sealed_secrets.source_config_digest,
"sha256:bbfc8314cb4978b252fb313b84e1d51a7b0c040befd79ecc903ea952485a3348",
)
self.assertEqual(
sealed_secrets.runtime_repository, "sealed-secrets-controller"
)
self.assertEqual(sealed_secrets.workload.kind, "deployment")
self.assertEqual(sealed_secrets.workload.namespace, "kube-system")
self.assertEqual(sealed_secrets.workload.name, "sealed-secrets-controller")
self.assertEqual(
sealed_secrets.workload.container, "sealed-secrets-controller"
)
self.assertEqual(sealed_secrets.workload.container_kind, "container")
self.assertNotIn("github.com", raw)
self.assertNotIn("ghcr.io", raw)
self.assertIn('"external_pull_allowed": false', raw)
@@ -711,6 +738,26 @@ class RuntimeImageMirrorControllerTest(unittest.TestCase):
)
)
def test_local_platform_digest_reads_platform_descriptor(self) -> None:
digest = "sha256:" + "1" * 64
completed = controller.subprocess.CompletedProcess(
args=[],
returncode=0,
stdout=json.dumps({"digest": digest}),
stderr="",
)
with patch.object(controller, "_run", return_value=completed) as run:
self.assertEqual(
controller._local_platform_digest("source:tag", "linux/amd64"),
digest,
)
command = run.call_args.args[0]
self.assertEqual(command[:3], ["docker", "image", "inspect"])
self.assertIn("--platform", command)
self.assertIn("linux/amd64", command)
self.assertIn("--format={{json .Descriptor}}", command)
def test_target_digest_verifier_uses_internal_registry_transport(self) -> None:
image = controller.load_policy(POLICY_PATH).images[0]
with patch.object(controller.subprocess, "run") as run:
@@ -888,11 +935,13 @@ class RuntimeImageMirrorControllerTest(unittest.TestCase):
side_effect=[None, descriptor],
),
patch.object(controller, "_local_image_present", return_value=False),
patch.object(controller, "_archive_contains_digest", return_value=True),
patch.object(
controller, "_archive_contains_digest", return_value=True
) as archive_contains,
patch.object(
controller,
"_local_config_digest",
return_value=image.source_config_digest,
"_local_platform_digest",
return_value=image.platform_digest,
),
patch.object(controller, "_registry_digest_present", return_value=True),
patch.object(controller, "_remove_local_image") as remove,
@@ -916,6 +965,11 @@ class RuntimeImageMirrorControllerTest(unittest.TestCase):
export.assert_called_once()
commands = [call.args[0] for call in run.call_args_list]
self.assertEqual([command[1] for command in commands], ["load", "tag", "push"])
self.assertEqual(archive_contains.call_count, 2)
self.assertIn("--platform", commands[0])
self.assertIn(policy.platform, commands[0])
self.assertIn("--platform", commands[2])
self.assertIn(policy.platform, commands[2])
self.assertTrue(all("pull" not in command for command in commands))
self.assertEqual(remove.call_count, 2)