Files
helm-charts/searxng/values.schema.json
jklein 46942db53a searxng: new chart (1.0.0+up2026.8.22.9fea41204)
SearXNG as a stateless Deployment plus a settings ConfigMap, with the four CI
steps a new chart needs: publish workflow, change-app-version choice list,
ci/searxng/ fixtures and a renovate.json5 block.

Three points where the chart is not a cyberchef with another name:

* The image entrypoint writes settings.yml into /etc/searxng only when the
  file is missing. The chart always mounts one by subPath, so the copy and
  the random-secret sed never run and the container needs no write access
  there - which is what allows readOnlyRootFilesystem: true.
* The signing key is a required OnePasswordItem, not a ConfigMap key. It
  signs the settings cookie and the image-proxy URLs, and the entrypoint's
  self-generating fallback cannot fire here, so without it the instance would
  run on the literal "ultrasecretkey" - which webapp.py refuses with exit 1.
* All three probes use /healthz, the only path the bot detection lets through
  unconditionally. Measured: with the limiter active, "/" answers 429 while
  /healthz still answers 200.

ingress.domain is read a second time outside the Ingress template, for
SEARXNG_BASE_URL, and carries its own required() there - so it stays
mandatory with the Ingress switched off.

The Renovate versioning regex deviates from the plan on the issue and matches
the commit hash WITHOUT capturing it. Renovate parses a "build" group with
Number.parseInt, so a hash becomes the digits leading it; measured on
renovate 41.173.1 and 44.48.0, the planned form reports an image pushed
earlier the same day as an update to a newer one. Reasoning in the block and
in README.
2026-08-27 21:09:59 +02:00

216 lines
8.2 KiB
JSON

