diff --git a/addons/api/addon/generated/models/credential-library.js b/addons/api/addon/generated/models/credential-library.js new file mode 100644 index 000000000..895c467f9 --- /dev/null +++ b/addons/api/addon/generated/models/credential-library.js @@ -0,0 +1,42 @@ +import BaseModel from '../../models/base'; +import { attr } from '@ember-data/model'; + +/** + * A credential library is a resource that can generate and retrieve + * credentials. + */ +export default class GeneratedCredentialLibraryModel extends BaseModel { + // =attributes + + @attr('string', { + description: 'The owning credential store ID.', + }) + credential_store_id; + + @attr('string', { + description: 'Optional name for identification purposes', + }) + name; + + @attr('string', { + description: 'Optional user-set description for identification purposes', + }) + description; + + @attr('date', { + description: 'The time this resource was created\nOutput only.', + readOnly: true, + }) + created_time; + + @attr('date', { + description: 'The time this resource was last updated\nOutput only.', + readOnly: true, + }) + updated_time; + + @attr('number', { + description: 'Current version number of this resource.', + }) + version; +} diff --git a/addons/api/addon/generated/models/credential-store.js b/addons/api/addon/generated/models/credential-store.js index 78834dc51..51dd4af87 100644 --- a/addons/api/addon/generated/models/credential-store.js +++ b/addons/api/addon/generated/models/credential-store.js @@ -5,7 +5,7 @@ import { attr } from '@ember-data/model'; * A credential store is a resource that can retrieve, store, and potentially * generate credentials. */ -export default class GeneratedAccountModel extends BaseModel { +export default class GeneratedCredentialStoreModel extends BaseModel { // =attributes @attr('string', { diff --git a/addons/api/addon/models/credential-library.js b/addons/api/addon/models/credential-library.js new file mode 100644 index 000000000..c95b9f73e --- /dev/null +++ b/addons/api/addon/models/credential-library.js @@ -0,0 +1,23 @@ +import GeneratedCredentialLibraryModel from '../generated/models/credential-library'; +import { attr } from '@ember-data/model'; +import { fragment } from 'ember-data-model-fragments/attributes'; + +export default class CredentialLibraryModel extends GeneratedCredentialLibraryModel { + // =error attributes + // These attributes exist solely to capture errors on nested fields. + // See the application adapter's error normalization method for + // more information. + + @attr('string', { readOnly: true }) attributes_http_method; + @attr('string', { readOnly: true }) attributes_http_request_body; + @attr('string', { readOnly: true }) attributes_path; + + // =attributes + + /** + * Attributes of this resource, if any, represented as a JSON fragment. + * @type {FragmentCredentialLibraryAttributesModel} + */ + @fragment('fragment-credential-library-attributes', { defaultValue: {} }) + attributes; +} diff --git a/addons/api/addon/models/fragment-credential-library-attributes.js b/addons/api/addon/models/fragment-credential-library-attributes.js new file mode 100644 index 000000000..dd6138199 --- /dev/null +++ b/addons/api/addon/models/fragment-credential-library-attributes.js @@ -0,0 +1,23 @@ +import Fragment from 'ember-data-model-fragments/fragment'; +import { attr } from '@ember-data/model'; + +export default class FragmentCredentialLibraryAttributesModel extends Fragment { + //= attributes (vault) + + @attr('string', { + description: + 'The HTTP method the library uses when requesting credentials from Vault.', + }) + http_method; + + @attr('string', { + description: + 'The body of the HTTP request the library sends to Vault when requesting credentials. Only valid if `http_method` is set to `POST`.', + }) + http_request_body; + + @attr('string', { + description: 'The path in Vault to request credentials from.', + }) + path; +} diff --git a/addons/api/addon/serializers/credential-library.js b/addons/api/addon/serializers/credential-library.js new file mode 100644 index 000000000..d1ced9a2b --- /dev/null +++ b/addons/api/addon/serializers/credential-library.js @@ -0,0 +1,3 @@ +import ApplicationSerializer from './application'; + +export default class CredentialLibrarySerializer extends ApplicationSerializer {} diff --git a/addons/api/addon/serializers/fragment-credential-library-attributes.js b/addons/api/addon/serializers/fragment-credential-library-attributes.js new file mode 100644 index 000000000..8d52b101f --- /dev/null +++ b/addons/api/addon/serializers/fragment-credential-library-attributes.js @@ -0,0 +1,27 @@ +import JSONSerializer from '@ember-data/serializer/json'; + +export default class FragmentCredentialLibraryAttributesSerializer extends JSONSerializer { + /** + * If an attribute is annotated as readOnly in the model, don't serialize it. + * Otherwise delegate to default attribute serializer. + * Only serialize http_request_body when `http_method` is set to `POST`. + * @override + * @method serializeAttribute + * @param {Snapshot} snapshot + * @param {Object} json + * @param {String} key + * @param {Object} attribute + */ + serializeAttribute(snapshot, json, key, attribute) { + const { type, options } = attribute; + let value = super.serializeAttribute(...arguments); + // Convert empty strings to null. + if (type === 'string' && json[key] === '') json[key] = null; + // Do not serialize read-only attributes. + if (options.readOnly) delete json[key]; + // Do not serialize http_request_body unless http_method is POST + if (key === 'http_request_body' && !json['http_method']?.match(/post/i)) + delete json[key]; + return value; + } +} diff --git a/addons/api/app/models/credential-library.js b/addons/api/app/models/credential-library.js new file mode 100644 index 000000000..b9f39e29d --- /dev/null +++ b/addons/api/app/models/credential-library.js @@ -0,0 +1 @@ +export { default } from 'api/models/credential-library'; diff --git a/addons/api/app/models/fragment-credential-library-attributes.js b/addons/api/app/models/fragment-credential-library-attributes.js new file mode 100644 index 000000000..04d8f2597 --- /dev/null +++ b/addons/api/app/models/fragment-credential-library-attributes.js @@ -0,0 +1 @@ +export { default } from 'api/models/fragment-credential-library-attributes'; diff --git a/addons/api/app/serializers/credential-library.js b/addons/api/app/serializers/credential-library.js new file mode 100644 index 000000000..2a76b7b03 --- /dev/null +++ b/addons/api/app/serializers/credential-library.js @@ -0,0 +1 @@ +export { default } from 'api/serializers/credential-library'; diff --git a/addons/api/app/serializers/fragment-credential-library-attributes.js b/addons/api/app/serializers/fragment-credential-library-attributes.js new file mode 100644 index 000000000..d16c81e21 --- /dev/null +++ b/addons/api/app/serializers/fragment-credential-library-attributes.js @@ -0,0 +1 @@ +export { default } from 'api/serializers/fragment-credential-library-attributes'; diff --git a/addons/api/tests/unit/models/credential-library-test.js b/addons/api/tests/unit/models/credential-library-test.js new file mode 100644 index 000000000..4cd00ab05 --- /dev/null +++ b/addons/api/tests/unit/models/credential-library-test.js @@ -0,0 +1,13 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Model | credential library', function (hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function (assert) { + let store = this.owner.lookup('service:store'); + let model = store.createRecord('credential-library', {}); + assert.ok(model); + }); +}); diff --git a/addons/api/tests/unit/models/fragment-credential-library-attributes-test.js b/addons/api/tests/unit/models/fragment-credential-library-attributes-test.js new file mode 100644 index 000000000..01f649c1e --- /dev/null +++ b/addons/api/tests/unit/models/fragment-credential-library-attributes-test.js @@ -0,0 +1,19 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Model | fragment credential library attributes', + function (hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function (assert) { + let store = this.owner.lookup('service:store'); + let model = store.createRecord( + 'fragment-credential-library-attributes', + {} + ); + assert.ok(model); + }); + } +); diff --git a/addons/api/tests/unit/serializers/credential-library-test.js b/addons/api/tests/unit/serializers/credential-library-test.js new file mode 100644 index 000000000..4be3c76f2 --- /dev/null +++ b/addons/api/tests/unit/serializers/credential-library-test.js @@ -0,0 +1,67 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Serializer | credential library', function (hooks) { + setupTest(hooks); + + test('it serializes correctly on create', function (assert) { + assert.expect(1); + const store = this.owner.lookup('service:store'); + const serializer = store.serializerFor('credential-library'); + const record = store.createRecord('credential-library', { + name: 'Name', + description: 'Description', + attributes: { + path: '/vault/path', + http_method: 'GET', + }, + version: 1, + }); + const snapshot = record._createSnapshot(); + const serializedRecord = serializer.serialize(snapshot); + assert.deepEqual(serializedRecord, { + credential_store_id: null, + name: 'Name', + description: 'Description', + version: 1, + attributes: { + path: '/vault/path', + http_method: 'GET', + }, + }); + }); + + test('it serializes correctly on update', function (assert) { + assert.expect(1); + const store = this.owner.lookup('service:store'); + const serializer = store.serializerFor('credential-library'); + store.push({ + data: { + id: '1', + type: 'credential-library', + attributes: { + name: 'Name', + description: 'Description', + attributes: { + path: '/vault/path', + http_method: 'GET', + }, + version: 1, + }, + }, + }); + const record = store.peekRecord('credential-library', '1'); + const snapshot = record._createSnapshot(); + const serializedRecord = serializer.serialize(snapshot); + assert.deepEqual(serializedRecord, { + credential_store_id: null, + name: 'Name', + description: 'Description', + attributes: { + path: '/vault/path', + http_method: 'GET', + }, + version: 1, + }); + }); +}); diff --git a/addons/api/tests/unit/serializers/fragment-credential-library-attributes-test.js b/addons/api/tests/unit/serializers/fragment-credential-library-attributes-test.js new file mode 100644 index 000000000..72818936c --- /dev/null +++ b/addons/api/tests/unit/serializers/fragment-credential-library-attributes-test.js @@ -0,0 +1,59 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Serializer | fragment credential library attributes', + function (hooks) { + setupTest(hooks); + + test('it serializes empty strings to null', function (assert) { + assert.expect(1); + const store = this.owner.lookup('service:store'); + const record = store.createRecord( + 'fragment-credential-library-attributes', + { + http_method: '', + path: null, + } + ); + let serializedRecord = record.serialize(); + assert.deepEqual(serializedRecord, { + http_method: null, + path: null, + }); + }); + + test('it does not serialize http_request_body unless http_method is set to POST', function (assert) { + assert.expect(2); + const store = this.owner.lookup('service:store'); + const record = store.createRecord( + 'fragment-credential-library-attributes', + { + http_method: 'GET', + http_request_body: 'body', + } + ); + let serializedRecord = record.serialize(); + assert.deepEqual( + serializedRecord, + { + http_method: 'GET', + path: null, + }, + 'http_request_body attribute is not expected' + ); + + record.http_method = 'POST'; + serializedRecord = record.serialize(); + assert.deepEqual( + serializedRecord, + { + http_method: 'POST', + http_request_body: 'body', + path: null, + }, + 'http_request_body attribute is expected' + ); + }); + } +);