From 3fc63ae3a1910c4518e671ece9067e318900394d Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Tue, 7 May 2024 15:00:17 -0500 Subject: [PATCH 01/18] VAULT-26829 --- .../components/console/command-input.hbs | 5 ++--- .../templates/components/console/ui-panel.hbs | 20 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/ui/app/templates/components/console/command-input.hbs b/ui/app/templates/components/console/command-input.hbs index d7c6394bff34..64188be7dcb3 100644 --- a/ui/app/templates/components/console/command-input.hbs +++ b/ui/app/templates/components/console/command-input.hbs @@ -10,7 +10,7 @@ {{/if}} diff --git a/ui/app/templates/components/console/ui-panel.hbs b/ui/app/templates/components/console/ui-panel.hbs index c90f8aa02636..11675cae3c1b 100644 --- a/ui/app/templates/components/console/ui-panel.hbs +++ b/ui/app/templates/components/console/ui-panel.hbs @@ -22,14 +22,18 @@ HashiCorp Developer site.

Examples:

-

→ Write secrets to kv v1: write <mount>/my-secret foo=bar

-

→ List kv v1 secret keys: list <mount>/

-

→ Read a kv v1 secret: read <mount>/my-secret

-

→ Mount a kv v2 secret engine: write sys/mounts/<mount> type=kv - options=version=2

-

→ Read a kv v2 secret: kv-get <mount>/secret-path

-

→ Read a kv v2 secret's metadata: kv-get <mount>/secret-path - -metadata

+

+ Write secrets to kv v1: write <mount>/my-secret foo=bar

+

+ List kv v1 secret keys: list <mount>/

+

+ Read a kv v1 secret: read <mount>/my-secret

+

+ Mount a kv v2 secret engine: write sys/mounts/<mount> type=kv options=version=2

+

+ Read a kv v2 secret: kv-get <mount>/secret-path

+

+ Read a kv v2 secret's metadata: kv-get <mount>/secret-path-metadata

Date: Tue, 7 May 2024 15:19:18 -0500 Subject: [PATCH 02/18] associate input and help text --- ui/app/templates/components/console/command-input.hbs | 1 + ui/lib/core/addon/components/namespace-reminder.hbs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/app/templates/components/console/command-input.hbs b/ui/app/templates/components/console/command-input.hbs index 64188be7dcb3..363ae89b7e01 100644 --- a/ui/app/templates/components/console/command-input.hbs +++ b/ui/app/templates/components/console/command-input.hbs @@ -11,6 +11,7 @@ {{/if}} +

{{yield (hash namespace=this.namespace)}}

{{else}} -

+

