Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions .github/workflows/preview-helm-charts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
image-loader: ${{ steps.changes.outputs.image-loader }}
automation: ${{ steps.changes.outputs.automation }}
plugin-directory: ${{ steps.changes.outputs.plugin-directory }}
integrations-hub: ${{ steps.changes.outputs.integrations-hub }}
openhands: ${{ steps.changes.outputs.openhands }}
openhands-secrets: ${{ steps.changes.outputs.openhands-secrets }}
steps:
Expand All @@ -39,7 +40,7 @@ jobs:
echo "$CHANGED_FILES"

# Check each chart for changes
for chart in crd-check runtime-api image-loader automation plugin-directory openhands openhands-secrets; do
for chart in crd-check runtime-api image-loader automation plugin-directory integrations-hub openhands openhands-secrets; do
if echo "$CHANGED_FILES" | grep -q "^charts/${chart}/"; then
echo "${chart}=true" >> $GITHUB_OUTPUT
echo "Changes detected in charts/${chart}"
Expand All @@ -62,13 +63,15 @@ jobs:
matrix:
chart:
# Order matters! Charts that are dependencies must be published first.
# crd-check, automation, plugin-directory, and runtime-api are dependencies of openhands.
# crd-check, automation, plugin-directory, integrations-hub, and runtime-api are dependencies of openhands.
- name: crd-check
path: charts/crd-check
- name: automation
path: charts/automation
- name: plugin-directory
path: charts/plugin-directory
- name: integrations-hub
path: charts/integrations-hub
- name: runtime-api
path: charts/runtime-api
- name: image-loader
Expand All @@ -88,13 +91,15 @@ jobs:
HAS_CHANGES_IMAGE_LOADER: ${{ needs.detect-changes.outputs.image-loader }}
HAS_CHANGES_AUTOMATION: ${{ needs.detect-changes.outputs.automation }}
HAS_CHANGES_PLUGIN_DIRECTORY: ${{ needs.detect-changes.outputs.plugin-directory }}
HAS_CHANGES_INTEGRATIONS_HUB: ${{ needs.detect-changes.outputs.integrations-hub }}
HAS_CHANGES_OPENHANDS: ${{ needs.detect-changes.outputs.openhands }}
HAS_CHANGES_OPENHANDS_SECRETS: ${{ needs.detect-changes.outputs.openhands-secrets }}
IS_PUBLISHABLE_CRD_CHECK: ${{ needs.validate-chart-versions.outputs.crd-check-publishable }}
IS_PUBLISHABLE_RUNTIME_API: ${{ needs.validate-chart-versions.outputs.runtime-api-publishable }}
IS_PUBLISHABLE_IMAGE_LOADER: ${{ needs.validate-chart-versions.outputs.image-loader-publishable }}
IS_PUBLISHABLE_AUTOMATION: ${{ needs.validate-chart-versions.outputs.automation-publishable }}
IS_PUBLISHABLE_PLUGIN_DIRECTORY: ${{ needs.validate-chart-versions.outputs.plugin-directory-publishable }}
IS_PUBLISHABLE_INTEGRATIONS_HUB: ${{ needs.validate-chart-versions.outputs.integrations-hub-publishable }}
IS_PUBLISHABLE_OPENHANDS: ${{ needs.validate-chart-versions.outputs.openhands-publishable }}
IS_PUBLISHABLE_OPENHANDS_SECRETS: ${{ needs.validate-chart-versions.outputs.openhands-secrets-publishable }}
run: |
Expand All @@ -120,6 +125,10 @@ jobs:
HAS_CHANGES="$HAS_CHANGES_PLUGIN_DIRECTORY"
IS_PUBLISHABLE="$IS_PUBLISHABLE_PLUGIN_DIRECTORY"
;;
integrations-hub)
HAS_CHANGES="$HAS_CHANGES_INTEGRATIONS_HUB"
IS_PUBLISHABLE="$IS_PUBLISHABLE_INTEGRATIONS_HUB"
;;
openhands)
HAS_CHANGES="$HAS_CHANGES_OPENHANDS"
IS_PUBLISHABLE="$IS_PUBLISHABLE_OPENHANDS"
Expand Down Expand Up @@ -203,6 +212,14 @@ jobs:

yq -i "(.dependencies[] | select(.name == \"plugin-directory\")).version = \"${PLUGIN_DIRECTORY_PREVIEW}\"" charts/openhands/Chart.yaml

- name: Update integrations-hub dependency version
if: steps.check.outputs.should_publish == 'true' && matrix.chart.name == 'openhands' && needs.detect-changes.outputs.integrations-hub == 'true'
run: |
INTEGRATIONS_HUB_VERSION=$(yq '.version' charts/integrations-hub/Chart.yaml)
INTEGRATIONS_HUB_PREVIEW="${INTEGRATIONS_HUB_VERSION}-alpha.${{ github.event.pull_request.number }}"

yq -i "(.dependencies[] | select(.name == \"integrations-hub\")).version = \"${INTEGRATIONS_HUB_PREVIEW}\"" charts/openhands/Chart.yaml

