From 6a854575f51ac26ffd4af084f778c43e9e32bdbe Mon Sep 17 00:00:00 2001 From: Alex Szakaly Date: Tue, 2 Dec 2025 18:54:20 +0100 Subject: [PATCH] feat: allow custom target template configuration for ExternalSecret Signed-off-by: Alex Szakaly --- application/templates/externalsecrets.yaml | 4 + application/tests/externalsecrets_test.yaml | 403 ++++++++++++++++++++ 2 files changed, 407 insertions(+) create mode 100644 application/tests/externalsecrets_test.yaml diff --git a/application/templates/externalsecrets.yaml b/application/templates/externalsecrets.yaml index 46345971..8df2e780 100644 --- a/application/templates/externalsecrets.yaml +++ b/application/templates/externalsecrets.yaml @@ -42,6 +42,9 @@ spec: target: name: {{ template "application.name" $ }}-{{ $nameSuffix }} template: +{{- if ($data.target).template }} +{{ include "application.tplvalues.render" ( dict "value" ($data.target).template "context" $ ) | indent 8 }} +{{- else }} type: {{ $data.type | default "Opaque" }} {{- if or $data.annotations $data.labels}} metadata: @@ -56,3 +59,4 @@ spec: {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/application/tests/externalsecrets_test.yaml b/application/tests/externalsecrets_test.yaml new file mode 100644 index 00000000..b71e8f3c --- /dev/null +++ b/application/tests/externalsecrets_test.yaml @@ -0,0 +1,403 @@ +suite: ExternalSecrets + +templates: + - externalsecrets.yaml + +tests: + - it: does not yield ExternalSecret resource if externalSecret.enabled is false + set: + externalSecret: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: renders a basic ExternalSecret with minimal configuration + set: + applicationName: my-app + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + asserts: + - hasDocuments: + count: 1 + - isKind: + of: ExternalSecret + - equal: + path: metadata.name + value: my-app-test-ing + - equal: + path: spec.data + value: + - remoteRef: + key: foo/bar + property: test + secretKey: password + - equal: + path: spec.target.name + value: my-app-test-ing + + - it: renders multiple external secrets with minimal configuration + set: + applicationName: my-app + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + testing: + data: + username: + remoteRef: + key: bar/foo + property: testing + asserts: + - hasDocuments: + count: 2 + - documentIndex: 0 + isKind: + of: ExternalSecret + - documentIndex: 1 + isKind: + of: ExternalSecret + - documentIndex: 0 + equal: + path: metadata.name + value: my-app-test-ing + - documentIndex: 1 + equal: + path: metadata.name + value: my-app-testing + - documentIndex: 0 + equal: + path: spec.data + value: + - remoteRef: + key: foo/bar + property: test + secretKey: password + - documentIndex: 1 + equal: + path: spec.data + value: + - remoteRef: + key: bar/foo + property: testing + secretKey: username + - documentIndex: 0 + equal: + path: spec.target.name + value: my-app-test-ing + - documentIndex: 1 + equal: + path: spec.target.name + value: my-app-testing + + - it: uses API version external-secrets.io/v1 if cluster advertises capability + set: + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + capabilities: + apiVersions: + - external-secrets.io/v1/ExternalSecret + asserts: + - isAPIVersion: + of: external-secrets.io/v1 + + - it: uses API version external-secrets.io/v1beta1 if cluster does not advertise capability + set: + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + capabilities: + apiVersions: + - external-secrets.io/v1beta1/ExternalSecret + asserts: + - isAPIVersion: + of: external-secrets.io/v1beta1 + + - it: includes additional annotations when defined + set: + externalSecret: + enabled: true + annotations: + foo: bar + test: ing + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + asserts: + - equal: + path: metadata.annotations + value: + foo: bar + test: ing + + - it: includes additional labels when defined + set: + externalSecret: + enabled: true + additionalLabels: + foo: bar + test: ing + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + asserts: + - equal: + path: metadata.labels.foo + value: bar + - equal: + path: metadata.labels.test + value: ing + + - it: renders external secret with default refreshInterval when not specified + set: + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + asserts: + - equal: + path: spec.refreshInterval + value: 1m + + - it: renders external secret with refreshInterval when defined + set: + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + refreshInterval: 24h + asserts: + - equal: + path: spec.refreshInterval + value: 24h + + - it: fails when neither data nor dataFrom are specified + set: + externalSecret: + enabled: true + files: + test-ing: + foo: bar + asserts: + - failedTemplate: + errorPattern: Data or datafrom not specified for secret + + - it: renders external secret with default secretStoreRef when not specified + set: + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + asserts: + - equal: + path: spec.secretStoreRef + value: + kind: SecretStore + name: tenant-vault-secret-store + + - it: renders external secret with refreshInterval when defined + set: + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + secretStore: + kind: foo + name: bar + asserts: + - equal: + path: spec.secretStoreRef + value: + kind: foo + name: bar + + - it: renders external secret with default template type when not specified + set: + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + asserts: + - equal: + path: spec.target.template.type + value: Opaque + + - it: renders external secret with target template when defined + set: + externalSecret: + enabled: true + files: + test-ing: + data: + pwd: + remoteRef: + key: foo/bar + property: secret-password + usrnm: + remoteRef: + key: bar/foo + property: secret-user + target: + template: + data: + username: "{{ `{{ .usrnm }}` }}" + password: "{{ `{{ .pwd | b64enc }}` }}" + engineVersion: v2 + type: kubernetes.io/basic-auth + asserts: + - equal: + path: spec.target.template + value: + data: + username: '{{ .usrnm }}' + password: '{{ .pwd | b64enc }}' + engineVersion: v2 + type: kubernetes.io/basic-auth + + - it: renders external secret with template type when defined + set: + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + type: foo + asserts: + - equal: + path: spec.target.template.type + value: foo + + - it: does not include template metadata annotations if none are defined + set: + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + asserts: + - notExists: + path: spec.target.template.metadata.annotations + + - it: renders external secret with template metadata annotations when defined + set: + externalSecret: + enabled: true + files: + test-ing: + annotations: + foo: bar + test: ing + data: + password: + remoteRef: + key: foo/bar + property: test + asserts: + - equal: + path: spec.target.template.metadata.annotations + value: + foo: bar + test: ing + + - it: does not include template metadata labels if none are defined + set: + externalSecret: + enabled: true + files: + test-ing: + data: + password: + remoteRef: + key: foo/bar + property: test + asserts: + - notExists: + path: spec.target.template.metadata.labels + + - it: renders external secret with template metadata labels when defined + set: + externalSecret: + enabled: true + files: + test-ing: + labels: + foo: bar + test: ing + data: + password: + remoteRef: + key: foo/bar + property: test + asserts: + - equal: + path: spec.target.template.metadata.labels + value: + foo: bar + test: ing