Skip to content

fix(hosting): make the Helm chart deploy cleanly on a managed Kubernetes (GKE Autopilot) - #6690

Open
mmabrouk wants to merge 18 commits into
release/v0.115.4from
fix/helm-gke-readiness
Open

fix(hosting): make the Helm chart deploy cleanly on a managed Kubernetes (GKE Autopilot)#6690
mmabrouk wants to merge 18 commits into
release/v0.115.4from
fix/helm-gke-readiness

Conversation

@mmabrouk

@mmabrouk mmabrouk commented Sep 8, 2026

Copy link
Copy Markdown
Member

Why

We deployed the chart on GKE Autopilot with an external Cloud SQL and found a set of defects and missing knobs. Each one either broke the install outright or forced a manual step after every helm upgrade. All of them were found on a live cluster; none is theoretical.

What changed

Correctness fixes

  • secrets.existingSecret was ignored for AGENTA_RUNNER_TOKEN in the runner Deployment and in the helper that feeds api and services; those three pods failed on a missing Secret. New test covers it.
  • The web and mobile Deployments read the raw URL values, so an install that relied on ingress derivation gave them empty strings while every other workload got the derived URL. They now use the same effective helpers.
  • The runner never set AGENTA_RUNNER_HOST, bound 127.0.0.1, and failed its startup probe forever. It now binds 0.0.0.0 by default (agentRunner.host).
  • AGENTA_STORE_ENDPOINT_URL ignored store.endpointUrl when SeaweedFS was bundled. Daytona sandboxes need the public URL; the value now wins over the internal Service URL.
  • ingress.paths.webMobile was rendered but rejected by the schema. The schema and the helpers agree now.
  • spec.ingressClassName is rendered only when ingress.className is non-empty. The GKE controller ignores that field and reads only the legacy kubernetes.io/ingress.class annotation.
  • The ingress.tls validation message described a shape the schema rejects.

New operator knobs

  • <component>.service.annotations on the four Services (GKE BackendConfig and NEG annotations).
  • agentRunner.fuse.enabled to turn off the SYS_ADMIN capability and the /dev/fuse hostPath, which Autopilot rejects.
  • alembic.hookPhase: pre to run migrations before the pods start when the database is external.
  • ingress.extraPaths and ingress.extraHosts.
  • store.seaweedfs.ingress for a public store hostname.
  • <component>.extraEnv and <component>.envFrom on every workload.

Docs and tests

  • New hosting/kubernetes/README.md with the external-Postgres and managed-ingress deltas.
  • The example values files no longer list seven worker components the chart does not have, and their /api stripping comment matches the chart.
  • The web-mobile chart test was red on the release branch (missing internal services key), and pytest collected the chart tests while running none of them. Both fixed.

Chart version, appVersion and default ports are unchanged. A default render is byte for byte identical to the base except for the web URL fix.

How to verify

cd hosting/kubernetes/helm
helm lint . -f ../ee/values.ee.example.yaml --set agenta.authKey=a --set agenta.cryptKey=b --set agenta.servicesInternalKey=c --set agenta.runnerToken=d
python3 -m pytest -q tests

Live: the oss and staging stages on the GKE cluster in agenta-stage deploy from this branch.

https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8

Mahmoud Mabrouk added 18 commits September 8, 2026 21:44
The runner Deployment and the agenta.agentRunner.servicesEnv helper asked for
AGENTA_RUNNER_TOKEN from a Secret named by agenta.fullname. When the operator
sets secrets.existingSecret the chart creates no such Secret, so the runner, the
api and the services pods failed with CreateContainerConfigError.

Both places now go through agenta.secretName, which is what every other secret
reference in the chart already uses. An explicit agentRunner.auth.tokenSecretRef
still wins.

Adds tests/test_existing_secret.py. It renders with secrets.existingSecret and
checks that no pod spec references the chart-managed Secret name.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
web-deployment.yaml and web-mobile-deployment.yaml read agenta.webUrl,
agenta.apiUrl and agenta.servicesUrl straight from the values, with an empty
string as the fallback. Every other workload uses the agenta.webUrlEffective,
agenta.apiUrlEffective and agenta.servicesUrlEffective helpers, which fall back
to ingress.host.

An operator who relied on that derivation got empty URLs in the browser bundle,
which breaks OAuth redirects, links in email and any absolute URL the app builds.
Both templates now use the same helpers.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
The api, web, web-mobile and services Service templates had no way to carry
annotations. A managed ingress needs them: GKE reads cloud.google.com/neg and
cloud.google.com/backend-config off the Service.