- name: Test ${{ matrix.chart.name }} chart with default values
if: steps.check.outputs.should_publish == 'true'
run: |
Expand Down Expand Up @@ -279,6 +296,8 @@ jobs:
path: charts/automation
- name: plugin-directory
path: charts/plugin-directory
- name: integrations-hub
path: charts/integrations-hub
- name: openhands
path: charts/openhands
- name: openhands-secrets
Expand Down Expand Up @@ -331,6 +350,15 @@ jobs:
echo "Updating openhands plugin-directory dependency to ${PLUGIN_DIRECTORY_PREVIEW}"
yq -i "(.dependencies[] | select(.name == \"plugin-directory\")).version = \"${PLUGIN_DIRECTORY_PREVIEW}\"" charts/openhands/Chart.yaml

- name: Update integrations-hub dependency version for openhands
if: matrix.chart.name == 'openhands' && needs.detect-changes.outputs.integrations-hub == 'true'
run: |
INTEGRATIONS_HUB_VERSION=$(yq '.version' charts/integrations-hub/Chart.yaml)
INTEGRATIONS_HUB_PREVIEW="${INTEGRATIONS_HUB_VERSION}-alpha.${{ github.event.pull_request.number }}"

echo "Updating openhands integrations-hub dependency to ${INTEGRATIONS_HUB_PREVIEW}"
yq -i "(.dependencies[] | select(.name == \"integrations-hub\")).version = \"${INTEGRATIONS_HUB_PREVIEW}\"" charts/openhands/Chart.yaml

- name: Lint ${{ matrix.chart.name }} chart
run: |
echo "Testing ${{ matrix.chart.name }} chart"
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/publish-helm-charts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
matrix:
chart:
# Order matters: openhands depends on crd-check, runtime-api, automation,
# and plugin-directory, so those must publish first.
# plugin-directory, and integrations-hub, so those must publish first.
- name: crd-check
path: charts/crd-check
- name: runtime-api
Expand All @@ -39,6 +39,8 @@ jobs:
path: charts/automation
- name: plugin-directory
path: charts/plugin-directory
- name: integrations-hub
path: charts/integrations-hub
- name: openhands
path: charts/openhands
- name: openhands-secrets
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/validate-chart-versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ on:
plugin-directory-publishable:
description: 'Whether plugin-directory chart is publishable (no changes or version bumped)'
value: ${{ jobs.validate-chart-versions.outputs.plugin-directory-publishable }}
integrations-hub-publishable:
description: 'Whether integrations-hub chart is publishable (no changes or version bumped)'
value: ${{ jobs.validate-chart-versions.outputs.integrations-hub-publishable }}
openhands-publishable:
description: 'Whether openhands chart is publishable (no changes or version bumped)'
value: ${{ jobs.validate-chart-versions.outputs.openhands-publishable }}
Expand All @@ -47,6 +50,7 @@ jobs:
image-loader-publishable: ${{ steps.validate.outputs.image-loader-publishable }}
automation-publishable: ${{ steps.validate.outputs.automation-publishable }}
plugin-directory-publishable: ${{ steps.validate.outputs.plugin-directory-publishable }}
integrations-hub-publishable: ${{ steps.validate.outputs.integrations-hub-publishable }}
openhands-publishable: ${{ steps.validate.outputs.openhands-publishable }}
openhands-secrets-publishable: ${{ steps.validate.outputs.openhands-secrets-publishable }}

Expand Down
11 changes: 11 additions & 0 deletions charts/integrations-hub/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v2
name: integrations-hub
description: OpenHands Integrations Hub - Agent context layer with managed connectors and MCP integrations
type: application
version: 0.1.0
appVersion: "0.1.0"
dependencies:
- name: postgresql
version: 15.x.x
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
149 changes: 149 additions & 0 deletions charts/integrations-hub/templates/_env.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
{{- define "integrations-hub.env.defaults" }}
# Python/FastAPI service configuration
- name: INTEGRATIONS_HUB_HOST
value: "0.0.0.0"
- name: INTEGRATIONS_HUB_SERVER_PORT
value: {{ .Values.service.port | default 8000 | quote }}
- name: INTEGRATIONS_HUB_LOG_LEVEL
value: "info"

# OpenHands authentication configuration
{{- if .Values.openhands.baseUrl }}
- name: INTEGRATIONS_HUB_OPENHANDS_BASE_URL
value: {{ .Values.openhands.baseUrl | quote }}
{{- else if .Values.global }}
{{- if .Values.global.ingress }}
{{- if .Values.global.ingress.host }}
{{- $host := .Values.global.ingress.host }}
{{- if and .Values.global.ingress.prefixWithBranch .Values.global.branchSanitized }}
{{- $host = printf "%s.%s" .Values.global.branchSanitized .Values.global.ingress.host }}
{{- end }}
- name: INTEGRATIONS_HUB_OPENHANDS_BASE_URL
value: {{ printf "https://%s" $host | quote }}
{{- end }}
{{- end }}
{{- end }}

