Skip to content
代码片段 群组 项目
未验证 提交 6cbea621 编辑于 作者: Artur Fedorov's avatar Artur Fedorov 提交者: GitLab
浏览文件

Merge branch '454287-add-yaml-conversion' into 'master'

No related branches found
No related tags found
1 合并请求!2419Fix TanukiBot spec relying on outdated code
......@@ -4,8 +4,8 @@ export const DEFAULT_PIPELINE_EXECUTION_POLICY = `type: pipeline_execution_polic
name: ''
description: ''
enabled: true
actions:
- foo: bar
content:
include: ''
`;
export const ADD_CONDITION_LABEL = s__('ScanExecutionPolicy|Add condition');
......
......@@ -88,6 +88,21 @@ export default {
changeEditorMode(mode) {
this.mode = mode;
},
handleUpdateProperty(property, value) {
this.policy[property] = value;
this.updateYamlEditorValue(this.policy);
},
handleUpdateYaml(manifest) {
const { policy, hasParsingError } = createPolicyObject(manifest);
this.yamlEditorValue = manifest;
this.hasParsingError = hasParsingError;
this.parsingError = hasParsingError ? this.$options.i18n.PARSING_ERROR_MESSAGE : '';
this.policy = policy;
},
updateYamlEditorValue(policy) {
this.yamlEditorValue = policyToYaml(policy);
},
},
};
</script>
......@@ -101,6 +116,8 @@ export default {
:policy="policy"
:yaml-editor-value="yamlEditorValue"
@update-editor-mode="changeEditorMode"
@update-property="handleUpdateProperty"
@update-yaml="handleUpdateYaml"
>
<template #rules>
<dim-disable-container :disabled="hasParsingError">
......
import { safeDump, safeLoad } from 'js-yaml';
import { addIdsToPolicy, removeIdsFromPolicy } from '../utils';
import { hasInvalidKey } from '../utils';
/*
Construct a policy object expected by the policy editor from a yaml manifest.
*/
export const fromYaml = ({ manifest }) => {
export const fromYaml = ({ manifest, validateRuleMode = false }) => {
try {
const policy = addIdsToPolicy(safeLoad(manifest, { json: true }));
const policy = safeLoad(manifest, { json: true });
if (validateRuleMode) {
/**
* These values are what is supported by rule mode. If the yaml has any other values,
* rule mode will be disabled. This validation should not be used to check whether
* the yaml is a valid policy; that should be done on the backend with the official
* schema. These values should not be retrieved from the backend schema because
* the UI for new attributes may not be available.
*/
const primaryKeys = [
'type',
'name',
'description',
'enabled',
'override_project_ci',
'content',
];
const contentKeys = ['workflow', 'include'];
return !(hasInvalidKey(policy, primaryKeys) || hasInvalidKey(policy.content, contentKeys))
? policy
: { error: true };
}
return policy;
} catch {
......@@ -23,7 +46,7 @@ export const fromYaml = ({ manifest }) => {
* @returns {Object} security policy object and any errors
*/
export const createPolicyObject = (manifest) => {
const policy = fromYaml({ manifest });
const policy = fromYaml({ manifest, validateRuleMode: true });
return { policy, hasParsingError: Boolean(policy.error) };
};
......@@ -32,7 +55,7 @@ export const createPolicyObject = (manifest) => {
Return yaml representation of a policy.
*/
export const policyToYaml = (policy) => {
return safeDump(removeIdsFromPolicy(policy));
return safeDump(policy);
};
export const toYaml = (yaml) => {
......
......@@ -2,11 +2,12 @@ import { GlEmptyState } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { DEFAULT_ASSIGNED_POLICY_PROJECT } from 'ee/security_orchestration/constants';
import EditorComponent from 'ee/security_orchestration/components/policy_editor/pipeline_execution/editor_component.vue';
import EditorLayout from 'ee/security_orchestration/components/policy_editor/editor_layout.vue';
import RuleSection from 'ee/security_orchestration/components/policy_editor/pipeline_execution/rule/rule_section.vue';
import ActionSection from 'ee/security_orchestration/components/policy_editor/pipeline_execution/action/action_section.vue';
import EditorLayout from 'ee/security_orchestration/components/policy_editor/editor_layout.vue';
import { DEFAULT_PIPELINE_EXECUTION_POLICY } from 'ee/security_orchestration/components/policy_editor/pipeline_execution/constants';
import { configFileManifest, configFileObject } from './mock_data';
describe('RuleSection', () => {
describe('EditorComponent', () => {
let wrapper;
const policyEditorEmptyStateSvgPath = 'path/to/svg';
const scanPolicyDocumentationPath = 'path/to/docs';
......@@ -28,26 +29,53 @@ describe('RuleSection', () => {
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findPolicyEditorLayout = () => wrapper.findComponent(EditorLayout);
const findActionSection = () => wrapper.findComponent(ActionSection);
const findRuleSection = () => wrapper.findComponent(RuleSection);
it('renders the editor', () => {
factory();
expect(findPolicyEditorLayout().exists()).toBe(true);
expect(findActionSection().exists()).toBe(true);
expect(findEmptyState().exists()).toBe(false);
describe('rule mode', () => {
it('renders the editor', () => {
factory();
expect(findEmptyState().exists()).toBe(false);
});
it('renders the rule section', () => {
factory();
expect(findRuleSection().exists()).toBe(true);
});
it('renders the default policy editor layout', () => {
factory();
const editorLayout = findPolicyEditorLayout();
expect(editorLayout.exists()).toBe(true);
expect(editorLayout.props()).toEqual(
expect.objectContaining({
yamlEditorValue: DEFAULT_PIPELINE_EXECUTION_POLICY,
}),
);
});
it('updates the policy', async () => {
const name = 'New name';
factory();
expect(findPolicyEditorLayout().props('policy').name).toBe('');
expect(findPolicyEditorLayout().props('yamlEditorValue')).toContain("name: ''");
await findPolicyEditorLayout().vm.$emit('update-property', 'name', name);
expect(findPolicyEditorLayout().props('policy').name).toBe(name);
expect(findPolicyEditorLayout().props('yamlEditorValue')).toContain(`name: ${name}`);
});
});
it('renders the rule section', () => {
factory();
expect(findRuleSection().exists()).toBe(true);
describe('yaml mode', () => {
it('updates the policy', async () => {
factory();
await findPolicyEditorLayout().vm.$emit('update-yaml', configFileManifest);
expect(findPolicyEditorLayout().props('policy')).toEqual(configFileObject);
expect(findPolicyEditorLayout().props('yamlEditorValue')).toBe(configFileManifest);
});
});
it('renders the empty page', () => {
factory({ provide: { disableScanPolicyUpdate: true } });
expect(findPolicyEditorLayout().exists()).toBe(false);
expect(findActionSection().exists()).toBe(false);
expect(findRuleSection().exists()).toBe(false);
const emptyState = findEmptyState();
expect(emptyState.exists()).toBe(true);
......
import { fromYaml } from 'ee/security_orchestration/components/policy_editor/pipeline_execution/utils';
/**
* Naming convention for mocks:
* mock policy yaml => name ends in `Manifest`
* mock parsed yaml => name ends in `Object`
* mock policy for list/drawer => name ends in `PipelinePolicy`
*
* If you have the same policy in multiple forms (e.g. mock yaml and mock parsed yaml that should
* match), please name them similarly (e.g. fooBarManifest and fooBarObject)
* and keep them near each other.
*/
export const customYaml = `variable: true
`;
export const customYamlObject = { variable: true };
export const configFileManifest = `name: "Ci config file"
description: "triggers all protected branches except main"
enabled: true
override_project_ci: true
content:
include:
project: pipeline-execution-policy/security-policy-project
file: ci.yml
`;
export const configFileObject = fromYaml({ manifest: configFileManifest });
import { DEFAULT_PIPELINE_EXECUTION_POLICY } from 'ee/security_orchestration/components/policy_editor/pipeline_execution/constants';
import {
createPolicyObject,
fromYaml,
policyToYaml,
toYaml,
} from 'ee/security_orchestration/components/policy_editor/pipeline_execution/utils';
import {
customYaml,
customYamlObject,
} from 'ee_jest/security_orchestration/mocks/mock_pipeline_execution_policy_data';
import { customYaml, customYamlObject } from './mock_data';
describe('fromYaml', () => {
it.each`
title | input | output | features
${'returns the policy object for a supported manifest'} | ${{ manifest: customYaml }} | ${customYamlObject} | ${{}}
`('$title', ({ input, output, features }) => {
window.gon = { features };
title | input | output
${'returns the policy object for a supported manifest'} | ${{ manifest: DEFAULT_PIPELINE_EXECUTION_POLICY }} | ${fromYaml({ manifest: DEFAULT_PIPELINE_EXECUTION_POLICY })}
${'returns the policy object for a policy with an unsupported attribute without validation'} | ${{ manifest: customYaml }} | ${customYamlObject}
${'returns the error object for a policy with an unsupported attribute with validation'} | ${{ manifest: customYaml, validateRuleMode: true }} | ${{ error: true }}
`('$title', ({ input, output }) => {
expect(fromYaml(input)).toStrictEqual(output);
});
});
describe('createPolicyObject', () => {
it.each`
title | input | output
${'returns the policy object and no errors for a supported manifest'} | ${[customYaml]} | ${{ policy: customYamlObject, hasParsingError: false }}
title | input | output
${'returns the policy object and no errors for a supported manifest'} | ${DEFAULT_PIPELINE_EXECUTION_POLICY} | ${{ policy: fromYaml({ manifest: DEFAULT_PIPELINE_EXECUTION_POLICY }), hasParsingError: false }}
${'returns the error policy object and the error for an unsupported manifest'} | ${customYaml} | ${{ policy: { error: true }, hasParsingError: true }}
`('$title', ({ input, output }) => {
expect(createPolicyObject(...input)).toStrictEqual(output);
expect(createPolicyObject(input)).toStrictEqual(output);
});
});
......
export const customYaml = `variable: true
`;
export const customYamlObject = { variable: true };
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册