diff --git a/features/k8s_helm_chart.feature b/features/k8s_helm_chart.feature index 551577ed2..f7c732148 100644 --- a/features/k8s_helm_chart.feature +++ b/features/k8s_helm_chart.feature @@ -131,6 +131,14 @@ Feature: Kubernetes Helm Chart Structure When I read the server Dockerfile Then it should not use unpinned uv latest tag + Scenario: Server Dockerfile uses python -m cleveragents as ENTRYPOINT + When I read the server Dockerfile + Then the ENTRYPOINT should use "python -m cleveragents" + + Scenario: Server Dockerfile CMD uses server serve subcommand + When I read the server Dockerfile + Then the CMD should include "server" and "serve" + # -- Secrets structure -- Scenario: Secrets template guards database secret with existingSecret check diff --git a/features/steps/k8s_helm_chart_steps.py b/features/steps/k8s_helm_chart_steps.py index df5588569..daaec178a 100644 --- a/features/steps/k8s_helm_chart_steps.py +++ b/features/steps/k8s_helm_chart_steps.py @@ -353,6 +353,35 @@ def step_dockerfile_removes_uv(context: Context) -> None: ) +@then('the ENTRYPOINT should use "{entrypoint}"') +def step_dockerfile_entrypoint(context: Context, entrypoint: str) -> None: + """Assert that the Dockerfile ENTRYPOINT contains the expected command.""" + pattern: re.Pattern[str] = re.compile(r"^ENTRYPOINT\s+\[.*\]", re.MULTILINE) + match = pattern.search(context.dockerfile_content) + assert match is not None, "Dockerfile.server is missing an ENTRYPOINT instruction" + entrypoint_line = match.group(0) + # Verify each token of the expected entrypoint appears in the ENTRYPOINT line + for token in entrypoint.split(): + assert token in entrypoint_line, ( + f"Expected ENTRYPOINT to contain '{token}', but got: {entrypoint_line!r}" + ) + + +@then('the CMD should include "{cmd_a}" and "{cmd_b}"') +def step_dockerfile_cmd_includes(context: Context, cmd_a: str, cmd_b: str) -> None: + """Assert that the Dockerfile CMD contains the expected subcommand tokens.""" + pattern: re.Pattern[str] = re.compile(r"^CMD\s+\[.*\]", re.MULTILINE) + match = pattern.search(context.dockerfile_content) + assert match is not None, "Dockerfile.server is missing a CMD instruction" + cmd_line = match.group(0) + assert cmd_a in cmd_line, ( + f"Expected CMD to contain '{cmd_a}', but got: {cmd_line!r}" + ) + assert cmd_b in cmd_line, ( + f"Expected CMD to contain '{cmd_b}', but got: {cmd_line!r}" + ) + + @when("I read the deployment README") def step_read_deployment_readme(context: Context) -> None: readme_path: Path = context.project_root / "k8s" / "README.md"