[VAULT-42686] UI: add playwright coverage for keymgmt binary tests (#12906) (#12950)

* [VAULT-42686] UI: add playwright coverage for keymgmt binary tests

* use test.step instead of comments

* cleanup

Co-authored-by: Shannon Roberts (Beagin) <beagins@users.noreply.github.com>
This commit is contained in:
Vault Automation 2026-03-12 14:16:30 -04:00 committed by GitHub
parent cd2c9b0304
commit 7f893c6ea3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 426 additions and 0 deletions

View File

@ -0,0 +1,136 @@
/**
* Copyright IBM Corp. 2016, 2025
* SPDX-License-Identifier: BUSL-1.1
*/
import { expect, test } from '@playwright/test';
const PINNED_PLUGIN_DATA = {
data: {
name: 'vault-plugin-secrets-keymgmt',
type: 'secret',
version: 'v0.17.0+ent',
},
};
const PLUGIN_CATALOG_DATA = {
request_id: 'request_id',
lease_id: '',
renewable: false,
lease_duration: 0,
data: {
detailed: [
{
builtin: true,
deprecation_status: 'supported',
name: 'keymgmt',
type: 'secret',
version: 'v0.18.1+builtin',
},
{
builtin: false,
name: 'vault-plugin-secrets-keymgmt',
sha256: 'sha256',
type: 'secret',
version: '',
},
{
builtin: false,
name: 'vault-plugin-secrets-keymgmt',
sha256: 'sha256',
type: 'secret',
version: 'v0.16.0+ent',
},
{
builtin: false,
name: 'vault-plugin-secrets-keymgmt',
sha256: 'sha256',
type: 'secret',
version: 'v0.17.0+ent',
},
{
builtin: false,
name: 'vault-plugin-secrets-keymgmt',
sha256: 'sha256',
type: 'secret',
version: 'v0.18.0+ent',
},
],
},
};
test('mount external keymgmt workflow', async ({ page }) => {
await test.step('mock the keymgmt pinned version response', async () => {
await page.route('**v1/sys/plugins/pins/secret/vault-plugin-secrets-keymgmt', async (route) => {
if (route.request().method() === 'GET') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(PINNED_PLUGIN_DATA),
});
} else {
await route.continue();
}
});
});
await test.step('mock the plugin catalog response to return builtin and external keymgmt plugins', async () => {
await page.route('**v1/sys/plugins/catalog', async (route) => {
if (route.request().method() === 'GET') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(PLUGIN_CATALOG_DATA),
});
} else {
await route.continue();
}
});
});
await page.goto('dashboard');
await test.step('navigate to enable Key Management engine', async () => {
await page.getByRole('link', { name: 'Secrets', exact: true }).click();
await page.getByRole('link', { name: 'Enable new engine' }).click();
await page.getByLabel('Key Management - enabled').click();
await page.getByRole('textbox', { name: 'Path' }).fill('keymgmt-external');
});
await test.step('verify builtin and external plugin type options are visible', async () => {
await expect(page.getByText('Built-in plugin Preregistered')).toBeVisible();
await expect(page.getByText('External plugin External')).toBeVisible();
await expect(page.getByText('Plugin version Required')).not.toBeVisible();
});
await test.step('selecting external plugin type shows plugin version dropdown', async () => {
await page.locator('label:nth-child(2) > .hds-form-radio-card__control-wrapper').click();
await expect(page.getByText('Plugin version Required')).toBeVisible();
await expect(page.getByLabel('Plugin version Required')).toContainText(
'v0.17.0+ent (pinned) v0.16.0+ent v0.18.0+ent'
);
});
await test.step('pinned version is selected by default with no warning', async () => {
await expect(page.getByLabel('Version differs from pinned')).not.toBeVisible();
});
await test.step('selecting a non-pinned version shows a warning', async () => {
await page.getByLabel('Plugin version Required').selectOption('v0.16.0+ent');
await expect(page.getByLabel('Version differs from pinned')).toContainText(
'You have selected v0.16.0+ent, but version v0.17.0+ent is pinned for this plugin. Enabling the engine with this version will override the pinned version for this mount.'
);
});
await test.step('re-selecting the pinned version clears the warning', async () => {
await page.getByLabel('Plugin version Required').selectOption('v0.17.0+ent');
await expect(page.getByLabel('Version differs from pinned')).not.toBeVisible();
});
await test.step('enabling engine shows error with external plugin name', async () => {
await page.getByRole('button', { name: 'Enable engine' }).click();
await expect(page.getByLabel('Error')).toContainText(
'plugin not found in the catalog: vault-plugin-secrets-keymgmt'
);
});
});

View File

