fix: support nss wrapper in Helm chart (#40673)

## Description

Requires: https://github.com/appsmithorg/appsmith/pull/40642

Adds an environment variable activating nss_wrapper when the
`securityPolicy.runAsUser` value is set so the UID can be set
dynamically. This avoids the `I have no name!` in the prompt when doing
a `kubectl exec` with that value set.

I am also introducing
[helm-unittest](https://github.com/helm-unittest/helm-unittest) for
ensuring that changes to our defaults are made explicit.

Fixes https://github.com/appsmithorg/appsmith/issues/38787

## Automation

/ok-to-test tags=""

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!WARNING]
> Tests have not run on the HEAD
d30d87ffc66c107f980a3b27464e97db0910dcbe yet
> <hr>Mon, 19 May 2025 18:59:10 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added automated unit testing for Helm charts, including snapshot and
security context tests.
- Introduced documentation for running and understanding Helm chart unit
tests.
- Added a GitHub Actions workflow to run Helm chart unit tests on pull
requests and manually.
- **Bug Fixes**
- Ensured the LD_PRELOAD environment variable is set when a specific
security context is configured in deployments.
- **Documentation**
- Updated Helm chart README to reference new testing documentation and
improve clarity.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Goutham Pratapa <goutham@appsmith.com>
This commit is contained in:
Wyatt Walter 2025-06-04 10:24:46 -05:00 committed by GitHub
parent 3d7a99e922
commit 4c7a019adf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 319 additions and 2 deletions

26
.github/workflows/helm-unittest.yml vendored Normal file
View File

@ -0,0 +1,26 @@
name: Helm Unit Tests
on:
pull_request:
branches:
- release
paths:
- "deploy/helm/**"
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
defaults:
run:
working-directory: deploy/helm
shell: bash
steps:
- name: Checkout the code
uses: actions/checkout@v4
- name: Unittest
run: |
docker run --rm -v $(pwd):/apps helmunittest/helm-unittest .

View File

@ -11,7 +11,7 @@ sources:
- https://github.com/appsmithorg/appsmith
home: https://www.appsmith.com/
icon: https://assets.appsmith.com/appsmith-icon.png
version: 3.6.2
version: 3.6.3
dependencies:
- condition: redis.enabled
name: redis

View File

@ -1,4 +1,3 @@
# Appsmith
Appsmith is a JS-based internal tool development platform. Internal tools take a lot of time to build even though they involve the same UI components, data integrations, and user access management. Developers love Appsmith because it saves them hundreds of hours.
@ -228,3 +227,7 @@ helm upgrade --values values.yaml stable-appsmith/appsmith appsmith
If at any time you encounter an error during the installation process, reach out to support@appsmith.com or join our Discord Server
If you know the error and would like to reinstall Appsmith, simply delete the installation folder and the templates folder and execute the script again
## Testing
Review tests/README.md for details on how the chart is tested.

View File

@ -144,6 +144,11 @@ spec:
value: kubernetes.KUBE_PING
- name: APPSMITH_HEADLESS_SVC
value: {{ include "appsmith.fullname" . }}-headless
{{- if .Values.securityContext.runAsUser | default nil }}
# ensure the interactive shell when connected via kubectl exec is set
- name: LD_PRELOAD
value: /usr/local/lib/libnss_wrapper.so
{{- end }}
envFrom:
- configMapRef:
name: {{ include "appsmith.fullname" . }}

View File

@ -0,0 +1,37 @@
# Helm Chart Unit Tests
This directory contains unit tests for our Helm charts using [helm-unittest](https://github.com/helm-unittest/helm-unittest), a BDD-style testing framework for Helm charts.
## Running Tests Locally
You can run the tests locally using Docker:
```bash
docker run -ti --rm -v $(pwd):/apps helmunittest/helm-unittest .
```
## Snapshot Testing
Our tests use snapshot testing to validate the rendered Kubernetes manifests. This ensures that any changes to the defaults are intentional and reviewed.
### Updating Snapshots
When making changes that affect the rendered output (like updating labels or other metadata), you'll need to update the snapshots. This is particularly important during releases when labels are updated.
To update snapshots, run the tests with the `-u` flag:
```bash
docker run -ti --rm -v $(pwd):/apps helmunittest/helm-unittest -u .
```
**Important**: Always review the changes in the snapshots before committing them to ensure they match your expectations.
## Documentation
For more information about helm-unittest, including:
- Writing test cases
- Available assertions
- Test suite configuration
- Best practices
Please refer to the [official helm-unittest documentation](https://github.com/helm-unittest/helm-unittest).

View File

@ -0,0 +1,210 @@
"":
1: |
raw: |
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace NAMESPACE -l "app.kubernetes.io/name=appsmith,app.kubernetes.io/instance=RELEASE-NAME" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace NAMESPACE $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace NAMESPACE port-forward $POD_NAME 8080:$CONTAINER_PORT
To expose your Appsmith service to be accessible from the Internet, please refer to our docs here https://docs.appsmith.com/getting-started/setup/installation-guides/kubernetes/publish-appsmith-online.
2: |
apiVersion: v1
data:
APPSMITH_DB_URL: |
mongodb+srv://root:password@appsmith-mongodb.NAMESPACE.svc.cluster.local/appsmith?retryWrites=true&authSource=admin&ssl=false
APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX: "false"
APPSMITH_KEYCLOAK_DB_DRIVER: postgresql
APPSMITH_KEYCLOAK_DB_PASSWORD: password
APPSMITH_KEYCLOAK_DB_URL: RELEASE-NAME-postgresql.NAMESPACE.svc.cluster.local:5432/keycloak
APPSMITH_KEYCLOAK_DB_USERNAME: root
APPSMITH_REDIS_URL: redis://RELEASE-NAME-redis-master.NAMESPACE.svc.cluster.local:6379
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: appsmith
appsmith.sh/chart: appsmith-3.6.2
name: RELEASE-NAME-appsmith
namespace: NAMESPACE
3: |
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: appsmith
appsmith.sh/chart: appsmith-3.6.2
name: RELEASE-NAME-appsmith
namespace: NAMESPACE
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/name: appsmith
serviceName: RELEASE-NAME-appsmith
template:
metadata:
labels:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/name: appsmith
spec:
containers:
- env:
- name: APPSMITH_ENABLE_EMBEDDED_DB
value: "0"
- name: JGROUPS_DISCOVERY_PROTOCOL
value: kubernetes.KUBE_PING
- name: APPSMITH_HEADLESS_SVC
value: RELEASE-NAME-appsmith-headless
envFrom:
- configMapRef:
name: RELEASE-NAME-appsmith
image: index.docker.io/appsmith/appsmith-ee:latest
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /api/v1/health
port: 80
periodSeconds: 60
name: appsmith
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 2019
name: metrics
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /api/v1/health
port: 80
periodSeconds: 60
resources:
limits: {}
requests:
cpu: 500m
memory: 3000Mi
securityContext: {}
startupProbe:
failureThreshold: 3
httpGet:
path: /api/v1/health
port: 80
periodSeconds: 60
volumeMounts:
- mountPath: /appsmith-stacks
name: data
initContainers:
- command:
- sh
- -c
- until redis-cli -h RELEASE-NAME-redis-master.NAMESPACE.svc.cluster.local ping ; do echo waiting for redis; sleep 2; done
image: docker.io/redis:7.0.15
name: redis-init-container
- command:
- sh
- -c
- until mongosh --host appsmith-mongodb.NAMESPACE.svc.cluster.local --eval 'db.runCommand({ping:1})' ; do echo waiting for mongo; sleep 2; done
image: docker.io/bitnami/mongodb:6.0.13
name: mongo-init-container
- command:
- sh
- -c
- until pg_isready -U $postgresuser -d $postgresdb -h RELEASE-NAME-postgresql.NAMESPACE.svc.cluster.local; do echo waiting for postgresql; sleep 2; done
image: docker.io/bitnami/postgresql:14.5.0-debian-11-r21
name: psql-init-container
securityContext: {}
serviceAccountName: RELEASE-NAME-appsmith
volumes: null
updateStrategy: null
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
4: |
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: appsmith
appsmith.sh/chart: appsmith-3.6.2
name: RELEASE-NAME-appsmith-headless
namespace: NAMESPACE
spec:
clusterIP: None
clusterIPs:
- None
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: http
port: 8080
targetPort: 8080
selector:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/name: appsmith
type: ClusterIP
5: |
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: RELEASE-NAME-appsmith-pdb
namespace: NAMESPACE
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/name: appsmith
6: |
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: appsmith
appsmith.sh/chart: appsmith-3.6.2
name: RELEASE-NAME-appsmith
namespace: NAMESPACE
spec:
ports:
- name: appsmith
nodePort: null
port: 80
targetPort: http
selector:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/name: appsmith
type: ClusterIP
7: |
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/instance: RELEASE-NAME
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: appsmith
appsmith.sh/chart: appsmith-3.6.2
name: RELEASE-NAME-appsmith
namespace: NAMESPACE
secrets:
- name: RELEASE-NAME-appsmith

View File

@ -0,0 +1,9 @@
# snapshot tests to capture expected changes to defaults
# exclude dependent charts from the snapshot
excludeTemplates:
- charts/*
tests:
- name: manifest should match snapshot from default values
asserts:
- matchSnapshot: {}

View File

@ -0,0 +1,27 @@
templates:
- deployment.yaml
tests:
- name: runAsUser should be 9999
set:
podSecurityContext:
sysctls:
- name: net.ipv4.ip_unprivileged_port_start
value: "80"
securityContext:
runAsNonRoot: true
runAsUser: 9999
asserts:
- equal:
path: spec.template.spec.containers[?(@.name == "appsmith")].securityContext
value:
runAsUser: 9999
runAsNonRoot: true
- equal:
path: spec.template.spec.securityContext
value:
sysctls:
- name: net.ipv4.ip_unprivileged_port_start
value: "80"
- equal:
path: spec.template.spec.containers[?(@.name == "appsmith")].env[?(@.name == "LD_PRELOAD")].value
value: "/usr/local/lib/libnss_wrapper.so"