diff --git a/changelog/24404.txt b/changelog/24404.txt new file mode 100644 index 000000000000..a0a9be7e4475 --- /dev/null +++ b/changelog/24404.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: fix issue where kv v2 capabilities checks were not passing in the full secret path if secret was inside a directory. +``` \ No newline at end of file diff --git a/ui/app/models/kv/metadata.js b/ui/app/models/kv/metadata.js index 1f998f488ad2..8aec0c7fcc5c 100644 --- a/ui/app/models/kv/metadata.js +++ b/ui/app/models/kv/metadata.js @@ -1,114 +1,149 @@ -/** - * Copyright (c) HashiCorp, Inc. - * SPDX-License-Identifier: MPL-2.0 - */ +{{! + Copyright (c) HashiCorp, Inc. +}} -import Model, { attr } from '@ember-data/model'; -import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities'; -import { withModelValidations } from 'vault/decorators/model-validations'; -import { withFormFields } from 'vault/decorators/model-form-fields'; -import { keyIsFolder } from 'core/utils/key-utils'; -import { isDeleted } from 'kv/utils/kv-deleted'; + + <:tabLinks> + Secrets + Configuration + -const validations = { - maxVersions: [ - { type: 'number', message: 'Maximum versions must be a number.' }, - { type: 'length', options: { min: 1, max: 16 }, message: 'You cannot go over 16 characters.' }, - ], -}; -const formFieldProps = ['customMetadata', 'maxVersions', 'casRequired', 'deleteVersionAfter']; + <:toolbarFilters> -@withModelValidations(validations) -@withFormFields(formFieldProps) -export default class KvSecretMetadataModel extends Model { - @attr('string') backend; - @attr('string') path; - @attr('string') fullSecretPath; + {{#if (and (not-eq @secrets 403) (or @secrets @filterValue))}} + + {{/if}} + - @attr('number', { - defaultValue: 0, - label: 'Maximum number of versions', - subText: - 'The number of versions to keep per key. Once the number of keys exceeds the maximum number set here, the oldest version will be permanently deleted.', - }) - maxVersions; - - @attr('boolean', { - defaultValue: false, - label: 'Require Check and Set', - subText: `Writes will only be allowed if the key's current version matches the version specified in the cas parameter.`, - }) - casRequired; - - @attr('string', { - defaultValue: '0s', - editType: 'ttl', - label: 'Automate secret deletion', - helperTextDisabled: `A secret's version must be manually deleted.`, - helperTextEnabled: 'Delete all new versions of this secret after:', - }) - deleteVersionAfter; - - @attr('object', { - editType: 'kv', - subText: 'An optional set of informational key-value pairs that will be stored with all secret versions.', - }) - customMetadata; - - // Additional Params only returned on the GET response. - @attr('string') createdTime; - @attr('number') currentVersion; - @attr('number') oldestVersion; - @attr('string') updatedTime; - @attr('object') versions; - - // used for KV list and list-directory view - get pathIsDirectory() { - // ex: beep/ - return keyIsFolder(this.path); - } - - // cannot use isDeleted due to ember property conflict - get isSecretDeleted() { - return isDeleted(this.deletionTime); - } - - // turns version object into an array for version dropdown menu - get sortedVersions() { - const array = []; - for (const key in this.versions) { - this.versions[key].isSecretDeleted = isDeleted(this.versions[key].deletion_time); - array.push({ version: key, ...this.versions[key] }); - } - // version keys are in order created with 1 being the oldest, we want newest first - return array.reverse(); - } - - // helps in long logic statements for state of a currentVersion - get currentSecret() { - if (!this.versions || !this.currentVersion) return false; - const data = this.versions[this.currentVersion]; - const state = data.destroyed ? 'destroyed' : isDeleted(data.deletion_time) ? 'deleted' : 'created'; - return { - state, - isDeactivated: state !== 'created', - }; - } - - // permissions needed for the list view where kv/data has not yet been called. Allows us to conditionally show action items in the LinkedBlock popups. - @lazyCapabilities(apiPath`${'backend'}/data/${'path'}`, 'backend', 'path') dataPath; - @lazyCapabilities(apiPath`${'backend'}/metadata/${'path'}`, 'backend', 'path') metadataPath; - - get canDeleteMetadata() { - return this.metadataPath.get('canDelete') !== false; - } - get canReadMetadata() { - return this.metadataPath.get('canRead') !== false; - } - get canUpdateMetadata() { - return this.metadataPath.get('canUpdate') !== false; - } - get canCreateVersionData() { - return this.dataPath.get('canUpdate') !== false; - } -} + <:toolbarActions> + + Create secret + + + +{{#if (eq @secrets 403)}} +
+
+ +
+ + + + {{#if @failedDirectoryQuery}} + + {{/if}} +
+
+
+{{else}} + {{#if @secrets}} + {{#each @secrets as |metadata|}} + +
+
+
+ + + {{metadata.path}} + +
+
+
+
+ + + +
+
+
+
+ {{/each}} + {{! Pagination }} + + {{else}} + {{#if @filterValue}} + + {{else}} + + + Create secret + + + {{/if}} + {{/if}} +{{/if}} \ No newline at end of file diff --git a/ui/lib/kv/addon/components/page/list.hbs b/ui/lib/kv/addon/components/page/list.hbs index 607a0906a79e..fbd4a4be3288 100644 --- a/ui/lib/kv/addon/components/page/list.hbs +++ b/ui/lib/kv/addon/components/page/list.hbs @@ -1,3 +1,7 @@ +{{! + Copyright (c) HashiCorp, Inc. + SPDX-License-Identifier: BUSL-1.1 +~}} <:tabLinks> Secrets @@ -86,7 +90,11 @@ {{/if}} {{#if metadata.canCreateVersionData}}
  • - + Create new version
  • @@ -98,7 +106,7 @@ @onConfirmAction={{fn this.onDelete metadata}} @confirmMessage="This will permanently delete this secret and all its versions." @cancelButtonText="Cancel" - data-test-delete-metadata={{metadata.path}} + data-test-popup-metadata-delete > Permanently delete