mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 18:48:08 +00:00 
			
		
		
		
	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:
		
							
								
								
									
										3
									
								
								changelog/14489.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								changelog/14489.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | ```release-note:bug | ||||||
|  | ui: Fixes caching issue on kv new version create | ||||||
|  | ``` | ||||||
| @@ -149,6 +149,7 @@ export default ApplicationAdapter.extend({ | |||||||
|     } else if (deleteType === 'soft-delete') { |     } else if (deleteType === 'soft-delete') { | ||||||
|       return this.softDelete(backend, path, version); |       return this.softDelete(backend, path, version); | ||||||
|     } else { |     } else { | ||||||
|  |       version = version || currentVersionForNoReadMetadata; | ||||||
|       return this.deleteByDeleteType(backend, path, deleteType, version); |       return this.deleteByDeleteType(backend, path, deleteType, version); | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   | |||||||
| @@ -248,20 +248,7 @@ export default Route.extend(UnloadModelRoute, { | |||||||
|     if (modelType === 'secret-v2') { |     if (modelType === 'secret-v2') { | ||||||
|       // after the the base model fetch, kv-v2 has a second associated |       // after the the base model fetch, kv-v2 has a second associated | ||||||
|       // version model that contains the secret data |       // 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); |       secretModel = await this.fetchV2Models(capabilities, secretModel, params); | ||||||
|       } else { |  | ||||||
|         secretModel = await this.fetchV2Models(capabilities, secretModel, params); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     return { |     return { | ||||||
|       secret: secretModel, |       secret: secretModel, | ||||||
|   | |||||||
| @@ -152,13 +152,13 @@ | |||||||
|   <form onsubmit={{action "createOrUpdateKey" "edit"}}> |   <form onsubmit={{action "createOrUpdateKey" "edit"}}> | ||||||
|     <div class="box is-sideless is-fullwidth is-marginless padding-top"> |     <div class="box is-sideless is-fullwidth is-marginless padding-top"> | ||||||
|       <MessageError @model={{@modelForData}} @errorMessage={{this.error}} /> |       <MessageError @model={{@modelForData}} @errorMessage={{this.error}} /> | ||||||
|       {{#unless @canReadSecretData}} |       {{#if (eq @canReadSecretData false)}} | ||||||
|         <AlertBanner |         <AlertBanner | ||||||
|           @type="warning" |           @type="warning" | ||||||
|           @message="You do not have read permissions. If a secret exists here creating a new secret will overwrite it." |           @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 |           data-test-warning-no-read-permissions | ||||||
|         /> |         /> | ||||||
|       {{/unless}} |       {{/if}} | ||||||
|       <NamespaceReminder @mode="edit" @noun="secret" /> |       <NamespaceReminder @mode="edit" @noun="secret" /> | ||||||
|       {{#if this.isCreateNewVersionFromOldVersion}} |       {{#if this.isCreateNewVersionFromOldVersion}} | ||||||
|         <div class="form-section"> |         <div class="form-section"> | ||||||
|   | |||||||
| @@ -92,12 +92,15 @@ | |||||||
|       {{#let (concat "vault.cluster.secrets.backend." (if (eq @mode "show") "edit" "show")) as |targetRoute|}} |       {{#let (concat "vault.cluster.secrets.backend." (if (eq @mode "show") "edit" "show")) as |targetRoute|}} | ||||||
|         {{#if @isV2}} |         {{#if @isV2}} | ||||||
|           <ToolbarLink |           <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" |             @data-test-secret-edit="true" | ||||||
|             @replace={{true}} |             @replace={{true}} | ||||||
|             @type="add" |             @type="add" | ||||||
|             @disabled={{@model.failedServerRead}} |  | ||||||
|             @disabledTooltip="Metadata read access is required to create new version" |  | ||||||
|           > |           > | ||||||
|             Create new version |             Create new version | ||||||
|           </ToolbarLink> |           </ToolbarLink> | ||||||
|   | |||||||
| @@ -86,14 +86,13 @@ export const testAliasDeleteFromForm = async function (name, itemType, assert) { | |||||||
|     `${itemType}: navigates to edit on create` |     `${itemType}: navigates to edit on create` | ||||||
|   ); |   ); | ||||||
|   await page.editForm.delete(); |   await page.editForm.delete(); | ||||||
|   await settled(); |   await page.editForm.waitForConfirm(); | ||||||
|   await page.editForm.confirmDelete(); |   await page.editForm.confirmDelete(); | ||||||
|   await settled(); |   await settled(); | ||||||
|   assert.ok( |   assert.ok( | ||||||
|     aliasIndexPage.flashMessage.latestMessage.startsWith('Successfully deleted'), |     aliasIndexPage.flashMessage.latestMessage.startsWith('Successfully deleted'), | ||||||
|     `${itemType}: shows flash message` |     `${itemType}: shows flash message` | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   assert.equal( |   assert.equal( | ||||||
|     currentRouteName(), |     currentRouteName(), | ||||||
|     'vault.cluster.access.identity.aliases.index', |     'vault.cluster.access.identity.aliases.index', | ||||||
|   | |||||||
| @@ -607,11 +607,22 @@ module('Acceptance | secrets/secret/create', function (hooks) { | |||||||
|     await assert |     await assert | ||||||
|       .dom('[data-test-value-div="secret-key"]') |       .dom('[data-test-value-div="secret-key"]') | ||||||
|       .exists('secret view page and info table row with secret-key value'); |       .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'); |     // Create new version | ||||||
|     assert |     assert.dom('[data-test-secret-edit]').doesNotHaveClass('disabled', 'Create new version is not disabled'); | ||||||
|       .dom('[data-test-popup-menu-trigger="version"]') |     await click('[data-test-secret-edit]'); | ||||||
|       .doesNotExist('the version drop down menu does not show'); |  | ||||||
|  |     // 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 |     // check metadata tab | ||||||
|     await click('[data-test-secret-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 settled(); // eslint-disable-line | ||||||
|     await click('[data-test-secret-tab]'); |     await click('[data-test-secret-tab]'); | ||||||
|     await settled(); // eslint-disable-line |     await settled(); // eslint-disable-line | ||||||
|     let text = document.querySelector('[data-test-empty-state-title]').innerText.trim(); |     assert | ||||||
|     assert.equal(text, 'Version 1 of this secret has been permanently destroyed'); |       .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) { |   test('version 2 with policy with only delete option does not show modal and undelete is an option', async function (assert) { | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| import { clickable, fillable, attribute } from 'ember-cli-page-object'; | import { clickable, fillable, attribute } from 'ember-cli-page-object'; | ||||||
|  | import { waitFor } from '@ember/test-helpers'; | ||||||
| import fields from '../form-field'; | import fields from '../form-field'; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
| @@ -13,4 +14,10 @@ export default { | |||||||
|   submit: clickable('[data-test-identity-submit]'), |   submit: clickable('[data-test-identity-submit]'), | ||||||
|   delete: clickable('[data-test-confirm-action-trigger]'), |   delete: clickable('[data-test-confirm-action-trigger]'), | ||||||
|   confirmDelete: clickable('[data-test-confirm-button]'), |   confirmDelete: clickable('[data-test-confirm-button]'), | ||||||
|  |   waitForConfirm() { | ||||||
|  |     return waitFor('[data-test-confirm-button]'); | ||||||
|  |   }, | ||||||
|  |   waitForFlash() { | ||||||
|  |     return waitFor('[data-test-flash-message-body]'); | ||||||
|  |   }, | ||||||
| }; | }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Chelsea Shaw
					Chelsea Shaw