From e28b7e89eb1589d31d7a1b101e5ed3e7328dfcf0 Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Freeman Date: Thu, 2 Apr 2026 08:13:01 +0000 Subject: [PATCH] feat(server): implement serve CLI subcommand and align Dockerfile entrypoint The `cleveragents server serve` CLI subcommand already exists in server.py and Dockerfile.server already uses `python -m cleveragents` as its ENTRYPOINT with `server serve` as the CMD. Add BDD scenarios to k8s_helm_chart.feature that explicitly verify: - Dockerfile.server ENTRYPOINT uses `python -m cleveragents` - Dockerfile.server CMD includes the `server serve` subcommand tokens Add corresponding step definitions to k8s_helm_chart_steps.py. Closes #1088 --- features/k8s_helm_chart.feature | 8 +++++++ features/steps/k8s_helm_chart_steps.py | 29 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) 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" -- 2.52.0