Files
threshold-ui/ui/admin/tests/e2e/helpers/boundary-cli.js
T
Stan RyzhovandMichael Li f100190ac1 test: 💍 Add storage policies e2e-test (#2175)
* test: 💍 Add storage policies e2e-test

✅ Closes: ICU-12883

* chore: Adjust required env for e2e-tests

✅ Closes: ICU-12883

* CR: Refactor helper method to pass in env

---------

Co-authored-by: Michael Li <michael.li@hashicorp.com>
2024-03-15 11:55:13 -04:00

633 lines
17 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
/* eslint-disable no-undef */
const { execSync, exec } = require('child_process');
const { nanoid } = require('nanoid');
/**
* Checks that the boundary cli is available
*/
exports.checkBoundaryCli = async () => {
try {
execSync('which boundary');
} catch (e) {
throw new Error('boundary does not exist on the path');
}
};
/**
* Uses the boundary CLI to authenticate to the specified Boundary instance
*/
exports.authenticateBoundaryCli = async () => {
try {
execSync(
'boundary authenticate password' +
' -addr=' +
process.env.BOUNDARY_ADDR +
' -auth-method-id=' +
process.env.E2E_PASSWORD_AUTH_METHOD_ID +
' -login-name=' +
process.env.E2E_PASSWORD_ADMIN_LOGIN_NAME +
' -password=env://E2E_PASSWORD_ADMIN_PASSWORD',
);
} catch (e) {
console.log(`${e.stderr}`);
}
};
/**
* Uses the boundary CLI to connect to the specified target
* @param {string} targetId ID of the target to be connected to
* @returns ChildProcess representing the result of the command execution
*/
exports.connectToTarget = async (targetId) => {
let connect;
try {
connect = exec(
'boundary connect' +
' -target-id=' +
targetId +
' -exec /usr/bin/ssh --' +
' -l ' +
process.env.E2E_SSH_USER +
' -i ' +
process.env.E2E_SSH_KEY_PATH +
' -o UserKnownHostsFile=/dev/null' +
' -o StrictHostKeyChecking=no' +
' -o IdentitiesOnly=yes' + // forces the use of the provided key
' -p {{boundary.port}}' +
' {{boundary.ip}}',
);
} catch (e) {
console.log(`${e.stderr}`);
}
return connect;
};
/**
* Uses the boundary CLI to connect ssh to the specified target
* @param {string} targetId ID of the target to be connected to
* @returns ChildProcess representing the result of the command execution
*/
exports.connectSshToTarget = async (targetId) => {
let connect;
try {
connect = exec(
'boundary connect ssh' +
' -target-id=' +
targetId +
' --' +
' -o UserKnownHostsFile=/dev/null' +
' -o StrictHostKeyChecking=no' +
' -o IdentitiesOnly=yes', // forces the use of the provided key
);
} catch (e) {
console.log(`${e.stderr}`);
}
return connect;
};
/**
* Uses the boundary CLI to create a new org.
* @returns {Promise<string>} new org's id
*/
exports.createNewOrgCli = async () => {
const orgName = 'Org ' + nanoid();
let newOrg;
try {
newOrg = JSON.parse(
execSync(
`boundary scopes create \
-name="${orgName}" \
-scope-id=global \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return newOrg.id;
};
/**
* Uses the boundary CLI to delete the specified organization
* @param {string} orgId ID of the organization to be deleted
*/
exports.deleteOrgCli = async (orgId) => {
try {
exec('boundary scopes delete -id=' + orgId);
} catch (e) {
console.log(`${e.stderr}`);
}
};
/**
* Uses the boundary CLI to delete the specified storage bucket
* @param {string} storageBucketId ID of the storage bucket to be deleted
*/
exports.deleteStorageBucketCli = async (storageBucketId) => {
try {
exec('boundary storage-buckets delete -id=' + storageBucketId);
} catch (e) {
console.log(`${e.stderr}`);
}
};
/**
* Uses the boundary CLI to delete the specified policy
* @param {string} policyId ID of the policy to be deleted
*/
exports.deletePolicyCli = async (policyId) => {
try {
exec('boundary policies delete -id=' + policyId);
} catch (e) {
console.log(`${e.stderr}`);
}
};
/**
* Uses the boundary CLI to create a new project.
* @param {string} orgId ID of the organization under which the project will be created.
* @returns {Promise<string>} new project's ID
*/
exports.createNewProjectCli = async (orgId) => {
const projectName = 'Project ' + nanoid();
let newProject;
try {
newProject = JSON.parse(
execSync(
`boundary scopes create \
-name="${projectName}" \
-scope-id=${orgId} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return newProject.id;
};
/**
* Uses the boundary CLI to create a new controller-led worker.
* @returns {Promise<string>} new worker's ID
*/
exports.createNewControllerLedWorkerCli = async () => {
const workerName = 'worker-' + nanoid();
let newWorker;
try {
newWorker = JSON.parse(
execSync(
`boundary workers create controller-led \
-name="${workerName.toLowerCase()}" \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return newWorker.id;
};
/**
* Uses the boundary CLI to create a new password auth-method.
* @param {string} scopeId ID of the scope under which the auth-method will be created.
* @returns {Promise<string>} new auth-method's ID
*/
exports.createNewPasswordAuthMethodCli = async (scopeId) => {
const authMethodName = 'auth-method-' + nanoid();
let newAuthMethod;
try {
newAuthMethod = JSON.parse(
execSync(
`boundary auth-methods create password \
-name "${authMethodName}" \
-scope-id ${scopeId} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return newAuthMethod.id;
};
/**
* Uses the boundary CLI to make an auth-method primary.
* @param {string} scopeId ID of the scope that the auth-method belongs to.
* @param {string} authMethodId ID of the auth method that will be made primary.
*/
exports.makeAuthMethodPrimaryCli = async (scopeId, authMethodId) => {
try {
execSync(
`boundary scopes update \
-id=${scopeId} \
-primary-auth-method-id ${authMethodId} \
-format json`,
);
} catch (e) {
console.log(`${e.stderr}`);
}
};
/**
* Uses the boundary CLI to create a new password account.
* @param {string} authMethodId ID of the auth-method that the new account will be created for.
* @returns {Promise<string>} new account's ID
*/
exports.createNewPasswordAccountCli = async (authMethodId) => {
let passwordAccount;
const login = 'test-login';
process.env.ACCOUNT_PASSWORD = 'test-password';
try {
passwordAccount = JSON.parse(
execSync(
`boundary accounts create password \
-auth-method-id ${authMethodId} \
-login-name ${login} \
-password env://ACCOUNT_PASSWORD \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return passwordAccount.id;
};
/**
* Uses the boundary CLI to create a new role.
* @param {string} scopeId ID of the scope under which the role will be created.
* @returns {Promise<string>} new role's ID
*/
exports.createNewRoleCli = async (scopeId) => {
const roleName = 'role-' + nanoid();
let role;
try {
role = JSON.parse(
execSync(
`boundary roles create \
-scope-id ${scopeId} \
-name ${roleName} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return role.id;
};
/**
* Uses the boundary CLI to create a new group.
* @param {string} scopeId ID of the scope under which the group will be created.
* @returns {Promise<string>} new group's ID
*/
exports.createNewGroupCli = async (scopeId) => {
const groupName = 'group-' + nanoid();
let group;
try {
group = JSON.parse(
execSync(
`boundary groups create \
-scope-id ${scopeId} \
-name ${groupName} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return group.id;
};
/**
* Uses the boundary CLI to create a new user.
* @param {string} scopeId ID of the scope under which the user will be created.
* @returns {Promise<string>} new user's ID
*/
exports.createNewUserCli = async (scopeId) => {
const userName = 'user-' + nanoid();
let user;
try {
user = JSON.parse(
execSync(
`boundary users create \
-scope-id ${scopeId} \
-name ${userName} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return user.id;
};
/**
* Uses the boundary CLI to create a new static host catalog.
* @param {string} projectId ID of the project under which the host catalog will be created.
* @returns {Promise<string>} new host catalog's ID
*/
exports.createNewStaticHostCatalogCli = async (projectId) => {
const hostCatalogName = 'static-host-catalog-' + nanoid();
let hostCatalog;
try {
hostCatalog = JSON.parse(
execSync(
`boundary host-catalogs create static \
-scope-id ${projectId} \
-name ${hostCatalogName} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return hostCatalog.id;
};
/**
* Uses the boundary CLI to create a new dynamic AWS host catalog.
* @param {string} projectId ID of the project under which the host catalog will be created.
* @returns {Promise<string>} new host catalog's ID
*/
exports.createDynamicAwsHostCatalogCli = async (projectId) => {
const hostCatalogName = 'dynamic-aws-host-catalog-' + nanoid();
let hostCatalog;
try {
hostCatalog = JSON.parse(
execSync(
`boundary host-catalogs create plugin \
-name ${hostCatalogName} \
-scope-id ${projectId} \
-plugin-name aws \
-attr disable_credential_rotation=true \
-attr region=us-east-1 \
-secret access_key_id=env://E2E_AWS_ACCESS_KEY_ID \
-secret secret_access_key=env://E2E_AWS_SECRET_ACCESS_KEY \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return hostCatalog.id;
};
/**
* Uses the boundary CLI to create a new static host.
* @param {string} hostCatalogId ID of the host catalog that the host will be created for.
* @returns {Promise<string>} new host's ID
*/
exports.createNewStaticHostCli = async (hostCatalogId) => {
const hostName = 'static-host-' + nanoid();
let host;
try {
host = JSON.parse(
execSync(
`boundary hosts create static \
-host-catalog-id ${hostCatalogId} \
-name ${hostName} \
-address localhost \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return host.id;
};
/**
* Uses the boundary CLI to create a new static host set.
* @param {string} hostCatalogId ID of the host catalog that the host set will be created for.
* @returns {Promise<string>} new host set's ID
*/
exports.createNewHostSetCli = async (hostCatalogId) => {
const hostSetName = 'static-host-' + nanoid();
let hostSet;
try {
hostSet = JSON.parse(
execSync(
`boundary host-sets create static \
-host-catalog-id ${hostCatalogId} \
-name ${hostSetName} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return hostSet.id;
};
/**
* Uses the boundary CLI to create a new static credential store.
* @param {string} projectId ID of the project under which the credential store will be created.
* @returns {Promise<string>} new credential store's ID
*/
exports.createNewStaticCredentialStoreCli = async (projectId) => {
const credentialStoreName = 'static-credential-store-' + nanoid();
let staticCredentialStore;
try {
staticCredentialStore = JSON.parse(
execSync(
`boundary credential-stores create static \
-scope-id ${projectId} \
-name ${credentialStoreName} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return staticCredentialStore.id;
};
/**
* Uses the boundary CLI to create a new vault credential store.
* @param {string} projectId ID of the project under which the credential store will be created.
* @param {string} secretPolicyName Name of the secret policy that's used to create vault token.
* @param {string} boundaryPolicyName Name of the boundary policy that's used to create vault token.
* @returns {Promise<string>} new credential store's ID
*/
exports.createNewVaultCredentialStoreCli = async (
projectId,
secretPolicyName,
boundaryPolicyName,
) => {
let credentialStore;
try {
execSync(
`vault policy write ${boundaryPolicyName} ./tests/e2e/tests/fixtures/boundary-controller-policy.hcl`,
);
execSync(
`vault policy write ${secretPolicyName} ./tests/e2e/tests/fixtures/kv-policy.hcl`,
);
const vaultToken = JSON.parse(
execSync(
`vault token create \
-no-default-policy=true \
-policy=${boundaryPolicyName} \
-policy=${secretPolicyName} \
-orphan=true \
-period=20m \
-renewable=true \
-format=json`,
),
);
const clientToken = vaultToken.auth.client_token;
const credentialStoreName = 'vault-credential-store-' + nanoid();
credentialStore = JSON.parse(
execSync(
`boundary credential-stores create vault \
-scope-id ${projectId} \
-name ${credentialStoreName} \
-vault-address ${process.env.E2E_VAULT_ADDR} \
-vault-token ${clientToken} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return credentialStore.id;
};
/**
* Uses the boundary CLI to create a new username-password credential.
* @param {string} credentialStoreId ID of the credential store that the credential will be created for.
* @returns {Promise<string>} new credential's ID
*/
exports.createNewUsernamePasswordCredentialCli = async (credentialStoreId) => {
let usernamePasswordCredential;
const login = 'test-login';
process.env.CREDENTIALS_PASSWORD = 'credentials-password';
try {
usernamePasswordCredential = JSON.parse(
execSync(
`boundary credentials create username-password \
-name ${login} \
-credential-store-id ${credentialStoreId} \
-username ${login} \
-password env://CREDENTIALS_PASSWORD \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return usernamePasswordCredential.id;
};
/**
* Uses the boundary CLI to create a new TCP target.
* @param {string} projectId ID of the project under which the target will be created.
* @returns {Promise<string>} new target's ID
*/
exports.createNewTcpTarget = async (projectId) => {
const targetName = 'target-' + nanoid();
const defaultPort = 22;
let target;
try {
target = JSON.parse(
execSync(
`boundary targets create tcp \
-default-port ${defaultPort} \
-name ${targetName} \
-scope-id ${projectId} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return target.id;
};
/**
* Uses the boundary CLI to create a new SSH target.
* @param {string} projectId ID of the project under which the target will be created.
* @returns {Promise<string>} new target's ID
*/
exports.createNewSshTargetCli = async (projectId) => {
const targetName = 'target-' + nanoid();
const defaultPort = 22;
let target;
try {
target = JSON.parse(
execSync(
`boundary targets create ssh \
-default-port ${defaultPort} \
-name ${targetName} \
-scope-id ${projectId} \
-format json`,
),
).item;
} catch (e) {
console.log(`${e.stderr}`);
}
return target.id;
};
/**
* Uses the boundary CLI to get a session created for the specified target
* @param {string} orgName Name of the organization with the specified project
* @param {string} projectName Name of project with the specified target
* @param {string} targetName Name of the target that the anticipated session is created for
* @returns An object representing an active session created for the specified target
*/
exports.getSessionCli = async (orgName, projectName, targetName) => {
let session;
try {
const orgs = JSON.parse(execSync('boundary scopes list -format json'));
const org = orgs.items.filter((obj) => obj.name == orgName)[0];
const projects = JSON.parse(
execSync(`boundary scopes list -format json -scope-id ${org.id}`),
);
const project = projects.items.filter((obj) => obj.name == projectName)[0];
const targets = JSON.parse(
execSync(`boundary targets list -format json -scope-id ${project.id}`),
);
const target = targets.items.filter((obj) => obj.name == targetName)[0];
session = JSON.parse(
execSync(
`boundary targets authorize-session -id ${target.id} -format json`,
),
);
} catch (e) {
console.log(`${e.stderr}`);
}
return session;
};
/**
* Uses the boundary CLI to wait for a session recording to be available.
* @param {string} storageBucketId ID of storage bucket that the session recording is associated with
* @returns An object representing a session recording
*/
exports.waitForSessionRecordingCli = async (storageBucketId) => {
let i = 0;
let filteredSessionRecording = [];
do {
i = i + 1;
const sessionRecordings = JSON.parse(
execSync('boundary session-recordings list -format json'),
);
filteredSessionRecording = sessionRecordings.items.filter(
(obj) =>
obj.storage_bucket_id == storageBucketId && obj.state == 'available',
);
if (filteredSessionRecording.length > 0) {
break;
}
await new Promise((resolve) => setTimeout(resolve, 1000));
} while (i < 5);
return filteredSessionRecording[0];
};