Dynamic Helm Configuration with Python Scripts

Enhance Helm deployments with dynamic configuration by using sandboxed Python scripts

Helm services can compute values and valuesFiles at render time with a Python script, as an alternative or a complement to Lua scripts. The script mutates two pre-defined globals, and the deployment agent merges the result into the Helm release:

json
{
  "values": {
    "key": "value"
  },
  "valuesFiles": ["file1.yaml", "file2.yaml"]
}
yaml
apiVersion: deployments.plural.sh/v1alpha1
kind: ServiceDeployment
metadata:
  name: my-app
  namespace: infra
spec:
  namespace: my-app
  name: my-app
  cluster: k3s
  configuration:
    environment: prod
  helm:
    version: 1.x.x
    chart: my-app
    url: https://example.invalid/charts
    pythonScript: |
      env = configuration.get("environment", "dev")
      values["replicaCount"] = 3 if env == "prod" else 1
      valuesFiles.append(f"values-{env}.yaml")

The Python Runtime

Scripts are executed by Monty, a sandboxed Python interpreter written in Rust, embedded in the deployment agent through gomonty. It is not CPython: it implements a subset of Python 3.14 syntax and a small subset of the standard library, and it has no access to the host system.

The agent currently bundles gomonty v0.0.14, which pins Monty v0.0.9. Monty's upstream documentation tracks the latest Monty release, which supports more than the pinned version does (for example classes and str.format). Treat this page as the reference for what works in the agent.

Security Model

  • No filesystem access: open does not exist, and filesystem calls in os and pathlib raise NotImplementedError. Unlike Lua, Python scripts cannot read files from the service tarball. Use valuesFiles to have the agent load files on your behalf.
  • No environment or network access: os.getenv and os.environ raise NotImplementedError, and there is no socket, HTTP, or subprocess module.
  • No third-party packages: there is no sys.path or site-packages, so import yaml, import requests, and similar fail with ModuleNotFoundError. YAML support is provided by the yaml_encode and yaml_decode globals instead.
  • Limited host callbacks: the only way to reach the agent is k8s_object_meta, a read-only lookup against the agent's object cache. The YAML and merge helpers also run on the agent, but they only transform the data you pass them. warn is defined in the sandbox itself.
  • Fresh state on every render: each render gets a new interpreter. Nothing defined in one render, including functions and globals, is visible to the next.

Resource Limits

Limit
Value
Execution time10 seconds, including time spent waiting for a free interpreter
Memory100 MB
Recursion depth100 frames