From 49bd8a608ec941f38bad58c7e3a1b368ca5ab3e1 Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Wed, 29 Jan 2025 18:54:41 +0100 Subject: [PATCH] Alerting: Fix fieldSelector encoding (#99751) Co-authored-by: Sonia Aguilar --- .../mute-timings/useMuteTimings.tsx | 9 +++++-- .../alerting/unified/utils/k8s/utils.test.ts | 27 +++++++++++++++++++ .../alerting/unified/utils/k8s/utils.ts | 8 ++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 public/app/features/alerting/unified/utils/k8s/utils.test.ts diff --git a/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx b/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx index fb873f967b3..edf6fd8fd05 100644 --- a/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx +++ b/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx @@ -10,7 +10,11 @@ import { import { BaseAlertmanagerArgs, Skippable } from 'app/features/alerting/unified/types/hooks'; import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; import { PROVENANCE_NONE } from 'app/features/alerting/unified/utils/k8s/constants'; -import { isK8sEntityProvisioned, shouldUseK8sApi } from 'app/features/alerting/unified/utils/k8s/utils'; +import { + encodeFieldSelector, + isK8sEntityProvisioned, + shouldUseK8sApi, +} from 'app/features/alerting/unified/utils/k8s/utils'; import { MuteTimeInterval } from 'app/plugins/datasource/alertmanager/types'; import { getAPINamespace } from '../../../../../api/utils'; @@ -200,7 +204,8 @@ export const useGetMuteTiming = ({ alertmanager, name: nameToFind }: BaseAlertma useEffect(() => { if (useK8sApi) { const namespace = getAPINamespace(); - getGrafanaTimeInterval({ namespace, fieldSelector: `spec.name=${nameToFind}` }, true); + const entityName = encodeFieldSelector(nameToFind); + getGrafanaTimeInterval({ namespace, fieldSelector: `spec.name=${entityName}` }, true); } else { getAlertmanagerTimeInterval(alertmanager, true); } diff --git a/public/app/features/alerting/unified/utils/k8s/utils.test.ts b/public/app/features/alerting/unified/utils/k8s/utils.test.ts new file mode 100644 index 00000000000..a04a1ea16ec --- /dev/null +++ b/public/app/features/alerting/unified/utils/k8s/utils.test.ts @@ -0,0 +1,27 @@ +import { encodeFieldSelector } from './utils'; + +describe('encodeFieldSelector', () => { + it('should escape backslashes', () => { + expect(encodeFieldSelector('some\\value')).toBe('some\\\\value'); + }); + + it('should escape equal signs', () => { + expect(encodeFieldSelector('key=value')).toBe('key\\=value'); + }); + + it('should handle strings with no backslashes or equal signs', () => { + expect(encodeFieldSelector('simplevalue')).toBe('simplevalue'); + }); + + it('should handle strings with multiple equal signs', () => { + expect(encodeFieldSelector('key=value=another=value')).toBe('key\\=value\\=another\\=value'); + }); + + it('should escape commas', () => { + expect(encodeFieldSelector('value,another')).toBe('value\\,another'); + }); + + it('should escape mixed special characters', () => { + expect(encodeFieldSelector('foo=bar,bar=baz,qux\\foo')).toBe('foo\\=bar\\,bar\\=baz\\,qux\\\\foo'); + }); +}); diff --git a/public/app/features/alerting/unified/utils/k8s/utils.ts b/public/app/features/alerting/unified/utils/k8s/utils.ts index 0aec7c1dd52..69444f02b2c 100644 --- a/public/app/features/alerting/unified/utils/k8s/utils.ts +++ b/public/app/features/alerting/unified/utils/k8s/utils.ts @@ -43,3 +43,11 @@ export const canAdminEntity = (k8sEntity: EntityToCheck) => export const canDeleteEntity = (k8sEntity: EntityToCheck) => getAnnotation(k8sEntity, K8sAnnotations.AccessDelete) === 'true'; + +/** + * Escape \ and = characters for field selectors. + * The Kubernetes API Machinery will decode those automatically. + */ +export const encodeFieldSelector = (value: string): string => { + return value.replaceAll(/\\/g, '\\\\').replaceAll(/\=/g, '\\=').replaceAll(/,/g, '\\,'); +};