Migrate from ember-cli-mirage to miragejs (#3088)
* chore: 🤖 import explicit mirage references * chore: 🤖 add mirage setupMirage helper * chore: 🤖 working example with application adapter test * chore: 🤖 use internal setupMirage test helper from api addon * chore: 🤖 conditionally load mirage * chore: 🤖 filter mirage folder inclusion in production builds * chore: 🤖 drop ember-mirage and use our own test helpers * chore: 🤖 collapse reference to import declaration * docs: ✏️ add comment better explaining the mirage test env * chore: 🤖 update configuration and manage mirage-related deps * fix: 🐛 restore ipc mock and add missing checkOS handler * chore: 🤖 add comment explaining omitting mirage deps in build * chore: 🤖 allow mirage.enabled to include deps and handlers * chore: 🤖 re-enable mirage for core dummy app * Add missing copyright headers * chore: 🤖 use embroider macros to conditionally start mirage * docs: ✏️ update api readme for mirage changes * chore: 🤖 replace remaining ember-cli-mirage references * chore: 🤖 add mirage to test builds * fix: 🐛 ensure that auto mirage start doesn't happen in test env * chore: 🤖 use const instead of var Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com> * refactor: 💡 use cleaner logic for excluded api build modules * fix: 🐛 handle issue where importSync was too eager This was fixed by bumping the @embroider/macros dependency that includes a fix to this issue: https://github.com/embroider-build/embroider/pull/2511 * refactor: 💡 move mirage from addon to app directory * refactor: 💡 update mirage test helper to be a factory * chore: 🤖 exclude mirage directory when necessary at build time * chore: 🤖 add miragejs as admin dev dependency * refactor: 💡 update reference to startMirage * chore: 🤖 update local mirage test helper * chore: 🤖 change import path for mirage on desktop * chore: 🤖 update imports in tests for startMirage * chore: 🤖 update startMirage imports for api addon tests * chore: 🤖 add miragejs dev dep to desktop * docs: ✏️ update README * chore: 🤖 set up setupMirage for core tests * chore: 🤖 fix copyright header * Add missing copyright headers --------- Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
This commit is contained in:
1 parent
72fa6d86c4
commit
63b810d53f
191 files changed
+500
-215
No files matched your search
@@ -0,0 +1,988 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { createServer, Response } from 'miragejs';
|
||||
import { authHandler, deauthHandler } from './route-handlers/auth';
|
||||
import { targetHandler } from './route-handlers/target';
|
||||
import { pickRandomStatusString } from './factories/session';
|
||||
import initializeMockIPC from './scenarios/ipc';
|
||||
import makeBooleanFilter from './helpers/bexpr-filter';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { asciicasts } from './data/asciicasts';
|
||||
import { TYPE_WORKER_PKI } from 'api/models/worker';
|
||||
import environmentConfig from 'ember-get-config';
|
||||
|
||||
// mirage models (alphabetical)
|
||||
import accountModel from './models/account';
|
||||
import aliasModel from './models/alias';
|
||||
import authMethodModel from './models/auth-method';
|
||||
import baseModel from './models/base';
|
||||
import channelRecordingModel from './models/channel-recording';
|
||||
import connectionRecordingModel from './models/connection-recording';
|
||||
import credentialLibraryModel from './models/credential-library';
|
||||
import credentialStoreModel from './models/credential-store';
|
||||
import credentialModel from './models/credential';
|
||||
import groupModel from './models/group';
|
||||
import hostCatalogModel from './models/host-catalog';
|
||||
import hostSetModel from './models/host-set';
|
||||
import hostModel from './models/host';
|
||||
import managedGroupModel from './models/managed-group';
|
||||
import policyModel from './models/policy';
|
||||
import roleModel from './models/role';
|
||||
import scopeModel from './models/scope';
|
||||
import sessionRecordingModel from './models/session-recording';
|
||||
import sessionModel from './models/session';
|
||||
import storageBucketModel from './models/storage-bucket';
|
||||
import targetModel from './models/target';
|
||||
import userModel from './models/user';
|
||||
import workerModel from './models/worker';
|
||||
|
||||
// mirage serializers (alphabetical)
|
||||
import accountSerializer from './serializers/account';
|
||||
import aliasSerializer from './serializers/alias';
|
||||
import applicationSerializer from './serializers/application';
|
||||
import authMethodSerializer from './serializers/auth-method';
|
||||
import channelRecordingSerializer from './serializers/channel-recording';
|
||||
import connectionRecordingSerializer from './serializers/connection-recording';
|
||||
import credentialLibrarySerializer from './serializers/credential-library';
|
||||
import credentialStoreSerializer from './serializers/credential-store';
|
||||
import credentialSerializer from './serializers/credential';
|
||||
import groupSerializer from './serializers/group';
|
||||
import hostCatalogSerializer from './serializers/host-catalog';
|
||||
import hostSetSerializer from './serializers/host-set';
|
||||
import hostSerializer from './serializers/host';
|
||||
import managedGroupSerializer from './serializers/managed-group';
|
||||
import policySerializer from './serializers/policy';
|
||||
import roleSerializer from './serializers/role';
|
||||
import scopeSerializer from './serializers/scope';
|
||||
import sessionRecordingSerializer from './serializers/session-recording';
|
||||
import sessionSerializer from './serializers/session';
|
||||
import storageBucketSerializer from './serializers/storage-bucket';
|
||||
import targetSerializer from './serializers/target';
|
||||
import userSerializer from './serializers/user';
|
||||
import workerSerializer from './serializers/worker';
|
||||
|
||||
// mirage scenarios (alphabetical)
|
||||
import defaultScenario from './scenarios/default';
|
||||
import ipcScenario from './scenarios/ipc';
|
||||
|
||||
// mirage factories (alphabetical)
|
||||
import accountFactory from './factories/account';
|
||||
import aliasFactory from './factories/alias';
|
||||
import authMethodFactory from './factories/auth-method';
|
||||
import channelRecordingFactory from './factories/channel-recording';
|
||||
import connectionRecordingFactory from './factories/connection-recording';
|
||||
import credentialLibraryFactory from './factories/credential-library';
|
||||
import credentialStoreFactory from './factories/credential-store';
|
||||
import credentialFactory from './factories/credential';
|
||||
import groupFactory from './factories/group';
|
||||
import hostCatalogFactory from './factories/host-catalog';
|
||||
import hostSetFactory from './factories/host-set';
|
||||
import hostFactory from './factories/host';
|
||||
import managedGroupFactory from './factories/managed-group';
|
||||
import policyFactory from './factories/policy';
|
||||
import roleFactory from './factories/role';
|
||||
import scopeFactory from './factories/scope';
|
||||
import sessionRecordingFactory from './factories/session-recording';
|
||||
import storageBucketFactory from './factories/storage-bucket';
|
||||
import sessionFactory from './factories/session';
|
||||
import targetFactory from './factories/target';
|
||||
import userFactory from './factories/user';
|
||||
import workerFactory from './factories/worker';
|
||||
|
||||
const isTesting = environmentConfig.environment === 'test';
|
||||
|
||||
// Main function
|
||||
// More info about server configuration:
|
||||
// https://github.com/miragejs/miragejs/blob/7ff4f3f6fe56bf0cb1648f5af3f5210fcb07e20b/types/index.d.ts#L375-L404
|
||||
export default function (mirageConfig) {
|
||||
let finalConfig = {
|
||||
...mirageConfig,
|
||||
|
||||
scenarios: {
|
||||
default: defaultScenario,
|
||||
ipcScenario: ipcScenario,
|
||||
},
|
||||
|
||||
factories: {
|
||||
account: accountFactory,
|
||||
alias: aliasFactory,
|
||||
authMethod: authMethodFactory,
|
||||
channelRecording: channelRecordingFactory,
|
||||
connectionRecording: connectionRecordingFactory,
|
||||
credentialLibrary: credentialLibraryFactory,
|
||||
credentialStore: credentialStoreFactory,
|
||||
credential: credentialFactory,
|
||||
group: groupFactory,
|
||||
hostCatalog: hostCatalogFactory,
|
||||
hostSet: hostSetFactory,
|
||||
host: hostFactory,
|
||||
managedGroup: managedGroupFactory,
|
||||
policy: policyFactory,
|
||||
role: roleFactory,
|
||||
scope: scopeFactory,
|
||||
sessionRecording: sessionRecordingFactory,
|
||||
session: sessionFactory,
|
||||
storageBucket: storageBucketFactory,
|
||||
target: targetFactory,
|
||||
user: userFactory,
|
||||
worker: workerFactory,
|
||||
},
|
||||
|
||||
models: {
|
||||
account: accountModel,
|
||||
alias: aliasModel,
|
||||
authMethod: authMethodModel,
|
||||
base: baseModel,
|
||||
channelRecording: channelRecordingModel,
|
||||
connectionRecording: connectionRecordingModel,
|
||||
credentialLibrary: credentialLibraryModel,
|
||||
credentialStore: credentialStoreModel,
|
||||
credential: credentialModel,
|
||||
group: groupModel,
|
||||
hostCatalog: hostCatalogModel,
|
||||
hostSet: hostSetModel,
|
||||
host: hostModel,
|
||||
managedGroup: managedGroupModel,
|
||||
policy: policyModel,
|
||||
role: roleModel,
|
||||
scope: scopeModel,
|
||||
sessionRecording: sessionRecordingModel,
|
||||
session: sessionModel,
|
||||
storageBucket: storageBucketModel,
|
||||
target: targetModel,
|
||||
user: userModel,
|
||||
worker: workerModel,
|
||||
},
|
||||
|
||||
serializers: {
|
||||
account: accountSerializer,
|
||||
alias: aliasSerializer,
|
||||
application: applicationSerializer,
|
||||
authMethod: authMethodSerializer,
|
||||
channelRecording: channelRecordingSerializer,
|
||||
connectionRecording: connectionRecordingSerializer,
|
||||
credentialLibrary: credentialLibrarySerializer,
|
||||
credentialStore: credentialStoreSerializer,
|
||||
credential: credentialSerializer,
|
||||
group: groupSerializer,
|
||||
hostCatalog: hostCatalogSerializer,
|
||||
hostSet: hostSetSerializer,
|
||||
host: hostSerializer,
|
||||
managedGroup: managedGroupSerializer,
|
||||
policy: policySerializer,
|
||||
role: roleSerializer,
|
||||
scope: scopeSerializer,
|
||||
sessionRecording: sessionRecordingSerializer,
|
||||
session: sessionSerializer,
|
||||
storageBucket: storageBucketSerializer,
|
||||
target: targetSerializer,
|
||||
user: userSerializer,
|
||||
worker: workerSerializer,
|
||||
},
|
||||
|
||||
routes,
|
||||
};
|
||||
return createServer(finalConfig);
|
||||
}
|
||||
|
||||
// Only routes are defined here
|
||||
function routes() {
|
||||
initializeMockIPC(this, environmentConfig);
|
||||
|
||||
this.passthrough();
|
||||
// make this `http://localhost:8080`, for example, if your API is on a different server
|
||||
// this.urlPrefix = '';
|
||||
|
||||
this.get('/metadata.json', () => {
|
||||
// this configuration is optional
|
||||
const licensedFeatures = environmentConfig?.features?.licensedFeatures;
|
||||
const edition = licensedFeatures ? 'enterprise' : 'oss';
|
||||
const features = licensedFeatures ? Object.keys(licensedFeatures) : [];
|
||||
const metadata = {
|
||||
license: {
|
||||
edition,
|
||||
features,
|
||||
},
|
||||
};
|
||||
return metadata;
|
||||
});
|
||||
|
||||
// make this `/api`, for example, if your API is namespaced
|
||||
this.namespace = environmentConfig.api?.namespace;
|
||||
// delay for each request, automatically set to 0 during testing
|
||||
this.timing = 1;
|
||||
|
||||
// Scope resources
|
||||
|
||||
this.get(
|
||||
'/scopes',
|
||||
({ scopes }, { queryParams: { scope_id, recursive, filter } }) => {
|
||||
let resultSet;
|
||||
// Default parent scope is global
|
||||
if (!scope_id) scope_id = 'global';
|
||||
// We do not return global scope to mimic our API.
|
||||
if (recursive && scope_id === 'global') {
|
||||
resultSet = scopes.where((scope) => {
|
||||
return scope.scope ? scope.type !== 'global' : false;
|
||||
});
|
||||
} else {
|
||||
resultSet = scopes.where((scope) => {
|
||||
return scope.scope
|
||||
? scope.scope.id === scope_id && scope.type !== 'global'
|
||||
: false;
|
||||
});
|
||||
}
|
||||
const filteredResultSet = resultSet.filter(makeBooleanFilter(filter));
|
||||
// add a response_type to the response to simulate pagination
|
||||
// without having response_type, the unsupported controller modal
|
||||
// will show when running with mirage
|
||||
return { items: filteredResultSet.models, response_type: 'complete' };
|
||||
},
|
||||
);
|
||||
this.post('/scopes', function ({ scopes }) {
|
||||
// Parent scope comes through the payload via `scope_id`, but this needs
|
||||
// to be expanded to a scope object `scope: {id:..., type:...}` before
|
||||
// saving, which is the gist of this function.
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const parentScopeAttrs = this.serialize(scopes.find(attrs.scopeId));
|
||||
attrs.scope = parentScopeAttrs;
|
||||
return scopes.create(attrs);
|
||||
});
|
||||
this.get('/scopes/:id');
|
||||
this.patch('/scopes/:id');
|
||||
this.del('/scopes/:id');
|
||||
this.post(
|
||||
'/scopes/:idMethod',
|
||||
function ({ scopes }, { params: { idMethod } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const scope = scopes.find(id);
|
||||
|
||||
const updatedAttrs = {
|
||||
version: attrs.version,
|
||||
storagePolicyId: attrs.storagePolicyId,
|
||||
};
|
||||
|
||||
if (method === 'attach-storage-policy') {
|
||||
updatedAttrs.storagePolicyId = attrs.storagePolicyId;
|
||||
}
|
||||
|
||||
if (method === 'detach-storage-policy') {
|
||||
updatedAttrs.storagePolicyId = '';
|
||||
}
|
||||
return scope.update(updatedAttrs);
|
||||
},
|
||||
);
|
||||
// Auth & IAM resources
|
||||
|
||||
this.get('/auth-methods');
|
||||
this.post('/auth-methods', function ({ authMethods }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
if (attrs.type === 'oidc') {
|
||||
attrs.attributes.state = 'active-public';
|
||||
}
|
||||
return authMethods.create(attrs);
|
||||
});
|
||||
this.get('/auth-methods/:id');
|
||||
this.patch(
|
||||
'/auth-methods/:id',
|
||||
function ({ authMethods }, { params: { id } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
if (attrs.type === 'oidc' || attrs.type === 'ldap') {
|
||||
attrs.attributes.state = 'active-public';
|
||||
}
|
||||
|
||||
return authMethods.find(id).update(attrs);
|
||||
},
|
||||
);
|
||||
this.del('/auth-methods/:id', ({ authMethods }, { params: { id } }) => {
|
||||
const authMethod = authMethods.find(id);
|
||||
const scope = authMethod.scope;
|
||||
authMethod.destroy();
|
||||
// If the primary auth method is deleted, the associated scope's
|
||||
// primary_auth_method_id field should be set to null.
|
||||
if (scope.primaryAuthMethodId === id) {
|
||||
scope.update({ primaryAuthMethodId: null });
|
||||
}
|
||||
return new Response(202);
|
||||
});
|
||||
|
||||
// Auth Method Accounts
|
||||
this.get(
|
||||
'/accounts',
|
||||
(
|
||||
{ accounts },
|
||||
{ queryParams: { auth_method_id: authMethodId, filter } },
|
||||
) => {
|
||||
let resultSet;
|
||||
if (authMethodId) {
|
||||
resultSet = accounts.where({ authMethodId });
|
||||
} else {
|
||||
resultSet = accounts.all();
|
||||
}
|
||||
return resultSet.filter(makeBooleanFilter(filter));
|
||||
},
|
||||
);
|
||||
this.post('/accounts');
|
||||
this.get('/accounts/:id');
|
||||
this.patch('/accounts/:id');
|
||||
this.del('/accounts/:id');
|
||||
this.post(
|
||||
'/accounts/:idMethod',
|
||||
function ({ accounts }, { params: { idMethod } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const account = accounts.find(id);
|
||||
const updatedAttrs = {
|
||||
version: attrs.version,
|
||||
attributes: account.attributes,
|
||||
};
|
||||
// Set new password
|
||||
if (method === 'set-password') {
|
||||
updatedAttrs.attributes.password = attrs.password;
|
||||
}
|
||||
// Set new password
|
||||
if (method === 'change-password') {
|
||||
updatedAttrs.attributes.password = attrs.new_password;
|
||||
}
|
||||
return account.update(updatedAttrs);
|
||||
},
|
||||
);
|
||||
|
||||
// Authenticate + auth methods custom routes
|
||||
this.post('/auth-methods/:id_method', authHandler);
|
||||
// Deauthenticate route
|
||||
this.delete('/auth-tokens/:id', deauthHandler);
|
||||
|
||||
// IAM : Users
|
||||
this.get(
|
||||
'/users',
|
||||
({ users }, { queryParams: { scope_id, recursive, filter } }) => {
|
||||
let resultSet;
|
||||
if (recursive && scope_id === 'global') {
|
||||
resultSet = users.all();
|
||||
} else if (recursive) {
|
||||
resultSet = users.where((user) => {
|
||||
const userModel = users.find(user.id);
|
||||
return (
|
||||
user.scopeId === scope_id ||
|
||||
userModel?.scope?.scope?.id === scope_id
|
||||
);
|
||||
});
|
||||
} else {
|
||||
resultSet = users.where((user) => user.scopeId === scope_id);
|
||||
}
|
||||
return resultSet.filter(makeBooleanFilter(filter));
|
||||
},
|
||||
);
|
||||
this.post('/users');
|
||||
this.get('/users/:id');
|
||||
this.patch('/users/:id');
|
||||
this.del('/users/:id');
|
||||
this.post('/users/:idMethod', function ({ users }, { params: { idMethod } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const user = users.find(id);
|
||||
const updatedAttrs = {
|
||||
version: attrs.version,
|
||||
accountIds: user.accountIds,
|
||||
};
|
||||
// If adding accounts, push them into the array
|
||||
if (method === 'add-accounts') {
|
||||
attrs.accountIds.forEach((id) => {
|
||||
if (!updatedAttrs.accountIds.includes(id)) {
|
||||
updatedAttrs.accountIds.push(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
// If deleting accounts, filter them out of the array
|
||||
if (method === 'remove-accounts') {
|
||||
updatedAttrs.accountIds = updatedAttrs.accountIds.filter((id) => {
|
||||
return !attrs.accountIds.includes(id);
|
||||
});
|
||||
}
|
||||
return user.update(updatedAttrs);
|
||||
});
|
||||
|
||||
// IAM: Groups
|
||||
this.get(
|
||||
'/groups',
|
||||
({ groups }, { queryParams: { scope_id, recursive, filter } }) => {
|
||||
let resultSet;
|
||||
if (recursive && scope_id === 'global') {
|
||||
resultSet = groups.all();
|
||||
} else if (recursive) {
|
||||
resultSet = groups.where((group) => {
|
||||
const groupModel = groups.find(group.id);
|
||||
return (
|
||||
group.scopeId === scope_id ||
|
||||
groupModel?.scope?.scope?.id === scope_id
|
||||
);
|
||||
});
|
||||
} else {
|
||||
resultSet = groups.where((group) => group.scopeId === scope_id);
|
||||
}
|
||||
return resultSet.filter(makeBooleanFilter(filter));
|
||||
},
|
||||
);
|
||||
this.post('/groups');
|
||||
this.get('/groups/:id');
|
||||
this.patch('/groups/:id');
|
||||
this.del('/groups/:id');
|
||||
this.post(
|
||||
'/groups/:idMethod',
|
||||
function ({ groups }, { params: { idMethod } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const group = groups.find(id);
|
||||
const updatedAttrs = {
|
||||
version: attrs.version,
|
||||
memberIds: group.memberIds,
|
||||
};
|
||||
// If adding members, push them into the array
|
||||
if (method === 'add-members') {
|
||||
attrs.memberIds.forEach((id) => {
|
||||
if (!updatedAttrs.memberIds.includes(id)) {
|
||||
updatedAttrs.memberIds.push(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
// If deleting members, filter them out of the array
|
||||
if (method === 'remove-members') {
|
||||
updatedAttrs.memberIds = updatedAttrs.memberIds.filter((id) => {
|
||||
return !attrs.memberIds.includes(id);
|
||||
});
|
||||
}
|
||||
return group.update(updatedAttrs);
|
||||
},
|
||||
);
|
||||
|
||||
// IAM: Roles
|
||||
this.get('/roles');
|
||||
this.post('/roles');
|
||||
this.get('/roles/:id');
|
||||
this.patch('/roles/:id');
|
||||
this.del('/roles/:id');
|
||||
this.post(
|
||||
'/roles/:idMethod',
|
||||
function (
|
||||
{ roles, users, groups, managedGroups },
|
||||
{ params: { idMethod } },
|
||||
) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const role = roles.find(id);
|
||||
let updatedAttrs = {};
|
||||
|
||||
if (method === 'set-grant-scopes') {
|
||||
updatedAttrs = {
|
||||
version: attrs.version,
|
||||
grantScopeIds: attrs.grantScopeIds,
|
||||
};
|
||||
}
|
||||
|
||||
// Principals is a combined list of users, groups and managed groups, but in Mirage we've
|
||||
// internally modelled them as separate lists. Therefore we must check
|
||||
// the type by looking up the user or group first, then determine which
|
||||
// list to add the principal to.
|
||||
if (method === 'add-principals') {
|
||||
updatedAttrs = {
|
||||
version: attrs.version,
|
||||
userIds: role.userIds,
|
||||
groupIds: role.groupIds,
|
||||
managedGroupIds: role.managedGroupIds,
|
||||
};
|
||||
attrs.principalIds.forEach((id) => {
|
||||
const isUser = users.find(id);
|
||||
const isGroup = groups.find(id);
|
||||
const isManagedGroup = managedGroups.find(id);
|
||||
if (isUser && !updatedAttrs.userIds.includes(id)) {
|
||||
updatedAttrs.userIds.push(id);
|
||||
}
|
||||
if (isGroup && !updatedAttrs.groupIds.includes(id)) {
|
||||
updatedAttrs.groupIds.push(id);
|
||||
}
|
||||
if (isManagedGroup && !updatedAttrs.managedGroupIds.includes(id)) {
|
||||
updatedAttrs.managedGroupIds.push(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
// If deleting principals, filter the ids out of users, groups and managed group lists,
|
||||
// and in this case don't care about the type
|
||||
if (method === 'remove-principals') {
|
||||
updatedAttrs = {
|
||||
version: attrs.version,
|
||||
userIds: role.userIds,
|
||||
groupIds: role.groupIds,
|
||||
managedGroupIds: role.managedGroupIds,
|
||||
};
|
||||
updatedAttrs.userIds = updatedAttrs.userIds.filter((id) => {
|
||||
return !attrs.principalIds.includes(id);
|
||||
});
|
||||
updatedAttrs.groupIds = updatedAttrs.groupIds.filter((id) => {
|
||||
return !attrs.principalIds.includes(id);
|
||||
});
|
||||
updatedAttrs.managedGroupIds = updatedAttrs.managedGroupIds.filter(
|
||||
(id) => {
|
||||
return !attrs.principalIds.includes(id);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (method === 'set-grants') {
|
||||
updatedAttrs = {
|
||||
version: attrs.version,
|
||||
grantStrings: attrs.grantStrings,
|
||||
};
|
||||
}
|
||||
|
||||
return role.update(updatedAttrs);
|
||||
},
|
||||
);
|
||||
|
||||
// Other resources
|
||||
// host-catalog
|
||||
|
||||
this.get('/host-catalogs');
|
||||
this.post(
|
||||
'/host-catalogs',
|
||||
function ({ hostCatalogs }, { queryParams: { plugin_name } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
if (plugin_name) {
|
||||
attrs.type = 'plugin';
|
||||
attrs.plugin = {
|
||||
name: plugin_name,
|
||||
};
|
||||
}
|
||||
return hostCatalogs.create(attrs);
|
||||
},
|
||||
);
|
||||
this.get('/host-catalogs/:id');
|
||||
this.patch('/host-catalogs/:id');
|
||||
this.del('/host-catalogs/:id');
|
||||
|
||||
// host
|
||||
|
||||
this.get(
|
||||
'/hosts',
|
||||
function ({ hosts }, { queryParams: { host_catalog_id: hostCatalogId } }) {
|
||||
return hosts.where({ hostCatalogId });
|
||||
},
|
||||
);
|
||||
this.post('/hosts', function ({ hostCatalogs, hosts }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const hostCatalog = hostCatalogs.find(attrs.hostCatalogId);
|
||||
attrs.scopeId = hostCatalog.scope.id;
|
||||
return hosts.create(attrs);
|
||||
});
|
||||
this.get('/hosts/:id');
|
||||
this.patch('/hosts/:id');
|
||||
this.del('/hosts/:id');
|
||||
|
||||
// host-set
|
||||
|
||||
this.get(
|
||||
'/host-sets',
|
||||
function (
|
||||
{ hostSets },
|
||||
{ queryParams: { host_catalog_id: hostCatalogId } },
|
||||
) {
|
||||
return hostSets.where({ hostCatalogId });
|
||||
},
|
||||
);
|
||||
|
||||
this.post('/host-sets', function ({ hostCatalogs, hostSets }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const hostCatalog = hostCatalogs.find(attrs.hostCatalogId);
|
||||
//this needs to be attached while creating a plugin type host set to mimic API
|
||||
if (hostCatalog.plugin) {
|
||||
attrs.type = 'plugin';
|
||||
attrs.plugin = {
|
||||
name: hostCatalog.plugin.name,
|
||||
};
|
||||
}
|
||||
attrs.scopeId = hostCatalog.scope.id;
|
||||
return hostSets.create(attrs);
|
||||
});
|
||||
this.get('/host-sets/:id');
|
||||
this.patch('/host-sets/:id');
|
||||
this.del('/host-sets/:id');
|
||||
this.post(
|
||||
'/host-sets/:idMethod',
|
||||
function ({ hostSets }, { params: { idMethod } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const hostSet = hostSets.find(id);
|
||||
const updatedAttrs = {
|
||||
version: attrs.version,
|
||||
hostIds: hostSet.hostIds,
|
||||
};
|
||||
|
||||
// If adding hosts, push them into the array
|
||||
if (method === 'add-hosts') {
|
||||
attrs.hostIds.forEach((id) => {
|
||||
if (!updatedAttrs.hostIds.includes(id)) {
|
||||
updatedAttrs.hostIds.push(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// If deleting hosts, filter them out of the array
|
||||
if (method === 'remove-hosts') {
|
||||
updatedAttrs.hostIds = updatedAttrs.hostIds.filter((id) => {
|
||||
return !attrs.hostIds.includes(id);
|
||||
});
|
||||
}
|
||||
|
||||
return hostSet.update(updatedAttrs);
|
||||
},
|
||||
);
|
||||
|
||||
// target
|
||||
|
||||
this.get(
|
||||
'/targets',
|
||||
function ({ targets }, { queryParams: { scope_id, recursive, filter } }) {
|
||||
let resultSet;
|
||||
if (recursive && scope_id === 'global') {
|
||||
resultSet = targets.all();
|
||||
} else if (recursive) {
|
||||
resultSet = targets.where((target) => {
|
||||
const targetModel = targets.find(target.id);
|
||||
return (
|
||||
target.scopeId === scope_id ||
|
||||
targetModel?.scope?.scope?.id === scope_id
|
||||
);
|
||||
});
|
||||
} else {
|
||||
resultSet = targets.where((target) => target.scopeId === scope_id);
|
||||
}
|
||||
return resultSet.filter(makeBooleanFilter(filter));
|
||||
},
|
||||
);
|
||||
this.post('/targets', function ({ targets }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
return targets.create(attrs);
|
||||
});
|
||||
this.get('/targets/:id');
|
||||
this.patch('/targets/:id');
|
||||
this.del('/targets/:id');
|
||||
this.post('/targets/:idMethod', targetHandler);
|
||||
|
||||
// session
|
||||
|
||||
this.get(
|
||||
'/sessions',
|
||||
function ({ sessions }, { queryParams: { scope_id, recursive, filter } }) {
|
||||
let resultSet;
|
||||
// To simulate changes to `session.status` that may occur in the backend,
|
||||
// we quietly randomize the value of the field on GET.
|
||||
// To populate sessions for logged in user,
|
||||
// update alternate sessions to auth user.
|
||||
// But only if not in testing mode.
|
||||
// In tests, we need deterministic statuses.
|
||||
if (!isTesting) {
|
||||
sessions.all().models.forEach((session) => {
|
||||
session.update({
|
||||
status: pickRandomStatusString(),
|
||||
});
|
||||
if (session.id.split('-').pop() % 2) {
|
||||
session.update({
|
||||
userId: 'authenticateduser',
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (recursive && scope_id === 'global') {
|
||||
resultSet = sessions.all();
|
||||
} else if (recursive) {
|
||||
resultSet = sessions.where((session) => {
|
||||
const sessionModel = sessions.find(session.id);
|
||||
return (
|
||||
session.scopeId === scope_id ||
|
||||
sessionModel?.scope?.scope?.id === scope_id
|
||||
);
|
||||
});
|
||||
} else {
|
||||
resultSet = sessions.where((session) => session.scopeId === scope_id);
|
||||
}
|
||||
return resultSet.filter(makeBooleanFilter(filter));
|
||||
},
|
||||
);
|
||||
this.get('/sessions/:id', function ({ sessions }, { params: { id } }) {
|
||||
const session = sessions.find(id);
|
||||
if (!isTesting) {
|
||||
session.update({
|
||||
status: pickRandomStatusString(),
|
||||
});
|
||||
}
|
||||
return session;
|
||||
});
|
||||
this.post(
|
||||
'/sessions/:idMethod',
|
||||
function ({ sessions }, { params: { idMethod } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const session = sessions.find(id);
|
||||
const updatedAttrs = {
|
||||
version: attrs.version,
|
||||
};
|
||||
if (method === 'cancel') {
|
||||
updatedAttrs.status = 'canceling';
|
||||
}
|
||||
return session.update(updatedAttrs);
|
||||
},
|
||||
);
|
||||
|
||||
// auth-tokens
|
||||
|
||||
this.get('/auth-tokens/:id', function () {
|
||||
// Set to 401 or 404 to simulate token invalidation, which will
|
||||
// cause the session to fail restoration and logout the user.
|
||||
return new Response(200);
|
||||
});
|
||||
|
||||
// credential-stores
|
||||
|
||||
this.get('/credential-stores');
|
||||
|
||||
this.get('/credential-stores/:id');
|
||||
this.post('/credential-stores');
|
||||
this.patch('/credential-stores/:id');
|
||||
this.del('/credential-stores/:id');
|
||||
|
||||
// credential-libraries
|
||||
|
||||
this.get(
|
||||
'/credential-libraries',
|
||||
(
|
||||
{ credentialLibraries },
|
||||
{ queryParams: { credential_store_id: credentialStoreId } },
|
||||
) => credentialLibraries.where({ credentialStoreId }),
|
||||
);
|
||||
this.get('/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');
|
||||
|
||||
// credentials
|
||||
|
||||
this.get(
|
||||
'/credentials',
|
||||
(
|
||||
{ credentials },
|
||||
{ queryParams: { credential_store_id: credentialStoreId } },
|
||||
) => credentials.where({ credentialStoreId }),
|
||||
);
|
||||
this.get('/credentials/:id');
|
||||
this.post('/credentials', function ({ credentialStores, credentials }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const credentialStore = credentialStores.find(attrs.credentialStoreId);
|
||||
attrs.scopeId = credentialStore.scope.id;
|
||||
return credentials.create(attrs);
|
||||
});
|
||||
|
||||
this.del('/credentials/:id');
|
||||
this.patch('/credentials/:id');
|
||||
|
||||
// managed-groups
|
||||
this.get(
|
||||
'/managed-groups',
|
||||
(
|
||||
{ managedGroups },
|
||||
{ queryParams: { auth_method_id: authMethodId, filter } },
|
||||
) => {
|
||||
let resultSet;
|
||||
if (authMethodId) {
|
||||
resultSet = managedGroups.where({ authMethodId });
|
||||
} else {
|
||||
resultSet = managedGroups.all();
|
||||
}
|
||||
return resultSet.filter(makeBooleanFilter(filter));
|
||||
},
|
||||
);
|
||||
this.post('/managed-groups');
|
||||
this.get('/managed-groups/:id');
|
||||
this.patch('/managed-groups/:id');
|
||||
this.del('/managed-groups/:id');
|
||||
|
||||
// workers
|
||||
this.get(
|
||||
'/workers',
|
||||
({ workers }, { queryParams: { scope_id: scopeId } }) => {
|
||||
return workers.where({ scopeId });
|
||||
},
|
||||
);
|
||||
this.get('/workers/:id');
|
||||
this.del('/workers/:id');
|
||||
this.patch('/workers/:id');
|
||||
this.post('/workers:create:worker-led', ({ workers, scopes }) => {
|
||||
const globalScope = scopes.find('global');
|
||||
|
||||
// This POST only takes in a token so we need to generate a random worker to return
|
||||
const newWorker = this.create('worker', {
|
||||
type: TYPE_WORKER_PKI,
|
||||
scope: globalScope,
|
||||
});
|
||||
return workers.create(newWorker.attrs);
|
||||
});
|
||||
this.post(
|
||||
'/workers/:idMethod',
|
||||
function ({ workers }, { params: { idMethod } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const worker = workers.find(id);
|
||||
let updatedAttrs = {
|
||||
version: attrs.version,
|
||||
api_tags: worker.api_tags,
|
||||
};
|
||||
|
||||
if (method === 'remove-worker-tags') {
|
||||
const key = Object.keys(attrs.apiTags)[0];
|
||||
const value = attrs.apiTags[key][0];
|
||||
updatedAttrs.api_tags[key] = updatedAttrs.api_tags[key].filter(
|
||||
(tag) => {
|
||||
return tag !== value;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (method === 'set-worker-tags') {
|
||||
updatedAttrs.api_tags = attrs.apiTags;
|
||||
}
|
||||
|
||||
return worker.update(updatedAttrs);
|
||||
},
|
||||
);
|
||||
|
||||
// storage-buckets
|
||||
this.get(
|
||||
'/storage-buckets',
|
||||
({ storageBuckets }, { queryParams: { scope_id: scopeId, recursive } }) => {
|
||||
if (recursive && scopeId === 'global') {
|
||||
return storageBuckets.all();
|
||||
}
|
||||
return storageBuckets.where({ scopeId });
|
||||
},
|
||||
);
|
||||
this.get('/storage-buckets/:id');
|
||||
this.del('/storage-buckets/:id');
|
||||
this.patch('/storage-buckets/:id');
|
||||
this.post(
|
||||
'/storage-buckets',
|
||||
function ({ storageBuckets }, { queryParams: { plugin_name } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
if (plugin_name) {
|
||||
attrs.type = 'plugin';
|
||||
attrs.plugin = {
|
||||
name: plugin_name,
|
||||
};
|
||||
}
|
||||
// Remove the secrets
|
||||
delete attrs.secrets;
|
||||
|
||||
return storageBuckets.create(attrs);
|
||||
},
|
||||
);
|
||||
|
||||
//storage-policy
|
||||
this.get(
|
||||
'/policies',
|
||||
({ policies }, { queryParams: { scope_id: scopeId } }) => {
|
||||
return policies.where({ scopeId });
|
||||
},
|
||||
);
|
||||
this.get('/policies/:id');
|
||||
this.del('/policies/:id');
|
||||
this.patch('/policies/:id');
|
||||
this.post('/policies', function ({ policies }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
|
||||
return policies.create(attrs);
|
||||
});
|
||||
|
||||
// Alias
|
||||
this.get(
|
||||
'/aliases',
|
||||
({ aliases }, { queryParams: { scope_id: scopeId } }) => {
|
||||
return aliases.where({ scopeId });
|
||||
},
|
||||
);
|
||||
this.get('/aliases/:id');
|
||||
this.del('/aliases/:id');
|
||||
this.patch('/aliases/:id');
|
||||
this.post('/aliases', function ({ aliases }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
|
||||
return aliases.create(attrs);
|
||||
});
|
||||
|
||||
// session recordings
|
||||
this.get('/session-recordings');
|
||||
this.get(
|
||||
'/session-recordings/:idMethod',
|
||||
async ({ sessionRecordings }, { params: { idMethod } }) => {
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
|
||||
if (method === 'download') {
|
||||
return faker.helpers.arrayElement(asciicasts);
|
||||
} else {
|
||||
return sessionRecordings.find(id);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
this.post(
|
||||
'/session-recordings/:idMethod',
|
||||
function ({ sessionRecordings }, { params: { idMethod } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const record = sessionRecordings.find(id);
|
||||
const updatedAttrs = {
|
||||
version: attrs.version,
|
||||
};
|
||||
if (method === 'reapply-storage-policy') {
|
||||
updatedAttrs.retain_until = faker.date.recent();
|
||||
updatedAttrs.delete_after = faker.date.recent();
|
||||
}
|
||||
return record.update(updatedAttrs);
|
||||
},
|
||||
);
|
||||
|
||||
this.del('/session-recordings/:id');
|
||||
|
||||
/* Uncomment the following line and the Response import above
|
||||
* Then change the response code to simulate error responses.
|
||||
* this.get('/scopes', () => new Response(505));
|
||||
*
|
||||
* Update error payload to simulate specific error responses.
|
||||
*/
|
||||
// this.get('/host-catalogs', () => new Response(404));
|
||||
// this.get('/scopes/:id', () => new Response(505, {}, {
|
||||
// errors: [{
|
||||
// status: 505,
|
||||
// message: 'HTTP version not supported.',
|
||||
// }]
|
||||
// }));
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
export const asciicast1 = `{"version": 2, "width": 124, "height": 36, "timestamp": 1670352594, "env": {"SHELL": "/bin/zsh", "TERM": "xterm-256color"}}
|
||||
[2.138652, "o", "\\u001b[1m\\u001b[7m%\\u001b[27m\\u001b[1m\\u001b[0m \\r \\r\\u001b]2;ember-asciinema-player\\u0007\\u001b]1;..iinema-player\\u0007"]
|
||||
[2.220877, "o", "\\r\\u001b[0m\\u001b[27m\\u001b[24m\\u001b[J\\u001b[33member-asciinema-player\\u001b[00m \\u001b[32mgit\\u001b[00m:\\u001b[36m(main*)\\u001b[00m $ \\u001b[K"]
|
||||
[2.221019, "o", "\\u001b[?1h\\u001b="]
|
||||
[2.221076, "o", "\\u001b[?2004h"]
|
||||
[2.676444, "o", "y"]
|
||||
[2.788653, "o", "\\bya"]
|
||||
[2.868652, "o", "r"]
|
||||
[3.001764, "o", "n"]
|
||||
[3.167636, "o", " "]
|
||||
[3.313668, "o", "t"]
|
||||
[3.460527, "o", "e"]
|
||||
[3.561983, "o", "s"]
|
||||
[3.63678, "o", "t"]
|
||||
[3.853437, "o", "\\u001b[?1l\\u001b>"]
|
||||
[3.853473, "o", "\\u001b[?2004l\\r\\r\\n"]
|
||||
[3.854604, "o", "\\u001b]2;yarn test\\u0007\\u001b]1;yarn\\u0007"]
|
||||
[4.489178, "o", "\\u001b[2K"]
|
||||
[4.48982, "o", "\\u001b[1G\\u001b[1myarn run v1.22.19\\u001b[22m\\r\\n"]
|
||||
[4.555618, "o", "\\u001b[2K"]
|
||||
[4.555649, "o", "\\u001b[1G\\u001b[2m$ npm-run-all lint\\u001b[22m\\r\\n"]
|
||||
[5.345253, "o", "\\u001b[2K"]
|
||||
[5.345509, "o", "\\u001b[1G\\u001b[2m$ npm-run-all --print-name --aggregate-output --continue-on-error --parallel \\"lint:!(fix)\\"\\u001b[22m\\r\\n"]
|
||||
[7.225926, "o", "\\r\\n> ember-asciinema-player@0.0.0 lint:js ember-asciinema-player/package.json\\r\\n> eslint . --cache \\r\\n\\r\\n$ eslint . --cache\\r\\n"]
|
||||
[8.398641, "o", "\\r\\n> ember-asciinema-player@0.0.0 lint:hbs ember-asciinema-player/package.json\\r\\n> ember-template-lint . \\r\\n\\r\\n$ ember-template-lint .\\r\\n\\r\\n"]
|
||||
[8.418537, "o", "\\u001b[2K\\u001b[1G\\u001b[2m$ ember test\\u001b[22m\\r\\n"]
|
||||
[12.256156, "o", "\\u001b[?25l"]
|
||||
[12.256464, "o", "\\u001b[32m⠋\\u001b[39m \\u001b[32mBuilding\\u001b[39m"]
|
||||
[12.2573, "o", "\\u001b[2K"]
|
||||
[12.257386, "o", "\\u001b[1G\\u001b[?25h"]
|
||||
[12.257689, "o", "Environment: test\\r\\n"]
|
||||
[12.257857, "o", "\\u001b[?25l\\u001b[32m⠋\\u001b[39m \\u001b[32mBuilding\\u001b[39m"]
|
||||
[12.539035, "o", "\\u001b[2K"]
|
||||
[12.539144, "o", "\\u001b[1G"]
|
||||
[12.539219, "o", "\\u001b[32m⠙\\u001b[39m \\u001b[32mbuilding... \\u001b[39m"]
|
||||
[12.745202, "o", "\\u001b[2K\\u001b[1G"]
|
||||
[12.745343, "o", "\\u001b[32m⠹\\u001b[39m \\u001b[32mbuilding... \\u001b[39m[Babel: @ember/test-helpers > applyPatches]"]
|
||||
[12.825004, "o", "\\u001b[2K"]
|
||||
[12.825031, "o", "\\u001b[1G"]
|
||||
[12.825122, "o", "\\u001b[32m⠸\\u001b[39m \\u001b[32mbuilding... \\u001b[39m[Babel: ember-qunit > applyPatches]"]
|
||||
[12.933588, "o", "\\u001b[2K\\u001b[1G"]
|
||||
[12.933624, "o", "\\u001b[32m⠼\\u001b[39m \\u001b[32mbuilding... \\u001b[39m[Babel: ember-load-initializers > applyPatches]"]
|
||||
[13.194738, "o", "\\u001b[2K\\u001b[1G"]
|
||||
[13.195009, "o", "\\u001b[32m⠴\\u001b[39m \\u001b[32mbuilding... \\u001b[39m[Babel: ember-asciinema-player > applyPatches]"]
|
||||
[13.307878, "o", "\\u001b[2K\\u001b[1G\\u001b[32m⠦\\u001b[39m \\u001b[32mbuilding... \\u001b[39m[Package /assets/vendor.js]"]
|
||||
[13.750717, "o", "\\u001b[2K\\u001b[1G"]
|
||||
[13.750755, "o", "\\u001b[32m⠧\\u001b[39m \\u001b[32mbuilding... \\u001b[39m[Concat: Test Support JS]"]
|
||||
[13.869411, "o", "\\u001b[2K\\u001b[1G"]
|
||||
[13.869438, "o", "\\u001b[32m⠇\\u001b[39m \\u001b[32mbuilding... \\u001b[39m[ember-auto-import-webpack]"]
|
||||
[14.655374, "o", "\\u001b[2K\\u001b[1G"]
|
||||
[14.655415, "o", "\\u001b[32m⠏\\u001b[39m \\u001b[32mbuilding... \\u001b[39m[ember-auto-import-webpack]"]
|
||||
[14.73686, "o", "\\u001b[2K\\u001b[1G\\u001b[?25h"]
|
||||
[14.738533, "o", "\\u001b[?25h"]
|
||||
[14.738818, "o", "\\u001b[?25l\\u001b[32m⠋\\u001b[39m cleaning up"]
|
||||
[14.739061, "o", "\\u001b[2K\\u001b[1G\\u001b[?25hcleaning up...\\r\\n"]
|
||||
[14.739197, "o", "\\u001b[?25l\\u001b[32m⠋\\u001b[39m cleaning up"]
|
||||
[14.907985, "o", "\\u001b[2K"]
|
||||
[14.90808, "o", "\\u001b[1G\\u001b[?25h"]
|
||||
[14.908128, "o", "\\u001b[32mBuilt project successfully.\\u001b[39m\\r\\n"]
|
||||
[16.224632, "o", "ok 1 Chrome 108.0 - [2 ms] - ember-qunit: Ember.onerror validation: Ember.onerror is functioning properly\\r\\n"]
|
||||
[16.346568, "o", "\\r\\n1..1\\r\\n# tests 1\\r\\n# pass 1\\r\\n# skip 0\\r\\n# todo 0\\r\\n# fail 0\\r\\n\\r\\n# ok\\r\\n"]
|
||||
[16.403167, "o", "\\u001b[2K"]
|
||||
[16.403388, "o", "\\u001b[1G✨ Done in 11.92s.\\r\\n"]
|
||||
[16.413967, "o", "\\u001b[1m\\u001b[7m%\\u001b[27m\\u001b[1m\\u001b[0m \\r \\r"]
|
||||
[16.414147, "o", "\\u001b]2;ember-asciinema-player\\u0007\\u001b]1;..iinema-player\\u0007"]
|
||||
[16.528341, "o", "\\r\\u001b[0m\\u001b[27m\\u001b[24m\\u001b[J\\u001b[33member-asciinema-player\\u001b[00m \\u001b[32mgit\\u001b[00m:\\u001b[36m(main*)\\u001b[00m $ \\u001b[K"]
|
||||
[16.528501, "o", "\\u001b[?1h\\u001b="]
|
||||
[16.52863, "o", "\\u001b[?2004h"]
|
||||
[19.078794, "o", "\\u001b[?2004l\\r\\r\\n"]`;
|
||||
|
||||
export const asciicast2 = `{"version": 2, "width": 112, "height": 30, "timestamp": 1672793720, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
|
||||
[0.036928, "o", "\\u001b[?2004h\\u001b[1;32m[\\u001b]0;johan@nixos: ~/src/hashicorp/boundary-enterprise\\u0007johan@nixos:~/src/hashicorp/boundary-enterprise]$\\u001b[0m "]
|
||||
[2.827983, "o", "b"]
|
||||
[2.9386, "o", "o"]
|
||||
[2.97036, "o", "u"]
|
||||
[3.032542, "o", "n"]
|
||||
[3.108687, "o", "d"]
|
||||
[3.246045, "o", "a"]
|
||||
[3.340117, "o", "r"]
|
||||
[3.841216, "o", "y"]
|
||||
[4.314958, "o", " "]
|
||||
[6.052102, "o", "u"]
|
||||
[6.146486, "o", "s"]
|
||||
[6.207341, "o", "e"]
|
||||
[6.273087, "o", "r"]
|
||||
[6.378873, "o", "s"]
|
||||
[6.799687, "o", " "]
|
||||
[7.08347, "o", "l"]
|
||||
[7.159196, "o", "i"]
|
||||
[7.249656, "o", "s"]
|
||||
[7.352251, "o", "t"]
|
||||
[7.450038, "o", " "]
|
||||
[7.688195, "o", "-"]
|
||||
[7.931818, "o", "r"]
|
||||
[8.001542, "o", "e"]
|
||||
[8.387771, "o", "c"]
|
||||
[8.526339, "o", "u"]
|
||||
[8.631438, "o", "r"]
|
||||
[8.81899, "o", "s"]
|
||||
[8.958184, "o", "i"]
|
||||
[9.085688, "o", "v"]
|
||||
[9.134885, "o", "e"]
|
||||
[9.786868, "o", "\\r\\n"]
|
||||
[9.788828, "o", "\\u001b[?2004l\\r"]
|
||||
[10.086691, "o", "\\u001b[0m\\r\\nUser information:\\r\\n ID: u_anon\\r\\n Scope ID: global\\r\\n Version: 1\\r\\n Name: anonymous\\r\\n Description: The anonymous user matches any request, whether authenticated or not\\r\\n Authorized Actions:\\r\\n no-op\\r\\n read\\r\\n update\\r\\n delete\\r\\n add-accounts\\r\\n set-accounts\\r\\n remove-accounts\\r\\n\\r\\n ID: u_auth\\r\\n Scope ID: global\\r\\n Version: 1\\r\\n Name: authenticated\\r\\n Description: The authenticated user matches any user that has a valid token\\r\\n Authorized Actions:\\r\\n no-op\\r\\n read\\r\\n update\\r\\n delete\\r\\n add-accounts\\r\\n set-accounts\\r\\n remove-accounts\\r\\n\\r\\n ID: u_recovery\\r\\n Scope ID: global\\r\\n Version: 1\\r\\n Name: recovery\\r\\n Description: The recovery user is used for any request that was performed with the recovery KMS\\r\\n workflow\\r\\n Autho"]
|
||||
[10.086736, "o", "rized Actions:\\r\\n no-op\\r\\n read\\r\\n update\\r\\n delete\\r\\n add-accounts\\r\\n set-accounts\\r\\n remove-accounts\\r\\n\\r\\n ID: u_1234567890\\r\\n Scope ID: global\\r\\n Version: 3\\r\\n Name: admin\\r\\n Description: Initial admin user within the \\"global\\" scope\\r\\n Primary Account ID: acctpw_1234567890\\r\\n Login Name: admin\\r\\n Authorized Actions:\\r\\n no-op\\r\\n read\\r\\n update\\r\\n delete\\r\\n add-accounts\\r\\n set-accounts\\r\\n remove-accounts\\r\\n\\r\\n ID: u_0987654321\\r\\n Scope ID: global\\r\\n Version: 3\\r\\n Name: user\\r\\n Description: Initial unprivileged user\\r\\n Primary Account ID: acctpw_0987654321\\r\\n Login Name: user\\r\\n Authorized Actions:\\r\\n no-op\\r\\n read\\r\\n update\\r\\n delete\\r\\n add-accounts\\r\\n set-accounts\\r\\n remove-accounts\\u001b[0m\\r\\n"]
|
||||
[10.106453, "o", "\\u001b[?2004h\\u001b[1;32m[\\u001b]0;johan@nixos: ~/src/hashicorp/boundary-enterprise\\u0007johan@nixos:~/src/hashicorp/boundary-enterprise]$\\u001b[0m "]
|
||||
[12.501496, "o", "b"]
|
||||
[12.703134, "o", "o"]
|
||||
[12.752198, "o", "u"]
|
||||
[12.775329, "o", "n"]
|
||||
[12.905261, "o", "d"]
|
||||
[13.002373, "o", "a"]
|
||||
[13.100111, "o", "r"]
|
||||
[13.354779, "o", "y"]
|
||||
[13.699827, "o", " "]
|
||||
[13.998849, "o", "t"]
|
||||
[14.139192, "o", "a"]
|
||||
[14.19663, "o", "r"]
|
||||
[14.392075, "o", "g"]
|
||||
[14.489938, "o", "e"]
|
||||
[14.579533, "o", "t"]
|
||||
[14.674628, "o", "s"]
|
||||
[14.830951, "o", " "]
|
||||
[15.015311, "o", "l"]
|
||||
[15.077147, "o", "i"]
|
||||
[15.262221, "o", "s"]
|
||||
[15.355571, "o", "t"]
|
||||
[15.456597, "o", " "]
|
||||
[15.91612, "o", "-"]
|
||||
[16.264491, "o", "r"]
|
||||
[16.351595, "o", "e"]
|
||||
[16.798456, "o", "c"]
|
||||
[16.891689, "o", "u"]
|
||||
[16.997975, "o", "r"]
|
||||
[17.176378, "o", "s"]
|
||||
[17.290104, "o", "i"]
|
||||
[17.434691, "o", "v"]
|
||||
[17.482502, "o", "e"]
|
||||
[18.393541, "o", "\\r\\n"]
|
||||
[18.39558, "o", "\\u001b[?2004l\\r"]
|
||||
[18.673452, "o", "\\u001b[0m\\r\\nTarget information:\\r\\n ID: ttcp_1234567890\\r\\n Scope ID: p_1234567890\\r\\n Version: 2\\r\\n Type: tcp\\r\\n Name: Generated target\\r\\n Description: Provides an initial target in Boundary\\r\\n Authorized Actions:\\r\\n no-op\\r\\n read\\r\\n update\\r\\n delete\\r\\n add-host-sources\\r\\n set-host-sources\\r\\n remove-host-sources\\r\\n add-credential-sources\\r\\n set-credential-sources\\r\\n remove-credential-sources\\r\\n authorize-session\\u001b[0m\\r\\n"]
|
||||
[18.692528, "o", "\\u001b[?2004h\\u001b[1;32m[\\u001b]0;johan@nixos: ~/src/hashicorp/boundary-enterprise\\u0007johan@nixos:~/src/hashicorp/boundary-enterprise]$\\u001b[0m "]
|
||||
[20.083966, "o", "e"]
|
||||
[20.37301, "o", "x"]
|
||||
[20.51445, "o", "i"]
|
||||
[20.612885, "o", "t"]
|
||||
[21.303896, "o", "\\r\\n"]
|
||||
[21.307902, "o", "\\u001b[?2004l\\rexit\\r\\n"]`;
|
||||
|
||||
export const asciicasts = [asciicast1, asciicast2];
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/account';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_PASSWORD,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
TYPES_AUTH_METHOD,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
export default factory.extend({
|
||||
authorized_actions() {
|
||||
let authorizedActions = ['no-op', 'read', 'update', 'delete'];
|
||||
if (this.type === TYPE_AUTH_METHOD_PASSWORD) {
|
||||
authorizedActions.push('set-password');
|
||||
}
|
||||
return permissions.authorizedActionsFor('account') || authorizedActions;
|
||||
},
|
||||
|
||||
id: () => generateId('acct_'),
|
||||
|
||||
type: (i) => TYPES_AUTH_METHOD[i % TYPES_AUTH_METHOD.length],
|
||||
|
||||
attributes() {
|
||||
switch (this.type) {
|
||||
case TYPE_AUTH_METHOD_PASSWORD:
|
||||
return { login_name: faker.internet.userName() };
|
||||
case TYPE_AUTH_METHOD_LDAP: {
|
||||
const randomNum = faker.number.int({ min: 3, max: 5 });
|
||||
let member_of_groups = [];
|
||||
const login_name = faker.internet.userName();
|
||||
let dn = `uid=${login_name}`;
|
||||
for (let i = 0; i < randomNum; i++) {
|
||||
member_of_groups.push(faker.word.noun());
|
||||
dn += `,dc=${faker.internet.domainSuffix()}`;
|
||||
}
|
||||
return {
|
||||
login_name,
|
||||
dn,
|
||||
member_of_groups,
|
||||
email: faker.internet.email(),
|
||||
full_name: faker.person.fullName(),
|
||||
};
|
||||
}
|
||||
case TYPE_AUTH_METHOD_OIDC:
|
||||
return {
|
||||
issuer:
|
||||
Math.random() > 0.5 ? faker.internet.ip() : faker.internet.ipv6(),
|
||||
subject: 'sub',
|
||||
email: faker.internet.email(),
|
||||
full_name: faker.person.fullName(),
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/alias';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
|
||||
const destinationIDs = ['', generateId('t_')];
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('alt_'),
|
||||
destination_id: (i) => destinationIDs[i % destinationIDs.length],
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('alias') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/auth-method';
|
||||
import { trait } from 'miragejs';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
|
||||
import {
|
||||
TYPE_AUTH_METHOD_PASSWORD,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
TYPES_AUTH_METHOD,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
export default factory.extend({
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('auth-method') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
'authenticate',
|
||||
],
|
||||
authorized_collection_actions() {
|
||||
switch (this.type) {
|
||||
case TYPE_AUTH_METHOD_PASSWORD:
|
||||
return { accounts: ['create', 'list'] };
|
||||
case TYPE_AUTH_METHOD_LDAP:
|
||||
case TYPE_AUTH_METHOD_OIDC:
|
||||
return {
|
||||
accounts: ['create', 'list'],
|
||||
'managed-groups': ['create', 'list'],
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
id: () => generateId('am_'),
|
||||
|
||||
// Cycle through available types
|
||||
type: (i) => TYPES_AUTH_METHOD[i % TYPES_AUTH_METHOD.length],
|
||||
|
||||
/**
|
||||
* Adds accounts (with associated users) to auth method and managed groups.
|
||||
*/
|
||||
withAccountsAndUsersAndManagedGroups: trait({
|
||||
afterCreate(authMethod, server) {
|
||||
const { scope, type } = authMethod;
|
||||
|
||||
server.createList('user', 5, { scope }).map((user) => {
|
||||
const { id } = server.create('account', { scope, type, authMethod });
|
||||
user.update({ accountIds: [id] });
|
||||
});
|
||||
|
||||
if (type === TYPE_AUTH_METHOD_OIDC || type === TYPE_AUTH_METHOD_LDAP) {
|
||||
server
|
||||
.createList('managed-group', 2, { scope, authMethod })
|
||||
.map((managedGroup) => {
|
||||
const accounts = server.createList('account', 2, {
|
||||
scope,
|
||||
type,
|
||||
authMethod,
|
||||
});
|
||||
const accountIds = accounts.map((account) => account.id);
|
||||
managedGroup.update({ memberIds: accountIds });
|
||||
});
|
||||
}
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/channel-recording';
|
||||
import generateId from '../helpers/id';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { MIME_TYPE_ASCIICAST } from 'api/models/channel-recording';
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('chr_'),
|
||||
start_time(i) {
|
||||
return i % 3 === 2
|
||||
? null
|
||||
: faker.date.recent({ days: 3, refDate: this.end_time });
|
||||
},
|
||||
end_time: (i) => (i % 3 === 2 ? null : faker.date.recent()),
|
||||
duration: (i) =>
|
||||
i % 3 === 2 ? null : `${faker.number.int({ max: 100000 })}s`,
|
||||
mime_types: (i) => (i % 3 === 2 ? null : [MIME_TYPE_ASCIICAST]),
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/connection-recording';
|
||||
import generateId from '../helpers/id';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('cr_'),
|
||||
connection_id: () => generateId('sc_'),
|
||||
start_time(i) {
|
||||
return i % 3 === 2
|
||||
? null
|
||||
: faker.date.recent({ days: 3, refDate: this.end_time });
|
||||
},
|
||||
end_time: (i) => (i % 3 === 2 ? null : faker.date.recent()),
|
||||
duration: (i) =>
|
||||
i % 3 === 2 ? null : `${faker.number.int({ max: 100000 })}s`,
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/credential-library';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
import {
|
||||
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
|
||||
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
|
||||
TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
|
||||
TYPES_CREDENTIAL_LIBRARY,
|
||||
options,
|
||||
} from 'api/models/credential-library';
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('cl_'),
|
||||
type: (i) => TYPES_CREDENTIAL_LIBRARY[i % TYPES_CREDENTIAL_LIBRARY.length],
|
||||
|
||||
credential_type(i) {
|
||||
if (this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC) {
|
||||
return options.credential_types[i % options.credential_types.length];
|
||||
}
|
||||
},
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('credential-library') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
],
|
||||
|
||||
attributes() {
|
||||
switch (this.type) {
|
||||
case TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC:
|
||||
return {
|
||||
http_method: 'GET',
|
||||
http_request_body: faker.word.words(1),
|
||||
path: faker.system.directoryPath(),
|
||||
};
|
||||
case TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE:
|
||||
return {
|
||||
username: faker.internet.userName(),
|
||||
key_bits: faker.number.int(999),
|
||||
path: faker.system.directoryPath(),
|
||||
};
|
||||
case TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP:
|
||||
return {
|
||||
path: faker.system.directoryPath(),
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/credential-store';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { trait } from 'miragejs';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
|
||||
const types = ['vault', 'static'];
|
||||
|
||||
export default factory.extend({
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('credential-store') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
],
|
||||
authorized_collection_actions() {
|
||||
switch (this.type) {
|
||||
case 'vault':
|
||||
return {
|
||||
'credential-libraries': ['create', 'list'],
|
||||
};
|
||||
case 'static':
|
||||
default:
|
||||
return {
|
||||
credentials: ['create', 'list'],
|
||||
};
|
||||
}
|
||||
},
|
||||
id: () => generateId('cs_'),
|
||||
type: (i) => types[i % types.length],
|
||||
|
||||
attributes() {
|
||||
switch (this.type) {
|
||||
case 'vault':
|
||||
return {
|
||||
address:
|
||||
Math.random() > 0.5 ? faker.internet.ip() : faker.internet.ipv6(),
|
||||
namespace: faker.word.words(1),
|
||||
ca_cert: 'ca-cert-123',
|
||||
tls_server_name: faker.internet.domainName(),
|
||||
tls_skip_verify: faker.datatype.boolean(),
|
||||
token_hmac: 'token-hmac-abcde0987654321',
|
||||
client_certificate: 'client-cert-123',
|
||||
client_certificate_key_hmac: 'client-cert-key-hmac-abcde0987654321',
|
||||
worker_filter: faker.word.words(),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
withAssociations: trait({
|
||||
afterCreate(credentialStore, server) {
|
||||
const { scope, type } = credentialStore;
|
||||
switch (type) {
|
||||
case 'vault':
|
||||
server.createList('credential-library', 3, {
|
||||
scope,
|
||||
credentialStore,
|
||||
});
|
||||
break;
|
||||
case 'static':
|
||||
default:
|
||||
server.createList('credential', 5, {
|
||||
scope,
|
||||
credentialStore,
|
||||
});
|
||||
}
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/credential';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generatedId from '../helpers/id';
|
||||
import {
|
||||
TYPES_CREDENTIAL,
|
||||
TYPE_CREDENTIAL_SSH_PRIVATE_KEY,
|
||||
TYPE_CREDENTIAL_USERNAME_PASSWORD,
|
||||
TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
|
||||
TYPE_CREDENTIAL_JSON,
|
||||
TYPE_CREDENTIAL_PASSWORD,
|
||||
} from 'api/models/credential';
|
||||
|
||||
const types = [...TYPES_CREDENTIAL];
|
||||
|
||||
export default factory.extend({
|
||||
type: (i) => types[i % types.length],
|
||||
id() {
|
||||
switch (this.type) {
|
||||
case TYPE_CREDENTIAL_SSH_PRIVATE_KEY:
|
||||
return generatedId('credspk_');
|
||||
case TYPE_CREDENTIAL_USERNAME_PASSWORD:
|
||||
return generatedId('credup_');
|
||||
case TYPE_CREDENTIAL_JSON:
|
||||
return generatedId('credjson_');
|
||||
case TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN:
|
||||
return generatedId('credupd_');
|
||||
case TYPE_CREDENTIAL_PASSWORD:
|
||||
return generatedId('credp_');
|
||||
}
|
||||
},
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('credential') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
],
|
||||
attributes() {
|
||||
switch (this.type) {
|
||||
case TYPE_CREDENTIAL_USERNAME_PASSWORD:
|
||||
return { username: faker.internet.userName() };
|
||||
|
||||
case TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN:
|
||||
return {
|
||||
username: faker.internet.userName(),
|
||||
domain: faker.internet.domainName(),
|
||||
};
|
||||
|
||||
case TYPE_CREDENTIAL_SSH_PRIVATE_KEY:
|
||||
return { username: faker.internet.userName() };
|
||||
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/group';
|
||||
import { trait } from 'miragejs';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
|
||||
export default factory.extend({
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('group') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
'add-members',
|
||||
'remove-members',
|
||||
],
|
||||
|
||||
id: () => generateId('g_'),
|
||||
|
||||
/**
|
||||
* Generates some users for the same scope and assigns them to the group
|
||||
* as members.
|
||||
*/
|
||||
withMembers: trait({
|
||||
afterCreate(group, server) {
|
||||
const scope = group.scope;
|
||||
const members = server.createList('user', 2, { scope });
|
||||
group.update({ members });
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/host-catalog';
|
||||
import { trait } from 'miragejs';
|
||||
import permissions from '../helpers/permissions';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import generateId from '../helpers/id';
|
||||
import {
|
||||
TYPE_HOST_CATALOG_PLUGIN_AZURE,
|
||||
TYPE_HOST_CATALOG_PLUGIN_GCP,
|
||||
TYPE_HOST_CATALOG_PLUGIN_AWS,
|
||||
TYPE_HOST_CATALOG_STATIC,
|
||||
TYPE_HOST_CATALOG_DYNAMIC,
|
||||
TYPES_HOST_CATALOG,
|
||||
} from 'api/models/host-catalog';
|
||||
|
||||
// Represents known plugin types, except "foobar" which models the possibility
|
||||
// of receiving an _unknown_ type, which the UI must handle gracefully.
|
||||
const pluginTypes = [
|
||||
TYPE_HOST_CATALOG_PLUGIN_GCP,
|
||||
TYPE_HOST_CATALOG_PLUGIN_AWS,
|
||||
TYPE_HOST_CATALOG_PLUGIN_AZURE,
|
||||
'foobar',
|
||||
];
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('hc_'),
|
||||
|
||||
// Cycle through available types
|
||||
type: (i) => TYPES_HOST_CATALOG[i % TYPES_HOST_CATALOG.length],
|
||||
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('host-catalog') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
],
|
||||
authorized_collection_actions: function () {
|
||||
const isStatic = this.type === TYPE_HOST_CATALOG_STATIC;
|
||||
return {
|
||||
// only static catalogs allow host create at this time
|
||||
hosts: isStatic ? ['create', 'list'] : ['list'],
|
||||
'host-sets': ['create', 'list'],
|
||||
};
|
||||
},
|
||||
|
||||
worker_filter: function () {
|
||||
if (
|
||||
this.type === TYPE_HOST_CATALOG_DYNAMIC &&
|
||||
(this.plugin?.name === TYPE_HOST_CATALOG_PLUGIN_AWS ||
|
||||
this.plugin?.name === TYPE_HOST_CATALOG_PLUGIN_GCP)
|
||||
) {
|
||||
return `"${faker.word.noun()}" in "${faker.system.directoryPath()}"`;
|
||||
}
|
||||
},
|
||||
|
||||
plugin: function (i) {
|
||||
if (this.type === TYPE_HOST_CATALOG_DYNAMIC) {
|
||||
return {
|
||||
id: `plugin-id-${i}`,
|
||||
name: pluginTypes[i % pluginTypes.length],
|
||||
description: faker.word.words(),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
attributes() {
|
||||
switch (this.plugin?.name) {
|
||||
case TYPE_HOST_CATALOG_PLUGIN_AWS:
|
||||
return {
|
||||
disable_credential_rotation: faker.datatype.boolean(),
|
||||
region: `us-${faker.location.cardinalDirection()}-${faker.number.int(
|
||||
9,
|
||||
)}`,
|
||||
};
|
||||
case TYPE_HOST_CATALOG_PLUGIN_AZURE:
|
||||
return {
|
||||
disable_credential_rotation: faker.datatype.boolean(),
|
||||
tenant_id: faker.string.uuid(),
|
||||
client_id: faker.string.uuid(),
|
||||
subscription_id: faker.string.uuid(),
|
||||
};
|
||||
case TYPE_HOST_CATALOG_PLUGIN_GCP:
|
||||
return {
|
||||
disable_credential_rotation: faker.datatype.boolean(),
|
||||
project_id: faker.string.uuid(),
|
||||
client_email: faker.internet.email(),
|
||||
target_service_account_id: faker.string.uuid(),
|
||||
zone: `us-${faker.location.cardinalDirection()}${faker.number.int(
|
||||
9,
|
||||
)}-${faker.string.fromCharacters('abc')}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
secrets() {
|
||||
switch (this.plugin?.name) {
|
||||
case TYPE_HOST_CATALOG_PLUGIN_AWS:
|
||||
return {
|
||||
access_key_id: faker.string.nanoid(),
|
||||
secret_access_key: faker.string.nanoid(),
|
||||
};
|
||||
case TYPE_HOST_CATALOG_PLUGIN_AZURE:
|
||||
return {
|
||||
secret_id: faker.string.nanoid(),
|
||||
secret_value: faker.string.nanoid(),
|
||||
};
|
||||
case TYPE_HOST_CATALOG_PLUGIN_GCP:
|
||||
return {
|
||||
private_key: faker.string.nanoid(),
|
||||
private_key_id: faker.string.nanoid(),
|
||||
};
|
||||
}
|
||||
},
|
||||
withChildren: trait({
|
||||
afterCreate(hostCatalog, server) {
|
||||
const { scope, type } = hostCatalog;
|
||||
const hosts = server.createList('host', 10, { scope, hostCatalog, type });
|
||||
const hostSets = server.createList('host-set', 3, {
|
||||
scope,
|
||||
hostCatalog,
|
||||
hosts,
|
||||
type,
|
||||
});
|
||||
const hostSetIds = hostSets.map((hostSet) => hostSet.id);
|
||||
hosts.forEach((host) => {
|
||||
host.update({ hostSetIds });
|
||||
});
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/host-set';
|
||||
import permissions from '../helpers/permissions';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import generateId from '../helpers/id';
|
||||
import {
|
||||
TYPE_HOST_CATALOG_PLUGIN_AWS,
|
||||
TYPE_HOST_CATALOG_PLUGIN_AZURE,
|
||||
TYPE_HOST_CATALOG_PLUGIN_GCP,
|
||||
} from 'api/models/host-catalog';
|
||||
|
||||
function generateFilters(prefix) {
|
||||
const filtersAmount = faker.number.int({ min: 1, max: 5 });
|
||||
let filters = [];
|
||||
for (let i = 0; i < filtersAmount; ++i) {
|
||||
filters.push(`${prefix}${faker.word.words(1)}=${faker.word.words(1)}`);
|
||||
}
|
||||
return {
|
||||
filters,
|
||||
};
|
||||
}
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('hs_'),
|
||||
type() {
|
||||
return this.hostCatalog?.type || factory.attrs.type;
|
||||
},
|
||||
authorized_actions: function () {
|
||||
const isStatic = this.type === 'static';
|
||||
const defaults = ['no-op', 'read', 'update', 'delete'];
|
||||
// Only static allows host management at this time.
|
||||
if (isStatic) defaults.push('add-hosts', 'remove-hosts');
|
||||
return permissions.authorizedActionsFor('host-set') || defaults;
|
||||
},
|
||||
plugin() {
|
||||
if (this.type === 'plugin') {
|
||||
return this.hostCatalog.plugin;
|
||||
}
|
||||
},
|
||||
preferred_endpoints() {
|
||||
if (this.type === 'plugin') {
|
||||
const endpointsAmount = faker.number.int({ min: 1, max: 5 });
|
||||
let result = [];
|
||||
for (let i = 0; i < endpointsAmount; ++i) {
|
||||
result.push(
|
||||
Math.random() > 0.5 ? faker.internet.ip() : faker.internet.ipv6(),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
sync_interval_seconds() {
|
||||
if (this.type === 'plugin') {
|
||||
return faker.number.int();
|
||||
}
|
||||
},
|
||||
|
||||
attributes() {
|
||||
switch (this.plugin?.name) {
|
||||
case TYPE_HOST_CATALOG_PLUGIN_AWS:
|
||||
return generateFilters('tag:');
|
||||
case TYPE_HOST_CATALOG_PLUGIN_AZURE:
|
||||
return {
|
||||
filter: `${faker.database.column()}=${faker.database.collation()}`,
|
||||
};
|
||||
case TYPE_HOST_CATALOG_PLUGIN_GCP:
|
||||
return generateFilters('labels.');
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/host';
|
||||
import permissions from '../helpers/permissions';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import generateId from '../helpers/id';
|
||||
import {
|
||||
TYPE_HOST_CATALOG_STATIC,
|
||||
TYPE_HOST_CATALOG_DYNAMIC,
|
||||
} from 'api/models/host-catalog';
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('h_'),
|
||||
name() {
|
||||
if (this.type === TYPE_HOST_CATALOG_STATIC) return faker.word.words();
|
||||
},
|
||||
type() {
|
||||
return this.hostCatalog?.type || factory.attrs.type;
|
||||
},
|
||||
authorized_actions: function () {
|
||||
const isStatic = this.type === TYPE_HOST_CATALOG_STATIC;
|
||||
const defaults = ['no-op', 'read'];
|
||||
// Only static allows update/delete at this time.
|
||||
if (isStatic) defaults.push('update', 'delete');
|
||||
return permissions.authorizedActionsFor('host') || defaults;
|
||||
},
|
||||
plugin() {
|
||||
if (this.type === TYPE_HOST_CATALOG_DYNAMIC) {
|
||||
return this.hostCatalog.plugin;
|
||||
}
|
||||
},
|
||||
ip_addresses() {
|
||||
const addressesAmount = Math.floor(Math.random() * 6) + 1;
|
||||
let result = [];
|
||||
for (let i = 0; i < addressesAmount; ++i) {
|
||||
result.push(
|
||||
Math.random() > 0.5 ? faker.internet.ip() : faker.internet.ipv6(),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
// Return external fields only for plugins
|
||||
external_id() {
|
||||
if (this.type === TYPE_HOST_CATALOG_DYNAMIC) {
|
||||
return faker.string.uuid();
|
||||
}
|
||||
},
|
||||
external_name(i) {
|
||||
if (this.type === TYPE_HOST_CATALOG_DYNAMIC) {
|
||||
return `${this.plugin.name} provided name ${i}`;
|
||||
}
|
||||
},
|
||||
// Only aws plugins have dns_names
|
||||
dns_names() {
|
||||
if (this.plugin?.name === 'aws') {
|
||||
const dnsNamesAmount = Math.floor(Math.random() * 6) + 1;
|
||||
let result = [];
|
||||
for (let i = 0; i < dnsNamesAmount; i++) {
|
||||
result.push(faker.internet.domainName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/managed-group';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
export default factory.extend({
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('managed-group') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
],
|
||||
|
||||
id: () => generateId('mg_'),
|
||||
|
||||
type() {
|
||||
return this.authMethod?.type;
|
||||
},
|
||||
|
||||
attributes() {
|
||||
switch (this.type) {
|
||||
case TYPE_AUTH_METHOD_OIDC:
|
||||
return {
|
||||
filter: `"${faker.word.noun()}" in "${faker.system.directoryPath()}"`,
|
||||
};
|
||||
case TYPE_AUTH_METHOD_LDAP: {
|
||||
const num = faker.number.int({ min: 2, max: 4 });
|
||||
const names = [];
|
||||
for (let i = 0; i < num; i++) {
|
||||
names.push(faker.word.noun());
|
||||
}
|
||||
return {
|
||||
group_names: names,
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/policy';
|
||||
import permissions from '../helpers/permissions';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import generateId from '../helpers/id';
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('pst_'),
|
||||
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('policy') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
],
|
||||
|
||||
attributes() {
|
||||
return {
|
||||
retain_for: {
|
||||
days: faker.number.int({ min: 10, max: 100 }),
|
||||
overridable: faker.datatype.boolean(),
|
||||
},
|
||||
|
||||
delete_after: {
|
||||
days: faker.number.int({ min: 101, max: 500 }),
|
||||
overridable: faker.datatype.boolean(),
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/role';
|
||||
import { trait } from 'miragejs';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
import {
|
||||
TYPE_SCOPE_GLOBAL,
|
||||
TYPE_SCOPE_ORG,
|
||||
TYPE_SCOPE_PROJECT,
|
||||
} from 'api/models/scope';
|
||||
|
||||
export default factory.extend({
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('role') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
'set-grants',
|
||||
'add-principals',
|
||||
'remove-principals',
|
||||
'set-grant-scopes',
|
||||
],
|
||||
// eslint-disable-next-line ember/avoid-leaking-state-in-ember-objects
|
||||
grant_strings: () => [
|
||||
'ids=*;action=*',
|
||||
'ids=*;type=host-catalog;actions=create,read',
|
||||
],
|
||||
|
||||
id: () => generateId('r_'),
|
||||
grant_scope_ids: () => ['this'],
|
||||
|
||||
/**
|
||||
* Adds grant scopes to the role.
|
||||
*/
|
||||
withScopes: trait({
|
||||
afterCreate(role, server) {
|
||||
const { scope } = role;
|
||||
const newScope =
|
||||
scope.id === 'global'
|
||||
? server.create('scope', {
|
||||
scope: { id: 'global', type: TYPE_SCOPE_GLOBAL },
|
||||
type: 'org',
|
||||
})
|
||||
: server.create('scope', {
|
||||
scope: { id: scope.id, type: TYPE_SCOPE_ORG },
|
||||
type: TYPE_SCOPE_PROJECT,
|
||||
});
|
||||
role.update({ grant_scope_ids: ['this', newScope.id] });
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
* Adds principals to the role.
|
||||
*/
|
||||
withPrincipals: trait({
|
||||
afterCreate(role, server) {
|
||||
const { scope } = role;
|
||||
const { id: scopeId } = scope;
|
||||
const users = server.createList('user', 2, { scope });
|
||||
const groups = server.createList('group', 2, { scope });
|
||||
const managedGroups = server.schema.managedGroups.where({
|
||||
scopeId,
|
||||
}).models;
|
||||
role.update({ users, groups, managedGroups });
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/scope';
|
||||
import { trait } from 'miragejs';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { TYPE_AUTH_METHOD_PASSWORD } from 'api/models/auth-method';
|
||||
|
||||
export default factory.extend({
|
||||
type: 'global',
|
||||
|
||||
authorized_actions() {
|
||||
const authorizedActions = ['no-op', 'read', 'update'];
|
||||
|
||||
// Storage policies can only be attached to global and org scopes.
|
||||
if (this.type === 'global' || this.type === 'org') {
|
||||
authorizedActions.push('attach-storage-policy', 'detach-storage-policy');
|
||||
}
|
||||
|
||||
if (this.type === 'org' || this.type === 'project') {
|
||||
authorizedActions.push('delete');
|
||||
}
|
||||
|
||||
return permissions.authorizedActionsFor('scope') || authorizedActions;
|
||||
},
|
||||
|
||||
authorized_collection_actions() {
|
||||
const collectionActions = {
|
||||
scopes: ['create', 'list'],
|
||||
groups: ['create', 'list'],
|
||||
roles: ['create', 'list'],
|
||||
};
|
||||
|
||||
// Resources that are available only on the global scope
|
||||
if (this.type === 'global') {
|
||||
collectionActions.workers = ['create:worker-led', 'list'];
|
||||
collectionActions.aliases = ['create', 'list'];
|
||||
}
|
||||
|
||||
// Resources that are only available on the global or the org scope
|
||||
if (this.type === 'global' || this.type === 'org') {
|
||||
collectionActions['storage-buckets'] = ['create', 'list'];
|
||||
collectionActions['session-recordings'] = ['list'];
|
||||
collectionActions.users = ['create', 'list'];
|
||||
collectionActions['auth-methods'] = ['create', 'list'];
|
||||
collectionActions['policies'] = ['create', 'list'];
|
||||
}
|
||||
|
||||
if (this.type === 'project') {
|
||||
collectionActions['credential-stores'] = ['create', 'list'];
|
||||
collectionActions['host-catalogs'] = ['create', 'list'];
|
||||
collectionActions.sessions = ['list'];
|
||||
collectionActions.targets = ['create', 'list'];
|
||||
}
|
||||
|
||||
return collectionActions;
|
||||
},
|
||||
|
||||
id() {
|
||||
let id = 'global';
|
||||
if (this.type === 'org') {
|
||||
id = generateId('o_');
|
||||
}
|
||||
if (this.type === 'project') {
|
||||
id = generateId('p_');
|
||||
}
|
||||
return id;
|
||||
},
|
||||
|
||||
name() {
|
||||
let name = faker.word.words();
|
||||
if (this.type === 'global') {
|
||||
name = 'global';
|
||||
}
|
||||
return name;
|
||||
},
|
||||
|
||||
scope() {
|
||||
if (this.type === 'global') {
|
||||
return {
|
||||
id: 'global',
|
||||
type: 'global',
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
withChildren: trait({
|
||||
afterCreate(record, server) {
|
||||
if (record.type === 'global') {
|
||||
server.createList(
|
||||
'scope',
|
||||
1,
|
||||
{
|
||||
type: 'org',
|
||||
scope: { id: record.id, type: record.type },
|
||||
},
|
||||
'withChildren',
|
||||
);
|
||||
}
|
||||
if (record.type === 'org') {
|
||||
server.createList('scope', 3, {
|
||||
type: 'project',
|
||||
scope: { id: record.id, type: record.type },
|
||||
});
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
withGlobalAuth: trait({
|
||||
afterCreate(record, server) {
|
||||
if (record.type === 'global') {
|
||||
const authMethod = server.create('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||
scope: record,
|
||||
});
|
||||
server.create('account', {
|
||||
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||
full_name: 'admin',
|
||||
scope: record,
|
||||
authMethod,
|
||||
});
|
||||
}
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/session-recording';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { trait } from 'miragejs';
|
||||
import {
|
||||
TYPES_SESSION_RECORDING as types,
|
||||
STATE_SESSION_RECORDING_STARTED,
|
||||
STATE_SESSION_RECORDING_AVAILABLE,
|
||||
STATE_SESSION_RECORDING_UNKNOWN,
|
||||
} from 'api/models/session-recording';
|
||||
|
||||
const states = [
|
||||
STATE_SESSION_RECORDING_AVAILABLE,
|
||||
STATE_SESSION_RECORDING_STARTED,
|
||||
STATE_SESSION_RECORDING_UNKNOWN,
|
||||
];
|
||||
const pickRandomElement = (arr) => faker.helpers.arrayElement(arr);
|
||||
export default factory.extend({
|
||||
id: () => generateId('sr_'),
|
||||
|
||||
// Cycle through available types
|
||||
type: (i) => types[i % types.length],
|
||||
state: (i) => states[i % states.length],
|
||||
start_time() {
|
||||
return this.state === STATE_SESSION_RECORDING_AVAILABLE
|
||||
? faker.date.recent({ days: 3, refDate: this.end_time })
|
||||
: null;
|
||||
},
|
||||
end_time() {
|
||||
return this.state === STATE_SESSION_RECORDING_AVAILABLE
|
||||
? faker.date.recent({ days: 1, refDate: this.updated_time })
|
||||
: null;
|
||||
},
|
||||
duration() {
|
||||
return this.state === STATE_SESSION_RECORDING_AVAILABLE
|
||||
? `${faker.number.int({ max: 100000 })}s`
|
||||
: null;
|
||||
},
|
||||
|
||||
retain_until() {
|
||||
return this.state === STATE_SESSION_RECORDING_AVAILABLE
|
||||
? faker.date.recent()
|
||||
: null;
|
||||
},
|
||||
delete_after() {
|
||||
return this.state === STATE_SESSION_RECORDING_AVAILABLE
|
||||
? faker.date.recent()
|
||||
: null;
|
||||
},
|
||||
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('session-recording') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'download',
|
||||
'reapply-storage-policy',
|
||||
'delete',
|
||||
],
|
||||
|
||||
withNonExistingUserAndTarget: trait({
|
||||
afterCreate(sessionRecording, server) {
|
||||
const user = pickRandomElement(server.schema.users.all().models);
|
||||
user.id = 'deleted_user';
|
||||
const session = pickRandomElement(server.schema.sessions.all().models);
|
||||
session.id = 'deleted_session';
|
||||
const target = pickRandomElement(
|
||||
server.schema.targets.where((target) => target.storage_bucket_id)
|
||||
.models,
|
||||
);
|
||||
target.id = 'deleted_target';
|
||||
|
||||
sessionRecording.update({
|
||||
sessionId: session.id,
|
||||
storage_bucket_id: target.storage_bucket_id,
|
||||
create_time_values: {
|
||||
user: user.attrs,
|
||||
target: target.attrs,
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
withExistingUserAndTarget: trait({
|
||||
afterCreate(sessionRecording, server) {
|
||||
const user = pickRandomElement(server.schema.users.all().models);
|
||||
const session = pickRandomElement(server.schema.sessions.all().models);
|
||||
const target = pickRandomElement(
|
||||
server.schema.targets.where((target) => target.storage_bucket_id)
|
||||
.models,
|
||||
);
|
||||
|
||||
sessionRecording.update({
|
||||
sessionId: session.id,
|
||||
storage_bucket_id: target.storage_bucket_id,
|
||||
create_time_values: {
|
||||
user: user.attrs,
|
||||
target: target.attrs,
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
withConnectionAndChannels: trait({
|
||||
afterCreate(session_recording, server) {
|
||||
server
|
||||
.createList('connection-recording', 3, { session_recording })
|
||||
.forEach((connection_recording) => {
|
||||
server.createList('channel-recording', 3, { connection_recording });
|
||||
});
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/session';
|
||||
import { trait } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import generateId from '../helpers/id';
|
||||
import permissions from '../helpers/permissions';
|
||||
|
||||
const statusStrings = ['pending', 'active', 'canceling', 'terminated'];
|
||||
|
||||
export const pickRandomStatusString = () =>
|
||||
faker.helpers.arrayElement(statusStrings);
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('ss_'),
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('session') || ['read', 'cancel'],
|
||||
status: pickRandomStatusString(),
|
||||
|
||||
/**
|
||||
* Sessions generated with this trait will automatically form
|
||||
* associations to user, target, host set, and host (if available) within
|
||||
* the current scope.
|
||||
*/
|
||||
withAssociations: trait({
|
||||
afterCreate(record, server) {
|
||||
const scopeId = record.scopeId;
|
||||
|
||||
// Assign a user to this session if not already assigned.
|
||||
if (record.scope && !record.user) {
|
||||
const scopeId =
|
||||
record.scope.type === 'project'
|
||||
? record.scope?.scope.id
|
||||
: record.scope.id;
|
||||
const user = server.schema.users.where({ scopeId }).models[0];
|
||||
if (user) record.update({ user });
|
||||
}
|
||||
|
||||
// Assign target and host set to this session, if not already assigned.
|
||||
const target = server.schema.targets.where({ scopeId }).models[0];
|
||||
if (target) {
|
||||
record.update({ target });
|
||||
const hostSet = target.hostSets.models[0];
|
||||
if (hostSet) {
|
||||
record.update({ hostSet });
|
||||
const host = hostSet.hosts.models[0];
|
||||
if (host) record.update({ host });
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/storage-bucket';
|
||||
import permissions from '../helpers/permissions';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import generateId from '../helpers/id';
|
||||
import {
|
||||
TYPES_STORAGE_BUCKET as types,
|
||||
TYPES_STORAGE_BUCKET_PLUGIN,
|
||||
TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3,
|
||||
TYPE_STORAGE_BUCKET_PLUGIN_MINIO,
|
||||
} from 'api/models/storage-bucket';
|
||||
|
||||
// Represents known plugin types, except "foobar" which models the possibility
|
||||
// of receiving an _unknown_ type, which the UI must handle gracefully.
|
||||
const pluginTypes = [...TYPES_STORAGE_BUCKET_PLUGIN, 'foobar'];
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('sb_'),
|
||||
|
||||
// Cycle through available types
|
||||
type: (i) => types[i % types.length],
|
||||
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('storage-bucket') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
],
|
||||
|
||||
plugin: function (i) {
|
||||
if (this.type === 'plugin') {
|
||||
return {
|
||||
id: `plugin-id-${i}`,
|
||||
name: pluginTypes[i % pluginTypes.length],
|
||||
description: faker.word.words(),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
attributes() {
|
||||
switch (this.plugin?.name) {
|
||||
case TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3:
|
||||
return {
|
||||
region: `us-${faker.location.cardinalDirection()}-${faker.number.int(
|
||||
9,
|
||||
)}`,
|
||||
disable_credential_rotation: faker.datatype.boolean(),
|
||||
};
|
||||
case TYPE_STORAGE_BUCKET_PLUGIN_MINIO:
|
||||
return {
|
||||
endpoint_url: faker.internet.url(),
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/target';
|
||||
import { trait } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
import {
|
||||
TYPES_TARGET,
|
||||
TYPE_TARGET_SSH,
|
||||
TYPE_TARGET_RDP,
|
||||
} from 'api/models/target';
|
||||
import {
|
||||
TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
|
||||
TYPE_CREDENTIAL_USERNAME_PASSWORD,
|
||||
TYPE_CREDENTIAL_JSON,
|
||||
TYPE_CREDENTIAL_PASSWORD,
|
||||
} from 'api/models/credential';
|
||||
import { TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP } from 'api/models/credential-library';
|
||||
|
||||
const randomBoolean = (chance = 0.5) => Math.random() < chance;
|
||||
const randomFilter = () =>
|
||||
`"${faker.word.noun()}" in "${faker.system.directoryPath()}"`;
|
||||
const hostSetChance = 0.3;
|
||||
const types = [...TYPES_TARGET];
|
||||
|
||||
/**
|
||||
* Helper to select items from a collection based on a condition.
|
||||
*/
|
||||
const selectItems = (collection, condition) =>
|
||||
collection
|
||||
.where(condition)
|
||||
.models.filter(() => randomBoolean())
|
||||
.map((item) => item.id);
|
||||
|
||||
/**
|
||||
* Helper to update target with selected credential sources and host sets.
|
||||
*/
|
||||
const updateTarget = (
|
||||
target,
|
||||
hostSets,
|
||||
isInjectable,
|
||||
injectedSources,
|
||||
brokeredSources,
|
||||
) => {
|
||||
const fieldsToUpdate = {
|
||||
hostSets,
|
||||
brokeredCredentialSourceIds: brokeredSources,
|
||||
};
|
||||
if (isInjectable) {
|
||||
fieldsToUpdate.injectedApplicationCredentialSourceIds = injectedSources;
|
||||
}
|
||||
target.update(fieldsToUpdate);
|
||||
};
|
||||
|
||||
export default factory.extend({
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('target') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
'authorize-session',
|
||||
'add-host-sources',
|
||||
'remove-host-sources',
|
||||
'add-credential-sources',
|
||||
'remove-credential-sources',
|
||||
],
|
||||
id: () => generateId('t_'),
|
||||
|
||||
/**
|
||||
* -1 means "unlimited" and we want to generate these on occasion.
|
||||
*/
|
||||
session_connection_limit: () =>
|
||||
faker.helpers.arrayElement([-1, faker.number.int()]),
|
||||
egress_worker_filter: (i) => (i % 2 !== 0 ? randomFilter() : null),
|
||||
ingress_worker_filter: (i) => (i % 2 !== 0 ? randomFilter() : null),
|
||||
type: (i) => types[i % types.length],
|
||||
|
||||
/**
|
||||
* Randomly selects existing host sets and credential libraries to assign to target.
|
||||
*/
|
||||
withAssociations: trait({
|
||||
afterCreate(target, server) {
|
||||
const { scope } = target;
|
||||
|
||||
const 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
|
||||
// expect at this level of abstraction, but appears to be a serialized
|
||||
// representation of the model instance. It's very confusing since
|
||||
// the result set of `where` _is a collection of model instances_.
|
||||
.where((hostSet) => hostSet.scopeId === scope.id)
|
||||
.models.filter(() => randomBoolean(hostSetChance));
|
||||
|
||||
const randomlySelectedBrokeredCredentialSources = [
|
||||
...selectItems(
|
||||
server.schema.credentialLibraries,
|
||||
(credentialLibrary) => credentialLibrary.scopeId === target.scope.id,
|
||||
),
|
||||
...selectItems(
|
||||
server.schema.credentials,
|
||||
(credential) => credential.scopeId === target.scope.id,
|
||||
),
|
||||
];
|
||||
|
||||
// Select compatible credential libraries and credentials for injection
|
||||
// Since not every credential or credential library can be injected, we filter them to mimic the expected behavior.
|
||||
const filteredCredentialLibraries = selectItems(
|
||||
server.schema.credentialLibraries,
|
||||
(cred) =>
|
||||
cred.scopeId === scope.id &&
|
||||
cred.credential_type !== TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN &&
|
||||
cred.credential_type !== TYPE_CREDENTIAL_PASSWORD &&
|
||||
cred.type !== TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
|
||||
);
|
||||
const filteredCredentials = selectItems(
|
||||
server.schema.credentials,
|
||||
(cred) =>
|
||||
cred.scopeId === scope.id &&
|
||||
![
|
||||
TYPE_CREDENTIAL_JSON,
|
||||
TYPE_CREDENTIAL_PASSWORD,
|
||||
TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
|
||||
].includes(cred.type),
|
||||
);
|
||||
|
||||
// RDP specific credential libraries and credentials
|
||||
const filteredCredentialLibrariesForRDP = selectItems(
|
||||
server.schema.credentialLibraries,
|
||||
(cred) =>
|
||||
(cred.scopeId === scope.id &&
|
||||
[
|
||||
TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
|
||||
TYPE_CREDENTIAL_USERNAME_PASSWORD,
|
||||
].includes(cred.credential_type)) ||
|
||||
cred.type == TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
|
||||
);
|
||||
const filteredCredentialsForRDP = selectItems(
|
||||
server.schema.credentials,
|
||||
(cred) =>
|
||||
cred.scopeId === scope.id &&
|
||||
[
|
||||
TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
|
||||
TYPE_CREDENTIAL_USERNAME_PASSWORD,
|
||||
].includes(cred.type),
|
||||
);
|
||||
|
||||
// Update target based on type
|
||||
const isInjectable =
|
||||
target.type === TYPE_TARGET_SSH || target.type === TYPE_TARGET_RDP;
|
||||
const injectedCredentialSources =
|
||||
target.type === TYPE_TARGET_RDP
|
||||
? [...filteredCredentialLibrariesForRDP, ...filteredCredentialsForRDP]
|
||||
: [...filteredCredentialLibraries, ...filteredCredentials];
|
||||
|
||||
updateTarget(
|
||||
target,
|
||||
randomlySelectedHostSets,
|
||||
isInjectable,
|
||||
injectedCredentialSources,
|
||||
randomlySelectedBrokeredCredentialSources,
|
||||
);
|
||||
|
||||
// Add storage bucket for SSH targets
|
||||
const storageBuckets = server.schema.storageBuckets.all().models;
|
||||
const randomlySelectedStorageBucket =
|
||||
storageBuckets.length === 0
|
||||
? undefined
|
||||
: faker.helpers.arrayElement(storageBuckets);
|
||||
|
||||
if (randomlySelectedStorageBucket && target.type === TYPE_TARGET_SSH) {
|
||||
target.update({
|
||||
storage_bucket_id: randomlySelectedStorageBucket.id,
|
||||
enable_session_recording: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Add Aliases
|
||||
const aliases = server.schema.aliases.all().models;
|
||||
const randomlySelectedAliases =
|
||||
aliases.length === 0 ? undefined : faker.helpers.arrayElement(aliases);
|
||||
if (randomlySelectedAliases) {
|
||||
target.update({
|
||||
aliases: randomlySelectedAliases.aliases,
|
||||
});
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
withManyHosts: trait({
|
||||
afterCreate(target, server) {
|
||||
const { scope } = target;
|
||||
const hostCatalog = server.create('host-catalog', { scope });
|
||||
const hosts = server.createList('host', 15, {
|
||||
scope,
|
||||
hostCatalog,
|
||||
type: hostCatalog.type,
|
||||
});
|
||||
const hostSets = [
|
||||
server.create('host-set', {
|
||||
scope,
|
||||
hostCatalog,
|
||||
hosts,
|
||||
type: hostCatalog.type,
|
||||
}),
|
||||
];
|
||||
const hostSetIds = hostSets.map((hostSet) => hostSet.id);
|
||||
hosts.forEach((host) => {
|
||||
host.update({ hostSetIds });
|
||||
});
|
||||
target.update({ hostSets });
|
||||
},
|
||||
}),
|
||||
|
||||
withTwoHosts: trait({
|
||||
afterCreate(target, server) {
|
||||
const { scope } = target;
|
||||
const hostCatalog = server.create('host-catalog', { scope });
|
||||
const hosts = server.createList('host', 2, {
|
||||
scope,
|
||||
hostCatalog,
|
||||
type: hostCatalog.type,
|
||||
});
|
||||
const hostSets = [
|
||||
server.create('host-set', {
|
||||
scope,
|
||||
hostCatalog,
|
||||
hosts,
|
||||
type: hostCatalog.type,
|
||||
}),
|
||||
];
|
||||
const hostSetIds = hostSets.map((hostSet) => hostSet.id);
|
||||
hosts.forEach((host) => {
|
||||
host.update({ hostSetIds });
|
||||
});
|
||||
target.update({ hostSets });
|
||||
},
|
||||
}),
|
||||
|
||||
withOneHost: trait({
|
||||
afterCreate(target, server) {
|
||||
const { scope } = target;
|
||||
const hostCatalog = server.create('host-catalog', { scope });
|
||||
const hosts = [
|
||||
server.create('host', { scope, hostCatalog, type: hostCatalog.type }),
|
||||
];
|
||||
const hostSets = [
|
||||
server.create('host-set', {
|
||||
scope,
|
||||
hostCatalog,
|
||||
hosts,
|
||||
type: hostCatalog.type,
|
||||
}),
|
||||
];
|
||||
const hostSetIds = hostSets.map((hostSet) => hostSet.id);
|
||||
hosts.forEach((host) => {
|
||||
host.update({ hostSetIds });
|
||||
});
|
||||
target.update({ hostSets });
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/user';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
|
||||
export default factory.extend({
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('user') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
'add-accounts',
|
||||
'remove-accounts',
|
||||
],
|
||||
id: () => generateId('u_'),
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import factory from '../generated/factories/worker';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('w_'),
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('worker') || [
|
||||
'no-op',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
'set-worker-tags',
|
||||
'remove-worker-tags',
|
||||
],
|
||||
config_tags: (i) => {
|
||||
if (i % 3 === 0) {
|
||||
return {
|
||||
os: ['ubuntu'],
|
||||
env: ['dev', 'local'],
|
||||
};
|
||||
}
|
||||
if (i % 2 === 0) {
|
||||
return { os: ['ubuntu'] };
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
api_tags: (i) => {
|
||||
if (i % 3 === 0) {
|
||||
return {
|
||||
type: [faker.word.words(1), faker.word.words(1)],
|
||||
os: ['z-os'],
|
||||
env: ['prod', 'qa'],
|
||||
sample: [faker.word.words(1), faker.word.words(1)],
|
||||
path: [faker.word.words(1)],
|
||||
};
|
||||
}
|
||||
if (i % 2 === 0) {
|
||||
return { os: ['z-os'] };
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
canonical_tags() {
|
||||
const configTags = this.config_tags || {};
|
||||
const apiTags = this.api_tags || {};
|
||||
const canonicalTags = {};
|
||||
|
||||
Object.keys(configTags).forEach((key) => {
|
||||
canonicalTags[key] = new Set(configTags[key]);
|
||||
});
|
||||
|
||||
Object.keys(apiTags).forEach((key) => {
|
||||
if (canonicalTags[key]) {
|
||||
apiTags[key].forEach((tag) => canonicalTags[key].add(tag));
|
||||
} else {
|
||||
canonicalTags[key] = new Set(apiTags[key]);
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(canonicalTags).forEach((key) => {
|
||||
canonicalTags[key] = Array.from(canonicalTags[key]);
|
||||
});
|
||||
|
||||
return canonicalTags;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedAccountFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
version: () => faker.number.int(),
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { TYPE_ALIAS_TARGET } from 'api/models/alias';
|
||||
|
||||
/**
|
||||
* GeneratedAliasModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
type: TYPE_ALIAS_TARGET,
|
||||
value: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
version: () => faker.number.int(),
|
||||
});
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
import {
|
||||
TYPE_AUTH_METHOD_PASSWORD,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
/**
|
||||
* GeneratedAuthMethodModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
disabled: () => faker.datatype.boolean(),
|
||||
|
||||
attributes: function () {
|
||||
let attrs;
|
||||
switch (this.type) {
|
||||
case TYPE_AUTH_METHOD_OIDC:
|
||||
attrs = {
|
||||
api_url_prefix: 'http://127.0.0.1:9200',
|
||||
callback_url:
|
||||
'http://127.0.0.1:9200/v1/auth-methods/oidc:authenticate:callback',
|
||||
client_id: 'YTwdJBB55LpKnuXb9n65',
|
||||
client_secret_hmac: 'GY7blb4ynM5TEPNi_qnphJ9aDWhW8FpmN3D-eP_L7Zk',
|
||||
issuer: 'http://127.0.0.1:57070',
|
||||
max_age: 1800,
|
||||
disable_discovered_config_validation: false,
|
||||
state: 'active-public',
|
||||
account_claim_maps: ['oid=sub', 'full_name=name'],
|
||||
claims_scopes: ['profile', 'email'],
|
||||
signing_algorithms: ['RS256', 'RS384'],
|
||||
allowed_audiences: ['www.alice.com', 'www.alice.com/admin'],
|
||||
idp_ca_certs: ['certificate-1234', 'certificate-5678'],
|
||||
prompts: ['consent'],
|
||||
};
|
||||
break;
|
||||
case TYPE_AUTH_METHOD_LDAP:
|
||||
attrs = {
|
||||
state: 'active-public',
|
||||
urls: [`ldap://${faker.internet.domainName()}`],
|
||||
certificates: [faker.string.alphanumeric(50)],
|
||||
client_certificate: faker.string.alphanumeric(50),
|
||||
client_certificate_key: `---Begin Certificate --- ${faker.string.alphanumeric(
|
||||
170,
|
||||
)} ---End Certificate ---`,
|
||||
client_certificate_key_hmac: faker.string.alphanumeric(50),
|
||||
enable_groups: true,
|
||||
start_tls: false,
|
||||
insecure_tls: false,
|
||||
bind_dn: 'cn=read-only-admin,dc=example,dc=com',
|
||||
bind_password: 'password',
|
||||
bind_password_hmac: faker.string.alphanumeric(50),
|
||||
upn_domain: 'example.com',
|
||||
discover_dn: false,
|
||||
anon_group_search: false,
|
||||
user_dn: 'dc=example,dc=com',
|
||||
user_attr: 'uid',
|
||||
user_filter: '({{.UserAttr}}={{.Username}})',
|
||||
group_dn: 'dc=example,dc=com',
|
||||
group_attr: 'cn',
|
||||
group_filter: '(|(memberUid={{.Username}})',
|
||||
account_attribute_maps: [
|
||||
'preferredName=fullName',
|
||||
'preferredEmail=email',
|
||||
],
|
||||
use_token_groups: false,
|
||||
};
|
||||
break;
|
||||
}
|
||||
return attrs;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedChannelRecordingModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
bytes_up: () => faker.string.numeric(faker.number.int({ min: 1, max: 12 })),
|
||||
bytes_down: () => faker.string.numeric(faker.number.int({ min: 1, max: 12 })),
|
||||
errors: () => faker.number.int({ max: 10 }),
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedConnectionRecordingModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
bytes_up: () => faker.string.numeric(faker.number.int({ min: 1, max: 12 })),
|
||||
bytes_down: () => faker.string.numeric(faker.number.int({ min: 1, max: 12 })),
|
||||
errors: () => faker.number.int({ max: 10 }),
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedCredentialLibraryModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedCredentialStoreModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedCredentialModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
version: () => faker.number.int(),
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedGroupModelFactory
|
||||
* Group contains all fields related to a Group resource
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
disabled: () => faker.datatype.boolean(),
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedHostCatalogModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
type: 'static',
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
disabled: () => faker.datatype.boolean(),
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedHostSetModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
type: 'static',
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
version: () => faker.number.int(),
|
||||
size: () => faker.number.int(),
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedHostModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
type: 'static',
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
version: () => faker.number.int(),
|
||||
attributes: () => {
|
||||
return {
|
||||
address:
|
||||
Math.random() > 0.5 ? faker.internet.ip() : faker.internet.ipv6(),
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedManagedGroupFactory
|
||||
* A managed group is a resource that represents a collection of accounts.
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
version: () => faker.number.int(),
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedOrgModelFactory
|
||||
*
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedStoragePolicyModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
type: 'storage',
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
version: () => faker.number.int(),
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedProjectModelFactory
|
||||
* Project contains all fields related to a Project resource
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
disabled: () => faker.datatype.boolean(),
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedRoleModelFactory
|
||||
* Role contains all field related to a Role resource
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
disabled: () => faker.datatype.boolean(),
|
||||
version: () => faker.number.int(),
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedScopeModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
disabled: () => faker.datatype.boolean(),
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedSessionRecordingModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
bytes_up: () => faker.string.numeric(faker.number.int({ min: 1, max: 12 })),
|
||||
bytes_down: () => faker.string.numeric(faker.number.int({ min: 1, max: 12 })),
|
||||
errors: () => faker.number.int(10),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedSessionModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
type: 'tcp',
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
expiration_time: () => faker.date.soon(),
|
||||
version: () => faker.number.int(),
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedStorageBucketModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
version: () => faker.number.int(),
|
||||
bucket_name: () => faker.internet.domainWord(),
|
||||
bucket_prefix: () => faker.system.directoryPath(),
|
||||
worker_filter: () =>
|
||||
`"${faker.word.noun()}" in "${faker.system.directoryPath()}"`,
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedTargetModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
session_max_seconds: () => faker.number.int(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
disabled: () => faker.datatype.boolean(),
|
||||
default_port: () => faker.internet.port(),
|
||||
default_client_port: () => faker.internet.port(),
|
||||
version: () => faker.number.int(),
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
/**
|
||||
* GeneratedUserModelFactory
|
||||
* User contains all fields related to a User resource
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
disabled: () => faker.datatype.boolean(),
|
||||
email: () => faker.internet.email().toLowerCase(),
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { TYPE_WORKER_PKI } from 'api/models/worker';
|
||||
|
||||
/**
|
||||
* GeneratedWorkerModelFactory
|
||||
* Worker contains all fields related to a Worker resource
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
type: TYPE_WORKER_PKI,
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
version: () => faker.number.int(),
|
||||
address: () =>
|
||||
`${faker.string.uuid()}.proxy.boundary.hashicorp.cloud:${faker.internet.port()}`,
|
||||
last_status_time: () => faker.date.recent(),
|
||||
active_connection_count: () => faker.number.int(10),
|
||||
release_version: () =>
|
||||
`Boundary v${faker.number.int(11)}.${faker.number.int(
|
||||
50,
|
||||
)}.${faker.number.int(12)}`,
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { makeEvaluator } from 'js-bexpr';
|
||||
import { underscore } from '@ember/string';
|
||||
|
||||
/**
|
||||
* Because Mirage, a record cannot be serialized outside of a route handler
|
||||
* context. Here is a quick and dirty attempt to serialize attribute names
|
||||
* to underscore format. This is not entirely realistic, but may suffice.
|
||||
*/
|
||||
const quickSerialize = (item) => {
|
||||
const json = item.toJSON();
|
||||
Object.keys(json).forEach((key) => {
|
||||
const newKey = underscore(key);
|
||||
json[newKey] = json[key];
|
||||
});
|
||||
return json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a filter function that operates on a single object, which itself
|
||||
* returns the result of evaluating the expression against the object.
|
||||
*/
|
||||
export default (expression) => {
|
||||
if (expression) {
|
||||
const evaluator = makeEvaluator(expression);
|
||||
// Since API query selectors begin with `/item`, the instance is wrapped.
|
||||
return (record) => {
|
||||
const item = quickSerialize(record);
|
||||
return evaluator({ item });
|
||||
};
|
||||
} else {
|
||||
// If no expression was passed, always return true,
|
||||
// thus filtering out none.
|
||||
return () => true;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
||||
/**
|
||||
* The Mulberry32 PRNG, JavaScript implementation. This is a seedable PRNG,
|
||||
* which we need in order to deterministically generate IDs which are stable
|
||||
* across reloads. Unfortunately, the built-in `Math.random` function
|
||||
* is not seedable.
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/bryc/code/blob/master/jshash/PRNGs.md#mulberry32
|
||||
*
|
||||
* @param {number} a
|
||||
* @return {number}
|
||||
*/
|
||||
function mulberry32(a = 0) {
|
||||
return function () {
|
||||
a += 0x6d2b79f5 | 0;
|
||||
var t = Math.imul(a ^ (a >>> 15), 1 | a);
|
||||
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
||||
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
||||
};
|
||||
}
|
||||
|
||||
const random = mulberry32();
|
||||
|
||||
/**
|
||||
* Generates a random ID string at least 10 characters long with the
|
||||
* specified prefix.
|
||||
*
|
||||
* @param {string} prefix
|
||||
* @return {string}
|
||||
*/
|
||||
export default function (prefix = '') {
|
||||
let result = '';
|
||||
for (let i = 0; i < 10; i++) {
|
||||
result = result.concat(
|
||||
characters[Math.floor(random() * characters.length)],
|
||||
);
|
||||
}
|
||||
return prefix.concat(result);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allows development-time toggling of resource permissions via the window
|
||||
* querystring. Pass a JSON object into the query to toggle permissions.
|
||||
* Note that the value must be a valid JSON object in order to be parsed.
|
||||
*
|
||||
* @example
|
||||
* ?authorized_actions={"account": ["read"]}
|
||||
*
|
||||
* Within a Mirage factory, pass the actions into the mock:
|
||||
*
|
||||
* @example
|
||||
* import { Factory } from 'miragejs';
|
||||
* import permissions from '../helpers/permissions';
|
||||
*
|
||||
* export default Factory.extend({
|
||||
* authorized_actions: () =>
|
||||
* permissions.authorizedActionsFor('account') ||
|
||||
* ['no-op', 'read', 'update', 'delete']
|
||||
* });
|
||||
*/
|
||||
class ToggledCapabilities {
|
||||
// =attributes
|
||||
|
||||
// Get the query string and drop the leading '?'
|
||||
#rawQuery = window.location.search.substring(1);
|
||||
|
||||
// Split the querystring into key/value pairs
|
||||
#queryPairs = this.#rawQuery.split('&').map((item) => item.split('='));
|
||||
|
||||
// Find the value of a pair with key `authorized_actions`
|
||||
// Safe-ish when the item is not present
|
||||
#rawAuthorizedActions = (this.#queryPairs.find(
|
||||
(item) => item[0] === 'authorized_actions',
|
||||
) || [])[1];
|
||||
|
||||
// Safe-ish when the value is not present
|
||||
#authorizedActions =
|
||||
JSON.parse(
|
||||
decodeURIComponent(this.#rawAuthorizedActions || '') || 'null',
|
||||
) || {};
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Returns authorized actions for the specified field, if any are defined
|
||||
* in the `authorized_actions` query. Returns undefined otherwise.
|
||||
* @return {?string[]}
|
||||
*/
|
||||
authorizedActionsFor(field) {
|
||||
if (this.#authorizedActions[field]) {
|
||||
return structuredClone(this.#authorizedActions[field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new ToggledCapabilities();
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
authMethod: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Model } from 'miragejs';
|
||||
|
||||
export default Model.extend({
|
||||
assignDefaults(defaultAttrs, attrs) {
|
||||
Object.entries(defaultAttrs).map(([key, value]) => {
|
||||
if (!attrs[key]) {
|
||||
attrs[key] = value;
|
||||
}
|
||||
});
|
||||
},
|
||||
defaultAttrs: () => ({
|
||||
version: 1,
|
||||
authorized_actions: ['no-op', 'read', 'update', 'delete'],
|
||||
created_time: new Date(),
|
||||
}),
|
||||
save() {
|
||||
this.assignDefaults(this.defaultAttrs(), this.attrs);
|
||||
return Model.prototype.save.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo, Model } from 'miragejs';
|
||||
|
||||
export default Model.extend({
|
||||
connection_recording: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo, hasMany, Model } from 'miragejs';
|
||||
|
||||
export default Model.extend({
|
||||
session_recording: belongsTo(),
|
||||
channel_recordings: hasMany(),
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
credentialStore: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
credentialStore: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo, hasMany } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
members: hasMany('user'),
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo, hasMany } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
hostSets: hasMany(),
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo, hasMany } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
target: belongsTo(),
|
||||
hostCatalog: belongsTo(),
|
||||
hosts: hasMany(),
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
hostCatalog: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
authMethod: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo, hasMany } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
users: hasMany(),
|
||||
groups: hasMany(),
|
||||
managedGroups: hasMany(),
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({});
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo, hasMany, Model } from 'miragejs';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
connection_recordings: hasMany(),
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
user: belongsTo(),
|
||||
target: belongsTo(),
|
||||
host: belongsTo(),
|
||||
hostSet: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Model from './base';
|
||||
import { belongsTo, hasMany } from 'miragejs';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
hostSets: hasMany(),
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo, hasMany } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
accounts: hasMany('account'),
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { belongsTo } from 'miragejs';
|
||||
import Model from './base';
|
||||
|
||||
export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
});
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { Response } from 'miragejs';
|
||||
|
||||
// Quick and dirty counter system to simulate the polling behavior
|
||||
// of the API. If the OIDC flow is pending, the route returns 100.
|
||||
// If complete it returns 200 with the token JSON.
|
||||
let oidcAttemptCounter = 0;
|
||||
const oidcRequiredAttempts = 3;
|
||||
|
||||
const commandHandlers = {
|
||||
password: {
|
||||
login: (payload, auth_method_id, account_id, scopeAttrs) => {
|
||||
if (payload.attributes.login_name === 'error') {
|
||||
return new Response(400);
|
||||
} else {
|
||||
return new Response(
|
||||
200,
|
||||
{},
|
||||
{
|
||||
attributes: {
|
||||
scope: scopeAttrs,
|
||||
id: 'token123',
|
||||
token: 'thetokenstring',
|
||||
account_id: account_id || 'authenticatedaccount',
|
||||
user_id: 'authenticateduser',
|
||||
auth_method_id: auth_method_id || 'authmethod123',
|
||||
created_time: '',
|
||||
updated_time: '',
|
||||
last_used_time: '',
|
||||
expiration_time: '',
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* OIDC authentication is a two-step process:
|
||||
*
|
||||
* 1. `authenticate:start` kicks of authentication by requesting some details
|
||||
* from the Boundary server about the request, including the third-party
|
||||
* URL to which to redirect the user.
|
||||
* 2. `authenticate` accepts the token_id and state parameters in
|
||||
* order to retrieve a Boundary token. This endpoint may be polled until
|
||||
* the authentication flow is completed.
|
||||
*/
|
||||
oidc: {
|
||||
start: () =>
|
||||
new Response(
|
||||
200,
|
||||
{},
|
||||
{
|
||||
attributes: {
|
||||
auth_url: 'https://www.duckduckgo.com',
|
||||
token_id: 'token_1234',
|
||||
},
|
||||
},
|
||||
),
|
||||
token: (_, auth_method_id, account_id, scopeAttrs) => {
|
||||
oidcAttemptCounter++;
|
||||
if (oidcAttemptCounter < oidcRequiredAttempts) {
|
||||
return new Response(202);
|
||||
} else {
|
||||
return new Response(
|
||||
200,
|
||||
{},
|
||||
{
|
||||
attributes: {
|
||||
scope: scopeAttrs,
|
||||
id: 'token123',
|
||||
token: 'thetokenstring',
|
||||
account_id: account_id || '1',
|
||||
user_id: 'authenticateduser',
|
||||
auth_method_id: auth_method_id || 'authmethod123',
|
||||
created_time: '',
|
||||
updated_time: '',
|
||||
last_used_time: '',
|
||||
expiration_time: '',
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Handles all custom methods on /auth-methods/:id route
|
||||
export function authHandler({ scopes, authMethods, accounts }, request) {
|
||||
const [, id, method] = request.params.id_method.match(
|
||||
/(?<id>.[^:]*):(?<method>(.*))/,
|
||||
);
|
||||
const authMethod = authMethods.find(id);
|
||||
|
||||
if (method === 'authenticate') {
|
||||
const payload = JSON.parse(request.requestBody);
|
||||
const { command } = payload;
|
||||
const scope = scopes.find(authMethod.scopeId);
|
||||
const account = accounts.where({ authMethodId: authMethod.id })?.models[0];
|
||||
const scopeAttrs = this.serialize(scopes.find(scope.id));
|
||||
return commandHandlers[authMethod.type][command](
|
||||
payload,
|
||||
authMethod.id,
|
||||
account?.id,
|
||||
scopeAttrs,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: this handler doesn't really belong here, but we already route
|
||||
// POST requests on existing auth methods to this route handler file under the
|
||||
// assumption it would be for authentication. While authentication should
|
||||
// still occur here, we should handle other custom methods in the
|
||||
// mirage config and route here only for auth.
|
||||
if (method === 'change-state') {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
return authMethod.update({
|
||||
attributes: {
|
||||
state: attrs.attributes.state,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function deauthHandler() {
|
||||
return new Response(200);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
export function targetHandler({ targets }, { params: { idMethod } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const id = idMethod.split(':')[0];
|
||||
const method = idMethod.split(':')[1];
|
||||
const target = targets.find(id);
|
||||
const {
|
||||
brokeredCredentialSourceIds: originalBrokeredCredentials = [],
|
||||
injectedApplicationCredentialSourceIds: originalInjectedCredentials = [],
|
||||
} = target;
|
||||
const selectedBrokeredCredentials = attrs.brokeredCredentialSourceIds;
|
||||
const selectedInjectedCredentials =
|
||||
attrs.injectedApplicationCredentialSourceIds;
|
||||
const selectedHostSourceIds = attrs.hostSourceIds;
|
||||
const originHostSetIds = target.hostSetIds;
|
||||
|
||||
const updatedAttrs = {
|
||||
version: attrs.version,
|
||||
};
|
||||
|
||||
const addToSourcesList = (originalSourceIds, selectedSourceIds) => {
|
||||
const sourceIds = new Set([...originalSourceIds, ...selectedSourceIds]);
|
||||
return [...sourceIds];
|
||||
};
|
||||
|
||||
const removeFromSourcesList = (originalSourceIds, selectedSourceIds) => {
|
||||
const sourceIds = new Set(originalSourceIds);
|
||||
for (const elem of selectedSourceIds) {
|
||||
sourceIds.delete(elem);
|
||||
}
|
||||
return [...sourceIds];
|
||||
};
|
||||
|
||||
// If adding host sources, push them into the array
|
||||
if (method === 'add-host-sources') {
|
||||
if (selectedHostSourceIds) {
|
||||
const listOfHostSources = addToSourcesList(
|
||||
originHostSetIds,
|
||||
selectedHostSourceIds,
|
||||
);
|
||||
if (listOfHostSources?.length) {
|
||||
updatedAttrs.hostSetIds = listOfHostSources;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If deleting host sources, filter them out of the array
|
||||
if (method === 'remove-host-sources') {
|
||||
if (selectedHostSourceIds) {
|
||||
const removedHostSources = removeFromSourcesList(
|
||||
originHostSetIds,
|
||||
selectedHostSourceIds,
|
||||
);
|
||||
updatedAttrs.hostSetIds = removedHostSources;
|
||||
}
|
||||
}
|
||||
// If adding brokered or injected application cred sources, push them into the array
|
||||
if (method === 'add-credential-sources') {
|
||||
if (selectedBrokeredCredentials) {
|
||||
const listOfBrokeredCredentialSources = addToSourcesList(
|
||||
originalBrokeredCredentials,
|
||||
selectedBrokeredCredentials,
|
||||
);
|
||||
if (listOfBrokeredCredentialSources?.length) {
|
||||
updatedAttrs.brokeredCredentialSourceIds =
|
||||
listOfBrokeredCredentialSources;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedInjectedCredentials) {
|
||||
const listOfInjectedCredentialSources = addToSourcesList(
|
||||
originalInjectedCredentials,
|
||||
selectedInjectedCredentials,
|
||||
);
|
||||
if (listOfInjectedCredentialSources?.length) {
|
||||
updatedAttrs.injectedApplicationCredentialSourceIds =
|
||||
listOfInjectedCredentialSources;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If deleting brokered or injected application cred sources, filter them out of the array
|
||||
if (method === 'remove-credential-sources') {
|
||||
if (selectedBrokeredCredentials) {
|
||||
const removedCredentialSources = removeFromSourcesList(
|
||||
originalBrokeredCredentials,
|
||||
selectedBrokeredCredentials,
|
||||
);
|
||||
updatedAttrs.brokeredCredentialSourceIds = removedCredentialSources;
|
||||
}
|
||||
|
||||
if (selectedInjectedCredentials) {
|
||||
const removedCredentialSources = removeFromSourcesList(
|
||||
originalInjectedCredentials,
|
||||
selectedInjectedCredentials,
|
||||
);
|
||||
updatedAttrs.injectedApplicationCredentialSourceIds =
|
||||
removedCredentialSources;
|
||||
}
|
||||
}
|
||||
|
||||
return target.update(updatedAttrs);
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { TYPE_AUTH_METHOD_OIDC } from 'api/models/auth-method';
|
||||
|
||||
export default function (server) {
|
||||
// Scope resources
|
||||
|
||||
// creates a global scope
|
||||
const globalScope = server.create('scope', {
|
||||
id: 'global',
|
||||
type: 'global',
|
||||
name: 'Global',
|
||||
});
|
||||
const orgScope = server.createList(
|
||||
'scope',
|
||||
3,
|
||||
{
|
||||
type: 'org',
|
||||
scope: { id: globalScope.id, type: globalScope.type },
|
||||
},
|
||||
'withChildren',
|
||||
)[0];
|
||||
|
||||
// Auth
|
||||
const globalAuthMethods = server.createList(
|
||||
'auth-method',
|
||||
5,
|
||||
{ scope: globalScope },
|
||||
'withAccountsAndUsersAndManagedGroups',
|
||||
);
|
||||
const orgAuthMethods = server.createList(
|
||||
'auth-method',
|
||||
3,
|
||||
{ scope: orgScope },
|
||||
'withAccountsAndUsersAndManagedGroups',
|
||||
);
|
||||
// Authenticated user/account
|
||||
const user = server.create('user', {
|
||||
id: 'authenticateduser',
|
||||
scope: globalScope,
|
||||
});
|
||||
const { id: accountID } = server.create('account', {
|
||||
id: 'authenticatedaccount',
|
||||
scope: globalScope,
|
||||
authMethod: globalAuthMethods[0],
|
||||
type: 'password',
|
||||
});
|
||||
user.update({ accountIds: [accountID] });
|
||||
// Assign primary auth methods per scope
|
||||
// TODO make this generic
|
||||
globalScope.update({ primaryAuthMethodId: globalAuthMethods[0].id });
|
||||
orgScope.update({ primaryAuthMethodId: orgAuthMethods[1].id });
|
||||
|
||||
// Groups and Users
|
||||
server.createList('group', 1, { scope: globalScope }, 'withMembers');
|
||||
server.createList('group', 5, { scope: orgScope }, 'withMembers');
|
||||
// Role
|
||||
const globalScopeRoles = server.createList(
|
||||
'role',
|
||||
1,
|
||||
{ scope: globalScope },
|
||||
'withPrincipals',
|
||||
);
|
||||
//create managed groups for role/principals in globalScope
|
||||
globalScopeRoles.forEach((role) => {
|
||||
const { scope } = role;
|
||||
const oidcAuthMethod = globalAuthMethods.filter(
|
||||
(auth) => auth.type === TYPE_AUTH_METHOD_OIDC,
|
||||
)[0];
|
||||
const { type } = oidcAuthMethod;
|
||||
const managedGroups = server.createList('managed-group', 2, {
|
||||
scope,
|
||||
authMethodId: oidcAuthMethod.id,
|
||||
type,
|
||||
});
|
||||
role.update({ managedGroups });
|
||||
});
|
||||
|
||||
const orgScopeRoles = server.createList(
|
||||
'role',
|
||||
5,
|
||||
{ scope: orgScope },
|
||||
'withPrincipals',
|
||||
);
|
||||
//create managed groups for role/principals in orgScope
|
||||
orgScopeRoles.forEach((role) => {
|
||||
const { scope } = role;
|
||||
const oidcAuthMethod = orgAuthMethods.filter(
|
||||
(auth) => auth.type === TYPE_AUTH_METHOD_OIDC,
|
||||
)[0];
|
||||
const { type } = oidcAuthMethod;
|
||||
const managedGroups = server.createList('managed-group', 2, {
|
||||
scope,
|
||||
authMethodId: oidcAuthMethod.id,
|
||||
type,
|
||||
});
|
||||
role.update({ managedGroups });
|
||||
});
|
||||
|
||||
// Storage Buckets
|
||||
server.createList('storage-bucket', 3, { scope: globalScope });
|
||||
server.createList('storage-bucket', 2, { scope: orgScope });
|
||||
|
||||
// Storage Policies
|
||||
server.createList('policy', 3, { scope: globalScope });
|
||||
server.createList('policy', 3, { scope: orgScope });
|
||||
|
||||
// Other resources
|
||||
server.schema.scopes.where({ type: 'project' }).models.forEach((scope) => {
|
||||
server.createList(
|
||||
'host-catalog',
|
||||
2,
|
||||
{ scope, type: 'static' },
|
||||
'withChildren',
|
||||
);
|
||||
server.createList(
|
||||
'host-catalog',
|
||||
8,
|
||||
{ scope, type: 'plugin' },
|
||||
'withChildren',
|
||||
);
|
||||
server.createList('credential-store', 5, { scope }, 'withAssociations');
|
||||
server.createList('target', 4, { scope }, 'withAssociations');
|
||||
server.create('target', { scope, address: '0.0.0.0' });
|
||||
// Sessions have target data. Create it after targets.
|
||||
server.createList('session', 4, { scope }, 'withAssociations');
|
||||
// Also create sessions for "authenticateduser" for Desktop,
|
||||
// which filters user_id by the currently authenticated user.
|
||||
server.createList('session', 1, { scope, user }, 'withAssociations');
|
||||
// Create IAM resources for project
|
||||
server.createList('group', 3, { scope });
|
||||
server.createList('role', 3, { scope });
|
||||
});
|
||||
|
||||
// Aliases
|
||||
const aliasDestinationTarget = server.schema.targets.all().models[0];
|
||||
const { id: destination_id } = aliasDestinationTarget;
|
||||
const aliases = server.createList('alias', 4, {
|
||||
scope: globalScope,
|
||||
destination_id,
|
||||
});
|
||||
|
||||
aliasDestinationTarget.update({
|
||||
aliases: aliases.map((alias) => ({ id: alias.id, value: alias.value })),
|
||||
});
|
||||
|
||||
// Workers
|
||||
server.createList('worker', 3, { scope: globalScope });
|
||||
|
||||
// Session Recordings
|
||||
server.createList(
|
||||
'session-recording',
|
||||
3,
|
||||
{ scope: globalScope },
|
||||
'withConnectionAndChannels',
|
||||
'withExistingUserAndTarget',
|
||||
);
|
||||
server.create(
|
||||
'session-recording',
|
||||
{ scope: globalScope },
|
||||
'withConnectionAndChannels',
|
||||
'withNonExistingUserAndTarget',
|
||||
);
|
||||
server.createList(
|
||||
'session-recording',
|
||||
2,
|
||||
{ scope: orgScope },
|
||||
'withConnectionAndChannels',
|
||||
'withExistingUserAndTarget',
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
export default function initializeMockIPC(server, config) {
|
||||
const isTesting = config.environment === 'test';
|
||||
|
||||
/**
|
||||
* We strive to make this application runnable in a regular web browser, since
|
||||
* it is a convenient environment for development and testing. But only an
|
||||
* Electron environment has true IPC. Outside of Electron or with mirage,
|
||||
* we mock the handling of the message-based IPC requests originating from the
|
||||
* renderer (the Ember app).
|
||||
*/
|
||||
class MockIPC {
|
||||
async invoke(method, payload) {
|
||||
return await this[method](payload);
|
||||
}
|
||||
|
||||
clusterUrl = null;
|
||||
|
||||
checkOS() {
|
||||
return {
|
||||
isLinux: false,
|
||||
isMac: true,
|
||||
isWindows: false,
|
||||
};
|
||||
}
|
||||
|
||||
getClusterUrl() {
|
||||
return this.clusterUrl;
|
||||
}
|
||||
|
||||
setClusterUrl(clusterUrl) {
|
||||
this.clusterUrl = clusterUrl;
|
||||
return this.clusterUrl;
|
||||
}
|
||||
|
||||
resetClusterUrl() {
|
||||
this.clusterUrl = null;
|
||||
}
|
||||
|
||||
openExternal(href) {
|
||||
window.open(href);
|
||||
}
|
||||
|
||||
cliExists() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new session instance associated with the specified target.
|
||||
* @param connect_details
|
||||
* @param
|
||||
*/
|
||||
connect({ target_id }) {
|
||||
const target = server.schema.targets.find(target_id);
|
||||
const { scope, type } = target;
|
||||
const newSession = server.schema.sessions.create({
|
||||
scope,
|
||||
target,
|
||||
userId: 'authenticateduser',
|
||||
type,
|
||||
created_time: new Date().toISOString(),
|
||||
expiration_time: faker.date.soon(),
|
||||
});
|
||||
const decoded = {
|
||||
key1: 'value 1',
|
||||
key2: true,
|
||||
key3: 'test',
|
||||
};
|
||||
const raw = btoa(JSON.stringify(decoded));
|
||||
return {
|
||||
address: window.location.hostname,
|
||||
port: faker.internet.port(),
|
||||
protocol: type,
|
||||
session_id: newSession.id,
|
||||
credentials: [
|
||||
{
|
||||
credential_source: {
|
||||
id: 'clvlt_4cvscMTl0N',
|
||||
name: 'Credential Library 1',
|
||||
description: 'Source Description',
|
||||
credential_store_id: 'csvlt_Q1HFGt7Jpm',
|
||||
type: 'vault',
|
||||
},
|
||||
secret: {
|
||||
raw: btoa('just-a-random-string'),
|
||||
},
|
||||
},
|
||||
{
|
||||
credential_source: {
|
||||
id: 'clvlt_4cvscMTl0N',
|
||||
name: 'Credential Library 0',
|
||||
description: 'Source Description',
|
||||
credential_store_id: 'csvlt_Q1HFGt7Jpm',
|
||||
type: 'vault-generic',
|
||||
},
|
||||
secret: {
|
||||
raw: 'eyJhcnJheSI6WyJvbmUiLCJ0d28iLCJ0aHJlZSIsIm9uZSIsInR3byIsInRocmVlIiwib25lIiwidHdvIiwidGhyZWUiLCJvbmUiLCJ0d28iLCJ0aHJlZSJdLCJuZXN0ZWQiOnsiYm9vbCI6dHJ1ZSwibG9uZyI6IjEyMjM1MzQ1NmFzZWRmYTQzd3J0ZjIzNGYyM2FzZGdmYXNkZnJnYXdzZWZhd3NlZnNkZjQiLCJzZWNlcmV0Ijoic28gbmVzdGVkIn0sInRlc3QiOiJwaHJhc2UifQ',
|
||||
decoded: {
|
||||
data: {
|
||||
backslash: 'password\\withslash\\',
|
||||
backslash1: 'password\\fwithslash\\f',
|
||||
password: '123',
|
||||
username: 'test',
|
||||
email: {
|
||||
address: 'test.com',
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
created_time: '2024-04-12T18:38:36.226715555Z',
|
||||
custom_metadata: null,
|
||||
deletion_time: '',
|
||||
destroyed: false,
|
||||
version: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
credential_source: {
|
||||
id: 'credjson_7cKBbBEkC3',
|
||||
credential_store_id: 'csst_yzlsot2pum',
|
||||
type: 'static',
|
||||
credential_type: 'json',
|
||||
},
|
||||
secret: {
|
||||
raw: 'eyJhcnJheSI6WyJvbmUiLCJ0d28iLCJ0aHJlZSIsIm9uZSIsInR3byIsInRocmVlIiwib25lIiwidHdvIiwidGhyZWUiLCJvbmUiLCJ0d28iLCJ0aHJlZSJdLCJuZXN0ZWQiOnsiYm9vbCI6dHJ1ZSwibG9uZyI6IjEyMjM1MzQ1NmFzZWRmYTQzd3J0ZjIzNGYyM2FzZGdmYXNkZnJnYXdzZWZhd3NlZnNkZjQiLCJzZWNlcmV0Ijoic28gbmVzdGVkIn0sInRlc3QiOiJwaHJhc2UifQ==',
|
||||
decoded: {
|
||||
secret_key: 'QWERTYUIOP',
|
||||
secret_access_key: 'QWERT.YUIOP234567890',
|
||||
nested_secret: {
|
||||
session_token: 'ZXCVBNMLKJHGFDSAQWERTYUIOP0987654321',
|
||||
complex_nest: {
|
||||
blackslash: 'password\\withslash\\',
|
||||
hash: 'qazxswedcvfrtgbnjhyujm.1234567890',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
credential: {
|
||||
secret_key: 'QWERTYUIOP',
|
||||
secret_access_key: 'QWERT.YUIOP234567890',
|
||||
nested_secret: {
|
||||
session_token: 'ZXCVBNMLKJHGFDSAQWERTYUIOP0987654321',
|
||||
complex_nest: {
|
||||
hash: 'qazxswedcvfrtgbnjhyujm.1234567890',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
credential_source: {
|
||||
id: 'clvlt_4cvscMTl0N',
|
||||
name: 'Credential Library 2',
|
||||
description: 'Source Description',
|
||||
credential_store_id: 'csvlt_Q1HFGt7Jpm',
|
||||
type: 'vault',
|
||||
},
|
||||
secret: {
|
||||
raw,
|
||||
decoded,
|
||||
},
|
||||
},
|
||||
{
|
||||
credential_source: {
|
||||
id: 'clvlt_9KWscxpcY7',
|
||||
name: 'Credential Library 3',
|
||||
description: 'Source Description',
|
||||
credential_store_id: 'csvlt_Q1HFGt7Jpm',
|
||||
type: 'vault',
|
||||
},
|
||||
secret: {
|
||||
raw: btoa('just-a-random-string'),
|
||||
},
|
||||
},
|
||||
{
|
||||
credential_source: {
|
||||
id: 'clvlt_9KWscxpcY7',
|
||||
name: 'Credential Library 4',
|
||||
description: 'Source Description',
|
||||
credential_store_id: 'csvlt_Q1HFGt7Jpm',
|
||||
type: 'vault',
|
||||
},
|
||||
secret: {
|
||||
raw,
|
||||
decoded,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for window chrome on MacOS
|
||||
*/
|
||||
hasMacOSChrome() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for OS chrome state
|
||||
*/
|
||||
showWindowActions() {
|
||||
if (navigator.userAgent.includes('Mac')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing when attempting to minimize, toggle fullscreen,
|
||||
* and close a browser window
|
||||
* * Do nothing when canceling a session invokes the stop method
|
||||
*/
|
||||
minimizeWindow() {}
|
||||
closeWindow() {}
|
||||
toggleFullscreenWindow() {}
|
||||
stop() {}
|
||||
checkCommand() {
|
||||
return faker.system.filePath();
|
||||
}
|
||||
addTokenToDaemons() {}
|
||||
searchCacheDaemon() {}
|
||||
isCacheDaemonRunning() {
|
||||
return false;
|
||||
}
|
||||
isClientAgentRunning() {
|
||||
return false;
|
||||
}
|
||||
cacheDaemonStatus() {
|
||||
return { version: 'Boundary v1.0.0' };
|
||||
}
|
||||
getCliVersion() {
|
||||
return { versionNumber: '1.0.0' };
|
||||
}
|
||||
getDesktopVersion() {
|
||||
return { desktopVersion: '1.0.0' };
|
||||
}
|
||||
getLogLevel() {
|
||||
return 'info';
|
||||
}
|
||||
getLogPath() {
|
||||
return '~/.config/Boundary/logs/desktop-client.log';
|
||||
}
|
||||
setLogLevel() {}
|
||||
clientAgentStatus() {
|
||||
return { version: '0.0.1-dev', status: 'running' };
|
||||
}
|
||||
pauseClientAgent() {}
|
||||
resumeClientAgent() {}
|
||||
hasRunningSessions() {}
|
||||
stopAll() {}
|
||||
getRdpClients() {
|
||||
return ['windows-app', 'none', 'mstsc'];
|
||||
}
|
||||
getPreferredRdpClient() {
|
||||
return 'windows-app';
|
||||
}
|
||||
getRecommendedRdpClient() {
|
||||
return {
|
||||
name: 'windows-app',
|
||||
link: 'https://apps.apple.com/us/app/windows-app/id1295203466',
|
||||
};
|
||||
}
|
||||
setPreferredRdpClient() {}
|
||||
launchRdpClient() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a mock IPC handler, which mimics the behavior of the Electron
|
||||
* main process, and routes messages to it in a way similar to our
|
||||
* preload.js script.
|
||||
*
|
||||
* Initializes mock IPC only in a non-testing context and when mirage is turned on.
|
||||
* We mock certain functions even in electron (e.g. hasMacOSChrome) when running
|
||||
* locally which will force a certain appearance regardless of platform
|
||||
*/
|
||||
if (config.mirage?.enabled && !isTesting) {
|
||||
const mockIPC = new MockIPC();
|
||||
|
||||
window.addEventListener('message', async function (event) {
|
||||
if (event.origin !== window.location.origin) return;
|
||||
const { method, payload } = event?.data ?? {};
|
||||
if (method) {
|
||||
const response = await mockIPC.invoke(method, payload);
|
||||
event.ports[0].postMessage(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'account',
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
json.auth_method_id = model.authMethodId;
|
||||
delete json.attributes?.password;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'alias',
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { RestSerializer } from 'miragejs';
|
||||
import { underscore } from '@ember/string';
|
||||
import { isArray } from '@ember/array';
|
||||
|
||||
/**
|
||||
* Manages serialization/normalization of data into and out of the mock API.
|
||||
*/
|
||||
export default RestSerializer.extend({
|
||||
// =attributes
|
||||
|
||||
/**
|
||||
* False to disable automatically rooting payloads under a key.
|
||||
* This is handled by the `serialize()` method, see below.
|
||||
* @type {boolean}
|
||||
*/
|
||||
root: false,
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
embed: true,
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Generates an underscored key for the attribute.
|
||||
* @param {string} attr
|
||||
* @return {string}
|
||||
*/
|
||||
keyForAttribute(attr) {
|
||||
return underscore(attr);
|
||||
},
|
||||
|
||||
keyForRelationshipId(relationshipName) {
|
||||
return `${this._container.inflector.singularize(
|
||||
underscore(relationshipName),
|
||||
)}_id`;
|
||||
},
|
||||
|
||||
/**
|
||||
* Serialize items into a root key `items`.
|
||||
* @return {object}
|
||||
*/
|
||||
serialize() {
|
||||
let json = RestSerializer.prototype.serialize.apply(this, arguments);
|
||||
// If array, root it under a standard `items` key
|
||||
if (isArray(json)) json = { items: json };
|
||||
return json;
|
||||
},
|
||||
|
||||
/**
|
||||
* Serialize scope into the payload, if set.
|
||||
* @param {object} model
|
||||
* @return {object}
|
||||
*/
|
||||
_hashForModel(model) {
|
||||
const json = RestSerializer.prototype._hashForModel.apply(this, arguments);
|
||||
if (model.scope) {
|
||||
json.scope = {
|
||||
id: model.scope.id,
|
||||
type: model.scope.type,
|
||||
};
|
||||
}
|
||||
return json;
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a root to the payload, since `root: false` doesn't appear to affect
|
||||
* the normalize method.
|
||||
* @param {object} json
|
||||
* @return {object}
|
||||
*/
|
||||
normalize(json) {
|
||||
let newJSON = json;
|
||||
if (this.modelName) {
|
||||
newJSON = {};
|
||||
newJSON[this.modelName] = json;
|
||||
}
|
||||
const value = RestSerializer.prototype.normalize.apply(this, [newJSON]);
|
||||
return value;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'auth-method',
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
// If the scope marks this auth method as primary, designate it
|
||||
// as such with a read-only boolean field (this is how the API behaves).
|
||||
const isPrimary =
|
||||
model.scope && model.scope.primaryAuthMethodId === model.id;
|
||||
json.is_primary = isPrimary;
|
||||
delete json.attributes?.client_certificate_key;
|
||||
delete json.attributes?.bind_password;
|
||||
delete json.attributes?.client_secret;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'channel-recording',
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
import ChannelSerializer from './channel-recording';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'connection-recording',
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
const { channelRecordings } = this.schema;
|
||||
if (model.channelRecordingIds) {
|
||||
json.channel_recordings = model.channelRecordingIds.map((id) => {
|
||||
const channel = channelRecordings.find(id);
|
||||
return ChannelSerializer.prototype._hashForModel.apply(this, [channel]);
|
||||
});
|
||||
}
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'credential-library',
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
json.credential_store_id = model.credentialStoreId;
|
||||
|
||||
// BE API only updates these fields if there's an update mask, otherwise they remain unmodified
|
||||
// but we don't need this flow in our mocks, so we are deleting fields with null value
|
||||
|
||||
if (json.credential_mapping_overrides) {
|
||||
Object.keys(json.credential_mapping_overrides).forEach((key) => {
|
||||
if (json.credential_mapping_overrides[key] === null) {
|
||||
delete json.credential_mapping_overrides[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'credential-store',
|
||||
|
||||
_hashForModel(/* model */) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
// in a real API, the following fields are set-only and returned in
|
||||
// associated HMAC fields
|
||||
delete json.attributes?.token;
|
||||
delete json.attributes?.client_certificate_key;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'credential',
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
json.credential_store_id = model.credentialStoreId;
|
||||
|
||||
// in a real API, the password, private_key, and private_key_passphrase
|
||||
// fields are not returned so we delete them from the response
|
||||
delete json.attributes?.password;
|
||||
delete json.attributes?.private_key;
|
||||
delete json.attributes?.private_key_passphrase;
|
||||
delete json.attributes?.json_object;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
import { underscore } from '@ember/string';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'group',
|
||||
|
||||
keyForRelationshipIds(relationshipName) {
|
||||
return `${this._container.inflector.singularize(
|
||||
underscore(relationshipName),
|
||||
)}_ids`;
|
||||
},
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
if (model.memberIds.length) json.member_ids = model.memberIds;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'host-catalog',
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
import { underscore } from '@ember/string';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'host-set',
|
||||
|
||||
keyForRelationshipIds(relationshipName) {
|
||||
return `${this._container.inflector.singularize(
|
||||
underscore(relationshipName),
|
||||
)}_ids`;
|
||||
},
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
json.host_catalog_id = model.hostCatalogId;
|
||||
if (model.hostIds?.length) {
|
||||
json.host_ids = model.hostIds;
|
||||
}
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'host',
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
json.host_catalog_id = model.hostCatalogId;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'managed-group',
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
json.auth_method_id = model.authMethodId;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'policy',
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'role',
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
const serializedUsers = model.users.models.map((user) => ({
|
||||
scope_id: model.scope.id,
|
||||
id: user.id,
|
||||
type: 'user',
|
||||
}));
|
||||
const serializedGroups = model.groups.models.map((group) => ({
|
||||
scope_id: model.scope.id,
|
||||
id: group.id,
|
||||
type: 'group',
|
||||
}));
|
||||
const serializedManagedGroups = model.managedGroups.models.map(
|
||||
(managedGroup) => ({
|
||||
scope_id: model.scope.id,
|
||||
id: managedGroup.id,
|
||||
type: 'managed group',
|
||||
}),
|
||||
);
|
||||
json.principals = [
|
||||
...serializedUsers,
|
||||
...serializedGroups,
|
||||
...serializedManagedGroups,
|
||||
];
|
||||
|
||||
if (!json.principals.length) delete json.principals;
|
||||
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'scope',
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
import ConnectionRecordingSerializer from './connection-recording';
|
||||
import ScopeSerializer from './scope';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'session-recording',
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
const { connectionRecordings, scopes } = this.schema;
|
||||
|
||||
// Manually map our models to the actual embedded json representation
|
||||
if (model.connectionRecordingIds) {
|
||||
json.connection_recordings = model.connectionRecordingIds.map((id) => {
|
||||
const connection = connectionRecordings.find(id);
|
||||
return ConnectionRecordingSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
[connection],
|
||||
);
|
||||
});
|
||||
}
|
||||
const userScopeId = model.create_time_values?.user?.scopeId;
|
||||
if (userScopeId) {
|
||||
const scope = scopes.find(userScopeId);
|
||||
json.create_time_values.user.scope =
|
||||
ScopeSerializer.prototype._hashForModel.apply(this, [scope]);
|
||||
}
|
||||
const targetScopeId = model.create_time_values?.target?.scopeId;
|
||||
if (targetScopeId) {
|
||||
const scope = scopes.find(targetScopeId);
|
||||
json.create_time_values.target.scope =
|
||||
ScopeSerializer.prototype._hashForModel.apply(this, [scope]);
|
||||
}
|
||||
delete json.create_time_values?.target?.storage_bucket_id;
|
||||
|
||||
json.session_id = model.sessionId;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
import { underscore } from '@ember/string';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'session',
|
||||
|
||||
keyForRelationshipId(relationshipName) {
|
||||
return `${this._container.inflector.singularize(
|
||||
underscore(relationshipName),
|
||||
)}_id`;
|
||||
},
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
json.user_id = model.userId;
|
||||
json.target_id = model.targetId;
|
||||
json.host_set_id = model.hostSetId;
|
||||
json.host_id = model.hostId;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'storage-bucket',
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
import { underscore } from '@ember/string';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'target',
|
||||
|
||||
keyForRelationshipIds(relationshipName) {
|
||||
return `${this._container.inflector.singularize(
|
||||
underscore(relationshipName),
|
||||
)}_ids`;
|
||||
},
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
const { hostSets, aliases } = this.schema;
|
||||
if (model.hostSetIds?.length) {
|
||||
json.host_sources = model.hostSetIds.map((host_set_id) => {
|
||||
const hostSet = hostSets.find(host_set_id);
|
||||
const host_catalog_id = hostSet?.hostCatalog?.id;
|
||||
return { id: host_set_id, host_catalog_id };
|
||||
});
|
||||
}
|
||||
|
||||
// After we clear an associated alias, we try to mimic the BE logic
|
||||
// by manually filter out the alias id from the target model
|
||||
|
||||
const associatedAliases = aliases
|
||||
.all()
|
||||
.models.reduce((arr, { destinationId, id }) => {
|
||||
// We iterate through the aliases list and
|
||||
// find the cleared alias by looking for camelCase destinationId since there is no other way to find the impacted alias
|
||||
if (destinationId !== null) arr.push(id);
|
||||
return arr;
|
||||
}, []);
|
||||
|
||||
json.aliases = model.aliases?.filter((alias) =>
|
||||
associatedAliases.includes(alias.id),
|
||||
);
|
||||
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
import { underscore } from '@ember/string';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'user',
|
||||
|
||||
keyForRelationshipIds(relationshipName) {
|
||||
return `${this._container.inflector.singularize(
|
||||
underscore(relationshipName),
|
||||
)}_ids`;
|
||||
},
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments,
|
||||
);
|
||||
if (model.accountIds.length) json.account_ids = model.accountIds;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
Loaded 100 of 191 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user