|
|
|
@ -6,6 +6,7 @@ import {
|
|
|
|
|
currentRouteName,
|
|
|
|
|
fillIn,
|
|
|
|
|
triggerKeyEvent,
|
|
|
|
|
typeIn,
|
|
|
|
|
} from '@ember/test-helpers';
|
|
|
|
|
import { create } from 'ember-cli-page-object';
|
|
|
|
|
import { module, test } from 'qunit';
|
|
|
|
@ -69,15 +70,113 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
|
|
|
|
assert.ok(showPage.editIsPresent, 'shows the edit button');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('it can create a secret with a non default max version', async function(assert) {
|
|
|
|
|
test('it can create a secret with a non default max version and add metadata', async function(assert) {
|
|
|
|
|
let enginePath = `kv-${new Date().getTime()}`;
|
|
|
|
|
let secretPath = 'maxVersions';
|
|
|
|
|
let maxVersions = 101;
|
|
|
|
|
await mountSecrets.visit();
|
|
|
|
|
await mountSecrets.enable('kv', enginePath);
|
|
|
|
|
await settled();
|
|
|
|
|
await click('[data-test-secret-create="true"]');
|
|
|
|
|
await fillIn('[data-test-secret-path="true"]', secretPath);
|
|
|
|
|
await editPage.startCreateSecret();
|
|
|
|
|
await editPage.path(secretPath);
|
|
|
|
|
await editPage.toggleMetadata();
|
|
|
|
|
await settled();
|
|
|
|
|
await editPage.maxVersion(maxVersions);
|
|
|
|
|
await settled();
|
|
|
|
|
await editPage.save();
|
|
|
|
|
await settled();
|
|
|
|
|
await editPage.metadataTab();
|
|
|
|
|
await settled();
|
|
|
|
|
let savedMaxVersions = Number(
|
|
|
|
|
document.querySelector('[data-test-value-div="Maximum versions"]').innerText
|
|
|
|
|
);
|
|
|
|
|
assert.equal(
|
|
|
|
|
maxVersions,
|
|
|
|
|
savedMaxVersions,
|
|
|
|
|
'max_version displays the saved number set when creating the secret'
|
|
|
|
|
);
|
|
|
|
|
// add metadata
|
|
|
|
|
await click('[data-test-add-custom-metadata]');
|
|
|
|
|
await fillIn('[data-test-kv-key]', 'key');
|
|
|
|
|
await fillIn('[data-test-kv-value]', 'value');
|
|
|
|
|
await click('[data-test-save-metadata]');
|
|
|
|
|
let key = document.querySelector('[data-test-row-label="key"]').innerText;
|
|
|
|
|
let value = document.querySelector('[data-test-row-value="key"]').innerText;
|
|
|
|
|
assert.equal(key, 'key', 'metadata key displays after adding it.');
|
|
|
|
|
assert.equal(value, 'value', 'metadata value displays after adding it.');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('it can handle validation on custom metadata', async function(assert) {
|
|
|
|
|
let enginePath = `kv-${new Date().getTime()}`;
|
|
|
|
|
let secretPath = 'customMetadataValidations';
|
|
|
|
|
|
|
|
|
|
await mountSecrets.visit();
|
|
|
|
|
await mountSecrets.enable('kv', enginePath);
|
|
|
|
|
await settled();
|
|
|
|
|
await editPage.startCreateSecret();
|
|
|
|
|
await editPage.path(secretPath);
|
|
|
|
|
await editPage.toggleMetadata();
|
|
|
|
|
await settled();
|
|
|
|
|
await typeIn('[data-test-kv-value]', 'invalid\\/');
|
|
|
|
|
assert
|
|
|
|
|
.dom('[data-test-inline-error-message]')
|
|
|
|
|
.hasText('Custom values cannot contain a backward slash.', 'will not allow backward slash in value.');
|
|
|
|
|
//remove validation error and cause another error that is captured by the API
|
|
|
|
|
await fillIn('[data-test-kv-value]', 'removed');
|
|
|
|
|
await typeIn('[data-test-kv-value]', '!');
|
|
|
|
|
await click('[data-test-secret-save="true"]');
|
|
|
|
|
assert
|
|
|
|
|
.dom('[data-test-error]')
|
|
|
|
|
.includesText(
|
|
|
|
|
'custom_metadata validation failed: length of key',
|
|
|
|
|
'shows API error that is not captured by validation'
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('it can create a secret with config metadata', async function(assert) {
|
|
|
|
|
let enginePath = `kv-${new Date().getTime()}`;
|
|
|
|
|
let maxVersion = 101;
|
|
|
|
|
await mountSecrets.visit();
|
|
|
|
|
await click('[data-test-mount-type="kv"]');
|
|
|
|
|
await settled();
|
|
|
|
|
await click('[data-test-mount-next]');
|
|
|
|
|
await settled();
|
|
|
|
|
await fillIn('[data-test-input="path"]', enginePath);
|
|
|
|
|
await fillIn('[data-test-input="maxVersions"]', maxVersion);
|
|
|
|
|
await click('[data-test-input="casRequired"]');
|
|
|
|
|
await click('[data-test-toggle-label="Automate secret deletion"]');
|
|
|
|
|
await fillIn('[data-test-ttl-value="Automate secret deletion"]', '1');
|
|
|
|
|
await click('[data-test-mount-submit="true"]');
|
|
|
|
|
await settled();
|
|
|
|
|
await click('[data-test-configuration-tab]');
|
|
|
|
|
await settled();
|
|
|
|
|
|
|
|
|
|
let cas = document.querySelector('[data-test-value-div="Check-and-Set required"]').innerText;
|
|
|
|
|
let deleteVersionAfter = document.querySelector('[data-test-value-div="Delete version after"]').innerText;
|
|
|
|
|
let savedMaxVersion = document.querySelector('[data-test-value-div="Maximum versions"]').innerText;
|
|
|
|
|
|
|
|
|
|
assert.equal(
|
|
|
|
|
maxVersion,
|
|
|
|
|
savedMaxVersion,
|
|
|
|
|
'displays the max version set when configuring the secret-engine'
|
|
|
|
|
);
|
|
|
|
|
assert.equal(cas.trim(), 'Yes', 'displays the cas set when configuring the secret-engine');
|
|
|
|
|
assert.equal(
|
|
|
|
|
deleteVersionAfter.trim(),
|
|
|
|
|
'1s',
|
|
|
|
|
'displays the delete version after set when configuring the secret-engine'
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('it can create a secret and metadata can be created and edited', async function(assert) {
|
|
|
|
|
let enginePath = `kv-${new Date().getTime()}`;
|
|
|
|
|
let secretPath = 'metadata';
|
|
|
|
|
let maxVersions = 101;
|
|
|
|
|
await mountSecrets.visit();
|
|
|
|
|
await mountSecrets.enable('kv', enginePath);
|
|
|
|
|
await settled();
|
|
|
|
|
await editPage.startCreateSecret();
|
|
|
|
|
await editPage.path(secretPath);
|
|
|
|
|
await editPage.toggleMetadata();
|
|
|
|
|
await settled();
|
|
|
|
|
await fillIn('[data-test-input="maxVersions"]', maxVersions);
|
|
|
|
@ -86,7 +185,6 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
|
|
|
|
await settled();
|
|
|
|
|
await editPage.metadataTab();
|
|
|
|
|
await settled();
|
|
|
|
|
// convert to number for IE11 browserstack test
|
|
|
|
|
let savedMaxVersions = Number(document.querySelectorAll('[data-test-value-div]')[0].innerText);
|
|
|
|
|
assert.equal(
|
|
|
|
|
maxVersions,
|
|
|
|
@ -94,16 +192,14 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
|
|
|
|
'max_version displays the saved number set when creating the secret'
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
// ARG TOD add test here that adds custom metadata
|
|
|
|
|
|
|
|
|
|
test('it disables save when validation errors occur', async function(assert) {
|
|
|
|
|
let enginePath = `kv-${new Date().getTime()}`;
|
|
|
|
|
await mountSecrets.visit();
|
|
|
|
|
await mountSecrets.enable('kv', enginePath);
|
|
|
|
|
await settled();
|
|
|
|
|
await click('[data-test-secret-create="true"]');
|
|
|
|
|
await fillIn('[data-test-secret-path="true"]', 'beep');
|
|
|
|
|
await triggerKeyEvent('[data-test-secret-path="true"]', 'keyup', 65);
|
|
|
|
|
await editPage.startCreateSecret();
|
|
|
|
|
await typeIn('[data-test-secret-path="true"]', 'beep');
|
|
|
|
|
assert
|
|
|
|
|
.dom('[data-test-inline-error-message]')
|
|
|
|
|
.hasText(
|
|
|
|
@ -113,16 +209,15 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
|
|
|
|
|
|
|
|
|
await editPage.toggleMetadata();
|
|
|
|
|
await settled();
|
|
|
|
|
document.querySelector('#maxVersions').value = 'abc';
|
|
|
|
|
await triggerKeyEvent('[data-test-input="maxVersions"]', 'keyup', 65);
|
|
|
|
|
await typeIn('[data-test-input="maxVersions"]', 'abc');
|
|
|
|
|
await settled();
|
|
|
|
|
assert
|
|
|
|
|
.dom('[data-test-input="maxVersions"]')
|
|
|
|
|
.hasClass('has-error-border', 'shows border error on input with error');
|
|
|
|
|
assert.dom('[data-test-secret-save="true"]').isDisabled('Save button is disabled');
|
|
|
|
|
await fillIn('[data-test-input="maxVersions"]', 20);
|
|
|
|
|
await fillIn('[data-test-input="maxVersions"]', 20); // fillIn replaces the text, whereas typeIn only adds to it.
|
|
|
|
|
await triggerKeyEvent('[data-test-input="maxVersions"]', 'keyup', 65);
|
|
|
|
|
await fillIn('[data-test-secret-path="true"]', 'meep');
|
|
|
|
|
await editPage.path('meep');
|
|
|
|
|
await triggerKeyEvent('[data-test-secret-path="true"]', 'keyup', 65);
|
|
|
|
|
await click('[data-test-secret-save="true"]');
|
|
|
|
|
assert.equal(currentURL(), `/vault/secrets/${enginePath}/show/meep`, 'navigates to show secret');
|
|
|
|
@ -155,7 +250,7 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('version 1 performs the correct capabilities lookup', async function(assert) {
|
|
|
|
|
test('version 1 performs the correct capabilities lookup and does not show metadata tab', async function(assert) {
|
|
|
|
|
let enginePath = `kv-${new Date().getTime()}`;
|
|
|
|
|
let secretPath = 'foo/bar';
|
|
|
|
|
// mount version 1 engine
|
|
|
|
@ -171,6 +266,8 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
|
|
|
|
await editPage.createSecret(secretPath, 'foo', 'bar');
|
|
|
|
|
assert.equal(currentRouteName(), 'vault.cluster.secrets.backend.show', 'redirects to the show page');
|
|
|
|
|
assert.ok(showPage.editIsPresent, 'shows the edit button');
|
|
|
|
|
//check for metadata tab should not exist on KV version 1
|
|
|
|
|
assert.dom('[data-test-secret-metadata-tab]').doesNotExist('does not show metadata tab');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// https://github.com/hashicorp/vault/issues/5960
|
|
|
|
@ -320,7 +417,7 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
|
|
|
|
assert.ok(showPage.editIsPresent, 'shows the edit button');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('version 2 with restricted policy still allows edit', async function(assert) {
|
|
|
|
|
test('version 2 with restricted policy still allows edit but does not show metadata tab', async function(assert) {
|
|
|
|
|
let backend = 'kv-v2';
|
|
|
|
|
const V2_POLICY = `
|
|
|
|
|
path "kv-v2/metadata/*" {
|
|
|
|
@ -339,16 +436,18 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
let userToken = consoleComponent.lastLogOutput;
|
|
|
|
|
// check secret edit
|
|
|
|
|
await writeSecret(backend, 'secret', 'foo', 'bar');
|
|
|
|
|
await logout.visit();
|
|
|
|
|
await authPage.login(userToken);
|
|
|
|
|
|
|
|
|
|
await editPage.visitEdit({ backend, id: 'secret' });
|
|
|
|
|
assert.notOk(editPage.hasMetadataFields, 'hides the metadata form');
|
|
|
|
|
await editPage.editSecret('bar', 'baz');
|
|
|
|
|
await settled();
|
|
|
|
|
assert.equal(currentRouteName(), 'vault.cluster.secrets.backend.show', 'redirects to the show page');
|
|
|
|
|
assert.ok(showPage.editIsPresent, 'shows the edit button');
|
|
|
|
|
//check for metadata tab
|
|
|
|
|
assert.dom('[data-test-secret-metadata-tab]').doesNotExist('does not show metadata tab');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('version 2 with policy with destroy capabilities shows modal', async function(assert) {
|
|
|
|
@ -603,7 +702,9 @@ module('Acceptance | secrets/secret/create', function(hooks) {
|
|
|
|
|
assert.ok(showPage.editIsPresent, 'shows the edit button');
|
|
|
|
|
|
|
|
|
|
await editPage.visitEdit({ backend, id: 'secret' });
|
|
|
|
|
assert.notOk(editPage.hasMetadataFields, 'hides the metadata form');
|
|
|
|
|
assert
|
|
|
|
|
.dom('[data-test-warning-no-read-permissions]')
|
|
|
|
|
.exists('shows custom warning instead of default API warning about permissions');
|
|
|
|
|
|
|
|
|
|
await editPage.editSecret('bar', 'baz');
|
|
|
|
|
assert.equal(currentRouteName(), 'vault.cluster.secrets.backend.show', 'redirects to the show page');
|
|
|
|
|