mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-18 12:37:02 +02:00
* UI: HDS adoption replace AlertBanner part 1 (#21163) * rename test selector * replace db banner * add class * replace db role edit * db creds * generate creds * simpler class * license banner component * oidc callback plash * raft * aws * secret create or update * change to compact alert for form field * change back to inline * combine alert banners * wrap in conditional * remove references to message class * UI: HDS adoption replace AlertBanner part 2 (#21243) * token expire warning * delete css * edit form * item details distribute mfa step 2 transit verify * back to secondary * distribute * oidc lease error * sign * kv obj and repl dash * more repl * update test selector * show, creds * shamir * pki csr * pki banners * add hds library to ember engines * woops comma * fix k8 test * update message error component for last! * hold off MessageError changes until next pr * revert test selectors * update pki tests * UI: part 3 remove alert banner (#21334) * final component swap * and actual final of MessageError * update MessageError selectors * delete alert-banner and remove references * update next step alerts to highlight color * finishing touches, auth form test and client dashboard inline link * fix more selectors * fix shamir flow test * ui: part 4 final cleanup (#21365) * replace AlertPopup * add test tag * move tag * one more message error tag * delete alert popup * final css cleanup * move preformatted flash into <p> tag * ui: address comments for sidebranch (#21388) * add periods, move link to trailing * more periods and typo fix
553 lines
24 KiB
JavaScript
553 lines
24 KiB
JavaScript
/**
|
||
* Copyright (c) HashiCorp, Inc.
|
||
* SPDX-License-Identifier: MPL-2.0
|
||
*/
|
||
|
||
import { module, test } from 'qunit';
|
||
import { setupApplicationTest } from 'ember-qunit';
|
||
import { currentURL, settled, click, visit, fillIn, typeIn } from '@ember/test-helpers';
|
||
import { create } from 'ember-cli-page-object';
|
||
import { selectChoose, clickTrigger } from 'ember-power-select/test-support/helpers';
|
||
|
||
import mountSecrets from 'vault/tests/pages/settings/mount-secret-backend';
|
||
import connectionPage from 'vault/tests/pages/secrets/backend/database/connection';
|
||
import rolePage from 'vault/tests/pages/secrets/backend/database/role';
|
||
import apiStub from 'vault/tests/helpers/noop-all-api-requests';
|
||
import authPage from 'vault/tests/pages/auth';
|
||
import logout from 'vault/tests/pages/logout';
|
||
import consoleClass from 'vault/tests/pages/components/console/ui-panel';
|
||
import searchSelect from 'vault/tests/pages/components/search-select';
|
||
|
||
const searchSelectComponent = create(searchSelect);
|
||
|
||
const consoleComponent = create(consoleClass);
|
||
|
||
const MODEL = {
|
||
engineType: 'database',
|
||
id: 'database-name',
|
||
};
|
||
|
||
const mount = async () => {
|
||
const path = `database-${Date.now()}`;
|
||
await mountSecrets.enable('database', path);
|
||
await settled();
|
||
return path;
|
||
};
|
||
|
||
const newConnection = async (backend, plugin = 'mongodb-database-plugin') => {
|
||
const name = `connection-${Date.now()}`;
|
||
await connectionPage.visitCreate({ backend });
|
||
await connectionPage.dbPlugin(plugin);
|
||
await connectionPage.name(name);
|
||
await connectionPage.connectionUrl(`mongodb://127.0.0.1:4321/${name}`);
|
||
await connectionPage.toggleVerify();
|
||
await connectionPage.save();
|
||
await connectionPage.enable();
|
||
return name;
|
||
};
|
||
|
||
const connectionTests = [
|
||
{
|
||
name: 'elasticsearch-connection',
|
||
plugin: 'elasticsearch-database-plugin',
|
||
elasticUser: 'username',
|
||
elasticPassword: 'password',
|
||
url: 'http://127.0.0.1:9200',
|
||
requiredFields: async (assert, name) => {
|
||
assert.dom('[data-test-input="username"]').exists(`Username field exists for ${name}`);
|
||
assert.dom('[data-test-input="password"]').exists(`Password field exists for ${name}`);
|
||
assert.dom('[data-test-input="ca_cert"]').exists(`CA certificate field exists for ${name}`);
|
||
assert.dom('[data-test-input="ca_path"]').exists(`CA path field exists for ${name}`);
|
||
assert.dom('[data-test-input="client_cert"]').exists(`Client certificate field exists for ${name}`);
|
||
assert.dom('[data-test-input="client_key"]').exists(`Client key field exists for ${name}`);
|
||
assert.dom('[data-test-input="tls_server_name"]').exists(`TLS server name field exists for ${name}`);
|
||
assert.dom('[data-test-input="insecure"]').exists(`Insecure checkbox exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-toggle-input="show-username_template"]')
|
||
.exists(`Username template toggle exists for ${name}`);
|
||
},
|
||
},
|
||
{
|
||
name: 'mongodb-connection',
|
||
plugin: 'mongodb-database-plugin',
|
||
url: `mongodb://127.0.0.1:4321/test`,
|
||
requiredFields: async (assert, name) => {
|
||
assert.dom('[data-test-input="username"]').exists(`Username field exists for ${name}`);
|
||
assert.dom('[data-test-input="password"]').exists(`Password field exists for ${name}`);
|
||
assert.dom('[data-test-input="write_concern"]').exists(`Write concern field exists for ${name}`);
|
||
assert.dom('[data-test-toggle-group="TLS options"]').exists('TLS options toggle exists');
|
||
assert
|
||
.dom('[data-test-input="root_rotation_statements"]')
|
||
.exists(`Root rotation statements exists for ${name}`);
|
||
},
|
||
},
|
||
{
|
||
name: 'mssql-connection',
|
||
plugin: 'mssql-database-plugin',
|
||
url: `mssql://127.0.0.1:4321/test`,
|
||
requiredFields: async (assert, name) => {
|
||
assert.dom('[data-test-input="username"]').exists(`Username field exists for ${name}`);
|
||
assert.dom('[data-test-input="password"]').exists(`Password field exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_open_connections"]')
|
||
.exists(`Max open connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_idle_connections"]')
|
||
.exists(`Max idle connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_connection_lifetime"]')
|
||
.exists(`Max connection lifetime exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="root_rotation_statements"]')
|
||
.exists(`Root rotation statements exists for ${name}`);
|
||
},
|
||
},
|
||
{
|
||
name: 'mysql-connection',
|
||
plugin: 'mysql-database-plugin',
|
||
url: `{{username}}:{{password}}@tcp(127.0.0.1:3306)/test`,
|
||
requiredFields: async (assert, name) => {
|
||
assert.dom('[data-test-input="username"]').exists(`Username field exists for ${name}`);
|
||
assert.dom('[data-test-input="password"]').exists(`Password field exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_open_connections"]')
|
||
.exists(`Max open connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_idle_connections"]')
|
||
.exists(`Max idle connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_connection_lifetime"]')
|
||
.exists(`Max connection lifetime exists for ${name}`);
|
||
assert.dom('[data-test-toggle-group="TLS options"]').exists('TLS options toggle exists');
|
||
assert
|
||
.dom('[data-test-input="root_rotation_statements"]')
|
||
.exists(`Root rotation statements exists for ${name}`);
|
||
},
|
||
},
|
||
{
|
||
name: 'mysql-aurora-connection',
|
||
plugin: 'mysql-aurora-database-plugin',
|
||
url: `{{username}}:{{password}}@tcp(127.0.0.1:3306)/test`,
|
||
requiredFields: async (assert, name) => {
|
||
assert.dom('[data-test-input="username"]').exists(`Username field exists for ${name}`);
|
||
assert.dom('[data-test-input="password"]').exists(`Password field exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_open_connections"]')
|
||
.exists(`Max open connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_idle_connections"]')
|
||
.exists(`Max idle connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_connection_lifetime"]')
|
||
.exists(`Max connection lifetime exists for ${name}`);
|
||
assert.dom('[data-test-toggle-group="TLS options"]').exists('TLS options toggle exists');
|
||
assert
|
||
.dom('[data-test-input="root_rotation_statements"]')
|
||
.exists(`Root rotation statements exists for ${name}`);
|
||
},
|
||
},
|
||
{
|
||
name: 'mysql-rds-connection',
|
||
plugin: 'mysql-rds-database-plugin',
|
||
url: `{{username}}:{{password}}@tcp(127.0.0.1:3306)/test`,
|
||
requiredFields: async (assert, name) => {
|
||
assert.dom('[data-test-input="username"]').exists(`Username field exists for ${name}`);
|
||
assert.dom('[data-test-input="password"]').exists(`Password field exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_open_connections"]')
|
||
.exists(`Max open connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_idle_connections"]')
|
||
.exists(`Max idle connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_connection_lifetime"]')
|
||
.exists(`Max connection lifetime exists for ${name}`);
|
||
assert.dom('[data-test-toggle-group="TLS options"]').exists('TLS options toggle exists');
|
||
assert
|
||
.dom('[data-test-input="root_rotation_statements"]')
|
||
.exists(`Root rotation statements exists for ${name}`);
|
||
},
|
||
},
|
||
{
|
||
name: 'mysql-legacy-connection',
|
||
plugin: 'mysql-legacy-database-plugin',
|
||
url: `{{username}}:{{password}}@tcp(127.0.0.1:3306)/test`,
|
||
requiredFields: async (assert, name) => {
|
||
assert.dom('[data-test-input="username"]').exists(`Username field exists for ${name}`);
|
||
assert.dom('[data-test-input="password"]').exists(`Password field exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_open_connections"]')
|
||
.exists(`Max open connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_idle_connections"]')
|
||
.exists(`Max idle connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_connection_lifetime"]')
|
||
.exists(`Max connection lifetime exists for ${name}`);
|
||
assert.dom('[data-test-toggle-group="TLS options"]').exists('TLS options toggle exists');
|
||
assert
|
||
.dom('[data-test-input="root_rotation_statements"]')
|
||
.exists(`Root rotation statements exists for ${name}`);
|
||
},
|
||
},
|
||
{
|
||
name: 'postgresql-connection',
|
||
plugin: 'postgresql-database-plugin',
|
||
url: `postgresql://{{username}}:{{password}}@localhost:5432/postgres?sslmode=disable`,
|
||
requiredFields: async (assert, name) => {
|
||
assert.dom('[data-test-input="username"]').exists(`Username field exists for ${name}`);
|
||
assert.dom('[data-test-input="password"]').exists(`Password field exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_open_connections"]')
|
||
.exists(`Max open connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_idle_connections"]')
|
||
.exists(`Max idle connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_connection_lifetime"]')
|
||
.exists(`Max connection lifetime exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="root_rotation_statements"]')
|
||
.exists(`Root rotation statements exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-toggle-input="show-username_template"]')
|
||
.exists(`Username template toggle exists for ${name}`);
|
||
},
|
||
},
|
||
// keep oracle as last DB because it is skipped in some tests (line 285) the UI doesn't return to empty state after
|
||
{
|
||
name: 'oracle-connection',
|
||
plugin: 'vault-plugin-database-oracle',
|
||
url: `{{username}}/{{password}}@localhost:1521/OraDoc.localhost`,
|
||
requiredFields: async (assert, name) => {
|
||
assert.dom('[data-test-input="username"]').exists(`Username field exists for ${name}`);
|
||
assert.dom('[data-test-input="password"]').exists(`Password field exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_open_connections"]')
|
||
.exists(`Max open connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_idle_connections"]')
|
||
.exists(`Max idle connections exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="max_connection_lifetime"]')
|
||
.exists(`Max connection lifetime exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-input="root_rotation_statements"]')
|
||
.exists(`Root rotation statements exists for ${name}`);
|
||
assert
|
||
.dom('[data-test-database-oracle-alert]')
|
||
.hasTextContaining(
|
||
`Warning Please ensure that your Oracle plugin has the default name of vault-plugin-database-oracle. Custom naming is not supported in the UI at this time. If the plugin is already named vault-plugin-database-oracle, disregard this warning.`,
|
||
'warning banner displays for oracle plugin name'
|
||
);
|
||
},
|
||
},
|
||
];
|
||
|
||
module('Acceptance | secrets/database/*', function (hooks) {
|
||
setupApplicationTest(hooks);
|
||
|
||
hooks.beforeEach(async function () {
|
||
this.server = apiStub({ usePassthrough: true });
|
||
return authPage.login();
|
||
});
|
||
hooks.afterEach(function () {
|
||
this.server.shutdown();
|
||
});
|
||
|
||
test('can enable the database secrets engine', async function (assert) {
|
||
const backend = `database-${Date.now()}`;
|
||
await mountSecrets.enable('database', backend);
|
||
await settled();
|
||
assert.strictEqual(
|
||
currentURL(),
|
||
`/vault/secrets/${backend}/list`,
|
||
'Mounts and redirects to connection list page'
|
||
);
|
||
assert.dom('[data-test-component="empty-state"]').exists('Empty state exists');
|
||
assert
|
||
.dom('.active[data-test-secret-list-tab="Connections"]')
|
||
.exists('Has Connections tab which is active');
|
||
await click('[data-test-tab="overview"]');
|
||
assert.strictEqual(currentURL(), `/vault/secrets/${backend}/overview`, 'Tab links to overview page');
|
||
assert.dom('[data-test-component="empty-state"]').exists('Empty state also exists on overview page');
|
||
assert.dom('[data-test-secret-list-tab="Roles"]').exists('Has Roles tab');
|
||
});
|
||
|
||
test('Connection create and edit form for each plugin', async function (assert) {
|
||
assert.expect(161);
|
||
const backend = await mount();
|
||
for (const testCase of connectionTests) {
|
||
await connectionPage.visitCreate({ backend });
|
||
assert.strictEqual(currentURL(), `/vault/secrets/${backend}/create`, 'Correct creation URL');
|
||
assert
|
||
.dom('[data-test-empty-state-title]')
|
||
.hasText('No plugin selected', 'No plugin is selected by default and empty state shows');
|
||
await connectionPage.dbPlugin(testCase.plugin);
|
||
assert.dom('[data-test-empty-state]').doesNotExist('Empty state goes away after plugin selected');
|
||
await connectionPage.name(testCase.name);
|
||
if (testCase.plugin === 'elasticsearch-database-plugin') {
|
||
await connectionPage.url(testCase.url);
|
||
await connectionPage.username(testCase.elasticUser);
|
||
await connectionPage.password(testCase.elasticPassword);
|
||
} else {
|
||
await connectionPage.connectionUrl(testCase.url);
|
||
}
|
||
// skip adding oracle db connection since plugin doesn't exist
|
||
if (testCase.plugin === 'vault-plugin-database-oracle') {
|
||
testCase.requiredFields(assert, testCase.name);
|
||
continue;
|
||
}
|
||
testCase.requiredFields(assert, testCase.name);
|
||
await connectionPage.toggleVerify();
|
||
await connectionPage.save();
|
||
await settled();
|
||
assert
|
||
.dom('.modal.is-active .title')
|
||
.hasText('Rotate your root credentials?', 'Modal appears asking to rotate root credentials');
|
||
await connectionPage.enable();
|
||
assert.ok(
|
||
currentURL().startsWith(`/vault/secrets/${backend}/show/${testCase.name}`),
|
||
`Saves connection and takes you to show page for ${testCase.name}`
|
||
);
|
||
assert
|
||
.dom(`[data-test-row-value="Password"]`)
|
||
.doesNotExist(`Does not show Password value on show page for ${testCase.name}`);
|
||
await connectionPage.edit();
|
||
assert.ok(
|
||
currentURL().startsWith(`/vault/secrets/${backend}/edit/${testCase.name}`),
|
||
`Edit connection button and takes you to edit page for ${testCase.name}`
|
||
);
|
||
assert.dom(`[data-test-input="name"]`).hasAttribute('readonly');
|
||
assert.dom(`[data-test-input="plugin_name"]`).hasAttribute('readonly');
|
||
assert.dom('[data-test-input="password"]').doesNotExist('Password is not displayed on edit form');
|
||
assert.dom('[data-test-toggle-input="show-password"]').exists('Update password toggle exists');
|
||
await connectionPage.toggleVerify();
|
||
await connectionPage.save();
|
||
// click "Add Role"
|
||
await connectionPage.addRole();
|
||
await settled();
|
||
assert.strictEqual(
|
||
searchSelectComponent.selectedOptions[0].text,
|
||
testCase.name,
|
||
'Database connection is pre-selected on the form'
|
||
);
|
||
await click('[data-test-secret-breadcrumb]');
|
||
}
|
||
});
|
||
|
||
test('Can create and delete a connection', async function (assert) {
|
||
const backend = await mount();
|
||
const connectionDetails = {
|
||
plugin: 'mongodb-database-plugin',
|
||
id: 'horses-db',
|
||
fields: [
|
||
{ label: 'Connection name', name: 'name', value: 'horses-db' },
|
||
{ label: 'Connection URL', name: 'connection_url', value: 'mongodb://127.0.0.1:235/horses' },
|
||
{ label: 'Username', name: 'username', value: 'user', hideOnShow: true },
|
||
{ label: 'Password', name: 'password', password: 'so-secure', hideOnShow: true },
|
||
{ label: 'Write concern', name: 'write_concern' },
|
||
],
|
||
};
|
||
assert.strictEqual(
|
||
currentURL(),
|
||
`/vault/secrets/${backend}/list`,
|
||
'Mounts and redirects to connection list page'
|
||
);
|
||
await connectionPage.createLink();
|
||
assert.strictEqual(currentURL(), `/vault/secrets/${backend}/create`, 'Create link goes to create page');
|
||
assert
|
||
.dom('[data-test-empty-state-title]')
|
||
.hasText('No plugin selected', 'No plugin is selected by default and empty state shows');
|
||
await connectionPage.dbPlugin(connectionDetails.plugin);
|
||
assert.dom('[data-test-empty-state]').doesNotExist('Empty state goes away after plugin selected');
|
||
connectionDetails.fields.forEach(async ({ name, value }) => {
|
||
assert
|
||
.dom(`[data-test-input="${name}"]`)
|
||
.exists(`Field ${name} exists for ${connectionDetails.plugin}`);
|
||
if (value) {
|
||
await fillIn(`[data-test-input="${name}"]`, value);
|
||
}
|
||
});
|
||
// uncheck verify for the save step to work
|
||
await connectionPage.toggleVerify();
|
||
await connectionPage.save();
|
||
await settled();
|
||
assert
|
||
.dom('.modal.is-active .title')
|
||
.hasText('Rotate your root credentials?', 'Modal appears asking to ');
|
||
await connectionPage.enable();
|
||
assert.strictEqual(
|
||
currentURL(),
|
||
`/vault/secrets/${backend}/show/${connectionDetails.id}`,
|
||
'Saves connection and takes you to show page'
|
||
);
|
||
connectionDetails.fields.forEach(({ label, name, value, hideOnShow }) => {
|
||
if (hideOnShow) {
|
||
assert
|
||
.dom(`[data-test-row-value="${label}"]`)
|
||
.doesNotExist(`Does not show ${name} value on show page for ${connectionDetails.plugin}`);
|
||
} else if (!value) {
|
||
assert.dom(`[data-test-row-value="${label}"]`).hasText('Default');
|
||
} else {
|
||
assert.dom(`[data-test-row-value="${label}"]`).hasText(value);
|
||
}
|
||
});
|
||
await connectionPage.delete();
|
||
assert
|
||
.dom('.modal.is-active .title')
|
||
.hasText('Delete connection?', 'Modal appears asking to confirm delete action');
|
||
await fillIn('[data-test-confirmation-modal-input="Delete connection?"]', connectionDetails.id);
|
||
await click('[data-test-confirm-button]');
|
||
|
||
assert.strictEqual(currentURL(), `/vault/secrets/${backend}/list`, 'Redirects to connection list page');
|
||
assert
|
||
.dom('[data-test-empty-state-title]')
|
||
.hasText('No connections in this backend', 'No connections listed because it was deleted');
|
||
});
|
||
|
||
test('buttons show up for managing connection', async function (assert) {
|
||
const backend = await mount();
|
||
const connection = await newConnection(backend);
|
||
await connectionPage.visitShow({ backend, id: connection });
|
||
assert
|
||
.dom('[data-test-database-connection-delete]')
|
||
.hasText('Delete connection', 'Delete connection button exists with correct text');
|
||
assert
|
||
.dom('[data-test-database-connection-reset]')
|
||
.hasText('Reset connection', 'Reset button exists with correct text');
|
||
assert.dom('[data-test-secret-create]').hasText('Add role', 'Add role button exists with correct text');
|
||
assert.dom('[data-test-edit-link]').hasText('Edit configuration', 'Edit button exists with correct text');
|
||
const CONNECTION_VIEW_ONLY = `
|
||
path "${backend}/*" {
|
||
capabilities = ["deny"]
|
||
}
|
||
path "${backend}/config" {
|
||
capabilities = ["list"]
|
||
}
|
||
path "${backend}/config/*" {
|
||
capabilities = ["read"]
|
||
}
|
||
`;
|
||
await consoleComponent.runCommands([
|
||
`write sys/mounts/${backend} type=database`,
|
||
`write sys/policies/acl/test-policy policy=${btoa(CONNECTION_VIEW_ONLY)}`,
|
||
'write -field=client_token auth/token/create policies=test-policy ttl=1h',
|
||
]);
|
||
const token = consoleComponent.lastTextOutput;
|
||
await logout.visit();
|
||
await authPage.login(token);
|
||
await connectionPage.visitShow({ backend, id: connection });
|
||
assert.strictEqual(
|
||
currentURL(),
|
||
`/vault/secrets/${backend}/show/${connection}`,
|
||
'Allows reading connection'
|
||
);
|
||
assert
|
||
.dom('[data-test-database-connection-delete]')
|
||
.doesNotExist('Delete button does not show due to permissions');
|
||
assert
|
||
.dom('[data-test-database-connection-reset]')
|
||
.doesNotExist('Reset button does not show due to permissions');
|
||
assert.dom('[data-test-secret-create]').doesNotExist('Add role button does not show due to permissions');
|
||
assert.dom('[data-test-edit-link]').doesNotExist('Edit button does not show due to permissions');
|
||
await visit(`/vault/secrets/${backend}/overview`);
|
||
assert.dom('[data-test-selectable-card="Connections"]').exists('Connections card exists on overview');
|
||
assert
|
||
.dom('[data-test-selectable-card="Roles"]')
|
||
.doesNotExist('Roles card does not exist on overview w/ policy');
|
||
assert.dom('.title-number').hasText('1', 'Lists the correct number of connections');
|
||
// confirm get credentials card is an option to select. Regression bug.
|
||
await typeIn('.ember-text-field', 'blah');
|
||
assert.dom('[data-test-get-credentials]').isEnabled();
|
||
});
|
||
|
||
test('Role create form', async function (assert) {
|
||
const backend = await mount();
|
||
// Connection needed for role fields
|
||
await newConnection(backend);
|
||
await rolePage.visitCreate({ backend });
|
||
await rolePage.name('bar');
|
||
assert
|
||
.dom('[data-test-component="empty-state"]')
|
||
.exists({ count: 2 }, 'Two empty states exist before selections made');
|
||
await clickTrigger('#database');
|
||
assert.strictEqual(searchSelectComponent.options.length, 1, 'list shows existing connections so far');
|
||
await selectChoose('#database', '.ember-power-select-option', 0);
|
||
assert
|
||
.dom('[data-test-component="empty-state"]')
|
||
.exists({ count: 2 }, 'Two empty states exist before selections made');
|
||
await rolePage.roleType('static');
|
||
assert.dom('[data-test-component="empty-state"]').doesNotExist('Empty states go away');
|
||
assert.dom('[data-test-input="username"]').exists('Username field appears for static role');
|
||
assert
|
||
.dom('[data-test-toggle-input="Rotation period"]')
|
||
.exists('Rotation period field appears for static role');
|
||
await rolePage.roleType('dynamic');
|
||
assert
|
||
.dom('[data-test-toggle-input="Generated credentials’s Time-to-Live (TTL)"]')
|
||
.exists('TTL field exists for dynamic');
|
||
assert
|
||
.dom('[data-test-toggle-input="Generated credentials’s maximum Time-to-Live (Max TTL)"]')
|
||
.exists('Max TTL field exists for dynamic');
|
||
// Real connection (actual running db) required to save role, so we aren't testing that flow yet
|
||
});
|
||
|
||
test('root and limited access', async function (assert) {
|
||
this.set('model', MODEL);
|
||
const backend = 'database';
|
||
const NO_ROLES_POLICY = `
|
||
path "database/roles/*" {
|
||
capabilities = ["delete"]
|
||
}
|
||
path "database/static-roles/*" {
|
||
capabilities = ["delete"]
|
||
}
|
||
path "database/config/*" {
|
||
capabilities = ["list", "create", "read", "update"]
|
||
}
|
||
path "database/creds/*" {
|
||
capabilities = ["list", "create", "read", "update"]
|
||
}
|
||
`;
|
||
await consoleComponent.runCommands([
|
||
`write sys/mounts/${backend} type=database`,
|
||
`write sys/policies/acl/test-policy policy=${btoa(NO_ROLES_POLICY)}`,
|
||
'write -field=client_token auth/token/create policies=test-policy ttl=1h',
|
||
]);
|
||
const token = consoleComponent.lastTextOutput;
|
||
|
||
// test root user flow
|
||
await settled();
|
||
|
||
// await click('[data-test-secret-backend-row="database"]');
|
||
// skipping the click because occasionally is shows up on the second page and cannot be found
|
||
await visit(`/vault/secrets/database/overview`);
|
||
|
||
assert.dom('[data-test-component="empty-state"]').exists('renders empty state');
|
||
assert.dom('[data-test-secret-list-tab="Connections"]').exists('renders connections tab');
|
||
assert.dom('[data-test-secret-list-tab="Roles"]').exists('renders connections tab');
|
||
|
||
await click('[data-test-secret-create="connections"]');
|
||
assert.strictEqual(currentURL(), '/vault/secrets/database/create');
|
||
|
||
// Login with restricted policy
|
||
await logout.visit();
|
||
await authPage.login(token);
|
||
await settled();
|
||
// skipping the click because occasionally is shows up on the second page and cannot be found
|
||
await visit(`/vault/secrets/database/overview`);
|
||
assert.dom('[data-test-tab="overview"]').exists('renders overview tab');
|
||
assert.dom('[data-test-secret-list-tab="Connections"]').exists('renders connections tab');
|
||
assert
|
||
.dom('[data-test-secret-list-tab="Roles"]')
|
||
.doesNotExist(`does not show the roles tab because it does not have permissions`);
|
||
assert
|
||
.dom('[data-test-selectable-card="Connections"]')
|
||
.exists({ count: 1 }, 'renders only the connection card');
|
||
|
||
await click('[data-test-action-text="Configure new"]');
|
||
assert.strictEqual(currentURL(), '/vault/secrets/database/create?itemType=connection');
|
||
});
|
||
});
|