From 45fc58fe757b53980848389d3b0bdfb2ec759ec8 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Sun, 18 Jul 2021 14:31:45 -0400 Subject: [PATCH 01/68] feat: Init credential library creation --- addons/api/addon/models/credential-library.js | 13 ++- addons/api/mirage/config.js | 10 +- addons/core/translations/form/en-us.yaml | 9 ++ addons/core/translations/resources/en-us.yaml | 2 + .../form/credential-library/index.hbs | 105 ++++++++++++++++++ .../form/credential-library/index.js | 20 ++++ ui/admin/app/router.js | 4 +- .../credential-stores/credential-store.js | 7 +- .../credential-store/credential-libraries.js | 37 ++++++ .../credential-libraries/new.js | 45 ++++++++ .../credential-stores/credential-store.hbs | 2 +- .../credential-store/-actions.hbs | 12 ++ .../credential-libraries/new.hbs | 7 ++ .../credential-libraries/new/-header.hbs | 3 + .../form/credential-library/index-test.js | 29 +++++ .../credential-libraries/new-test.js | 16 +++ 16 files changed, 316 insertions(+), 5 deletions(-) create mode 100644 ui/admin/app/components/form/credential-library/index.hbs create mode 100644 ui/admin/app/components/form/credential-library/index.js create mode 100644 ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js create mode 100644 ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs create mode 100644 ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/new.hbs create mode 100644 ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/new/-header.hbs create mode 100644 ui/admin/tests/integration/components/form/credential-library/index-test.js create mode 100644 ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new-test.js diff --git a/addons/api/addon/models/credential-library.js b/addons/api/addon/models/credential-library.js index c95b9f73e..4ca321a18 100644 --- a/addons/api/addon/models/credential-library.js +++ b/addons/api/addon/models/credential-library.js @@ -2,13 +2,24 @@ import GeneratedCredentialLibraryModel from '../generated/models/credential-libr import { attr } from '@ember-data/model'; import { fragment } from 'ember-data-model-fragments/attributes'; +/** + * Enum options for credential library. + */ +export const options = { + http_methods: ['GET', 'POST'], +}; + 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, + defaultValue: options.http_methods[0], + }) + attributes_http_method; @attr('string', { readOnly: true }) attributes_http_request_body; @attr('string', { readOnly: true }) attributes_path; diff --git a/addons/api/mirage/config.js b/addons/api/mirage/config.js index 1fd364182..a45cd1bab 100644 --- a/addons/api/mirage/config.js +++ b/addons/api/mirage/config.js @@ -478,7 +478,15 @@ export default function () { ) => credentialLibraries.where({ credentialStoreId }) ); this.get('/credential-libraries/:id'); - this.post('/credential-libraries/:id'); + this.post( + '/credential-libraries', + function ({ credentialStores, credentialLibraries }) { + const attrs = this.normalizedRequestAttrs(); + const credentialStore = credentialStores.find(attrs.credentialStoreId); + attrs.scopeId = credentialStore.scope.id; + return credentialLibraries.create(attrs); + } + ); this.del('/credential-libraries/:id'); this.patch('/credential-libraries/:id'); diff --git a/addons/core/translations/form/en-us.yaml b/addons/core/translations/form/en-us.yaml index cb7b69832..b59b55b91 100644 --- a/addons/core/translations/form/en-us.yaml +++ b/addons/core/translations/form/en-us.yaml @@ -115,3 +115,12 @@ value: callback_url: label: Callback URL help: The URL to which the third-party provider sends the authentication response. Paste this into the provider configuration. +vault_path: + label: Vault Path + help: The path in Vault to request credentials from. +http_method: + label: HTTP Method + help: The HTTP method the library uses when requesting credentials from Vault. +http_request_body: + label: HTTP Request Body + help: The body of the HTTP request the library sends to Vault when requesting credentials. diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index cc9fed978..9468e3500 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -275,6 +275,8 @@ credential-library: title: Credential Library title_plural: Credential Libraries description: A credential library is a resource that provides credentials. + actions: + create: New Credential Library messages: none: title: No Credential Libraries Available diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs new file mode 100644 index 000000000..f5bd6c4eb --- /dev/null +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -0,0 +1,105 @@ + + + {{#if @model.errors.name}} + + {{#each @model.errors.name as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.description}} + + {{#each @model.errors.description as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.name}} + + {{#each @model.errors.name as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#each this.httpMethods as |httpMethod|}} + + {{/each}} + + + {{#if this.isHttpRequestBodyAllowed}} + + {{#if @model.errors.description}} + + {{#each @model.errors.description as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + {{/if}} + + + \ No newline at end of file diff --git a/ui/admin/app/components/form/credential-library/index.js b/ui/admin/app/components/form/credential-library/index.js new file mode 100644 index 000000000..69427c13b --- /dev/null +++ b/ui/admin/app/components/form/credential-library/index.js @@ -0,0 +1,20 @@ +import Component from '@glimmer/component'; +import { options } from 'api/models/credential-library'; +import { computed } from '@ember/object'; + +export default class FormCredentialLibraryIndexComponent extends Component { + // =properties + /** + * @type {object} + */ + httpMethods = options.http_methods; + + /** + * Only allow HTTP request body field if http_method is set to POST. + * @type {boolean} + */ + @computed('args.model.attributes_http_method') + get isHttpRequestBodyAllowed() { + return this.args.model.attributes_http_method?.match(/post/i); + } +} diff --git a/ui/admin/app/router.js b/ui/admin/app/router.js index 4012791b2..3c359e268 100644 --- a/ui/admin/app/router.js +++ b/ui/admin/app/router.js @@ -91,7 +91,9 @@ Router.map(function () { 'credential-store', { path: ':credential_store_id' }, function () { - this.route('credential-libraries', function () {}); + this.route('credential-libraries', function () { + this.route('new'); + }); } ); this.route('new'); diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js index 307c11079..fa5b56baf 100644 --- a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js @@ -10,7 +10,7 @@ export default class ScopesScopeCredentialStoresCredentialStoreRoute extends Rou } /** - * Render credential store header and navigation page sections. + * Render credential store header, navigation, and actions page sections. * @override */ renderTemplate() { @@ -25,5 +25,10 @@ export default class ScopesScopeCredentialStoresCredentialStoreRoute extends Rou into: 'scopes/scope/credential-stores/credential-store', outlet: 'navigation', }); + + this.render('scopes/scope/credential-stores/credential-store/-actions', { + into: 'scopes/scope/credential-stores/credential-store', + outlet: 'actions', + }); } } diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js index 7c8ade755..fa54e9691 100644 --- a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js @@ -1,4 +1,7 @@ import Route from '@ember/routing/route'; +import { action } from '@ember/object'; +import loading from 'ember-loading/decorator'; +import { notifySuccess, notifyError } from 'core/decorators/notify'; export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrariesRoute extends Route { // =methods @@ -13,4 +16,38 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari ); return this.store.query('credential-library', { credential_store_id }); } + + // =actions + + /** + * Rollback changes on a credential library. + * @param {CredentialLibraryModel} credentialLibrary + */ + @action + cancel(credentialLibrary) { + const { isNew } = credentialLibrary; + credentialLibrary.rollbackAttributes(); + if (isNew) + this.transitionTo( + 'scopes.scope.credential-stores.credential-store.credential-libraries' + ); + } + + /** + * Handle save of a credential library + * @param {CredentialLibraryModel} credentialLibrary + */ + @action + @loading + @notifyError(({ message }) => message) + @notifySuccess(({ isNew }) => + isNew ? 'notifications.create-success' : 'notifications.save-success' + ) + async save(credentialLibrary) { + await credentialLibrary.save(); + await this.transitionTo( + 'scopes.scope.credential-stores.credential-store.credential-libraries' + ); + this.refresh(); + } } diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js new file mode 100644 index 000000000..d83109dda --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js @@ -0,0 +1,45 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrariesNewRoute extends Route { + // =methods + + /** + * Creates a new unsaved credential library in current credential store. + * @return {CredentialLibraryModel} + */ + model() { + const { id: credential_store_id } = this.modelFor( + 'scopes.scope.credential-stores.credential-store' + ); + return this.store.createRecord('credential-library', { + credential_store_id, + }); + } + + /** + * Renders new credential library specific templates for header, navigation, + * and action page sections. + * @override + */ + renderTemplate() { + super.renderTemplate(...arguments); + + this.render( + 'scopes/scope/credential-stores/credential-store/credential-libraries/new/-header', + { + into: 'scopes/scope/credential-stores/credential-store', + outlet: 'header', + } + ); + + this.render('_empty', { + into: 'scopes/scope/credential-stores/credential-store', + outlet: 'navigation', + }); + + this.render('_empty', { + into: 'scopes/scope/credential-stores/credential-store', + outlet: 'actions', + }); + } +} diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store.hbs index a6ecd7f81..efc46641a 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store.hbs @@ -15,7 +15,7 @@ - {{!-- {{outlet 'actions'}} --}} + {{outlet 'actions'}} diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs new file mode 100644 index 000000000..587d095db --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs @@ -0,0 +1,12 @@ + + + {{t 'resources.credential-library.actions.create'}} + + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/new.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/new.hbs new file mode 100644 index 000000000..5d03e5b9f --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/new.hbs @@ -0,0 +1,7 @@ +{{page-title (t 'titles.new')}} + + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/new/-header.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/new/-header.hbs new file mode 100644 index 000000000..51755b136 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/new/-header.hbs @@ -0,0 +1,3 @@ +

+ {{t 'titles.new'}} +