@ -0,0 +1,204 @@
/**
* Copyright IBM Corp. 2016, 2025
* SPDX-License-Identifier: BUSL-1.1
*/
import { expect, test } from '@playwright/test';
const PINNED_PLUGIN_DATA = {
data: {
name: 'vault-plugin-secrets-keymgmt',
type: 'secret',
version: 'v0.17.0+ent',
},
};
const PLUGIN_CATALOG_DATA = {
request_id: 'request_id',
lease_id: '',
renewable: false,
lease_duration: 0,
data: {
detailed: [
{
builtin: true,
deprecation_status: 'supported',
name: 'keymgmt',
type: 'secret',
version: 'v0.18.1+builtin',
},
{
builtin: false,
name: 'vault-plugin-secrets-keymgmt',
sha256: 'sha256',
type: 'secret',
version: '',
},
{
builtin: false,
name: 'vault-plugin-secrets-keymgmt',
sha256: 'sha256',
type: 'secret',
version: 'v0.16.0+ent',
},
{
builtin: false,
name: 'vault-plugin-secrets-keymgmt',
sha256: 'sha256',
type: 'secret',
version: 'v0.17.0+ent',
},
{
builtin: false,
name: 'vault-plugin-secrets-keymgmt',
sha256: 'sha256',
type: 'secret',
version: 'v0.18.0+ent',
},
],
},
};
const KEYMGMT_EXTERNAL_MOUNT_DATA = {
request_id: 'request_id',
lease_id: '',
renewable: false,
lease_duration: 0,
data: {
accessor: 'vault-plugin-secrets-keymgmt_accessor',
config: {
default_lease_ttl: 2764800,
force_no_cache: false,
listing_visibility: 'hidden',
max_lease_ttl: 2764800,
},
description: '',
external_entropy_access: false,
local: false,
options: {},
path: 'keymgmt-external/',
plugin_version: 'v0.17.0+ent',
running_plugin_version: 'v0.17.0+ent',
running_sha256: 'sha256',
seal_wrap: false,
type: 'vault-plugin-secrets-keymgmt',
uuid: 'uuid',
},
wrap_info: null,
warnings: null,
auth: null,
mount_type: '',
};
const UPDATED_KEYMGMT_EXTERNAL_MOUNT_DATA = {
...KEYMGMT_EXTERNAL_MOUNT_DATA,
data: {
...KEYMGMT_EXTERNAL_MOUNT_DATA.data,
plugin_version: 'v0.18.0+ent',
running_plugin_version: 'v0.18.0+ent',
},
};
test('tune external keymgmt workflow', async ({ page }) => {
await test.step('mock the keymgmt pinned version response', async () => {
await page.route('**v1/sys/plugins/pins/secret/vault-plugin-secrets-keymgmt', async (route) => {
if (route.request().method() === 'GET') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(PINNED_PLUGIN_DATA),
});
} else {
await route.continue();
}
});
});
await test.step('mock the plugin catalog response to return builtin and external keymgmt plugins', async () => {
await page.route('**v1/sys/plugins/catalog', async (route) => {
if (route.request().method() === 'GET') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(PLUGIN_CATALOG_DATA),
});
} else {
await route.continue();
}
});
});
await test.step('mock the keymgmt external mount response', async () => {
await page.route('**/v1/sys/internal/ui/mounts/keymgmt-external', async (route) => {
if (route.request().method() === 'GET') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(KEYMGMT_EXTERNAL_MOUNT_DATA),
});
} else {
await route.continue();
}
});
});
await test.step('mock the initial keymgmt external tunde response', async () => {
await page.route('**/v1/sys/mounts/keymgmt-external/tune', async (route) => {
if (route.request().method() === 'POST') {
await route.fulfill({
status: 204,
contentType: 'application/json',
});
} else {
await route.continue();
}
});
});
await page.goto('dashboard');
await test.step("navigate to the external keymgmt mount's general settings page", async () => {
await page.goto('secrets-engines/keymgmt-external/list');
await page.getByRole('button', { name: 'Manage' }).click();
await page.getByRole('link', { name: 'Configure' }).click();
await expect(page.getByRole('heading', { level: 1 })).toContainText('keymgmt-external configuration');
await expect(page.getByRole('link', { name: 'General settings' })).toBeVisible();
await expect(page.getByRole('paragraph').nth(2)).toContainText('vault-plugin-secrets-keymgmt');
await expect(page.getByRole('paragraph').nth(3)).toContainText('v0.17.0+ent (Pinned)');
});
await test.step('verify that selecting an unpinned version shows the override message', async () => {
await page.getByLabel('Update version to:').selectOption('v0.16.0+ent');
await expect(page.getByLabel('Override pinned version')).toContainText(
'You have selected v0.16.0+ent, but version v0.17.0+ent is pinned for this plugin. Updating to this version will override the pinned version for this mount.'
);
});
await test.step('reset the version selection and verify that the override message goes away', async () => {
await page.getByLabel('Update version to:').selectOption('');
await expect(page.getByLabel('Override pinned version')).not.toBeVisible();
});
await test.step('verify that selecting an unpinned version shows the override message', async () => {
await page.getByLabel('Update version to:').selectOption('v0.18.0+ent');
await expect(page.getByLabel('Override pinned version')).toContainText(
'You have selected v0.18.0+ent, but version v0.17.0+ent is pinned for this plugin. Updating to this version will override the pinned version for this mount.'
);
});
await test.step('mock updated mount response after tuning with a new plugin version', async () => {
await page.route('**/v1/sys/internal/ui/mounts/keymgmt-external', async (route) => {
if (route.request().method() === 'GET') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(UPDATED_KEYMGMT_EXTERNAL_MOUNT_DATA),
});
} else {
await route.continue();
}
});
});
await page.getByRole('button', { name: 'Save changes' }).click();
});