{{- if .Values.openhands.authCookieName }}
- name: INTEGRATIONS_HUB_OPENHANDS_AUTH_COOKIE_NAME
value: {{ .Values.openhands.authCookieName | quote }}
{{- end }}

# Service base URL
{{- if .Values.service.baseUrl }}
- name: INTEGRATIONS_HUB_BASE_URL
value: {{ .Values.service.baseUrl | quote }}
{{- end }}

# Credential encryption key
- name: INTEGRATIONS_HUB_CREDENTIAL_ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.credentialEncryption.secretName }}
key: {{ .Values.credentialEncryption.secretKey }}

# Admin configuration
{{- if .Values.admin.emails }}
- name: INTEGRATIONS_HUB_APP_ADMIN_EMAILS
value: {{ .Values.admin.emails | quote }}
{{- end }}

# PostgreSQL database configuration
- name: INTEGRATIONS_HUB_DB_HOST
value: {{ .Values.database.host | quote }}
- name: INTEGRATIONS_HUB_DB_PORT
value: {{ .Values.database.port | quote }}
- name: INTEGRATIONS_HUB_DB_USER
value: {{ .Values.database.user | quote }}
- name: INTEGRATIONS_HUB_DB_NAME
value: {{ .Values.database.name | quote }}
- name: INTEGRATIONS_HUB_DB_PASS
valueFrom:
secretKeyRef:
name: {{ .Values.database.secretName }}
key: {{ .Values.database.secretKey }}
- name: INTEGRATIONS_HUB_DB_POOL_SIZE
value: {{ .Values.database.poolSize | default 10 | quote }}
- name: INTEGRATIONS_HUB_DB_MAX_OVERFLOW
value: {{ .Values.database.maxOverflow | default 5 | quote }}

{{- if .Values.gcp.dbInstance }}
# GCP Cloud SQL configuration
- name: INTEGRATIONS_HUB_GCP_DB_INSTANCE
value: {{ .Values.gcp.dbInstance | quote }}
- name: INTEGRATIONS_HUB_GCP_PROJECT
value: {{ .Values.gcp.project | quote }}
- name: INTEGRATIONS_HUB_GCP_REGION
value: {{ .Values.gcp.region | quote }}
{{- end }}

# Cron job authentication
- name: INTEGRATIONS_HUB_CRON_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.cron.secretName }}
key: {{ .Values.cron.secretKey }}

# CORS configuration
{{- if .Values.cors.origins }}
- name: INTEGRATIONS_HUB_CORS_ORIGINS
value: {{ .Values.cors.origins | quote }}
{{- end }}

{{- if .Values.datadog.enabled }}
# Datadog configuration
- name: DD_AGENT_HOST
value: "datadog-agent.all-hands-system.svc.cluster.local"
- name: DD_TRACE_AGENT_PORT
value: "8126"
- name: DD_SERVICE
value: {{ .Values.datadog.serviceName | quote }}
- name: DD_ENV
value: {{ .Values.datadog.env | quote }}
- name: DD_TRACE_ENABLED
value: "true"
{{- end }}
{{- end }}

{{/*
integrations-hub.env — Deduplicated environment variable list.

This wrapper renders the default env vars from "integrations-hub.env.defaults",
then removes any entries whose name conflicts with a key in .Values.env,
and finally appends the .Values.env overrides. The result is a clean list
with no duplicate names, which prevents:
- Helm warnings about duplicate env vars
- Strategic Merge Patch conflicts during helm upgrade
("The order in patch list doesn't match $setElementOrder list")

How it works:
1. Render "integrations-hub.env.defaults" via include (evaluates all conditionals)
2. Parse the rendered YAML list into Go objects with fromYamlArray
3. Filter out any default entries whose name appears in .Values.env
4. Append .Values.env entries (user overrides always win)
5. Re-render the deduplicated list with toYaml
*/}}
{{- define "integrations-hub.env" }}
{{- $defaults := include "integrations-hub.env.defaults" . | fromYamlArray }}
{{- /* Build a lookup dict of override keys for O(1) membership checks */}}
{{- $overrideKeys := dict }}
{{- if .Values.env }}
{{- range $key, $_ := .Values.env }}
{{- $_ := set $overrideKeys $key true }}
{{- end }}
{{- end }}
{{- /* Keep only default entries that are NOT overridden by .Values.env */}}
{{- $filtered := list }}
{{- range $entry := $defaults }}
{{- if not (hasKey $overrideKeys (get $entry "name")) }}
{{- $filtered = append $filtered $entry }}
{{- end }}
{{- end }}
{{- /* Append user overrides from .Values.env (these take precedence) */}}
{{- if .Values.env }}
{{- range $key, $value := .Values.env }}
{{- $filtered = append $filtered (dict "name" $key "value" ($value | toString)) }}
{{- end }}
{{- end }}
{{- $filtered | toYaml }}
{{- end }}
Loading
Loading