diff --git a/ui/app/components/page/policies.ts b/ui/app/components/page/policies.ts index 22af985125..a37a1bd3a2 100644 --- a/ui/app/components/page/policies.ts +++ b/ui/app/components/page/policies.ts @@ -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 { } 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 diff --git a/ui/e2e/tests/superuser/kv.spec.ts b/ui/e2e/tests/superuser/kv.spec.ts index 7249ca4b46..15fa331167 100644 --- a/ui/e2e/tests/superuser/kv.spec.ts +++ b/ui/e2e/tests/superuser/kv.spec.ts @@ -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" "" { name = "foo-policy" policy = < { + 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(); +}); diff --git a/ui/e2e/tests/superuser/policies.spec.ts b/ui/e2e/tests/superuser/policies.spec.ts new file mode 100644 index 0000000000..2294bbeb91 --- /dev/null +++ b/ui/e2e/tests/superuser/policies.spec.ts @@ -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" "" { name = "acl-policy" policy = <