mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: validate namespace and groupname for Grafana manages and Lotex alerts (#44872)
This commit is contained in:
parent
9df43abbb5
commit
1680e284e5
@ -5,10 +5,11 @@ import { css } from '@emotion/css';
|
|||||||
import { RuleEditorSection } from './RuleEditorSection';
|
import { RuleEditorSection } from './RuleEditorSection';
|
||||||
import { useFormContext } from 'react-hook-form';
|
import { useFormContext } from 'react-hook-form';
|
||||||
import { RuleFormType, RuleFormValues } from '../../types/rule-form';
|
import { RuleFormType, RuleFormValues } from '../../types/rule-form';
|
||||||
import { RuleFolderPicker } from './RuleFolderPicker';
|
import { Folder, RuleFolderPicker } from './RuleFolderPicker';
|
||||||
import { GroupAndNamespaceFields } from './GroupAndNamespaceFields';
|
import { GroupAndNamespaceFields } from './GroupAndNamespaceFields';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
import { CloudRulesSourcePicker } from './CloudRulesSourcePicker';
|
import { CloudRulesSourcePicker } from './CloudRulesSourcePicker';
|
||||||
|
import { checkForPathSeparator } from './util';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
editingExistingRule: boolean;
|
editingExistingRule: boolean;
|
||||||
@ -72,6 +73,16 @@ export const AlertTypeStep: FC<Props> = ({ editingExistingRule }) => {
|
|||||||
{...register('name', {
|
{...register('name', {
|
||||||
required: { value: true, message: 'Must enter an alert name' },
|
required: { value: true, message: 'Must enter an alert name' },
|
||||||
pattern: ruleFormType === RuleFormType.cloudRecording ? recordingRuleNameValidationPattern : undefined,
|
pattern: ruleFormType === RuleFormType.cloudRecording ? recordingRuleNameValidationPattern : undefined,
|
||||||
|
validate: {
|
||||||
|
pathSeparator: (value: string) => {
|
||||||
|
// we use the alert rule name as the "groupname" for Grafana managed alerts, so we can't allow path separators
|
||||||
|
if (ruleFormType === RuleFormType.grafana) {
|
||||||
|
return checkForPathSeparator(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
})}
|
})}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
/>
|
/>
|
||||||
@ -148,6 +159,9 @@ export const AlertTypeStep: FC<Props> = ({ editingExistingRule }) => {
|
|||||||
name="folder"
|
name="folder"
|
||||||
rules={{
|
rules={{
|
||||||
required: { value: true, message: 'Please select a folder' },
|
required: { value: true, message: 'Please select a folder' },
|
||||||
|
validate: {
|
||||||
|
pathSeparator: (folder: Folder) => checkForPathSeparator(folder.title),
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
@ -8,6 +8,7 @@ import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
|||||||
import { SelectWithAdd } from './SelectWIthAdd';
|
import { SelectWithAdd } from './SelectWIthAdd';
|
||||||
import { Field, InputControl, useStyles2 } from '@grafana/ui';
|
import { Field, InputControl, useStyles2 } from '@grafana/ui';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
import { checkForPathSeparator } from './util';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
rulesSourceName: string;
|
rulesSourceName: string;
|
||||||
@ -75,6 +76,9 @@ export const GroupAndNamespaceFields: FC<Props> = ({ rulesSourceName }) => {
|
|||||||
control={control}
|
control={control}
|
||||||
rules={{
|
rules={{
|
||||||
required: { value: true, message: 'Required.' },
|
required: { value: true, message: 'Required.' },
|
||||||
|
validate: {
|
||||||
|
pathSeparator: checkForPathSeparator,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
@ -87,6 +91,9 @@ export const GroupAndNamespaceFields: FC<Props> = ({ rulesSourceName }) => {
|
|||||||
control={control}
|
control={control}
|
||||||
rules={{
|
rules={{
|
||||||
required: { value: true, message: 'Required.' },
|
required: { value: true, message: 'Required.' },
|
||||||
|
validate: {
|
||||||
|
pathSeparator: checkForPathSeparator,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ClassicCondition, ExpressionQuery } from 'app/features/expressions/types';
|
import { ClassicCondition, ExpressionQuery } from 'app/features/expressions/types';
|
||||||
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
||||||
import { queriesWithUpdatedReferences, updateMathExpressionRefs } from './util';
|
import { checkForPathSeparator, queriesWithUpdatedReferences, updateMathExpressionRefs } from './util';
|
||||||
import { ExpressionDatasourceRef } from '@grafana/runtime/src/utils/DataSourceWithBackend';
|
import { ExpressionDatasourceRef } from '@grafana/runtime/src/utils/DataSourceWithBackend';
|
||||||
|
|
||||||
describe('rule-editor', () => {
|
describe('rule-editor', () => {
|
||||||
@ -191,3 +191,17 @@ describe('rule-editor', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('checkForPathSeparator', () => {
|
||||||
|
it('should not allow strings with /', () => {
|
||||||
|
expect(checkForPathSeparator('foo / bar')).not.toBe(true);
|
||||||
|
expect(typeof checkForPathSeparator('foo / bar')).toBe('string');
|
||||||
|
});
|
||||||
|
it('should not allow strings with \\', () => {
|
||||||
|
expect(checkForPathSeparator('foo \\ bar')).not.toBe(true);
|
||||||
|
expect(typeof checkForPathSeparator('foo \\ bar')).toBe('string');
|
||||||
|
});
|
||||||
|
it('should allow anything without / or \\', () => {
|
||||||
|
expect(checkForPathSeparator('foo bar')).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { isExpressionQuery } from 'app/features/expressions/guards';
|
import { isExpressionQuery } from 'app/features/expressions/guards';
|
||||||
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
||||||
|
import { ValidateResult } from 'react-hook-form';
|
||||||
|
|
||||||
export function queriesWithUpdatedReferences(
|
export function queriesWithUpdatedReferences(
|
||||||
queries: AlertQuery[],
|
queries: AlertQuery[],
|
||||||
@ -64,3 +65,16 @@ export function updateMathExpressionRefs(expression: string, previousRefId: stri
|
|||||||
|
|
||||||
return expression.replace(oldExpression, newExpression);
|
return expression.replace(oldExpression, newExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// some gateways (like Istio) will decode "/" and "\" characters – this will cause 404 errors for any API call
|
||||||
|
// that includes these values in the URL (ie. /my/path%2fto/resource -> /my/path/to/resource)
|
||||||
|
//
|
||||||
|
// see https://istio.io/latest/docs/ops/best-practices/security/#customize-your-system-on-path-normalization
|
||||||
|
export function checkForPathSeparator(value: string): ValidateResult {
|
||||||
|
const containsPathSeparator = value.includes('/') || value.includes('\\');
|
||||||
|
if (containsPathSeparator) {
|
||||||
|
return 'Cannot contain "/" or "\\" characters';
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user