\ No newline at end of file diff --git a/ui/admin/tests/integration/components/form/credential-library/index-test.js b/ui/admin/tests/integration/components/form/credential-library/index-test.js new file mode 100644 index 000000000..e0d24a8c2 --- /dev/null +++ b/ui/admin/tests/integration/components/form/credential-library/index-test.js @@ -0,0 +1,29 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module( + 'Integration | Component | form/credential-library/index', + function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + + await render(hbs``); + + assert.equal(this.element.textContent.trim(), ''); + + // Template block usage: + await render(hbs` + + template block text + + `); + + assert.equal(this.element.textContent.trim(), 'template block text'); + }); + } +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new-test.js b/ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new-test.js new file mode 100644 index 000000000..3c4efdd66 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Route | scopes/scope/credential-stores/credential-store/credential-libraries/new', + function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup( + 'route:scopes/scope/credential-stores/credential-store/credential-libraries/new' + ); + assert.ok(route); + }); + } +); From 98e14a642fe13c7e514d49b2d8b810f144da8b19 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 19 Jul 2021 12:05:40 -0400 Subject: [PATCH 02/68] fix: Treat credential library attributes as an object --- addons/api/mirage/config.js | 1 + .../form/credential-library/index.hbs | 8 ++--- .../form/credential-library/index.js | 4 +-- .../credential-libraries/index.hbs | 6 ++++ .../form/credential-library/index-test.js | 29 ------------------- 5 files changed, 13 insertions(+), 35 deletions(-) delete mode 100644 ui/admin/tests/integration/components/form/credential-library/index-test.js diff --git a/addons/api/mirage/config.js b/addons/api/mirage/config.js index a45cd1bab..5d9ddaf8e 100644 --- a/addons/api/mirage/config.js +++ b/addons/api/mirage/config.js @@ -484,6 +484,7 @@ export default function () { const attrs = this.normalizedRequestAttrs(); const credentialStore = credentialStores.find(attrs.credentialStoreId); attrs.scopeId = credentialStore.scope.id; + console.log(attrs); return credentialLibraries.create(attrs); } ); diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs index f5bd6c4eb..35aa5c339 100644 --- a/ui/admin/app/components/form/credential-library/index.hbs +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -47,7 +47,7 @@ {{#each this.httpMethods as |httpMethod|}} @@ -78,7 +78,7 @@ {{t 'resources.credential-library.messages.none.description'}} + + + {{t 'titles.new'}} + diff --git a/ui/admin/tests/integration/components/form/credential-library/index-test.js b/ui/admin/tests/integration/components/form/credential-library/index-test.js deleted file mode 100644 index e0d24a8c2..000000000 --- a/ui/admin/tests/integration/components/form/credential-library/index-test.js +++ /dev/null @@ -1,29 +0,0 @@ -import { module, test } from 'qunit'; -import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; -import { hbs } from 'ember-cli-htmlbars'; - -module( - 'Integration | Component | form/credential-library/index', - function (hooks) { - setupRenderingTest(hooks); - - test('it renders', async function (assert) { - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.set('myAction', function(val) { ... }); - - await render(hbs``); - - assert.equal(this.element.textContent.trim(), ''); - - // Template block usage: - await render(hbs` - - template block text - - `); - - assert.equal(this.element.textContent.trim(), 'template block text'); - }); - } -); From 59818fa24d8d53338450f49e92839a0cfdf8e11f Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 19 Jul 2021 13:13:35 -0400 Subject: [PATCH 03/68] feat: Add credential libraries breadcrumbs --- .../credential-store/credential-libraries.js | 18 ++++++++++++++++++ .../credential-libraries/new.js | 18 ++++++++++++++++++ .../credential-libraries-test.js | 17 +++++++++++++++++ .../credential-libraries/new-test.js | 17 +++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 ui/admin/app/controllers/scopes/scope/credential-stores/credential-store/credential-libraries.js create mode 100644 ui/admin/app/controllers/scopes/scope/credential-stores/credential-store/credential-libraries/new.js create mode 100644 ui/admin/tests/unit/controllers/scopes/scope/credential-stores/credential-store/credential-libraries-test.js create mode 100644 ui/admin/tests/unit/controllers/scopes/scope/credential-stores/credential-store/credential-libraries/new-test.js diff --git a/ui/admin/app/controllers/scopes/scope/credential-stores/credential-store/credential-libraries.js b/ui/admin/app/controllers/scopes/scope/credential-stores/credential-store/credential-libraries.js new file mode 100644 index 000000000..fe9084ea7 --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/credential-stores/credential-store/credential-libraries.js @@ -0,0 +1,18 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrariesController extends Controller { + // =services + + @service intl; + + // =attributes + + /** + * Translated credential libraries breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.intl.t('resources.credential-library.title_plural'); + } +} diff --git a/ui/admin/app/controllers/scopes/scope/credential-stores/credential-store/credential-libraries/new.js b/ui/admin/app/controllers/scopes/scope/credential-stores/credential-store/credential-libraries/new.js new file mode 100644 index 000000000..ff4053f92 --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/credential-stores/credential-store/credential-libraries/new.js @@ -0,0 +1,18 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrariesNewController extends Controller { + // =services + + @service intl; + + // =attributes + + /** + * Translated new credential libraries breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.intl.t('titles.new'); + } +} diff --git a/ui/admin/tests/unit/controllers/scopes/scope/credential-stores/credential-store/credential-libraries-test.js b/ui/admin/tests/unit/controllers/scopes/scope/credential-stores/credential-store/credential-libraries-test.js new file mode 100644 index 000000000..944329525 --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/credential-stores/credential-store/credential-libraries-test.js @@ -0,0 +1,17 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Controller | scopes/scope/credential-stores/credential-store/credential-libraries', + function (hooks) { + setupTest(hooks); + + // TODO: Replace this with your real tests. + test('it exists', function (assert) { + let controller = this.owner.lookup( + 'controller:scopes/scope/credential-stores/credential-store/credential-libraries' + ); + assert.ok(controller); + }); + } +); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/credential-stores/credential-store/credential-libraries/new-test.js b/ui/admin/tests/unit/controllers/scopes/scope/credential-stores/credential-store/credential-libraries/new-test.js new file mode 100644 index 000000000..2dce4303a --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/credential-stores/credential-store/credential-libraries/new-test.js @@ -0,0 +1,17 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Controller | scopes/scope/credential-stores/credential-store/credential-libraries/new', + function (hooks) { + setupTest(hooks); + + // TODO: Replace this with your real tests. + test('it exists', function (assert) { + let controller = this.owner.lookup( + 'controller:scopes/scope/credential-stores/credential-store/credential-libraries/new' + ); + assert.ok(controller); + }); + } +); From dd96423ead34e4793b636d1c1015a0743b7b18fc Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 20 Jul 2021 09:32:41 -0400 Subject: [PATCH 04/68] fix: Disable credential library request body in form --- addons/core/translations/form/en-us.yaml | 2 +- .../form/credential-library/index.hbs | 42 +++++++++---------- .../form/credential-library/index.js | 8 ++-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/addons/core/translations/form/en-us.yaml b/addons/core/translations/form/en-us.yaml index b59b55b91..171011a4a 100644 --- a/addons/core/translations/form/en-us.yaml +++ b/addons/core/translations/form/en-us.yaml @@ -123,4 +123,4 @@ http_method: help: The HTTP method the library uses when requesting credentials from Vault. http_request_body: label: HTTP Request Body - help: The body of the HTTP request the library sends to Vault when requesting credentials. + help: The body of the HTTP request the library sends to Vault when requesting credentials. Only allowed when http_method is set to POST. diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs index 35aa5c339..d45f78b58 100644 --- a/ui/admin/app/components/form/credential-library/index.hbs +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -31,7 +31,7 @@ @label={{t 'form.description.label'}} @error={{@model.errors.description}} @helperText={{t 'form.description.help'}} - disabled={{@model.isSaving}} + @disabled={{@model.isSaving}} readonly={{false}} as |field| > @@ -74,27 +74,25 @@ {{/each}} - {{#if this.isHttpRequestBodyAllowed}} - - {{#if @model.errors.description}} - - {{#each @model.errors.description as |error|}} - {{error.message}} - {{/each}} - - {{/if}} - - {{/if}} + + {{#if @model.errors.description}} + + {{#each @model.errors.description as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + Date: Tue, 20 Jul 2021 16:11:57 -0700 Subject: [PATCH 05/68] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20inline=20ali?= =?UTF-8?q?gntment=20support=20to=20checkbox=20and=20radio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/rose/addon/components/rose/form/checkbox/index.hbs | 2 +- .../rose/addon/components/rose/form/radio/group/index.hbs | 2 ++ .../rose/addon/components/rose/form/radio/radio/index.hbs | 4 ++-- .../rose/addon/styles/rose/components/form/_checkbox.scss | 4 ++++ addons/rose/addon/styles/rose/components/form/_radio.scss | 6 ++++++ 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/addons/rose/addon/components/rose/form/checkbox/index.hbs b/addons/rose/addon/components/rose/form/checkbox/index.hbs index a660c270d..e4a2c11d5 100644 --- a/addons/rose/addon/components/rose/form/checkbox/index.hbs +++ b/addons/rose/addon/components/rose/form/checkbox/index.hbs @@ -1,4 +1,4 @@ -
+
{{yield (hash radio=(component 'rose/form/radio/radio' name=@name selectedValue=@selectedValue disabled=@disabled changed=@changed) )}} +
\ No newline at end of file diff --git a/addons/rose/addon/components/rose/form/radio/radio/index.hbs b/addons/rose/addon/components/rose/form/radio/radio/index.hbs index eb45384c6..86edfd524 100644 --- a/addons/rose/addon/components/rose/form/radio/radio/index.hbs +++ b/addons/rose/addon/components/rose/form/radio/radio/index.hbs @@ -1,8 +1,8 @@ -
+
Date: Tue, 20 Jul 2021 16:26:13 -0700 Subject: [PATCH 06/68] =?UTF-8?q?fix:=20=F0=9F=90=9B=20undo=20unnecessary?= =?UTF-8?q?=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/rose/addon/components/rose/form/radio/group/index.hbs | 2 -- addons/rose/addon/components/rose/form/radio/radio/index.hbs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/rose/addon/components/rose/form/radio/group/index.hbs b/addons/rose/addon/components/rose/form/radio/group/index.hbs index a503c3bc9..fc34bd1cc 100644 --- a/addons/rose/addon/components/rose/form/radio/group/index.hbs +++ b/addons/rose/addon/components/rose/form/radio/group/index.hbs @@ -1,5 +1,3 @@ -
{{yield (hash radio=(component 'rose/form/radio/radio' name=@name selectedValue=@selectedValue disabled=@disabled changed=@changed) )}} -
\ No newline at end of file diff --git a/addons/rose/addon/components/rose/form/radio/radio/index.hbs b/addons/rose/addon/components/rose/form/radio/radio/index.hbs index 86edfd524..d38bc3680 100644 --- a/addons/rose/addon/components/rose/form/radio/radio/index.hbs +++ b/addons/rose/addon/components/rose/form/radio/radio/index.hbs @@ -2,7 +2,7 @@ Date: Tue, 20 Jul 2021 14:55:00 -0700 Subject: [PATCH 07/68] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Add=20credential?= =?UTF-8?q?=20store=20delete=20CRUD=20operation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/mirage/config.js | 1 + addons/core/translations/resources/en-us.yaml | 2 +- .../routes/scopes/scope/credential-stores.js | 16 ++++++++++++++++ .../scope/credential-stores/credential-store.js | 5 +++++ .../credential-stores/credential-store.hbs | 2 +- .../credential-store/-actions.hbs | 17 +++++++++++++++++ 6 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs diff --git a/addons/api/mirage/config.js b/addons/api/mirage/config.js index 1fd364182..c796d099c 100644 --- a/addons/api/mirage/config.js +++ b/addons/api/mirage/config.js @@ -467,6 +467,7 @@ export default function () { this.get('/credential-stores/:id'); this.post('/credential-stores'); this.patch('/credential-stores/:id'); + this.del('/credential-stores/:id'); // credential-libraries diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index cc9fed978..56baf2d3d 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -278,4 +278,4 @@ credential-library: messages: none: title: No Credential Libraries Available - description: No Credential Libraries available in this credential store. \ No newline at end of file + description: No Credential Libraries available in this credential store. diff --git a/ui/admin/app/routes/scopes/scope/credential-stores.js b/ui/admin/app/routes/scopes/scope/credential-stores.js index 4bac020b1..8bfce1b1d 100644 --- a/ui/admin/app/routes/scopes/scope/credential-stores.js +++ b/ui/admin/app/routes/scopes/scope/credential-stores.js @@ -1,6 +1,7 @@ import Route from '@ember/routing/route'; import { action } from '@ember/object'; import loading from 'ember-loading/decorator'; +import { confirm } from 'core/decorators/confirm'; import { notifySuccess, notifyError } from 'core/decorators/notify'; export default class ScopesScopeCredentialStoresRoute extends Route { @@ -44,4 +45,19 @@ export default class ScopesScopeCredentialStoresRoute extends Route { credentialStore.rollbackAttributes(); if (isNew) this.transitionTo('scopes.scope.credential-stores'); } + + /** + * Deletes the credential store and redirects to index + * @param {CredentialStoreModel} credentialStore + */ + @action + @loading + @confirm('questions.delete-confirm') + @notifyError(({ message }) => message, { catch: true }) + @notifySuccess('notifications.delete-success') + async delete(credentialStore) { + await credentialStore.destroyRecord(); + await this.replaceWith('scopes.scope.credential-stores'); + this.refresh(); + } } diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js index 307c11079..d217736fc 100644 --- a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js @@ -25,5 +25,10 @@ export default class ScopesScopeCredentialStoresCredentialStoreRoute extends Rou into: 'scopes/scope/credential-stores/credential-store', outlet: 'navigation', }); + + this.render('scopes/scope/credential-stores/credential-store/-actions', { + into: 'scopes/scope/credential-stores/credential-store', + outlet: 'actions', + }); } } diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store.hbs index a6ecd7f81..efc46641a 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store.hbs @@ -15,7 +15,7 @@ - {{!-- {{outlet 'actions'}} --}} + {{outlet 'actions'}} diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs new file mode 100644 index 000000000..165b709ca --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs @@ -0,0 +1,17 @@ + + + {{t 'resources.credential-store.actions.create'}} + + + + {{t 'resources.credential-store.actions.delete'}} + + \ No newline at end of file From c5af15f4c14e3771dac7199252e9bf18342ae843 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Wed, 21 Jul 2021 10:30:44 -0700 Subject: [PATCH 08/68] Add missing translation after rebase --- addons/core/translations/resources/en-us.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 56baf2d3d..fcc631b72 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -271,6 +271,9 @@ credential-store: title: Credential Store title_plural: Credential Stores description: A credential stores is a collection of credentials and credential libraries. + actions: + create: New Credential Library + delete: Delete Credential Store credential-library: title: Credential Library title_plural: Credential Libraries From d034631e4d586dddc595cba30cac54fee31bc43a Mon Sep 17 00:00:00 2001 From: dharini Date: Wed, 21 Jul 2021 10:51:33 -0700 Subject: [PATCH 09/68] =?UTF-8?q?fix:=20=F0=9F=90=9B=20add=20attr=20in=20s?= =?UTF-8?q?torybook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rose/addon/components/rose/form/checkbox/index.stories.mdx | 1 + .../addon/components/rose/form/radio/radio/index.stories.mdx | 1 + 2 files changed, 2 insertions(+) diff --git a/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx b/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx index 4f98fed53..fe92b59ec 100644 --- a/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx +++ b/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx @@ -16,6 +16,7 @@ Renders a form input checkbox. @checked={{false}} @error={{false}} @disabled={{false}} + @inline={{true}} /> ``` diff --git a/addons/rose/addon/components/rose/form/radio/radio/index.stories.mdx b/addons/rose/addon/components/rose/form/radio/radio/index.stories.mdx index 633a5c082..6ac5d9f15 100644 --- a/addons/rose/addon/components/rose/form/radio/radio/index.stories.mdx +++ b/addons/rose/addon/components/rose/form/radio/radio/index.stories.mdx @@ -16,6 +16,7 @@ Renders a form radiofield. @selectedValue="yes-agree" @disabled={{false}} @changed={{fn}} + @inline={{true}} /> ``` From 0823c1cb2d467f26601a2d94776fbc19fd3626fa Mon Sep 17 00:00:00 2001 From: dharini Date: Wed, 21 Jul 2021 12:39:24 -0700 Subject: [PATCH 10/68] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20stories=20fo?= =?UTF-8?q?r=20inline=20radio=20&=20checkbox,=20radiogrp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rose/form/checkbox/index.stories.mdx | 58 +++++++++++++++- .../rose/form/radio/group/index.hbs | 4 +- .../rose/form/radio/group/index.stories.mdx | 3 + .../rose/form/radio/radio/index.stories.mdx | 68 ++++++++++++++++++- .../styles/rose/components/form/_radio.scss | 15 ++-- 5 files changed, 138 insertions(+), 10 deletions(-) diff --git a/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx b/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx index fe92b59ec..11405c643 100644 --- a/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx +++ b/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx @@ -16,7 +16,6 @@ Renders a form input checkbox. @checked={{false}} @error={{false}} @disabled={{false}} - @inline={{true}} /> ``` @@ -69,3 +68,60 @@ Renders a form input checkbox. } }} + + +```htmlbars + +``` + + + {{ + template: hbs` + + + + `, + context: { + description: text('description', 'Short description in label'), + helperText: text('helperText', 'This is an optional help text.'), + checked: boolean('checked', false), + error: boolean('error', false), + disabled: boolean('disabled', false), + } + }} + + diff --git a/addons/rose/addon/components/rose/form/radio/group/index.hbs b/addons/rose/addon/components/rose/form/radio/group/index.hbs index fc34bd1cc..de2b010b6 100644 --- a/addons/rose/addon/components/rose/form/radio/group/index.hbs +++ b/addons/rose/addon/components/rose/form/radio/group/index.hbs @@ -1,3 +1,3 @@ {{yield (hash - radio=(component 'rose/form/radio/radio' name=@name selectedValue=@selectedValue disabled=@disabled changed=@changed) -)}} + radio=(component 'rose/form/radio/radio' name=@name selectedValue=@selectedValue disabled=@disabled changed=@changed inline=@inline) +)}} \ No newline at end of file diff --git a/addons/rose/addon/components/rose/form/radio/group/index.stories.mdx b/addons/rose/addon/components/rose/form/radio/group/index.stories.mdx index bafffaaa4..515c7ca35 100644 --- a/addons/rose/addon/components/rose/form/radio/group/index.stories.mdx +++ b/addons/rose/addon/components/rose/form/radio/group/index.stories.mdx @@ -15,6 +15,7 @@ Renders a form radiofield group. @name={{name}} @selectedValue="disagree" @changed={{fn}} + @inline={{false}} as |radioGroup| > ``` @@ -55,3 +54,70 @@ Renders a form radiofield. } }} + + +```htmlbars + +``` + + + {{ + template: hbs` + + + + `, + context: { + error: boolean('error', false), + value: text('value', 'value and selectedValue must match to select radiofield'), + selectedValue: text( + 'selectedValue', + 'value and selectedValue must match to select radiofield' + ), + disabled: boolean('disabled', false), + icon: select( + 'icon', + { + 'none': null, + 'user-organization': 'user-organization', + 'copy-action': 'copy-action', + 'unfold-more': 'unfold-more', + 'unfold-less': 'unfold-less', + }, + null + ), + } + }} + \ No newline at end of file diff --git a/addons/rose/addon/styles/rose/components/form/_radio.scss b/addons/rose/addon/styles/rose/components/form/_radio.scss index 723407017..f248d0b7a 100644 --- a/addons/rose/addon/styles/rose/components/form/_radio.scss +++ b/addons/rose/addon/styles/rose/components/form/_radio.scss @@ -21,14 +21,17 @@ $radio-svg: ( ); $data-svg-prefix: 'data:image/svg+xml;utf-8,'; -.radio-group-inline { - display: flex; - .rose-form-radio { + .rose-form-radio { + &.inline { + display: inline-block; + .rose-form-radio-label { + margin-right: sizing.rems(s); + } + } + .radio-group-inline { + display: flex; margin-right: sizing.rems(s); } -} - -.rose-form-radio { @include type.type(m); position: relative; margin-bottom: sizing.rems(xs); From e74fd0202e1ba49c048a4314aaf8f7aac5374af4 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 20 Jul 2021 16:09:59 -0400 Subject: [PATCH 11/68] feat: API: Load credential libraries associated to a target --- .../models/fragment-credential-library.js | 11 ++++++++ addons/api/addon/models/target.js | 22 ++++++++++++++++ .../fragment-credential-library.js | 16 ++++++++++++ addons/api/addon/serializers/target.js | 26 ++++++++++++++++++- .../app/models/fragment-credential-library.js | 1 + .../fragment-credential-library.js | 1 + addons/api/mirage/factories/target.js | 18 +++++++++---- addons/api/mirage/models/target.js | 1 + addons/api/mirage/scenarios/default.js | 2 +- addons/api/mirage/serializers/target.js | 3 +++ .../fragment-credential-library-test.js | 13 ++++++++++ .../fragment-credential-library-test.js | 23 ++++++++++++++++ 12 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 addons/api/addon/models/fragment-credential-library.js create mode 100644 addons/api/addon/serializers/fragment-credential-library.js create mode 100644 addons/api/app/models/fragment-credential-library.js create mode 100644 addons/api/app/serializers/fragment-credential-library.js create mode 100644 addons/api/tests/unit/models/fragment-credential-library-test.js create mode 100644 addons/api/tests/unit/serializers/fragment-credential-library-test.js diff --git a/addons/api/addon/models/fragment-credential-library.js b/addons/api/addon/models/fragment-credential-library.js new file mode 100644 index 000000000..384ffef1e --- /dev/null +++ b/addons/api/addon/models/fragment-credential-library.js @@ -0,0 +1,11 @@ +import Fragment from 'ember-data-model-fragments/fragment'; +import { attr } from '@ember-data/model'; + +export default class FragmentCredentialLibraryModel extends Fragment { + // =attributes + + @attr('string', { + description: 'ID of the related credential library', + }) + credential_library_id; +} diff --git a/addons/api/addon/models/target.js b/addons/api/addon/models/target.js index a00c3b182..3788e595f 100644 --- a/addons/api/addon/models/target.js +++ b/addons/api/addon/models/target.js @@ -20,6 +20,15 @@ export default class TargetModel extends GeneratedTargetModel { }) host_sets; + /** + * @type {[FragmentCredentialLibrary]} + */ + @fragmentArray('fragment-credential-library', { + readOnly: true, + emptyArrayIfMissing: true, + }) + credential_libraries; + /** * An array of resolved host set and host catalog instances. Model instances * must already be loaded into the store (this method will not load unloaded @@ -65,6 +74,19 @@ export default class TargetModel extends GeneratedTargetModel { return Boolean(pendingOrActiveSessions.length); } + /** + * An array of resolved credential library instances. Model instances + * must already be loaded into the store (this method will not load unloaded + * instances). Unresolvable instances are excluded from the array. + * @type {[CredentialLibraryModel]} + */ + @computed('credential_libraries.[]', 'store') + get credentialLibraries() { + return this.credential_libraries + .map((id) => this.store.peekRecord('credential-library', id)) + .filter(Boolean); + } + // =methods /** diff --git a/addons/api/addon/serializers/fragment-credential-library.js b/addons/api/addon/serializers/fragment-credential-library.js new file mode 100644 index 000000000..9f3d01c81 --- /dev/null +++ b/addons/api/addon/serializers/fragment-credential-library.js @@ -0,0 +1,16 @@ +import JSONSerializer from '@ember-data/serializer/json'; + +export default class FragmentCredentialLibrarySerializer extends JSONSerializer { + // =methods + + /** + * Renames `id` to `credential_library_id` because fragments may not have IDs. + * Otherwise normalizes as normal. + * @param {ModelClass} typeClass + * @param {object} resourceHash + * @return {object} + */ + normalize(typeClass, { id: credential_library_id, ...obj }) { + return super.normalize(typeClass, { credential_library_id, ...obj }); + } +} diff --git a/addons/api/addon/serializers/target.js b/addons/api/addon/serializers/target.js index 4c6745b89..c287aca46 100644 --- a/addons/api/addon/serializers/target.js +++ b/addons/api/addon/serializers/target.js @@ -6,7 +6,11 @@ export default class TargetSerializer extends ApplicationSerializer { /** * If `adapterOptions.hostSets` is set to an array of host set models, * the resulting target serialization should include **only host sets** - * and the version. Normally, host sets are not serialized. + * and the version. + * If `adapterOptions.credentialLibraries` is set to an array of + * credential library models, the resulting target serialization should + * include **only credential libraries** and the version. + * Normally, neither host sets or credential libraries are not serialized. * @override * @param {Snapshot} snapshot * @return {object} @@ -16,6 +20,12 @@ export default class TargetSerializer extends ApplicationSerializer { const hostSetIDs = snapshot?.adapterOptions?.hostSetIDs; if (hostSetIDs) serialized = this.serializeWithHostSets(snapshot, hostSetIDs); + const credentialLibraryIDs = snapshot?.adapterOptions?.credentialLibraryIDs; + if (credentialLibraryIDs) + serialized = this.serializeWithCredentialLibraries( + snapshot, + credentialLibraryIDs + ); return serialized; } @@ -32,4 +42,18 @@ export default class TargetSerializer extends ApplicationSerializer { host_set_ids: hostSetIDs, }; } + + /** + * Returns a payload containing only the credential_library_ids array using IDs + * passed into the function (rather than existing credential libraries on the model). + * @param {Snapshot} snapshot + * @param {[string]} credentialLibraryIDs + * @return {object} + */ + serializeWithCredentialLibraries(snapshot, credentialLibraryIDs) { + return { + version: snapshot.attr('version'), + application_credential_library_ids: credentialLibraryIDs, + }; + } } diff --git a/addons/api/app/models/fragment-credential-library.js b/addons/api/app/models/fragment-credential-library.js new file mode 100644 index 000000000..4cee0ae38 --- /dev/null +++ b/addons/api/app/models/fragment-credential-library.js @@ -0,0 +1 @@ +export { default } from 'api/models/fragment-credential-library'; diff --git a/addons/api/app/serializers/fragment-credential-library.js b/addons/api/app/serializers/fragment-credential-library.js new file mode 100644 index 000000000..b60ecfef5 --- /dev/null +++ b/addons/api/app/serializers/fragment-credential-library.js @@ -0,0 +1 @@ +export { default } from 'api/serializers/fragment-credential-library'; diff --git a/addons/api/mirage/factories/target.js b/addons/api/mirage/factories/target.js index dc1c97d00..8ae03edbe 100644 --- a/addons/api/mirage/factories/target.js +++ b/addons/api/mirage/factories/target.js @@ -7,7 +7,7 @@ const hostSetChance = 0.3; export default factory.extend({ /** - * -1 means "unlimited" and we want to generate these on occassion. + * -1 means "unlimited" and we want to generate these on occasion. */ session_connection_limit: () => random.arrayElement([-1, datatype.number()]), @@ -25,11 +25,11 @@ export default factory.extend({ }, /** - * Randomly selects existing host sets to assign to target. + * Randomly selects existing host sets and credential libraries to assign to target. */ - withRandomHostSets: trait({ + withAssociations: trait({ afterCreate(target, server) { - let randomlySelectedHostSets; + let randomlySelectedHostSets, randomlySelectedCredentialLibraries; randomlySelectedHostSets = server.schema.hostSets // BLERG: fun fact, for no reason at all, the element passed // into a where function is not a full model instance, as you might @@ -38,7 +38,15 @@ export default factory.extend({ // the result set of `where` _is a collection of model instances_. .where((hostSet) => hostSet.scopeId === target.scope.id) .models.filter(() => randomBoolean(hostSetChance)); - target.update({ hostSets: randomlySelectedHostSets }); + + randomlySelectedCredentialLibraries = server.schema.credentialLibraries + .where((credentialLibrary) => credentialLibrary.scopeId === target.scope.id) + .models.filter(() => randomBoolean()); + + target.update({ + hostSets: randomlySelectedHostSets, + credentialLibraries: randomlySelectedCredentialLibraries, + }); }, }), }); diff --git a/addons/api/mirage/models/target.js b/addons/api/mirage/models/target.js index 0f03cb6ef..389e255d2 100644 --- a/addons/api/mirage/models/target.js +++ b/addons/api/mirage/models/target.js @@ -3,4 +3,5 @@ import { Model, belongsTo, hasMany } from 'ember-cli-mirage'; export default Model.extend({ scope: belongsTo(), hostSets: hasMany(), + credentialLibraries: hasMany(), }); diff --git a/addons/api/mirage/scenarios/default.js b/addons/api/mirage/scenarios/default.js index fc5931908..d448a443b 100644 --- a/addons/api/mirage/scenarios/default.js +++ b/addons/api/mirage/scenarios/default.js @@ -47,8 +47,8 @@ export default function (server) { // Other resources server.schema.scopes.where({ type: 'project' }).models.forEach((scope) => { server.createList('host-catalog', 2, { scope }, 'withChildren'); - server.createList('target', 2, { scope }, 'withRandomHostSets'); server.createList('session', 4, { scope }, 'withAssociations'); server.createList('credential-store', 3, { scope }, 'withAssociations'); + server.createList('target', 2, { scope }, 'withAssociations'); }); } diff --git a/addons/api/mirage/serializers/target.js b/addons/api/mirage/serializers/target.js index 006388773..c23330189 100644 --- a/addons/api/mirage/serializers/target.js +++ b/addons/api/mirage/serializers/target.js @@ -23,6 +23,9 @@ export default ApplicationSerializer.extend({ return { id: host_set_id, host_catalog_id }; }); } + if (model.credentialLibraryIds?.length) { + json.credential_libraries = model.credentialLibraryIds; + } return json; }, }); diff --git a/addons/api/tests/unit/models/fragment-credential-library-test.js b/addons/api/tests/unit/models/fragment-credential-library-test.js new file mode 100644 index 000000000..f5014569e --- /dev/null +++ b/addons/api/tests/unit/models/fragment-credential-library-test.js @@ -0,0 +1,13 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Model | fragment 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('fragment-credential-library', {}); + assert.ok(model); + }); +}); diff --git a/addons/api/tests/unit/serializers/fragment-credential-library-test.js b/addons/api/tests/unit/serializers/fragment-credential-library-test.js new file mode 100644 index 000000000..719d97955 --- /dev/null +++ b/addons/api/tests/unit/serializers/fragment-credential-library-test.js @@ -0,0 +1,23 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Serializer | fragment 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 serializer = store.serializerFor('fragment-credential-library'); + + assert.ok(serializer); + }); + + test('it serializes records', function (assert) { + let store = this.owner.lookup('service:store'); + let record = store.createRecord('fragment-credential-library', {}); + + let serializedRecord = record.serialize(); + + assert.ok(serializedRecord); + }); +}); From 28a4a7304e06d7d6aba520da611421958f1cb3ea Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Wed, 21 Jul 2021 15:45:45 -0400 Subject: [PATCH 12/68] feat: Add credential library add and remove methods to target --- .../models/fragment-credential-library.js | 11 -- addons/api/addon/models/target.js | 100 +++++++++-- .../fragment-credential-library.js | 16 -- .../app/models/fragment-credential-library.js | 1 - .../fragment-credential-library.js | 1 - addons/api/mirage/config.js | 20 ++- addons/api/mirage/factories/target.js | 4 +- addons/api/mirage/serializers/target.js | 2 +- .../fragment-credential-library-test.js | 13 -- addons/api/tests/unit/models/target-test.js | 158 ++++++++++++++++++ .../unit/serializers/application-test.js | 1 + .../fragment-credential-library-test.js | 23 --- .../api/tests/unit/serializers/target-test.js | 29 +++- ui/admin/tests/acceptance/sessions-test.js | 2 +- ui/desktop/tests/acceptance/origin-test.js | 2 +- ui/desktop/tests/acceptance/projects-test.js | 2 +- .../acceptance/projects/sessions-test.js | 2 +- .../tests/acceptance/projects/targets-test.js | 2 +- .../projects/targets/sessions-test.js | 2 +- ui/desktop/tests/acceptance/scopes-test.js | 2 +- ui/desktop/tests/acceptance/targets-test.js | 2 +- 21 files changed, 301 insertions(+), 94 deletions(-) delete mode 100644 addons/api/addon/models/fragment-credential-library.js delete mode 100644 addons/api/addon/serializers/fragment-credential-library.js delete mode 100644 addons/api/app/models/fragment-credential-library.js delete mode 100644 addons/api/app/serializers/fragment-credential-library.js delete mode 100644 addons/api/tests/unit/models/fragment-credential-library-test.js delete mode 100644 addons/api/tests/unit/serializers/fragment-credential-library-test.js diff --git a/addons/api/addon/models/fragment-credential-library.js b/addons/api/addon/models/fragment-credential-library.js deleted file mode 100644 index 384ffef1e..000000000 --- a/addons/api/addon/models/fragment-credential-library.js +++ /dev/null @@ -1,11 +0,0 @@ -import Fragment from 'ember-data-model-fragments/fragment'; -import { attr } from '@ember-data/model'; - -export default class FragmentCredentialLibraryModel extends Fragment { - // =attributes - - @attr('string', { - description: 'ID of the related credential library', - }) - credential_library_id; -} diff --git a/addons/api/addon/models/target.js b/addons/api/addon/models/target.js index 3788e595f..d60596465 100644 --- a/addons/api/addon/models/target.js +++ b/addons/api/addon/models/target.js @@ -21,13 +21,14 @@ export default class TargetModel extends GeneratedTargetModel { host_sets; /** - * @type {[FragmentCredentialLibrary]} + * Credential library ids are read only and can be + * persisted via a dedicated call to `addCredentialLibraries()`. */ - @fragmentArray('fragment-credential-library', { + @fragmentArray('fragment-string', { readOnly: true, emptyArrayIfMissing: true, }) - credential_libraries; + application_credential_library_ids; /** * An array of resolved host set and host catalog instances. Model instances @@ -45,6 +46,24 @@ export default class TargetModel extends GeneratedTargetModel { .filter((hostSetRef) => hostSetRef.model !== null); } + /** + * An array of resolved credential library instances. Model instances + * must already be loaded into the store (this method will not load unloaded + * instances). Unresolvable instances are excluded from the array. + * @type {[CredentialLibraryModel]} + */ + @computed('application_credential_library_ids.[]', 'store') + get credentialLibraries() { + return this.application_credential_library_ids + .map((credential_library_fragment) => + this.store.peekRecord( + 'credential-library', + credential_library_fragment.value + ) + ) + .filter(Boolean); + } + /** * Sessions associated with this target (but only already loaded sessions). * @type {SessionModel[]} @@ -74,19 +93,6 @@ export default class TargetModel extends GeneratedTargetModel { return Boolean(pendingOrActiveSessions.length); } - /** - * An array of resolved credential library instances. Model instances - * must already be loaded into the store (this method will not load unloaded - * instances). Unresolvable instances are excluded from the array. - * @type {[CredentialLibraryModel]} - */ - @computed('credential_libraries.[]', 'store') - get credentialLibraries() { - return this.credential_libraries - .map((id) => this.store.peekRecord('credential-library', id)) - .filter(Boolean); - } - // =methods /** @@ -144,4 +150,66 @@ export default class TargetModel extends GeneratedTargetModel { removeHostSet(hostSetID, options) { return this.removeHostSets([hostSetID], options); } + + /** + * Adds credential libraries via the `add-credential-libraries` method. + * See serializer and adapter for more information. + * @param {[string]} credentialLibraryIDs + * @param {object} options + * @param {object} options.adapterOptions + * @return {Promise} + */ + addCredentialLibraries( + credentialLibraryIDs, + options = { adapterOptions: {} } + ) { + const defaultAdapterOptions = { + method: 'add-credential-libraries', + credentialLibraryIDs, + }; + // There is no "deep merge" in ES. + return this.save({ + ...options, + adapterOptions: { + ...defaultAdapterOptions, + ...options.adapterOptions, + }, + }); + } + + /** + * Delete credential libraries via the `remove-credential-libraries` method. + * See serializer and adapter for more information. + * @param {[string]} credentialLibraryIDs + * @param {object} options + * @param {object} options.adapterOptions + * @return {Promise} + */ + removeCredentialLibraries( + credentialLibraryIDs, + options = { adapterOptions: {} } + ) { + const defaultAdapterOptions = { + method: 'remove-credential-libraries', + credentialLibraryIDs, + }; + // There is no "deep merge" in ES. + return this.save({ + ...options, + adapterOptions: { + ...defaultAdapterOptions, + ...options.adapterOptions, + }, + }); + } + + /** + * Delete a single credential library set via the `remove-credential-libraries` method. + * @param {number} credentialLibraryID + * @param {object} options + * @return {Promise} + */ + removeCredentialLibrary(credentialLibraryID, options) { + return this.removeCredentialLibraries([credentialLibraryID], options); + } } diff --git a/addons/api/addon/serializers/fragment-credential-library.js b/addons/api/addon/serializers/fragment-credential-library.js deleted file mode 100644 index 9f3d01c81..000000000 --- a/addons/api/addon/serializers/fragment-credential-library.js +++ /dev/null @@ -1,16 +0,0 @@ -import JSONSerializer from '@ember-data/serializer/json'; - -export default class FragmentCredentialLibrarySerializer extends JSONSerializer { - // =methods - - /** - * Renames `id` to `credential_library_id` because fragments may not have IDs. - * Otherwise normalizes as normal. - * @param {ModelClass} typeClass - * @param {object} resourceHash - * @return {object} - */ - normalize(typeClass, { id: credential_library_id, ...obj }) { - return super.normalize(typeClass, { credential_library_id, ...obj }); - } -} diff --git a/addons/api/app/models/fragment-credential-library.js b/addons/api/app/models/fragment-credential-library.js deleted file mode 100644 index 4cee0ae38..000000000 --- a/addons/api/app/models/fragment-credential-library.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from 'api/models/fragment-credential-library'; diff --git a/addons/api/app/serializers/fragment-credential-library.js b/addons/api/app/serializers/fragment-credential-library.js deleted file mode 100644 index b60ecfef5..000000000 --- a/addons/api/app/serializers/fragment-credential-library.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from 'api/serializers/fragment-credential-library'; diff --git a/addons/api/mirage/config.js b/addons/api/mirage/config.js index 1fd364182..9e09af76e 100644 --- a/addons/api/mirage/config.js +++ b/addons/api/mirage/config.js @@ -366,10 +366,10 @@ export default function () { const target = targets.find(id); const updatedAttrs = { version: attrs.version, - hostSetIds: target.hostSetIds, }; // If adding host sets, push them into the array if (method === 'add-host-sets') { + updatedAttrs.hostSetIds = target.hostSetIds; attrs.hostSetIds.forEach((id) => { if (!updatedAttrs.hostSetIds.includes(id)) { updatedAttrs.hostSetIds.push(id); @@ -378,10 +378,28 @@ export default function () { } // If deleting host sets, filter them out of the array if (method === 'remove-host-sets') { + updatedAttrs.hostSetIds = target.hostSetIds; updatedAttrs.hostSetIds = updatedAttrs.hostSetIds.filter((id) => { return !attrs.hostSetIds.includes(id); }); } + // If adding credential libraries, push them into the array + if (method === 'add-credential-libraries') { + updatedAttrs.credentialLibraryIds = target.credentialLibraryIds; + attrs.applicationCredentialLibraryIds.forEach((id) => { + if (!updatedAttrs.credentialLibraryIds.includes(id)) { + updatedAttrs.credentialLibraryIds.push(id); + } + }); + } + // If deleting credential libraries, filter them out of the array + if (method === 'remove-credential-libraries') { + updatedAttrs.credentialLibraryIds = target.credentialLibraryIds; + updatedAttrs.credentialLibraryIds = + updatedAttrs.credentialLibraryIds.filter((id) => { + return !attrs.applicationCredentialLibraryIds.includes(id); + }); + } return target.update(updatedAttrs); } ); diff --git a/addons/api/mirage/factories/target.js b/addons/api/mirage/factories/target.js index 8ae03edbe..e40df6abf 100644 --- a/addons/api/mirage/factories/target.js +++ b/addons/api/mirage/factories/target.js @@ -40,7 +40,9 @@ export default factory.extend({ .models.filter(() => randomBoolean(hostSetChance)); randomlySelectedCredentialLibraries = server.schema.credentialLibraries - .where((credentialLibrary) => credentialLibrary.scopeId === target.scope.id) + .where( + (credentialLibrary) => credentialLibrary.scopeId === target.scope.id + ) .models.filter(() => randomBoolean()); target.update({ diff --git a/addons/api/mirage/serializers/target.js b/addons/api/mirage/serializers/target.js index c23330189..b970f4853 100644 --- a/addons/api/mirage/serializers/target.js +++ b/addons/api/mirage/serializers/target.js @@ -24,7 +24,7 @@ export default ApplicationSerializer.extend({ }); } if (model.credentialLibraryIds?.length) { - json.credential_libraries = model.credentialLibraryIds; + json.application_credential_library_ids = model.credentialLibraryIds; } return json; }, diff --git a/addons/api/tests/unit/models/fragment-credential-library-test.js b/addons/api/tests/unit/models/fragment-credential-library-test.js deleted file mode 100644 index f5014569e..000000000 --- a/addons/api/tests/unit/models/fragment-credential-library-test.js +++ /dev/null @@ -1,13 +0,0 @@ -import { module, test } from 'qunit'; -import { setupTest } from 'ember-qunit'; - -module('Unit | Model | fragment 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('fragment-credential-library', {}); - assert.ok(model); - }); -}); diff --git a/addons/api/tests/unit/models/target-test.js b/addons/api/tests/unit/models/target-test.js index 18be834bd..1c6fa2b22 100644 --- a/addons/api/tests/unit/models/target-test.js +++ b/addons/api/tests/unit/models/target-test.js @@ -223,4 +223,162 @@ module('Unit | Model | target', function (hooks) { 'Target has two associated sessions loaded in the store' ); }); + + test('it has a `credentialLibraries` array of resolved model instances (if those instances are already in the store)', function (assert) { + assert.expect(4); + const store = this.owner.lookup('service:store'); + store.push({ + data: { + id: '123abc', + type: 'target', + attributes: { + application_credential_library_ids: [{ value: '1' }, { value: '2' }], + }, + }, + }); + const target = store.peekRecord('target', '123abc'); + assert.equal( + target.application_credential_library_ids.length, + 2, + 'Target has two entires in application_credential_library_ids' + ); + assert.equal( + target.credentialLibraries.length, + 0, + 'Target has no resolved credentialLibraries because they are not loaded yet' + ); + store.push({ + data: { + id: '1', + type: 'credential-library', + attributes: {}, + }, + }); + store.push({ + data: { + id: '2', + type: 'credential-library', + attributes: {}, + }, + }); + // Since `credentialLibraries` is computed on `application_credential_library_ids`, + // not the store itself, it's necessary to do this assignment to kick-off the + // computed update. + /* eslint-disable no-self-assign */ + target.application_credential_library_ids = + target.application_credential_library_ids; + /* eslint-enable no-self-assign */ + assert.equal( + target.application_credential_library_ids.length, + 2, + 'Target has two entires in application_credential_library_ids' + ); + assert.equal( + target.credentialLibraries.length, + 2, + 'Target has two resolved credentialLibraries' + ); + }); + + test('it has an `addCredentialLibraries` method that targets a specific POST API endpoint and serialization', async function (assert) { + assert.expect(1); + this.server.post( + '/v1/targets/123abc:add-credential-libraries', + (schema, request) => { + const body = JSON.parse(request.requestBody); + assert.deepEqual(body, { + application_credential_library_ids: ['123_abc', 'foobar'], + version: 1, + }); + return { id: '123abc' }; + } + ); + const store = this.owner.lookup('service:store'); + store.push({ + data: { + id: '123abc', + type: 'target', + attributes: { + name: 'Target', + description: 'Description', + application_credential_library_ids: [{ value: '1' }, { value: '2' }], + version: 1, + scope: { + scope_id: 'o_1', + type: 'scope', + }, + }, + }, + }); + const model = store.peekRecord('target', '123abc'); + await model.addCredentialLibraries(['123_abc', 'foobar']); + }); + + test('it has a `removeCredentialLibraries` method that targets a specific POST API endpoint and serialization', async function (assert) { + assert.expect(1); + this.server.post( + '/v1/targets/123abc:remove-credential-libraries', + (schema, request) => { + const body = JSON.parse(request.requestBody); + assert.deepEqual(body, { + application_credential_library_ids: ['1', '2'], + version: 1, + }); + return { id: '123abc' }; + } + ); + const store = this.owner.lookup('service:store'); + store.push({ + data: { + id: '123abc', + type: 'target', + attributes: { + name: 'Target', + description: 'Description', + application_credential_library_ids: [{ value: '1' }, { value: '2' }], + version: 1, + scope: { + scope_id: 'o_1', + type: 'scope', + }, + }, + }, + }); + const model = store.peekRecord('target', '123abc'); + await model.removeCredentialLibraries(['1', '2']); + }); + + test('it has a `removeCredentialLibrary` method that deletes a single credential library using `removeCredentialLibraries` method', async function (assert) { + assert.expect(1); + this.server.post( + '/v1/targets/123abc:remove-credential-libraries', + (schema, request) => { + const body = JSON.parse(request.requestBody); + assert.deepEqual(body, { + application_credential_library_ids: ['2'], + version: 1, + }); + return { id: '123abc' }; + } + ); + const store = this.owner.lookup('service:store'); + store.push({ + data: { + id: '123abc', + type: 'target', + attributes: { + name: 'Target', + description: 'Description', + application_credential_library_ids: [{ value: '1' }, { value: '2' }], + version: 1, + scope: { + scope_id: 'o_1', + type: 'scope', + }, + }, + }, + }); + const model = store.peekRecord('target', '123abc'); + await model.removeCredentialLibrary('2'); + }); }); diff --git a/addons/api/tests/unit/serializers/application-test.js b/addons/api/tests/unit/serializers/application-test.js index a7040e876..c2fe164c9 100644 --- a/addons/api/tests/unit/serializers/application-test.js +++ b/addons/api/tests/unit/serializers/application-test.js @@ -203,6 +203,7 @@ module('Unit | Serializer | application', function (hooks) { name: 'Target 1', scope: { scope_id: 'o_123' }, host_sets: [], + application_credential_library_ids: [], }, relationships: {}, }, diff --git a/addons/api/tests/unit/serializers/fragment-credential-library-test.js b/addons/api/tests/unit/serializers/fragment-credential-library-test.js deleted file mode 100644 index 719d97955..000000000 --- a/addons/api/tests/unit/serializers/fragment-credential-library-test.js +++ /dev/null @@ -1,23 +0,0 @@ -import { module, test } from 'qunit'; -import { setupTest } from 'ember-qunit'; - -module('Unit | Serializer | fragment 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 serializer = store.serializerFor('fragment-credential-library'); - - assert.ok(serializer); - }); - - test('it serializes records', function (assert) { - let store = this.owner.lookup('service:store'); - let record = store.createRecord('fragment-credential-library', {}); - - let serializedRecord = record.serialize(); - - assert.ok(serializedRecord); - }); -}); diff --git a/addons/api/tests/unit/serializers/target-test.js b/addons/api/tests/unit/serializers/target-test.js index 255faa9ac..12dcacd4b 100644 --- a/addons/api/tests/unit/serializers/target-test.js +++ b/addons/api/tests/unit/serializers/target-test.js @@ -4,7 +4,7 @@ import { setupTest } from 'ember-qunit'; module('Unit | Serializer | target', function (hooks) { setupTest(hooks); - test('it serializes targets normally, without host sets', function (assert) { + test('it serializes targets normally, without host sets or credential libraries', function (assert) { assert.expect(1); const store = this.owner.lookup('service:store'); const serializer = store.serializerFor('target'); @@ -15,6 +15,7 @@ module('Unit | Serializer | target', function (hooks) { { host_set_id: '1', host_catalog_id: '2' }, { host_set_id: '3', host_catalog_id: '4' }, ], + application_credential_library_ids: [{ value: '1' }, { value: '2' }], scope: { scope_id: 'org_1', type: 'org', @@ -63,6 +64,27 @@ module('Unit | Serializer | target', function (hooks) { }); }); + test('it serializes only credential libraries and version when an `adapterOptions.credentialLibraryIDs` array is passed', function (assert) { + assert.expect(1); + const store = this.owner.lookup('service:store'); + const serializer = store.serializerFor('target'); + const record = store.createRecord('target', { + name: 'User', + description: 'Description', + application_credential_library_ids: [{ value: '1' }, { value: '2' }], + version: 1, + }); + const snapshot = record._createSnapshot(); + snapshot.adapterOptions = { + credentialLibraryIDs: ['4', '5'], + }; + const serializedRecord = serializer.serialize(snapshot); + assert.deepEqual(serializedRecord, { + application_credential_library_ids: ['4', '5'], + version: 1, + }); + }); + test('it normalizes records with array fields', function (assert) { assert.expect(1); const store = this.owner.lookup('service:store'); @@ -75,6 +97,7 @@ module('Unit | Serializer | target', function (hooks) { { host_set_id: '1', host_catalog_id: '2' }, { host_set_id: '3', host_catalog_id: '4' }, ], + application_credential_library_ids: ['1'], }; const normalized = serializer.normalizeSingleResponse( store, @@ -92,13 +115,14 @@ module('Unit | Serializer | target', function (hooks) { { host_set_id: '1', host_catalog_id: '2' }, { host_set_id: '3', host_catalog_id: '4' }, ], + application_credential_library_ids: [{ value: '1' }], }, relationships: {}, }, }); }); - test('it normalizes missing host_sets to empty array', function (assert) { + test('it normalizes missing host_sets and credential libraries to empty array', function (assert) { assert.expect(1); const store = this.owner.lookup('service:store'); const serializer = store.serializerFor('target'); @@ -122,6 +146,7 @@ module('Unit | Serializer | target', function (hooks) { name: 'Target 1', scope: { scope_id: 'o_123' }, host_sets: [], + application_credential_library_ids: [], }, relationships: {}, }, diff --git a/ui/admin/tests/acceptance/sessions-test.js b/ui/admin/tests/acceptance/sessions-test.js index 15a263925..d5f68ffeb 100644 --- a/ui/admin/tests/acceptance/sessions-test.js +++ b/ui/admin/tests/acceptance/sessions-test.js @@ -55,7 +55,7 @@ module('Acceptance | sessions', function (hooks) { 'target', 1, { scope: instances.scopes.project }, - 'withRandomHostSets' + 'withAssociations' ); instances.sessions = this.server.createList( 'session', diff --git a/ui/desktop/tests/acceptance/origin-test.js b/ui/desktop/tests/acceptance/origin-test.js index eddad56bb..6eb0c5d22 100644 --- a/ui/desktop/tests/acceptance/origin-test.js +++ b/ui/desktop/tests/acceptance/origin-test.js @@ -97,7 +97,7 @@ module('Acceptance | origin', function (hooks) { instances.target = this.server.create( 'target', { scope: instances.scopes.project }, - 'withRandomHostSets' + 'withAssociations' ); urls.scopes.global = `/scopes/${instances.scopes.global.id}`; diff --git a/ui/desktop/tests/acceptance/projects-test.js b/ui/desktop/tests/acceptance/projects-test.js index 38d54b480..3f6dd5506 100644 --- a/ui/desktop/tests/acceptance/projects-test.js +++ b/ui/desktop/tests/acceptance/projects-test.js @@ -92,7 +92,7 @@ module('Acceptance | projects', function (hooks) { instances.target = this.server.create( 'target', { scope: instances.scopes.project }, - 'withRandomHostSets' + 'withAssociations' ); urls.scopes.global = `/scopes/${instances.scopes.global.id}`; diff --git a/ui/desktop/tests/acceptance/projects/sessions-test.js b/ui/desktop/tests/acceptance/projects/sessions-test.js index 2cdbafc16..2b31e5eaa 100644 --- a/ui/desktop/tests/acceptance/projects/sessions-test.js +++ b/ui/desktop/tests/acceptance/projects/sessions-test.js @@ -97,7 +97,7 @@ module('Acceptance | projects | sessions', function (hooks) { instances.target = this.server.create( 'target', { scope: instances.scopes.project }, - 'withRandomHostSets' + 'withAssociations' ); instances.session = this.server.create( 'session', diff --git a/ui/desktop/tests/acceptance/projects/targets-test.js b/ui/desktop/tests/acceptance/projects/targets-test.js index 81dfbb22b..2fb027eec 100644 --- a/ui/desktop/tests/acceptance/projects/targets-test.js +++ b/ui/desktop/tests/acceptance/projects/targets-test.js @@ -101,7 +101,7 @@ module('Acceptance | projects | targets', function (hooks) { instances.target = this.server.create( 'target', { scope: instances.scopes.project }, - 'withRandomHostSets' + 'withAssociations' ); instances.session = this.server.create( diff --git a/ui/desktop/tests/acceptance/projects/targets/sessions-test.js b/ui/desktop/tests/acceptance/projects/targets/sessions-test.js index 6bfe8bd89..f687be5d1 100644 --- a/ui/desktop/tests/acceptance/projects/targets/sessions-test.js +++ b/ui/desktop/tests/acceptance/projects/targets/sessions-test.js @@ -106,7 +106,7 @@ module('Acceptance | projects | targets | sessions', function (hooks) { instances.target = this.server.create( 'target', { scope: instances.scopes.project }, - 'withRandomHostSets' + 'withAssociations' ); instances.session = this.server.create( diff --git a/ui/desktop/tests/acceptance/scopes-test.js b/ui/desktop/tests/acceptance/scopes-test.js index 93ec928bb..71907a984 100644 --- a/ui/desktop/tests/acceptance/scopes-test.js +++ b/ui/desktop/tests/acceptance/scopes-test.js @@ -110,7 +110,7 @@ module('Acceptance | scopes', function (hooks) { instances.target = this.server.create( 'target', { scope: instances.scopes.project }, - 'withRandomHostSets' + 'withAssociations' ); instances.session = this.server.create( diff --git a/ui/desktop/tests/acceptance/targets-test.js b/ui/desktop/tests/acceptance/targets-test.js index 85881b7ec..f92168c3a 100644 --- a/ui/desktop/tests/acceptance/targets-test.js +++ b/ui/desktop/tests/acceptance/targets-test.js @@ -94,7 +94,7 @@ module('Acceptance | targets', function (hooks) { instances.target = this.server.create( 'target', { scope: instances.scopes.project }, - 'withRandomHostSets' + 'withAssociations' ); urls.scopes.global = `/scopes/${instances.scopes.global.id}`; From c43ced038030e82395b32fc947272e0c342f9db7 Mon Sep 17 00:00:00 2001 From: dharini Date: Wed, 21 Jul 2021 13:01:59 -0700 Subject: [PATCH 13/68] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20toggle=20fun?= =?UTF-8?q?ctionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/rose/form/checkbox/index.stories.mdx | 9 +++++---- .../components/rose/form/radio/radio/index.stories.mdx | 7 ++++--- .../rose/addon/styles/rose/components/form/_radio.scss | 4 ---- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx b/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx index 11405c643..39925964b 100644 --- a/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx +++ b/addons/rose/addon/components/rose/form/checkbox/index.stories.mdx @@ -77,7 +77,7 @@ Renders a form input checkbox. @checked={{false}} @error={{false}} @disabled={{false}} - @inline={{true}} + @inline={{false}} /> ``` @@ -92,7 +92,7 @@ Renders a form input checkbox. @checked={{checked}} @error={{error}} @disabled={{disabled}} - @inline={{true}} + @inline={{inline}} /> `, context: { @@ -121,6 +121,7 @@ Renders a form input checkbox. checked: boolean('checked', false), error: boolean('error', false), disabled: boolean('disabled', false), + inline: boolean('inline', false) } }} diff --git a/addons/rose/addon/components/rose/form/radio/radio/index.stories.mdx b/addons/rose/addon/components/rose/form/radio/radio/index.stories.mdx index feb783d31..4d6a4153e 100644 --- a/addons/rose/addon/components/rose/form/radio/radio/index.stories.mdx +++ b/addons/rose/addon/components/rose/form/radio/radio/index.stories.mdx @@ -78,7 +78,7 @@ Renders a form radiofield. @selectedValue={{selectedValue}} @disabled={{disabled}} @icon={{icon}} - @inline={{true}} + @inline={{inline}} /> `, context: { @@ -118,6 +118,7 @@ Renders a form radiofield. }, null ), + inline: boolean('inline', false) } }} \ No newline at end of file diff --git a/addons/rose/addon/styles/rose/components/form/_radio.scss b/addons/rose/addon/styles/rose/components/form/_radio.scss index f248d0b7a..4ce25f95b 100644 --- a/addons/rose/addon/styles/rose/components/form/_radio.scss +++ b/addons/rose/addon/styles/rose/components/form/_radio.scss @@ -28,10 +28,6 @@ $data-svg-prefix: 'data:image/svg+xml;utf-8,'; margin-right: sizing.rems(s); } } - .radio-group-inline { - display: flex; - margin-right: sizing.rems(s); - } @include type.type(m); position: relative; margin-bottom: sizing.rems(xs); From 2eb7084643ef0ae01430e70a57d68dd7e8ee07a8 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Wed, 21 Jul 2021 13:31:48 -0700 Subject: [PATCH 14/68] =?UTF-8?q?test:=20=F0=9F=92=8D=20Adding=20acceptanc?= =?UTF-8?q?e=20test=20for=20delete=20CRUD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add acceptance test for delete CRUD operation in credential stores --- .../acceptance/credential-stores-test.js | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/ui/admin/tests/acceptance/credential-stores-test.js b/ui/admin/tests/acceptance/credential-stores-test.js index f41d31a12..53c98d274 100644 --- a/ui/admin/tests/acceptance/credential-stores-test.js +++ b/ui/admin/tests/acceptance/credential-stores-test.js @@ -5,6 +5,8 @@ import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import a11yAudit from 'ember-a11y-testing/test-support/audit'; import { authenticateSession } from 'ember-simple-auth/test-support'; import { Response } from 'miragejs'; +import { resolve, reject } from 'rsvp'; +import sinon from 'sinon'; module('Acceptance | credential-stores', function (hooks) { setupApplicationTest(hooks); @@ -236,4 +238,54 @@ module('Acceptance | credential-stores', function (hooks) { ); } }); + + test('can delete credential store', async function (assert) { + assert.expect(1); + const count = getCredentialStoresCount(); + await visit(urls.credentialStore); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.equal(getCredentialStoresCount(), count - 1); + }); + + test('can accept delete credential store via dialog', async function (assert) { + assert.expect(2); + const confirmService = this.owner.lookup('service:confirm'); + confirmService.enabled = true; + confirmService.confirm = sinon.fake.returns(resolve()); + const count = getCredentialStoresCount(); + await visit(urls.credentialStore); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.equal(getCredentialStoresCount(), count - 1); + assert.ok(confirmService.confirm.calledOnce); + }); + + test('cannot cancel delete credential store via dialog', async function (assert) { + assert.expect(2); + const confirmService = this.owner.lookup('service:confirm'); + confirmService.enabled = true; + confirmService.confirm = sinon.fake.returns(reject()); + const count = getCredentialStoresCount(); + await visit(urls.credentialStore); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.equal(getCredentialStoresCount(), count); + assert.ok(confirmService.confirm.calledOnce); + }); + + test('deleting a host catalog which errors displays error messages', async function (assert) { + assert.expect(1); + this.server.del('/credential-stores/:id', () => { + return new Response( + 490, + {}, + { + status: 490, + code: 'error', + message: 'Oops.', + } + ); + }); + await visit(urls.credentialStore); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.ok(find('[role="alert"]').textContent.trim(), 'Oops.'); + }); }); From 0ad6d027e61f9a4f3f21fab81cb4bc55920416ea Mon Sep 17 00:00:00 2001 From: dharini Date: Wed, 21 Jul 2021 13:33:03 -0700 Subject: [PATCH 15/68] =?UTF-8?q?fix:=20=F0=9F=90=9B=20space?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rose/addon/styles/rose/components/form/_radio.scss | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/addons/rose/addon/styles/rose/components/form/_radio.scss b/addons/rose/addon/styles/rose/components/form/_radio.scss index 4ce25f95b..2b547edce 100644 --- a/addons/rose/addon/styles/rose/components/form/_radio.scss +++ b/addons/rose/addon/styles/rose/components/form/_radio.scss @@ -23,11 +23,11 @@ $radio-svg: ( $data-svg-prefix: 'data:image/svg+xml;utf-8,'; .rose-form-radio { &.inline { - display: inline-block; - .rose-form-radio-label { - margin-right: sizing.rems(s); - } - } + display: inline-block; + .rose-form-radio-label { + margin-right: sizing.rems(s); + } + } @include type.type(m); position: relative; margin-bottom: sizing.rems(xs); From 74fa0876fb1fcf560e03f82e3db9036d23caa23e Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Wed, 21 Jul 2021 14:01:57 -0700 Subject: [PATCH 16/68] =?UTF-8?q?fix:=20=F0=9F=90=9B=20Fix=20translation?= =?UTF-8?q?=20misplacement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/core/translations/resources/en-us.yaml | 3 ++- .../routes/scopes/scope/credential-stores/credential-store.js | 2 +- .../scope/credential-stores/credential-store/-actions.hbs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index fcc631b72..9d8564288 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -272,7 +272,6 @@ credential-store: title_plural: Credential Stores description: A credential stores is a collection of credentials and credential libraries. actions: - create: New Credential Library delete: Delete Credential Store credential-library: title: Credential Library @@ -282,3 +281,5 @@ credential-library: none: title: No Credential Libraries Available description: No Credential Libraries available in this credential store. + actions: + create: New Credential Library diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js index d217736fc..046b8a01c 100644 --- a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store.js @@ -10,7 +10,7 @@ export default class ScopesScopeCredentialStoresCredentialStoreRoute extends Rou } /** - * Render credential store header and navigation page sections. + * Render credential store header, navigation and actions page sections. * @override */ renderTemplate() { diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs index 165b709ca..9364d89f5 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs @@ -4,7 +4,7 @@ as |dropdown| > - {{t 'resources.credential-store.actions.create'}} + {{t 'resources.credential-library.actions.create'}} Date: Wed, 21 Jul 2021 14:07:29 -0700 Subject: [PATCH 17/68] =?UTF-8?q?fix:=20=F0=9F=90=9B=20lint=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../addon/components/rose/form/checkbox/index.hbs | 2 +- .../addon/styles/rose/components/form/_radio.scss | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/addons/rose/addon/components/rose/form/checkbox/index.hbs b/addons/rose/addon/components/rose/form/checkbox/index.hbs index e4a2c11d5..d9b655458 100644 --- a/addons/rose/addon/components/rose/form/checkbox/index.hbs +++ b/addons/rose/addon/components/rose/form/checkbox/index.hbs @@ -1,4 +1,4 @@ -
+
Date: Wed, 21 Jul 2021 14:31:10 -0700 Subject: [PATCH 18/68] Comment dropdown option to create a new library store until that route is available --- .../scope/credential-stores/credential-store/-actions.hbs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs index 9364d89f5..e19af1ada 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/-actions.hbs @@ -3,10 +3,10 @@ @dropdownRight={{true}} as |dropdown| > - + {{!-- {{t 'resources.credential-library.actions.create'}} - + --}} Date: Wed, 21 Jul 2021 15:09:21 -0700 Subject: [PATCH 19/68] Fix typo --- ui/admin/tests/acceptance/credential-stores-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/admin/tests/acceptance/credential-stores-test.js b/ui/admin/tests/acceptance/credential-stores-test.js index 53c98d274..3979f664e 100644 --- a/ui/admin/tests/acceptance/credential-stores-test.js +++ b/ui/admin/tests/acceptance/credential-stores-test.js @@ -271,7 +271,7 @@ module('Acceptance | credential-stores', function (hooks) { assert.ok(confirmService.confirm.calledOnce); }); - test('deleting a host catalog which errors displays error messages', async function (assert) { + test('deleting a credential store which errors displays error messages', async function (assert) { assert.expect(1); this.server.del('/credential-stores/:id', () => { return new Response( From dad2d456d02f5b172fc888ed76828dd21accac10 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Thu, 22 Jul 2021 08:50:54 -0700 Subject: [PATCH 20/68] =?UTF-8?q?chore:=20=F0=9F=A4=96=20Update=20eslint?= =?UTF-8?q?=20dependency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/package.json | 2 +- addons/auth/package.json | 2 +- addons/core/package.json | 2 +- addons/rose/package.json | 2 +- ui/admin/package.json | 2 +- ui/desktop/package.json | 2 +- yarn.lock | 77 +++++++++++++++++++++++++++++++++++++++- 7 files changed, 82 insertions(+), 7 deletions(-) diff --git a/addons/api/package.json b/addons/api/package.json index 1bf61697c..a38301dec 100644 --- a/addons/api/package.json +++ b/addons/api/package.json @@ -59,7 +59,7 @@ "ember-source-channel-url": "^3.0.0", "ember-template-lint": "^2.15.0", "ember-try": "^1.4.0", - "eslint": "^7.17.0", + "eslint": "^7.31.0", "eslint-config-prettier": "^7.1.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", diff --git a/addons/auth/package.json b/addons/auth/package.json index 9d27bee7c..44405d65b 100644 --- a/addons/auth/package.json +++ b/addons/auth/package.json @@ -53,7 +53,7 @@ "ember-source-channel-url": "^3.0.0", "ember-template-lint": "^2.15.0", "ember-try": "^1.4.0", - "eslint": "^7.17.0", + "eslint": "^7.31.0", "eslint-config-prettier": "^7.1.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", diff --git a/addons/core/package.json b/addons/core/package.json index 1e3f3ef9a..3bdf0c75c 100644 --- a/addons/core/package.json +++ b/addons/core/package.json @@ -68,7 +68,7 @@ "ember-source-channel-url": "^3.0.0", "ember-template-lint": "^2.15.0", "ember-try": "^1.4.0", - "eslint": "^7.17.0", + "eslint": "^7.31.0", "eslint-config-prettier": "^7.1.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", diff --git a/addons/rose/package.json b/addons/rose/package.json index dad7f51cb..04110e79e 100644 --- a/addons/rose/package.json +++ b/addons/rose/package.json @@ -73,7 +73,7 @@ "ember-source-channel-url": "^3.0.0", "ember-template-lint": "^2.15.0", "ember-try": "^1.4.0", - "eslint": "^7.17.0", + "eslint": "^7.31.0", "eslint-config-prettier": "^7.1.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", diff --git a/ui/admin/package.json b/ui/admin/package.json index 0f7e95b19..2d1e8f9b0 100644 --- a/ui/admin/package.json +++ b/ui/admin/package.json @@ -77,7 +77,7 @@ "ember-source": "~3.24.0", "ember-template-lint": "^2.15.0", "ember-template-lint-plugin-prettier": "^2.0.0", - "eslint": "^7.17.0", + "eslint": "^7.31.0", "eslint-config-prettier": "^7.1.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", diff --git a/ui/desktop/package.json b/ui/desktop/package.json index c22ee5143..046442e65 100755 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -92,7 +92,7 @@ "ember-source": "~3.24.0", "ember-template-lint": "^2.15.0", "ember-template-lint-plugin-prettier": "^2.0.0", - "eslint": "^7.17.0", + "eslint": "^7.31.0", "eslint-config-prettier": "^7.1.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", diff --git a/yarn.lock b/yarn.lock index eeeb32795..82666df63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2060,6 +2060,21 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + "@formatjs/ecma402-abstract@1.6.4": version "1.6.4" resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.6.4.tgz#cff5ef03837fb6bae70b16d04940213c17e87884" @@ -2284,6 +2299,20 @@ resolved "https://registry.yarnpkg.com/@hashicorp/structure-icons/-/structure-icons-1.9.1.tgz#eb294ef28e8192062f6c7c08459382ba31a8b4af" integrity sha512-uuncAHmehXk/WeNzE3NqS8z0YX/AU3Go8rDEUK2rNFdp1c0T1HiHO6RaBW5byB8KEBAPRdSsFSNqB4RaETarNA== +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" + integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== + "@iarna/cli@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@iarna/cli/-/cli-1.2.0.tgz#0f7af5e851afe895104583c4ca07377a8094d641" @@ -10099,7 +10128,7 @@ eslint@^2.7.0: text-table "~0.2.0" user-home "^2.0.0" -eslint@^7.17.0, eslint@^7.27.0: +eslint@^7.27.0: version "7.28.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.28.0.tgz#435aa17a0b82c13bb2be9d51408b617e49c1e820" integrity sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g== @@ -10144,6 +10173,52 @@ eslint@^7.17.0, eslint@^7.27.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" +eslint@^7.31.0: + version "7.31.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.31.0.tgz#f972b539424bf2604907a970860732c5d99d3aca" + integrity sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + esm@^3.2.25, esm@^3.2.4: version "3.2.25" resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" From af337626f56c6d004e7ed7a36cccd20ff569e885 Mon Sep 17 00:00:00 2001 From: dharini Date: Thu, 22 Jul 2021 09:37:41 -0700 Subject: [PATCH 21/68] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20fieldset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../form/credential-library/index.hbs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs index d45f78b58..0e9e69e7c 100644 --- a/ui/admin/app/components/form/credential-library/index.hbs +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -74,6 +74,23 @@ {{/each}} + + <:title>{{t 'form.http_method.label'}} + <:description>{{t 'form.http_method.help'}} + <:body> + + {{#each this.httpMethods as |httpMethod|}} + + {{/each}} + + + Date: Thu, 22 Jul 2021 09:45:45 -0700 Subject: [PATCH 22/68] =?UTF-8?q?fix:=20=F0=9F=90=9B=20space?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/admin/app/components/form/credential-library/index.hbs | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs index 0e9e69e7c..6a5395f4e 100644 --- a/ui/admin/app/components/form/credential-library/index.hbs +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -91,6 +91,7 @@ + Date: Thu, 22 Jul 2021 09:58:49 -0700 Subject: [PATCH 23/68] =?UTF-8?q?chore:=20=F0=9F=A4=96=20Update=20eslint-c?= =?UTF-8?q?onfig-prettier=20dependency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/package.json | 2 +- addons/auth/package.json | 2 +- addons/core/package.json | 2 +- addons/rose/package.json | 2 +- ui/admin/package.json | 2 +- ui/desktop/package.json | 2 +- yarn.lock | 8 ++++---- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/addons/api/package.json b/addons/api/package.json index 1bf61697c..670e3e111 100644 --- a/addons/api/package.json +++ b/addons/api/package.json @@ -60,7 +60,7 @@ "ember-template-lint": "^2.15.0", "ember-try": "^1.4.0", "eslint": "^7.17.0", - "eslint-config-prettier": "^7.1.0", + "eslint-config-prettier": "^8.3.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.3.1", diff --git a/addons/auth/package.json b/addons/auth/package.json index 9d27bee7c..bad492680 100644 --- a/addons/auth/package.json +++ b/addons/auth/package.json @@ -54,7 +54,7 @@ "ember-template-lint": "^2.15.0", "ember-try": "^1.4.0", "eslint": "^7.17.0", - "eslint-config-prettier": "^7.1.0", + "eslint-config-prettier": "^8.3.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.3.1", diff --git a/addons/core/package.json b/addons/core/package.json index 1e3f3ef9a..b1418ff28 100644 --- a/addons/core/package.json +++ b/addons/core/package.json @@ -69,7 +69,7 @@ "ember-template-lint": "^2.15.0", "ember-try": "^1.4.0", "eslint": "^7.17.0", - "eslint-config-prettier": "^7.1.0", + "eslint-config-prettier": "^8.3.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.3.1", diff --git a/addons/rose/package.json b/addons/rose/package.json index dad7f51cb..da14ad1aa 100644 --- a/addons/rose/package.json +++ b/addons/rose/package.json @@ -74,7 +74,7 @@ "ember-template-lint": "^2.15.0", "ember-try": "^1.4.0", "eslint": "^7.17.0", - "eslint-config-prettier": "^7.1.0", + "eslint-config-prettier": "^8.3.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.3.1", diff --git a/ui/admin/package.json b/ui/admin/package.json index 0f7e95b19..d3c989db5 100644 --- a/ui/admin/package.json +++ b/ui/admin/package.json @@ -78,7 +78,7 @@ "ember-template-lint": "^2.15.0", "ember-template-lint-plugin-prettier": "^2.0.0", "eslint": "^7.17.0", - "eslint-config-prettier": "^7.1.0", + "eslint-config-prettier": "^8.3.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.3.1", diff --git a/ui/desktop/package.json b/ui/desktop/package.json index c22ee5143..81be68f37 100755 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -93,7 +93,7 @@ "ember-template-lint": "^2.15.0", "ember-template-lint-plugin-prettier": "^2.0.0", "eslint": "^7.17.0", - "eslint-config-prettier": "^7.1.0", + "eslint-config-prettier": "^8.3.0", "eslint-plugin-ember": "^10.1.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.3.1", diff --git a/yarn.lock b/yarn.lock index eeeb32795..3b25ae477 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9975,10 +9975,10 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-config-prettier@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz#f4a4bd2832e810e8cc7c1411ec85b3e85c0c53f9" - integrity sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg== +eslint-config-prettier@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" + integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== eslint-plugin-ember@^10.1.1: version "10.5.0" From aa2114062b710775ce92211a6c0616ca2eb82cb1 Mon Sep 17 00:00:00 2001 From: dharini Date: Thu, 22 Jul 2021 10:13:33 -0700 Subject: [PATCH 24/68] =?UTF-8?q?fix:=20=F0=9F=90=9B=20update=20to=20semi?= =?UTF-8?q?=20bold=20to=20match=20labels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/rose/addon/styles/rose/components/form/_fieldset.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/rose/addon/styles/rose/components/form/_fieldset.scss b/addons/rose/addon/styles/rose/components/form/_fieldset.scss index f35d3755c..c01a77a60 100644 --- a/addons/rose/addon/styles/rose/components/form/_fieldset.scss +++ b/addons/rose/addon/styles/rose/components/form/_fieldset.scss @@ -5,7 +5,7 @@ margin-bottom: sizing.rems(m); .rose-form-fieldset-title { - @include type.type(s, bold); + @include type.type(s, semibold); } .rose-form-fieldset-description { From 8b9d945efbce37a6b06c983e9e126ebbfff6b283 Mon Sep 17 00:00:00 2001 From: dharini Date: Thu, 22 Jul 2021 10:24:56 -0700 Subject: [PATCH 25/68] =?UTF-8?q?fix:=20=F0=9F=90=9B=20use=20named=20block?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/admin/app/components/form/credential-library/index.hbs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs index 6a5395f4e..a3c7acbae 100644 --- a/ui/admin/app/components/form/credential-library/index.hbs +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -74,7 +74,7 @@ {{/each}} - + <:title>{{t 'form.http_method.label'}} <:description>{{t 'form.http_method.help'}} <:body> @@ -90,7 +90,7 @@ {{/each}} - + Date: Thu, 22 Jul 2021 16:26:05 -0400 Subject: [PATCH 26/68] fix: Surface fieldset as a form component --- addons/rose/addon/components/rose/form/index.hbs | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/rose/addon/components/rose/form/index.hbs b/addons/rose/addon/components/rose/form/index.hbs index 8c545ec22..e23e52c0b 100644 --- a/addons/rose/addon/components/rose/form/index.hbs +++ b/addons/rose/addon/components/rose/form/index.hbs @@ -20,6 +20,7 @@ input=(component 'rose/form/input' disabled=this.disabled) select=(component 'rose/form/select' disabled=this.disabled) textarea=(component 'rose/form/textarea' disabled=this.disabled) + fieldset=(component 'rose/form/fieldset') actions=(component (if this.showEditToggleButton 'rose/form/actions/edit-toggle' From 03ce6be3ee09c0b6996f41b2d3c2775ec92ea395 Mon Sep 17 00:00:00 2001 From: dharini Date: Thu, 22 Jul 2021 13:44:02 -0700 Subject: [PATCH 27/68] =?UTF-8?q?fix:=20=F0=9F=90=9B=20cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/components/form/credential-library/index.hbs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs index a3c7acbae..322c35965 100644 --- a/ui/admin/app/components/form/credential-library/index.hbs +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -63,17 +63,6 @@ {{/if}} - - {{#each this.httpMethods as |httpMethod|}} - - {{/each}} - - <:title>{{t 'form.http_method.label'}} <:description>{{t 'form.http_method.help'}} From a6be658aa58c19672e5cfa5cef98094af9c634a0 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Thu, 22 Jul 2021 17:42:37 -0400 Subject: [PATCH 28/68] fix: Add error handling to credential-library creation form --- addons/api/addon/models/credential-library.js | 8 +-- .../fragment-credential-library-attributes.js | 2 + addons/api/mirage/config.js | 1 - addons/core/translations/form/en-us.yaml | 9 --- addons/core/translations/resources/en-us.yaml | 15 +++- .../form/credential-library/index.hbs | 72 ++++++++++++------- .../form/credential-library/index.js | 10 ++- 7 files changed, 67 insertions(+), 50 deletions(-) diff --git a/addons/api/addon/models/credential-library.js b/addons/api/addon/models/credential-library.js index 4ca321a18..a77e605ba 100644 --- a/addons/api/addon/models/credential-library.js +++ b/addons/api/addon/models/credential-library.js @@ -6,7 +6,7 @@ import { fragment } from 'ember-data-model-fragments/attributes'; * Enum options for credential library. */ export const options = { - http_methods: ['GET', 'POST'], + http_method: ['GET', 'POST'], }; export default class CredentialLibraryModel extends GeneratedCredentialLibraryModel { @@ -15,11 +15,7 @@ export default class CredentialLibraryModel extends GeneratedCredentialLibraryMo // See the application adapter's error normalization method for // more information. - @attr('string', { - readOnly: true, - defaultValue: options.http_methods[0], - }) - attributes_http_method; + @attr('string', { readOnly: true }) attributes_http_method; @attr('string', { readOnly: true }) attributes_http_request_body; @attr('string', { readOnly: true }) attributes_path; diff --git a/addons/api/addon/models/fragment-credential-library-attributes.js b/addons/api/addon/models/fragment-credential-library-attributes.js index dd6138199..582922601 100644 --- a/addons/api/addon/models/fragment-credential-library-attributes.js +++ b/addons/api/addon/models/fragment-credential-library-attributes.js @@ -1,5 +1,6 @@ import Fragment from 'ember-data-model-fragments/fragment'; import { attr } from '@ember-data/model'; +import { options } from './credential-library'; export default class FragmentCredentialLibraryAttributesModel extends Fragment { //= attributes (vault) @@ -7,6 +8,7 @@ export default class FragmentCredentialLibraryAttributesModel extends Fragment { @attr('string', { description: 'The HTTP method the library uses when requesting credentials from Vault.', + defaultValue: () => options.http_method[0], }) http_method; diff --git a/addons/api/mirage/config.js b/addons/api/mirage/config.js index 5d9ddaf8e..a45cd1bab 100644 --- a/addons/api/mirage/config.js +++ b/addons/api/mirage/config.js @@ -484,7 +484,6 @@ export default function () { const attrs = this.normalizedRequestAttrs(); const credentialStore = credentialStores.find(attrs.credentialStoreId); attrs.scopeId = credentialStore.scope.id; - console.log(attrs); return credentialLibraries.create(attrs); } ); diff --git a/addons/core/translations/form/en-us.yaml b/addons/core/translations/form/en-us.yaml index 171011a4a..cb7b69832 100644 --- a/addons/core/translations/form/en-us.yaml +++ b/addons/core/translations/form/en-us.yaml @@ -115,12 +115,3 @@ value: callback_url: label: Callback URL help: The URL to which the third-party provider sends the authentication response. Paste this into the provider configuration. -vault_path: - label: Vault Path - help: The path in Vault to request credentials from. -http_method: - label: HTTP Method - help: The HTTP method the library uses when requesting credentials from Vault. -http_request_body: - label: HTTP Request Body - help: The body of the HTTP request the library sends to Vault when requesting credentials. Only allowed when http_method is set to POST. diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 9468e3500..d889b0975 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -280,4 +280,17 @@ credential-library: messages: none: title: No Credential Libraries Available - description: No Credential Libraries available in this credential store. \ No newline at end of file + description: No Credential Libraries available in this credential store. + form: + vault_path: + label: Vault Path + help: The path the library uses when requesting credentials from Vault. + http_method: + label: HTTP Method + help: The HTTP method the library uses when requesting credentials from Vault. + http_request_body: + label: HTTP Request Body + help: The body of the HTTP request the library sends to Vault when requesting credentials. Only allowed when HTTP method is set to POST. + http_post_method_options: + label: HTTP Method POST Options + help: The options available for when HTTP method is set to POST. \ No newline at end of file diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs index 322c35965..f55445503 100644 --- a/ui/admin/app/components/form/credential-library/index.hbs +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -48,15 +48,15 @@ @name='vault_path' @type='text' @value={{@model.attributes.path}} - @label={{t 'form.vault_path.label'}} - @error={{@model.errors.name}} - @helperText={{t 'form.vault_path.help'}} + @label={{t 'resources.credential-library.form.vault_path.label'}} + @error={{@model.errors.attributes_path}} + @helperText={{t 'resources.credential-library.form.vault_path.help'}} readonly={{false}} as |field| > - {{#if @model.errors.name}} + {{#if @model.errors.attributes_path}} - {{#each @model.errors.name as |error|}} + {{#each @model.errors.attributes_path as |error|}} {{error.message}} {{/each}} @@ -64,8 +64,10 @@ - <:title>{{t 'form.http_method.label'}} - <:description>{{t 'form.http_method.help'}} + <:title>{{t 'resources.credential-library.form.http_method.label'}} + <:description>{{t + 'resources.credential-library.form.http_method.help' + }} <:body> - {{#each this.httpMethods as |httpMethod|}} + {{#each this.httpMethodOptions as |httpMethod|}} {{/each}} - - {{#if @model.errors.description}} - - {{#each @model.errors.description as |error|}} - {{error.message}} - {{/each}} - - {{/if}} - + {{#if this.isHttpRequestBodyAllowed}} + + <:title>{{t + 'resources.credential-library.form.http_post_method_options.label' + }} + <:description>{{t + 'resources.credential-library.form.http_post_method_options.help' + }} + <:body> + + {{#if @model.errors.attributes_http_request_body}} + + {{#each @model.errors.attributes_http_request_body as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{/if}} Date: Tue, 20 Jul 2021 08:50:31 -0400 Subject: [PATCH 29/68] feat: View credential library details --- ui/admin/app/router.js | 5 ++ .../credential-library.js | 49 +++++++++++++++++++ .../credential-library/index.js | 3 ++ .../credential-library.hbs | 3 ++ .../credential-library/-actions.hbs | 0 .../credential-library/-header.hbs | 9 ++++ .../credential-library/-navigation.hbs | 7 +++ .../credential-library/index.hbs | 5 ++ .../credential-libraries/index.hbs | 7 ++- .../credential-library-test.js | 16 ++++++ .../credential-library/index-test.js | 16 ++++++ 11 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library.js create mode 100644 ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index.js create mode 100644 ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library.hbs create mode 100644 ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-actions.hbs create mode 100644 ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs create mode 100644 ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-navigation.hbs create mode 100644 ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index.hbs create mode 100644 ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library-test.js create mode 100644 ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index-test.js diff --git a/ui/admin/app/router.js b/ui/admin/app/router.js index 3c359e268..a1bfa1e18 100644 --- a/ui/admin/app/router.js +++ b/ui/admin/app/router.js @@ -93,6 +93,11 @@ Router.map(function () { function () { this.route('credential-libraries', function () { this.route('new'); + this.route( + 'credential-library', + { path: ':credential_library_id' }, + function () {} + ); }); } ); diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library.js new file mode 100644 index 000000000..45f5953fb --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library.js @@ -0,0 +1,49 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrariesCredentialLibraryRoute extends Route { + // =methods + + /** + * Load a credential-library using current credential store and its parent scope. + * @param {object} params + * @param {string} params.credential_library_id + * @return {CredentialLibraryModel} + */ + async model({ credential_library_id }) { + return this.store.findRecord('credential-library', credential_library_id, { + reload: true, + }); + } + + /** + * Renders the credential library specific templates for header, navigation, and action page sections. + * @override + */ + renderTemplate() { + super.renderTemplate(...arguments); + + this.render( + 'scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header', + { + into: 'scopes/scope/credential-stores/credential-store', + outlet: 'header', + } + ); + + this.render( + 'scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-navigation', + { + into: 'scopes/scope/credential-stores/credential-store', + outlet: 'navigation', + } + ); + + this.render( + 'scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-actions', + { + into: 'scopes/scope/credential-stores/credential-store', + outlet: 'actions', + } + ); + } +} diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index.js new file mode 100644 index 000000000..8d9b40c15 --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrariesCredentialLibraryIndexRoute extends Route {} diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library.hbs new file mode 100644 index 000000000..7d32ecb0d --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library.hbs @@ -0,0 +1,3 @@ +{{page-title @model.displayName}} + +{{outlet}} \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-actions.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-actions.hbs new file mode 100644 index 000000000..e69de29bb diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs new file mode 100644 index 000000000..3c2de9eef --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs @@ -0,0 +1,9 @@ +

{{t 'resources.credential-library.title'}}

+

{{t 'resources.credential-library.description'}}

+ + {{@model.id}} + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-navigation.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-navigation.hbs new file mode 100644 index 000000000..d5bb5cf63 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-navigation.hbs @@ -0,0 +1,7 @@ + + + {{t 'titles.details'}} + + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index.hbs new file mode 100644 index 000000000..648221a43 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index.hbs @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs index 2164989cc..cbe1ede49 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs @@ -11,7 +11,12 @@ {{#each @model as |credentialLibrary|}} - {{credentialLibrary.displayName}} + + {{credentialLibrary.displayName}} +

{{credentialLibrary.description}}

diff --git a/ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library-test.js b/ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library-test.js new file mode 100644 index 000000000..54025fe54 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Route | scopes/scope/credential-stores/credential-store/credential-libraries/credential-library', + function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup( + 'route:scopes/scope/credential-stores/credential-store/credential-libraries/credential-library' + ); + assert.ok(route); + }); + } +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index-test.js b/ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index-test.js new file mode 100644 index 000000000..1e4586a16 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Route | scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index', + function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup( + 'route:scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/index' + ); + assert.ok(route); + }); + } +); From 027371567b5341a4de9da2146e0050280ce0b5a9 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Thu, 22 Jul 2021 18:02:29 -0400 Subject: [PATCH 30/68] fix: Disable credential library view in non-edit mode --- ui/admin/app/components/form/credential-library/index.hbs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs index f55445503..6c396faf0 100644 --- a/ui/admin/app/components/form/credential-library/index.hbs +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -12,6 +12,7 @@ @label={{t 'form.name.label'}} @error={{@model.errors.name}} @helperText={{t 'form.name.help'}} + disabled={{@model.isSaving}} readonly={{false}} as |field| > @@ -31,7 +32,7 @@ @label={{t 'form.description.label'}} @error={{@model.errors.description}} @helperText={{t 'form.description.help'}} - @disabled={{@model.isSaving}} + disabled={{@model.isSaving}} readonly={{false}} as |field| > @@ -51,6 +52,7 @@ @label={{t 'resources.credential-library.form.vault_path.label'}} @error={{@model.errors.attributes_path}} @helperText={{t 'resources.credential-library.form.vault_path.help'}} + disabled={{@model.isSaving}} readonly={{false}} as |field| > @@ -74,6 +76,7 @@ @selectedValue={{@model.attributes.http_method}} @changed={{fn (mut @model.attributes.http_method)}} @inline={{true}} + disabled={{@model.isSaving}} as |radioGroup| > {{#each this.httpMethodOptions as |httpMethod|}} @@ -103,7 +106,7 @@ @helperText={{t 'resources.credential-library.form.http_request_body.help' }} - @disabled={{this.cannotSaveHttpRequestBody}} + disabled={{@model.isSaving}} readonly={{false}} as |field| > From b7e5477b3dbb399bf639fd3aa5ceb33fee2de875 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Fri, 23 Jul 2021 09:29:42 -0400 Subject: [PATCH 31/68] fix: Shorten credential library POST form area --- addons/core/translations/resources/en-us.yaml | 5 +- .../form/credential-library/index.hbs | 54 ++++++++----------- 2 files changed, 22 insertions(+), 37 deletions(-) diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index b2ec4d304..8094abf9e 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -291,8 +291,5 @@ credential-library: label: HTTP Method help: The HTTP method the library uses when requesting credentials from Vault. http_request_body: - label: HTTP Request Body + label: HTTP Method POST Request Body help: The body of the HTTP request the library sends to Vault when requesting credentials. Only allowed when HTTP method is set to POST. - http_post_method_options: - label: HTTP Method POST Options - help: The options available for when HTTP method is set to POST. \ No newline at end of file diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs index f55445503..beef7e8c6 100644 --- a/ui/admin/app/components/form/credential-library/index.hbs +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -84,39 +84,27 @@
{{#if this.isHttpRequestBodyAllowed}} - - <:title>{{t - 'resources.credential-library.form.http_post_method_options.label' - }} - <:description>{{t - 'resources.credential-library.form.http_post_method_options.help' - }} - <:body> - - {{#if @model.errors.attributes_http_request_body}} - - {{#each @model.errors.attributes_http_request_body as |error|}} - {{error.message}} - {{/each}} - - {{/if}} - - - + + {{#if @model.errors.attributes_http_request_body}} + + {{#each @model.errors.attributes_http_request_body as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + {{/if}} Date: Fri, 23 Jul 2021 11:28:11 -0700 Subject: [PATCH 32/68] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Add=20credential?= =?UTF-8?q?=20stores=20empty=20list=20message?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add credential stores empty list message with link to create a new one. --- addons/core/translations/resources/en-us.yaml | 5 +++- .../scopes/scope/credential-stores/index.hbs | 23 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 9d8564288..72f062f7b 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -270,7 +270,10 @@ target: credential-store: title: Credential Store title_plural: Credential Stores - description: A credential stores is a collection of credentials and credential libraries. + description: A credential store is a collection of credentials and credential libraries. + messages: + welcome: + title: Welcome to Credential Stores actions: delete: Delete Credential Store credential-library: diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/index.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/index.hbs index c8ff3b098..7b6e88c9e 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/index.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/index.hbs @@ -8,7 +8,9 @@ {{t 'resources.credential-store.title_plural'}} -

{{t 'resources.credential-store.description'}}

+ {{#if @model}} +

{{t 'resources.credential-store.description'}}

+ {{/if}} @@ -61,6 +63,25 @@ {{/each}} + + {{else}} + + + + {{t 'resources.credential-store.description'}} + + + + {{t 'titles.new'}} + + + + {{/if}} + + \ No newline at end of file From af7e539f3d0f960bf2b753ae7832793d07ef7bab Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Fri, 23 Jul 2021 16:33:45 -0400 Subject: [PATCH 33/68] feat: List credential libraries for a target --- addons/core/translations/resources/en-us.yaml | 5 ++ .../targets/target/credential-libraries.js | 18 +++++++ ui/admin/app/router.js | 1 + .../targets/target/credential-libraries.js | 35 ++++++++++++ .../scope/targets/target/-navigation.hbs | 3 ++ .../targets/target/credential-libraries.hbs | 54 +++++++++++++++++++ .../target/credential-libraries-test.js | 17 ++++++ .../target/credential-libraries-test.js | 16 ++++++ 8 files changed, 149 insertions(+) create mode 100644 ui/admin/app/controllers/scopes/scope/targets/target/credential-libraries.js create mode 100644 ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js create mode 100644 ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs create mode 100644 ui/admin/tests/unit/controllers/scopes/scope/targets/target/credential-libraries-test.js create mode 100644 ui/admin/tests/unit/routes/scopes/scope/targets/target/credential-libraries-test.js diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 8094abf9e..259824292 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -267,6 +267,11 @@ target: add: title: Add Host Sets description: Select host sets to assign to this target. + credential-library: + messages: + welcome: + title: Welcome to Credential Libraries + description: No credential libraries in this target. credential-store: title: Credential Store title_plural: Credential Stores diff --git a/ui/admin/app/controllers/scopes/scope/targets/target/credential-libraries.js b/ui/admin/app/controllers/scopes/scope/targets/target/credential-libraries.js new file mode 100644 index 000000000..ff0f8c558 --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/targets/target/credential-libraries.js @@ -0,0 +1,18 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeTargetsTargetCredentialLibrariesController extends Controller { + // =services + + @service intl; + + // =attributes + + /** + * Translated credential library breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.intl.t('resources.credential-library.title_plural'); + } +} diff --git a/ui/admin/app/router.js b/ui/admin/app/router.js index a1bfa1e18..8638e4e48 100644 --- a/ui/admin/app/router.js +++ b/ui/admin/app/router.js @@ -65,6 +65,7 @@ Router.map(function () { this.route('target', { path: ':target_id' }, function () { this.route('host-sets', function () {}); this.route('add-host-sets'); + this.route('credential-libraries'); }); this.route('new'); }); diff --git a/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js b/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js new file mode 100644 index 000000000..792cc2aa8 --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js @@ -0,0 +1,35 @@ +import Route from '@ember/routing/route'; +import { hash, all } from 'rsvp'; + +export default class ScopesScopeTargetsTargetCredentialLibrariesRoute extends Route { + // =methods + + /** + * Loads all credential libraries under the current target + * and it's parent scope. + * @return {Promise{[CredentialLibraryModel]}} + */ + beforeModel() { + const { application_credential_library_ids: credential_library_ids } = + this.modelFor('scopes.scope.targets.target'); + return hash({ + credentialLibraries: all( + credential_library_ids.map((credential_library) => + this.store.findRecord( + 'credential-library', + credential_library.value, + { reload: true } + ) + ) + ), + }); + } + + /** + * Returns the previously loaded target instance. + * @return {TargetModel} + */ + model() { + return this.modelFor('scopes.scope.targets.target'); + } +} diff --git a/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs b/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs index adbeded12..be112a45a 100644 --- a/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs +++ b/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs @@ -5,4 +5,7 @@ {{t 'resources.host-set.title_plural'}} + + {{t 'resources.credential-library.title_plural'}} + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs b/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs new file mode 100644 index 000000000..ebba89bff --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs @@ -0,0 +1,54 @@ +{{page-title (t 'resources.credential-library.title_plural')}} + +{{#if @model.credentialLibraries}} + + + + + {{t 'form.name.label'}} + {{t 'form.id.label'}} + + + + {{#each @model.credentialLibraries as |credentialLibrary|}} + + + + {{credentialLibrary.displayName}} + +

{{credentialLibrary.description}}

+
+ + + {{credentialLibrary.id}} + + +
+ {{/each}} +
+
+ +{{else}} + + + + + {{t 'resources.target.credential-library.messages.welcome.description'}} + + + + +{{/if}} \ No newline at end of file diff --git a/ui/admin/tests/unit/controllers/scopes/scope/targets/target/credential-libraries-test.js b/ui/admin/tests/unit/controllers/scopes/scope/targets/target/credential-libraries-test.js new file mode 100644 index 000000000..76a26ff69 --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/targets/target/credential-libraries-test.js @@ -0,0 +1,17 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Controller | scopes/scope/targets/target/credential-libraries', + function (hooks) { + setupTest(hooks); + + // TODO: Replace this with your real tests. + test('it exists', function (assert) { + let controller = this.owner.lookup( + 'controller:scopes/scope/targets/target/credential-libraries' + ); + assert.ok(controller); + }); + } +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/targets/target/credential-libraries-test.js b/ui/admin/tests/unit/routes/scopes/scope/targets/target/credential-libraries-test.js new file mode 100644 index 000000000..894e3add0 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/targets/target/credential-libraries-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Route | scopes/scope/targets/target/credential-libraries', + function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup( + 'route:scopes/scope/targets/target/credential-libraries' + ); + assert.ok(route); + }); + } +); From 0dedbfb4116e9bb4e40ee51697c5988dab791af3 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Fri, 23 Jul 2021 17:04:39 -0400 Subject: [PATCH 34/68] docs: Fix comment for listing target credential libraries --- .../routes/scopes/scope/targets/target/credential-libraries.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js b/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js index 792cc2aa8..cb3570645 100644 --- a/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js +++ b/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js @@ -5,8 +5,7 @@ export default class ScopesScopeTargetsTargetCredentialLibrariesRoute extends Ro // =methods /** - * Loads all credential libraries under the current target - * and it's parent scope. + * Loads all credential libraries under the current target. * @return {Promise{[CredentialLibraryModel]}} */ beforeModel() { From 1e5d52410ef931418b6f131c8feb2c9025f8ec8c Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Fri, 23 Jul 2021 17:34:31 -0400 Subject: [PATCH 35/68] refactor: Cleanup credential library parameter name --- .../scopes/scope/targets/target/credential-libraries.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js b/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js index cb3570645..17e3e2692 100644 --- a/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js +++ b/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js @@ -9,11 +9,11 @@ export default class ScopesScopeTargetsTargetCredentialLibrariesRoute extends Ro * @return {Promise{[CredentialLibraryModel]}} */ beforeModel() { - const { application_credential_library_ids: credential_library_ids } = + const { application_credential_library_ids: credential_libraries } = this.modelFor('scopes.scope.targets.target'); return hash({ credentialLibraries: all( - credential_library_ids.map((credential_library) => + credential_libraries.map((credential_library) => this.store.findRecord( 'credential-library', credential_library.value, From f5b80f93d2163eca5eda182630487c9f72eb0754 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Fri, 23 Jul 2021 14:38:26 -0700 Subject: [PATCH 36/68] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20Delete=20jQuer?= =?UTF-8?q?y=20and=20refactor=20handler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete jQuery from desktop client and refactor the handler using a native electron way. --- ui/desktop/app/routes/application.js | 13 ------------- ui/desktop/electron-app/src/index.js | 7 ++++++- ui/desktop/package.json | 1 - yarn.lock | 14 +------------- 4 files changed, 7 insertions(+), 28 deletions(-) diff --git a/ui/desktop/app/routes/application.js b/ui/desktop/app/routes/application.js index 66790a728..f2f8e11fe 100644 --- a/ui/desktop/app/routes/application.js +++ b/ui/desktop/app/routes/application.js @@ -1,5 +1,4 @@ import Route from '@ember/routing/route'; -import jQuery from 'jquery'; import { inject as service } from '@ember/service'; import { action } from '@ember/object'; import { A } from '@ember/array'; @@ -31,18 +30,6 @@ export default class ApplicationRoute extends Route { return this.origin.updateOrigin(); } - /** - * Adds listener on target=_blank links so that they may be opened in an - * external browser. - */ - afterModel() { - const ipc = this.ipc; - /* eslint-disable-next-line ember/no-jquery */ - jQuery(document).on('click', 'a[href][target="_blank"]', function () { - ipc.invoke('openExternal', this.href); - }); - } - /** * Add OS config on controller */ diff --git a/ui/desktop/electron-app/src/index.js b/ui/desktop/electron-app/src/index.js index 1c9c7f6e2..a08bfba96 100644 --- a/ui/desktop/electron-app/src/index.js +++ b/ui/desktop/electron-app/src/index.js @@ -12,6 +12,7 @@ const { BrowserWindow, Menu, MenuItem, + shell, } = require('electron'); require('./ipc/handlers.js'); @@ -166,9 +167,13 @@ app.on('ready', async () => { /* eng-disable LIMIT_NAVIGATION_JS_CHECK */ if (!url.startsWith('serve://boundary')) event.preventDefault(); }); + // Also opens links with target="_blank" in a browser window mainWindow.webContents.on('new-window', (event, url) => { /* eng-disable LIMIT_NAVIGATION_JS_CHECK */ - if (!url.startsWith('serve://boundary')) event.preventDefault(); + if (!url.startsWith('serve://boundary')) { + event.preventDefault(); + shell.openExternal(url); + } }); mainWindow.on('unresponsive', () => { diff --git a/ui/desktop/package.json b/ui/desktop/package.json index c22ee5143..607e577b1 100755 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -49,7 +49,6 @@ }, "devDependencies": { "@doyensec/electronegativity": "^1.8.1", - "@ember/jquery": "^1.1.0", "@ember/optional-features": "^2.0.0", "@ember/render-modifiers": "^1.0.2", "@ember/test-helpers": "^2.2.8", diff --git a/yarn.lock b/yarn.lock index eeeb32795..99bc92f8e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1753,18 +1753,6 @@ resolved "https://registry.yarnpkg.com/@ember/edition-utils/-/edition-utils-1.2.0.tgz#a039f542dc14c8e8299c81cd5abba95e2459cfa6" integrity sha512-VmVq/8saCaPdesQmftPqbFtxJWrzxNGSQ+e8x8LLe3Hjm36pJ04Q8LeORGZkAeOhldoUX9seLGmSaHeXkIqoog== -"@ember/jquery@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@ember/jquery/-/jquery-1.1.0.tgz#33d062610a5ceaa5c5c8a3187f870d47d6595940" - integrity sha512-zePT3LiK4/2bS4xafrbOlwoLJrDFseOZ95OOuVDyswv8RjFL+9lar+uxX6+jxRb0w900BcQSWP/4nuFSK6HXXw== - dependencies: - broccoli-funnel "^2.0.2" - broccoli-merge-trees "^3.0.2" - ember-cli-babel "^7.11.1" - ember-cli-version-checker "^3.1.3" - jquery "^3.4.1" - resolve "^1.11.1" - "@ember/optional-features@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@ember/optional-features/-/optional-features-2.0.0.tgz#c809abd5a27d5b0ef3c6de3941334ab6153313f0" @@ -13497,7 +13485,7 @@ joi@^12.0.0: isemail "3.x.x" topo "2.x.x" -jquery@^3.4.1, jquery@^3.5.0: +jquery@^3.5.0: version "3.6.0" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470" integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw== From dbfc21ace3da3cb63d1d44906452624084c7ebea Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Fri, 23 Jul 2021 15:00:07 -0700 Subject: [PATCH 37/68] =?UTF-8?q?chore:=20=F0=9F=A4=96=20Update=20ember-cl?= =?UTF-8?q?i-app-version=20dependency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/admin/package.json | 2 +- ui/desktop/package.json | 2 +- yarn.lock | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/admin/package.json b/ui/admin/package.json index 666ddc101..6c2390fe6 100644 --- a/ui/admin/package.json +++ b/ui/admin/package.json @@ -51,7 +51,7 @@ "ember-auto-import": "^1.10.1", "ember-breadcrumbs": "^0.2.3", "ember-cli": "~3.27.0", - "ember-cli-app-version": "^4.0.0", + "ember-cli-app-version": "^5.0.0", "ember-cli-babel": "^7.23.0", "ember-cli-code-coverage": "^1.0.2", "ember-cli-content-security-policy": "^1.1.1", diff --git a/ui/desktop/package.json b/ui/desktop/package.json index dd0279831..6ed9cd93e 100755 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -67,7 +67,7 @@ "ember-auto-import": "^1.10.1", "ember-autofocus-modifier": "^1.1.0", "ember-cli": "~3.27.0", - "ember-cli-app-version": "^4.0.0", + "ember-cli-app-version": "^5.0.0", "ember-cli-babel": "^7.23.0", "ember-cli-code-coverage": "^1.0.2", "ember-cli-dependency-checker": "^3.2.0", diff --git a/yarn.lock b/yarn.lock index 15234911f..1f136f3b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8574,12 +8574,12 @@ ember-cli-addon-docs-yuidoc@^0.2.3: lodash "^4.17.5" yuidocjs "^0.10.2" -ember-cli-app-version@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-4.0.0.tgz#033057ec5fe4d3ecdf5ac5380d442e2dc9f7526a" - integrity sha512-YRH1r4vjA9ZIgTVJ38zWxhtt4SCzIHb0ppEsO/z+JV0ZTQlS3+2dT5RhJWz7O3dyw5FWnlIng+gPRoQEz1umHA== +ember-cli-app-version@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-5.0.0.tgz#adad17c6f706f419b223707eec66dd1cd28530c3" + integrity sha512-afhx/CXDOMNXzoe4NDPy5WUfxWmYYHUzMCiTyvPBxCDBXYcMrtxNWxvgaSaeqcoHVEmqzeyBj8V82tzmT1dcyw== dependencies: - ember-cli-babel "^7.22.1" + ember-cli-babel "^7.23.1" git-repo-info "^2.1.1" ember-cli-babel-plugin-helpers@^1.0.0, ember-cli-babel-plugin-helpers@^1.1.0, ember-cli-babel-plugin-helpers@^1.1.1: From 7fd89bb946a251f763cc98ff71f56257fdfc7ee9 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Fri, 23 Jul 2021 15:15:24 -0700 Subject: [PATCH 38/68] =?UTF-8?q?chore:=20=F0=9F=A4=96=20Update=20ember-fe?= =?UTF-8?q?tch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/addons/api/package.json b/addons/api/package.json index 2dfeaf358..d45cb03aa 100644 --- a/addons/api/package.json +++ b/addons/api/package.json @@ -29,7 +29,7 @@ "ember-cli-mirage": "^1.1.8", "ember-data": "^3.20.0", "ember-data-model-fragments": "5.0.0-beta.2", - "ember-fetch": "^8.0.1" + "ember-fetch": "^8.1.0" }, "devDependencies": { "@ember/optional-features": "^2.0.0", diff --git a/yarn.lock b/yarn.lock index 15234911f..dc51f4422 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9248,10 +9248,10 @@ ember-feature-flags@^6.0.0: dependencies: ember-cli-babel "^7.11.1" -ember-fetch@^8.0.1: - version "8.0.5" - resolved "https://registry.yarnpkg.com/ember-fetch/-/ember-fetch-8.0.5.tgz#0ed6257b3158473f662e72831cab223010c5ec50" - integrity sha512-tKwSWZ2l4jKynqUuF8qgwiCfzmnRWDDO2j5l0Lrn4TgZo8YXbdM3DfgheLSZd+aybBFEAtXBgKH0qaTox28LFg== +ember-fetch@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/ember-fetch/-/ember-fetch-8.1.0.tgz#6228f49baaf6f435af1e5c767e19ef638ff28883" + integrity sha512-797IPPuXrWGAecsAuCPH6+2pJCcawy7+CiRrtoe1qLhXJ6Ue0Lxu4loXxHHQNCxRvvUvx8tTDuP63sOKfi3xug== dependencies: abortcontroller-polyfill "^1.7.1" broccoli-concat "^4.2.5" From a7a84d64b96d9545701566148bab62f5e866fd78 Mon Sep 17 00:00:00 2001 From: dharini Date: Fri, 23 Jul 2021 15:33:29 -0700 Subject: [PATCH 39/68] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20delete=20cre?= =?UTF-8?q?d=20library=20action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/core/translations/resources/en-us.yaml | 1 + .../credential-store/credential-libraries.js | 21 ++++++++++++++++++- .../credential-library/-actions.hbs | 13 ++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 8094abf9e..16d2cde4f 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -279,6 +279,7 @@ credential-library: description: A credential library is a resource that provides credentials. actions: create: New Credential Library + delete: Delete Credential Library messages: none: title: No Credential Libraries Available diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js index fa54e9691..0a0435003 100644 --- a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js @@ -1,6 +1,7 @@ import Route from '@ember/routing/route'; import { action } from '@ember/object'; import loading from 'ember-loading/decorator'; +import { confirm } from 'core/decorators/confirm'; import { notifySuccess, notifyError } from 'core/decorators/notify'; export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrariesRoute extends Route { @@ -50,4 +51,22 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari ); this.refresh(); } -} + + /** + * Handle delete of a credential library + * @param {CredentialLibraryModel} credentialLibrary + */ + @action + @loading + @confirm('questions.delete-confirm') + @notifyError(({ message }) => message) + @notifyError(({ message }) => message, { catch: true }) + async delete(credentialLibrary) { + await credentialLibrary.destroyRecord(); + await this.replaceWith( + 'scopes.scope.credential-stores.credential-store.credential-libraries' + ); + this.refresh(); + } + } + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-actions.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-actions.hbs index e69de29bb..759b187d5 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-actions.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-actions.hbs @@ -0,0 +1,13 @@ + + + {{t 'resources.credential-library.actions.delete'}} + + \ No newline at end of file From ad3b9ed6849fd96e8f2bdf24ef05416e72e4534e Mon Sep 17 00:00:00 2001 From: dharini Date: Fri, 23 Jul 2021 15:41:14 -0700 Subject: [PATCH 40/68] add success message --- .../credential-store/credential-libraries.js | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js index 0a0435003..d9602dba4 100644 --- a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js @@ -56,17 +56,16 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari * Handle delete of a credential library * @param {CredentialLibraryModel} credentialLibrary */ - @action - @loading - @confirm('questions.delete-confirm') - @notifyError(({ message }) => message) - @notifyError(({ message }) => message, { catch: true }) - async delete(credentialLibrary) { - await credentialLibrary.destroyRecord(); - await this.replaceWith( - 'scopes.scope.credential-stores.credential-store.credential-libraries' - ); - this.refresh(); - } - } - \ No newline at end of file + @action + @loading + @confirm('questions.delete-confirm') + @notifyError(({ message }) => message, { catch: true }) + @notifySuccess('notifications.delete-success') + async delete(credentialLibrary) { + await credentialLibrary.destroyRecord(); + await this.replaceWith( + 'scopes.scope.credential-stores.credential-store.credential-libraries' + ); + this.refresh(); + } +} From 89b7d0345aa61c2514480cd14a07dd2e9367f869 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Sun, 25 Jul 2021 09:26:03 -0400 Subject: [PATCH 41/68] fix: Add feature flag to target credential libraries list --- .../templates/scopes/scope/targets/target/-navigation.hbs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs b/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs index be112a45a..c337646f9 100644 --- a/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs +++ b/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs @@ -5,7 +5,9 @@ {{t 'resources.host-set.title_plural'}} - - {{t 'resources.credential-library.title_plural'}} - + {{#if (feature-flag 'credential-store')}} + + {{t 'resources.credential-library.title_plural'}} + + {{/if}} \ No newline at end of file From 8f2deadc4960c6cbc50b0d24fd9383f3f327f40c Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Sun, 25 Jul 2021 10:11:11 -0400 Subject: [PATCH 42/68] feat: Add credential libraries association form in target --- addons/core/translations/resources/en-us.yaml | 4 + .../target/add-credential-libraries/index.hbs | 36 +++++++ .../target/add-credential-libraries/index.js | 55 +++++++++++ ui/admin/app/router.js | 1 + .../target/add-credential-libraries.js | 94 +++++++++++++++++++ .../scopes/scope/targets/target/-actions.hbs | 7 ++ .../target/add-credential-libraries.hbs | 10 ++ .../add-credential-libraries/-header.hbs | 4 + .../add-credential-libraries/index-test.js | 29 ++++++ .../target/add-credential-libraries-test.js | 16 ++++ 10 files changed, 256 insertions(+) create mode 100644 ui/admin/app/components/form/target/add-credential-libraries/index.hbs create mode 100644 ui/admin/app/components/form/target/add-credential-libraries/index.js create mode 100644 ui/admin/app/routes/scopes/scope/targets/target/add-credential-libraries.js create mode 100644 ui/admin/app/templates/scopes/scope/targets/target/add-credential-libraries.hbs create mode 100644 ui/admin/app/templates/scopes/scope/targets/target/add-credential-libraries/-header.hbs create mode 100644 ui/admin/tests/integration/components/form/target/add-credential-libraries/index-test.js create mode 100644 ui/admin/tests/unit/routes/scopes/scope/targets/target/add-credential-libraries-test.js diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 259824292..91e85111e 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -254,6 +254,7 @@ target: create: New Target delete: Delete Target add-host-sets: Add Host Sets + add-credential-libraries: Add Credential Libraries types: tcp: TCP host-set: @@ -272,6 +273,9 @@ target: welcome: title: Welcome to Credential Libraries description: No credential libraries in this target. + add: + title: Add Credential Libraries + description: Select credential libraries to assign to this target. credential-store: title: Credential Store title_plural: Credential Stores diff --git a/ui/admin/app/components/form/target/add-credential-libraries/index.hbs b/ui/admin/app/components/form/target/add-credential-libraries/index.hbs new file mode 100644 index 000000000..1c76a5bdb --- /dev/null +++ b/ui/admin/app/components/form/target/add-credential-libraries/index.hbs @@ -0,0 +1,36 @@ + + + + + + + {{t 'form.id.label'}} + {{t 'form.name.label'}} + + + + {{#each this.filteredCredentialLibraries as |credentialLibrary|}} + + + + + {{credentialLibrary.name}} + + {{/each}} + + + \ No newline at end of file diff --git a/ui/admin/app/components/form/target/add-credential-libraries/index.js b/ui/admin/app/components/form/target/add-credential-libraries/index.js new file mode 100644 index 000000000..b8177dab0 --- /dev/null +++ b/ui/admin/app/components/form/target/add-credential-libraries/index.js @@ -0,0 +1,55 @@ +import Component from '@glimmer/component'; +import { computed, action } from '@ember/object'; +import { A } from '@ember/array'; + +export default class FormTargetAddCredentialLibrariesIndexComponent extends Component { + // =properties + + /** + * Array of selected credential library IDs. + * @type {EmberArray} + */ + selectedCredentialLibraryIDs = A(); + + /** + * Filter out credential libraries not already added to the target. + * @type {[CredentialLibraryModel]} + */ + @computed( + 'args.{credentialLibraries.[],model.application_credential_library_ids.[]}' + ) + get filteredCredentialLibraries() { + // Get IDs for credential libraries already added to the current target + const currentCredentialLibraryIDs = + this.args.model.application_credential_library_ids.map( + (credentialLibrary) => credentialLibrary.value + ); + const notAddedCredentialLibraries = this.args.credentialLibraries.filter( + ({ id }) => !currentCredentialLibraryIDs.includes(id) + ); + return notAddedCredentialLibraries; + } + + // =actions + + /** + * Add/Remove credential library to current selection + * @param CredentialLibraryModel + */ + @action + toggleCredentialLibrary(credentialLibrary) { + if (!this.selectedCredentialLibraryIDs.includes(credentialLibrary.id)) { + this.selectedCredentialLibraryIDs.addObject(credentialLibrary.id); + } else { + this.selectedCredentialLibraryIDs.removeObject(credentialLibrary.id); + } + } + + /** + * Submit selected credential library ids + */ + @action + submit(fn) { + fn(this.selectedCredentialLibraryIDs); + } +} diff --git a/ui/admin/app/router.js b/ui/admin/app/router.js index 8638e4e48..6b70bd999 100644 --- a/ui/admin/app/router.js +++ b/ui/admin/app/router.js @@ -66,6 +66,7 @@ Router.map(function () { this.route('host-sets', function () {}); this.route('add-host-sets'); this.route('credential-libraries'); + this.route('add-credential-libraries'); }); this.route('new'); }); diff --git a/ui/admin/app/routes/scopes/scope/targets/target/add-credential-libraries.js b/ui/admin/app/routes/scopes/scope/targets/target/add-credential-libraries.js new file mode 100644 index 000000000..f2cb1eca2 --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/targets/target/add-credential-libraries.js @@ -0,0 +1,94 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; +import { all } from 'rsvp'; +import { action } from '@ember/object'; +import loading from 'ember-loading/decorator'; +import { notifySuccess, notifyError } from 'core/decorators/notify'; + +export default class ScopesScopeTargetsTargetAddCredentialLibrariesRoute extends Route { + // =services + + @service intl; + @service notify; + + // =methods + + /** + * Empty out any previously loaded credential libraries. + */ + beforeModel() { + this.store.unloadAll('credential-library'); + } + + /** + * Returns the current target and all credential libraries. + * @return {{target: TargetModel, credentialLibraries: [CredentialLibraryModel]}} + */ + async model() { + const target = this.modelFor('scopes.scope.targets.target'); + const { id: scope_id } = this.modelFor('scopes.scope'); + const credentialStores = await this.store.query('credential-store', { + scope_id, + }); + await all( + credentialStores.map(({ id: credential_store_id }) => + this.store.query('credential-library', { credential_store_id }) + ) + ); + const credentialLibraries = this.store.peekAll('credential-library'); + return { + target, + credentialLibraries, + }; + } + + /** + * Renders credential libraries specific header template. + * @override + */ + renderTemplate() { + super.renderTemplate(...arguments); + + this.render( + 'scopes/scope/targets/target/add-credential-libraries/-header', + { + into: 'scopes/scope/targets/target', + outlet: 'header', + } + ); + + this.render('-empty', { + into: 'scopes/scope/targets/target', + outlet: 'navigation', + }); + + this.render('-empty', { + into: 'scopes/scope/targets/target', + outlet: 'actions', + }); + } + + // =actions + + /** + * Add credential libraries to current target + * @param {TargetModel} target + * @param {[string]} credentialLibraryIDs + */ + @action + @loading + @notifyError(({ message }) => message, { catch: true }) + @notifySuccess('notifications.add-success') + async save(target, credentialLibraryIDs) { + await target.addCredentialLibraries(credentialLibraryIDs); + this.replaceWith('scopes.scope.targets.target.credential-libraries'); + } + + /** + * Redirect to target credential libraries as if nothing ever happened. + */ + @action + cancel() { + this.replaceWith('scopes.scope.targets.target.credential-libraries'); + } +} diff --git a/ui/admin/app/templates/scopes/scope/targets/target/-actions.hbs b/ui/admin/app/templates/scopes/scope/targets/target/-actions.hbs index 9b6b207e3..9c95b8fa2 100644 --- a/ui/admin/app/templates/scopes/scope/targets/target/-actions.hbs +++ b/ui/admin/app/templates/scopes/scope/targets/target/-actions.hbs @@ -6,6 +6,13 @@ {{t 'resources.target.actions.add-host-sets'}} + {{#if (feature-flag 'credential-store')}} + + {{t 'resources.target.actions.add-credential-libraries'}} + + {{/if}} +{{/if}} \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/targets/target/add-credential-libraries/-header.hbs b/ui/admin/app/templates/scopes/scope/targets/target/add-credential-libraries/-header.hbs new file mode 100644 index 000000000..4ae5bad96 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/targets/target/add-credential-libraries/-header.hbs @@ -0,0 +1,4 @@ +

+ {{t 'resources.target.credential-library.messages.add.title'}} +

+

{{t 'resources.target.credential-library.messages.add.description'}}

\ No newline at end of file diff --git a/ui/admin/tests/integration/components/form/target/add-credential-libraries/index-test.js b/ui/admin/tests/integration/components/form/target/add-credential-libraries/index-test.js new file mode 100644 index 000000000..867478cc8 --- /dev/null +++ b/ui/admin/tests/integration/components/form/target/add-credential-libraries/index-test.js @@ -0,0 +1,29 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module( + 'Integration | Component | form/target/add-credential-libraries/index', + function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + + await render(hbs``); + + assert.equal(this.element.textContent.trim(), ''); + + // Template block usage: + await render(hbs` + + template block text + + `); + + assert.equal(this.element.textContent.trim(), 'template block text'); + }); + } +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/targets/target/add-credential-libraries-test.js b/ui/admin/tests/unit/routes/scopes/scope/targets/target/add-credential-libraries-test.js new file mode 100644 index 000000000..e6279d5b3 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/targets/target/add-credential-libraries-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Route | scopes/scope/targets/target/add-credential-libraries', + function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup( + 'route:scopes/scope/targets/target/add-credential-libraries' + ); + assert.ok(route); + }); + } +); From 0fbcf8e16ec63091e019229310efb6758bd9e46e Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Sun, 25 Jul 2021 10:25:09 -0400 Subject: [PATCH 43/68] feat: Show message when no cred-libs are available in target --- addons/core/translations/resources/en-us.yaml | 3 + .../target/add-credential-libraries/index.hbs | 89 +++++++++++-------- .../target/add-credential-libraries/index.js | 10 +++ .../add-credential-libraries/index-test.js | 29 ------ 4 files changed, 67 insertions(+), 64 deletions(-) delete mode 100644 ui/admin/tests/integration/components/form/target/add-credential-libraries/index-test.js diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 91e85111e..551479737 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -273,6 +273,9 @@ target: welcome: title: Welcome to Credential Libraries description: No credential libraries in this target. + none: + title: No Credential Libraries Available + description: No credential libraries available to add to this target. add: title: Add Credential Libraries description: Select credential libraries to assign to this target. diff --git a/ui/admin/app/components/form/target/add-credential-libraries/index.hbs b/ui/admin/app/components/form/target/add-credential-libraries/index.hbs index 1c76a5bdb..eb51f5129 100644 --- a/ui/admin/app/components/form/target/add-credential-libraries/index.hbs +++ b/ui/admin/app/components/form/target/add-credential-libraries/index.hbs @@ -1,36 +1,55 @@ - - +{{#if this.hasAvailableCredentialLibraries}} + + - - - - {{t 'form.id.label'}} - {{t 'form.name.label'}} - - - - {{#each this.filteredCredentialLibraries as |credentialLibrary|}} - - - - - {{credentialLibrary.name}} - - {{/each}} - - - \ No newline at end of file + + + + {{t 'form.id.label'}} + {{t 'form.name.label'}} + + + + {{#each this.filteredCredentialLibraries as |credentialLibrary|}} + + + + + {{credentialLibrary.name}} + + {{/each}} + + + +{{/if}} + +{{#unless this.hasAvailableCredentialLibraries}} + + + + {{t 'resources.target.credential-library.messages.none.description'}} + + + + {{t 'actions.back'}} + + + +{{/unless}} \ No newline at end of file diff --git a/ui/admin/app/components/form/target/add-credential-libraries/index.js b/ui/admin/app/components/form/target/add-credential-libraries/index.js index b8177dab0..21ce6250a 100644 --- a/ui/admin/app/components/form/target/add-credential-libraries/index.js +++ b/ui/admin/app/components/form/target/add-credential-libraries/index.js @@ -11,6 +11,16 @@ export default class FormTargetAddCredentialLibrariesIndexComponent extends Comp */ selectedCredentialLibraryIDs = A(); + /** + * Checks for unassigned credential libraries. + * @param {[CredentialLibraryModel]} filteredCredentialLibraries + * @type {boolean} + */ + @computed('filteredCredentialLibraries.length') + get hasAvailableCredentialLibraries() { + return this.filteredCredentialLibraries.length > 0; + } + /** * Filter out credential libraries not already added to the target. * @type {[CredentialLibraryModel]} diff --git a/ui/admin/tests/integration/components/form/target/add-credential-libraries/index-test.js b/ui/admin/tests/integration/components/form/target/add-credential-libraries/index-test.js deleted file mode 100644 index 867478cc8..000000000 --- a/ui/admin/tests/integration/components/form/target/add-credential-libraries/index-test.js +++ /dev/null @@ -1,29 +0,0 @@ -import { module, test } from 'qunit'; -import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; -import { hbs } from 'ember-cli-htmlbars'; - -module( - 'Integration | Component | form/target/add-credential-libraries/index', - function (hooks) { - setupRenderingTest(hooks); - - test('it renders', async function (assert) { - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.set('myAction', function(val) { ... }); - - await render(hbs``); - - assert.equal(this.element.textContent.trim(), ''); - - // Template block usage: - await render(hbs` - - template block text - - `); - - assert.equal(this.element.textContent.trim(), 'template block text'); - }); - } -); From 63d302d7166a1e66536d9ccc6f94068b81e4c9c0 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 26 Jul 2021 14:41:21 -0400 Subject: [PATCH 44/68] style: Update credentials store icon --- addons/core/public/app-icons/credentials.svg | 12 ++++-------- ui/admin/app/templates/scopes/scope.hbs | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/addons/core/public/app-icons/credentials.svg b/addons/core/public/app-icons/credentials.svg index 72c15d48a..30c8e75eb 100644 --- a/addons/core/public/app-icons/credentials.svg +++ b/addons/core/public/app-icons/credentials.svg @@ -1,9 +1,5 @@ - - - - - - - - + + + + diff --git a/ui/admin/app/templates/scopes/scope.hbs b/ui/admin/app/templates/scopes/scope.hbs index b0040f3e7..65e456c51 100644 --- a/ui/admin/app/templates/scopes/scope.hbs +++ b/ui/admin/app/templates/scopes/scope.hbs @@ -85,7 +85,7 @@ {{#if (feature-flag 'credential-store')}} - + {{t 'resources.credential-store.title_plural'}} {{/if}} From 1d71e3bec8120d66e9b34f7409e9424a4a799884 Mon Sep 17 00:00:00 2001 From: dharini Date: Mon, 26 Jul 2021 12:37:37 -0700 Subject: [PATCH 45/68] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20delete=20action=20?= =?UTF-8?q?and=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✅ Closes: #1996 --- .../credential-library-test.js | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 ui/admin/tests/acceptance/credential-library/credential-library-test.js diff --git a/ui/admin/tests/acceptance/credential-library/credential-library-test.js b/ui/admin/tests/acceptance/credential-library/credential-library-test.js new file mode 100644 index 000000000..9faf69576 --- /dev/null +++ b/ui/admin/tests/acceptance/credential-library/credential-library-test.js @@ -0,0 +1,96 @@ +import { module, test } from 'qunit'; +import { visit, click } from '@ember/test-helpers'; +import { setupApplicationTest } from 'ember-qunit'; +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; +import { authenticateSession } from 'ember-simple-auth/test-support'; +import { resolve, reject } from 'rsvp'; +import sinon from 'sinon'; + +module('Acceptance | credential-library', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + let getCredentialLibraryCount; + + const instances = { + scopes: { + global: null, + org: null, + project: null, + }, + }; + + const urls = { + globalScope: null, + orgScope: null, + projectScope: null, + credentialStores: null, + credentialStore: null, + credentialLibrary: null, + credentialLibraries: null, + newCredentialLibrary: null, + }; + + hooks.beforeEach(function () { + // Generate resources + instances.scopes.global = this.server.create('scope', { id: 'global' }); + instances.scopes.org = this.server.create('scope', { + type: 'org', + scope: { id: 'global', type: 'global' }, + }); + instances.scopes.project = this.server.create('scope', { + type: 'project', + scope: { id: instances.scopes.org.id, type: 'org' }, + }); + instances.credentialStore = this.server.create('credential-store', { + scope: instances.scopes.project, + }); + instances.credentialLibrary = this.server.create('credential-library', { + scope: instances.scopes.project, + }); + // Generate route URLs for resources + urls.globalScope = `/scopes/global/scopes`; + urls.orgScope = `/scopes/${instances.scopes.org.id}/scopes`; + urls.projectScope = `/scopes/${instances.scopes.project.id}`; + urls.credentialStores = `${urls.projectScope}/credential-stores`; + urls.credentialStore = `${urls.credentialStores}/${instances.credentialStore.id}`; + urls.credentialLibraries = `${urls.credentialStore}/credential-libraries`; + urls.credentialLibrary = `${urls.credentialLibraries}/${instances.credentialLibrary.id}`; + // Generate resource couner + getCredentialLibraryCount = () => + this.server.schema.credentialLibraries.all().models.length; + authenticateSession({}); + }); + + test('can delete credential library', async function (assert) { + assert.expect(1); + const count = getCredentialLibraryCount(); + await visit(urls.credentialLibrary); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.equal(getCredentialLibraryCount(), count - 1); + }); + + test('can accept delete credential library via dialog', async function (assert) { + assert.expect(2); + const confirmService = this.owner.lookup('service:confirm'); + confirmService.enabled = true; + confirmService.confirm = sinon.fake.returns(resolve()); + const count = getCredentialLibraryCount(); + await visit(urls.credentialLibrary); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.equal(getCredentialLibraryCount(), count - 1); + assert.ok(confirmService.confirm.calledOnce); + }); + + test('cannot cancel delete credential library via dialog', async function (assert) { + assert.expect(2); + const confirmService = this.owner.lookup('service:confirm'); + confirmService.enabled = true; + confirmService.confirm = sinon.fake.returns(reject()); + const count = getCredentialLibraryCount(); + await visit(urls.credentialLibrary); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.equal(getCredentialLibraryCount(), count); + assert.ok(confirmService.confirm.calledOnce); + }); +}); From a07cd9e1a13a0a28713afda0d203e9ea0e6957e8 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Mon, 26 Jul 2021 13:09:08 -0700 Subject: [PATCH 46/68] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20Allow=20extern?= =?UTF-8?q?al=20links=20just=20for=20specific=20domain?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow external links just for boundary.io domain. So far the only urls we want to open externally are our own documentation --- ui/desktop/electron-app/src/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/desktop/electron-app/src/index.js b/ui/desktop/electron-app/src/index.js index a08bfba96..8c303a7ee 100644 --- a/ui/desktop/electron-app/src/index.js +++ b/ui/desktop/electron-app/src/index.js @@ -167,10 +167,11 @@ app.on('ready', async () => { /* eng-disable LIMIT_NAVIGATION_JS_CHECK */ if (!url.startsWith('serve://boundary')) event.preventDefault(); }); - // Also opens links with target="_blank" in a browser window + // Opens external links in the host default browser. + // We just allow boundaryproject.io domain to open on external window (for now). mainWindow.webContents.on('new-window', (event, url) => { /* eng-disable LIMIT_NAVIGATION_JS_CHECK */ - if (!url.startsWith('serve://boundary')) { + if (url.startsWith('https://boundaryproject.io/')) { event.preventDefault(); shell.openExternal(url); } From 4a6555317af91f2b2be26d1c5d54514734a42583 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Mon, 26 Jul 2021 15:37:36 -0700 Subject: [PATCH 47/68] =?UTF-8?q?test:=20=F0=9F=92=8D=20Add=20credential?= =?UTF-8?q?=20library=20creation=20acceptance=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add credential library creation acceptance test --- .../credential-library-test.js | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/ui/admin/tests/acceptance/credential-library/credential-library-test.js b/ui/admin/tests/acceptance/credential-library/credential-library-test.js index 9faf69576..ea3568c45 100644 --- a/ui/admin/tests/acceptance/credential-library/credential-library-test.js +++ b/ui/admin/tests/acceptance/credential-library/credential-library-test.js @@ -1,8 +1,9 @@ import { module, test } from 'qunit'; -import { visit, click } from '@ember/test-helpers'; +import { visit, click, fillIn, currentURL, find } from '@ember/test-helpers'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import { authenticateSession } from 'ember-simple-auth/test-support'; +import { Response } from 'miragejs'; import { resolve, reject } from 'rsvp'; import sinon from 'sinon'; @@ -56,12 +57,65 @@ module('Acceptance | credential-library', function (hooks) { urls.credentialStore = `${urls.credentialStores}/${instances.credentialStore.id}`; urls.credentialLibraries = `${urls.credentialStore}/credential-libraries`; urls.credentialLibrary = `${urls.credentialLibraries}/${instances.credentialLibrary.id}`; + urls.newCredentialLibrary = `${urls.credentialLibraries}/new`; // Generate resource couner getCredentialLibraryCount = () => this.server.schema.credentialLibraries.all().models.length; authenticateSession({}); }); + test('can create a credential library', async function (assert) { + assert.expect(1); + const count = getCredentialLibraryCount(); + await visit(urls.newCredentialLibrary); + await fillIn('[name="name"]', 'random string'); + await click('[type="submit"]'); + assert.equal(getCredentialLibraryCount(), count + 1); + }); + + test('can cancel create a new credential library', async function (assert) { + assert.expect(2); + const count = getCredentialLibraryCount(); + await visit(urls.newCredentialLibrary); + await fillIn('[name="name"]', 'random string'); + await click('.rose-form-actions [type="button"]'); + assert.equal(currentURL(), urls.credentialLibraries); + assert.equal(getCredentialLibraryCount(), count); + }); + + test('saving a new credential library with invalid fields displays error messasges', async function (assert) { + assert.expect(2); + this.server.post('/credential-libraries', () => { + return new Response( + 400, + {}, + { + status: 400, + code: 'invalid_argument', + message: 'The request was invalid', + details: { + request_fields: [ + { + name: 'name', + description: 'Name is required.', + }, + ], + }, + } + ); + }); + await visit(urls.newCredentialLibrary); + await click('[type="submit"]'); + assert.ok( + find('[role="alert"]').textContent.trim(), + 'The request was invalid.' + ); + assert.ok( + find('.rose-form-error-message').textContent.trim(), + 'Name is required.' + ); + }); + test('can delete credential library', async function (assert) { assert.expect(1); const count = getCredentialLibraryCount(); From 0bc4cd6e21db5610ff2a33e0ab30e79c531f4250 Mon Sep 17 00:00:00 2001 From: dharini Date: Mon, 26 Jul 2021 16:43:28 -0700 Subject: [PATCH 48/68] =?UTF-8?q?test:=20=F0=9F=92=8D=20add=20cred=20list?= =?UTF-8?q?=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../credential-library-test.js | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/ui/admin/tests/acceptance/credential-library/credential-library-test.js b/ui/admin/tests/acceptance/credential-library/credential-library-test.js index 9faf69576..56cbbdac1 100644 --- a/ui/admin/tests/acceptance/credential-library/credential-library-test.js +++ b/ui/admin/tests/acceptance/credential-library/credential-library-test.js @@ -1,7 +1,8 @@ import { module, test } from 'qunit'; -import { visit, click } from '@ember/test-helpers'; +import { visit, currentURL, find, click } from '@ember/test-helpers'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; +import a11yAudit from 'ember-a11y-testing/test-support/audit'; import { authenticateSession } from 'ember-simple-auth/test-support'; import { resolve, reject } from 'rsvp'; import sinon from 'sinon'; @@ -29,6 +30,7 @@ module('Acceptance | credential-library', function (hooks) { credentialLibrary: null, credentialLibraries: null, newCredentialLibrary: null, + unknownCredentialLibrary: null, }; hooks.beforeEach(function () { @@ -56,12 +58,31 @@ module('Acceptance | credential-library', function (hooks) { urls.credentialStore = `${urls.credentialStores}/${instances.credentialStore.id}`; urls.credentialLibraries = `${urls.credentialStore}/credential-libraries`; urls.credentialLibrary = `${urls.credentialLibraries}/${instances.credentialLibrary.id}`; + urls.unknownCredentialLibrary = `${urls.credentialLibraries}/foo`; // Generate resource couner getCredentialLibraryCount = () => this.server.schema.credentialLibraries.all().models.length; authenticateSession({}); }); + test('visiting credential-libraries', async function (assert) { + assert.expect(2); + await visit(urls.credentialLibraries); + await a11yAudit(); + assert.equal(currentURL(), urls.credentialLibraries); + await visit(urls.credentialLibrary); + await a11yAudit(); + assert.equal(currentURL(), urls.credentialLibrary); + }); + + test('visiting an unknown credentila library displays 404 message', async function (assert) { + assert.expect(1); + await visit(urls.unknownCredentialLibrary); + await a11yAudit(); + console.debug(find('.rose-message-subtitle')); + assert.ok(find('.rose-message-subtitle').textContent.trim(), 'Error 404'); + }); + test('can delete credential library', async function (assert) { assert.expect(1); const count = getCredentialLibraryCount(); From 025ae1bfe2e5887c78d2c7052353e27d370247d1 Mon Sep 17 00:00:00 2001 From: dharini Date: Mon, 26 Jul 2021 16:58:23 -0700 Subject: [PATCH 49/68] =?UTF-8?q?test:=20=F0=9F=92=8D=20Credential=20libra?= =?UTF-8?q?ry=20deletion=20error=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../credential-library-test.js | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ui/admin/tests/acceptance/credential-library/credential-library-test.js b/ui/admin/tests/acceptance/credential-library/credential-library-test.js index 9faf69576..dfab8c002 100644 --- a/ui/admin/tests/acceptance/credential-library/credential-library-test.js +++ b/ui/admin/tests/acceptance/credential-library/credential-library-test.js @@ -1,5 +1,5 @@ import { module, test } from 'qunit'; -import { visit, click } from '@ember/test-helpers'; +import { visit, click, find } from '@ember/test-helpers'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import { authenticateSession } from 'ember-simple-auth/test-support'; @@ -93,4 +93,22 @@ module('Acceptance | credential-library', function (hooks) { assert.equal(getCredentialLibraryCount(), count); assert.ok(confirmService.confirm.calledOnce); }); + + test('deleting a credential library which errors displays error messages', async function (assert) { + assert.expect(1); + this.server.del('/credential-libraries/:id', () => { + return new Response( + 490, + {}, + { + status: 490, + code: 'error', + message: 'Oops.', + } + ); + }); + await visit(urls.credentialLibrary); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.ok(find('[role="alert"]').textContent.trim(), 'Oops.'); + }); }); From e42647e6a2efd0671d5b37b276a03fb7160139d1 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 27 Jul 2021 10:03:56 -0400 Subject: [PATCH 50/68] fix: Add missing empty credential libraries message --- .../target/add-credential-libraries.hbs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/ui/admin/app/templates/scopes/scope/targets/target/add-credential-libraries.hbs b/ui/admin/app/templates/scopes/scope/targets/target/add-credential-libraries.hbs index 00d905ef8..e4573894c 100644 --- a/ui/admin/app/templates/scopes/scope/targets/target/add-credential-libraries.hbs +++ b/ui/admin/app/templates/scopes/scope/targets/target/add-credential-libraries.hbs @@ -7,4 +7,21 @@ @submit={{route-action 'save' @model.target}} @cancel={{route-action 'cancel'}} /> -{{/if}} \ No newline at end of file +{{/if}} + +{{#unless @model.credentialLibraries}} + + + + {{t 'resources.target.credential-library.messages.none.description'}} + + + + {{t 'actions.back'}} + + + +{{/unless}} \ No newline at end of file From 9d342cf517f8f5fb430b2100dfa35447a3e02ad3 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 27 Jul 2021 11:22:06 -0400 Subject: [PATCH 51/68] feat: Remove a credential library associated to a target --- .../targets/target/credential-libraries.js | 41 +++++--- .../targets/target/credential-libraries.hbs | 23 +++++ .../credential-library-test.js | 2 +- .../targets/credential-libraries-test.js | 98 +++++++++++++++++++ 4 files changed, 151 insertions(+), 13 deletions(-) create mode 100644 ui/admin/tests/acceptance/targets/credential-libraries-test.js diff --git a/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js b/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js index 17e3e2692..66ce6f8ec 100644 --- a/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js +++ b/ui/admin/app/routes/scopes/scope/targets/target/credential-libraries.js @@ -1,5 +1,9 @@ import Route from '@ember/routing/route'; -import { hash, all } from 'rsvp'; +import { all } from 'rsvp'; +import { action } from '@ember/object'; +import loading from 'ember-loading/decorator'; +import { confirm } from 'core/decorators/confirm'; +import { notifySuccess, notifyError } from 'core/decorators/notify'; export default class ScopesScopeTargetsTargetCredentialLibrariesRoute extends Route { // =methods @@ -11,17 +15,13 @@ export default class ScopesScopeTargetsTargetCredentialLibrariesRoute extends Ro beforeModel() { const { application_credential_library_ids: credential_libraries } = this.modelFor('scopes.scope.targets.target'); - return hash({ - credentialLibraries: all( - credential_libraries.map((credential_library) => - this.store.findRecord( - 'credential-library', - credential_library.value, - { reload: true } - ) - ) - ), - }); + return all( + credential_libraries.map((credential_library) => + this.store.findRecord('credential-library', credential_library.value, { + reload: true, + }) + ) + ); } /** @@ -31,4 +31,21 @@ export default class ScopesScopeTargetsTargetCredentialLibrariesRoute extends Ro model() { return this.modelFor('scopes.scope.targets.target'); } + + // =actions + + /** + * Remove a credential library from the current target. + * @param {TargetModel} target + * @param {CredentialLibraryModel} credentialLibrary + */ + @action + @loading + @confirm('questions.remove-confirm') + @notifyError(({ message }) => message, { catch: true }) + @notifySuccess('notifications.remove-success') + async removeCredentialLibrary(target, credentialLibrary) { + await target.removeCredentialLibrary(credentialLibrary.id); + this.refresh(); + } } diff --git a/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs b/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs index ebba89bff..9e7a24657 100644 --- a/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs +++ b/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs @@ -7,6 +7,7 @@ {{t 'form.name.label'}} {{t 'form.id.label'}} + {{t 'titles.actions'}} @@ -33,6 +34,28 @@ {{credentialLibrary.id}} + + + + {{t 'actions.remove'}} + + + {{/each}} diff --git a/ui/admin/tests/acceptance/credential-library/credential-library-test.js b/ui/admin/tests/acceptance/credential-library/credential-library-test.js index ea3568c45..0ca994ee1 100644 --- a/ui/admin/tests/acceptance/credential-library/credential-library-test.js +++ b/ui/admin/tests/acceptance/credential-library/credential-library-test.js @@ -58,7 +58,7 @@ module('Acceptance | credential-library', function (hooks) { urls.credentialLibraries = `${urls.credentialStore}/credential-libraries`; urls.credentialLibrary = `${urls.credentialLibraries}/${instances.credentialLibrary.id}`; urls.newCredentialLibrary = `${urls.credentialLibraries}/new`; - // Generate resource couner + // Generate resource counter getCredentialLibraryCount = () => this.server.schema.credentialLibraries.all().models.length; authenticateSession({}); diff --git a/ui/admin/tests/acceptance/targets/credential-libraries-test.js b/ui/admin/tests/acceptance/targets/credential-libraries-test.js new file mode 100644 index 000000000..b8e2d5233 --- /dev/null +++ b/ui/admin/tests/acceptance/targets/credential-libraries-test.js @@ -0,0 +1,98 @@ +import { module, test } from 'qunit'; +import { visit, find, findAll, click } from '@ember/test-helpers'; +import { setupApplicationTest } from 'ember-qunit'; +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; +import { Response } from 'miragejs'; +import { + authenticateSession, + // These are left here intentionally for future reference. + //currentSession, + //invalidateSession, +} from 'ember-simple-auth/test-support'; + +module('Acceptance | targets | credential-libraries', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + let getCredentialLibraryCount; + + const instances = { + scopes: { + global: null, + org: null, + project: null, + }, + credentialLibraries: null, + }; + const urls = { + globalScope: null, + orgScope: null, + projectScope: null, + targets: null, + target: null, + targetCredentialLibraries: null, + }; + + hooks.beforeEach(function () { + // Generate resources + instances.scopes.global = this.server.create('scope', { id: 'global' }); + instances.scopes.org = this.server.create('scope', { + type: 'org', + scope: { id: 'global', type: 'global' }, + }); + instances.scopes.project = this.server.create('scope', { + type: 'project', + scope: { id: instances.scopes.org.id, type: 'org' }, + }); + instances.credentialLibraries = this.server.createList( + 'credential-library', + 2, + { scope: instances.scopes.project } + ); + instances.target = this.server.create('target', { + scope: instances.scopes.project, + credentialLibraries: instances.credentialLibraries, + }); + // Generate route URLs for resources + urls.globalScope = `/scopes/global/scopes`; + urls.orgScope = `/scopes/${instances.scopes.org.id}/scopes`; + urls.projectScope = `/scopes/${instances.scopes.project.id}`; + urls.targets = `/scopes/${instances.scopes.project.id}/targets`; + urls.target = `${urls.targets}/${instances.target.id}`; + urls.targetCredentialLibraries = `${urls.target}/credential-libraries`; + // Generate resource counter + getCredentialLibraryCount = () => + this.server.schema.credentialLibraries.all().models.length; + authenticateSession({}); + }); + + test('can remove a credential library', async function (assert) { + assert.expect(2); + const count = getCredentialLibraryCount(); + await visit(urls.targetCredentialLibraries); + assert.equal(findAll('tbody tr').length, count); + await click('tbody tr .rose-dropdown-button-danger'); + assert.equal(findAll('tbody tr').length, count - 1); + }); + + test('removing a target credential library which errors displays error messages', async function (assert) { + assert.expect(2); + this.server.post('/targets/:idMethod', () => { + return new Response( + 400, + {}, + { + status: 400, + code: 'invalid_argument', + message: 'The request was invalid.', + details: {}, + } + ); + }); + const count = getCredentialLibraryCount(); + await visit(urls.targetCredentialLibraries); + assert.equal(findAll('tbody tr').length, count); + await click('tbody tr .rose-dropdown-button-danger'); + assert.ok(find('[role="alert"]')); + }); +}); From 0cb90353f00ae8a4cc5839e4844fd9ac56578a26 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 27 Jul 2021 11:52:02 -0400 Subject: [PATCH 52/68] fix: Add type field to credential library --- .../addon/generated/models/credential-library.js | 5 +++++ .../api/mirage/factories/credential-library.js | 16 +++++++++++----- .../unit/serializers/credential-library-test.js | 4 ++++ addons/core/translations/resources/en-us.yaml | 4 ++++ .../components/form/credential-library/index.hbs | 8 ++++++++ .../target/add-credential-libraries/index.hbs | 8 ++++++++ .../credential-store/credential-libraries/new.js | 3 ++- .../credential-libraries/index.hbs | 8 ++++++++ .../scopes/scope/credential-stores/index.hbs | 6 +++++- .../targets/target/credential-libraries.hbs | 8 ++++++++ 10 files changed, 63 insertions(+), 7 deletions(-) diff --git a/addons/api/addon/generated/models/credential-library.js b/addons/api/addon/generated/models/credential-library.js index 895c467f9..a5f63633a 100644 --- a/addons/api/addon/generated/models/credential-library.js +++ b/addons/api/addon/generated/models/credential-library.js @@ -8,6 +8,11 @@ import { attr } from '@ember-data/model'; export default class GeneratedCredentialLibraryModel extends BaseModel { // =attributes + @attr('string', { + description: 'The type of the resource, to help differentiate schemas', + }) + type; + @attr('string', { description: 'The owning credential store ID.', }) diff --git a/addons/api/mirage/factories/credential-library.js b/addons/api/mirage/factories/credential-library.js index f1127d5ef..06d8c4f6c 100644 --- a/addons/api/mirage/factories/credential-library.js +++ b/addons/api/mirage/factories/credential-library.js @@ -1,14 +1,20 @@ import factory from '../generated/factories/credential-library'; import { random, system } from 'faker'; +const types = ['vault']; + export default factory.extend({ id: (i) => `credential-library-id-${i}`, + type: (i) => types[i % types.length], attributes() { - return { - http_method: 'GET', - http_request_body: random.word(), - path: system.directoryPath(), - }; + switch (this.type) { + case 'vault': + return { + http_method: 'GET', + http_request_body: random.word(), + path: system.directoryPath(), + }; + } }, }); diff --git a/addons/api/tests/unit/serializers/credential-library-test.js b/addons/api/tests/unit/serializers/credential-library-test.js index 4be3c76f2..885474d42 100644 --- a/addons/api/tests/unit/serializers/credential-library-test.js +++ b/addons/api/tests/unit/serializers/credential-library-test.js @@ -9,6 +9,7 @@ module('Unit | Serializer | credential library', function (hooks) { const store = this.owner.lookup('service:store'); const serializer = store.serializerFor('credential-library'); const record = store.createRecord('credential-library', { + type: 'vault', name: 'Name', description: 'Description', attributes: { @@ -20,6 +21,7 @@ module('Unit | Serializer | credential library', function (hooks) { const snapshot = record._createSnapshot(); const serializedRecord = serializer.serialize(snapshot); assert.deepEqual(serializedRecord, { + type: 'vault', credential_store_id: null, name: 'Name', description: 'Description', @@ -40,6 +42,7 @@ module('Unit | Serializer | credential library', function (hooks) { id: '1', type: 'credential-library', attributes: { + type: 'vault', name: 'Name', description: 'Description', attributes: { @@ -54,6 +57,7 @@ module('Unit | Serializer | credential library', function (hooks) { const snapshot = record._createSnapshot(); const serializedRecord = serializer.serialize(snapshot); assert.deepEqual(serializedRecord, { + type: 'vault', credential_store_id: null, name: 'Name', description: 'Description', diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 0867adc93..a448c0011 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -288,6 +288,8 @@ credential-store: title: Welcome to Credential Stores actions: delete: Delete Credential Store + types: + vault: Vault credential-library: title: Credential Library title_plural: Credential Libraries @@ -309,3 +311,5 @@ credential-library: http_request_body: label: HTTP Method POST Request Body help: The body of the HTTP request the library sends to Vault when requesting credentials. Only allowed when HTTP method is set to POST. + types: + vault: Vault diff --git a/ui/admin/app/components/form/credential-library/index.hbs b/ui/admin/app/components/form/credential-library/index.hbs index 88154aa84..3e3add0ee 100644 --- a/ui/admin/app/components/form/credential-library/index.hbs +++ b/ui/admin/app/components/form/credential-library/index.hbs @@ -5,6 +5,14 @@ @showEditToggle={{if @model.isNew false true}} as |form| > + + + {{t 'form.id.label'}} {{t 'form.name.label'}} + {{t 'form.type.label'}} @@ -30,6 +31,13 @@ /> {{credentialLibrary.name}} + + {{t + (concat + 'resources.credential-library.types.' credentialLibrary.type + ) + }} + {{/each}} diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js index d83109dda..c9ccc770c 100644 --- a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js @@ -8,10 +8,11 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari * @return {CredentialLibraryModel} */ model() { - const { id: credential_store_id } = this.modelFor( + const { id: credential_store_id, type } = this.modelFor( 'scopes.scope.credential-stores.credential-store' ); return this.store.createRecord('credential-library', { + type, credential_store_id, }); } diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs index cbe1ede49..e97d52411 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs @@ -4,6 +4,7 @@ {{t 'form.name.label'}} + {{t 'form.type.label'}} {{t 'form.id.label'}} @@ -19,6 +20,13 @@

{{credentialLibrary.description}}

+ + {{t + (concat + 'resources.credential-library.types.' credentialLibrary.type + ) + }} + {{credentialStore.description}}

- {{credentialStore.type}} + {{t + (concat + 'resources.credential-store.types.' credentialStore.type + ) + }} {{t 'form.name.label'}} + {{t 'form.type.label'}} {{t 'form.id.label'}} @@ -24,6 +25,13 @@

{{credentialLibrary.description}}

+ + {{t + (concat + 'resources.credential-library.types.' credentialLibrary.type + ) + }} + Date: Tue, 27 Jul 2021 14:08:16 -0400 Subject: [PATCH 53/68] feat: Add credential store attributes to it's form --- addons/core/translations/resources/en-us.yaml | 25 +++ .../form/credential-store/index.hbs | 152 ++++++++++++++++++ 2 files changed, 177 insertions(+) diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index a448c0011..b9eb433c3 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -290,6 +290,31 @@ credential-store: delete: Delete Credential Store types: vault: Vault + form: + address: + label: Address + help: The address of the Vault server. This should be a complete URL such as https://127.0.0.1:8200. + namespace: + label: Namespace + help: A Vault namespace. Requires Vault Enterprise. + ca_cert: + label: CA Certificate + help: A PEM-encoded CA certificate to verify the Vault server's TLS certificate. + tls_server_name: + label: TLS Server Name + help: Name to use as the SNI host when connecting to Vault via TLS. + tls_skip_verify: + label: TLS Skip Verify + help: Disable verification of TLS certificates. Using this option is highly discouraged as it decreases the security of data transmissions to and from the Vault server. + token: + label: Token + help: A token used for accessing Vault. + client_certificate: + label: Client Certificate + help: A PEM-encoded client certificate to use for TLS authentication to the Vault server. + client_certificate_key: + label: Client Certificate Key + help: A PEM-encoded private key matching the client certificate from Client Certificate. credential-library: title: Credential Library title_plural: Credential Libraries diff --git a/ui/admin/app/components/form/credential-store/index.hbs b/ui/admin/app/components/form/credential-store/index.hbs index b70183ed3..cd50e3aae 100644 --- a/ui/admin/app/components/form/credential-store/index.hbs +++ b/ui/admin/app/components/form/credential-store/index.hbs @@ -52,6 +52,158 @@ {{/if}}
+ + {{#if @model.errors.attributes_address}} + + {{#each @model.errors.attributes_address as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.attributes_token}} + + {{#each @model.errors.attributes_token as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.attributes_namespace}} + + {{#each @model.errors.attributes_namespace as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.attributes_tls_server_name}} + + {{#each @model.errors.attributes_tls_server_name as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + + + {{#if @model.errors.attributes_client_certificate}} + + {{#each @model.errors.attributes_client_certificate as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.attributes_client_certificate_key}} + + {{#each @model.errors.attributes_client_certificate_key as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.attributes_ca_cert}} + + {{#each @model.errors.attributes_ca_cert as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + Date: Tue, 27 Jul 2021 14:15:59 -0700 Subject: [PATCH 54/68] =?UTF-8?q?test:=20=F0=9F=92=8D=20Add=20creation=20e?= =?UTF-8?q?rror=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add credential library creation error tests --- .../credential-library-test.js | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/ui/admin/tests/acceptance/credential-library/credential-library-test.js b/ui/admin/tests/acceptance/credential-library/credential-library-test.js index a23fac3f2..77dbc0912 100644 --- a/ui/admin/tests/acceptance/credential-library/credential-library-test.js +++ b/ui/admin/tests/acceptance/credential-library/credential-library-test.js @@ -137,6 +137,112 @@ module('Acceptance | credential-library', function (hooks) { ); }); + test.skip('can save changes to existing credential library', async function (assert) { + assert.expect(3); + assert.notEqual(instances.credentialLibrary.name, 'random string'); + await visit(urls.credentialLibrary); + await click('form [type="button"]', 'Activate edit mode'); + await fillIn('[name="name"]', 'random string'); + await click('.rose-form-actions [type="submit"]'); + assert.equal(currentURL(), urls.credentialLibrary); + assert.equal( + this.server.schema.credentialLibraries.all().models[0].name, + 'random string' + ); + }); + + test('can cancel changes to existing credential library', async function (assert) { + assert.expect(2); + await visit(urls.credentialLibrary); + await click('form [type="button"]', 'Activate edit mode'); + await fillIn('[name="name"]', 'random string'); + await click('.rose-form-actions [type="button"]'); + assert.notEqual(instances.credentialStore.name, 'random string'); + assert.equal(find('[name="name"]').value, instances.credentialLibrary.name); + }); + + test('saving an existing credential library with invalid fields displays error messages', async function (assert) { + assert.expect(2); + this.server.patch('/credential-libraries/:id', () => { + return new Response( + 400, + {}, + { + status: 400, + code: 'invalid_argument', + message: 'The request was invalid.', + details: { + request_fields: [ + { + name: 'name', + description: 'Name is required', + }, + ], + }, + } + ); + }); + await visit(urls.credentialLibrary); + await click('form [type="button"]', 'Activate edit mode'); + await fillIn('[name="name"]', 'random string'); + await click('[type="submit"]'); + assert.ok( + find('[role="alert"]').textContent.trim(), + 'The request was invalid.' + ); + assert.ok( + find('.rose-form-error-message').textContent.trim(), + 'Name is required.' + ); + }); + + test('can discard unsaved credential library changes via dialog', async function (assert) { + assert.expect(5); + const confirmService = this.owner.lookup('service:confirm'); + confirmService.enabled = true; + assert.notEqual(instances.credentialLibrary.name, 'random string'); + + await visit(urls.credentialLibrary); + await click('form [type="button"]', 'Activate edit mode'); + await fillIn('[name="name"]', 'random string'); + assert.equal(currentURL(), urls.credentialLibrary); + + try { + await visit(urls.credentialLibraries); + } catch (e) { + assert.ok(find('.rose-dialog')); + await click('.rose-dialog-footer button:first-child', 'Click Discard'); + assert.equal(currentURL(), urls.credentialLibraries); + assert.notEqual( + this.server.schema.credentialLibraries.all().models[0].name, + 'random string' + ); + } + }); + + test('can cancel discard unsaved credential library via dialog', async function (assert) { + assert.expect(5); + const confirmService = this.owner.lookup('service:confirm'); + confirmService.enabled = true; + assert.notEqual(instances.credentialLibrary.name, 'random string'); + await visit(urls.credentialLibrary); + await click('form [type="button"]', 'Activate edit mode'); + await fillIn('[name="name"]', 'random string'); + assert.equal(currentURL(), urls.credentialLibrary); + + try { + await visit(urls.credentialLibraries); + } catch (e) { + assert.ok(find('.rose-dialog')); + await click('.rose-dialog-footer button:last-child'); + assert.equal(currentURL(), urls.credentialLibrary); + assert.notEqual( + this.server.schema.credentialLibraries.all().models[0].name, + 'random string' + ); + } + }); + test('can delete credential library', async function (assert) { assert.expect(1); const count = getCredentialLibraryCount(); From 8cceb4090fcc6ba59da7021fe146aeb68a80c818 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Tue, 27 Jul 2021 14:27:13 -0700 Subject: [PATCH 55/68] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20Change=20save?= =?UTF-8?q?=20crdential=20library=20behaviour?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change save credential library behaviour to not redirect after saving a change --- .../credential-stores/credential-store/credential-libraries.js | 3 ++- .../acceptance/credential-library/credential-library-test.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js index d9602dba4..84684ecfd 100644 --- a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js +++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries.js @@ -47,7 +47,8 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari async save(credentialLibrary) { await credentialLibrary.save(); await this.transitionTo( - 'scopes.scope.credential-stores.credential-store.credential-libraries' + 'scopes.scope.credential-stores.credential-store.credential-libraries.credential-library', + credentialLibrary ); this.refresh(); } diff --git a/ui/admin/tests/acceptance/credential-library/credential-library-test.js b/ui/admin/tests/acceptance/credential-library/credential-library-test.js index 77dbc0912..245fc7157 100644 --- a/ui/admin/tests/acceptance/credential-library/credential-library-test.js +++ b/ui/admin/tests/acceptance/credential-library/credential-library-test.js @@ -137,7 +137,7 @@ module('Acceptance | credential-library', function (hooks) { ); }); - test.skip('can save changes to existing credential library', async function (assert) { + test('can save changes to existing credential library', async function (assert) { assert.expect(3); assert.notEqual(instances.credentialLibrary.name, 'random string'); await visit(urls.credentialLibrary); From f3a4017e5f5c1690e831ce518158e55911865e51 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Tue, 27 Jul 2021 15:35:51 -0700 Subject: [PATCH 56/68] =?UTF-8?q?chore:=20=F0=9F=A4=96=20Update=20Sass=20v?= =?UTF-8?q?ersion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/rose/package.json | 2 +- ui/admin/package.json | 2 +- ui/desktop/package.json | 2 +- yarn.lock | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/addons/rose/package.json b/addons/rose/package.json index dde5784b5..6e1f5fadb 100644 --- a/addons/rose/package.json +++ b/addons/rose/package.json @@ -83,7 +83,7 @@ "prettier": "^2.2.1", "qunit": "^2.13.0", "qunit-dom": "^1.6.0", - "sass": "^1.26.5", + "sass": "^1.36.0", "sass-lint": "^1.13.1" }, "engines": { diff --git a/ui/admin/package.json b/ui/admin/package.json index 6c2390fe6..bc9e5b2b6 100644 --- a/ui/admin/package.json +++ b/ui/admin/package.json @@ -89,7 +89,7 @@ "qunit": "^2.13.0", "qunit-dom": "^1.6.0", "rose": "*", - "sass": "^1.29.0", + "sass": "^1.36.0", "sass-lint": "^1.13.1", "sinon": "^11.1.1" }, diff --git a/ui/desktop/package.json b/ui/desktop/package.json index 6ed9cd93e..1327bccd6 100755 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -104,7 +104,7 @@ "qunit": "^2.13.0", "qunit-dom": "^1.6.0", "rose": "*", - "sass": "^1.29.0", + "sass": "^1.36.0", "sinon": "^11.1.1", "stylelint": "^13.8.0", "stylelint-config-sass-guidelines": "^7.1.0" diff --git a/yarn.lock b/yarn.lock index e2f00c012..80808da5a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18934,10 +18934,10 @@ sass-lint@^1.13.1: path-is-absolute "^1.0.0" util "^0.10.3" -sass@^1.26.5, sass@^1.29.0: - version "1.34.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.34.1.tgz#30f45c606c483d47b634f1e7371e13ff773c96ef" - integrity sha512-scLA7EIZM+MmYlej6sdVr0HRbZX5caX5ofDT9asWnUJj21oqgsC+1LuNfm0eg+vM0fCTZHhwImTiCU0sx9h9CQ== +sass@^1.36.0: + version "1.36.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.36.0.tgz#5912ef9d5d16714171ba11cb17edb274c4bbc07e" + integrity sha512-fQzEjipfOv5kh930nu3Imzq3ie/sGDc/4KtQMJlt7RRdrkQSfe37Bwi/Rf/gfuYHsIuE1fIlDMvpyMcEwjnPvg== dependencies: chokidar ">=3.0.0 <4.0.0" From 264f81a6f3df95c771eb9b8b0f7863e27b586100 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Wed, 28 Jul 2021 10:16:37 -0700 Subject: [PATCH 57/68] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20Prevent=20open?= =?UTF-8?q?ing=20unknown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevent opening unknown links --- ui/desktop/electron-app/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/desktop/electron-app/src/index.js b/ui/desktop/electron-app/src/index.js index 8c303a7ee..c0c437698 100644 --- a/ui/desktop/electron-app/src/index.js +++ b/ui/desktop/electron-app/src/index.js @@ -171,8 +171,8 @@ app.on('ready', async () => { // We just allow boundaryproject.io domain to open on external window (for now). mainWindow.webContents.on('new-window', (event, url) => { /* eng-disable LIMIT_NAVIGATION_JS_CHECK */ + event.preventDefault(); if (url.startsWith('https://boundaryproject.io/')) { - event.preventDefault(); shell.openExternal(url); } }); From e40ff1f63ce02846c75678d8c09da8e09ff15113 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Wed, 28 Jul 2021 13:22:47 -0400 Subject: [PATCH 58/68] fix: Protect credentialstore attrs hmac values in serializati --- .../fragment-credential-store-attributes.js | 10 ++ ...agment-credential-store-attributes-test.js | 114 +++++++++++++++--- addons/core/translations/resources/en-us.yaml | 6 +- .../form/credential-store/index.hbs | 32 ++++- 4 files changed, 146 insertions(+), 16 deletions(-) diff --git a/addons/api/addon/serializers/fragment-credential-store-attributes.js b/addons/api/addon/serializers/fragment-credential-store-attributes.js index 547c6a4f7..883a823aa 100644 --- a/addons/api/addon/serializers/fragment-credential-store-attributes.js +++ b/addons/api/addon/serializers/fragment-credential-store-attributes.js @@ -19,6 +19,16 @@ export default class FragmentCredentialStoreAttributesSerializer extends JSONSer if (type === 'string' && json[key] === '') json[key] = null; // Do not serialize read-only attributes. if (options.readOnly) delete json[key]; + // Token cannot be unset. If it's falsy, it must be removed. + if (key === 'token' && !json[key]) delete json[key]; + // Client certificate key cannot be unset when certificate is set. + // If it's falsy, it must be removed. + if ( + key === 'client_certificate_key' && + !json[key] && + json['client_certificate'] + ) + delete json[key]; return value; } } diff --git a/addons/api/tests/unit/serializers/fragment-credential-store-attributes-test.js b/addons/api/tests/unit/serializers/fragment-credential-store-attributes-test.js index 7fbbd0744..cfa00734b 100644 --- a/addons/api/tests/unit/serializers/fragment-credential-store-attributes-test.js +++ b/addons/api/tests/unit/serializers/fragment-credential-store-attributes-test.js @@ -6,26 +6,112 @@ module( function (hooks) { setupTest(hooks); - // Replace this with your real tests. - test('it exists', function (assert) { - let store = this.owner.lookup('service:store'); - let serializer = store.serializerFor( - 'fragment-credential-store-attributes' + 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-store-attributes', + { + address: '', + ca_cert: '', + client_certificate: '', + client_certificate_key: '', + namespace: '', + tls_server_name: '', + tls_skip_verify: false, + } ); - - assert.ok(serializer); + let serializedRecord = record.serialize(); + assert.deepEqual(serializedRecord, { + address: null, + ca_cert: null, + client_certificate: null, + client_certificate_key: null, + namespace: null, + tls_server_name: null, + tls_skip_verify: false, + }); }); - test('it serializes records', function (assert) { - let store = this.owner.lookup('service:store'); - let record = store.createRecord( + test('it does not serialize token if present but falsy', function (assert) { + assert.expect(1); + const store = this.owner.lookup('service:store'); + const record = store.createRecord( 'fragment-credential-store-attributes', - {} + { + token: null, + address: 'http://localhost:5000', + ca_cert: 'ca-cert-123', + client_certificate: 'client-cert-123', + client_certificate_key: 'client-cert-key-456', + namespace: 'foobar', + tls_server_name: 'yes', + tls_skip_verify: false, + } + ); + let serializedRecord = record.serialize(); + assert.deepEqual( + serializedRecord, + { + address: 'http://localhost:5000', + ca_cert: 'ca-cert-123', + client_certificate: 'client-cert-123', + client_certificate_key: 'client-cert-key-456', + namespace: 'foobar', + tls_server_name: 'yes', + tls_skip_verify: false, + }, + 'token attribute is not expected' + ); + }); + + test('it does not serialize client certificate key if present but falsy when client certificate is present', function (assert) { + assert.expect(2); + const store = this.owner.lookup('service:store'); + const record = store.createRecord( + 'fragment-credential-store-attributes', + { + client_certificate: 'client-cert-123', + client_certificate_key: '', + address: 'http://localhost:5000', + token: 'foo', + ca_cert: 'ca-cert-123', + namespace: 'foobar', + tls_server_name: 'yes', + tls_skip_verify: false, + } + ); + let serializedRecord = record.serialize(); + assert.deepEqual( + serializedRecord, + { + client_certificate: 'client-cert-123', + address: 'http://localhost:5000', + token: 'foo', + ca_cert: 'ca-cert-123', + namespace: 'foobar', + tls_server_name: 'yes', + tls_skip_verify: false, + }, + 'client certificate key attribute is not expected' ); - let serializedRecord = record.serialize(); - - assert.ok(serializedRecord); + record.client_certificate_key = 'client-cert-key-456'; + serializedRecord = record.serialize(); + assert.deepEqual( + serializedRecord, + { + client_certificate: 'client-cert-123', + client_certificate_key: 'client-cert-key-456', + address: 'http://localhost:5000', + token: 'foo', + ca_cert: 'ca-cert-123', + namespace: 'foobar', + tls_server_name: 'yes', + tls_skip_verify: false, + }, + 'client certificate key attribute is expected' + ); }); } ); diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index b9eb433c3..9d001037f 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -308,13 +308,17 @@ credential-store: help: Disable verification of TLS certificates. Using this option is highly discouraged as it decreases the security of data transmissions to and from the Vault server. token: label: Token - help: A token used for accessing Vault. + help: A token used for accessing Vault. + token_hmac: + label: Token HMAC client_certificate: label: Client Certificate help: A PEM-encoded client certificate to use for TLS authentication to the Vault server. client_certificate_key: label: Client Certificate Key help: A PEM-encoded private key matching the client certificate from Client Certificate. + client_certificate_key_hmac: + label: Client Certificate Key HMAC credential-library: title: Credential Library title_plural: Credential Libraries diff --git a/ui/admin/app/components/form/credential-store/index.hbs b/ui/admin/app/components/form/credential-store/index.hbs index cd50e3aae..c77bfb410 100644 --- a/ui/admin/app/components/form/credential-store/index.hbs +++ b/ui/admin/app/components/form/credential-store/index.hbs @@ -92,6 +92,15 @@ {{/if}} + {{#unless @model.isNew}} + + {{/unless}} + + @error={{@model.errors.attributes_tls_skip_verify}} + as |field| + > + {{#if @model.errors.attributes_tls_skip_verify}} + + {{#each @model.errors.attributes_tls_skip_verify as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + {{#unless @model.isNew}} + + {{/unless}} + Date: Wed, 28 Jul 2021 10:51:57 -0700 Subject: [PATCH 59/68] =?UTF-8?q?test:=20=F0=9F=92=8D=20Change=20assertion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change assertion to avoid false positive --- .../acceptance/credential-library/credential-library-test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/admin/tests/acceptance/credential-library/credential-library-test.js b/ui/admin/tests/acceptance/credential-library/credential-library-test.js index ce2265856..c2b71f8f1 100644 --- a/ui/admin/tests/acceptance/credential-library/credential-library-test.js +++ b/ui/admin/tests/acceptance/credential-library/credential-library-test.js @@ -157,7 +157,10 @@ module('Acceptance | credential-library', function (hooks) { await click('form [type="button"]', 'Activate edit mode'); await fillIn('[name="name"]', 'random string'); await click('.rose-form-actions [type="button"]'); - assert.notEqual(instances.credentialStore.name, 'random string'); + assert.notEqual( + this.server.schema.credentialLibraries.all().models[0].name, + 'random string' + ); assert.equal(find('[name="name"]').value, instances.credentialLibrary.name); }); From 296b5fbecdce27e6cf33a588ae3447644d9aa001 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Wed, 28 Jul 2021 16:27:40 -0400 Subject: [PATCH 60/68] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20add=20doc=20?= =?UTF-8?q?links=20for=20cred=20stores=20and=20sources?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../credential-libraries/credential-library/-header.hbs | 5 ++++- .../app/templates/scopes/scope/credential-stores/index.hbs | 2 +- ui/admin/config/environment.js | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs index 3c2de9eef..ce2cbce51 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs @@ -1,4 +1,7 @@ -

{{t 'resources.credential-library.title'}}

+

+ {{t 'resources.credential-library.title'}} + +

{{t 'resources.credential-library.description'}}

{{t 'resources.credential-store.title_plural'}} - +

{{#if @model}}

{{t 'resources.credential-store.description'}}

diff --git a/ui/admin/config/environment.js b/ui/admin/config/environment.js index fca0dab92..9f13c5e50 100644 --- a/ui/admin/config/environment.js +++ b/ui/admin/config/environment.js @@ -55,7 +55,8 @@ module.exports = function (environment) { 'host-set': '/host-sets', 'host-set.new': '/host-sets/new', 'host-set.add-hosts': '/host-sets/add-hosts', - 'credential-stores': '/credential-stores', + 'credential-store': '/credential-stores', + 'credential-source': '/credential-sources', host: '/hosts', 'host.new': '/hosts/new', role: '/roles', From d23afb1c71b83b5555d703e4087da8d2abe96690 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Thu, 29 Jul 2021 10:34:33 -0400 Subject: [PATCH 61/68] fix: credential library naming does not change --- .../credential-libraries/credential-library/-header.hbs | 4 ++-- ui/admin/config/environment.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs index ce2cbce51..c8c637132 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs @@ -1,6 +1,6 @@

{{t 'resources.credential-library.title'}} - +

{{t 'resources.credential-library.description'}}

{{@model.id}} - \ No newline at end of file +
diff --git a/ui/admin/config/environment.js b/ui/admin/config/environment.js index 9f13c5e50..3524d5c08 100644 --- a/ui/admin/config/environment.js +++ b/ui/admin/config/environment.js @@ -56,7 +56,7 @@ module.exports = function (environment) { 'host-set.new': '/host-sets/new', 'host-set.add-hosts': '/host-sets/add-hosts', 'credential-store': '/credential-stores', - 'credential-source': '/credential-sources', + 'credential-library': '/credential-libraries', host: '/hosts', 'host.new': '/hosts/new', role: '/roles', From 8e6988c179e58fd1d34b1a51ddb7ca22d2e91750 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Thu, 29 Jul 2021 12:21:03 -0400 Subject: [PATCH 62/68] formatting --- .../credential-libraries/credential-library/-header.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs index c8c637132..229448ada 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/credential-library/-header.hbs @@ -9,4 +9,4 @@ @acknowledgeText={{t 'states.copied'}} > {{@model.id}} - + \ No newline at end of file From a8f1780731ae2bda848b429d23266df72f847aab Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Thu, 29 Jul 2021 12:59:54 -0400 Subject: [PATCH 63/68] test: Add target association tests for credential libraries --- ui/admin/config/environment.js | 3 + .../targets/credential-libraries-test.js | 99 +++++++++++++++++-- 2 files changed, 95 insertions(+), 7 deletions(-) diff --git a/ui/admin/config/environment.js b/ui/admin/config/environment.js index 9f13c5e50..e668b6a55 100644 --- a/ui/admin/config/environment.js +++ b/ui/admin/config/environment.js @@ -158,6 +158,9 @@ module.exports = function (environment) { ENV.sessionPollingTimeoutSeconds = 0.25; ENV.oidcPollingTimeoutSeconds = 0; ENV.enableConfirmService = false; + + // Enable tests for development features + ENV.featureFlags['credential-store'] = true; } if (environment === 'production') { diff --git a/ui/admin/tests/acceptance/targets/credential-libraries-test.js b/ui/admin/tests/acceptance/targets/credential-libraries-test.js index b8e2d5233..3e75c8fa2 100644 --- a/ui/admin/tests/acceptance/targets/credential-libraries-test.js +++ b/ui/admin/tests/acceptance/targets/credential-libraries-test.js @@ -1,8 +1,9 @@ import { module, test } from 'qunit'; -import { visit, find, findAll, click } from '@ember/test-helpers'; +import { visit, find, findAll, click, currentURL } from '@ember/test-helpers'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import { Response } from 'miragejs'; +import a11yAudit from 'ember-a11y-testing/test-support/audit'; import { authenticateSession, // These are left here intentionally for future reference. @@ -22,7 +23,9 @@ module('Acceptance | targets | credential-libraries', function (hooks) { org: null, project: null, }, + credentialStore: null, credentialLibraries: null, + credentialLibrary: null, }; const urls = { globalScope: null, @@ -30,7 +33,9 @@ module('Acceptance | targets | credential-libraries', function (hooks) { projectScope: null, targets: null, target: null, - targetCredentialLibraries: null, + credentialLibraries: null, + credentialLibrary: null, + addCredentialLibraries: null, }; hooks.beforeEach(function () { @@ -44,11 +49,19 @@ module('Acceptance | targets | credential-libraries', function (hooks) { type: 'project', scope: { id: instances.scopes.org.id, type: 'org' }, }); + instances.credentialStore = this.server.create('credential-store', { + type: 'vault', + scope: instances.scopes.project, + }); instances.credentialLibraries = this.server.createList( 'credential-library', 2, - { scope: instances.scopes.project } + { + scope: instances.scopes.project, + credentialStore: instances.credentialStore, + } ); + instances.credentialLibrary = instances.credentialLibraries[0]; instances.target = this.server.create('target', { scope: instances.scopes.project, credentialLibraries: instances.credentialLibraries, @@ -57,19 +70,91 @@ module('Acceptance | targets | credential-libraries', function (hooks) { urls.globalScope = `/scopes/global/scopes`; urls.orgScope = `/scopes/${instances.scopes.org.id}/scopes`; urls.projectScope = `/scopes/${instances.scopes.project.id}`; - urls.targets = `/scopes/${instances.scopes.project.id}/targets`; + urls.targets = `${urls.projectScope}/targets`; urls.target = `${urls.targets}/${instances.target.id}`; - urls.targetCredentialLibraries = `${urls.target}/credential-libraries`; + urls.credentialLibraries = `${urls.target}/credential-libraries`; + urls.credentialLibrary = `${urls.projectScope}/credential-stores/${instances.credentialLibrary.credentialStoreId}/credential-libraries/${instances.credentialLibrary.id}`; + urls.addCredentialLibraries = `${urls.target}/add-credential-libraries`; // Generate resource counter getCredentialLibraryCount = () => this.server.schema.credentialLibraries.all().models.length; authenticateSession({}); }); + test('visiting target credential libraries', async function (assert) { + assert.expect(2); + await visit(urls.credentialLibraries); + await a11yAudit(); + assert.equal(currentURL(), urls.credentialLibraries); + assert.equal(findAll('tbody tr').length, getCredentialLibraryCount()); + }); + + test('can navigate to a credential library', async function (assert) { + assert.expect(1); + await visit(urls.credentialLibraries); + await click('main tbody .rose-table-header-cell:nth-child(1) a'); + await a11yAudit(); + assert.equal(currentURL(), urls.credentialLibrary); + }); + + test('visiting add credential libraries', async function (assert) { + assert.expect(1); + await visit(urls.addCredentialLibraries); + await a11yAudit(); + assert.equal(currentURL(), urls.addCredentialLibraries); + }); + + test('can select and save credential libraries to add', async function (assert) { + assert.expect(4); + instances.target.update({ credentialLibraries: [] }); + await visit(urls.credentialLibraries); + assert.equal(findAll('tbody tr').length, 0); + await visit(urls.addCredentialLibraries); + assert.equal(findAll('tbody tr').length, getCredentialLibraryCount()); + await click('tbody label'); + await click('form [type="submit"]'); + assert.equal(currentURL(), urls.credentialLibraries); + assert.equal(findAll('tbody tr').length, 1); + }); + + test('can select and cancel credential libraries to add', async function (assert) { + assert.expect(4); + instances.target.update({ credentialLibraries: [] }); + await visit(urls.credentialLibraries); + assert.equal(findAll('tbody tr').length, 0); + await visit(urls.addCredentialLibraries); + assert.equal(findAll('tbody tr').length, getCredentialLibraryCount()); + await click('tbody label'); + await click('form [type="button"]'); + assert.equal(currentURL(), urls.credentialLibraries); + assert.equal(findAll('tbody tr').length, 0); + }); + + test('adding credential libraries which errors displays error message', async function (assert) { + assert.expect(1); + this.server.post('/targets/:idMethod', () => { + return new Response( + 400, + {}, + { + status: 400, + code: 'invalid_argument', + message: 'The request was invalid.', + details: {}, + } + ); + }); + instances.target.update({ credentialLibraries: [] }); + await visit(urls.addCredentialLibraries); + await click('tbody label'); + await click('form [type="submit"]'); + assert.ok(find('[role="alert"]')); + }); + test('can remove a credential library', async function (assert) { assert.expect(2); const count = getCredentialLibraryCount(); - await visit(urls.targetCredentialLibraries); + await visit(urls.credentialLibraries); assert.equal(findAll('tbody tr').length, count); await click('tbody tr .rose-dropdown-button-danger'); assert.equal(findAll('tbody tr').length, count - 1); @@ -90,7 +175,7 @@ module('Acceptance | targets | credential-libraries', function (hooks) { ); }); const count = getCredentialLibraryCount(); - await visit(urls.targetCredentialLibraries); + await visit(urls.credentialLibraries); assert.equal(findAll('tbody tr').length, count); await click('tbody tr .rose-dropdown-button-danger'); assert.ok(find('[role="alert"]')); From 0231dabbe69a2e4b846013da7cf1ba1afb8267da Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Thu, 29 Jul 2021 14:17:58 -0400 Subject: [PATCH 64/68] refactor: Rename target host sets and credential libraries Rename to Target Host Sources and Credential Sources --- addons/core/translations/resources/en-us.yaml | 32 +++++++++++-------- .../form/target/add-host-sets/index.hbs | 2 +- .../scope/targets/target/-navigation.hbs | 4 +-- .../targets/target/credential-libraries.hbs | 8 ++++- .../scopes/scope/targets/target/host-sets.hbs | 2 +- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 9d001037f..52bd07d03 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -253,32 +253,36 @@ target: actions: create: New Target delete: Delete Target - add-host-sets: Add Host Sets - add-credential-libraries: Add Credential Libraries + add-host-sets: Add Host Sources + add-credential-libraries: Add Credential Sources types: tcp: TCP host-set: + title: Host Source + title_plural: Host Sources messages: welcome: - title: Welcome to Host Sets - description: No hosts sets in this target. + title: Welcome to Host Sources + description: No hosts sources in this target. none: - title: No Host Sets Available - description: No hosts sets available to add to target. + title: No Host Sources Available + description: No hosts sources available to add to target. add: - title: Add Host Sets - description: Select host sets to assign to this target. + title: Add Host Sources + description: Select host sources to assign to this target. credential-library: + title: Credential Source + title_plural: Credential Sources messages: welcome: - title: Welcome to Credential Libraries - description: No credential libraries in this target. + title: Welcome to Credential Sources + description: No credential sources in this target. none: - title: No Credential Libraries Available - description: No credential libraries available to add to this target. + title: No Credential Sources Available + description: No credential sources available to add to this target. add: - title: Add Credential Libraries - description: Select credential libraries to assign to this target. + title: Add Credential Sources + description: Select credential sources to assign to this target. credential-store: title: Credential Store title_plural: Credential Stores diff --git a/ui/admin/app/components/form/target/add-host-sets/index.hbs b/ui/admin/app/components/form/target/add-host-sets/index.hbs index 3bfd6b1b7..0ad80f766 100644 --- a/ui/admin/app/components/form/target/add-host-sets/index.hbs +++ b/ui/admin/app/components/form/target/add-host-sets/index.hbs @@ -9,7 +9,7 @@ > diff --git a/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs b/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs index c337646f9..027162874 100644 --- a/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs +++ b/ui/admin/app/templates/scopes/scope/targets/target/-navigation.hbs @@ -3,11 +3,11 @@ {{t 'titles.details'}} - {{t 'resources.host-set.title_plural'}} + {{t 'resources.target.host-set.title_plural'}} {{#if (feature-flag 'credential-store')}} - {{t 'resources.credential-library.title_plural'}} + {{t 'resources.target.credential-library.title_plural'}} {{/if}} \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs b/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs index f92cd3715..14d0b4d90 100644 --- a/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs +++ b/ui/admin/app/templates/scopes/scope/targets/target/credential-libraries.hbs @@ -1,4 +1,4 @@ -{{page-title (t 'resources.credential-library.title_plural')}} +{{page-title (t 'resources.target.credential-library.title_plural')}} {{#if @model.credentialLibraries}} @@ -79,6 +79,12 @@ {{t 'resources.target.credential-library.messages.welcome.description'}} + + + {{t 'resources.target.actions.add-credential-libraries'}} + diff --git a/ui/admin/app/templates/scopes/scope/targets/target/host-sets.hbs b/ui/admin/app/templates/scopes/scope/targets/target/host-sets.hbs index 81a8e4c3c..ad9f10154 100644 --- a/ui/admin/app/templates/scopes/scope/targets/target/host-sets.hbs +++ b/ui/admin/app/templates/scopes/scope/targets/target/host-sets.hbs @@ -1,4 +1,4 @@ -{{page-title (t 'resources.host-set.title_plural')}} +{{page-title (t 'resources.target.host-set.title_plural')}} {{#if @model.hostSets}} From 8fb33b8ff5542f971b71fcdfc4ba813f2df73ce7 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Thu, 29 Jul 2021 15:13:13 -0400 Subject: [PATCH 65/68] chore: Enable credential brokering feature in admin --- ui/admin/config/environment.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/ui/admin/config/environment.js b/ui/admin/config/environment.js index 98858a1c9..d20097dff 100644 --- a/ui/admin/config/environment.js +++ b/ui/admin/config/environment.js @@ -95,7 +95,7 @@ module.exports = function (environment) { search: false, filter: false, capabilities: false, - 'credential-store': false, + 'credential-store': true, }, }; @@ -131,11 +131,7 @@ module.exports = function (environment) { if (API_HOST) ENV.contentSecurityPolicy['connect-src'].push(API_HOST); // Enable features in development - ENV.featureFlags['primary-auth-method'] = true; - ENV.featureFlags['oidc'] = true; - ENV.featureFlags['oidc-crud'] = true; - ENV.featureFlags['credential-store'] = true; - //ENV.featureFlags['oidc-account-crud'] = true; + // ENV.featureFlags['credential-store'] = true; } if (environment === 'test') { @@ -160,7 +156,7 @@ module.exports = function (environment) { ENV.enableConfirmService = false; // Enable tests for development features - ENV.featureFlags['credential-store'] = true; + // ENV.featureFlags['credential-store'] = true; } if (environment === 'production') { From cdecf570e276efbcb13d98c99097d4419fe101a8 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 2 Aug 2021 18:02:59 -0400 Subject: [PATCH 66/68] docs: Bump desktop changelog for next release --- ui/desktop/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ui/desktop/CHANGELOG.md b/ui/desktop/CHANGELOG.md index e9c021464..eeb56bd30 100644 --- a/ui/desktop/CHANGELOG.md +++ b/ui/desktop/CHANGELOG.md @@ -2,6 +2,14 @@ Canonical reference for changes, improvements, and bugfixes for Boundary Desktop. +## Next + +## v1.2.1 [CLI 0.5.0] (2021.08.03) + +### New + +- Add secret toggle capability to connection details dialog. ([PR](https://github.com/hashicorp/boundary-ui/pull/637)) + ## v1.2.0 [CLI 0.4.0] (2021.06.29) ### New From a19aa2ff0ccc795e64b6880109d44b525ad8a6da Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 3 Aug 2021 13:11:21 -0400 Subject: [PATCH 67/68] chore: Refactor cli version into it's own file In addition, fail cli setup step for desktop build when cli cannot be downloaded and extracted successfully --- ui/desktop/electron-app/config/cli.js | 22 ++++++++++++++++------ ui/desktop/electron-app/config/cli/VERSION | 1 + 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 ui/desktop/electron-app/config/cli/VERSION diff --git a/ui/desktop/electron-app/config/cli.js b/ui/desktop/electron-app/config/cli.js index e9b5a6a12..a07585ae0 100644 --- a/ui/desktop/electron-app/config/cli.js +++ b/ui/desktop/electron-app/config/cli.js @@ -5,7 +5,6 @@ const https = require('https'); const decompress = require('decompress'); const { isMac, isWindows } = require('../src/helpers/platform.js'); -const artifactVersion = '0.4.0'; const artifactDestination = path.resolve(__dirname, '..', 'cli'); const downloadArtifact = (version) => { @@ -28,11 +27,13 @@ const downloadArtifact = (version) => { console.log('Create tmp artifact directory: ', tmpDir); const artifactFileName = url.split('/').pop(); - if (!artifactFileName) reject('Could not find artifact filename in: ', url); + if (!artifactFileName) + reject(`Could not find artifact filename in: ${url}.`); const artifactPath = path.resolve(tmpDir, artifactFileName); console.log('Download artifact url: ', url); https.get(url, (response) => { + if (response.statusCode > 400) reject('Could not access artifact url.'); const stream = response.pipe(fs.createWriteStream(artifactPath)); stream.on('close', () => resolve(artifactPath)); stream.on('error', reject); @@ -52,7 +53,16 @@ module.exports = { console.warn('WARNING: Bypassing cli setup'); return; } - const artifactPath = await downloadArtifact(artifactVersion); - await extract(artifactPath, artifactDestination); - } -} + try { + const artifactVersion = await fs.promises.readFile( + path.resolve(__dirname, 'cli', 'VERSION'), + 'utf8' + ); + const artifactPath = await downloadArtifact(artifactVersion); + await extract(artifactPath, artifactDestination); + } catch (e) { + console.error('ERROR: Failed setting up CLI.', e); + process.exit(1); + } + }, +}; diff --git a/ui/desktop/electron-app/config/cli/VERSION b/ui/desktop/electron-app/config/cli/VERSION new file mode 100644 index 000000000..60a2d3e96 --- /dev/null +++ b/ui/desktop/electron-app/config/cli/VERSION @@ -0,0 +1 @@ +0.4.0 \ No newline at end of file From 76e721bd915fcd13b9103671dbed22b7b4beed8c Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 3 Aug 2021 13:16:10 -0400 Subject: [PATCH 68/68] chore: Check for http error status codes including 400 --- ui/desktop/electron-app/config/cli.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/desktop/electron-app/config/cli.js b/ui/desktop/electron-app/config/cli.js index a07585ae0..c2f06d13d 100644 --- a/ui/desktop/electron-app/config/cli.js +++ b/ui/desktop/electron-app/config/cli.js @@ -33,7 +33,7 @@ const downloadArtifact = (version) => { const artifactPath = path.resolve(tmpDir, artifactFileName); console.log('Download artifact url: ', url); https.get(url, (response) => { - if (response.statusCode > 400) reject('Could not access artifact url.'); + if (response.statusCode >= 400) reject('Could not access artifact url.'); const stream = response.pipe(fs.createWriteStream(artifactPath)); stream.on('close', () => resolve(artifactPath)); stream.on('error', reject);