diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bcdeaeb63..40b59b930 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -203,6 +203,7 @@ jobs: run: | helm unittest helm/kagent helm unittest helm/tools/querydoc + helm unittest helm/tools/grafana-mcp ui-tests: runs-on: ubuntu-latest diff --git a/helm/kagent/tests/postgresql_test.yaml b/helm/kagent/tests/postgresql_test.yaml index 22c32d558..153cd53ab 100644 --- a/helm/kagent/tests/postgresql_test.yaml +++ b/helm/kagent/tests/postgresql_test.yaml @@ -238,9 +238,8 @@ tests: - contains: path: spec.template.spec.containers[0].securityContext.capabilities.drop content: ALL - - equal: - path: spec.template.spec.containers[0].securityContext.seccompProfile.type - value: RuntimeDefault + - isNull: + path: spec.template.spec.containers[0].securityContext.seccompProfile - it: should allow bundled postgres pod security context override template: postgresql.yaml diff --git a/helm/kagent/tests/security-context_test.yaml b/helm/kagent/tests/security-context_test.yaml index 62d31bcc4..05b5238dd 100644 --- a/helm/kagent/tests/security-context_test.yaml +++ b/helm/kagent/tests/security-context_test.yaml @@ -16,6 +16,9 @@ tests: - equal: path: spec.template.spec.securityContext.runAsNonRoot value: true + - equal: + path: spec.template.spec.securityContext.seccompProfile.type + value: RuntimeDefault - it: should apply default container security context to controller template: controller-deployment.yaml @@ -23,6 +26,14 @@ tests: - equal: path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem value: true + - equal: + path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation + value: false + - contains: + path: spec.template.spec.containers[0].securityContext.capabilities.drop + content: ALL + - isNull: + path: spec.template.spec.containers[0].securityContext.seccompProfile - it: should allow controller pod security context override template: controller-deployment.yaml @@ -87,12 +98,30 @@ tests: # ============================================================================= # UI Security Context Tests # ============================================================================= - - it: should apply UI-specific container security context override + - it: should apply default pod security context to UI + template: ui-deployment.yaml + asserts: + - equal: + path: spec.template.spec.securityContext.runAsNonRoot + value: true + - equal: + path: spec.template.spec.securityContext.seccompProfile.type + value: RuntimeDefault + + - it: should apply default container security context to UI template: ui-deployment.yaml asserts: - equal: path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem value: true + - equal: + path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation + value: false + - contains: + path: spec.template.spec.containers[0].securityContext.capabilities.drop + content: ALL + - isNull: + path: spec.template.spec.containers[0].securityContext.seccompProfile - it: should have nextjs-cache volume for UI template: ui-deployment.yaml diff --git a/helm/kagent/values.yaml b/helm/kagent/values.yaml index 00c2cd990..2327f006c 100644 --- a/helm/kagent/values.yaml +++ b/helm/kagent/values.yaml @@ -37,14 +37,17 @@ labels: {} # -- Security context for all pods podSecurityContext: runAsNonRoot: true + seccompProfile: + type: RuntimeDefault # fsGroup: 2000 # -- Security context for all containers securityContext: + allowPrivilegeEscalation: false readOnlyRootFilesystem: true -# capabilities: -# drop: -# - ALL + capabilities: + drop: + - ALL # runAsUser: 1000 # ============================================================================== @@ -117,8 +120,6 @@ database: capabilities: drop: - ALL - seccompProfile: - type: RuntimeDefault # ============================================================================== # RBAC CONFIGURATION @@ -398,6 +399,16 @@ kagent-tools: enabled: true nameOverride: tools replicaCount: 1 + podSecurityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true resources: requests: cpu: 50m @@ -407,7 +418,7 @@ kagent-tools: tools: loglevel: "debug" metrics: - port: 8085 # Use a different port than the main service port (8084) to avoid duplicate port definitions + port: 8085 # Use a different port than the main service port (8084) to avoid duplicate port definitions # ============================================================================== # PROXY CONFIGURATION diff --git a/helm/tools/grafana-mcp/templates/deployment.yaml b/helm/tools/grafana-mcp/templates/deployment.yaml index 45d593cd3..e2a99b046 100644 --- a/helm/tools/grafana-mcp/templates/deployment.yaml +++ b/helm/tools/grafana-mcp/templates/deployment.yaml @@ -19,6 +19,10 @@ spec: {{- include "grafana-mcp.selectorLabels" . | nindent 8 }} spec: serviceAccountName: {{ include "grafana-mcp.serviceAccountName" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/helm/tools/grafana-mcp/tests/deployment_test.yaml b/helm/tools/grafana-mcp/tests/deployment_test.yaml new file mode 100644 index 000000000..b01bdd4ea --- /dev/null +++ b/helm/tools/grafana-mcp/tests/deployment_test.yaml @@ -0,0 +1,102 @@ +suite: test grafana-mcp deployment +templates: + - deployment.yaml + - configmap.yaml + - secret.yaml +tests: + - it: should render deployment with default values + template: deployment.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: metadata.name + value: RELEASE-NAME-grafana-mcp + - equal: + path: spec.replicas + value: 1 + - hasDocuments: + count: 1 + + - it: should have correct container name + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].name + value: grafana-mcp + + - it: should have correct service account name + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: RELEASE-NAME-grafana-mcp + + - it: should have correct container port + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].ports[0].containerPort + value: 8000 + + # ============================================================================= + # Security Context Tests + # ============================================================================= + - it: should apply default pod security context + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.securityContext.runAsNonRoot + value: true + - equal: + path: spec.template.spec.securityContext.seccompProfile.type + value: RuntimeDefault + + - it: should apply default container security context + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation + value: false + - contains: + path: spec.template.spec.containers[0].securityContext.capabilities.drop + content: ALL + - equal: + path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem + value: true + - equal: + path: spec.template.spec.containers[0].securityContext.runAsUser + value: 1000 + - equal: + path: spec.template.spec.containers[0].securityContext.runAsGroup + value: 999 + - isNull: + path: spec.template.spec.containers[0].securityContext.seccompProfile + + - it: should allow pod security context override + template: deployment.yaml + set: + podSecurityContext: + runAsNonRoot: true + fsGroup: 2000 + asserts: + - equal: + path: spec.template.spec.securityContext.runAsNonRoot + value: true + - equal: + path: spec.template.spec.securityContext.fsGroup + value: 2000 + + - it: should allow container security context override + template: deployment.yaml + set: + securityContext: + readOnlyRootFilesystem: false + runAsUser: 1000 + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem + value: false + - equal: + path: spec.template.spec.containers[0].securityContext.runAsUser + value: 1000 diff --git a/helm/tools/grafana-mcp/values.yaml b/helm/tools/grafana-mcp/values.yaml index 851f1ae2d..01f0f1f50 100644 --- a/helm/tools/grafana-mcp/values.yaml +++ b/helm/tools/grafana-mcp/values.yaml @@ -9,7 +9,7 @@ grafana: image: registry: mcp repository: grafana - pullPolicy: Always + pullPolicy: Always tag: "latest" # Only latest is available via docker hub at present. See https://github.com/grafana/mcp-grafana/issues/180 nameOverride: "" @@ -20,8 +20,20 @@ serviceAccount: annotations: {} name: "" -securityContext: {} - +podSecurityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsUser: 1000 + runAsGroup: 999 + tolerations: [] nodeSelector: {} @@ -57,4 +69,3 @@ volumeMounts: [] # Deployment configuration - used to populate the ConfigMap template. # Add custom configuration values here as needed. config: - diff --git a/helm/tools/querydoc/tests/deployment_test.yaml b/helm/tools/querydoc/tests/deployment_test.yaml index 9923b7a49..c2df4b8e9 100644 --- a/helm/tools/querydoc/tests/deployment_test.yaml +++ b/helm/tools/querydoc/tests/deployment_test.yaml @@ -76,13 +76,38 @@ tests: path: spec.template.metadata.labels["app.kubernetes.io/instance"] value: RELEASE-NAME - - it: should not set pod security context by default + - it: should apply default pod security context template: deployment.yaml asserts: - - notExists: - path: spec.template.spec.securityContext + - equal: + path: spec.template.spec.securityContext.runAsNonRoot + value: true + - equal: + path: spec.template.spec.securityContext.seccompProfile.type + value: RuntimeDefault + + - it: should apply default container security context + template: deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation + value: false + - contains: + path: spec.template.spec.containers[0].securityContext.capabilities.drop + content: ALL + - equal: + path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem + value: true + - equal: + path: spec.template.spec.containers[0].securityContext.runAsUser + value: 14000 + - equal: + path: spec.template.spec.containers[0].securityContext.runAsGroup + value: 14000 + - isNull: + path: spec.template.spec.containers[0].securityContext.seccompProfile - - it: should set pod security context when podSecurityContext is provided + - it: should allow pod security context override template: deployment.yaml set: podSecurityContext: @@ -96,6 +121,20 @@ tests: path: spec.template.spec.securityContext.fsGroup value: 1000 + - it: should allow container security context override + template: deployment.yaml + set: + securityContext: + readOnlyRootFilesystem: false + runAsUser: 1000 + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem + value: false + - equal: + path: spec.template.spec.containers[0].securityContext.runAsUser + value: 1000 + - it: should set nodeSelector template: deployment.yaml set: diff --git a/helm/tools/querydoc/values.yaml b/helm/tools/querydoc/values.yaml index 868a787ec..5321e1d71 100644 --- a/helm/tools/querydoc/values.yaml +++ b/helm/tools/querydoc/values.yaml @@ -14,9 +14,19 @@ serviceAccount: annotations: {} name: "" -podSecurityContext: {} +podSecurityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault -securityContext: {} +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsUser: 14000 + runAsGroup: 14000 tolerations: []