Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Homogenized encoding of variable values, added tests for variable ops… #423

Merged
merged 1 commit into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions src/api/cloud/VariablesApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import * as VariablesApi from './VariablesApi';
import { autoSetupPolly, filterRecording } from '../../utils/AutoSetupPolly';
import { state } from '../../index';
import { encode } from '../../utils/Base64Utils';

const ctx = autoSetupPolly();

Expand Down Expand Up @@ -60,7 +61,7 @@ async function stageVariable(variable: TestVariable, create = true) {
try {
await VariablesApi.putVariable({
variableId: variable.name,
value: variable.value,
valueBase64: encode(variable.value),
description: variable.description,
expressionType: variable.type,
state,
Expand Down Expand Up @@ -240,7 +241,7 @@ describe('VariablesApi', () => {
test(`1: Create new variable with default type (string): ${var4.name} - success`, async () => {
const response = await VariablesApi.putVariable({
variableId: var4.name,
value: var4.value,
valueBase64: encode(var4.value),
description: var4.description,
expressionType: var4.type,
state,
Expand All @@ -251,7 +252,7 @@ describe('VariablesApi', () => {
test(`2: Create new string variable (explicit type): ${var5.name} - success`, async () => {
const response = await VariablesApi.putVariable({
variableId: var5.name,
value: var5.value,
valueBase64: encode(var5.value),
description: var5.description,
expressionType: var5.type,
state,
Expand All @@ -262,7 +263,7 @@ describe('VariablesApi', () => {
test(`3: Create new array variable: ${var6.name} - success`, async () => {
const response = await VariablesApi.putVariable({
variableId: var6.name,
value: var6.value,
valueBase64: encode(var6.value),
description: var6.description,
expressionType: var6.type,
state,
Expand All @@ -284,7 +285,7 @@ describe('VariablesApi', () => {
test(`5: Create new bool variable: ${var8.name} - success`, async () => {
const response = await VariablesApi.putVariable({
variableId: var8.name,
value: var8.value,
valueBase64: encode(var8.value),
description: var8.description,
expressionType: var8.type,
state,
Expand All @@ -295,7 +296,7 @@ describe('VariablesApi', () => {
test(`6: Create new int variable: ${var9.name} - success`, async () => {
const response = await VariablesApi.putVariable({
variableId: var9.name,
value: var9.value,
valueBase64: encode(var9.value),
description: var9.description,
expressionType: var9.type,
state,
Expand All @@ -306,7 +307,7 @@ describe('VariablesApi', () => {
test(`7: Create new keyvaluelist variable: ${var10.name} - success`, async () => {
const response = await VariablesApi.putVariable({
variableId: var10.name,
value: var10.value,
valueBase64: encode(var10.value),
description: var10.description,
expressionType: var10.type,
state,
Expand All @@ -317,7 +318,7 @@ describe('VariablesApi', () => {
test(`8: Create new list variable: ${var11.name} - success`, async () => {
const response = await VariablesApi.putVariable({
variableId: var11.name,
value: var11.value,
valueBase64: encode(var11.value),
description: var11.description,
expressionType: var11.type,
state,
Expand All @@ -328,7 +329,7 @@ describe('VariablesApi', () => {
test(`9: Create new number variable: ${var12.name} - success`, async () => {
const response = await VariablesApi.putVariable({
variableId: var12.name,
value: var12.value,
valueBase64: encode(var12.value),
description: var12.description,
expressionType: var12.type,
state,
Expand All @@ -339,7 +340,7 @@ describe('VariablesApi', () => {
test(`10: Create new object variable: ${var13.name} - success`, async () => {
const response = await VariablesApi.putVariable({
variableId: var13.name,
value: var13.value,
valueBase64: encode(var13.value),
description: var13.description,
expressionType: var13.type,
state,
Expand Down
12 changes: 6 additions & 6 deletions src/api/cloud/VariablesApi.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import util from 'util';

import { State } from '../../shared/State';
import { encode } from '../../utils/Base64Utils';
import { getHostBaseUrl } from '../../utils/ForgeRockUtils';
import { IdObjectSkeletonInterface, PagedResult } from '../ApiTypes';
import { generateEnvApi } from '../BaseApi';
Expand Down Expand Up @@ -52,7 +51,8 @@ export type VariableExpressionType =
* Variable object skeleton
*/
export type VariableSkeleton = IdObjectSkeletonInterface & {
valueBase64: string;
valueBase64?: string;
value?: string;
description?: string;
loaded?: boolean;
lastChangedBy?: string;
Expand Down Expand Up @@ -111,25 +111,25 @@ export async function getVariable({
/**
* Create or update variable by id/name
* @param {string} variableId variable id/name
* @param {string} value variable value
* @param {string} valueBase64 base64-encoded variable value
* @param {string} description variable description
* @returns {Promise<unknown>} a promise that resolves to a variable object
*/
export async function putVariable({
variableId,
value,
valueBase64,
description = '',
expressionType = 'string',
state,
}: {
variableId: string;
value: string;
valueBase64: string;
description?: string;
expressionType?: VariableExpressionType;
state: State;
}): Promise<VariableSkeleton> {
const variableData: VariableSkeleton = {
valueBase64: encode(value),
valueBase64,
description,
expressionType,
};
Expand Down
4 changes: 2 additions & 2 deletions src/ops/ConfigOps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('ConfigOps', () => {
test('1: Export everything with string arrays, decoding variables, including journey coordinates and default scripts', async () => {
// Set deployment type to cloud since it is necessary for exporting applications correctly. It does this automatically when recording the mock, but not when running the test after recording
state.setDeploymentType(Constants.CLOUD_DEPLOYMENT_TYPE_KEY);
const response = await ConfigOps.exportFullConfiguration({ options: { useStringArrays: true, noDecode: false, coords: true, includeDefault: true }, state });
const response = await ConfigOps.exportFullConfiguration({ options: { useStringArrays: true, noDecode: false, coords: true, includeDefault: true, includeActiveValues: false }, state });
expect(response).toMatchSnapshot({
meta: expect.any(Object)
});
Expand All @@ -65,7 +65,7 @@ describe('ConfigOps', () => {
test('2: Export everything without string arrays, decoding variables, excluding journey coordinates and default scripts', async () => {
// Set deployment type to cloud since it is necessary for exporting applications correctly. It does this automatically when recording the mock, but not when running the test after recording
state.setDeploymentType(Constants.CLOUD_DEPLOYMENT_TYPE_KEY);
const response = await ConfigOps.exportFullConfiguration({ options: { useStringArrays: false, noDecode: true, coords: false, includeDefault: false }, state });
const response = await ConfigOps.exportFullConfiguration({ options: { useStringArrays: false, noDecode: true, coords: false, includeDefault: false, includeActiveValues: false }, state });
expect(response).toMatchSnapshot({
meta: expect.any(Object)
});
Expand Down
80 changes: 74 additions & 6 deletions src/ops/ConfigOps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ import {
exportCirclesOfTrust,
importCirclesOfTrust,
} from './CirclesOfTrustOps';
import { exportSecrets } from './cloud/SecretsOps';
import { exportVariables } from './cloud/VariablesOps';
import { exportSecrets, importSecrets } from './cloud/SecretsOps';
import { exportVariables, importVariables } from './cloud/VariablesOps';
import {
EmailTemplateSkeleton,
exportEmailTemplates,
Expand Down Expand Up @@ -97,6 +97,7 @@ export default (state: State): Config => {
noDecode: false,
coords: true,
includeDefault: false,
includeActiveValues: true,
},
collectErrors: Error[]
) {
Expand All @@ -111,6 +112,7 @@ export default (state: State): Config => {
global: false,
realm: false,
includeDefault: false,
includeActiveValues: true,
},
collectErrors: Error[]
) {
Expand Down Expand Up @@ -144,6 +146,14 @@ export interface FullExportOptions {
* Include default scripts in export if true
*/
includeDefault: boolean;
/**
* Include active and loaded secret values
*/
includeActiveValues: boolean;
/**
* Host URL of target environment to encrypt secret values for
*/
target?: string;
}

/**
Expand Down Expand Up @@ -174,6 +184,14 @@ export interface FullImportOptions {
* Include default scripts in import if true
*/
includeDefault: boolean;
/**
* Include active secret values
*/
includeActiveValues: boolean;
/**
* Host URL of source environment to decrypt secret values from
*/
source?: string;
}

export interface FullExportInterface {
Expand Down Expand Up @@ -214,6 +232,8 @@ export async function exportFullConfiguration({
noDecode: false,
coords: true,
includeDefault: false,
includeActiveValues: true,
target: '',
},
collectErrors,
state,
Expand All @@ -228,7 +248,14 @@ export async function exportFullConfiguration({
throwErrors = false;
errors = collectErrors;
}
const { useStringArrays, noDecode, coords, includeDefault } = options;
const {
useStringArrays,
noDecode,
coords,
includeDefault,
includeActiveValues,
target,
} = options;
const stateObj = { state };
//Export saml2 providers and circle of trusts
let saml = (
Expand Down Expand Up @@ -341,7 +368,11 @@ export async function exportFullConfiguration({
)
)?.script,
secrets: (
await exportOrImportWithErrorHandling(exportSecrets, stateObj, errors)
await exportOrImportWithErrorHandling(
exportSecrets,
{ options: { includeActiveValues, target }, state },
errors
)
)?.secrets,
service: {
...(
Expand Down Expand Up @@ -409,6 +440,8 @@ export async function importFullConfiguration({
global: false,
realm: false,
includeDefault: false,
includeActiveValues: true,
source: '',
},
collectErrors,
state,
Expand All @@ -431,13 +464,48 @@ export async function importFullConfiguration({
global,
realm,
includeDefault,
includeActiveValues,
source,
} = options;
const indicatorId = createProgressIndicator({
total: 16,
total: 18,
message: 'Importing everything...',
state,
});
// Order of imports matter here since we want dependencies to be imported first. For example, journeys depend on a lot of things, so they are last, and many things depend on scripts, so they are first.
// Order of imports matter here since we want dependencies to be imported first. For example, journeys depend on a lot of things, so they are last, and many things depend on scripts, which depend on variables and secrets, so they are first.
updateProgressIndicator({
id: indicatorId,
message: `Importing Secrets...`,
state,
});
await exportOrImportWithErrorHandling(
importSecrets,
{
importData,
options: {
includeActiveValues,
source,
},
state,
},
errors
);
updateProgressIndicator({
id: indicatorId,
message: `Importing Variables...`,
state,
});
await exportOrImportWithErrorHandling(
importVariables,
{
importData,
options: {
includeActiveValues,
},
state,
},
errors
);
updateProgressIndicator({
id: indicatorId,
message: `Importing Scripts...`,
Expand Down
Loading