Each template now renders <component>.service.annotations under
metadata.annotations when the map is not empty. The key is documented on the
shared component definition in values.schema.json.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
values.schema.json set additionalProperties:false on ingress.paths and listed
only api, services and web. ingress.yaml renders a fourth path from the
agenta.ingress.paths.webMobile helpers, so ingress.paths.webMobile was rejected
at install time. The two helpers also ignored the values and returned constants.

The schema now lists webMobile with the same shape as the other three, and the
helpers read it with the old constants as defaults. The path should stay /m
because the mobile image is built with that basePath. pathType is now
overridable, which a managed ingress can need.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
tests/test_web_mobile.py did not set agenta.servicesInternalKey, so every render
it made failed on agenta.validateRequiredSecrets and the test errored out. The
break predates this branch. Add the key to the shared render arguments.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
The public URL validation told the operator to write 'tls: true'. The schema
types ingress.tls as an array and ingress.yaml passes it through with toYaml, so
that advice fails schema validation. Show the list form instead, and say that any
non-empty list switches the derived URLs to https.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
With store.enabled=true the runner Deployment added the SYS_ADMIN capability and
a hostPath volume for /dev/fuse. GKE Autopilot rejects both, and the only way to
avoid them was to set agentRunner.securityContext, which also has to replace the
whole security context.

agentRunner.fuse.enabled now gates the capability and the volume together. It
defaults to true, so nothing changes for current users. An explicit
agentRunner.securityContext still wins, as before.

values.yaml tells Autopilot users to set it false and run sandboxes on the
Daytona provider.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
The migration Job is a post-install/post-upgrade hook because a pre-install hook
would deadlock on the bundled PostgreSQL StatefulSet, which does not exist yet at
that point. That reasoning does not hold with an external database, and there the
app pods start against an unmigrated schema for no reason.

alembic.hookPhase now picks the phase. It defaults to post, the behavior the
chart always had. Set it to pre with postgresql.enabled=false to render
pre-install,pre-upgrade. The delete policy stays before-hook-creation, and both
Secrets sit at hook weight -5, so they still land before the Job at weight 0.

A bad value is rejected by the schema, and by agenta.validateAlembicHookPhase
when schema validation is skipped.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
The Ingress only ever routed the four services the chart owns. An operator who
needs one more route on the same host, such as /llm in front of a gateway, had to
write a second Ingress by hand through extraObjects.

ingress.extraPaths appends items to the main host rule, after the built-in paths.
ingress.extraHosts adds whole rules, one per hostname, each with its own path
list. Both take the same item shape: path, pathType (default Prefix),
serviceName, servicePort. A numeric servicePort renders as port.number and a
string as port.name.

The Ingress used to render only when a chart component was enabled. It now also
renders for extra routes alone, and the main host rule is skipped when it would
have no paths.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
Three fixes to both hosting/kubernetes/oss/values.oss.example.yaml and
hosting/kubernetes/ee/values.ee.example.yaml.

Remove seven worker components no template reads: workerEvaluations,
workerTracing, workerWebhooks, workerEvents, workerRecords, workerTriggers and
workerInteractions. The chart has workerStreams and workerQueues, which the
examples never showed. Show those instead.

Correct the ingress comment. It said /api is prefix-stripped. The API is mounted
at /api through SCRIPT_NAME and the FastAPI root_path, so the prefix must reach
it; docker-compose says the same. Only /services is stripped, so /api is dropped
from the example StripPrefix Middleware.

Say that store.enabled defaults to false, and that an external store also needs
store.seaweedfs.enabled: false, which otherwise defaults to true and deploys a
StatefulSet nothing reads.

The audit named only the EE file. The OSS file carried the same three defects, so
both are fixed together.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
The chart tests are standalone scripts whose checks all live in main(), so
pytest collected the files, found no test function and reported success without
running anything. Each file now has a thin test function that calls main(). Both
entry points still work: uv run <file> and pytest tests/.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
hosting/kubernetes had no entry point. The chart is large and the keys a managed
cluster needs are spread across values.schema.json and the two example files.

The README says what the chart deploys, which values are required, and gives the
minimal delta for an external PostgreSQL and a managed ingress on GKE: the
external database block, alembic.hookPhase, the ingress class and annotations,
the per-component Service annotations, ingress.extraPaths and extraHosts,
agentRunner.fuse.enabled on Autopilot, and the object store toggles. It links to
docs/docs/self-host/deploy/03-deploy-to-kubernetes.mdx for the walkthrough.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
The store env block pointed AGENTA_STORE_ENDPOINT_URL at the in-cluster
SeaweedFS Service whenever the bundled store was enabled, and read
store.endpointUrl only when it was not. A Daytona sandbox runs outside the
cluster and cannot resolve that Service name, so the sandbox could not reach the
store at all.

