diff --git a/changelog/23585.txt b/changelog/23585.txt new file mode 100644 index 000000000000..42c9a498c67b --- /dev/null +++ b/changelog/23585.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: Assumes version 1 for kv engines when options are null because no version is specified +``` \ No newline at end of file diff --git a/ui/app/serializers/secret-engine.js b/ui/app/serializers/secret-engine.js index 2c22ff5df269..37d51f599540 100644 --- a/ui/app/serializers/secret-engine.js +++ b/ui/app/serializers/secret-engine.js @@ -28,7 +28,7 @@ export default ApplicationSerializer.extend(EmbeddedRecordsMixin, { for (const attribute in backend) { struct[attribute] = backend[attribute]; } - //queryRecord adds path to the response + // queryRecord adds path to the response if (path !== null && !struct.path) { struct.path = path; } @@ -40,6 +40,13 @@ export default ApplicationSerializer.extend(EmbeddedRecordsMixin, { // strip the trailing slash off of the path so we // can navigate to it without getting `//` in the url struct.id = struct.path.slice(0, -1); + + if (backend?.type === 'kv' && !backend?.options?.version) { + // enabling kv in the CLI without a version flag mounts a v1 engine + // however, when no version is specified the options key is null + // we explicitly set v1 here, otherwise v2 is pulled from the ember model default + struct.options = { version: '1', ...struct.options }; + } return struct; }, diff --git a/ui/tests/unit/serializers/secret-engine-test.js b/ui/tests/unit/serializers/secret-engine-test.js new file mode 100644 index 000000000000..ede64c9e0fc4 --- /dev/null +++ b/ui/tests/unit/serializers/secret-engine-test.js @@ -0,0 +1,126 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: BUSL-1.1 + */ + +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Serializer | secret-engine', function (hooks) { + setupTest(hooks); + + hooks.beforeEach(function () { + this.serializer = this.owner.lookup('serializer:secret-engine'); + this.path = 'kv-engine/'; + this.backend = { + accessor: 'kv_77813cc8', + config: { + default_lease_ttl: 0, + force_no_cache: false, + max_lease_ttl: 0, + }, + deprecation_status: 'supported', + description: '', + external_entropy_access: false, + local: true, + options: null, + plugin_version: '', + running_plugin_version: 'v0.16.1+builtin', + running_sha256: '', + seal_wrap: false, + type: 'kv', + uuid: '400a4673-6bd9-1336-b84c-caf43ee28340', + }; + }); + + test('it should not overwrite options for version 2', async function (assert) { + assert.expect(1); + this.backend.options = { version: '2' }; + const expectedData = { + ...this.backend, + id: 'kv-engine', + path: 'kv-engine/', + options: { + version: '2', + }, + }; + assert.propEqual( + this.serializer.normalizeBackend(this.path, this.backend), + expectedData, + 'options contain version 2' + ); + }); + + test('it should add version 1 for kv mounts when options is null', async function (assert) { + assert.expect(1); + + const expectedData = { + ...this.backend, + id: 'kv-engine', + path: 'kv-engine/', + options: { + version: '1', + }, + }; + assert.propEqual( + this.serializer.normalizeBackend(this.path, this.backend), + expectedData, + 'options contains version 1' + ); + }); + + test('it should add version 1 for kv mounts if options has data but no version key', async function (assert) { + assert.expect(1); + + this.backend.options = { foo: 'bar' }; + const expectedData = { + ...this.backend, + id: 'kv-engine', + path: 'kv-engine/', + options: { + foo: 'bar', + version: '1', + }, + }; + + assert.propEqual( + this.serializer.normalizeBackend(this.path, this.backend), + expectedData, + 'it adds version 1 to existing options' + ); + }); + + test('it should not update options for non-kv engines', async function (assert) { + assert.expect(1); + + const cubbyholeData = { + accessor: 'cubbyhole_8a89fbc7', + config: { + default_lease_ttl: 0, + force_no_cache: false, + max_lease_ttl: 0, + }, + description: 'per-token private secret storage', + external_entropy_access: false, + local: true, + options: null, + plugin_version: '', + running_plugin_version: 'v1.15.0+builtin.vault', + running_sha256: '', + seal_wrap: false, + type: 'cubbyhole', + uuid: 'a7638176-6c6e-2c65-0e50-05d689ef7fc8', + }; + + const expectedData = { + ...cubbyholeData, + id: 'cubbyhole', + path: 'cubbyhole/', + }; + assert.propEqual( + this.serializer.normalizeBackend('cubbyhole/', cubbyholeData), + expectedData, + 'options are still null' + ); + }); +});