Skip to content

Commit

Permalink
UI Secrets Sync: Ember data sync destinations (#23674)
Browse files Browse the repository at this point in the history
* add models

* adapters

* base model adapter

* update test response

* add sync destinations helper

* finish renaming base destination model/adapter

* add comment

* add serializer

* use normalizeItems instead

* destination serializer test

* add destination find method;

* add conditional operand
  • Loading branch information
hellobontempo authored Oct 17, 2023
1 parent b0ca805 commit df35050
Show file tree
Hide file tree
Showing 22 changed files with 346 additions and 0 deletions.
20 changes: 20 additions & 0 deletions ui/app/adapters/sync/destination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import ApplicationAdapter from 'vault/adapters/application';

export default class SyncDestinationAdapter extends ApplicationAdapter {
namespace = 'v1';

_baseUrl() {
return `${this.buildURL()}/sys`;
}

// id is the destination name
// modelName is sync/destination/<destination type>
urlForFindRecord(id, modelName) {
return `${this._baseUrl()}/${modelName}/${id}`;
}
}
8 changes: 8 additions & 0 deletions ui/app/adapters/sync/destinations/aws-sm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationAdapter from '../destination';

export default class SyncDestinationsAwsSecretsManagerAdapter extends SyncDestinationAdapter {}
8 changes: 8 additions & 0 deletions ui/app/adapters/sync/destinations/azure-kv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationAdapter from '../destination';

export default class SyncDestinationsAzureKeyVaultAdapter extends SyncDestinationAdapter {}
8 changes: 8 additions & 0 deletions ui/app/adapters/sync/destinations/gcp-sm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationAdapter from '../destination';

export default class SyncDestinationGoogleCloudSecretManagerAdapter extends SyncDestinationAdapter {}
8 changes: 8 additions & 0 deletions ui/app/adapters/sync/destinations/gh.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationAdapter from '../destination';

export default class SyncDestinationsGithubAdapter extends SyncDestinationAdapter {}
8 changes: 8 additions & 0 deletions ui/app/adapters/sync/destinations/vercel-project.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationAdapter from '../destination';

export default class SyncDestinationsVercelProjectAdapter extends SyncDestinationAdapter {}
17 changes: 17 additions & 0 deletions ui/app/models/sync/destination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import Model, { attr } from '@ember-data/model';
import { findDestination } from 'vault/helpers/sync-destinations';

// Base model for all secret sync destination types
export default class SyncDestinationModel extends Model {
@attr('string') name;
@attr type;

get icon() {
return findDestination(this.type)?.icon;
}
}
15 changes: 15 additions & 0 deletions ui/app/models/sync/destinations/aws-sm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationModel from '../destination';
import { attr } from '@ember-data/model';
import { withFormFields } from 'vault/decorators/model-form-fields';

@withFormFields()
export default class SyncDestinationsAwsSecretsManagerModel extends SyncDestinationModel {
@attr('string') accessKeyId;
@attr('string') secretAccessKey;
@attr('string') region;
}
17 changes: 17 additions & 0 deletions ui/app/models/sync/destinations/azure-kv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationModel from '../destination';
import { attr } from '@ember-data/model';
import { withFormFields } from 'vault/decorators/model-form-fields';

@withFormFields()
export default class SyncDestinationsAzureKeyVaultModel extends SyncDestinationModel {
@attr('string') keyVaultUri;
@attr('string') clientId;
@attr('string') clientSecret;
@attr('string') tenantId;
@attr('string') cloud;
}
13 changes: 13 additions & 0 deletions ui/app/models/sync/destinations/gcp-sm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationModel from '../destination';
import { attr } from '@ember-data/model';
import { withFormFields } from 'vault/decorators/model-form-fields';

@withFormFields()
export default class SyncDestinationsGoogleCloudSecretManagerModel extends SyncDestinationModel {
@attr('string') credentials;
}
15 changes: 15 additions & 0 deletions ui/app/models/sync/destinations/gh.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationModel from '../destination';
import { attr } from '@ember-data/model';
import { withFormFields } from 'vault/decorators/model-form-fields';

@withFormFields()
export default class SyncDestinationsGithubModel extends SyncDestinationModel {
@attr('string') accessToken;
@attr('string') repositoryOwner;
@attr('string') repositoryName;
}
16 changes: 16 additions & 0 deletions ui/app/models/sync/destinations/vercel-project.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationModel from '../destination';
import { attr } from '@ember-data/model';
import { withFormFields } from 'vault/decorators/model-form-fields';

@withFormFields()
export default class SyncDestinationsVercelProjectModel extends SyncDestinationModel {
@attr('string') accessToken;
@attr('string') projectId;
@attr('string') teamId;
@attr('array') deploymentEnvironments;
}
19 changes: 19 additions & 0 deletions ui/app/serializers/sync/destination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import ApplicationSerializer from 'vault/serializers/application';

export default class SyncDestinationSerializer extends ApplicationSerializer {
primaryKey = 'name';

normalizeItems(payload) {
if (payload.data?.connection_details) {
const data = { ...payload.data, ...payload.data.connection_details };
delete data.connection_details;
return data;
}
return super.normalizeItems(...arguments);
}
}
8 changes: 8 additions & 0 deletions ui/app/serializers/sync/destinations/aws-sm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationSerializer from '../destination';

export default class SyncDestinationsAwsSecretsManagerSerializer extends SyncDestinationSerializer {}
8 changes: 8 additions & 0 deletions ui/app/serializers/sync/destinations/azure-kv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationSerializer from '../destination';

export default class SyncDestinationsAzureKeyVaultSerializer extends SyncDestinationSerializer {}
8 changes: 8 additions & 0 deletions ui/app/serializers/sync/destinations/gcp-sm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationSerializer from '../destination';

export default class SyncDestinationGoogleCloudSecretManagerSerializer extends SyncDestinationSerializer {}
8 changes: 8 additions & 0 deletions ui/app/serializers/sync/destinations/gh.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationSerializer from '../destination';

export default class SyncDestinationsGithubSerializer extends SyncDestinationSerializer {}
8 changes: 8 additions & 0 deletions ui/app/serializers/sync/destinations/vercel-project.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import SyncDestinationSerializer from '../destination';

export default class SyncDestinationsVercelProjectSerializer extends SyncDestinationSerializer {}
53 changes: 53 additions & 0 deletions ui/lib/core/addon/helpers/sync-destinations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { helper as buildHelper } from '@ember/component/helper';
import { assert } from '@ember/debug';

const SYNC_DESTINATIONS = [
{
displayName: 'AWS Secrets Manager',
type: 'aws-sm',
icon: 'aws-color',
},
{
displayName: 'Azure Key Vault',
type: 'azure-kv',
icon: 'azure-color',
},
{
displayName: 'Google Secret Manager',
type: 'gcp-sm',
icon: 'gcp-color',
},
{
displayName: 'Github Actions',
type: 'gh',
icon: 'github',
},
{
displayName: 'Vercel Project',
type: 'vercel-project',
icon: 'vercel',
},
];

export function syncDestinations() {
return [...SYNC_DESTINATIONS];
}

export function destinationTypes() {
return SYNC_DESTINATIONS.map((d) => d.type);
}

export function findDestination(type) {
assert(
`you must pass one of the following types: ${destinationTypes().join(', ')}`,
destinationTypes().includes(type)
);
return SYNC_DESTINATIONS.find((d) => d.type === type);
}

export default buildHelper(syncDestinations);
6 changes: 6 additions & 0 deletions ui/lib/core/app/helpers/sync-destinations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

export { default, syncDestinations, destinationTypes, findDestination } from 'core/helpers/sync-destinations';
37 changes: 37 additions & 0 deletions ui/tests/unit/adapters/sync/destinations-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { setupTest } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { destinationTypes } from 'vault/helpers/sync-destinations';

module('Unit | Adapter | sync/destinations', function (hooks) {
setupTest(hooks);
setupMirage(hooks);

hooks.beforeEach(function () {
this.store = this.owner.lookup('service:store');
});

test('it calls the correct endpoint for findRecord', async function (assert) {
const types = destinationTypes();
assert.expect(types.length);

for (const type of types) {
this.server.get(`sys/sync/destinations/${type}/my-dest`, () => {
assert.ok(true, `request is made to GET sys/sync/destinations/${type}/my-dest endpoint on find`);
return {
data: {
connection_details: {},
name: 'my-dest',
type,
},
};
});
this.store.findRecord(`sync/destinations/${type}`, 'my-dest');
}
});
});
38 changes: 38 additions & 0 deletions ui/tests/unit/serializers/sync/destinations-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { module, test } from 'qunit';
import { setupTest } from 'vault/tests/helpers';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { destinationTypes } from 'vault/helpers/sync-destinations';

module('Unit | Serializer | sync/destination', function (hooks) {
setupTest(hooks);
setupMirage(hooks);

hooks.beforeEach(function () {
this.serializer = this.owner.lookup('serializer:sync/destination');
});

test('it normalizes the payload from the server', async function (assert) {
const types = destinationTypes();
assert.expect(types.length);

for (const destinationType of types) {
const { name, type, id, ...connection_details } = this.server.create(
'sync-destination',
destinationType
);
const serverData = { request_id: id, data: { name, type, connection_details } };
const normalized = this.serializer.normalizeItems(serverData);
const expected = { type, name, ...connection_details };
assert.propEqual(
normalized,
expected,
`connection details key is removed and params are added to ${destinationType} data object`
);
}
});
});

0 comments on commit df35050

Please sign in to comment.