An explicit store.endpointUrl now wins in both cases. The internal Service URL
stays the fallback when the key is unset, so a cluster-only deployment is
unchanged. Compose solves this the same way, with AGENTA_STORE_TRAEFIK_ENABLE
and AGENTA_STORE_DOMAIN.

The SeaweedFS pod is untouched: it never reads the endpoint URL. The runner
renders no store variables at all, so there was nothing to change there.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
The bundled SeaweedFS gateway was reachable only from inside the cluster. A
Daytona sandbox needs a hostname it can resolve, and the chart had no way to give
it one short of a hand-written Ingress in extraObjects.

store.seaweedfs.ingress renders one: enabled (false by default), className,
annotations, host and a tls list passed through verbatim. It routes / with
pathType Prefix to the SeaweedFS Service on its named s3 port, and it renders
only when the bundled SeaweedFS is deployed. host is required once enabled.

Pair it with store.endpointUrl set to the same hostname, so every pod hands out
the URL the sandbox can reach.

The SeaweedFS Service already exposed a named s3 port, so it needed no change.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
The runner binds 127.0.0.1 unless AGENTA_RUNNER_HOST says otherwise, and the
chart never set it. In a pod the kubelet connects over the pod IP, so the startup
probe on :8765/health got connection refused forever and the runner never became
ready. Confirmed on a live GKE cluster; the container logged
'http server listening on 127.0.0.1:8765'.

The runner Deployment now renders AGENTA_RUNNER_HOST from agentRunner.host,
default 0.0.0.0. Setting AGENTA_RUNNER_HOST in the agentRunner.env map suppresses
the chart's entry instead of adding a duplicate, which is how
AGENTA_RUNNER_REPLICA_ID and PI_CODING_AGENT_DIR already behave.

tests/test_runner_secret_absence.py now requires the variable, checks the value
is 0.0.0.0, checks both override paths, and checks it is never set twice.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
<component>.env takes plain strings only, so an operator could not point a
variable at a Secret key the chart does not model. The EE api needs
AGENTA_STARTER_CREDITS_BRIDGE_MASTER_KEY from the platform Secret, and there was
no way to ask for it.

Every workload now also takes extraEnv, a raw list of Kubernetes env entries
rendered with toYaml so valueFrom works, and envFrom, a raw list rendered on the
container. Both come after the chart's own variables, so a later entry wins.
Covered: api, services, web, webMobile, cron, workerStreams, workerQueues,
agentRunner, alembic and supertokens.

The runner carries a warning in the template and the schema. Its environment is
narrow on purpose, because a local harness shares the container and can read
/proc. envFrom pulls a whole Secret and defeats
tests/test_runner_secret_absence.py, which can only see named entries.

A render with no extraEnv or envFrom is byte for byte what it was before.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
Two corrections from a live GKE cluster.

GKE does not act on spec.ingressClassName. The controller reads the legacy
kubernetes.io/ingress.class annotation, and without it the Ingress gets no
controller events and never gets an IP. The chart always renders
ingressClassName, so the operator sets both.

Set the NEG annotation on each Service yourself. Autopilot adds it only when it
creates the Service, so a helm upgrade --force recreates Services without it.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
The Ingress always rendered spec.ingressClassName, defaulting to traefik. The GKE
controller ignores that field: an Ingress carrying className gce gets no
controller events and never gets an IP, even with an IngressClass object
present. It reacts only to the legacy kubernetes.io/ingress.class annotation, and
the chart gave the operator no way to leave the field out.

ingress.className: "" now renders no ingressClassName. The helper checks hasKey
instead of using default, which would turn an empty string back into traefik. An
unset key still means traefik, so nothing changes for current users, and a
default render is byte for byte what it was.

The README, the schema and both example files carry the GKE note.

Claude-Session: https://claude.ai/code/session_01GZqpvjwLHgVnMrpKH8hzq8
@vercel

vercel Bot commented Sep 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
agenta-documentation Ready Ready Preview Sep 8, 2026 8:10pm UTC

Request Review

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Mahmoud Mabrouk seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

📝 Summary

