diff --git a/ui/app/components/configure-aws-secret.hbs b/ui/app/components/configure-aws-secret.hbs new file mode 100644 index 00000000000..fafec4906b6 --- /dev/null +++ b/ui/app/components/configure-aws-secret.hbs @@ -0,0 +1,141 @@ +{{! + Copyright (c) HashiCorp, Inc. + SPDX-License-Identifier: BUSL-1.1 +~}} + + + + Dynamic IAM root credentials + + + Leases + + +
+
+ +

+ Note: the client uses the official AWS SDK and will use the specified credentials, environment credentials, shared + file credentials, or IAM role/ECS task credentials in that order. +

+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ + + {{#if this.showOptions}} +
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ {{/if}} + +
+ +
+ +
+ +
+
+ + +

+ If you do not supply lease settings, we will use the default values in AWS. +

+
+ + +
+ +
+ +
+
\ No newline at end of file diff --git a/ui/app/components/configure-aws-secret.js b/ui/app/components/configure-aws-secret.ts similarity index 65% rename from ui/app/components/configure-aws-secret.js rename to ui/app/components/configure-aws-secret.ts index c5639a0d4f4..a941586fc08 100644 --- a/ui/app/components/configure-aws-secret.js +++ b/ui/app/components/configure-aws-secret.ts @@ -6,6 +6,9 @@ import Component from '@glimmer/component'; import { action } from '@ember/object'; +import type SecretEngineModel from 'vault/models/secret-engine'; +import type { TtlEvent } from 'vault/app-types'; + /** * @module ConfigureAwsSecretComponent * @@ -34,21 +37,44 @@ import { action } from '@ember/object'; * @param {Function} saveAWSLease - parent action which updates AWS lease information * */ -export default class ConfigureAwsSecretComponent extends Component { + +type AWSRootCredsFields = { + access_key: string | null; + iam_endpoint: string | null; + sts_endpoint: string | null; + secret_key: string | null; + region: string | null; +}; + +type LeaseFields = { lease: string; lease_max: string }; + +interface Args { + model: SecretEngineModel; + tab?: string; + accessKey: string; + secretKey: string; + region: string; + iamEndpoint: string; + stsEndpoint: string; + saveAWSRoot: (data: AWSRootCredsFields) => void; + saveAWSLease: (data: LeaseFields) => void; +} + +export default class ConfigureAwsSecretComponent extends Component { @action - saveRootCreds(data, event) { + saveRootCreds(data: AWSRootCredsFields, event: Event) { event.preventDefault(); this.args.saveAWSRoot(data); } @action - saveLease(data, event) { + saveLease(data: LeaseFields, event: Event) { event.preventDefault(); this.args.saveAWSLease(data); } @action - handleTtlChange(name, ttlObj) { + handleTtlChange(name: string, ttlObj: TtlEvent) { // lease values cannot be undefined, set to 0 to use default const valueToSet = ttlObj.enabled ? ttlObj.goSafeTimeString : 0; this.args.model.set(name, valueToSet); diff --git a/ui/app/templates/components/configure-aws-secret.hbs b/ui/app/templates/components/configure-aws-secret.hbs deleted file mode 100644 index 52403a12a33..00000000000 --- a/ui/app/templates/components/configure-aws-secret.hbs +++ /dev/null @@ -1,159 +0,0 @@ -{{! - Copyright (c) HashiCorp, Inc. - SPDX-License-Identifier: BUSL-1.1 -~}} - -
- -
- -{{#if (eq @tab "leases")}} -
-
- - -

- If you do not supply lease settings, we will use the default values in AWS. -

-
- - -
- -
- -{{else}} -
-
- -

- Note: the client uses the official AWS SDK and will use the specified credentials, environment credentials, shared - file credentials, or IAM role/ECS task credentials in that order. -

-
- -
- -
- -
-
- -
- -
- -
-
- - - {{#if this.showOptions}} -
-
- -
-
- -
-
-
-
- -
- -
-
-
- -
- -
-
-
- {{/if}} - -
- -
- -{{/if}} \ No newline at end of file diff --git a/ui/tests/acceptance/aws-test.js b/ui/tests/acceptance/aws-test.js index e415746e8d9..b9ac6669f59 100644 --- a/ui/tests/acceptance/aws-test.js +++ b/ui/tests/acceptance/aws-test.js @@ -7,7 +7,9 @@ import { click, fillIn, currentURL, find, settled, waitUntil } from '@ember/test import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import { v4 as uuidv4 } from 'uuid'; +import { spy } from 'sinon'; +import { GENERAL } from '../helpers/general-selectors'; import authPage from 'vault/tests/pages/auth'; import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; import { setupMirage } from 'ember-cli-mirage/test-support'; @@ -17,6 +19,10 @@ module('Acceptance | aws secret backend', function (hooks) { setupMirage(hooks); hooks.beforeEach(function () { + const flash = this.owner.lookup('service:flash-messages'); + this.flashSuccessSpy = spy(flash, 'success'); + this.flashDangerSpy = spy(flash, 'danger'); + this.uid = uuidv4(); return authPage.login(); }); @@ -37,33 +43,37 @@ module('Acceptance | aws secret backend', function (hooks) { await click('[data-test-secret-backend-configure]'); assert.strictEqual(currentURL(), `/vault/settings/secrets/configure/${path}`); + assert.dom('[data-test-aws-root-creds-form]').exists(); - assert.dom('[data-test-aws-link="root-creds"]').exists(); - assert.dom('[data-test-aws-link="leases"]').exists(); + assert.dom(GENERAL.tab('access-to-aws')).exists('renders the root creds tab'); + assert.dom(GENERAL.tab('lease')).exists('renders the leases config tab'); await fillIn('[data-test-aws-input="accessKey"]', 'foo'); await fillIn('[data-test-aws-input="secretKey"]', 'bar'); await click('[data-test-aws-input="root-save"]'); - assert - .dom('[data-test-flash-message]:last-of-type [data-test-flash-message-body]') - .includesText(`The backend configuration saved successfully!`); + assert.true( + this.flashSuccessSpy.calledWith('The backend configuration saved successfully!'), + 'success flash message is rendered' + ); - await click('[data-test-aws-link="leases"]'); + await click(GENERAL.tab('lease')); await click('[data-test-aws-input="lease-save"]'); - assert - .dom('[data-test-flash-message]:last-of-type [data-test-flash-message-body]') - .includesText(`The backend configuration saved successfully!`); + + assert.true( + this.flashSuccessSpy.calledTwice, + 'a new success flash message is rendered upon saving lease' + ); await click('[data-test-backend-view-link]'); - assert.strictEqual(currentURL(), `/vault/secrets/${path}/list`, `navigates to the roles list`); + assert.strictEqual(currentURL(), `/vault/secrets/${path}/list`, 'navigates to the roles list'); await click('[data-test-secret-create]'); - assert.dom('[data-test-secret-header]').includesText('AWS Role'); + assert.dom('[data-test-secret-header]').hasText('Create an AWS Role', 'aws: renders the create page'); await fillIn('[data-test-input="name"]', roleName); @@ -73,7 +83,7 @@ module('Acceptance | aws secret backend', function (hooks) { assert.strictEqual( currentURL(), `/vault/secrets/${path}/show/${roleName}`, - `$aws: navigates to the show page on creation` + 'aws: navigates to the show page on creation' ); await click(`[data-test-secret-breadcrumb="${path}"] a`); @@ -96,7 +106,7 @@ module('Acceptance | aws secret backend', function (hooks) { await click(`[data-test-secret-link="${roleName}"] [data-test-popup-menu-trigger]`); await waitUntil(() => find(`[data-test-aws-role-delete="${roleName}"]`)); // flaky without await click(`[data-test-aws-role-delete="${roleName}"]`); - await click(`[data-test-confirm-button]`); - assert.dom(`[data-test-secret-link="${roleName}"]`).doesNotExist(`aws: role is no longer in the list`); + await click(GENERAL.confirmButton); + assert.dom(`[data-test-secret-link="${roleName}"]`).doesNotExist('aws: role is no longer in the list'); }); });