feat: 🎸 rdp form - create and update
This commit is contained in:
1 parent
d2d351c9f7
commit
30a5f2a701
12 files changed
+372
-15
No files matched your search
@@ -44,7 +44,8 @@ export default class TargetAbility extends ModelAbility {
|
||||
*/
|
||||
get canAddInjectedApplicationCredentialSources() {
|
||||
return (
|
||||
this.model.isSSH && this.hasAuthorizedAction('add-credential-sources')
|
||||
(this.model.isSSH || this.model.isRDP) &&
|
||||
this.hasAuthorizedAction('add-credential-sources')
|
||||
);
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -750,6 +750,7 @@ target:
|
||||
default_client_port:
|
||||
label: Default Client Port
|
||||
help: The local proxy port on which to listen by default when a session is started on a client.
|
||||
rdp-windows-error: 'Note: Windows OS prevents port 3389 from being used.'
|
||||
sidebar:
|
||||
label: Session Recording
|
||||
help: Record SSH sessions on this target and save them to a storage bucket.
|
||||
@@ -812,6 +813,10 @@ target:
|
||||
add:
|
||||
title: Add Injected Application Credential Sources
|
||||
description: Select injected Application credential sources to assign to this target.
|
||||
alert:
|
||||
title: Cannot connect to this target without injected application credentials
|
||||
description: Injected application credentials are used by Boundary to sign in to remote resources without showing them to the end-user.
|
||||
action: Add injected application credentials
|
||||
workers:
|
||||
description: You can customize how your workers route traffic to this target by setting up a filter that matches specific worker tags. If your target is in a private network, we recommend setting up an egress filter to specify a worker inside the network so that Boundary can access the host. Ingress and egress filters are allowed to select the same worker.
|
||||
messages:
|
||||
|
||||
@@ -3,6 +3,31 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
}}
|
||||
|
||||
{{#if this.showInjectedApplicationCredentialAlert}}
|
||||
<Hds::Alert
|
||||
data-test-injected-application-credential-alert
|
||||
class='injected-app-credential-alert'
|
||||
@type='inline'
|
||||
@color='critical'
|
||||
as |A|
|
||||
>
|
||||
<A.Title>{{t
|
||||
'resources.target.injected-application-credential-source.messages.alert.title'
|
||||
}}</A.Title>
|
||||
<A.Description>{{t
|
||||
'resources.target.injected-application-credential-source.messages.alert.description'
|
||||
}}</A.Description>
|
||||
<A.Button
|
||||
@color='secondary'
|
||||
@text={{t
|
||||
'resources.target.injected-application-credential-source.messages.alert.action'
|
||||
}}
|
||||
@route='scopes.scope.targets.target.add-injected-application-credential-sources'
|
||||
@model={{@model}}
|
||||
/>
|
||||
</Hds::Alert>
|
||||
{{/if}}
|
||||
|
||||
<Rose::Form
|
||||
class={{unless @model.isNew 'full-width'}}
|
||||
@onSubmit={{@submit}}
|
||||
@@ -52,7 +77,7 @@
|
||||
{{/if}}
|
||||
</Hds::Form::Textarea::Field>
|
||||
|
||||
{{#if (and @model.isNew (feature-flag 'ssh-target'))}}
|
||||
{{#if this.showTargetTypeRadioGroup}}
|
||||
<Hds::Form::RadioCard::Group
|
||||
@name={{t 'form.type.label'}}
|
||||
@alignment='center'
|
||||
@@ -144,22 +169,28 @@
|
||||
<Hds::Form::TextInput::Field
|
||||
@isOptional={{true}}
|
||||
@value={{@model.default_client_port}}
|
||||
@isInvalid={{@model.errors.default_client_port}}
|
||||
@isInvalid={{this.showDefaultClientPortError}}
|
||||
@type='text'
|
||||
name='default_client_port'
|
||||
disabled={{form.disabled}}
|
||||
{{on 'input' (set-from-event @model 'default_client_port')}}
|
||||
{{on 'blur' this.handleDefaultClientPortBlur}}
|
||||
as |F|
|
||||
>
|
||||
<F.Label>{{t 'resources.target.form.default_client_port.label'}}</F.Label>
|
||||
<F.HelperText>{{t
|
||||
'resources.target.form.default_client_port.help'
|
||||
}}</F.HelperText>
|
||||
{{#if @model.errors.default_client_port}}
|
||||
{{#if this.showDefaultClientPortError}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.default_client_port as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
{{#if this.showRDPWindowsDefaultClientPortError}}
|
||||
<E.Message data-test-error-message-default-client-port-rdp-windows>
|
||||
{{t 'resources.target.form.default_client_port.rdp-windows-error'}}
|
||||
</E.Message>
|
||||
{{/if}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</Hds::Form::TextInput::Field>
|
||||
|
||||
@@ -4,17 +4,33 @@
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { TYPES_TARGET } from 'api/models/target';
|
||||
import {
|
||||
TYPE_TARGET_TCP,
|
||||
TYPE_TARGET_RDP,
|
||||
TYPE_TARGET_SSH,
|
||||
} from 'api/models/target';
|
||||
import { service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
// NOTE: this is all a temporary solution till we have a resource type helper.
|
||||
const types = [...TYPES_TARGET].reverse();
|
||||
const icons = {
|
||||
ssh: 'terminal-screen',
|
||||
tcp: 'network',
|
||||
rdp: 'monitor',
|
||||
};
|
||||
const RDP_WINDOWS_INVALID_DEFAULT_CLIENT_PORT = '3389';
|
||||
|
||||
export default class FormTargetComponent extends Component {
|
||||
// attributes
|
||||
|
||||
/**
|
||||
* Flag to show the RDP Windows default client port error.
|
||||
* This is set to true when the default client port is '3389' for RDP targets.
|
||||
* It is used to indicate that the default client port is not recommended for Windows RDP targets.
|
||||
* @type {boolean}
|
||||
*/
|
||||
@tracked showRDPWindowsDefaultClientPortError = false;
|
||||
|
||||
// =services
|
||||
|
||||
@service features;
|
||||
@@ -24,6 +40,10 @@ export default class FormTargetComponent extends Component {
|
||||
* @type {object}
|
||||
*/
|
||||
get typeMetas() {
|
||||
const types = [TYPE_TARGET_TCP];
|
||||
if (this.isSSHEnabled) types.push(TYPE_TARGET_SSH);
|
||||
if (this.isRDPEnabled) types.push(TYPE_TARGET_RDP);
|
||||
|
||||
return types.map((type) => ({
|
||||
type,
|
||||
icon: icons[type],
|
||||
@@ -38,4 +58,61 @@ export default class FormTargetComponent extends Component {
|
||||
get icon() {
|
||||
return icons[this.args.model.type];
|
||||
}
|
||||
|
||||
get isRDPEnabled() {
|
||||
return this.features.isEnabled('rdp-target');
|
||||
}
|
||||
|
||||
get isSSHEnabled() {
|
||||
return this.features.isEnabled('ssh-target');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the default client port error should be shown.
|
||||
* This is true if either the default client port `3389` error is shown or there is an error on the default client port field.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get showDefaultClientPortError() {
|
||||
return (
|
||||
this.showRDPWindowsDefaultClientPortError ||
|
||||
this.args.model.get('errors.default_client_port')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the injected application credential alert should be shown for SSH and RDP targets.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get showInjectedApplicationCredentialAlert() {
|
||||
return (
|
||||
!this.args.model.isNew &&
|
||||
this.args.model.injected_application_credential_source_ids.length === 0 &&
|
||||
this.args.model.type !== TYPE_TARGET_TCP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the target type radio group should be displayed.
|
||||
* This is true if either the 'rdp-target' or 'ssh-target' feature is enabled.
|
||||
* @returns {boolean}
|
||||
* @type {boolean}
|
||||
*/
|
||||
get showTargetTypeRadioGroup() {
|
||||
return (this.isRDPEnabled || this.isSSHEnabled) && this.args.model.isNew;
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
* Validates the default client port for the target.
|
||||
* If the target type is RDP and the default client port is set to '3389', it sets the error flag.
|
||||
* @param {Event} event
|
||||
*/
|
||||
@action
|
||||
handleDefaultClientPortBlur(event) {
|
||||
const defaultClientPort = event.target.value;
|
||||
this.showRDPWindowsDefaultClientPortError =
|
||||
defaultClientPort === RDP_WINDOWS_INVALID_DEFAULT_CLIENT_PORT &&
|
||||
this.args.model.type === TYPE_TARGET_RDP;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
}}
|
||||
|
||||
<Form::Target::Details
|
||||
@model={{@model}}
|
||||
@defaultPort='3389'
|
||||
@submit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@changeType={{@changeType}}
|
||||
@globalScope={{@globalScope}}
|
||||
/>
|
||||
@@ -16,7 +16,7 @@
|
||||
<nav.link @route='scopes.scope.targets.target.brokered-credential-sources'>
|
||||
{{t 'resources.target.brokered-credential-source.title_plural'}}
|
||||
</nav.link>
|
||||
{{#if @model.isSSH}}
|
||||
{{#if (or @model.isSSH @model.isRDP)}}
|
||||
<nav.link
|
||||
@route='scopes.scope.targets.target.injected-application-credential-sources'
|
||||
>
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
|
||||
import Route from '@ember/routing/route';
|
||||
import { service } from '@ember/service';
|
||||
import { TYPE_TARGET_TCP, TYPE_TARGET_SSH } from 'api/models/target';
|
||||
import {
|
||||
TYPE_TARGET_TCP,
|
||||
TYPE_TARGET_SSH,
|
||||
TYPE_TARGET_RDP,
|
||||
} from 'api/models/target';
|
||||
|
||||
export default class ScopesScopeTargetsNewRoute extends Route {
|
||||
// =services
|
||||
@@ -47,11 +51,16 @@ export default class ScopesScopeTargetsNewRoute extends Route {
|
||||
let name, description;
|
||||
const scopeModel = this.modelFor('scopes.scope');
|
||||
|
||||
// default type is SSH if the feature is enabled, otherwise TCP
|
||||
if (!type)
|
||||
type = this.features.isEnabled('ssh-target')
|
||||
? TYPE_TARGET_SSH
|
||||
: TYPE_TARGET_TCP;
|
||||
// default type is RDP if the feature is enabled, or is SSH if feature enabled otherwise TCP
|
||||
if (!type) {
|
||||
if (this.features.isEnabled('rdp-target')) {
|
||||
type = TYPE_TARGET_RDP;
|
||||
} else if (this.features.isEnabled('ssh-target')) {
|
||||
type = TYPE_TARGET_SSH;
|
||||
} else {
|
||||
type = TYPE_TARGET_TCP;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.currentModel?.isNew) {
|
||||
({ name, description } = this.currentModel);
|
||||
|
||||
@@ -1020,3 +1020,8 @@
|
||||
.dropdown-checkbox-list {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
// target
|
||||
.injected-app-credential-alert {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@@ -10,13 +10,18 @@ import {
|
||||
fillIn,
|
||||
getContext,
|
||||
visit,
|
||||
blur,
|
||||
} from '@ember/test-helpers';
|
||||
import { setupApplicationTest } from 'admin/tests/helpers';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { Response } from 'miragejs';
|
||||
import { authenticateSession } from 'ember-simple-auth/test-support';
|
||||
import { TYPE_TARGET_SSH, TYPE_TARGET_TCP } from 'api/models/target';
|
||||
import { setupSqlite } from 'api/test-support/helpers/sqlite';
|
||||
import {
|
||||
TYPE_TARGET_TCP,
|
||||
TYPE_TARGET_SSH,
|
||||
TYPE_TARGET_RDP,
|
||||
} from 'api/models/target';
|
||||
import { setupIntl } from 'ember-intl/test-support';
|
||||
import * as commonSelectors from 'admin/tests/helpers/selectors';
|
||||
import * as selectors from './selectors';
|
||||
@@ -32,6 +37,7 @@ module('Acceptance | targets | create', function (hooks) {
|
||||
let getTCPTargetCount;
|
||||
let getSSHTargetCount;
|
||||
let featuresService;
|
||||
let getRDPTargetCount;
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
@@ -48,6 +54,7 @@ module('Acceptance | targets | create', function (hooks) {
|
||||
newTarget: null,
|
||||
newTCPTarget: null,
|
||||
newSSHTarget: null,
|
||||
newRDPTarget: null,
|
||||
};
|
||||
|
||||
hooks.beforeEach(async function () {
|
||||
@@ -72,12 +79,15 @@ module('Acceptance | targets | create', function (hooks) {
|
||||
urls.newTarget = `${urls.targets}/new`;
|
||||
urls.newTCPTarget = `${urls.targets}/new?type=tcp`;
|
||||
urls.newSSHTarget = `${urls.targets}/new?type=ssh`;
|
||||
urls.newRDPTarget = `${urls.targets}/new?type=rdp`;
|
||||
// Generate resource counter
|
||||
getTargetCount = () => this.server.schema.targets.all().models.length;
|
||||
getSSHTargetCount = () =>
|
||||
this.server.schema.targets.where({ type: TYPE_TARGET_SSH }).models.length;
|
||||
getTCPTargetCount = () =>
|
||||
this.server.schema.targets.where({ type: TYPE_TARGET_TCP }).models.length;
|
||||
getRDPTargetCount = () =>
|
||||
this.server.schema.targets.where({ type: TYPE_TARGET_RDP }).models.length;
|
||||
await authenticateSession({});
|
||||
});
|
||||
|
||||
@@ -505,4 +515,115 @@ module('Acceptance | targets | create', function (hooks) {
|
||||
);
|
||||
assert.strictEqual(currentURL(), urls.targets);
|
||||
});
|
||||
|
||||
test('defaults to type `rdp` when no query param provided and rdp feature is enabled', async function (assert) {
|
||||
featuresService.enable('rdp-target');
|
||||
await visit(urls.targets);
|
||||
|
||||
await click(commonSelectors.HREF(urls.newTarget));
|
||||
|
||||
assert.dom(selectors.FIELD_TYPE_CHECKED).hasValue(TYPE_TARGET_RDP);
|
||||
});
|
||||
|
||||
test('cannot navigate to new RDP targets route when rdp feature is disabled', async function (assert) {
|
||||
await visit(urls.targets);
|
||||
|
||||
await click(commonSelectors.HREF(urls.newTarget));
|
||||
|
||||
assert.false(featuresService.isEnabled('rdp-target'));
|
||||
assert.true(
|
||||
instances.scopes.project.authorized_collection_actions.targets.includes(
|
||||
'create',
|
||||
),
|
||||
);
|
||||
assert.dom(selectors.FIELD_INFO).isVisible({ count: 1 });
|
||||
assert.dom(selectors.FIELD_INFO_LABEL).includesText('TCP');
|
||||
});
|
||||
|
||||
test('default port is not marked required for RDP targets', async function (assert) {
|
||||
featuresService.enable('rdp-target');
|
||||
await visit(urls.targets);
|
||||
|
||||
await click(commonSelectors.HREF(urls.newTarget));
|
||||
|
||||
assert.dom(selectors.FIELD_DEFAULT_PORT_LABEL).includesText('Optional');
|
||||
});
|
||||
|
||||
test('can cancel create new RDP target', async function (assert) {
|
||||
featuresService.enable('rdp-target');
|
||||
const targetCount = getTargetCount();
|
||||
const rdpTargetCount = getRDPTargetCount();
|
||||
await visit(urls.targets);
|
||||
|
||||
await click(commonSelectors.HREF(urls.newTarget));
|
||||
await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
|
||||
await click(selectors.FIELD_TYPE_VALUE('rdp'));
|
||||
await click(commonSelectors.CANCEL_BTN);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.targets);
|
||||
assert.strictEqual(getTargetCount(), targetCount);
|
||||
assert.strictEqual(getRDPTargetCount(), rdpTargetCount);
|
||||
});
|
||||
|
||||
test('can create a type `rdp` target', async function (assert) {
|
||||
featuresService.enable('rdp-target');
|
||||
|
||||
const targetCount = getTargetCount();
|
||||
const rdpTargetCount = getRDPTargetCount();
|
||||
await visit(urls.targets);
|
||||
|
||||
await click(commonSelectors.HREF(urls.newTarget));
|
||||
await click(selectors.FIELD_TYPE_VALUE('rdp'));
|
||||
await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
|
||||
await fillIn(selectors.FIELD_DEFAULT_CLIENT_PORT, '3389');
|
||||
await blur(selectors.FIELD_DEFAULT_CLIENT_PORT);
|
||||
|
||||
assert
|
||||
.dom(selectors.FIELD_DEFAULT_CLIENT_PORT_RDP_WINDOWS_ERROR)
|
||||
.hasText('Note: Windows OS prevents port 3389 from being used.');
|
||||
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
|
||||
assert.strictEqual(getRDPTargetCount(), rdpTargetCount + 1);
|
||||
assert.strictEqual(getTargetCount(), targetCount + 1);
|
||||
assert.strictEqual(
|
||||
this.server.schema.targets.all().models[getTargetCount() - 1].name,
|
||||
commonSelectors.FIELD_NAME_VALUE,
|
||||
);
|
||||
assert.strictEqual(
|
||||
this.server.schema.targets.all().models[getTargetCount() - 1].attributes
|
||||
.default_client_port,
|
||||
3389,
|
||||
);
|
||||
});
|
||||
|
||||
test('saving a new RDP target with invalid fields displays error messages', async function (assert) {
|
||||
this.server.post('/targets', () => {
|
||||
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.newRDPTarget);
|
||||
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
|
||||
assert
|
||||
.dom(commonSelectors.ALERT_TOAST_BODY)
|
||||
.hasText('The request was invalid.');
|
||||
assert.dom(selectors.FIELD_NAME_ERROR).hasText('Name is required.');
|
||||
});
|
||||
});
|
||||
@@ -24,6 +24,9 @@ export const FIELD_ENABLE_RECORDING_TOGGLE =
|
||||
'[name=target-enable-session-recording]';
|
||||
export const FIELD_ADD_NEW_STORAGE_BUCKET_LINK =
|
||||
'.enable-session-recording-toggle .hds-link-standalone';
|
||||
export const FIELD_DEFAULT_CLIENT_PORT_RDP_WINDOWS_ERROR =
|
||||
'[data-test-error-message-default-client-port-rdp-windows';
|
||||
export const FIELD_DEFAULT_CLIENT_PORT = '[name="default_client_port"]';
|
||||
|
||||
export const NEW_TARGET_BTN = '[data-test-new-target-button]';
|
||||
export const MANAGE_DROPDOWN = '[data-test-manage-targets-dropdown] button';
|
||||
@@ -68,3 +71,7 @@ export const WORKERS_ACCORDION_DROPDOWN = (name) =>
|
||||
`[data-test-target-${name}-workers-accordion-item] .hds-accordion-item__button`;
|
||||
export const WORKERS_ACCORDION_DROPDOWN_LINK = (name) =>
|
||||
`[data-test-target-${name}-workers-accordion-item] a`;
|
||||
export const ALERT_INJECTED_APPLICATION_CREDENTIAL =
|
||||
'[data-test-injected-application-credential-alert]';
|
||||
export const ALERT_INJECTED_APPLICATION_CREDENTIAL_ADD_BTN =
|
||||
'[data-test-injected-application-credential-alert] .hds-alert__actions a';
|
||||
@@ -14,6 +14,7 @@ import { authenticateSession } from 'ember-simple-auth/test-support';
|
||||
import * as commonSelectors from 'admin/tests/helpers/selectors';
|
||||
import * as selectors from './selectors';
|
||||
import { setRunOptions } from 'ember-a11y-testing/test-support';
|
||||
import { TYPE_TARGET_RDP, TYPE_TARGET_SSH } from 'api/models/target';
|
||||
|
||||
module('Acceptance | targets | update', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
@@ -30,11 +31,15 @@ module('Acceptance | targets | update', function (hooks) {
|
||||
project: null,
|
||||
},
|
||||
target: null,
|
||||
rdpTarget: null,
|
||||
sshTarget: null,
|
||||
};
|
||||
const urls = {
|
||||
projectScope: null,
|
||||
targets: null,
|
||||
target: null,
|
||||
rdpTarget: null,
|
||||
sshTarget: null,
|
||||
};
|
||||
|
||||
hooks.beforeEach(async function () {
|
||||
@@ -52,10 +57,22 @@ module('Acceptance | targets | update', function (hooks) {
|
||||
instances.target = this.server.create('target', {
|
||||
scope: instances.scopes.project,
|
||||
});
|
||||
instances.rdpTarget = this.server.create('target', {
|
||||
type: TYPE_TARGET_RDP,
|
||||
scope: instances.scopes.project,
|
||||
injected_application_credential_source_ids: [],
|
||||
});
|
||||
instances.sshTarget = this.server.create('target', {
|
||||
type: TYPE_TARGET_SSH,
|
||||
scope: instances.scopes.project,
|
||||
injected_application_credential_source_ids: [],
|
||||
});
|
||||
// Generate route URLs for resources
|
||||
urls.projectScope = `/scopes/${instances.scopes.project.id}`;
|
||||
urls.targets = `${urls.projectScope}/targets`;
|
||||
urls.target = `${urls.targets}/${instances.target.id}`;
|
||||
urls.rdpTarget = `${urls.targets}/${instances.rdpTarget.id}`;
|
||||
urls.sshTarget = `${urls.targets}/${instances.sshTarget.id}`;
|
||||
|
||||
await authenticateSession({});
|
||||
});
|
||||
@@ -344,4 +361,53 @@ module('Acceptance | targets | update', function (hooks) {
|
||||
);
|
||||
assert.true(this.server.schema.targets.find(target.id).hostSets.length > 0);
|
||||
});
|
||||
|
||||
test('can save changes to existing rdp target', async function (assert) {
|
||||
featuresService.enable('rdp-target');
|
||||
featuresService.enable('ssh-target');
|
||||
|
||||
await visit(urls.targets);
|
||||
|
||||
await click(commonSelectors.HREF(urls.rdpTarget));
|
||||
|
||||
assert
|
||||
.dom(selectors.ALERT_INJECTED_APPLICATION_CREDENTIAL)
|
||||
.exists('Injected application credential alert is displayed');
|
||||
assert
|
||||
.dom(selectors.ALERT_INJECTED_APPLICATION_CREDENTIAL_ADD_BTN)
|
||||
.hasAttribute(
|
||||
'href',
|
||||
`${urls.rdpTarget}/add-injected-application-credential-sources`,
|
||||
);
|
||||
|
||||
await click(commonSelectors.EDIT_BTN, 'Activate edit mode');
|
||||
await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.rdpTarget);
|
||||
assert.strictEqual(
|
||||
this.server.schema.targets.where({ type: TYPE_TARGET_RDP }).models[0]
|
||||
.name,
|
||||
commonSelectors.FIELD_NAME_VALUE,
|
||||
);
|
||||
});
|
||||
|
||||
test('displays add injected credentials alert for ssh target', async function (assert) {
|
||||
featuresService.enable('ssh-target');
|
||||
|
||||
await visit(urls.targets);
|
||||
|
||||
await click(commonSelectors.HREF(urls.sshTarget));
|
||||
|
||||
assert
|
||||
.dom(selectors.ALERT_INJECTED_APPLICATION_CREDENTIAL)
|
||||
.exists('Injected application credential alert is displayed');
|
||||
|
||||
await click(selectors.ALERT_INJECTED_APPLICATION_CREDENTIAL_ADD_BTN);
|
||||
|
||||
assert.strictEqual(
|
||||
currentURL(),
|
||||
`${urls.sshTarget}/add-injected-application-credential-sources`,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
|
||||
module(
|
||||
'Unit | Controller | scopes/scope/targets/target/index',
|
||||
function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let controller = this.owner.lookup(
|
||||
'controller:scopes/scope/targets/target/index',
|
||||
);
|
||||
assert.ok(controller);
|
||||
assert.ok(controller.targets);
|
||||
});
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user