diff --git a/.github/workflows/helm-test.yaml b/.github/workflows/helm-test.yaml index d091fed4..1bfc4a03 100644 --- a/.github/workflows/helm-test.yaml +++ b/.github/workflows/helm-test.yaml @@ -18,8 +18,28 @@ on: pull_request: paths: - 'charts/**' + - 'mise.toml' + - '.github/workflows/helm-test.yaml' jobs: + helm-schema: + name: Schema + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup mise tools + uses: jdx/mise-action@v4 + with: + install: true + install_args: "helm" + experimental: true + + - name: Verify Helm Values Schema + run: | + mise run nauth:check-values-schema + helm-test: name: Test runs-on: ubuntu-latest @@ -27,8 +47,16 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - - name: Setup Helm - uses: azure/setup-helm@v5 + - name: Setup mise tools + uses: jdx/mise-action@v4 + with: + install: true + install_args: "helm" + experimental: true + + - name: Run Helm Lint + run: | + helm lint charts/nauth - name: Setup Helm Unittest # TODO: re-add verification when https://github.com/helm-unittest/helm-unittest/issues/777 is resolved diff --git a/charts/nauth/.schema.yaml b/charts/nauth/.schema.yaml new file mode 100644 index 00000000..f4df2d82 --- /dev/null +++ b/charts/nauth/.schema.yaml @@ -0,0 +1,14 @@ +# yaml-language-server: $schema=https://github.com/losisin/helm-values-schema-json/raw/refs/heads/main/config.schema.json +values: + - values.yaml + +draft: 7 +indent: 2 +output: values.schema.json +useHelmDocs: true +noDefaultGlobal: true + +schemaRoot: + title: NAuth Helm chart values + description: Schema for NAuth Helm chart values. + additionalProperties: false diff --git a/charts/nauth/templates/verify.yaml b/charts/nauth/templates/verify.yaml deleted file mode 100644 index c0293e3a..00000000 --- a/charts/nauth/templates/verify.yaml +++ /dev/null @@ -1,6 +0,0 @@ -{{- if and .Values.logging.format (not (mustHas .Values.logging.format (list "text" "json"))) }} -{{- fail "logging.format must be empty, text, or json" }} -{{- end }} -{{- if and .Values.logging.level (not (mustHas .Values.logging.level (list "debug" "info" "warn" "error"))) }} -{{- fail "logging.level must be empty, debug, info, warn, or error" }} -{{- end }} diff --git a/charts/nauth/tests/verify_test.yaml b/charts/nauth/tests/verify_test.yaml deleted file mode 100644 index 7154d187..00000000 --- a/charts/nauth/tests/verify_test.yaml +++ /dev/null @@ -1,19 +0,0 @@ -suite: values validation -templates: - - verify.yaml -tests: - - it: rejects invalid logging format - set: - logging: - format: console - asserts: - - failedTemplate: - errorMessage: logging.format must be empty, text, or json - - - it: rejects invalid logging level - set: - logging: - level: trace - asserts: - - failedTemplate: - errorMessage: logging.level must be empty, debug, info, warn, or error diff --git a/charts/nauth/values.schema.json b/charts/nauth/values.schema.json new file mode 100644 index 00000000..73682e5b --- /dev/null +++ b/charts/nauth/values.schema.json @@ -0,0 +1,309 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "NAuth Helm chart values", + "description": "Schema for NAuth Helm chart values.", + "type": "object", + "properties": { + "affinity": { + "description": "Affinity rules for scheduling the NAuth operator Pod.", + "type": [ + "object", + "null" + ] + }, + "crds": { + "type": "object", + "properties": { + "install": { + "description": "Install and upgrade NAuth CustomResourceDefinitions as part of this chart release.", + "type": "boolean" + }, + "keep": { + "description": "Keep NAuth CustomResourceDefinitions when this chart release is uninstalled.", + "type": "boolean" + } + }, + "additionalProperties": false + }, + "extraResources": { + "description": "Additional Kubernetes resources to render with the chart. Values are templated before rendering.", + "type": [ + "array", + "null" + ], + "items": { + "type": "object" + } + }, + "fullnameOverride": { + "description": "Override the full generated resource name. Defaults to `\u003cRelease.Name\u003e-\u003cChart.Name\u003e`.", + "type": "string" + }, + "global": { + "type": "object", + "properties": { + "labels": { + "description": "Additional labels to add to templated NAuth chart resources.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": true + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "description": "Kubernetes image pull policy for the NAuth operator container.", + "type": "string", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + }, + "registry": { + "description": "Container image registry for the NAuth operator.", + "type": "string" + }, + "repository": { + "description": "Container image repository for the NAuth operator.", + "type": "string" + }, + "tag": { + "description": "Override the container image tag. Defaults to the chart app version when empty.", + "type": "string" + } + }, + "additionalProperties": false + }, + "livenessProbe": { + "description": "Liveness probe for the NAuth operator container.", + "type": [ + "object", + "null" + ] + }, + "logging": { + "type": "object", + "properties": { + "format": { + "description": "Operator log output format. Leave empty to use the operator default. Set to `json` for structured log ingestion. Supported values: `text`, `json`.", + "type": "string", + "enum": [ + "", + "text", + "json" + ] + }, + "level": { + "description": "Operator log level. Supported values: `debug`, `info`, `warn`, `error`.", + "type": "string", + "enum": [ + "", + "debug", + "info", + "warn", + "error" + ] + } + }, + "additionalProperties": false + }, + "monitoring": { + "type": "object", + "properties": { + "enabled": { + "description": "Expose controller-runtime Prometheus metrics on `/metrics` for direct scraping or collection through a Prometheus receiver.", + "type": "boolean" + }, + "serviceMonitor": { + "type": "object", + "properties": { + "enabled": { + "description": "Create Prometheus Operator ServiceMonitor and PrometheusRule resources. Requires the ServiceMonitor and PrometheusRule CRDs.", + "type": "boolean" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "nameOverride": { + "description": "Override the chart name used in generated resource names.", + "type": "string" + }, + "namespace": { + "type": "object", + "properties": { + "nameOverride": { + "description": "Override the namespace rendered into namespaced resources. Defaults to the Helm release namespace.", + "type": "string" + } + }, + "additionalProperties": false + }, + "namespaced": { + "description": "Limit the operator to the configured namespace instead of watching all namespaces.", + "type": "boolean" + }, + "nats": { + "type": "object", + "properties": { + "clusterRef": { + "description": "Operator-level NatsCluster reference. Set `name` to bind the operator to one NATS cluster.", + "type": "object", + "properties": { + "name": { + "description": "NatsCluster resource name. Leave empty to disable operator-level binding.", + "type": "string" + }, + "namespace": { + "description": "NatsCluster resource namespace. When empty and `name` is set, the chart namespace is used.", + "type": "string" + }, + "optional": { + "description": "Whether account-level `spec.natsClusterRef` values may override this operator-level cluster.", + "type": "boolean" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "nodeSelector": { + "description": "Node selector for scheduling the NAuth operator Pod.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "podAnnotations": { + "description": "Annotations to add to the NAuth operator Pod.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "podLabels": { + "description": "Reserved value for labels on the NAuth operator Pod. This value is not currently rendered by the chart.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "podSecurityContext": { + "description": "Pod security context for the NAuth operator Pod.", + "type": [ + "object", + "null" + ] + }, + "readinessProbe": { + "description": "Readiness probe for the NAuth operator container.", + "type": [ + "object", + "null" + ] + }, + "replicaCount": { + "description": "Number of NAuth operator replicas.", + "type": "integer", + "minimum": 0 + }, + "resources": { + "description": "Resource requests and limits for the NAuth operator container.", + "type": [ + "object", + "null" + ] + }, + "securityContext": { + "description": "Container security context for the NAuth operator container.", + "type": [ + "object", + "null" + ] + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations to add to the ServiceAccount.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "automount": { + "description": "Reserved value for ServiceAccount token automounting. This value is not currently rendered by the chart.", + "type": "boolean" + }, + "create": { + "description": "Create a ServiceAccount for the NAuth operator.", + "type": "boolean" + }, + "nameOverride": { + "description": "Override the ServiceAccount name. Defaults to the generated full name when empty.", + "type": "string" + } + }, + "additionalProperties": false + }, + "terminationGracePeriodSeconds": { + "description": "Termination grace period for the NAuth operator Pod, in seconds.", + "type": "integer", + "minimum": 0 + }, + "tolerations": { + "description": "Tolerations for scheduling the NAuth operator Pod.", + "type": [ + "array", + "null" + ], + "items": { + "type": "object" + } + }, + "volumeMounts": { + "description": "Additional volume mounts for the NAuth operator container.", + "type": [ + "array", + "null" + ], + "items": { + "type": "object" + } + }, + "volumes": { + "description": "Additional volumes for the NAuth operator Pod.", + "type": [ + "array", + "null" + ], + "items": { + "type": "object" + } + } + }, + "additionalProperties": false +} diff --git a/charts/nauth/values.yaml b/charts/nauth/values.yaml index 249b3d0d..6bb72d5b 100644 --- a/charts/nauth/values.yaml +++ b/charts/nauth/values.yaml @@ -2,12 +2,15 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. +# @schema additionalProperties: true global: + # @schema type: [object, null]; additionalProperties: {type: string} # -- Additional labels to add to templated NAuth chart resources. labels: {} # custom.label.environment: dev # custom.label.team: team-potato +# @schema additionalProperties: false nats: # To move from one operator-level NatsCluster binding to explicit per-Account # bindings, first set this reference in strict mode, then add matching @@ -16,6 +19,7 @@ nats: # # With `optional=false`, account-level refs must either be unset or match this cluster. # With `optional=true`, accounts without `spec.natsClusterRef` use this cluster, and accounts may override it. + # @schema additionalProperties: false # -- Operator-level NatsCluster reference. Set `name` to bind the operator to one NATS cluster. clusterRef: # -- NatsCluster resource name. Leave empty to disable operator-level binding. @@ -27,14 +31,17 @@ nats: # -- Whether account-level `spec.natsClusterRef` values may override this operator-level cluster. optional: false +# @schema minimum: 0 # -- Number of NAuth operator replicas. replicaCount: 1 +# @schema additionalProperties: false image: # -- Container image registry for the NAuth operator. registry: ghcr.io/wirelesscar # -- Container image repository for the NAuth operator. repository: nauth-operator + # @schema enum: [Always, IfNotPresent, Never] # -- Kubernetes image pull policy for the NAuth operator container. pullPolicy: IfNotPresent # -- Override the container image tag. Defaults to the chart app version when empty. @@ -47,6 +54,7 @@ nameOverride: "" # -- Override the full generated resource name. Defaults to `-`. fullnameOverride: "" +# @schema additionalProperties: false namespace: # -- Override the namespace rendered into namespaced resources. Defaults to the Helm release namespace. nameOverride: "" @@ -54,35 +62,44 @@ namespace: # -- Limit the operator to the configured namespace instead of watching all namespaces. namespaced: false +# @schema additionalProperties: false logging: + # @schema enum: ["", text, json] # -- Operator log output format. Leave empty to use the operator default. Set to `json` for structured log ingestion. Supported values: `text`, `json`. format: "" + # @schema enum: ["", debug, info, warn, error] # -- Operator log level. Supported values: `debug`, `info`, `warn`, `error`. level: "" +# @schema additionalProperties: false serviceAccount: # -- Create a ServiceAccount for the NAuth operator. create: true # TODO(#345): Decide whether to render this value or remove it from the public values API. # -- Reserved value for ServiceAccount token automounting. This value is not currently rendered by the chart. automount: true + # @schema type: [object, null]; additionalProperties: {type: string} # -- Annotations to add to the ServiceAccount. annotations: {} # -- Override the ServiceAccount name. Defaults to the generated full name when empty. nameOverride: "" +# @schema type: [object, null]; additionalProperties: {type: string} # -- Annotations to add to the NAuth operator Pod. podAnnotations: {} # TODO(#345): Decide whether to render this value or remove it from the public values API. +# @schema type: [object, null]; additionalProperties: {type: string} # -- Reserved value for labels on the NAuth operator Pod. This value is not currently rendered by the chart. podLabels: {} +# @schema type: [object, null]; skipProperties: true # -- Pod security context for the NAuth operator Pod. podSecurityContext: runAsNonRoot: true # fsGroup: 2000 +# @schema type: [object, null]; skipProperties: true # -- Container security context for the NAuth operator container. securityContext: # This is defined by the distroless nonroot user @@ -96,13 +113,16 @@ securityContext: seccompProfile: type: RuntimeDefault +# @schema additionalProperties: false monitoring: # -- Expose controller-runtime Prometheus metrics on `/metrics` for direct scraping or collection through a Prometheus receiver. enabled: false + # @schema additionalProperties: false serviceMonitor: # -- Create Prometheus Operator ServiceMonitor and PrometheusRule resources. Requires the ServiceMonitor and PrometheusRule CRDs. enabled: false +# @schema type: [object, null]; skipProperties: true # -- Resource requests and limits for the NAuth operator container. resources: {} # limits: @@ -112,6 +132,7 @@ resources: {} # cpu: 100m # memory: 128Mi +# @schema type: [object, null]; skipProperties: true # -- Liveness probe for the NAuth operator container. livenessProbe: httpGet: @@ -120,6 +141,7 @@ livenessProbe: initialDelaySeconds: 15 periodSeconds: 20 +# @schema type: [object, null]; skipProperties: true # -- Readiness probe for the NAuth operator container. readinessProbe: httpGet: @@ -128,29 +150,37 @@ readinessProbe: initialDelaySeconds: 5 periodSeconds: 10 +# @schema type: [array, null]; item: object # -- Additional volumes for the NAuth operator Pod. volumes: [] +# @schema type: [array, null]; item: object # -- Additional volume mounts for the NAuth operator container. volumeMounts: [] +# @schema minimum: 0 # -- Termination grace period for the NAuth operator Pod, in seconds. terminationGracePeriodSeconds: 10 +# @schema type: [object, null]; additionalProperties: {type: string} # -- Node selector for scheduling the NAuth operator Pod. nodeSelector: {} +# @schema type: [array, null]; item: object # -- Tolerations for scheduling the NAuth operator Pod. tolerations: [] +# @schema type: [object, null]; skipProperties: true # -- Affinity rules for scheduling the NAuth operator Pod. affinity: {} +# @schema additionalProperties: false crds: # -- Install and upgrade NAuth CustomResourceDefinitions as part of this chart release. install: true # -- Keep NAuth CustomResourceDefinitions when this chart release is uninstalled. keep: true +# @schema type: [array, null]; item: object # -- Additional Kubernetes resources to render with the chart. Values are templated before rendering. extraResources: [] diff --git a/mise.toml b/mise.toml index 6092f770..a21407df 100644 --- a/mise.toml +++ b/mise.toml @@ -4,6 +4,7 @@ NATS_VERSION = "2.14.0-alpine" NACK_VERSION = "0.23.0" NATS_RELOADER_VERSION = "0.23.0" NATS_BOX_VERSION = "0.19.5" +HELM_VALUES_SCHEMA_JSON_VERSION = "v2.5.0" [tools] go = "1.26.3" @@ -36,6 +37,34 @@ description = "Lint public documentation with Vale" alias = "nld" run = "vale README.md www/src/content/docs/index.mdx www/src/content/docs/guides" +[tasks."nauth:generate-values-schema"] +description = "Generate Helm values schema from charts/nauth/values.yaml" +run = """ +if ! helm plugin list | awk 'NR > 1 { print $1 }' | grep -qx schema; then + helm plugin install https://github.com/losisin/helm-values-schema-json.git --version="${HELM_VALUES_SCHEMA_JSON_VERSION}" --verify=false +fi + +expected_version="helm schema version ${HELM_VALUES_SCHEMA_JSON_VERSION}" +actual_version="$(helm schema version)" +if [ "${actual_version}" != "${expected_version}" ]; then + echo "helm-values-schema-json ${HELM_VALUES_SCHEMA_JSON_VERSION} is required, got: ${actual_version}" >&2 + echo "Run: helm plugin install https://github.com/losisin/helm-values-schema-json.git --version=${HELM_VALUES_SCHEMA_JSON_VERSION} --verify=false" >&2 + exit 1 +fi + +cd charts/nauth +helm schema lint --strict +helm schema +""" + +[tasks."nauth:check-values-schema"] +description = "Verify generated Helm values schema is up to date" +run = """ +mise run nauth:generate-values-schema +git ls-files --error-unmatch charts/nauth/values.schema.json >/dev/null 2>&1 +git diff --exit-code -- charts/nauth/values.schema.json +""" + [tasks."nauth:e2e-test"] silent = false description = "Run end-to-end tests"