diff --git a/addons/api/addon/serializers/credential-library.js b/addons/api/addon/serializers/credential-library.js index 1d35eaa07..609f21671 100644 --- a/addons/api/addon/serializers/credential-library.js +++ b/addons/api/addon/serializers/credential-library.js @@ -68,21 +68,25 @@ export default class CredentialLibrarySerializer extends ApplicationSerializer { */ handleCredentialMappingOverrides(serialized, isNew) { const { credential_type, credential_mapping_overrides } = serialized; + if (Object.keys(credential_mapping_overrides).length === 0) { serialized.credential_mapping_overrides = null; } - // API expects to send null to fields if it is undefined or deleted - if (credential_mapping_overrides && !isNew) { - serialized.credential_mapping_overrides = options.mapping_overrides[ - credential_type - ].reduce((obj, key) => { - if (credential_mapping_overrides[key]) { - obj[key] = credential_mapping_overrides[key]; - } else { - obj[key] = null; - } - return obj; - }, {}); + + if (!credential_mapping_overrides || isNew || !credential_type) { + return; } + + // API expects to send null to fields if it is undefined or deleted + serialized.credential_mapping_overrides = options.mapping_overrides[ + credential_type + ].reduce((obj, key) => { + if (credential_mapping_overrides[key]) { + obj[key] = credential_mapping_overrides[key]; + } else { + obj[key] = null; + } + return obj; + }, {}); } } diff --git a/addons/api/tests/unit/serializers/credential-library-test.js b/addons/api/tests/unit/serializers/credential-library-test.js index 158c9584c..fcb635751 100644 --- a/addons/api/tests/unit/serializers/credential-library-test.js +++ b/addons/api/tests/unit/serializers/credential-library-test.js @@ -138,6 +138,45 @@ module('Unit | Serializer | credential library', function (hooks) { }); }); + test('it serializes credential library updates without credential_type', function (assert) { + const store = this.owner.lookup('service:store'); + const serializer = store.serializerFor('credential-library'); + store.push({ + data: { + id: '1', + type: 'credential-library', + attributes: { + type: TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC, + name: 'Name', + description: 'Description', + path: '/vault/path', + http_method: 'GET', + version: 1, + credential_type: null, + credential_mapping_overrides: {}, + }, + }, + }); + const record = store.peekRecord('credential-library', '1'); + const snapshot = record._createSnapshot(); + const serializedRecord = serializer.serialize(snapshot); + + assert.deepEqual(serializedRecord, { + type: TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC, + credential_store_id: null, + name: 'Name', + description: 'Description', + credential_type: null, + credential_mapping_overrides: null, + attributes: { + path: '/vault/path', + http_method: 'GET', + http_request_body: null, + }, + version: 1, + }); + }); + test('it does not serialize http_request_body unless http_method is set to POST', function (assert) { const store = this.owner.lookup('service:store'); const record = store.createRecord('credential-library', { diff --git a/ui/admin/tests/acceptance/credential-library/update-test.js b/ui/admin/tests/acceptance/credential-library/update-test.js index bf80f3d9f..d7995cf65 100644 --- a/ui/admin/tests/acceptance/credential-library/update-test.js +++ b/ui/admin/tests/acceptance/credential-library/update-test.js @@ -460,4 +460,58 @@ module('Acceptance | credential-libraries | update', function (hooks) { selectors.FIELD_VAULT_PATH_VALUE, ); }); + + test('can update a vault generic credential library without credential_type and save changes without error', async function (assert) { + setRunOptions({ + rules: { + 'color-contrast': { + // [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2026-07-07 + enabled: false, + }, + }, + }); + + const credentialLibraryWithoutType = this.server.create( + 'credential-library', + { + scope: instances.scopes.project, + credentialStore: instances.credentialStore, + type: TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC, + credential_type: null, + credentialMappingOverrides: null, + }, + ); + + await visit( + `${urls.credentialLibraries}/${credentialLibraryWithoutType.id}`, + ); + + await click(commonSelectors.EDIT_BTN, 'Activate edit mode'); + await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE); + await fillIn( + commonSelectors.FIELD_DESCRIPTION, + commonSelectors.FIELD_DESCRIPTION_VALUE, + ); + await fillIn(selectors.FIELD_VAULT_PATH, selectors.FIELD_VAULT_PATH_VALUE); + + await click(commonSelectors.SAVE_BTN); + + const credentialLibrary = this.server.schema.credentialLibraries.find( + credentialLibraryWithoutType.id, + ); + + assert.strictEqual( + credentialLibrary.name, + commonSelectors.FIELD_NAME_VALUE, + ); + assert.strictEqual( + credentialLibrary.description, + commonSelectors.FIELD_DESCRIPTION_VALUE, + ); + assert.strictEqual( + credentialLibrary.attributes.path, + selectors.FIELD_VAULT_PATH_VALUE, + ); + assert.strictEqual(credentialLibrary.credentialType, null); + }); });