From e35e60591488c33dcfbc7e17d37dee507f12bc3b Mon Sep 17 00:00:00 2001 From: Developer Date: Mon, 15 Jun 2026 10:22:36 +0000 Subject: [PATCH] fix: bump manifest image tag when compiler logic changes compute_image_tag hashed only the manifest JSON, so cached images built before the entrypoint fix were reused even though compile_entrypoint() now produces a different entrypoint. This caused containers to keep using the old (broken) entrypoint that exited immediately. - Include a compiler_version token in the hash input so manifest compiler changes invalidate previously built images - This forces a fresh image build for new instances after any change to compile_dockerfile, compile_entrypoint, or compile_compose Quality gates: - pytest tests/unit: 219 passed - ruff: clean on changed files - mypy: clean on changed files --- apps/api/src/services/build/manifest_compiler.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/api/src/services/build/manifest_compiler.py b/apps/api/src/services/build/manifest_compiler.py index 605edaa..a82e4b7 100644 --- a/apps/api/src/services/build/manifest_compiler.py +++ b/apps/api/src/services/build/manifest_compiler.py @@ -571,6 +571,10 @@ def get_manifest_home_dir(manifest: dict) -> str: def compute_image_tag(tool_name: str, manifest: dict) -> str: """Compute a deterministic image tag from manifest content. + The hash includes the manifest JSON plus a compiler version token so + that changes to the Dockerfile/entrypoint generation logic invalidate + previously built images. + Args: tool_name: Human-readable tool name. manifest: Fully resolved manifest JSON. @@ -578,9 +582,11 @@ def compute_image_tag(tool_name: str, manifest: dict) -> str: Returns: Docker image tag string. """ - # Canonicalize: sort keys, stable JSON + compiler_version = "v2" # bump when compile_dockerfile/entrypoint/compose change canonical = json.dumps(manifest, sort_keys=True, separators=(",", ":")) - hash_suffix = hashlib.sha256(canonical.encode()).hexdigest()[:8] + hash_suffix = hashlib.sha256( + f"{compiler_version}:{canonical}".encode() + ).hexdigest()[:8] safe_name = tool_name.lower().replace(" ", "-").replace("_", "-") return f"headquarter/{safe_name}-{hash_suffix}:latest"