Skip to content

Commit f231e3a

Browse files
committed
OTel quick setup: Validate contact group membership in password slide-in
CMK-34207 Change-Id: I415c3ac261c878ec9943c8e5bf9d0648c683a528 (cherry picked from commit 939a188)
1 parent dc51146 commit f231e3a

2 files changed

Lines changed: 129 additions & 0 deletions

File tree

packages/cmk-frontend-vue/src/mode-otel/otel-configuration-steps/PasswordStoreSlideIn.vue

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,17 @@ const api: API<string, PasswordConfig> = {
112112
})
113113
}
114114
115+
const ownedBy = data.password_props.owned_by
116+
if (Array.isArray(ownedBy) && ownedBy[0] === 'contact_group' && !ownedBy[1]) {
117+
validationMessages.push({
118+
location: ['password_props', 'owned_by'],
119+
message: _t(
120+
'You need to be member of at least one contact group to be able to create a password.'
121+
),
122+
replacement_value: ownedBy
123+
})
124+
}
125+
115126
if (data.general_props.id) {
116127
const existing = await configEntityAPI.listEntities(
117128
'passwordstore_password',

packages/cmk-frontend-vue/tests/mode-otel/PasswordStoreSlideIn.test.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
import { cleanup, fireEvent, render, screen } from '@testing-library/vue'
77
import { flushPromises } from '@vue/test-utils'
8+
import type * as FormSpec from 'cmk-shared-typing/typescript/vue_formspec_components'
89
import type { Catalog } from 'cmk-shared-typing/typescript/vue_formspec_components'
910
import { HttpResponse, http } from 'msw'
1011
import { setupServer } from 'msw/node'
@@ -91,6 +92,61 @@ const defaultValues = {
9192
password_props: { password: '', owned_by: '', share_with: '' }
9293
}
9394

95+
const ownedByContactGroupForm: FormSpec.CascadingSingleChoice = {
96+
type: 'cascading_single_choice',
97+
title: 'Editable by',
98+
label: null,
99+
help: '',
100+
validators: [],
101+
input_hint: '',
102+
no_elements_text: '',
103+
layout: 'vertical',
104+
elements: [
105+
{
106+
name: 'contact_group',
107+
title: 'Members of the contact group:',
108+
default_value: '',
109+
parameter_form: stringField('Contact group')
110+
}
111+
]
112+
}
113+
114+
const schemaWithCascadingOwner: Catalog = {
115+
type: 'catalog',
116+
title: 'New password',
117+
help: '',
118+
validators: [],
119+
elements: [
120+
{
121+
name: 'general_props',
122+
title: 'General properties',
123+
locked: null,
124+
elements: [
125+
topicElement('id', 'Unique ID'),
126+
topicElement('title', 'Title'),
127+
topicElement('comment', 'Comment'),
128+
topicElement('docu_url', 'Documentation URL')
129+
]
130+
},
131+
{
132+
name: 'password_props',
133+
title: 'Password properties',
134+
locked: null,
135+
elements: [
136+
topicElement('password', 'Password'),
137+
{
138+
type: 'topic_element',
139+
name: 'owned_by',
140+
required: true,
141+
default_value: ['contact_group', ''],
142+
parameter_form: ownedByContactGroupForm
143+
},
144+
topicElement('share_with', 'Share with')
145+
]
146+
}
147+
]
148+
}
149+
94150
const FORM_SPEC_URL = `${location.protocol}//${location.host}/api/internal/domain-types/form_spec/collections/:entity_type`
95151
const LIST_PASSWORDS_URL = `${location.protocol}//${location.host}/api/internal/domain-types/passwordstore_password/collections/:entity_type_specifier`
96152

@@ -293,4 +349,66 @@ describe('PasswordStoreSlideIn', () => {
293349
screen.getByText('This ID is already in use. Please choose another one.')
294350
).toBeInTheDocument()
295351
})
352+
353+
test('shows validation error when no contact group can own the password', async () => {
354+
server.use(
355+
http.get(FORM_SPEC_URL, () =>
356+
HttpResponse.json({
357+
extensions: {
358+
schema: schemaWithCascadingOwner,
359+
default_values: {
360+
general_props: { id: 'my-password', title: 'My Password', comment: '', docu_url: '' },
361+
password_props: {
362+
password: 'secret',
363+
owned_by: ['contact_group', ''],
364+
share_with: ''
365+
}
366+
}
367+
}
368+
})
369+
)
370+
)
371+
mockListPasswords()
372+
render(PasswordStoreSlideIn, { props: { open: true } })
373+
374+
await flushPromises()
375+
await fireEvent.click(screen.getByRole('button', { name: 'Save' }))
376+
await flushPromises()
377+
378+
expect(
379+
screen.getByText(
380+
'You need to be member of at least one contact group to be able to create a password.'
381+
)
382+
).toBeInTheDocument()
383+
})
384+
385+
test('emits created when a contact group owner is selected', async () => {
386+
server.use(
387+
http.get(FORM_SPEC_URL, () =>
388+
HttpResponse.json({
389+
extensions: {
390+
schema: schemaWithCascadingOwner,
391+
default_values: {
392+
general_props: { id: 'my-password', title: 'My Password', comment: '', docu_url: '' },
393+
password_props: {
394+
password: 'secret',
395+
owned_by: ['contact_group', 'linux'],
396+
share_with: ''
397+
}
398+
}
399+
}
400+
})
401+
)
402+
)
403+
mockListPasswords()
404+
const { emitted } = render(PasswordStoreSlideIn, { props: { open: true } })
405+
406+
await flushPromises()
407+
await fireEvent.click(screen.getByRole('button', { name: 'Save' }))
408+
await flushPromises()
409+
410+
expect(emitted().created).toMatchObject([
411+
[{ password_props: { owned_by: ['contact_group', 'linux'] } }]
412+
])
413+
})
296414
})

0 commit comments

Comments
 (0)