UI/fix kv data cache (#14489)

* KV fetches recent version on every page, no longer disallow new version without metadata access

* Don't flash no read permissions warning

* Send noMetadataVersion on destroy if version is undefined

* test coverage

* add changelog, fix tests

* Fix failing test
This commit is contained in:
Chelsea Shaw 2022-03-16 11:00:08 -05:00 committed by GitHub
parent 50a9dedbcb
commit ecd4c1e514
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 40 additions and 28 deletions

3
changelog/14489.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
ui: Fixes caching issue on kv new version create
```

View File

@ -149,6 +149,7 @@ export default ApplicationAdapter.extend({
} else if (deleteType === 'soft-delete') {
return this.softDelete(backend, path, version);
} else {
version = version || currentVersionForNoReadMetadata;
return this.deleteByDeleteType(backend, path, deleteType, version);
}
},

View File

@ -248,20 +248,7 @@ export default Route.extend(UnloadModelRoute, {
if (modelType === 'secret-v2') {
// after the the base model fetch, kv-v2 has a second associated
// version model that contains the secret data
// if no read access to metadata, return current Version from secret data.
if (!secretModel.currentVersion) {
let adapter = this.store.adapterFor('secret-v2-version');
try {
secretModel.currentVersion = await adapter.getSecretDataVersion(backend, secret);
} catch {
// will get error if you have deleted the secret
// if this is the case do nothing
}
secretModel = await this.fetchV2Models(capabilities, secretModel, params);
} else {
secretModel = await this.fetchV2Models(capabilities, secretModel, params);
}
secretModel = await this.fetchV2Models(capabilities, secretModel, params);
}
return {
secret: secretModel,

View File

@ -152,13 +152,13 @@
<form onsubmit={{action "createOrUpdateKey" "edit"}}>
<div class="box is-sideless is-fullwidth is-marginless padding-top">
<MessageError @model={{@modelForData}} @errorMessage={{this.error}} />
{{#unless @canReadSecretData}}
{{#if (eq @canReadSecretData false)}}
<AlertBanner
@type="warning"
@message="You do not have read permissions. If a secret exists here creating a new secret will overwrite it."
data-test-warning-no-read-permissions
/>
{{/unless}}
{{/if}}
<NamespaceReminder @mode="edit" @noun="secret" />
{{#if this.isCreateNewVersionFromOldVersion}}
<div class="form-section">

View File

@ -92,12 +92,15 @@
{{#let (concat "vault.cluster.secrets.backend." (if (eq @mode "show") "edit" "show")) as |targetRoute|}}
{{#if @isV2}}
<ToolbarLink
@params={{array targetRoute @model.id (query-params version=@modelForData.version)}}
{{! Always create new version from latest if no metadata read access }}
@params={{array
targetRoute
@model.id
(query-params version=(if @model.canReadMetadata @modelForData.version ""))
}}
@data-test-secret-edit="true"
@replace={{true}}
@type="add"
@disabled={{@model.failedServerRead}}
@disabledTooltip="Metadata read access is required to create new version"
>
Create new version
</ToolbarLink>

View File

@ -86,14 +86,13 @@ export const testAliasDeleteFromForm = async function (name, itemType, assert) {
`${itemType}: navigates to edit on create`
);
await page.editForm.delete();
await settled();
await page.editForm.waitForConfirm();
await page.editForm.confirmDelete();
await settled();
assert.ok(
aliasIndexPage.flashMessage.latestMessage.startsWith('Successfully deleted'),
`${itemType}: shows flash message`
);
assert.equal(
currentRouteName(),
'vault.cluster.access.identity.aliases.index',

View File

@ -607,11 +607,22 @@ module('Acceptance | secrets/secret/create', function (hooks) {
await assert
.dom('[data-test-value-div="secret-key"]')
.exists('secret view page and info table row with secret-key value');
// create new version should be disabled with no metadata read access
assert.dom('[data-test-secret-edit]').hasClass('disabled', 'Create new version action is disabled');
assert
.dom('[data-test-popup-menu-trigger="version"]')
.doesNotExist('the version drop down menu does not show');
// Create new version
assert.dom('[data-test-secret-edit]').doesNotHaveClass('disabled', 'Create new version is not disabled');
await click('[data-test-secret-edit]');
// create new version should not include version in the URL
assert.equal(
currentURL(),
`/vault/secrets/${enginePath}/edit/${secretPath}`,
'edit route does not include version query param'
);
// Update key
await editPage.secretKey('newKey');
await editPage.secretValue('some-value');
await editPage.save();
assert.dom('[data-test-value-div="newKey"]').exists('Info row table exists at newKey');
// check metadata tab
await click('[data-test-secret-metadata-tab]');
@ -683,8 +694,9 @@ module('Acceptance | secrets/secret/create', function (hooks) {
await settled(); // eslint-disable-line
await click('[data-test-secret-tab]');
await settled(); // eslint-disable-line
let text = document.querySelector('[data-test-empty-state-title]').innerText.trim();
assert.equal(text, 'Version 1 of this secret has been permanently destroyed');
assert
.dom('[data-test-empty-state-title]')
.includesText('Version 1 of this secret has been permanently destroyed');
});
test('version 2 with policy with only delete option does not show modal and undelete is an option', async function (assert) {

View File

@ -1,4 +1,5 @@
import { clickable, fillable, attribute } from 'ember-cli-page-object';
import { waitFor } from '@ember/test-helpers';
import fields from '../form-field';
export default {
@ -13,4 +14,10 @@ export default {
submit: clickable('[data-test-identity-submit]'),
delete: clickable('[data-test-confirm-action-trigger]'),
confirmDelete: clickable('[data-test-confirm-button]'),
waitForConfirm() {
return waitFor('[data-test-confirm-button]');
},
waitForFlash() {
return waitFor('[data-test-flash-message-body]');
},
};