{
"$schema": "https://json-schema.org/draft-07/schema#",
"title": "searxng values",
"description": "Values schema for the searxng chart (issue #68). additionalProperties is false on every chart-owned object level, so a key the chart does not read is rejected at render time instead of being silently ignored. Objects that go verbatim into the Kubernetes pod spec (probes, security contexts, global, free-form annotations) stay open, and so does settings.extra - its schema belongs to SearXNG, not to this chart. The schema ADDS to the required() calls in the templates, it does not replace them.",
"type": "object",
"additionalProperties": false,
"properties": {
"global": {
"description": "Helm's conventional cross-chart values. Unused by this chart, kept open so an umbrella install cannot break on it.",
"type": "object"
},
"scaleDown": {
"type": "boolean"
},
"secrets": {
"type": "object",
"additionalProperties": false,
"properties": {
"searxngSecretRef": {
"description": "op:// item path carrying a \"secret-key\" field. Required by the template - SearXNG exits 1 when server.secret_key is still the upstream placeholder.",
"type": ["string", "null"]
},
"valkeySecretRef": {
"description": "op:// item path carrying a \"valkey-url\" field for an external Valkey/Redis. Optional; only meaningful with settings.limiter: true.",
"type": ["string", "null"]
}
}
},
"settings": {
"description": "The chart-owned part of /etc/searxng/settings.yml. May be null / empty: the chart then falls back to its own defaults (issue #99) instead of rendering an instance with an empty name and no image proxy.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"instanceName": {
"description": "general.instance_name.",
"type": ["string", "null"]
},
"safeSearch": {
"description": "search.safe_search - 0 off, 1 moderate, 2 strict. Constrained because SearXNG accepts nothing else and a typo here would otherwise reach the app as a config error at start.",
"type": ["integer", "null"],
"enum": [0, 1, 2, null]
},
"autocomplete": {
"description": "search.autocomplete - the suggestion backend, or the empty string to disable suggestions. Not enumerated: the list of backends is upstream's and grows.",
"type": ["string", "null"]
},
"imageProxy": {
"description": "server.image_proxy.",
"type": ["boolean", "null"]
},
"limiter": {
"description": "server.limiter - the bot detection. Needs an external Valkey (secrets.valkeySecretRef) to do anything.",
"type": ["boolean", "null"]
},
"publicInstance": {
"description": "server.public_instance.",
"type": ["boolean", "null"]
},
"extra": {
"description": "Free-form SearXNG settings, merged over the block the keys above build and rendered verbatim into settings.yml. Deliberately open: the schema here is SearXNG's, and restricting it would only reject keys the upstream has not invented yet.",
"type": ["object", "null"]
}
}
},
"searxng": {
"type": "object",
"additionalProperties": false,
"properties": {
"replicas": {
"type": "integer",
"minimum": 0
},
"resources": {
"$ref": "#/definitions/resources"
},
"livenessProbe": {
"$ref": "#/definitions/probe"
},
"readinessProbe": {
"$ref": "#/definitions/probe"
},
"startupProbe": {
"$ref": "#/definitions/probe"
},
"securityContext": {
"$ref": "#/definitions/securityContext"
},
"env": {
"$ref": "#/definitions/env"
}
}
},
"ingress": {
"type": "object",
"additionalProperties": false,
"properties": {
"enabled": {
"description": "Gates the Ingress template only. ingress.domain is read a second time in the Deployment (SEARXNG_BASE_URL) and keeps its own required() there, so switching the Ingress off frees clusterIssuer but NOT domain.",
"type": "boolean"
},
"clusterIssuer": {
"type": ["string", "null"]
},
"domain": {
"type": ["string", "null"]
},
"className": {
"type": ["string", "null"]
},
"annotations": {
"description": "Extra Ingress annotations, merged with the cert-manager annotation the chart always sets. Free-form keys by nature, so this object stays open.",
"type": "object"
}
}
}
},
"definitions": {
"resources": {
"description": "May be null / empty: the chart then falls back to its default requests and computed limits (issue #99) instead of rendering a container without resource accounting.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"limitFactor": {
"type": "number",
"exclusiveMinimum": 0
},
"requests": {
"$ref": "#/definitions/resourceList"
},
"limits": {
"$ref": "#/definitions/resourceList"
}
}
},
"resourceList": {
"description": "Both spellings of the ephemeral-storage key are accepted because the resources helper normalizes camelCase to the Kubernetes key.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"cpu": {
"type": ["string", "number", "null"]
},
"memory": {
"type": ["string", "number", "null"]
},
"ephemeral-storage": {
"type": ["string", "number", "null"]
},
"ephemeralStorage": {
"type": ["string", "number", "null"]
}
}
},
"env": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"value": {
"type": "string"
},
"valueFrom": {
"type": "object",
"additionalProperties": false,
"properties": {
"secretKeyRef": {
"$ref": "#/definitions/keyRef"
},
"configMapKeyRef": {
"$ref": "#/definitions/keyRef"
}
}
}
}
}
},
"keyRef": {
"type": "object",
"additionalProperties": false,
"required": ["name", "key"],
"properties": {
"name": {
"type": "string"
},
"key": {
"type": "string"
}
}
},
"securityContext": {
"description": "May be null / empty at any level: the chart then falls back to its hardening defaults (issue #99) instead of rendering an unhardened workload. Those fallbacks reproduce THIS chart's uid/gid 977, not the repo's generic numbers.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"pod": {
"description": "Merged onto the chart's pod hardening defaults and rendered as the pod's securityContext; kept open because the chart does not interpret the individual fields.",
"type": ["object", "null"]
},
"container": {
"description": "Merged onto the chart's container hardening defaults and rendered as the container's securityContext; kept open because the chart does not interpret the individual fields.",
"type": ["object", "null"]
}
}
},
"probe": {
"description": "Merged onto the chart's probe defaults and rendered as a container probe; kept open because the chart does not interpret the individual fields. May be null / empty, which means the defaults apply (issue #99) rather than the probe disappearing. The chart's defaults carry the probe's context - the /healthz path and the \"http\" port name - not just its timings.",
"type": ["object", "null"]
}
}
}