2023-03-01 09:39:41 -06:00
/**
* Copyright (c) HashiCorp, Inc.
2024-05-31 11:29:24 -07:00
* SPDX-License-Identifier: BUSL-1.1
2023-03-01 09:39:41 -06:00
*/
2021-08-16 16:12:55 -04:00
import { module , test } from 'qunit' ;
2024-11-08 15:12:43 -06:00
import { visit , click , fillIn , currentURL , select } from '@ember/test-helpers' ;
2024-12-02 12:51:24 -06:00
import { setupApplicationTest } from 'admin/tests/helpers' ;
2025-08-26 11:31:30 -07:00
import { setupSqlite } from 'api/test-support/helpers/sqlite' ;
2021-08-16 16:12:55 -04:00
import { Response } from 'miragejs' ;
2025-11-14 15:49:32 -08:00
import { faker } from '@faker-js/faker' ;
2025-08-04 15:34:18 -05:00
import {
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE ,
TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP ,
} from 'api/models/credential-library' ;
2024-11-08 15:12:43 -06:00
import * as selectors from './selectors' ;
import * as commonSelectors from 'admin/tests/helpers/selectors' ;
2025-08-11 11:04:07 -07:00
import { setRunOptions } from 'ember-a11y-testing/test-support' ;
2025-11-14 15:49:32 -08:00
import { options } from 'api/models/credential-library' ;
2021-08-16 16:12:55 -04:00
2021-09-01 19:38:48 -07:00
module ( 'Acceptance | credential-libraries | create' , function ( hooks ) {
2021-08-16 16:12:55 -04:00
setupApplicationTest ( hooks );
2025-08-26 11:31:30 -07:00
setupSqlite ( hooks );
2021-08-16 16:12:55 -04:00
2023-03-31 17:38:17 -07:00
let featuresService ;
2021-08-16 16:12:55 -04:00
let getCredentialLibraryCount ;
2025-11-14 15:49:32 -08:00
let getTypeCredentialLibraryCount ;
2021-08-16 16:12:55 -04:00
const instances = {
scopes : {
org : null ,
project : null ,
},
};
const urls = {
globalScope : null ,
orgScope : null ,
projectScope : null ,
credentialStores : null ,
credentialStore : null ,
credentialLibrary : null ,
credentialLibraries : null ,
newCredentialLibrary : null ,
};
2024-12-03 10:27:27 -08:00
hooks . beforeEach ( async function () {
2021-08-16 16:12:55 -04:00
// Generate resources
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 ,
credentialStore : instances . credentialStore ,
2022-06-28 19:30:26 -04:00
http_method : 'GET' ,
2021-08-16 16:12:55 -04:00
});
// 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 } ` ;
urls . newCredentialLibrary = ` ${ urls . credentialLibraries } /new` ;
// Generate resource counter
getCredentialLibraryCount = () =>
this . server . schema . credentialLibraries . all (). models . length ;
2025-11-14 15:49:32 -08:00
getTypeCredentialLibraryCount = ( credentialType ) => {
return this . server . schema . credentialLibraries . where ({ credentialType })
. length ;
2025-06-17 11:24:19 -07:00
};
2023-03-31 17:38:17 -07:00
featuresService = this . owner . lookup ( 'service:features' );
2021-08-16 16:12:55 -04:00
});
2024-11-08 15:12:43 -06:00
2021-08-16 16:12:55 -04:00
test ( 'visiting credential libraries' , async function ( assert ) {
2025-08-11 11:04:07 -07:00
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-01
enabled : false ,
},
},
});
2021-08-16 16:12:55 -04:00
await visit ( urls . credentialLibraries );
2024-11-08 15:12:43 -06:00
2022-07-07 11:18:51 -07:00
assert . strictEqual ( currentURL (), urls . credentialLibraries );
2024-11-08 15:12:43 -06:00
2021-08-16 16:12:55 -04:00
await visit ( urls . credentialLibrary );
2024-11-08 15:12:43 -06:00
2022-07-07 11:18:51 -07:00
assert . strictEqual ( currentURL (), urls . credentialLibrary );
2021-08-16 16:12:55 -04:00
});
2025-11-14 15:49:32 -08:00
test . each (
'can create a new credential library with credential type for vault generic' ,
options . credential_types ,
async function ( assert , type ) {
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-26
enabled : false ,
},
2025-08-11 11:04:07 -07:00
},
2025-11-14 15:49:32 -08:00
});
const credentialLibraryCount = getCredentialLibraryCount ();
const typeCredentialLibraryCount = getTypeCredentialLibraryCount ( type );
await visit ( urls . newCredentialLibrary );
await fillIn (
selectors . FIELD_VAULT_PATH ,
selectors . FIELD_VAULT_PATH_VALUE ,
);
await fillIn (
commonSelectors . FIELD_NAME ,
commonSelectors . FIELD_NAME_VALUE ,
);
await select ( selectors . FIELD_CRED_TYPE , type );
const credentialMappingOverrides = {};
options . mapping_overrides [ type ]. forEach ( async ( overrideField ) => {
const randName = faker . word . words ();
credentialMappingOverrides [ overrideField ] = randName ;
await fillIn (
selectors . FIELD_CRED_MAP_OVERRIDES ( overrideField ),
randName ,
);
});
await click ( commonSelectors . SAVE_BTN );
assert . strictEqual (
getCredentialLibraryCount (),
credentialLibraryCount + 1 ,
);
assert . strictEqual (
getTypeCredentialLibraryCount (),
typeCredentialLibraryCount + 1 ,
);
const credentialLibrary = this . server . schema . credentialLibraries . findBy ({
credentialType : type ,
});
assert . strictEqual (
credentialLibrary . name ,
commonSelectors . FIELD_NAME_VALUE ,
);
assert . strictEqual ( credentialLibrary . credentialType , type );
assert . deepEqual (
credentialLibrary . credentialMappingOverrides ,
credentialMappingOverrides ,
);
},
);
2025-06-17 11:24:19 -07:00
2023-02-01 13:46:23 -05:00
test ( 'can create a new credential library of type vault ssh cert' , async function ( assert ) {
2025-08-11 11:04:07 -07:00
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-01
enabled : false ,
},
},
});
2023-03-31 17:38:17 -07:00
featuresService . enable ( 'ssh-target' );
2023-02-01 13:46:23 -05:00
const count = getCredentialLibraryCount ();
await visit ( urls . newCredentialLibrary );
2024-11-08 15:12:43 -06:00
await click ( selectors . TYPE_VAULT_SSH_CERT );
await fillIn ( commonSelectors . FIELD_NAME , commonSelectors . FIELD_NAME_VALUE );
2023-02-01 13:46:23 -05:00
await fillIn (
2024-11-08 15:12:43 -06:00
commonSelectors . FIELD_DESCRIPTION ,
commonSelectors . FIELD_DESCRIPTION_VALUE ,
2023-02-01 13:46:23 -05:00
);
2024-11-08 15:12:43 -06:00
await fillIn ( selectors . FIELD_VAULT_PATH , selectors . FIELD_VAULT_PATH_VALUE );
await fillIn ( selectors . FIELD_USERNAME , selectors . FIELD_USERNAME_VALUE );
await fillIn ( selectors . FIELD_KEY_TYPE , selectors . FIELD_KEY_TYPE_VALUE );
await fillIn ( selectors . FIELD_KEY_BITS , selectors . FIELD_KEY_BITS_VALUE );
await fillIn ( selectors . FIELD_TTL , selectors . FIELD_TTL_VALUE );
await fillIn ( selectors . FIELD_KEY_ID , selectors . FIELD_KEY_ID_VALUE );
await fillIn ( selectors . FIELD_CRIT_OPTS_KEY , 'co_key' );
await fillIn ( selectors . FIELD_CRIT_OPTS_VALUE , 'co_value' );
await click ( selectors . FIELD_CRIT_OPTS_BTN );
await fillIn ( selectors . FIELD_EXT_KEY , 'ext_key' );
await fillIn ( selectors . FIELD_EXT_VALUE , 'ext_value' );
await click ( selectors . FIELD_EXT_BTN );
await click ( commonSelectors . SAVE_BTN );
2023-02-01 13:46:23 -05:00
assert . strictEqual ( getCredentialLibraryCount (), count + 1 );
assert . strictEqual (
this . server . schema . credentialLibraries . where ({
type : TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE ,
}). length ,
2023-11-22 14:07:41 -05:00
1 ,
2023-02-01 13:46:23 -05:00
);
const credentialLibrary = this . server . schema . credentialLibraries . findBy ({
type : TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE ,
});
2024-11-08 15:12:43 -06:00
assert . strictEqual (
credentialLibrary . name ,
commonSelectors . FIELD_NAME_VALUE ,
);
assert . strictEqual (
credentialLibrary . description ,
commonSelectors . FIELD_DESCRIPTION_VALUE ,
);
assert . strictEqual (
credentialLibrary . attributes . path ,
selectors . FIELD_VAULT_PATH_VALUE ,
);
assert . strictEqual (
credentialLibrary . attributes . username ,
selectors . FIELD_USERNAME_VALUE ,
);
assert . strictEqual (
credentialLibrary . attributes . key_type ,
selectors . FIELD_KEY_TYPE_VALUE ,
);
assert . strictEqual (
credentialLibrary . attributes . key_bits ,
selectors . FIELD_KEY_BITS_VALUE ,
);
assert . strictEqual (
credentialLibrary . attributes . ttl ,
selectors . FIELD_TTL_VALUE ,
);
assert . strictEqual (
credentialLibrary . attributes . key_id ,
selectors . FIELD_KEY_ID_VALUE ,
);
2023-02-01 13:46:23 -05:00
assert . deepEqual ( credentialLibrary . attributes . critical_options , {
co_key : 'co_value' ,
});
assert . deepEqual ( credentialLibrary . attributes . extensions , {
ext_key : 'ext_value' ,
});
});
test ( 'ecdsa and rsa key types bring up a key bits field' , async function ( assert ) {
2025-08-11 11:04:07 -07:00
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-01
enabled : false ,
},
},
});
2023-03-31 17:38:17 -07:00
featuresService . enable ( 'ssh-target' );
2023-02-01 13:46:23 -05:00
await visit ( urls . newCredentialLibrary );
2024-11-08 15:12:43 -06:00
await click ( selectors . TYPE_VAULT_SSH_CERT );
await select ( selectors . FIELD_KEY_TYPE , 'ed25519' );
assert . dom ( selectors . FIELD_KEY_BITS ). doesNotExist ();
await select ( selectors . FIELD_KEY_TYPE , 'ecdsa' );
assert . dom ( selectors . FIELD_KEY_BITS ). isVisible ();
await select ( selectors . FIELD_KEY_TYPE , 'rsa' );
assert . dom ( selectors . FIELD_KEY_BITS ). isVisible ();
2023-02-01 13:46:23 -05:00
});
2021-09-01 19:38:48 -07:00
test ( 'Users cannot navigate to new credential library route without proper authorization' , async function ( assert ) {
2025-08-11 11:04:07 -07:00
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-01
enabled : false ,
},
},
});
2021-09-01 19:38:48 -07:00
instances . credentialStore . authorized_collection_actions [
'credential-libraries'
] = [];
2021-11-05 14:23:20 -04:00
await visit ( urls . credentialLibraries );
2025-07-15 14:03:27 -05:00
await click ( selectors . MANAGE_DROPDOWN_CREDENTIAL_STORE );
2024-11-08 15:12:43 -06:00
2021-09-01 19:38:48 -07:00
assert . notOk (
instances . credentialStore . authorized_collection_actions [
'credential-libraries'
2023-11-22 14:07:41 -05:00
]. includes ( 'create' ),
2021-09-01 19:38:48 -07:00
);
2024-11-08 15:12:43 -06:00
assert . dom ( commonSelectors . HREF ( urls . newCredentialLibrary )). doesNotExist ();
2021-09-01 19:38:48 -07:00
});
2021-08-16 16:12:55 -04:00
test ( 'can cancel create a new credential library' , async function ( assert ) {
2025-08-11 11:04:07 -07:00
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-01
enabled : false ,
},
},
});
2021-08-16 16:12:55 -04:00
const count = getCredentialLibraryCount ();
await visit ( urls . newCredentialLibrary );
2024-11-08 15:12:43 -06:00
await fillIn ( commonSelectors . FIELD_NAME , commonSelectors . FIELD_NAME_VALUE );
await click ( commonSelectors . CANCEL_BTN );
2022-07-07 11:18:51 -07:00
assert . strictEqual ( currentURL (), urls . credentialLibraries );
assert . strictEqual ( getCredentialLibraryCount (), count );
2021-08-16 16:12:55 -04:00
});
2023-02-01 13:46:23 -05:00
test ( 'saving a new credential library with invalid fields displays error messages' , async function ( assert ) {
2025-08-11 11:04:07 -07:00
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-01
enabled : false ,
},
},
});
2021-08-16 16:12:55 -04:00
this . server . post ( '/credential-libraries' , () => {
return new Response (
400 ,
{},
{
status : 400 ,
code : 'invalid_argument' ,
message : 'The request was invalid' ,
details : {
request_fields : [
{
2024-12-12 12:26:52 -06:00
name : 'path' ,
description : 'Vault path is required' ,
2021-08-16 16:12:55 -04:00
},
],
},
2023-11-22 14:07:41 -05:00
},
2021-08-16 16:12:55 -04:00
);
});
2024-11-08 15:12:43 -06:00
2021-08-16 16:12:55 -04:00
await visit ( urls . newCredentialLibrary );
2024-11-08 15:12:43 -06:00
await click ( commonSelectors . SAVE_BTN );
assert
. dom ( commonSelectors . ALERT_TOAST_BODY )
. hasText ( 'The request was invalid' );
2024-12-12 12:26:52 -06:00
assert
. dom ( selectors . FIELD_VAULT_PATH_ERROR )
. hasText ( 'Vault path is required' );
2021-08-16 16:12:55 -04:00
});
2023-02-01 13:46:23 -05:00
test ( 'cannot select vault ssh cert when feature is disabled' , async function ( assert ) {
2025-08-11 11:04:07 -07:00
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-01
enabled : false ,
},
},
});
2023-02-01 13:46:23 -05:00
await visit ( urls . newCredentialLibrary );
2024-11-08 15:12:43 -06:00
2023-03-31 17:38:17 -07:00
assert . false ( featuresService . isEnabled ( 'ssh-target' ));
2024-11-08 15:12:43 -06:00
assert . dom ( selectors . TYPE_VAULT_SSH_CERT ). doesNotExist ();
2023-02-01 13:46:23 -05:00
});
2023-11-02 16:08:25 -07:00
test ( 'users cannot directly navigate to new credential library route without proper authorization' , async function ( assert ) {
2025-08-11 11:04:07 -07:00
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-01
enabled : false ,
},
},
});
2023-11-02 16:08:25 -07:00
instances . credentialStore . authorized_collection_actions [
'credential-libraries'
] = instances . credentialStore . authorized_collection_actions [
'credential-libraries'
]. filter (( item ) => item !== 'create' );
await visit ( urls . newCredentialLibrary );
assert . false (
instances . credentialStore . authorized_collection_actions [
'credential-libraries'
2023-11-22 14:07:41 -05:00
]. includes ( 'create' ),
2023-11-02 16:08:25 -07:00
);
assert . strictEqual ( currentURL (), urls . credentialLibraries );
});
2025-08-04 15:34:18 -05:00
test ( 'can create a new credential library of type vault ldap' , async function ( assert ) {
2025-08-28 16:42:39 -07:00
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-26
enabled : false ,
},
},
});
2025-08-04 15:34:18 -05:00
await visit ( urls . newCredentialLibrary );
await click ( selectors . TYPE_VAULT_LDAP );
await fillIn ( selectors . FIELD_VAULT_PATH , selectors . FIELD_VAULT_PATH_VALUE );
await fillIn ( commonSelectors . FIELD_NAME , commonSelectors . FIELD_NAME_VALUE );
await click ( commonSelectors . SAVE_BTN );
assert . strictEqual (
this . server . schema . credentialLibraries . where ({
type : TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP ,
}). length ,
1 ,
);
const credentialLibrary = this . server . schema . credentialLibraries . findBy ({
type : TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP ,
});
assert . strictEqual (
credentialLibrary . name ,
commonSelectors . FIELD_NAME_VALUE ,
);
assert . strictEqual (
credentialLibrary . attributes . path ,
selectors . FIELD_VAULT_PATH_VALUE ,
);
});
test ( 'default `vault-generic` credential library is selected when `ssh-target` feature is not enabled and user manually sets `type` in the query params' , async function ( assert ) {
2025-08-28 16:42:39 -07:00
setRunOptions ({
rules : {
'color-contrast' : {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2025-08-26
enabled : false ,
},
},
});
2025-08-04 15:34:18 -05:00
await visit ( ` ${ urls . newCredentialLibrary } ?type=vault-ssh-certificate` );
assert . dom ( selectors . TYPE_VAULT_SSH_CERT ). isNotVisible ();
assert . dom ( selectors . TYPE_VAULT_LDAP ). isNotChecked ();
assert . dom ( selectors . TYPE_VAULT_GENERIC ). isChecked ();
});
2021-08-16 16:12:55 -04:00
});