Summary by CodeRabbit

  • New Features

    • Added flexible environment configuration through Secrets and ConfigMaps across workloads.
    • Added configurable ingress hosts, paths, classes, TLS, service annotations, and optional object-store access.
    • Added runner host, replica, port, and FUSE settings.
    • Added configurable database migration timing and validation.
    • Added support for using an existing application Secret.
  • Bug Fixes

    • Improved default application URL handling and runner probe connectivity.
    • Corrected ingress prefix handling so API routes retain /api.
  • Documentation

    • Added comprehensive Kubernetes deployment guidance and updated example configurations.

Walkthrough

The Helm chart adds configurable environment injection, migration hook phases, runner networking and FUSE controls, ingress routes, SeaweedFS exposure, service annotations, existing-secret handling, URL fallback fixes, schemas, tests, and Kubernetes deployment documentation.

Changes

Kubernetes Helm deployment configuration

Layer / File(s) Summary
Chart contracts and validation
hosting/kubernetes/helm/_helpers.tpl, hosting/kubernetes/helm/templates/_validations.tpl, hosting/kubernetes/helm/values.schema.json
Adds schema and helper support for runner, Alembic, ingress, SeaweedFS, environment, and service configuration.
Workload runtime configuration
hosting/kubernetes/helm/templates/*-deployment.yaml, hosting/kubernetes/helm/templates/alembic-job.yaml, hosting/kubernetes/helm/tests/*
Adds extraEnv and envFrom support, existing-secret handling, configurable migration hooks, runner bind settings, FUSE controls, worker selectors, and regression tests.
Ingress and object-store exposure
hosting/kubernetes/helm/templates/ingress.yaml, hosting/kubernetes/helm/templates/seaweedfs-ingress.yaml, hosting/kubernetes/helm/templates/*-service.yaml
Adds extra ingress paths and hosts, optional SeaweedFS ingress, service annotations, configurable ingress classes, and external store endpoint precedence.
Operator documentation and examples
hosting/kubernetes/README.md, hosting/kubernetes/*/values.*.yaml, hosting/kubernetes/helm/values.yaml
Documents database, ingress, storage, runner, environment, worker, and validation configuration.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🟡 Moderate · up to 8986b

