From 06c2ac59cb028c960837e4ab6b3bc42ddd69fbeb Mon Sep 17 00:00:00 2001 From: Matthias Erll Date: Wed, 30 Sep 2026 11:59:04 +0200 Subject: [PATCH 1/7] refactor: merge git url conditions --- helmfile.d/snippets/derived.gotmpl | 10 +++++++++- values/argocd/argocd-raw.gotmpl | 4 ++-- values/team-ns/team-ns.gotmpl | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/helmfile.d/snippets/derived.gotmpl b/helmfile.d/snippets/derived.gotmpl index 112dce044b..43dbc48970 100644 --- a/helmfile.d/snippets/derived.gotmpl +++ b/helmfile.d/snippets/derived.gotmpl @@ -76,7 +76,14 @@ {{- $tlsSecretName = "otomi-byo-wildcard-cert" }} {{- end -}} - +{{- $gitValuesSource := "external" }} +{{- if contains "git-server.git-server.svc.cluster.local" $v.otomi.git.repoUrl }} + {{- /** built-in git-server */}} + {{- $gitValuesSource = "internal" }} +{{- else if contains "gitea-http.gitea.svc.cluster.local" $v.otomi.git.repoUrl }} + {{- /** Legacy Gitea values store */}} + {{- $gitValuesSource = "gitea" }} +{{- end }} {{- $ingressClasses := $v.ingress.classes | default list }} {{- $ingressClassNames := list $v.ingress.platformClass.className }} @@ -261,6 +268,7 @@ environments: egressGatewayName: {{ $egressGatewayName }} egressGatewayLabel: {{ $egressGatewayLabel }} ingressClassNames: {{- $ingressClassNames | toYaml | nindent 12 }} + gitValuesSource: {{ $gitValuesSource }} {{- /* Hostnames the platform serves itself. auth is oauth2-proxy's own route; the bare domain must stay unclaimed too. */}} platformHostnames: - {{ $domainSuffix }} diff --git a/values/argocd/argocd-raw.gotmpl b/values/argocd/argocd-raw.gotmpl index bf2d10d9a4..4021cc81e2 100644 --- a/values/argocd/argocd-raw.gotmpl +++ b/values/argocd/argocd-raw.gotmpl @@ -11,7 +11,7 @@ resources: data: custom-ca-certificates.crt: {{ .Values._derived.caCert | b64enc }} {{- end }} -{{- if contains "gitea-http.gitea.svc.cluster.local" $v.otomi.git.repoUrl }} +{{- if eq $v._derived.gitValuesSource "gitea" }} {{- $gitSecretName = "argocd-repo-creds-gitea-internal" }} {{- /* Additional secret specifically for external Git URL of Gitea */}} - apiVersion: external-secrets.io/v1 @@ -41,7 +41,7 @@ resources: - extract: key: apl-git-config -{{- else if contains "git-server.git-server.svc.cluster.local" $v.otomi.git.repoUrl }} +{{- else if eq $v._derived.gitValuesSource "internal" }} {{- $gitSecretName = "argocd-repo-creds-git-server" }} {{- end }} - apiVersion: external-secrets.io/v1 diff --git a/values/team-ns/team-ns.gotmpl b/values/team-ns/team-ns.gotmpl index b84647b3df..316b7aad22 100644 --- a/values/team-ns/team-ns.gotmpl +++ b/values/team-ns/team-ns.gotmpl @@ -54,7 +54,7 @@ httpRouteAnnotations: {{- $httpRoute.annotations | toYaml | nindent 2 }} gitOps: branch: {{ $v.otomi.git.branch }} -{{- if contains "gitea-http.gitea.svc.cluster.local" $v.otomi.git.repoUrl }} +{{- if eq $v._derived.gitValuesSource "gitea" }} teamRepoUrl: "https://{{ $v._derived.giteaDomain }}/otomi/team-{{ $teamId }}-argocd.git" valuesRepoUrl: "https://{{ $v._derived.giteaDomain }}/otomi/values.git" workloadValuesRepoUrl: "https://{{ $v._derived.giteaDomain }}/otomi/values.git" From 24de505d91f907560c0e3fe399e7a0f3e53158c1 Mon Sep 17 00:00:00 2001 From: Matthias Erll Date: Wed, 30 Sep 2026 12:28:02 +0200 Subject: [PATCH 2/7] feat: enable git-server if needed --- helmfile.d/snippets/defaults.yaml | 2 +- helmfile.d/snippets/derived.gotmpl | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/helmfile.d/snippets/defaults.yaml b/helmfile.d/snippets/defaults.yaml index 58bb0531a6..484a28886a 100644 --- a/helmfile.d/snippets/defaults.yaml +++ b/helmfile.d/snippets/defaults.yaml @@ -162,7 +162,7 @@ environments: cpu: 10m git-server: _rawValues: { } - enabled: true + enabled: false resources: requests: cpu: 50m diff --git a/helmfile.d/snippets/derived.gotmpl b/helmfile.d/snippets/derived.gotmpl index 43dbc48970..589bc1dc16 100644 --- a/helmfile.d/snippets/derived.gotmpl +++ b/helmfile.d/snippets/derived.gotmpl @@ -298,6 +298,8 @@ environments: {{- end }} external-dns: enabled: {{ $v.otomi.hasExternalDNS }} + git-server: + enabled: {{ or ($a | get "git-server.enabled") (eq $gitValuesSource "internal") }} harbor: {} keycloak: address: {{ $keycloakBaseUrl }} From 84caba42b60dc8737c58856865565b1eb97971a7 Mon Sep 17 00:00:00 2001 From: Matthias Erll Date: Wed, 30 Sep 2026 13:07:49 +0200 Subject: [PATCH 3/7] feat: deactivate git-server if no longer used --- helmfile.d/snippets/defaults.yaml | 2 +- src/cmd/migrate.ts | 12 ++++++++++++ tests/fixtures/env/settings/versions.yaml | 2 +- values-changes.yaml | 3 +++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/helmfile.d/snippets/defaults.yaml b/helmfile.d/snippets/defaults.yaml index 484a28886a..ac2f9ca862 100644 --- a/helmfile.d/snippets/defaults.yaml +++ b/helmfile.d/snippets/defaults.yaml @@ -1185,4 +1185,4 @@ environments: authenticationLayer: keycloak users: [] versions: - specVersion: 74 + specVersion: 75 diff --git a/src/cmd/migrate.ts b/src/cmd/migrate.ts index 3cb7c16e49..c3fec2d923 100644 --- a/src/cmd/migrate.ts +++ b/src/cmd/migrate.ts @@ -778,6 +778,17 @@ const migrateGeneratedSecrets = async (values: Record) => { } } +const deactivateGitServer = async (values: Record) => { + const d = terminal('deactivateGitServer') + if ( + values?.apps?.['git-server']?.enabled && + !values?.otomi?.git?.repoUrl?.includes('git-server.git-server.svc.cluster.local') + ) { + d.info('Disabling git-server as external Git repository is configured.') + set(values, 'apps.git-server.enabled', false) + } +} + const customMigrationFunctions: Record = { valkeyAndOauth2RedisPVCMigration, preservePvcStorageClassInRawValues, @@ -787,6 +798,7 @@ const customMigrationFunctions: Record = { removeIngressNginxValues, removeSopsConfig, migrateGeneratedSecrets, + deactivateGitServer, } /** diff --git a/tests/fixtures/env/settings/versions.yaml b/tests/fixtures/env/settings/versions.yaml index b3fbd599bb..279f9b2e37 100644 --- a/tests/fixtures/env/settings/versions.yaml +++ b/tests/fixtures/env/settings/versions.yaml @@ -2,4 +2,4 @@ kind: AplVersion metadata: name: versions spec: - specVersion: 74 + specVersion: 75 diff --git a/values-changes.yaml b/values-changes.yaml index f61fce136c..8fe36b9e1f 100644 --- a/values-changes.yaml +++ b/values-changes.yaml @@ -55,3 +55,6 @@ changes: additions: - apps.keycloak.enabled: true - otomi.oidc.authenticationLayer: keycloak + - version: 75 + customFunctions: + - deactivateGitServer From 65ff4133ad06751bbf7b62e9923137fc6eaa2491 Mon Sep 17 00:00:00 2001 From: Matthias Erll Date: Wed, 30 Sep 2026 13:14:50 +0200 Subject: [PATCH 4/7] feat: conditionally enable git-server during bootstrap --- src/cmd/bootstrap.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cmd/bootstrap.ts b/src/cmd/bootstrap.ts index 831f9c90ec..32f1339584 100644 --- a/src/cmd/bootstrap.ts +++ b/src/cmd/bootstrap.ts @@ -1,6 +1,6 @@ import { existsSync } from 'fs' import { copyFile, cp, mkdir, writeFile } from 'fs/promises' -import { cloneDeep, get, merge, pick, unset } from 'lodash' +import { cloneDeep, get, merge, pick, set, unset } from 'lodash' import { pki } from 'node-forge' import path from 'path' import { bootstrapGit } from 'src/common/bootstrap' @@ -118,6 +118,11 @@ export const processValues = async ( const { VALUES_INPUT } = env d.log(`Loading app values from ${VALUES_INPUT}`) const originalValues = (await deps.loadYaml(VALUES_INPUT)) as Record + const repoUrl = get(originalValues, 'otomi.git.repoUrl') + if (!repoUrl || repoUrl.includes('git-server.git-server.svc.cluster.local')) { + // If any other Git URL is set, assume it is a Git repo external to the cluster + set(originalValues, 'apps.git-server.enabled', true) + } // This part should be stored in a secret by initializeGitConfig unset(originalValues, 'otomi.git') const secretPaths = await deps.getSchemaSecretsPaths(Object.keys(get(originalValues, 'teamConfig', {}))) From 4c905274e779ff02aabf522b200ba423a3766e4c Mon Sep 17 00:00:00 2001 From: Matthias Erll Date: Wed, 30 Sep 2026 15:41:53 +0200 Subject: [PATCH 5/7] fix: consider value in test as inserted during bootstrap --- src/cmd/bootstrap.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cmd/bootstrap.test.ts b/src/cmd/bootstrap.test.ts index dbf63c975e..9d378bd2d8 100644 --- a/src/cmd/bootstrap.test.ts +++ b/src/cmd/bootstrap.test.ts @@ -226,9 +226,11 @@ describe('Bootstrapping values', () => { const res = await processValues(deps) // mergedForDisk includes allSecrets (stripAllSecrets mock is identity, real impl strips x-secret paths) expect(deps.writeValues).toHaveBeenNthCalledWith(1, { + apps: { 'git-server': { enabled: true } }, cluster: { name: 'bla', provider: 'dida' }, }) expect(res.originalInput).toEqual({ + apps: { 'git-server': { enabled: true } }, cluster: { name: 'bla', provider: 'dida' }, }) }) From 4f68dfa9e54270503bd2058920f5162142dc59c6 Mon Sep 17 00:00:00 2001 From: Matthias Erll Date: Thu, 1 Oct 2026 10:08:39 +0200 Subject: [PATCH 6/7] feat: do not override input values --- src/cmd/bootstrap.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/bootstrap.ts b/src/cmd/bootstrap.ts index 32f1339584..bce308b917 100644 --- a/src/cmd/bootstrap.ts +++ b/src/cmd/bootstrap.ts @@ -119,7 +119,8 @@ export const processValues = async ( d.log(`Loading app values from ${VALUES_INPUT}`) const originalValues = (await deps.loadYaml(VALUES_INPUT)) as Record const repoUrl = get(originalValues, 'otomi.git.repoUrl') - if (!repoUrl || repoUrl.includes('git-server.git-server.svc.cluster.local')) { + const gitServerEnabled = get(originalValues, 'apps.git-server.enabled') + if ((!repoUrl || repoUrl.includes('git-server.git-server.svc.cluster.local')) && gitServerEnabled === undefined) { // If any other Git URL is set, assume it is a Git repo external to the cluster set(originalValues, 'apps.git-server.enabled', true) } From 70d2b31083b28a852f674e2f95330004e5343a03 Mon Sep 17 00:00:00 2001 From: Matthias Erll Date: Thu, 1 Oct 2026 10:09:07 +0200 Subject: [PATCH 7/7] test: regression tests for bootstrap --- src/cmd/bootstrap.test.ts | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/cmd/bootstrap.test.ts b/src/cmd/bootstrap.test.ts index 9d378bd2d8..f453d9672d 100644 --- a/src/cmd/bootstrap.test.ts +++ b/src/cmd/bootstrap.test.ts @@ -180,9 +180,10 @@ describe('Bootstrapping values', () => { }) }) describe('processing values', () => { + const internalRepoUrl = 'http://git-server.git-server.svc.cluster.local:3000/otomi-admin/values.git' + const externalRepoUrl = 'https://example.com/values.git' const generatedSecrets = { gen: 'x' } const ca = { a: 'cert' } - const mergedSecretsWithGen = merge(cloneDeep(secrets), cloneDeep(generatedSecrets)) let deps beforeEach(() => { deps = { @@ -259,6 +260,42 @@ describe('Bootstrapping values', () => { const result = await processValues(deps) expect(result.allSecrets).toEqual(merge(cloneDeep(ca), secrets)) }) + it('should enable the internal git-server when no repo URL is given', async () => { + deps.loadYaml.mockReturnValue({ cluster: { name: 'bla', provider: 'dida' } }) + const res = await processValues(deps) + expect(res.originalInput.apps['git-server'].enabled).toBe(true) + }) + it('should enable the internal git-server when the repo URL points at the in-cluster git server', async () => { + deps.loadYaml.mockReturnValue({ + cluster: { name: 'bla', provider: 'dida' }, + otomi: { git: { repoUrl: internalRepoUrl } }, + }) + const res = await processValues(deps) + expect(res.originalInput.apps['git-server'].enabled).toBe(true) + }) + it('should not enable the internal git-server when the repo URL is external', async () => { + deps.loadYaml.mockReturnValue({ + cluster: { name: 'bla', provider: 'dida' }, + otomi: { git: { repoUrl: externalRepoUrl } }, + }) + const res = await processValues(deps) + expect(res.originalInput.apps?.['git-server']).toBeUndefined() + }) + it('should keep an explicitly disabled git-server disabled', async () => { + deps.loadYaml.mockReturnValue({ + apps: { 'git-server': { enabled: false } }, + }) + const res = await processValues(deps) + expect(res.originalInput.apps['git-server'].enabled).toBe(false) + }) + it('should keep an explicitly enabled git-server enabled', async () => { + deps.loadYaml.mockReturnValue({ + apps: { 'git-server': { enabled: true } }, + otomi: { git: { repoUrl: externalRepoUrl } }, + }) + const res = await processValues(deps) + expect(res.originalInput.apps['git-server'].enabled).toBe(true) + }) }) }) })