e5398e3cc7
CI / lint (push) Successful in 17s
CI / build (push) Successful in 16s
CI / security (push) Has been cancelled
CI / docker (push) Has been cancelled
CI / typecheck (push) Has been cancelled
CI / unit_tests (push) Has been cancelled
CI / coverage (push) Has been cancelled
CI / integration_tests (push) Has been cancelled
CI / e2e_tests (push) Has been cancelled
CI / status-check (push) Has been cancelled
CI / benchmark-regression (push) Has been cancelled
CI / benchmark-publish (push) Has been cancelled
CI / quality (push) Has been cancelled
CI / helm (push) Has been cancelled
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 Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me> Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
298 lines
13 KiB
Gherkin
298 lines
13 KiB
Gherkin
Feature: Kubernetes Helm Chart Structure
|
|
As a DevOps engineer
|
|
I want a valid Helm chart in the k8s/ directory
|
|
So that I can deploy the CleverAgents server to Kubernetes
|
|
|
|
Background:
|
|
Given the project root directory
|
|
|
|
# -- Chart.yaml validation --
|
|
|
|
Scenario: Chart.yaml exists with required Helm v2 fields
|
|
When I read the Helm chart metadata
|
|
Then the chart API version should be "v2"
|
|
And the chart name should be "cleveragents"
|
|
And the chart type should be "application"
|
|
And the chart version should be set
|
|
|
|
Scenario: Chart.yaml declares optional Redis dependency
|
|
When I read the Helm chart metadata
|
|
Then the chart should have a dependency named "redis"
|
|
And the Redis dependency should be conditional on "redis.enabled"
|
|
|
|
# -- values.yaml validation --
|
|
|
|
Scenario: values.yaml has configurable replica count
|
|
When I read the Helm chart values
|
|
Then the values should contain key "replicaCount"
|
|
And the default replica count should be 1
|
|
|
|
Scenario: values.yaml has configurable resource limits
|
|
When I read the Helm chart values
|
|
Then the values should contain key "resources"
|
|
And the resources should have CPU and memory limits
|
|
And the resources should have CPU and memory requests
|
|
|
|
Scenario: values.yaml has ingress configuration with TLS support
|
|
When I read the Helm chart values
|
|
Then the values should contain key "ingress"
|
|
And the ingress should have an enabled toggle
|
|
And the ingress should have a TLS configuration section
|
|
|
|
Scenario: values.yaml has optional Redis configuration
|
|
When I read the Helm chart values
|
|
Then the values should contain key "redis"
|
|
And the Redis configuration should have an enabled toggle
|
|
And the Redis configuration should have authentication settings
|
|
|
|
Scenario: values.yaml has server configuration
|
|
When I read the Helm chart values
|
|
Then the values should contain key "server"
|
|
And the server config should have host setting
|
|
And the server config should have port setting
|
|
And the server config should have workers setting
|
|
|
|
Scenario: values.yaml has database configuration
|
|
When I read the Helm chart values
|
|
Then the values should contain key "database"
|
|
And the database config should support existing secrets
|
|
|
|
Scenario: values.yaml has security context for non-root execution
|
|
When I read the Helm chart values
|
|
Then the pod security context should enforce non-root execution
|
|
And the container security context should drop all capabilities
|
|
|
|
# -- Template file content validation --
|
|
|
|
Scenario: Deployment template has correct kind and API version
|
|
When I read the template "k8s/templates/deployment.yaml"
|
|
Then the template should contain "kind: Deployment"
|
|
And the template should contain "apiVersion: apps/v1"
|
|
And the template should contain "volumeMounts:"
|
|
And the template should contain "mountPath: /tmp"
|
|
And the template should contain "mountPath: /app/data"
|
|
And the template should contain "sizeLimit: 100Mi"
|
|
And the template should contain "sizeLimit: 1Gi"
|
|
|
|
Scenario: Service template has correct kind and API version
|
|
When I read the template "k8s/templates/service.yaml"
|
|
Then the template should contain "kind: Service"
|
|
And the template should contain "apiVersion: v1"
|
|
|
|
Scenario: Ingress template has correct kind and API version
|
|
When I read the template "k8s/templates/ingress.yaml"
|
|
Then the template should contain "kind: Ingress"
|
|
And the template should contain "networking.k8s.io/v1"
|
|
And the template should match pattern "^\s+tls:"
|
|
|
|
Scenario: ConfigMap template has correct kind and API version
|
|
When I read the template "k8s/templates/configmap.yaml"
|
|
Then the template should contain "kind: ConfigMap"
|
|
And the template should contain "apiVersion: v1"
|
|
|
|
Scenario: ServiceAccount template has correct kind and API version
|
|
When I read the template "k8s/templates/serviceaccount.yaml"
|
|
Then the template should contain "kind: ServiceAccount"
|
|
And the template should contain "apiVersion: v1"
|
|
And the template should contain "automountServiceAccountToken: false"
|
|
|
|
Scenario: Secrets template has correct kind
|
|
When I read the template "k8s/templates/secrets.yaml"
|
|
Then the template should contain "kind: Secret"
|
|
|
|
Scenario: Helpers template exists with chart helpers
|
|
When I read the template "k8s/templates/_helpers.tpl"
|
|
Then the template should contain "cleveragents.fullname"
|
|
And the template should contain "cleveragents.labels"
|
|
|
|
Scenario: NOTES.txt template exists with deployment info
|
|
When I read the template "k8s/templates/NOTES.txt"
|
|
Then the template should contain "CleverAgents Server has been deployed"
|
|
|
|
# -- Server Dockerfile --
|
|
|
|
Scenario: Server-specific Dockerfile exists
|
|
Then the chart file "Dockerfile.server" should exist
|
|
|
|
Scenario: Server Dockerfile uses multi-stage build
|
|
When I read the server Dockerfile
|
|
Then it should have a builder stage
|
|
And it should have a runtime stage
|
|
|
|
Scenario: Server Dockerfile uses non-root user
|
|
When I read the server Dockerfile
|
|
Then it should create a non-root user with uid 1000
|
|
|
|
Scenario: Server Dockerfile exposes port 8000
|
|
When I read the server Dockerfile
|
|
Then it should expose port 8000
|
|
|
|
Scenario: Server Dockerfile pins uv image version
|
|
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
|
|
When I read the template "k8s/templates/secrets.yaml"
|
|
Then the template should contain "database.existingSecret"
|
|
And the template should contain "database.url"
|
|
And the template should contain "database-url"
|
|
|
|
Scenario: Secrets template guards Redis secret with existingSecret check
|
|
When I read the template "k8s/templates/secrets.yaml"
|
|
Then the template should contain "redis.auth.existingSecret"
|
|
And the template should contain "redis.auth.password"
|
|
And the template should contain "redis-password"
|
|
|
|
# -- Deployment command/args --
|
|
|
|
Scenario: Deployment template overrides command with CLI server serve values
|
|
When I read the template "k8s/templates/deployment.yaml"
|
|
Then the template should contain "python"
|
|
And the template should contain "cleveragents"
|
|
And the template should contain "server"
|
|
And the template should contain "serve"
|
|
And the template should contain "--app"
|
|
And the template should contain "cleveragents.a2a.asgi:app"
|
|
And the template should contain "server.host"
|
|
And the template should contain "server.port"
|
|
And the template should contain "server.workers"
|
|
And the template should contain "server.logLevel"
|
|
|
|
# -- envFrom wiring --
|
|
|
|
Scenario: Deployment template injects ConfigMap via envFrom
|
|
When I read the template "k8s/templates/deployment.yaml"
|
|
Then the template should contain "envFrom"
|
|
And the template should contain "configMapRef"
|
|
|
|
# -- Redis host helper --
|
|
|
|
Scenario: Helpers template defines Redis host using Release.Name
|
|
When I read the template "k8s/templates/_helpers.tpl"
|
|
Then the template should contain "cleveragents.redisHost"
|
|
And the template should contain ".Release.Name"
|
|
|
|
# -- Probes --
|
|
|
|
Scenario: values.yaml splits liveness and readiness probe endpoints
|
|
When I read the Helm chart values
|
|
Then the liveness probe should target the live endpoint
|
|
And the readiness probe should target the ready endpoint
|
|
|
|
# -- Image defaults --
|
|
|
|
Scenario: values.yaml has sensible image defaults
|
|
When I read the Helm chart values
|
|
Then the image pull policy should be "IfNotPresent"
|
|
And the image tag should default to empty for appVersion fallback
|
|
|
|
# -- Service defaults --
|
|
|
|
Scenario: values.yaml service defaults to ClusterIP on port 8000
|
|
When I read the Helm chart values
|
|
Then the service type should be "ClusterIP"
|
|
And the service port should be 8000
|
|
|
|
# -- Conditional template branch validation --
|
|
|
|
Scenario: Ingress template is guarded by ingress.enabled condition
|
|
When I read the template "k8s/templates/ingress.yaml"
|
|
Then the template should match pattern "^\{\{-\s*if\s+\.Values\.ingress\.enabled"
|
|
|
|
Scenario: Ingress template guards ssl-redirect against user annotation override
|
|
When I read the template "k8s/templates/ingress.yaml"
|
|
Then the template should match pattern "not.*hasKey.*\.Values\.ingress\.annotations.*ssl-redirect"
|
|
|
|
Scenario: ServiceAccount template is guarded by serviceAccount.create condition
|
|
When I read the template "k8s/templates/serviceaccount.yaml"
|
|
Then the template should match pattern "^\{\{-\s*if\s+\.Values\.serviceAccount\.create"
|
|
|
|
Scenario: Secrets template guards database secret with conditional logic
|
|
When I read the template "k8s/templates/secrets.yaml"
|
|
Then the template should match pattern "if\s+and\s+\.Values\.database\.url.*not\s+\.Values\.database\.existingSecret"
|
|
|
|
Scenario: Secrets template guards Redis secret with conditional logic
|
|
When I read the template "k8s/templates/secrets.yaml"
|
|
Then the template should match pattern "if\s+and\s+\.Values\.redis\.enabled\s+\.Values\.redis\.auth\.enabled\s+\.Values\.redis\.auth\.password.*not\s+\.Values\.redis\.auth\.existingSecret"
|
|
|
|
Scenario: Deployment template has database credential 3-way branching
|
|
When I read the template "k8s/templates/deployment.yaml"
|
|
Then the template should match pattern "if\s+\.Values\.database\.existingSecret"
|
|
And the template should match pattern "else\s+if\s+\.Values\.database\.url"
|
|
|
|
Scenario: Deployment template has Redis credential 3-way branching
|
|
When I read the template "k8s/templates/deployment.yaml"
|
|
Then the template should match pattern "if\s+\.Values\.redis\.auth\.existingSecret"
|
|
And the template should match pattern "else\s+if\s+\.Values\.redis\.auth\.password"
|
|
And the template should contain "name: {{ .Release.Name }}-redis"
|
|
And the template should contain "key: redis-password"
|
|
|
|
Scenario: Deployment template gates Redis env vars behind redis.enabled
|
|
When I read the template "k8s/templates/deployment.yaml"
|
|
Then the template should match pattern "if\s+\.Values\.redis\.enabled"
|
|
And the template should match pattern "CLEVERAGENTS_REDIS_HOST"
|
|
And the template should match pattern "CLEVERAGENTS_REDIS_PASSWORD"
|
|
|
|
Scenario: Deployment template requires explicit database configuration
|
|
When I read the template "k8s/templates/deployment.yaml"
|
|
Then the template should contain "database configuration is required"
|
|
|
|
Scenario: Helm render fails fast without database configuration
|
|
When I render the Helm chart without database configuration
|
|
Then the render should fail with required database configuration error
|
|
|
|
Scenario: Helm render fails when ingress is enabled without TLS by default
|
|
When I render the Helm chart with ingress enabled and no TLS
|
|
Then the render should fail with required ingress TLS configuration error
|
|
|
|
Scenario: Helm render allows explicit insecure ingress opt-out for development
|
|
When I render the Helm chart with ingress enabled and insecure opt-out enabled
|
|
Then the ingress render should succeed in insecure dev mode
|
|
|
|
Scenario: Helm render succeeds when ingress TLS is explicitly configured
|
|
When I render the Helm chart with ingress enabled and TLS configured
|
|
Then the ingress render should succeed with TLS enabled
|
|
|
|
Scenario: Deployment template disables service account token mounting
|
|
When I read the template "k8s/templates/deployment.yaml"
|
|
Then the template should match pattern "^\s+automountServiceAccountToken:\s+false"
|
|
|
|
Scenario: Security context includes seccomp profile
|
|
When I read the Helm chart values
|
|
Then the container security context should have a seccomp profile
|
|
|
|
Scenario: Security context enforces readOnlyRootFilesystem
|
|
When I read the Helm chart values
|
|
Then the container security context should set readOnlyRootFilesystem to true
|
|
|
|
Scenario: Security context disables privilege escalation
|
|
When I read the Helm chart values
|
|
Then the container security context should set allowPrivilegeEscalation to false
|
|
|
|
Scenario: Server Dockerfile pins uv version to specific semver
|
|
When I read the server Dockerfile
|
|
Then the uv image reference should use a specific semver tag
|
|
|
|
Scenario: Server Dockerfile removes uv from runtime image
|
|
When I read the server Dockerfile
|
|
Then the Dockerfile should remove uv after installation
|
|
|
|
# -- Deployment README --
|
|
|
|
Scenario: Deployment README exists with instructions
|
|
When I read the deployment README
|
|
Then it should contain quick start instructions
|
|
And it should contain TLS configuration documentation
|
|
And it should contain Redis configuration documentation
|
|
And it should contain scaling instructions
|