Several valid chart configurations can fail installation or break runner operation, while configuration guidance can produce ineffective overrides. These issues should be corrected before merge.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: improving Helm chart deployment on managed Kubernetes, specifically GKE Autopilot.
Description check ✅ Passed The description directly explains the Helm chart fixes, new operator configuration, documentation, tests, and GKE Autopilot deployment objective.
Docstring Coverage ✅ Passed Docstring coverage is 66.67% which is sufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 3 files. (24 skipped: 2…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/helm-gke-readiness

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: 8a1bc4a9-d957-47dc-9653-083e140d21ea

📥 Commits

Reviewing files that changed from the base of the PR and between 0c85a59 and 8986b5c.

📒 Files selected for processing (27)
  • hosting/kubernetes/README.md
  • hosting/kubernetes/ee/values.ee.example.yaml
  • hosting/kubernetes/helm/templates/_helpers.tpl
  • hosting/kubernetes/helm/templates/_validations.tpl
  • hosting/kubernetes/helm/templates/alembic-job.yaml
  • hosting/kubernetes/helm/templates/api-deployment.yaml
  • hosting/kubernetes/helm/templates/api-service.yaml
  • hosting/kubernetes/helm/templates/cron-deployment.yaml
  • hosting/kubernetes/helm/templates/ingress.yaml
  • hosting/kubernetes/helm/templates/runner-deployment.yaml
  • hosting/kubernetes/helm/templates/seaweedfs-ingress.yaml
  • hosting/kubernetes/helm/templates/secrets.yaml
  • hosting/kubernetes/helm/templates/services-deployment.yaml
  • hosting/kubernetes/helm/templates/services-service.yaml
  • hosting/kubernetes/helm/templates/supertokens-deployment.yaml
  • hosting/kubernetes/helm/templates/web-deployment.yaml
  • hosting/kubernetes/helm/templates/web-mobile-deployment.yaml
  • hosting/kubernetes/helm/templates/web-mobile-service.yaml
  • hosting/kubernetes/helm/templates/web-service.yaml
  • hosting/kubernetes/helm/templates/worker-queues-deployment.yaml
  • hosting/kubernetes/helm/templates/worker-streams-deployment.yaml
  • hosting/kubernetes/helm/tests/test_existing_secret.py
  • hosting/kubernetes/helm/tests/test_runner_secret_absence.py
  • hosting/kubernetes/helm/tests/test_web_mobile.py
  • hosting/kubernetes/helm/values.schema.json
  • hosting/kubernetes/helm/values.yaml
  • hosting/kubernetes/oss/values.oss.example.yaml

Included review availability: Your plan provides up to 8 included reviews per hour; 1 remains after this review.

Comment on lines +91 to +94
{{- with $api.envFrom }}
envFrom:
{{- toYaml . | nindent 12 }}
{{- end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the envFrom precedence comments

Kubernetes gives duplicate names in explicit env entries precedence over envFrom, regardless of template order. Update the comments in api-deployment.yaml, alembic-job.yaml, cron-deployment.yaml, services-deployment.yaml, supertokens-deployment.yaml, web-deployment.yaml, worker-queues-deployment.yaml, worker-streams-deployment.yaml, and web-mobile-deployment.yaml to state that envFrom supplies only names absent from env. Otherwise, an operator-supplied Secret or ConfigMap retains the chart-generated value for colliding names. Keep extraEnv as the override mechanism because it emits explicit env entries and supports valueFrom.

Comment on lines +87 to +88
{{- range .paths }}
{{- include "agenta.ingress.extraPath" . | nindent 10 }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🔎 Supported by static analysis

🤖 get_repo_knowledge executed:

get_repo_knowledge Agenta-AI/agenta /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/learnings /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/conventions

Length of output: 43621


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- changed hunk ---'
git diff -- hosting/kubernetes/helm/templates/ingress.yaml hosting/kubernetes/helm/values.schema.json
printf '%s\n' '--- ingress template ---'
cat -n hosting/kubernetes/helm/templates/ingress.yaml | sed -n '1,130p'
printf '%s\n' '--- schema ingress section ---'
rg -n -A80 -B20 '"extraHosts"|"paths"|"extraPath"' hosting/kubernetes/helm/values.schema.json
printf '%s\n' '--- values references ---'
rg -n -A30 -B10 'extraHosts|extraPath' hosting/kubernetes/helm

Repository: Agenta-AI/agenta

Length of output: 26846


🌐 Web query:

site:kubernetes.io Ingress networking.k8s.io/v1 HTTPIngressRuleValue paths minItems 1 validation

💡 Result:

In the Kubernetes networking.k8s.io/v1 Ingress API, the paths field within an HTTPIngressRuleValue is an array of HTTPIngressPath objects [1]. This array is required to contain at least one element [1]. Validation for this requirement is enforced by the Kubernetes API server [2]. While the specific minItems validation tag may not always be explicitly exposed in high-level documentation summaries, the API schema mandates that an Ingress rule must define paths to map requests to backends [1]. If a rule is provided without any paths, the Ingress object will fail validation upon submission because the list is empty, which violates the structural requirements of the HTTPIngressRuleValue type [1]. In practice, if you attempt to create an Ingress resource with an empty paths list, the Kubernetes API server will reject the request with a validation error [2][3]. Users should ensure that every http block within an Ingress rule includes at least one path entry along with its associated pathType and backend [1][4][5].

Citations:


Reject empty extraHosts[].paths.

The schema permits paths: [], but the template renders an Ingress rule with an empty http.paths list. Kubernetes rejects this rule. Add minItems: 1 to hosting/kubernetes/helm/values.schema.json, or reject the empty array before rendering.

{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and (eq (include "agenta.store.enabled" .) "true") (not $runner.securityContext) }}
{{- if and (eq (include "agenta.store.enabled" .) "true") (eq (include "agenta.agentRunner.fuse.enabled" .) "true") (not $runner.securityContext) }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Render the /dev/fuse mount independently of runner.securityContext.

When store.enabled and agentRunner.fuse.enabled are true, a custom runner.securityContext suppresses both the /dev/fuse mount and the SYS_ADMIN default. The custom context is the capability override, while agentRunner.fuse.enabled controls FUSE support for local geesefs sandboxes. Remove (not $runner.securityContext) from both volume conditions so a custom context that grants the required capability does not break local sandbox operation.

Comment on lines +28 to +31
{{- with $ingress.tls }}
tls:
{{- toYaml . | nindent 4 }}
{{- end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🛡️ Analyzed with Security Review | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🤖 get_repo_knowledge executed:

get_repo_knowledge Agenta-AI/agenta /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/learnings /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/conventions

Length of output: 5732


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- ingress template ---'
cat -n hosting/kubernetes/helm/templates/seaweedfs-ingress.yaml
printf '%s\n' '--- relevant values ---'
rg -n -C 8 'seaweedfs|endpointUrl|tls:' hosting/kubernetes/helm/values.yaml
printf '%s\n' '--- endpointUrl and ingress references ---'
rg -n -C 4 'endpointUrl|seaweedfs\.ingress|ingress\.tls' hosting/kubernetes/helm --glob '!values.schema.json'

Repository: Agenta-AI/agenta

Length of output: 13316


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- store schema and credentials ---'
sed -n '210,330p' hosting/kubernetes/helm/values.schema.json
sed -n '930,980p' hosting/kubernetes/helm/templates/_helpers.tpl
printf '%s\n' '--- store endpoint and credential consumers ---'
rg -n -C 5 'AGENTA_STORE_(ACCESS|SECRET|ENDPOINT)|accessKey|secretKey|endpointUrl' hosting/kubernetes/helm/templates hosting/kubernetes/helm/values.schema.json

Repository: Agenta-AI/agenta

Length of output: 50372


Security Misconfiguration

Reachability: External
Exploitability: Moderate
CWE: CWE-319 — Cleartext Transmission of Sensitive Information

Require HTTPS for the public SeaweedFS route.

When store.seaweedfs.ingress.enabled is true and tls is omitted, the Ingress exposes the S3 gateway without spec.tls. Reject HTTP store.endpointUrl values or require TLS for this route. Update hosting/kubernetes/helm/values.yaml to show an HTTPS endpoint and matching tls configuration.

"type": "object",
"additionalProperties": false,
"description": "Optional public route to the bundled S3 gateway, for clients outside the cluster such as a Daytona sandbox. Set store.endpointUrl to the same hostname so every pod hands out that URL.",
"required": ["host"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Make host conditional on enabled for the SeaweedFS ingress.

"required": ["host"] applies whenever the store.seaweedfs.ingress object exists. The description says host is "Required when enabled", but the schema does not express that condition. An operator who only turns the route off, for example --set store.seaweedfs.seaweedfs.ingress.enabled=false or --set store.seaweedfs.ingress.enabled=false, gets a schema validation failure asking for a host they do not need.

Use if/then so the requirement applies only when enabled is true.

🔧 Proposed schema fix
               "additionalProperties": false,
               "description": "Optional public route to the bundled S3 gateway, for clients outside the cluster such as a Daytona sandbox. Set store.endpointUrl to the same hostname so every pod hands out that URL.",
-              "required": ["host"],
+              "if": { "properties": { "enabled": { "const": true } }, "required": ["enabled"] },
+              "then": { "required": ["host"] },
               "properties": {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"required": ["host"],
"if": { "properties": { "enabled": { "const": true } }, "required": ["enabled"] },
"then": { "required": ["host"] },

Comment on lines +483 to +484
# The chart has two worker deployments. `streams` and `queues` are selector
# lists; an empty list means every loop of that kind.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Worker selector documented as a list in both example values files. The chart renders AGENTA_WORKER_STREAMS and AGENTA_WORKER_QUEUES from a single string (default "" $workerStreams.streams | quote), but both comments call streams and queues "selector lists" and say an empty list runs every loop. An operator who sets streams: [] renders the literal "[]".

  • hosting/kubernetes/oss/values.oss.example.yaml#L483-L484: describe streams and queues as comma-separated strings, and say an empty string means every loop of that kind.
  • hosting/kubernetes/ee/values.ee.example.yaml#L486-L487: apply the same wording change so both examples match the template contract.
📍 Affects 2 files
  • hosting/kubernetes/oss/values.oss.example.yaml#L483-L484 (this comment)
  • hosting/kubernetes/ee/values.ee.example.yaml#L486-L487

Comment on lines +85 to +87
Nothing constrains the keys under `postgresql`, so `helm install` accepts a
misspelled one and falls back to the default. Render the chart and read the
`POSTGRES_URI_CORE` value back before you install.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Correct the schema-validation claims.

The chart schema sets additionalProperties: true at both the root and postgresql levels. Helm accepts unknown or misspelled keys, and templates read only declared keys, so the default remains active. Update lines 11 and 279-280 to describe validation of declared fields, and keep the warning at lines 85-87.

@mmabrouk

mmabrouk commented Sep 8, 2026

Copy link
Copy Markdown
Member Author

The failing check "Application Web Unit Test Results" is pre-existing on release/v0.115.4: the same job failed on the last three runs of that branch (commits 0c85a59, b6b1cc1, 59dbca8) before this PR. This PR touches only hosting/kubernetes/.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants