From 4cd56f8ae521dd6a312038732d9e23e7544710b9 Mon Sep 17 00:00:00 2001 From: Cameron Perera Date: Tue, 15 Jul 2025 14:03:27 -0500 Subject: [PATCH] Icu 17393 manage resource button permissions bug (#2927) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 🐛 hide manage button if no action items ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17393 * fix: 🐛 update manage actions for credential-stores ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17393 * fix: 🐛 update manage actions for groups ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17393 * fix: 🐛 update manage actions for host-sets ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17393 * fix: 🐛 update manage actions for roles ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17393 * fix: 🐛 update manage action for targets ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17393 * fix: 🐛 update manage actions for workers ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17393 * fix: 🐛 update manage actions for users ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17393 * fix: 🐛 update manage actions for auth-methods ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-17393 --- .../auth-method/actions/index.hbs | 85 +++++++++------- .../credential-store/actions/index.hbs | 88 +++++++++++------ .../components/groups/group/actions/index.hbs | 46 +++++---- .../host-catalog/actions/index.hbs | 61 +++++++----- .../host-sets/host-set/actions/index.hbs | 52 ++++++---- .../components/roles/role/actions/index.hbs | 69 +++++++------ .../targets/target/actions/index.hbs | 98 ++++++++++++------- .../components/users/user/actions/index.hbs | 47 +++++---- .../workers/worker/actions/index.hbs | 45 ++++++--- .../credential-library/create-test.js | 1 + .../credential-library/selectors.js | 3 + .../credentials/create-test.js | 17 ++++ .../credential-store/credentials/selectors.js | 3 + .../tests/acceptance/groups/members-test.js | 1 + .../host-catalogs/host-sets/create-test.js | 6 +- .../host-catalogs/host-sets/selectors.js | 3 + 16 files changed, 403 insertions(+), 222 deletions(-) diff --git a/ui/admin/app/components/auth-methods/auth-method/actions/index.hbs b/ui/admin/app/components/auth-methods/auth-method/actions/index.hbs index 60203da29..848f582c5 100644 --- a/ui/admin/app/components/auth-methods/auth-method/actions/index.hbs +++ b/ui/admin/app/components/auth-methods/auth-method/actions/index.hbs @@ -26,39 +26,54 @@ {{/each}} {{/if}} - - - {{#if @model.isPrimary}} - - {{t 'resources.auth-method.actions.remove-as-primary'}} - - {{else}} - - {{t 'resources.auth-method.actions.make-primary'}} - +{{#let + (hash + canCreateAccount=(can 'create model' @model collection='accounts') + canCreateManagedGroup=(can + 'create model' @model collection='managed-groups' + ) + canDelete=(can 'delete auth-method' @model) + ) + as |perms| +}} + {{#if + (or perms.canCreateAccount perms.canCreateManagedGroup perms.canDelete) + }} + + + {{#if @model.isPrimary}} + + {{t 'resources.auth-method.actions.remove-as-primary'}} + + {{else}} + + {{t 'resources.auth-method.actions.make-primary'}} + + {{/if}} + {{#if perms.canCreateAccount}} + + {{t 'resources.account.actions.create'}} + + {{/if}} + {{#if perms.canCreateManagedGroup}} + {{#if (or @model.isOIDC @model.isLDAP)}} + + {{t 'resources.managed-group.actions.create'}} + + {{/if}} + {{/if}} + {{#if perms.canDelete}} + + + {{t 'resources.auth-method.actions.delete'}} + + {{/if}} + {{/if}} - {{#if (can 'create model' @model collection='accounts')}} - - {{t 'resources.account.actions.create'}} - - {{/if}} - {{#if (can 'create model' @model collection='managed-groups')}} - {{#if (or @model.isOIDC @model.isLDAP)}} - - {{t 'resources.managed-group.actions.create'}} - - {{/if}} - {{/if}} - {{#if (can 'delete auth-method' @model)}} - - - {{t 'resources.auth-method.actions.delete'}} - - {{/if}} - \ No newline at end of file +{{/let}} \ No newline at end of file diff --git a/ui/admin/app/components/credential-stores/credential-store/actions/index.hbs b/ui/admin/app/components/credential-stores/credential-store/actions/index.hbs index d5e8a613f..45dab0c85 100644 --- a/ui/admin/app/components/credential-stores/credential-store/actions/index.hbs +++ b/ui/admin/app/components/credential-stores/credential-store/actions/index.hbs @@ -2,33 +2,63 @@ Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: BUSL-1.1 }} - - - {{#if (can 'create model' @model collection='credential-libraries')}} - - {{t 'resources.credential-library.actions.create'}} - + +{{#let + (hash + canCreateCredLibraries=(can + 'create model' @model collection='credential-libraries' + ) + canCreateCredentials=(can 'create model' @model collection='credentials') + canDelete=(can 'delete model' @model) + canEditWorkerFilter=(and (feature-flag 'worker-filter') @model.isVault) + ) + as |perms| +}} + {{#if + (or + perms.canCreateCredLibraries + perms.canCreateCredentials + perms.canEditWorkerFilter + perms.canDelete + ) + }} + + + {{#if perms.canCreateCredLibraries}} + + {{t 'resources.credential-library.actions.create'}} + + {{/if}} + {{#if perms.canCreateCredentials}} + + {{t 'resources.credential.actions.create'}} + + {{/if}} + {{#if perms.canEditWorkerFilter}} + + {{t 'actions.edit-worker-filter'}} + + {{/if}} + {{#if perms.canDelete}} + {{#if + (or + perms.canCreateCredLibraries + perms.canCreateCredentials + perms.canEditWorkerFilter + ) + }} + + {{/if}} + + {{t 'resources.credential-store.actions.delete'}} + + {{/if}} + {{/if}} - {{#if (can 'create model' @model collection='credentials')}} - - {{t 'resources.credential.actions.create'}} - - {{/if}} - {{#if (and (feature-flag 'worker-filter') @model.isVault)}} - - {{t 'actions.edit-worker-filter'}} - - {{/if}} - {{#if (can 'delete model' @model)}} - - - {{t 'resources.credential-store.actions.delete'}} - - {{/if}} - \ No newline at end of file +{{/let}} \ No newline at end of file diff --git a/ui/admin/app/components/groups/group/actions/index.hbs b/ui/admin/app/components/groups/group/actions/index.hbs index 813094ec1..fcf07f61a 100644 --- a/ui/admin/app/components/groups/group/actions/index.hbs +++ b/ui/admin/app/components/groups/group/actions/index.hbs @@ -3,21 +3,33 @@ SPDX-License-Identifier: BUSL-1.1 }} - - - {{#if (can 'addMembers group' @model)}} - - {{t 'resources.group.actions.add-members'}} - +{{#let + (hash + canAddMembers=(can 'addMembers group' @model) + canDelete=(can 'delete model' @model) + ) + as |perms| +}} + {{#if (or perms.canAddMembers perms.canDelete)}} + + + {{#if perms.canAddMembers}} + + {{t 'resources.group.actions.add-members'}} + + {{/if}} + {{#if perms.canDelete}} + {{#if perms.canAddMembers}} + + {{/if}} + + {{t 'resources.group.actions.delete'}} + + {{/if}} + {{/if}} - {{#if (can 'delete model' @model)}} - - - {{t 'resources.group.actions.delete'}} - - {{/if}} - \ No newline at end of file +{{/let}} \ No newline at end of file diff --git a/ui/admin/app/components/host-catalogs/host-catalog/actions/index.hbs b/ui/admin/app/components/host-catalogs/host-catalog/actions/index.hbs index 61d85b43d..6c3bbdb53 100644 --- a/ui/admin/app/components/host-catalogs/host-catalog/actions/index.hbs +++ b/ui/admin/app/components/host-catalogs/host-catalog/actions/index.hbs @@ -3,28 +3,41 @@ SPDX-License-Identifier: BUSL-1.1 }} - - - {{#if (can 'create model' @model collection='hosts')}} - - {{t 'resources.host.actions.create'}} - +{{#let + (hash + canCreateHosts=(can 'create model' @model collection='hosts') + canCreateHostSets=(can 'create model' @model collection='host-sets') + canDelete=(can 'delete model' @model) + ) + as |perms| +}} + {{#if (or perms.canCreateHosts perms.canCreateHostSets perms.canDelete)}} + + + {{#if perms.canCreateHosts}} + + {{t 'resources.host.actions.create'}} + + {{/if}} + {{#if perms.canCreateHostSets}} + + {{t 'resources.host-set.actions.create'}} + + {{/if}} + {{#if perms.canDelete}} + {{#if (or perms.canCreateHosts perms.canCreateHostSets)}} + + {{/if}} + + {{t 'resources.host-catalog.actions.delete'}} + + {{/if}} + {{/if}} - {{#if (can 'create model' @model collection='host-sets')}} - - {{t 'resources.host-set.actions.create'}} - - {{/if}} - {{#if (can 'delete model' @model)}} - - - {{t 'resources.host-catalog.actions.delete'}} - - {{/if}} - \ No newline at end of file +{{/let}} \ No newline at end of file diff --git a/ui/admin/app/components/host-catalogs/host-catalog/host-sets/host-set/actions/index.hbs b/ui/admin/app/components/host-catalogs/host-catalog/host-sets/host-set/actions/index.hbs index 651db1e08..3a0e5c91b 100644 --- a/ui/admin/app/components/host-catalogs/host-catalog/host-sets/host-set/actions/index.hbs +++ b/ui/admin/app/components/host-catalogs/host-catalog/host-sets/host-set/actions/index.hbs @@ -3,24 +3,36 @@ SPDX-License-Identifier: BUSL-1.1 }} - - - {{#if (can 'addHosts hostSet' @model)}} - - {{t 'resources.host-set.actions.create-and-add-host'}} - - - {{t 'resources.host-set.actions.add-hosts'}} - - +{{#let + (hash + canAddHosts=(can 'addHosts hostSet' @model) + canDelete=(can 'delete model' @model) + ) + as |perms| +}} + {{#if (or perms.canAddHosts perms.canDelete)}} + + + {{#if perms.canAddHosts}} + + {{t 'resources.host-set.actions.create-and-add-host'}} + + + {{t 'resources.host-set.actions.add-hosts'}} + + {{/if}} + {{#if perms.canDelete}} + {{#if perms.canAddHosts}} + + {{/if}} + + {{t 'resources.host-set.actions.delete'}} + + {{/if}} + {{/if}} - {{#if (can 'delete model' @model)}} - - {{t 'resources.host-set.actions.delete'}} - - {{/if}} - \ No newline at end of file +{{/let}} \ No newline at end of file diff --git a/ui/admin/app/components/roles/role/actions/index.hbs b/ui/admin/app/components/roles/role/actions/index.hbs index 4be1034a3..84df4cf38 100644 --- a/ui/admin/app/components/roles/role/actions/index.hbs +++ b/ui/admin/app/components/roles/role/actions/index.hbs @@ -3,32 +3,45 @@ SPDX-License-Identifier: BUSL-1.1 }} - - - {{#if (can 'addPrincipals role' @model)}} - - {{t 'resources.role.principal.actions.add-principals'}} - +{{#let + (hash + canAddPrincipals=(can 'addPrincipals role' @model) + canSetGrantScopes=(can 'setGrantScopes role' @model) + canDelete=(can 'delete model' @model) + ) + as |perms| +}} + {{#if (or perms.canAddPrincipals perms.canSetGrantScopes perms.canDelete)}} + + + {{#if perms.canAddPrincipals}} + + {{t 'resources.role.principal.actions.add-principals'}} + + {{/if}} + {{#if perms.canSetGrantScopes}} + + {{t 'resources.role.scope.actions.manage-scopes'}} + + {{/if}} + {{#if perms.canDelete}} + {{#if (or perms.canAddPrincipals perms.canSetGrantScopes)}} + + {{/if}} + + {{t 'resources.role.actions.delete'}} + + {{/if}} + {{/if}} - {{#if (can 'setGrantScopes role' @model)}} - - {{t 'resources.role.scope.actions.manage-scopes'}} - - {{/if}} - {{#if (can 'delete model' @model)}} - - - {{t 'resources.role.actions.delete'}} - - {{/if}} - \ No newline at end of file +{{/let}} \ No newline at end of file diff --git a/ui/admin/app/components/targets/target/actions/index.hbs b/ui/admin/app/components/targets/target/actions/index.hbs index 35479ed89..86ffaf42d 100644 --- a/ui/admin/app/components/targets/target/actions/index.hbs +++ b/ui/admin/app/components/targets/target/actions/index.hbs @@ -2,38 +2,68 @@ Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: BUSL-1.1 }} - - - {{#if (can 'addHostSources target' @model)}} - - {{t 'resources.target.actions.add-host-sources'}} - + +{{#let + (hash + canAddHostSources=(can 'addHostSources target' @model) + canAddBrokeredCredSources=(can 'addBrokeredCredentialSources target' @model) + canAddInjectedApplicationCredSources=(can + 'addInjectedApplicationCredentialSources target' @model + ) + canDelete=(can 'delete model' @model) + ) + as |perms| +}} + {{#if + (or + perms.canAddHostSources + perms.canAddBrokeredCredSources + perms.canAddInjectedApplicationCredSources + perms.canDelete + ) + }} + + + {{#if perms.canAddHostSources}} + + {{t 'resources.target.actions.add-host-sources'}} + + {{/if}} + {{#if perms.canAddBrokeredCredSources}} + + {{t 'resources.target.actions.add-brokered-credential-sources'}} + + {{/if}} + {{#if perms.canAddInjectedApplicationCredSources}} + + {{t + 'resources.target.actions.add-injected-application-credential-sources' + }} + + {{/if}} + {{#if perms.canDelete}} + {{#if + (or + perms.canAddHostSources + perms.canAddBrokeredCredSources + perms.canAddInjectedApplicationCredSources + ) + }} + + {{/if}} + + {{t 'resources.target.actions.delete'}} + + {{/if}} + {{/if}} - {{#if (can 'addBrokeredCredentialSources target' @model)}} - - {{t 'resources.target.actions.add-brokered-credential-sources'}} - - {{/if}} - {{#if (can 'addInjectedApplicationCredentialSources target' @model)}} - - {{t - 'resources.target.actions.add-injected-application-credential-sources' - }} - - {{/if}} - {{#if (can 'delete model' @model)}} - - - {{t 'resources.target.actions.delete'}} - - {{/if}} - \ No newline at end of file +{{/let}} \ No newline at end of file diff --git a/ui/admin/app/components/users/user/actions/index.hbs b/ui/admin/app/components/users/user/actions/index.hbs index 96ca3068f..f4ef1b123 100644 --- a/ui/admin/app/components/users/user/actions/index.hbs +++ b/ui/admin/app/components/users/user/actions/index.hbs @@ -2,23 +2,34 @@ Copyright (c) HashiCorp, Inc. SPDX-License-Identifier: BUSL-1.1 }} - - - {{#if (can 'addAccounts user' @model)}} - - {{t 'resources.user.actions.add-accounts'}} - +{{#let + (hash + canAddAccounts=(can 'addAccounts user' @model) + canDelete=(can 'delete model' @model) + ) + as |perms| +}} + {{#if (or perms.canAddAccounts perms.canDelete)}} + + + {{#if perms.canAddAccounts}} + + {{t 'resources.user.actions.add-accounts'}} + + {{/if}} + {{#if perms.canDelete}} + {{#if perms.canAddAccounts}} + + {{/if}} + + {{t 'resources.user.actions.delete'}} + + {{/if}} + {{/if}} - - {{#if (can 'delete model' @model)}} - - - {{t 'resources.user.actions.delete'}} - - {{/if}} - \ No newline at end of file +{{/let}} \ No newline at end of file diff --git a/ui/admin/app/components/workers/worker/actions/index.hbs b/ui/admin/app/components/workers/worker/actions/index.hbs index cce6048f3..0a9ebe652 100644 --- a/ui/admin/app/components/workers/worker/actions/index.hbs +++ b/ui/admin/app/components/workers/worker/actions/index.hbs @@ -3,20 +3,33 @@ SPDX-License-Identifier: BUSL-1.1 }} - - - {{#if (can 'setWorkerTags worker' @model)}} - - {{t 'resources.worker.actions.create_tags'}} - +{{#let + (hash + canSetWorkerTags=(can 'setWorkerTags worker' @model) + canDelete=(can 'delete worker' @model) + ) + as |perms| +}} + {{#if (or perms.canSetWorkerTags perms.canDelete)}} + + + {{#if perms.canSetWorkerTags}} + + {{t 'resources.worker.actions.create_tags'}} + + {{/if}} + {{#if perms.canDelete}} + {{#if perms.canSetWorkerTags}} + + {{/if}} + + {{t 'resources.worker.actions.delete'}} + + {{/if}} + {{/if}} - {{#if (can 'delete worker' @model)}} - - {{t 'resources.worker.actions.delete'}} - - {{/if}} - \ No newline at end of file +{{/let}} \ No newline at end of file diff --git a/ui/admin/tests/acceptance/credential-library/create-test.js b/ui/admin/tests/acceptance/credential-library/create-test.js index 3604fb4f7..208143da1 100644 --- a/ui/admin/tests/acceptance/credential-library/create-test.js +++ b/ui/admin/tests/acceptance/credential-library/create-test.js @@ -215,6 +215,7 @@ module('Acceptance | credential-libraries | create', function (hooks) { 'credential-libraries' ] = []; await visit(urls.credentialLibraries); + await click(selectors.MANAGE_DROPDOWN_CREDENTIAL_STORE); assert.notOk( instances.credentialStore.authorized_collection_actions[ diff --git a/ui/admin/tests/acceptance/credential-library/selectors.js b/ui/admin/tests/acceptance/credential-library/selectors.js index 1cc6a7637..5bd415366 100644 --- a/ui/admin/tests/acceptance/credential-library/selectors.js +++ b/ui/admin/tests/acceptance/credential-library/selectors.js @@ -51,3 +51,6 @@ export const MANAGE_DROPDOWN_CRED_LIB = '[data-test-manage-credential-library-dropdown] button:first-child'; export const MANAGE_DROPDOWN_CRED_LIB_DELETE = '[data-test-manage-credential-library-dropdown] ul li button'; + +export const MANAGE_DROPDOWN_CREDENTIAL_STORE = + '[data-test-manage-credential-stores-dropdown] button'; diff --git a/ui/admin/tests/acceptance/credential-store/credentials/create-test.js b/ui/admin/tests/acceptance/credential-store/credentials/create-test.js index 67e6b9669..62dae4d43 100644 --- a/ui/admin/tests/acceptance/credential-store/credentials/create-test.js +++ b/ui/admin/tests/acceptance/credential-store/credentials/create-test.js @@ -344,6 +344,23 @@ module( assert.dom(selectors.FIELD_TYPE_JSON).doesNotExist(); }); + test('users cannot create a new credential without proper authorization', async function (assert) { + instances.staticCredentialStore.authorized_collection_actions.credentials = + instances.staticCredentialStore.authorized_collection_actions.credentials.filter( + (item) => item !== 'create', + ); + + await visit(urls.credentials); + await click(selectors.MANAGE_DROPDOWN_CREDENTIAL_STORE); + + assert.false( + instances.staticCredentialStore.authorized_collection_actions.credentials.includes( + 'create', + ), + ); + assert.dom(commonSelectors.HREF(urls.newCredential)).doesNotExist(); + }); + test('users cannot directly navigate to new credential route without proper authorization', async function (assert) { instances.staticCredentialStore.authorized_collection_actions.credentials = instances.staticCredentialStore.authorized_collection_actions.credentials.filter( diff --git a/ui/admin/tests/acceptance/credential-store/credentials/selectors.js b/ui/admin/tests/acceptance/credential-store/credentials/selectors.js index e3bd61414..0e34b5c24 100644 --- a/ui/admin/tests/acceptance/credential-store/credentials/selectors.js +++ b/ui/admin/tests/acceptance/credential-store/credentials/selectors.js @@ -21,4 +21,7 @@ export const MANAGE_DROPDOWN_DELETE = export const MANAGE_DROPDOWN_NEW_CREDENTIAL = '[data-test-manage-credential-stores-dropdown] a'; +export const MANAGE_DROPDOWN_CREDENTIAL_STORE = + '[data-test-manage-credential-stores-dropdown] button'; + export const REPLACE_SECRET_BTN = '.secret-editor button'; diff --git a/ui/admin/tests/acceptance/groups/members-test.js b/ui/admin/tests/acceptance/groups/members-test.js index 7c3102470..94c70eccb 100644 --- a/ui/admin/tests/acceptance/groups/members-test.js +++ b/ui/admin/tests/acceptance/groups/members-test.js @@ -129,6 +129,7 @@ module('Acceptance | groups | members', function (hooks) { instances.group.update({ authorized_actions }); await visit(urls.group); + await click(selectors.MANAGE_DROPDOWN); assert.dom(commonSelectors.HREF(urls.addMembers)).doesNotExist(); }); diff --git a/ui/admin/tests/acceptance/host-catalogs/host-sets/create-test.js b/ui/admin/tests/acceptance/host-catalogs/host-sets/create-test.js index ce8529b92..0f80eb004 100644 --- a/ui/admin/tests/acceptance/host-catalogs/host-sets/create-test.js +++ b/ui/admin/tests/acceptance/host-catalogs/host-sets/create-test.js @@ -174,8 +174,12 @@ module('Acceptance | host-catalogs | host sets | create', function (hooks) { }); test('Users cannot create a new host set without proper authorization', async function (assert) { - instances.hostCatalog.authorized_collection_actions['host-sets'] = []; + instances.hostCatalog.authorized_collection_actions['host-sets'] = + instances.hostCatalog.authorized_collection_actions['host-sets'].filter( + (item) => item !== 'create', + ); await visit(urls.hostCatalog); + await click(selectors.MANAGE_DROPDOWN_HOST_CATALOG); assert.notOk( instances.hostCatalog.authorized_collection_actions['host-sets'].includes( diff --git a/ui/admin/tests/acceptance/host-catalogs/host-sets/selectors.js b/ui/admin/tests/acceptance/host-catalogs/host-sets/selectors.js index efc1752b7..7ca47c70d 100644 --- a/ui/admin/tests/acceptance/host-catalogs/host-sets/selectors.js +++ b/ui/admin/tests/acceptance/host-catalogs/host-sets/selectors.js @@ -15,6 +15,9 @@ export const FIELD_AZURE_FILTER = '[name=filter]'; export const FIELD_FILTERS_REMOVE_BTN = '[name=filters] [data-test-remove-button]'; +export const MANAGE_DROPDOWN_HOST_CATALOG = + '[data-test-manage-host-catalogs-dropdown] button'; + export const MANAGE_DROPDOWN_HOST_SETS = '[data-test-manage-dropdown-host-sets] button:first-child'; export const MANAGE_DROPDOWN_HOST_SETS_DELETE =