From 9f5ead16a49b2c4e46d6ecb1c0091f1074d44ba3 Mon Sep 17 00:00:00 2001 From: "clairebontempo@gmail.com" Date: Fri, 7 Jun 2024 13:58:34 -0700 Subject: [PATCH] delete tool action form component --- ui/app/components/tool-actions-form.js | 156 --------- .../components/tool-actions-form.hbs | 22 -- ui/app/templates/vault/cluster/tools/tool.hbs | 16 +- ui/tests/acceptance/tools-test.js | 305 +++++++++--------- 4 files changed, 168 insertions(+), 331 deletions(-) delete mode 100644 ui/app/components/tool-actions-form.js delete mode 100644 ui/app/templates/components/tool-actions-form.hbs diff --git a/ui/app/components/tool-actions-form.js b/ui/app/components/tool-actions-form.js deleted file mode 100644 index b6407255b6..0000000000 --- a/ui/app/components/tool-actions-form.js +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (c) HashiCorp, Inc. - * SPDX-License-Identifier: BUSL-1.1 - */ - -import { match } from '@ember/object/computed'; -import { service } from '@ember/service'; -import Component from '@ember/component'; -import { setProperties, computed, set } from '@ember/object'; -import { addSeconds, parseISO } from 'date-fns'; -import { capitalize } from '@ember/string'; - -const DEFAULTS = { - token: null, - rewrap_token: null, - errors: null, - wrap_info: null, - creation_time: null, - creation_ttl: null, - data: '{\n}', - unwrap_data: null, - details: null, - wrapTTL: null, - sum: null, - random_bytes: null, - input: null, -}; - -const WRAPPING_ENDPOINTS = ['lookup', 'wrap', 'unwrap', 'rewrap']; - -export default Component.extend(DEFAULTS, { - flashMessages: service(), - store: service(), - // putting these attrs here so they don't get reset when you click back - // random - bytes: 32, - // hash - format: 'base64', - algorithm: 'sha2-256', - data: '{\n}', - tagName: '', - - didReceiveAttrs() { - this._super(...arguments); - this.checkAction(); - }, - - selectedAction: null, - - reset() { - if (this.isDestroyed || this.isDestroying) { - return; - } - setProperties(this, DEFAULTS); - }, - - checkAction() { - const currentAction = this.selectedAction; - const oldAction = this.oldSelectedAction; - - if (currentAction !== oldAction) { - this.reset(); - } - set(this, 'oldSelectedAction', currentAction); - }, - - dataIsEmpty: match('data', new RegExp(DEFAULTS.data)), - - expirationDate: computed('creation_time', 'creation_ttl', function () { - const { creation_time, creation_ttl } = this; - if (!(creation_time && creation_ttl)) { - return null; - } - // returns new Date with seconds added. - return addSeconds(parseISO(creation_time), creation_ttl); - }), - - handleError(e) { - set(this, 'errors', e.errors); - }, - - handleSuccess(resp, action) { - let props = {}; - const secret = (resp && resp.data) || resp.auth; - if (secret && action === 'unwrap') { - const details = { - 'Request ID': resp.request_id, - 'Lease ID': resp.lease_id || 'None', - Renewable: resp.renewable ? 'Yes' : 'No', - 'Lease Duration': resp.lease_duration || 'None', - }; - props = { ...props, unwrap_data: secret, details: details }; - } - props = { ...props, ...secret }; - if (resp && resp.wrap_info) { - const keyName = action === 'rewrap' ? 'rewrap_token' : 'token'; - props = { ...props, [keyName]: resp.wrap_info.token }; - } - setProperties(this, props); - this.flashMessages.success(`${capitalize(action)} was successful.`); - }, - - getData() { - const action = this.selectedAction; - if (WRAPPING_ENDPOINTS.includes(action)) { - return this.dataIsEmpty ? { token: (this.token || '').trim() } : JSON.parse(this.data); - } - if (action === 'random') { - return { bytes: this.bytes, format: this.format }; - } - if (action === 'hash') { - return { input: this.input, format: this.format, algorithm: this.algorithm }; - } - }, - - actions: { - doSubmit(evt) { - evt.preventDefault(); - const action = this.selectedAction; - const wrapTTL = action === 'wrap' ? this.wrapTTL : null; - const data = this.getData(); - setProperties(this, { - errors: null, - wrap_info: null, - creation_time: null, - creation_ttl: null, - }); - - this.store - .adapterFor('tools') - .toolAction(action, data, { wrapTTL }) - .then( - (resp) => this.handleSuccess(resp, action), - (...errArgs) => this.handleError(...errArgs) - ); - }, - - onClear() { - this.reset(); - }, - - onBack(properties) { - // only reset specific properties so user can reuse input data and repeat the action - if (this.isDestroyed || this.isDestroying) { - return; - } - properties.forEach((prop) => { - set(this, prop, DEFAULTS[prop]); - }); - }, - - onChange(param, value) { - set(this, param, value); - }, - }, -}); diff --git a/ui/app/templates/components/tool-actions-form.hbs b/ui/app/templates/components/tool-actions-form.hbs deleted file mode 100644 index cb73f511c9..0000000000 --- a/ui/app/templates/components/tool-actions-form.hbs +++ /dev/null @@ -1,22 +0,0 @@ -{{! - Copyright (c) HashiCorp, Inc. - SPDX-License-Identifier: BUSL-1.1 -~}} - -
- {{#if (eq this.selectedAction "hash")}} - - {{else if (eq this.selectedAction "random")}} - - {{else if (eq this.selectedAction "rewrap")}} - - {{else if (eq this.selectedAction "unwrap")}} - - {{else if (eq this.selectedAction "lookup")}} - - {{else if (eq this.selectedAction "wrap")}} - - {{else}} - - {{/if}} - \ No newline at end of file diff --git a/ui/app/templates/vault/cluster/tools/tool.hbs b/ui/app/templates/vault/cluster/tools/tool.hbs index 609ff360f7..1644af49e1 100644 --- a/ui/app/templates/vault/cluster/tools/tool.hbs +++ b/ui/app/templates/vault/cluster/tools/tool.hbs @@ -3,4 +3,18 @@ SPDX-License-Identifier: BUSL-1.1 ~}} - \ No newline at end of file +{{#if (eq this.selectedAction "hash")}} + +{{else if (eq this.selectedAction "random")}} + +{{else if (eq this.selectedAction "rewrap")}} + +{{else if (eq this.selectedAction "unwrap")}} + +{{else if (eq this.selectedAction "lookup")}} + +{{else if (eq this.selectedAction "wrap")}} + +{{else}} + +{{/if}} \ No newline at end of file diff --git a/ui/tests/acceptance/tools-test.js b/ui/tests/acceptance/tools-test.js index d5d7741c7b..bb0b4aea3d 100644 --- a/ui/tests/acceptance/tools-test.js +++ b/ui/tests/acceptance/tools-test.js @@ -3,17 +3,7 @@ * SPDX-License-Identifier: BUSL-1.1 */ -import { - click, - fillIn, - find, - findAll, - currentURL, - visit, - settled, - waitUntil, - waitFor, -} from '@ember/test-helpers'; +import { click, fillIn, find, findAll, currentURL, visit, waitUntil } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import { toolsActions } from 'vault/helpers/tools-actions'; @@ -24,153 +14,164 @@ import { setupMirage } from 'ember-cli-mirage/test-support'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; import { TOOLS_SELECTORS as TS } from 'vault/tests/helpers/tools-selectors'; +const createTokenStore = () => { + let token; + return { + set(val) { + token = val; + }, + get() { + return token; + }, + }; +}; +const DATA_TO_WRAP = JSON.stringify({ tools: 'tests' }); + module('Acceptance | tools', function (hooks) { setupApplicationTest(hooks); setupMirage(hooks); - hooks.beforeEach(function () { - return authPage.login(); + hooks.beforeEach(async function () { + await authPage.login(); + return visit('/vault/tools'); }); - const DATA_TO_WRAP = JSON.stringify({ tools: 'tests' }); - const TOOLS_ACTIONS = toolsActions(); - - var createTokenStore = () => { - let token; - return { - set(val) { - token = val; - }, - get() { - return token; - }, - }; - }; - - test('tools functionality', async function (assert) { - var tokenStore = createTokenStore(); - await visit('/vault/tools'); - - assert.strictEqual(currentURL(), '/vault/tools/wrap', 'forwards to the first action'); - TOOLS_ACTIONS.forEach((action) => { - assert.dom(GENERAL.navLink(capitalize(action))).exists(`${action} link renders`); - }); - - await waitFor('.CodeMirror'); - codemirror().setValue(DATA_TO_WRAP); - - // wrap - await click(TS.submit); - const wrappedToken = await waitUntil(() => find(TS.toolsInput('wrapping-token'))); - tokenStore.set(wrappedToken.innerText); - - // lookup - await click(GENERAL.navLink('Lookup')); - - await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get()); - await click(TS.submit); - await waitUntil(() => findAll('[data-test-component="info-table-row"]').length >= 3); - assert.dom(GENERAL.infoRowValue('Creation path')).hasText('sys/wrapping/wrap', 'show creation path row'); - assert.dom(GENERAL.infoRowValue('Creation time')).exists(); - assert.dom(GENERAL.infoRowValue('Creation TTL')).hasText('1800', 'show creation ttl row'); - - // rewrap - await click(GENERAL.navLink('Rewrap')); - - await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get()); - await click(TS.submit); - const rewrappedToken = await waitUntil(() => find(TS.toolsInput('rewrapped-token'))); - assert.ok(rewrappedToken.value, 'has a new re-wrapped token'); - assert.notEqual(rewrappedToken.value, tokenStore.get(), 're-wrapped token is not the wrapped token'); - tokenStore.set(rewrappedToken.value); - await settled(); - - // unwrap - await click(GENERAL.navLink('Unwrap')); - - await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get()); - await click(TS.submit); - await waitFor('.CodeMirror'); - assert.deepEqual( - JSON.parse(codemirror().getValue()), - JSON.parse(DATA_TO_WRAP), - 'unwrapped data equals input data' - ); - await waitUntil(() => find(TS.tab('details'))); - await click(TS.tab('details')); - await click(TS.tab('data')); - assert.deepEqual( - JSON.parse(codemirror().getValue()), - JSON.parse(DATA_TO_WRAP), - 'data tab still has unwrapped data' - ); - //random - await click(GENERAL.navLink('Random')); - - assert.dom(TS.toolsInput('bytes')).hasValue('32', 'defaults to 32 bytes'); - await click(TS.submit); - const randomBytes = await waitUntil(() => find(TS.toolsInput('random-bytes'))); - assert.ok(randomBytes.value, 'shows the returned value of random bytes'); - - // hash - await click(GENERAL.navLink('Hash')); - - await fillIn(TS.toolsInput('hash-input'), 'foo'); - await click('[data-test-transit-b64-toggle="input"]'); - - await click(TS.submit); - let sumInput = await waitUntil(() => find(TS.toolsInput('sum'))); - assert - .dom(sumInput) - .hasValue('LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564=', 'hashes the data, encodes input'); - await click(TS.button('Back')); - - await fillIn(TS.toolsInput('hash-input'), 'e2RhdGE6ImZvbyJ9'); - - await click(TS.submit); - sumInput = await waitUntil(() => find(TS.toolsInput('sum'))); - assert - .dom(sumInput) - .hasValue('JmSi2Hhbgu2WYOrcOyTqqMdym7KT3sohCwAwaMonVrc=', 'hashes the data, passes b64 input through'); + test('it navigates to each action link', async function (assert) { + assert.strictEqual(currentURL(), '/vault/tools/wrap', 'forwards from "vault/tools" to the first action'); + for (const action of toolsActions()) { + await click(GENERAL.navLink(capitalize(action))); + assert.strictEqual(currentURL(), `/vault/tools/${action}`, `it navigates to ${action}`); + } }); - const AUTH_RESPONSE = { - request_id: '39802bc4-235c-2f0b-87f3-ccf38503ac3e', - lease_id: '', - renewable: false, - lease_duration: 0, - data: null, - wrap_info: null, - warnings: null, - auth: { - client_token: 'ecfc2758-588e-981d-50f4-a25883bbf03c', - accessor: '6299780b-f2b2-1a3f-7b83-9d3d67629249', - policies: ['root'], - metadata: null, - lease_duration: 0, - renewable: false, - entity_id: '', - }, - }; + module('cross tool workflow', function () { + test('it wraps data, performs lookup, rewraps and then unwraps data', async function (assert) { + const tokenStore = createTokenStore(); - test('ensure unwrap with auth block works properly', async function (assert) { - this.server.post('/sys/wrapping/unwrap', () => { - return AUTH_RESPONSE; + await waitUntil(() => find('.CodeMirror')); + codemirror().setValue(DATA_TO_WRAP); + + await click(TS.submit); + const wrappedToken = await waitUntil(() => find(TS.toolsInput('wrapping-token'))); + tokenStore.set(wrappedToken.innerText); + + // lookup + await click(GENERAL.navLink('Lookup')); + + await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get()); + await click(TS.submit); + await waitUntil(() => findAll('[data-test-component="info-table-row"]').length >= 3); + assert + .dom(GENERAL.infoRowValue('Creation path')) + .hasText('sys/wrapping/wrap', 'show creation path row'); + assert.dom(GENERAL.infoRowValue('Creation time')).exists(); + assert.dom(GENERAL.infoRowValue('Creation TTL')).hasText('1800', 'show creation ttl row'); + + // rewrap + await click(GENERAL.navLink('Rewrap')); + + await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get()); + await click(TS.submit); + await waitUntil(() => find(TS.toolsInput('rewrapped-token'))); + const rewrappedToken = find(TS.toolsInput('rewrapped-token')).innerText; + assert.notEqual(rewrappedToken, tokenStore.get(), 're-wrapped token is not the wrapped token'); + tokenStore.set(rewrappedToken); + + // unwrap + await click(GENERAL.navLink('Unwrap')); + + await fillIn(TS.toolsInput('unwrap-token'), tokenStore.get()); + await click(TS.submit); + await waitUntil(() => find('.CodeMirror')); + assert.deepEqual( + JSON.parse(codemirror().getValue()), + JSON.parse(DATA_TO_WRAP), + 'unwrapped data equals input data' + ); + await waitUntil(() => find(TS.tab('details'))); + await click(TS.tab('details')); + await click(TS.tab('data')); + assert.deepEqual( + JSON.parse(codemirror().getValue()), + JSON.parse(DATA_TO_WRAP), + 'data tab still has unwrapped data' + ); }); - await visit('/vault/tools'); + }); - //unwrap - await click(GENERAL.navLink('Unwrap')); + module('random', function () { + test('it generates random bytes', async function (assert) { + await click(GENERAL.navLink('Random')); + assert.dom(TS.toolsInput('bytes')).hasValue('32', 'defaults to 32 bytes'); + await click(TS.submit); + const randomBytes = await waitUntil(() => find(TS.toolsInput('random-bytes'))); + assert.strictEqual(randomBytes.innerText.length, 44, 'shows the returned value of random bytes'); + }); + }); - await fillIn(TS.toolsInput('wrapping-token'), 'sometoken'); - await click(TS.submit); + module('hash', function () { + test('it generates hash', async function (assert) { + await click(GENERAL.navLink('Hash')); - await waitFor('.CodeMirror'); - assert.deepEqual( - JSON.parse(codemirror().getValue()), - AUTH_RESPONSE.auth, - 'unwrapped data equals input data' - ); + await fillIn(TS.toolsInput('hash-input'), 'foo'); + await click(TS.toolsInput('b64-toggle')); + assert.dom(TS.toolsInput('hash-input')).hasValue('Zm9v', 'it base64 encodes input'); + await click(TS.submit); + let sumInput = await waitUntil(() => find(TS.toolsInput('sum'))); + assert + .dom(sumInput) + .hasText('LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564=', 'hashes the data, encodes input'); + await click(TS.button('Done')); + + await waitUntil(() => find(TS.toolsInput('hash-input'))); + assert.dom(TS.toolsInput('hash-input')).hasText('', 'it clears input on done'); + await fillIn(TS.toolsInput('hash-input'), 'e2RhdGE6ImZvbyJ9'); + + await click(TS.submit); + sumInput = await waitUntil(() => find(TS.toolsInput('sum'))); + assert + .dom(sumInput) + .hasText('JmSi2Hhbgu2WYOrcOyTqqMdym7KT3sohCwAwaMonVrc=', 'hashes the data, passes b64 input through'); + }); + }); + + module('unwrap', function () { + test('it unwraps with auth block', async function (assert) { + const AUTH_RESPONSE = { + request_id: '39802bc4-235c-2f0b-87f3-ccf38503ac3e', + lease_id: '', + renewable: false, + lease_duration: 0, + data: null, + wrap_info: null, + warnings: null, + auth: { + client_token: 'ecfc2758-588e-981d-50f4-a25883bbf03c', + accessor: '6299780b-f2b2-1a3f-7b83-9d3d67629249', + policies: ['root'], + metadata: null, + lease_duration: 0, + renewable: false, + entity_id: '', + }, + }; + this.server.post('/sys/wrapping/unwrap', () => { + return AUTH_RESPONSE; + }); + + // unwrap + await click(GENERAL.navLink('Unwrap')); + + await fillIn(TS.toolsInput('unwrap-token'), 'sometoken'); + await click(TS.submit); + + await waitUntil(() => find('.CodeMirror')); + assert.deepEqual( + JSON.parse(codemirror().getValue()), + AUTH_RESPONSE.auth, + 'unwrapped data equals input data' + ); + }); }); module('wrap', function () { @@ -178,7 +179,7 @@ module('Acceptance | tools', function (hooks) { const tokenStore = createTokenStore(); await visit('/vault/tools/wrap'); - await waitFor('.CodeMirror'); + await waitUntil(() => find('.CodeMirror')); codemirror().setValue(DATA_TO_WRAP); // initial wrap @@ -195,18 +196,18 @@ module('Acceptance | tools', function (hooks) { // so when users attempted to wrap data again the payload was actually empty and unwrapping the token returned {token: ""} // it is user desired behavior that the form does not clear on back, and that wrapping can be immediately repeated // we use lookup to check our token from the second wrap returns the unwrapped data we expect - await click(GENERAL.navLink('Lookup')); - await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get()); + await click(GENERAL.navLink('Unwrap')); + await fillIn(TS.toolsInput('unwrap-token'), tokenStore.get()); await click(TS.submit); - await waitUntil(() => findAll('[data-test-component="info-table-row"]').length >= 3); - assert.dom(GENERAL.infoRowValue('Creation TTL')).hasText('1800', 'show creation ttl row'); + await waitUntil(() => find('.CodeMirror')); + assert.strictEqual(codemirror().getValue(' '), '{ "tools": "tests" }', 'it renders unwrapped data'); }); test('it sends wrap ttl', async function (assert) { const tokenStore = createTokenStore(); await visit('/vault/tools/wrap'); - await waitFor('.CodeMirror'); + await waitUntil(() => find('.CodeMirror')); codemirror().setValue(DATA_TO_WRAP); // update to non-default ttl @@ -217,7 +218,7 @@ module('Acceptance | tools', function (hooks) { const wrappedToken = await waitUntil(() => find(TS.toolsInput('wrapping-token'))); tokenStore.set(wrappedToken.innerText); - // lookup to check unwrapped data is what we expect + // lookup to check ttl is what we expect await click(GENERAL.navLink('Lookup')); await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get()); await click(TS.submit);