View File

@ -0,0 +1,86 @@
/**
* Copyright IBM Corp. 2016, 2025
* SPDX-License-Identifier: BUSL-1.1
*/
import { expect, test } from '@playwright/test';
test('keymgmt workflow', async ({ page }) => {
await test.step('mock the distribution response', async () => {
await page.route('**/v1/keymgmt-builtin/kms/test-provider/key/test-key', async (route) => {
if (route.request().method() === 'PUT') {
await route.fulfill({
status: 200,
contentType: 'application/json',
});
} else {
await route.continue();
}
});
});
await page.goto('dashboard');
await test.step('enable Key Management secrets engine', async () => {
await page.getByRole('link', { name: 'Secrets', exact: true }).click();
await page.getByRole('link', { name: 'Enable new engine' }).click();
await page.getByLabel('Key Management - enabled').click();
await page.getByRole('textbox', { name: 'Path' }).fill('keymgmt-builtin');
await page.getByRole('button', { name: 'Method Options' }).click();
await page.getByRole('textbox', { name: 'Description' }).fill('This is a keymgmt mount.');
await page.getByRole('checkbox', { name: 'Local' }).check();
await page.getByRole('button', { name: 'Enable engine' }).click();
await expect(page.getByText('Success', { exact: true })).toBeVisible();
await expect(
page.getByText('Successfully mounted the keymgmt secrets engine at keymgmt-builtin')
).toBeVisible();
await page.getByRole('button', { name: 'Dismiss' }).click();
});
await test.step('create a provider', async () => {
await page.getByRole('link', { name: 'Create provider' }).click();
await page.getByLabel('Type').selectOption('azurekeyvault');
await page.getByRole('textbox', { name: 'Provider name' }).fill('test-provider');
await page.getByRole('textbox', { name: 'Key Vault instance name' }).fill('keyvault-name');
await page.getByRole('textbox', { name: 'client_id' }).fill('a0454cd1-e28e-405e-bc50-7477fa8a00b7');
await page.getByRole('textbox', { name: 'client_secret' }).fill('eR%HizuCVEpAKgeaUEx');
await page.getByRole('textbox', { name: 'tenant_id' }).fill('cd4bf224-d114-4f96-9bbc-b8f45751c43f');
await page.getByRole('button', { name: 'Create provider' }).click();
await expect(page.locator('span').filter({ hasText: 'test-provider' })).toBeVisible();
await expect(page.getByText('Azure Key Vault')).toBeVisible();
await expect(page.getByText('keyvault-name')).toBeVisible();
await expect(page.getByText('None')).toBeVisible();
});
await test.step('create a key', async () => {
await page.getByRole('link', { name: 'Keys' }).click();
await page.getByRole('link', { name: 'Create key' }).click();
await page.getByRole('textbox', { name: 'Key name' }).fill('test-key');
await page.getByRole('checkbox', { name: 'Allow deletion' }).check();
await page.getByRole('button', { name: 'Create key' }).click();
await expect(page.locator('section')).toContainText('test-key');
await expect(page.locator('section')).toContainText('rsa-2048');
await expect(page.locator('section')).toContainText('Yes');
});
await test.step('distribute key to provider', async () => {
await page.getByLabel('toolbar actions').getByRole('button', { name: 'Distribute key' }).click();
await page.getByText('Search').click();
await page.getByRole('option', { name: 'test-provider' }).click();
await page.getByText('Encrypt').click();
await page.getByText('Decrypt').click();
await page.getByText('Sign').click();
await page.getByText('Verify').click();
await page.getByText('Wrap', { exact: true }).click();
await page.getByText('Unwrap').click();
await page.getByRole('radio', { name: 'HSM' }).check();
await page.getByRole('button', { name: 'Distribute key' }).click();
await expect(page.getByText('Success', { exact: true })).toBeVisible();
await expect(page.getByText('Successfully distributed key test-key to test-provider')).toBeVisible();
await page.getByRole('button', { name: 'Dismiss' }).click();
});
});