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