This {{@noun}} will be From c128021be26b7cb08c57ef827c07777bd4ec3463 Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Tue, 7 May 2024 15:24:53 -0500 Subject: [PATCH 03/18] Add ESC key support --- ui/app/components/console/command-input.js | 4 ++++ ui/app/templates/components/console/ui-panel.hbs | 1 + 2 files changed, 5 insertions(+) diff --git a/ui/app/components/console/command-input.js b/ui/app/components/console/command-input.js index 5cbb8601982f..b5e319f5912e 100644 --- a/ui/app/components/console/command-input.js +++ b/ui/app/components/console/command-input.js @@ -7,6 +7,7 @@ import Component from '@ember/component'; import keys from 'core/utils/key-codes'; export default Component.extend({ + onEscCommand() {}, onExecuteCommand() {}, onFullscreen() {}, onValueUpdate() {}, @@ -18,6 +19,9 @@ export default Component.extend({ handleKeyUp(event) { const keyCode = event.keyCode; switch (keyCode) { + case keys.ESC: + this.onEscCommand(keyCode); + break; case keys.ENTER: this.onExecuteCommand(event.target.value); break; diff --git a/ui/app/templates/components/console/ui-panel.hbs b/ui/app/templates/components/console/ui-panel.hbs index 11675cae3c1b..9168ab39c7fe 100644 --- a/ui/app/templates/components/console/ui-panel.hbs +++ b/ui/app/templates/components/console/ui-panel.hbs @@ -44,5 +44,6 @@ @onFullscreen={{action "toggleFullscreen"}} @onExecuteCommand={{action "executeCommand"}} @onShiftCommand={{action "shiftCommandIndex"}} + @onEscCommand={{action "closeConsole"}} /> \ No newline at end of file From b3d5706ebd388ec938da172740e62339250fd6b1 Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Tue, 7 May 2024 16:28:13 -0500 Subject: [PATCH 04/18] adjust console-ui panel for text-spacing requirement Added console focus trap Added else conditional for console-panel update aria-label for input reverting height style change reverting focus trap for now fixed typo re-adding focus trap to console::uiPanel component refactor conditional yield of console ui panel remove duplicated option for ui panel move ESC command to focus-trap change focus-trap to use onDeactivate --- ui/app/components/console/command-input.js | 9 +++----- ui/app/components/console/ui-panel.js | 1 + ui/app/components/sidebar/frame.hbs | 9 +++++++- .../styles/components/console-ui-panel.scss | 8 ++++--- .../components/console/command-input.hbs | 5 ++-- .../templates/components/console/ui-panel.hbs | 23 ++++++++++--------- 6 files changed, 32 insertions(+), 23 deletions(-) diff --git a/ui/app/components/console/command-input.js b/ui/app/components/console/command-input.js index b5e319f5912e..bdeb404fa404 100644 --- a/ui/app/components/console/command-input.js +++ b/ui/app/components/console/command-input.js @@ -7,7 +7,6 @@ import Component from '@ember/component'; import keys from 'core/utils/key-codes'; export default Component.extend({ - onEscCommand() {}, onExecuteCommand() {}, onFullscreen() {}, onValueUpdate() {}, @@ -18,19 +17,17 @@ export default Component.extend({ actions: { handleKeyUp(event) { const keyCode = event.keyCode; + const val = event.target.value; switch (keyCode) { - case keys.ESC: - this.onEscCommand(keyCode); - break; case keys.ENTER: - this.onExecuteCommand(event.target.value); + this.onExecuteCommand(val); break; case keys.UP: case keys.DOWN: this.onShiftCommand(keyCode); break; default: - this.onValueUpdate(event.target.value); + this.onValueUpdate(val); } }, fullscreen() { diff --git a/ui/app/components/console/ui-panel.js b/ui/app/components/console/ui-panel.js index a001b051f5df..cecc3e71a3f3 100644 --- a/ui/app/components/console/ui-panel.js +++ b/ui/app/components/console/ui-panel.js @@ -159,6 +159,7 @@ export default Component.extend({ actions: { closeConsole() { this.set('console.isOpen', false); + // element.querySelector('[data-test-console-toggle').focus(); }, toggleFullscreen() { this.toggleProperty('isFullscreen'); diff --git a/ui/app/components/sidebar/frame.hbs b/ui/app/components/sidebar/frame.hbs index 2139385f3ade..7cd0c84b2f88 100644 --- a/ui/app/components/sidebar/frame.hbs +++ b/ui/app/components/sidebar/frame.hbs @@ -49,7 +49,14 @@ {{yield}}

- + {{#if this.console.isOpen}} + + {{/if}}
\ No newline at end of file diff --git a/ui/app/styles/components/console-ui-panel.scss b/ui/app/styles/components/console-ui-panel.scss index ed4b420ef5fd..52203b342fdd 100644 --- a/ui/app/styles/components/console-ui-panel.scss +++ b/ui/app/styles/components/console-ui-panel.scss @@ -14,7 +14,9 @@ $console-close-height: 35px; overflow: auto; position: fixed; bottom: 0; - transition: min-height $speed $easing, transform $speed ease-in; + transition: + min-height $speed $easing, + transform $speed ease-in; will-change: transform, min-height; -webkit-overflow-scrolling: touch; z-index: 199; @@ -118,11 +120,11 @@ $console-close-height: 35px; .panel-open .console-ui-panel { box-shadow: $box-shadow-highest; - min-height: 400px; + min-height: 425px; } .main--console-open { - padding-bottom: 400px; + padding-bottom: 425px; } .panel-open .console-ui-panel.fullscreen { diff --git a/ui/app/templates/components/console/command-input.hbs b/ui/app/templates/components/console/command-input.hbs index 363ae89b7e01..15196b02119b 100644 --- a/ui/app/templates/components/console/command-input.hbs +++ b/ui/app/templates/components/console/command-input.hbs @@ -10,19 +10,20 @@ {{/if}} diff --git a/ui/app/templates/components/console/ui-panel.hbs b/ui/app/templates/components/console/ui-panel.hbs index 9168ab39c7fe..13d9ccc39a2f 100644 --- a/ui/app/templates/components/console/ui-panel.hbs +++ b/ui/app/templates/components/console/ui-panel.hbs @@ -3,17 +3,19 @@ SPDX-License-Identifier: BUSL-1.1 ~}} -
- -
+
+
+ +
+

The Vault Web REPL provides an easy way to execute common Vault CLI commands, such as write, read, delete, and list. It @@ -44,6 +46,5 @@ @onFullscreen={{action "toggleFullscreen"}} @onExecuteCommand={{action "executeCommand"}} @onShiftCommand={{action "shiftCommandIndex"}} - @onEscCommand={{action "closeConsole"}} />

\ No newline at end of file From 36256daff1797a56b39a4b614ba687fa9a1e534a Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Mon, 13 May 2024 09:33:50 -0500 Subject: [PATCH 05/18] fix test to toggle panel open before using it move toggle to commands helper file move toggle to ui-panel helper file added shouldToggle arg to runcommand fix console tests --- ui/tests/acceptance/console-test.js | 10 ++++------ ui/tests/helpers/commands.js | 5 +++-- .../components/console/ui-panel-test.js | 16 ++++++++-------- .../integration/components/sidebar/frame-test.js | 4 ++-- ui/tests/pages/components/console/ui-panel.js | 8 +++++++- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/ui/tests/acceptance/console-test.js b/ui/tests/acceptance/console-test.js index 527605da81c2..0b532ff6bc8a 100644 --- a/ui/tests/acceptance/console-test.js +++ b/ui/tests/acceptance/console-test.js @@ -25,8 +25,6 @@ module('Acceptance | console', function (hooks) { assert.expect(6); await enginesPage.visit(); await settled(); - await consoleComponent.toggle(); - await settled(); const ids = [uuidv4(), uuidv4(), uuidv4()]; for (const id of ids) { const inputString = `write sys/mounts/console-route-${id} type=kv`; @@ -59,7 +57,7 @@ module('Acceptance | console', function (hooks) { test('fullscreen command expands the cli panel', async function (assert) { await consoleComponent.toggle(); await settled(); - await consoleComponent.runCommands('fullscreen'); + await consoleComponent.runCommands('fullscreen', false); await settled(); const consoleEle = document.querySelector('[data-test-component="console/ui-panel"]'); // wait for the CSS transition to finish @@ -74,7 +72,7 @@ module('Acceptance | console', function (hooks) { test('array output is correctly formatted', async function (assert) { await consoleComponent.toggle(); await settled(); - await consoleComponent.runCommands('read -field=policies /auth/token/lookup-self'); + await consoleComponent.runCommands('read -field=policies /auth/token/lookup-self', false); await settled(); const consoleOut = document.querySelector('.console-ui-output>pre'); // wait for the CSS transition to finish @@ -86,7 +84,7 @@ module('Acceptance | console', function (hooks) { test('number output is correctly formatted', async function (assert) { await consoleComponent.toggle(); await settled(); - await consoleComponent.runCommands('read -field=creation_time /auth/token/lookup-self'); + await consoleComponent.runCommands('read -field=creation_time /auth/token/lookup-self', false); await settled(); const consoleOut = document.querySelector('.console-ui-output>pre'); // wait for the CSS transition to finish @@ -97,7 +95,7 @@ module('Acceptance | console', function (hooks) { test('boolean output is correctly formatted', async function (assert) { await consoleComponent.toggle(); await settled(); - await consoleComponent.runCommands('read -field=orphan /auth/token/lookup-self'); + await consoleComponent.runCommands('read -field=orphan /auth/token/lookup-self', false); await settled(); const consoleOut = document.querySelector('.console-ui-output>pre'); // have to wrap in a later so that we can wait for the CSS transition to finish diff --git a/ui/tests/helpers/commands.js b/ui/tests/helpers/commands.js index 3cf3a19d189f..a1a0dd857b9a 100644 --- a/ui/tests/helpers/commands.js +++ b/ui/tests/helpers/commands.js @@ -1,10 +1,11 @@ -import consoleClass from 'vault/tests/pages/components/console/ui-panel'; -import { create } from 'ember-cli-page-object'; /** * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: BUSL-1.1 */ +import consoleClass from 'vault/tests/pages/components/console/ui-panel'; +import { create } from 'ember-cli-page-object'; + /** * Helper functions to run common commands in the consoleComponent during tests. * Please note that a user must be logged in during the test context for the commands to run. diff --git a/ui/tests/integration/components/console/ui-panel-test.js b/ui/tests/integration/components/console/ui-panel-test.js index 9275d43e9db7..25c0a22e99ea 100644 --- a/ui/tests/integration/components/console/ui-panel-test.js +++ b/ui/tests/integration/components/console/ui-panel-test.js @@ -23,20 +23,21 @@ module('Integration | Component | console/ui panel', function (hooks) { test('it clears console input on enter', async function (assert) { await render(hbs`{{console/ui-panel}}`); - - await component.runCommands('list this/thing/here'); + await component.runCommands('list this/thing/here', false); await settled(); assert.strictEqual(component.consoleInputValue, '', 'empties input field on enter'); }); test('it clears the log when using clear command', async function (assert) { await render(hbs`{{console/ui-panel}}`); - - await component.runCommands(['list this/thing/here', 'list this/other/thing', 'read another/thing']); + await component.runCommands( + ['list this/thing/here', 'list this/other/thing', 'read another/thing'], + false + ); await settled(); assert.notEqual(component.logOutput, '', 'there is output in the log'); - await component.runCommands('clear'); + await component.runCommands('clear', false); await settled(); await component.up(); await settled(); @@ -51,7 +52,7 @@ module('Integration | Component | console/ui panel', function (hooks) { test('it adds command to history on enter', async function (assert) { await render(hbs`{{console/ui-panel}}`); - await component.runCommands('list this/thing/here'); + await component.runCommands('list this/thing/here', false); await settled(); await component.up(); await settled(); @@ -67,8 +68,7 @@ module('Integration | Component | console/ui panel', function (hooks) { test('it cycles through history with more than one command', async function (assert) { await render(hbs`{{console/ui-panel}}`); - - await component.runCommands(['list this/thing/here', 'read that/thing/there', 'qwerty']); + await component.runCommands(['list this/thing/here', 'read that/thing/there', 'qwerty'], false); await settled(); await component.up(); await settled(); diff --git a/ui/tests/integration/components/sidebar/frame-test.js b/ui/tests/integration/components/sidebar/frame-test.js index 3bae4cc3fdc0..f597b133893d 100644 --- a/ui/tests/integration/components/sidebar/frame-test.js +++ b/ui/tests/integration/components/sidebar/frame-test.js @@ -35,7 +35,7 @@ module('Integration | Component | sidebar-frame', function (hooks) { assert.dom('[data-test-sidebar-nav]').doesNotExist('Sidebar is hidden'); }); - test('it should render link status, console ui panel and yield block for app content', async function (assert) { + test('it should render link status, console ui panel container and yield block for app content', async function (assert) { const currentCluster = this.owner.lookup('service:currentCluster'); currentCluster.setCluster({ hcpLinkStatus: 'connected' }); const version = this.owner.lookup('service:version'); @@ -50,7 +50,7 @@ module('Integration | Component | sidebar-frame', function (hooks) { `); assert.dom('[data-test-link-status]').exists('Link status component renders'); - assert.dom('[data-test-component="console/ui-panel"]').exists('Console UI panel renders'); + assert.dom('[data-test-console-panel]').exists('Console UI panel container renders'); assert.dom('.page-container').exists('Block yields for app content'); }); diff --git a/ui/tests/pages/components/console/ui-panel.js b/ui/tests/pages/components/console/ui-panel.js index 3bb6503c3157..35189d0c7f74 100644 --- a/ui/tests/pages/components/console/ui-panel.js +++ b/ui/tests/pages/components/console/ui-panel.js @@ -54,12 +54,18 @@ export default { eventProperties: { keyCode: keys.ENTER }, }), hasInput: isPresent('[data-test-component="console/command-input"] input'), - runCommands: async function (commands) { + runCommands: async function (commands, shouldToggle = true) { const toExecute = Array.isArray(commands) ? commands : [commands]; + if (shouldToggle) { + await this.toggle(); // toggle the console open + } for (const command of toExecute) { await this.consoleInput(command); await this.enter(); await settled(); } + if (shouldToggle) { + await this.toggle(); // toggle it closed + } }, }; From 425cc5be4b259a5df02a22a633292316d68d752e Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Mon, 13 May 2024 14:45:17 -0500 Subject: [PATCH 06/18] add changelog --- changelog/26872.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog/26872.txt diff --git a/changelog/26872.txt b/changelog/26872.txt new file mode 100644 index 000000000000..1b5de982936e --- /dev/null +++ b/changelog/26872.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: Resolved accessibility issues with Web REPL +``` \ No newline at end of file From 4bb5705640ad14d3cfcacca37cc281635d0e5e1f Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Mon, 13 May 2024 17:27:57 -0500 Subject: [PATCH 07/18] Update ui/app/components/console/ui-panel.js remove unnecessary comment --- ui/app/components/console/ui-panel.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/app/components/console/ui-panel.js b/ui/app/components/console/ui-panel.js index cecc3e71a3f3..a001b051f5df 100644 --- a/ui/app/components/console/ui-panel.js +++ b/ui/app/components/console/ui-panel.js @@ -159,7 +159,6 @@ export default Component.extend({ actions: { closeConsole() { this.set('console.isOpen', false); - // element.querySelector('[data-test-console-toggle').focus(); }, toggleFullscreen() { this.toggleProperty('isFullscreen'); From bf26929cb081ef070276c10fd756c591ed68d6cd Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Mon, 13 May 2024 18:42:44 -0500 Subject: [PATCH 08/18] Update test to try to get it to pass --- ui/tests/acceptance/oidc-provider-test.js | 72 ++++++++++++++--------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/ui/tests/acceptance/oidc-provider-test.js b/ui/tests/acceptance/oidc-provider-test.js index f69ae5070ffc..5ff1fdc084b6 100644 --- a/ui/tests/acceptance/oidc-provider-test.js +++ b/ui/tests/acceptance/oidc-provider-test.js @@ -36,45 +36,58 @@ const GROUP_TOKEN_TEMPLATE = `{ "groups": {{identity.entity.groups.names}} }`; const oidcEntity = async function (name, policy) { - return await runCmd([ - `write sys/policies/acl/${name} policy=${window.btoa(policy)}`, - `write identity/entity name="${OIDC_USER}" policies="${name}" metadata="email=vault@hashicorp.com" metadata="phone_number=123-456-7890"`, - `read -field=id identity/entity/name/${OIDC_USER}`, - ]); + return await runCmd( + [ + `write sys/policies/acl/${name} policy=${window.btoa(policy)}`, + `write identity/entity name="${OIDC_USER}" policies="${name}" metadata="email=vault@hashicorp.com" metadata="phone_number=123-456-7890"`, + `read -field=id identity/entity/name/${OIDC_USER}`, + ], + false + ); }; const oidcGroup = async function (entityId) { - return await runCmd([ - `write identity/group name="engineering" member_entity_ids="${entityId}"`, - `read -field=id identity/group/name/engineering`, - ]); + return await runCmd( + [ + `write identity/group name="engineering" member_entity_ids="${entityId}"`, + `read -field=id identity/group/name/engineering`, + ], + false + ); }; const authAccessor = async function (path = 'userpass') { await enablePage.enable('userpass', path); - return await runCmd([ - `write auth/${path}/users/end-user password="${USER_PASSWORD}"`, - `read -field=accessor sys/internal/ui/mounts/auth/${path}`, - ]); + return await runCmd( + [ + `write auth/${path}/users/end-user password="${USER_PASSWORD}"`, + `read -field=accessor sys/internal/ui/mounts/auth/${path}`, + ], + false + ); }; const entityAlias = async function (entityId, accessor, groupId) { const userTokenTemplate = btoa(USER_TOKEN_TEMPLATE); const groupTokenTemplate = btoa(GROUP_TOKEN_TEMPLATE); - const res = await runCmd([ - `write identity/entity-alias name="end-user" canonical_id="${entityId}" mount_accessor="${accessor}"`, - `write identity/oidc/key/sigkey allowed_client_ids="*"`, - `write identity/oidc/assignment/my-assignment group_ids="${groupId}" entity_ids="${entityId}"`, - `write identity/oidc/scope/user description="scope for user metadata" template="${userTokenTemplate}"`, - `write identity/oidc/scope/groups description="scope for groups" template="${groupTokenTemplate}"`, - ]); + const res = await runCmd( + [ + `write identity/entity-alias name="end-user" canonical_id="${entityId}" mount_accessor="${accessor}"`, + `write identity/oidc/key/sigkey allowed_client_ids="*"`, + `write identity/oidc/assignment/my-assignment group_ids="${groupId}" entity_ids="${entityId}"`, + `write identity/oidc/scope/user description="scope for user metadata" template="${userTokenTemplate}"`, + `write identity/oidc/scope/groups description="scope for groups" template="${groupTokenTemplate}"`, + ], + false + ); return res.includes('Success'); }; const setupProvider = async function (clientId) { await runCmd( - `write identity/oidc/provider/${PROVIDER_NAME} allowed_client_ids="${clientId}" scopes="user,groups"` + `write identity/oidc/provider/${PROVIDER_NAME} allowed_client_ids="${clientId}" scopes="user,groups"`, + false ); }; @@ -104,15 +117,18 @@ const setupOidc = async function (uid) { const authMethodPath = `oidc-userpass-${uid}`; const accessor = await authAccessor(authMethodPath); await entityAlias(entityId, accessor, groupId); - await runCmd([ - `delete identity/oidc/client/${WEB_APP_NAME}`, - `write identity/oidc/client/${WEB_APP_NAME} redirect_uris="${callback}" assignments="my-assignment" key="sigkey" id_token_ttl="30m" access_token_ttl="1h"`, - `clear`, - `read -field=client_id identity/oidc/client/${WEB_APP_NAME}`, - ]); + await runCmd( + [ + `delete identity/oidc/client/${WEB_APP_NAME}`, + `write identity/oidc/client/${WEB_APP_NAME} redirect_uris="${callback}" assignments="my-assignment" key="sigkey" id_token_ttl="30m" access_token_ttl="1h"`, + `clear`, + `read -field=client_id identity/oidc/client/${WEB_APP_NAME}`, + ], + false + ); await settled(); - const clientId = await runCmd([`read -field=client_id identity/oidc/client/${WEB_APP_NAME}`]); + const clientId = await runCmd([`read -field=client_id identity/oidc/client/${WEB_APP_NAME}`], false); await setupProvider(clientId); return { providerName: PROVIDER_NAME, From b319d1090e66bde5b7ef96e558d153b6d4af8b6b Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Tue, 14 May 2024 11:47:31 -0500 Subject: [PATCH 09/18] add support for console dismiss button --- ui/app/templates/components/console/command-input.hbs | 2 +- ui/tests/pages/components/console/ui-panel.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/app/templates/components/console/command-input.hbs b/ui/app/templates/components/console/command-input.hbs index 15196b02119b..57c604de2c3d 100644 --- a/ui/app/templates/components/console/command-input.hbs +++ b/ui/app/templates/components/console/command-input.hbs @@ -21,7 +21,7 @@ Date: Tue, 14 May 2024 14:35:37 -0500 Subject: [PATCH 10/18] updates to command helper for toggling console --- ui/tests/acceptance/pki/pki-engine-workflow-test.js | 1 + ui/tests/helpers/commands.js | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/tests/acceptance/pki/pki-engine-workflow-test.js b/ui/tests/acceptance/pki/pki-engine-workflow-test.js index 6852ce18589e..c9df281b8f1c 100644 --- a/ui/tests/acceptance/pki/pki-engine-workflow-test.js +++ b/ui/tests/acceptance/pki/pki-engine-workflow-test.js @@ -111,6 +111,7 @@ module('Acceptance | pki workflow', function (hooks) { allow_subdomains=true \ max_ttl="720h"`, ]); + await runCmd([`write ${this.mountPath}/root/generate/internal common_name="Hashicorp Test"`]); const pki_admin_policy = adminPolicy(this.mountPath, 'roles'); const pki_reader_policy = readerPolicy(this.mountPath, 'roles'); diff --git a/ui/tests/helpers/commands.js b/ui/tests/helpers/commands.js index a1a0dd857b9a..4f3da8e84ffc 100644 --- a/ui/tests/helpers/commands.js +++ b/ui/tests/helpers/commands.js @@ -46,8 +46,10 @@ export async function runCmd(commands, throwErrors = true) { if (!Array.isArray(commands)) { commands = [commands]; } - await cc.runCommands(commands); + await cc.toggle(); + await cc.runCommands(commands, false); const lastOutput = cc.lastLogOutput; + await cc.toggle(); if (throwErrors && lastOutput.includes('Error')) { throw new Error(`Error occurred while running commands: "${commands.join('; ')}" - ${lastOutput}`); } From 8bbb24a2550ebad6cadf7cf72c4f9c03135650a5 Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Tue, 14 May 2024 15:02:05 -0500 Subject: [PATCH 11/18] Adjusted code so tests pass --- ui/tests/acceptance/wrapped-token-test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/tests/acceptance/wrapped-token-test.js b/ui/tests/acceptance/wrapped-token-test.js index 150741b0ada6..876281a0d840 100644 --- a/ui/tests/acceptance/wrapped-token-test.js +++ b/ui/tests/acceptance/wrapped-token-test.js @@ -14,7 +14,12 @@ import consoleClass from 'vault/tests/pages/components/console/ui-panel'; const consoleComponent = create(consoleClass); const wrappedAuth = async () => { - await consoleComponent.runCommands(`write -field=token auth/token/create policies=default -wrap-ttl=3m`); + await consoleComponent.toggle(); + await settled(); + await consoleComponent.runCommands( + `write -field=token auth/token/create policies=default -wrap-ttl=3m`, + false + ); await settled(); return consoleComponent.lastLogOutput; }; From 6b39201ac432f3575a66a45dc6874f15954bbcb2 Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Tue, 14 May 2024 15:08:51 -0500 Subject: [PATCH 12/18] Fixed one of the failing tests (one is still failing) --- .../settings/mount-secret-backend-test.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ui/tests/acceptance/settings/mount-secret-backend-test.js b/ui/tests/acceptance/settings/mount-secret-backend-test.js index b437a2e8dab7..50b80fac2180 100644 --- a/ui/tests/acceptance/settings/mount-secret-backend-test.js +++ b/ui/tests/acceptance/settings/mount-secret-backend-test.js @@ -153,12 +153,16 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) { capabilities = ["read"] } `; - await consoleComponent.runCommands([ - // delete any previous mount with same name - `delete sys/mounts/${enginePath}`, - `write sys/policies/acl/kv-v2-degrade policy=${btoa(V2_POLICY)}`, - 'write -field=client_token auth/token/create policies=kv-v2-degrade', - ]); + await consoleComponent.toggle(); + await consoleComponent.runCommands( + [ + // delete any previous mount with same name + `delete sys/mounts/${enginePath}`, + `write sys/policies/acl/kv-v2-degrade policy=${btoa(V2_POLICY)}`, + 'write -field=client_token auth/token/create policies=kv-v2-degrade', + ], + false + ); await settled(); const userToken = consoleComponent.lastLogOutput; await logout.visit(); From 5977177bf57e9e1da71671af0dac58d4bd8aa5fb Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Tue, 14 May 2024 15:22:17 -0500 Subject: [PATCH 13/18] Adjusted code so tests pass --- ui/tests/acceptance/settings/auth/configure/section-test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/tests/acceptance/settings/auth/configure/section-test.js b/ui/tests/acceptance/settings/auth/configure/section-test.js index 318333a8962c..b6533273c0ee 100644 --- a/ui/tests/acceptance/settings/auth/configure/section-test.js +++ b/ui/tests/acceptance/settings/auth/configure/section-test.js @@ -7,7 +7,7 @@ import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import { setupMirage } from 'ember-cli-mirage/test-support'; import { create } from 'ember-cli-page-object'; -import { fillIn } from '@ember/test-helpers'; +import { fillIn, settled } from '@ember/test-helpers'; import { v4 as uuidv4 } from 'uuid'; import enablePage from 'vault/tests/pages/settings/auth/enable'; @@ -59,6 +59,8 @@ module('Acceptance | settings/auth/configure/section', function (hooks) { for (const type of ['aws', 'azure', 'gcp', 'github', 'kubernetes']) { test(`it shows tabs for auth method: ${type}`, async function (assert) { const path = `${type}-showtab-${this.uid}`; + await cli.toggle(); + await settled(); await cli.consoleInput(`write sys/auth/${path} type=${type}`); await cli.enter(); await indexPage.visit({ path }); From 7525254512382ee1f61b6475d15dfa4900f69ffb Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Tue, 14 May 2024 16:21:41 -0500 Subject: [PATCH 14/18] Adjusted code to fix test --- ui/tests/acceptance/redirect-to-test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/tests/acceptance/redirect-to-test.js b/ui/tests/acceptance/redirect-to-test.js index dc788d1dbac3..aee810e35968 100644 --- a/ui/tests/acceptance/redirect-to-test.js +++ b/ui/tests/acceptance/redirect-to-test.js @@ -25,7 +25,12 @@ const visit = async (url) => { const consoleComponent = create(consoleClass); const wrappedAuth = async () => { - await consoleComponent.runCommands(`write -field=token auth/token/create policies=default -wrap-ttl=5m`); + await consoleComponent.toggle(); + await settled(); + await consoleComponent.runCommands( + `write -field=token auth/token/create policies=default -wrap-ttl=5m`, + false + ); await settled(); // because of flaky test, trying to capture the token using a dom selector instead of the page object const token = document.querySelector('[data-test-component="console/log-text"] pre').textContent; From 30f9edc08a1f0c9a1ee5fa3e7eef6cba3b9ec2d9 Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Tue, 14 May 2024 16:33:11 -0500 Subject: [PATCH 15/18] Added additional changelog text --- changelog/26872.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/26872.txt b/changelog/26872.txt index 1b5de982936e..d3f278b557e8 100644 --- a/changelog/26872.txt +++ b/changelog/26872.txt @@ -1,3 +1,3 @@ ```release-note:bug -ui: Resolved accessibility issues with Web REPL +ui: Resolved accessibility issues with Web REPL. Associated label and help text with input, added a conditional to show the console/ui-panel only when toggled open, added keyboard focus trap. Note: this required an additional arg added for testing, to toggle the console open when it is necessary to use the console in tests. ``` \ No newline at end of file From a5b207603b85023eb0cbb06a443d818c56904170 Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Thu, 16 May 2024 10:18:30 -0500 Subject: [PATCH 16/18] Update changelog/26872.txt Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com> --- changelog/26872.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/26872.txt b/changelog/26872.txt index d3f278b557e8..3309a2310619 100644 --- a/changelog/26872.txt +++ b/changelog/26872.txt @@ -1,3 +1,3 @@ ```release-note:bug -ui: Resolved accessibility issues with Web REPL. Associated label and help text with input, added a conditional to show the console/ui-panel only when toggled open, added keyboard focus trap. Note: this required an additional arg added for testing, to toggle the console open when it is necessary to use the console in tests. +ui: Resolved accessibility issues with Web REPL. Associated label and help text with input, added a conditional to show the console/ui-panel only when toggled open, added keyboard focus trap. ``` \ No newline at end of file From 5029cf1d4744468131401e10be64d6e7d6efd1b9 Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Thu, 16 May 2024 10:22:11 -0500 Subject: [PATCH 17/18] Update ui/tests/acceptance/oidc-provider-test.js --- ui/tests/acceptance/oidc-provider-test.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ui/tests/acceptance/oidc-provider-test.js b/ui/tests/acceptance/oidc-provider-test.js index 5ff1fdc084b6..8a4ba40c50a2 100644 --- a/ui/tests/acceptance/oidc-provider-test.js +++ b/ui/tests/acceptance/oidc-provider-test.js @@ -41,9 +41,7 @@ const oidcEntity = async function (name, policy) { `write sys/policies/acl/${name} policy=${window.btoa(policy)}`, `write identity/entity name="${OIDC_USER}" policies="${name}" metadata="email=vault@hashicorp.com" metadata="phone_number=123-456-7890"`, `read -field=id identity/entity/name/${OIDC_USER}`, - ], - false - ); + ]); }; const oidcGroup = async function (entityId) { From b9d6b0cbbf3c23ceed925404aee8b9d1053e19fe Mon Sep 17 00:00:00 2001 From: Melanie Sumner Date: Thu, 16 May 2024 10:31:09 -0500 Subject: [PATCH 18/18] remove errant code --- ui/tests/acceptance/oidc-provider-test.js | 70 +++++++++-------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/ui/tests/acceptance/oidc-provider-test.js b/ui/tests/acceptance/oidc-provider-test.js index 8a4ba40c50a2..f69ae5070ffc 100644 --- a/ui/tests/acceptance/oidc-provider-test.js +++ b/ui/tests/acceptance/oidc-provider-test.js @@ -36,56 +36,45 @@ const GROUP_TOKEN_TEMPLATE = `{ "groups": {{identity.entity.groups.names}} }`; const oidcEntity = async function (name, policy) { - return await runCmd( - [ - `write sys/policies/acl/${name} policy=${window.btoa(policy)}`, - `write identity/entity name="${OIDC_USER}" policies="${name}" metadata="email=vault@hashicorp.com" metadata="phone_number=123-456-7890"`, - `read -field=id identity/entity/name/${OIDC_USER}`, - ]); + return await runCmd([ + `write sys/policies/acl/${name} policy=${window.btoa(policy)}`, + `write identity/entity name="${OIDC_USER}" policies="${name}" metadata="email=vault@hashicorp.com" metadata="phone_number=123-456-7890"`, + `read -field=id identity/entity/name/${OIDC_USER}`, + ]); }; const oidcGroup = async function (entityId) { - return await runCmd( - [ - `write identity/group name="engineering" member_entity_ids="${entityId}"`, - `read -field=id identity/group/name/engineering`, - ], - false - ); + return await runCmd([ + `write identity/group name="engineering" member_entity_ids="${entityId}"`, + `read -field=id identity/group/name/engineering`, + ]); }; const authAccessor = async function (path = 'userpass') { await enablePage.enable('userpass', path); - return await runCmd( - [ - `write auth/${path}/users/end-user password="${USER_PASSWORD}"`, - `read -field=accessor sys/internal/ui/mounts/auth/${path}`, - ], - false - ); + return await runCmd([ + `write auth/${path}/users/end-user password="${USER_PASSWORD}"`, + `read -field=accessor sys/internal/ui/mounts/auth/${path}`, + ]); }; const entityAlias = async function (entityId, accessor, groupId) { const userTokenTemplate = btoa(USER_TOKEN_TEMPLATE); const groupTokenTemplate = btoa(GROUP_TOKEN_TEMPLATE); - const res = await runCmd( - [ - `write identity/entity-alias name="end-user" canonical_id="${entityId}" mount_accessor="${accessor}"`, - `write identity/oidc/key/sigkey allowed_client_ids="*"`, - `write identity/oidc/assignment/my-assignment group_ids="${groupId}" entity_ids="${entityId}"`, - `write identity/oidc/scope/user description="scope for user metadata" template="${userTokenTemplate}"`, - `write identity/oidc/scope/groups description="scope for groups" template="${groupTokenTemplate}"`, - ], - false - ); + const res = await runCmd([ + `write identity/entity-alias name="end-user" canonical_id="${entityId}" mount_accessor="${accessor}"`, + `write identity/oidc/key/sigkey allowed_client_ids="*"`, + `write identity/oidc/assignment/my-assignment group_ids="${groupId}" entity_ids="${entityId}"`, + `write identity/oidc/scope/user description="scope for user metadata" template="${userTokenTemplate}"`, + `write identity/oidc/scope/groups description="scope for groups" template="${groupTokenTemplate}"`, + ]); return res.includes('Success'); }; const setupProvider = async function (clientId) { await runCmd( - `write identity/oidc/provider/${PROVIDER_NAME} allowed_client_ids="${clientId}" scopes="user,groups"`, - false + `write identity/oidc/provider/${PROVIDER_NAME} allowed_client_ids="${clientId}" scopes="user,groups"` ); }; @@ -115,18 +104,15 @@ const setupOidc = async function (uid) { const authMethodPath = `oidc-userpass-${uid}`; const accessor = await authAccessor(authMethodPath); await entityAlias(entityId, accessor, groupId); - await runCmd( - [ - `delete identity/oidc/client/${WEB_APP_NAME}`, - `write identity/oidc/client/${WEB_APP_NAME} redirect_uris="${callback}" assignments="my-assignment" key="sigkey" id_token_ttl="30m" access_token_ttl="1h"`, - `clear`, - `read -field=client_id identity/oidc/client/${WEB_APP_NAME}`, - ], - false - ); + await runCmd([ + `delete identity/oidc/client/${WEB_APP_NAME}`, + `write identity/oidc/client/${WEB_APP_NAME} redirect_uris="${callback}" assignments="my-assignment" key="sigkey" id_token_ttl="30m" access_token_ttl="1h"`, + `clear`, + `read -field=client_id identity/oidc/client/${WEB_APP_NAME}`, + ]); await settled(); - const clientId = await runCmd([`read -field=client_id identity/oidc/client/${WEB_APP_NAME}`], false); + const clientId = await runCmd([`read -field=client_id identity/oidc/client/${WEB_APP_NAME}`]); await setupProvider(clientId); return { providerName: PROVIDER_NAME,