UI: add playwright test coverage for policies (#12860) (#12947)

* add playwright test coverage for policies

* add playwright test coverage for policy generator in kv v2

* only show intro button for acl policies

* separate ent tests

Co-authored-by: lane-wetmore <lane.wetmore@hashicorp.com>
This commit is contained in:
Vault Automation 2026-03-12 18:20:40 -04:00 committed by GitHub
parent 4f71c2cde0
commit 6208c6a416
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 192 additions and 1 deletions

View file

@ -9,6 +9,7 @@ import { tracked } from '@glimmer/tracking';
import Component from '@glimmer/component';
import { WIZARD_ID } from 'vault/components/wizard/acl-policies/acl-wizard';
import errorMessage from 'vault/utils/error-message';
import { PolicyTypes } from 'core/utils/code-generators/policy';
import type ApiService from 'vault/services/api';
import type FlashMessageService from 'vault/services/flash-messages';
@ -88,7 +89,7 @@ export default class PagePoliciesComponent extends Component<Args> {
}
get showIntroButton() {
return this.showContent && this.hasOnlyDefaultPolicies;
return this.args.policyType === PolicyTypes.ACL && this.showContent && this.hasOnlyDefaultPolicies;
}
// Show when it is not in a dismissed state and there are no non-default policies and

View file

@ -126,4 +126,21 @@ test('kvv2 workflow', async ({ page }) => {
await expect(page.locator('section')).toContainText(
'Version 1 of this secret has been permanently destroyed A version that has been permanently deleted cannot be restored. You can view other versions of this secret in the Version History tab above. KV v2 API docs'
);
// generate policy
await page.getByRole('button', { name: 'Generate policy' }).click();
await page.getByRole('textbox', { name: 'Policy name' }).fill('foo-policy');
await page.getByRole('checkbox', { name: 'sudo' }).nth(0).check();
await page.getByRole('checkbox', { name: 'read' }).nth(1).check();
await page.getByRole('checkbox', { name: 'list' }).nth(2).check();
await page.getByRole('button', { name: 'Delete' }).nth(3).click();
await page.getByRole('button', { name: 'Add rule' }).click();
await page.getByRole('textbox', { name: 'Resource path' }).nth(5).fill('kv-test/nomatch');
await page.getByRole('checkbox', { name: 'create' }).nth(5).check();
await page.getByRole('button', { name: 'Automation snippets' }).click();
await expect(page.getByRole('code')).toContainText(
'resource "vault_policy" "<local identifier>" { name = "foo-policy" policy = <<EOT path "kv-test/metadata/foo" { capabilities = ["sudo"] } path "kv-test/data/foo" { capabilities = ["read"] } path "kv-test/subkeys/foo" { capabilities = ["list"] } path "kv-test/undelete/foo" { capabilities = [] } path "kv-test/destroy/foo" { capabilities = [] } path "kv-test/nomatch" { capabilities = ["create"] } EOT }'
);
await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('link', { name: 'View policy' }).click();
await expect(page.getByRole('heading', { name: 'foo-policy' })).toBeVisible();
});

View file

@ -0,0 +1,99 @@
/**
* Copyright IBM Corp. 2016, 2025
* SPDX-License-Identifier: BUSL-1.1
*/
import { test, expect } from '@playwright/test';
test('rgp policy workflow', async ({ page }) => {
await page.goto('dashboard');
// nav to rgp policies and create a policy
await page.getByRole('link', { name: 'Access control' }).click();
await page.getByRole('link', { name: 'Role governing policies' }).click();
await page.getByRole('heading', { name: 'RGP policies', exact: true }).click();
await page.getByRole('link', { name: 'Create RGP policy' }).click();
await page.getByRole('textbox', { name: 'Policy name' }).fill('rgp-policy');
await page.getByRole('button', { name: 'How to write a policy' }).click();
await page.getByText('Here is an example policy').click();
await page.getByRole('button', { name: 'Copy' }).nth(1).click();
// access the clipboard to get the example policy
const clipboardValue = await page.evaluate(() => navigator.clipboard.readText());
await page.getByRole('button', { name: 'Close' }).click();
await page.getByRole('textbox', { name: 'Policy editor' }).fill(clipboardValue);
await page.getByLabel('Enforcement level').selectOption('advisory');
await page.getByRole('button', { name: 'Create policy' }).click();
await page.getByRole('heading', { name: 'rgp-policy' }).click();
await page.getByRole('button', { name: 'Download policy' }).click();
await expect(page.getByRole('alert', { name: 'Info' })).toBeVisible();
await expect(page.getByLabel('Enforcement level: advisory')).toBeVisible();
// edit
await page.getByRole('link', { name: 'Edit policy' }).click();
await page.getByLabel('Policy').clear();
const updatedValue = clipboardValue + '\n# just a comment';
await page.getByLabel('Policy').fill(updatedValue);
await page.getByLabel('Enforcement level', { exact: true }).selectOption('hard-mandatory');
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByLabel('Enforcement level: hard-')).toBeVisible();
await expect(page.getByRole('code')).toContainText('# just a comment');
// delete
await page.getByRole('link', { name: 'Edit policy' }).click();
await page.getByRole('button', { name: 'Delete policy' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
await expect(page.getByRole('link', { name: 'rgp-policy', exact: true })).not.toBeVisible();
});
test('egp policy workflow', async ({ page }) => {
await page.goto('dashboard');
// nav to egp policies and create a policy
await page.getByRole('link', { name: 'Access control' }).click();
await page.getByRole('link', { name: 'Endpoint governing policies' }).click();
await page.getByRole('heading', { name: 'EGP policies', exact: true }).click();
await page.getByRole('link', { name: 'Create EGP policy' }).click();
await page.getByRole('textbox', { name: 'Policy name' }).fill('egp-policy');
await page.getByRole('button', { name: 'How to write a policy' }).click();
await page.getByText('Here is an example policy').click();
await page.getByRole('button', { name: 'Copy' }).nth(1).click();
// access the clipboard to get the example policy
const clipboardValue = await page.evaluate(() => navigator.clipboard.readText());
await page.getByRole('button', { name: 'Close' }).click();
await page.getByRole('textbox', { name: 'Policy editor' }).fill(clipboardValue);
await page.getByLabel('Enforcement level').selectOption('advisory');
await page.getByRole('textbox', { name: 'Paths list item' }).fill('foo');
await page.getByRole('button', { name: 'Add' }).click();
await page.getByRole('textbox', { name: 'Paths list item 1' }).fill('bar');
await page.getByRole('button', { name: 'Add' }).click();
await page.getByRole('button', { name: 'Create policy' }).click();
await page.getByRole('heading', { name: 'egp-policy' }).click();
await page.getByRole('button', { name: 'Download policy' }).click();
await expect(page.getByRole('alert', { name: 'Info' })).toBeVisible();
await expect(page.getByLabel('Enforcement level: advisory')).toBeVisible();
await expect(page.getByRole('listitem').filter({ hasText: 'foo' })).toBeVisible();
await expect(page.getByRole('listitem').filter({ hasText: 'bar' })).toBeVisible();
// edit
await page.getByRole('link', { name: 'Edit policy' }).click();
await page.getByLabel('Policy').clear();
const updatedValue = clipboardValue + '\n# just a comment';
await page.getByLabel('Policy').fill(updatedValue);
await page.getByLabel('Enforcement level', { exact: true }).selectOption('hard-mandatory');
await page.getByRole('button', { name: 'delete row' }).nth(1).click();
await page.getByRole('textbox', { name: 'Paths list item 1' }).fill('baz');
await page.getByRole('button', { name: 'Add' }).click();
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByLabel('Enforcement level: hard-')).toBeVisible();
await page.getByRole('button', { name: 'Show more code' }).click();
await expect(page.getByText('# just a comment')).toBeVisible();
await expect(page.getByRole('listitem').filter({ hasText: 'foo' })).toBeVisible();
await expect(page.getByRole('listitem').filter({ hasText: 'bar' })).not.toBeVisible();
await expect(page.getByRole('listitem').filter({ hasText: 'baz' })).toBeVisible();
// delete
await page.getByRole('link', { name: 'Edit policy' }).click();
await page.getByRole('button', { name: 'Delete policy' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
await expect(page.getByRole('link', { name: 'egp-policy', exact: true })).not.toBeVisible();
});

View file

@ -0,0 +1,74 @@
/**
* Copyright IBM Corp. 2016, 2025
* SPDX-License-Identifier: BUSL-1.1
*/
import { test, expect } from '@playwright/test';
test('acl policy workflow', async ({ page }) => {
await page.goto('dashboard');
// nav to acl policies and create a policy
await page.getByRole('link', { name: 'Access control' }).click();
await page.getByRole('link', { name: 'Create ACL policy' }).click();
await page.getByRole('textbox', { name: 'Policy name' }).fill('acl-policy');
await page.getByRole('textbox', { name: 'Resource path' }).fill('kv');
await page.getByRole('checkbox', { name: 'read' }).check();
await page.getByRole('checkbox', { name: 'update' }).check();
await page.getByRole('switch', { name: 'Show preview' }).click();
await expect(page.getByRole('code')).toContainText('path "kv" { capabilities = ["read", "update"] }');
await page.getByRole('switch', { name: 'Hide preview' }).click();
await page.getByRole('button', { name: 'Add rule' }).click();
await page.getByRole('textbox', { name: 'Resource path' }).nth(1).fill('pki');
await page.getByRole('checkbox', { name: 'list' }).nth(1).check();
await page.getByRole('checkbox', { name: 'patch' }).nth(1).check();
await page.getByRole('button', { name: 'Add rule' }).click();
await page.getByRole('textbox', { name: 'Resource path' }).nth(2).fill('totp');
await page.getByRole('checkbox', { name: 'create' }).nth(2).check();
// check snippets
await page.getByRole('button', { name: 'Automation snippets' }).click();
await expect(page.getByRole('code')).toContainText(
'resource "vault_policy" "<local identifier>" { name = "acl-policy" policy = <<EOT path "kv" { capabilities = ["read", "update"] } path "pki" { capabilities = ["list", "patch"] } path "totp" { capabilities = ["create"] } EOT }'
);
await page.getByRole('tab', { name: 'CLI' }).click();
await expect(page.getByText('vault policy write acl-policy')).toBeVisible();
await page.getByRole('button', { name: 'Delete' }).nth(2).click();
await expect(page.getByRole('code')).toContainText(
'vault policy write acl-policy - <<EOT path "kv" { capabilities = ["read", "update"] } path "pki" { capabilities = ["list", "patch"] } EOT'
);
// check change detection
await page.getByRole('radio', { name: 'Code editor' }).check();
await expect(page.getByRole('heading', { name: 'Policy editor' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Switch and discard changes' })).not.toBeVisible();
await page.getByRole('radio', { name: 'Visual editor' }).check();
await page.getByRole('radio', { name: 'Code editor' }).check();
await page.getByRole('textbox', { name: 'Policy editor' }).clear();
await page
.getByRole('textbox', { name: 'Policy editor' })
.fill(
'vault policy write acl-policy - <<EOT path "kv" { capabilities = ["read"] } path "pki" { capabilities = ["list", "patch"] } EOT'
);
await page.getByRole('radio', { name: 'Visual editor' }).click();
await page.getByRole('button', { name: 'Switch and discard changes' }).click();
await expect(page.getByRole('code')).toContainText(
'EOT path "kv" { capabilities = ["read", "update"] } path "pki" { capabilities = ["list", "patch"] } EOT'
);
await page.getByRole('button', { name: 'Create policy' }).click();
await expect(page.getByRole('heading', { name: 'acl-policy' })).toBeVisible();
await page.getByRole('button', { name: 'Download policy' }).click();
await expect(page.getByRole('alert', { name: 'Info' })).toBeVisible();
await expect(page.getByText('Policy HCL format')).toBeVisible();
await expect(page.getByRole('button', { name: 'Automation snippets' })).toBeVisible();
// edit
await page.getByRole('link', { name: 'Edit policy' }).click();
await page.getByLabel('Policy').clear();
await page.getByLabel('Policy').fill('path "kv" { capabilities = ["read", "update"] }');
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByLabel('Policy')).toContainText('path "kv" { capabilities = ["read", "update"] }');
// delete
await page.getByRole('link', { name: 'Edit policy' }).click();
await page.getByRole('button', { name: 'Delete policy' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
await expect(page.getByRole('link', { name: 'acl-policy', exact: true })).not.toBeVisible();
});