From f0cad5e2e098c1445592713c3904630f63d5b823 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 23:25:50 +0000 Subject: [PATCH 01/44] feat: Add config-manager push authentication command --- .../config-manager-push-authentication.ts | 58 ++ .../config-manager-push.ts | 2 + .../FrConfigAuthenticationOps.ts | 64 +- ...g-manager-push-authentication.test.js.snap | 28 + .../config-manager-push.test.js.snap | 1 + ...config-manager-push-authentication.test.js | 10 + ...nager-push-authentication.e2e.test.js.snap | 5 + ...ig-manager-push-authentication.e2e.test.js | 78 ++ .../alpha/realm-config/authentication.json | 66 ++ .../bravo/realm-config/authentication.json | 66 ++ .../am_1076162899/recording.har | 945 ++++++++++++++++++ .../oauth2_393036114/recording.har | 289 ++++++ .../am_1076162899/recording.har | 788 +++++++++++++++ .../oauth2_393036114/recording.har | 289 ++++++ 14 files changed, 2687 insertions(+), 2 deletions(-) create mode 100644 src/cli/config-manager/config-manager-push/config-manager-push-authentication.ts create mode 100644 test/client_cli/en/__snapshots__/config-manager-push-authentication.test.js.snap create mode 100644 test/client_cli/en/config-manager-push-authentication.test.js create mode 100644 test/e2e/__snapshots__/config-manager-push-authentication.e2e.test.js.snap create mode 100644 test/e2e/config-manager-push-authentication.e2e.test.js create mode 100644 test/e2e/exports/fr-config-manager/forgeops/realms/alpha/realm-config/authentication.json create mode 100644 test/e2e/exports/fr-config-manager/forgeops/realms/bravo/realm-config/authentication.json create mode 100644 test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_D_m_314327836/am_1076162899/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_D_m_314327836/oauth2_393036114/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_r_D_m_3443305505/am_1076162899/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_r_D_m_3443305505/oauth2_393036114/recording.har diff --git a/src/cli/config-manager/config-manager-push/config-manager-push-authentication.ts b/src/cli/config-manager/config-manager-push/config-manager-push-authentication.ts new file mode 100644 index 000000000..a4466a0c2 --- /dev/null +++ b/src/cli/config-manager/config-manager-push/config-manager-push-authentication.ts @@ -0,0 +1,58 @@ +import { frodo } from '@rockcarver/frodo-lib'; +import { Option } from 'commander'; + +import { configManagerImportAuthentication } from '../../../configManagerOps/FrConfigAuthenticationOps'; +import { getTokens } from '../../../ops/AuthenticateOps'; +import { printMessage, verboseMessage } from '../../../utils/Console'; +import { FrodoCommand } from '../../FrodoCommand'; + +const { CLOUD_DEPLOYMENT_TYPE_KEY, FORGEOPS_DEPLOYMENT_TYPE_KEY } = + frodo.utils.constants; + +const deploymentTypes = [ + CLOUD_DEPLOYMENT_TYPE_KEY, + FORGEOPS_DEPLOYMENT_TYPE_KEY, +]; + +export default function setup() { + const program = new FrodoCommand( + 'frodo config-manager push authentication', + [], + deploymentTypes + ); + + program + .description('Import authentication objects.') + .addOption( + new Option( + '-r, --realm ', + 'Specifies the realm to import from. Only the configuration from this realm will be imported.' + ) + ) + .action(async (host, realm, user, password, options, command) => { + command.handleDefaultArgsAndOpts( + host, + realm, + user, + password, + options, + command + ); + if (await getTokens(false, true, deploymentTypes)) { + verboseMessage('Importing config entity authentication'); + const outcome = await configManagerImportAuthentication(options.realm); + if (!outcome) process.exitCode = 1; + } + // unrecognized combination of options or no options + else { + printMessage( + 'Unrecognized combination of options or no options...', + 'error' + ); + program.help(); + process.exitCode = 1; + } + }); + + return program; +} diff --git a/src/cli/config-manager/config-manager-push/config-manager-push.ts b/src/cli/config-manager/config-manager-push/config-manager-push.ts index 0e9c55345..227574575 100644 --- a/src/cli/config-manager/config-manager-push/config-manager-push.ts +++ b/src/cli/config-manager/config-manager-push/config-manager-push.ts @@ -1,6 +1,7 @@ import { FrodoStubCommand } from '../../FrodoCommand'; import AccessConfig from './config-manager-push-access-config'; import Audit from './config-manager-push-audit'; +import Authentication from './config-manager-push-authentication'; import CookieDomains from './config-manager-push-cookie-domain'; import EmailProvider from './config-manager-push-email-provider'; import EmailTemplates from './config-manager-push-email-templates'; @@ -39,6 +40,7 @@ export default function setup() { program.addCommand(CookieDomains().name('cookie-domains')); program.addCommand(ServiceObjects().name('service-objects')); program.addCommand(UiConfig().name('ui-config')); + program.addCommand(Authentication().name('authentication')); return program; } diff --git a/src/configManagerOps/FrConfigAuthenticationOps.ts b/src/configManagerOps/FrConfigAuthenticationOps.ts index 22d92ac83..10733613b 100644 --- a/src/configManagerOps/FrConfigAuthenticationOps.ts +++ b/src/configManagerOps/FrConfigAuthenticationOps.ts @@ -1,10 +1,14 @@ import { frodo, state } from '@rockcarver/frodo-lib'; +import { AuthenticationSettingsExportInterface } from '@rockcarver/frodo-lib/types/ops/AuthenticationSettingsOps'; +import fs from 'fs'; import { printError } from '../utils/Console'; import { realmList } from '../utils/FrConfig'; -const { readAuthenticationSettings: _readAuthenticationSettings } = - frodo.authn.settings; +const { + readAuthenticationSettings: _readAuthenticationSettings, + importAuthenticationSettings, +} = frodo.authn.settings; const { getFilePath, saveJsonToFile } = frodo.utils; /** @@ -47,3 +51,59 @@ export async function configManagerExportAuthentication( } return false; } + +/** + * Import authentication configuration from the fr-config-manager format. + * @param {string} realm The realm of the authentication configuration being imported. If not supplied, will import all authentication configuration. + * @return {Promise} a promise that resolves to true if successful, false otherwise + */ +export async function configManagerImportAuthentication( + realm?: string +): Promise { + try { + if (realm) { + const filePath = getFilePath( + `realms/${realm}/realm-config/authentication.json` + ); + const fileContent = fs.readFileSync(filePath, 'utf-8'); + const authData = JSON.parse(fileContent); + delete authData._rev; + const importData: AuthenticationSettingsExportInterface = { + authentication: authData, + }; + + await importAuthenticationSettings(importData, false); + } else { + const realmsPath = getFilePath(`realms/`); + const realmDirs = fs.readdirSync(realmsPath); + for (const realmName of realmDirs) { + await state.setRealm(realmName); + let realmPath; + + if (realmName === 'realm-config') { + await state.setRealm('/'); + realmPath = getFilePath(`realms/realm-config/authentication.json`); + } else { + await state.setRealm(realmName); + realmPath = getFilePath( + `realms/${realmName}/realm-config/authentication.json` + ); + } + + const fileContent = fs.readFileSync(realmPath, 'utf-8'); + const authData = JSON.parse(fileContent); + delete authData._rev; + const importData: AuthenticationSettingsExportInterface = { + authentication: authData, + }; + + await importAuthenticationSettings(importData, false); + } + } + + return true; + } catch (error) { + printError(error, `Error importing authentication settings`); + } + return false; +} diff --git a/test/client_cli/en/__snapshots__/config-manager-push-authentication.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-push-authentication.test.js.snap new file mode 100644 index 000000000..ff5e68b74 --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-push-authentication.test.js.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config-manager push authentication' should be expected english 1`] = ` +"Usage: frodo config-manager push authentication [options] [host] [realm] [username] [password] + +[Experimental] Import authentication objects. + +Arguments: + host AM base URL, e.g.: https://cdk.iam.example.com/am. To use + a connection profile, just specify a unique substring or + alias. + realm Realm. Specify realm as '/' for the root realm or 'realm' + or '/parent/child' otherwise. (default: "alpha" for + Identity Cloud tenants, "/" otherwise.) + username Username to login with. Must be an admin user with + appropriate rights to manage authentication + journeys/trees. + password Password. + +Options: + -r, --realm Specifies the realm to import from. Only the + configuration from this realm will be imported. + -h, --help Help + -hh, --help-more Help with all options. + -hhh, --help-all Help with all options, environment variables, and usage + examples. +" +`; diff --git a/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap index 0bba29ad7..94538d70f 100644 --- a/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap +++ b/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap @@ -15,6 +15,7 @@ Options: Commands: access-config [Experimental] Import access configuration. audit [Experimental] Import audit configuration. + authentication [Experimental] Import authentication objects. cookie-domains [Experimental] Import cookie domains. email-provider [Experimental] Import email provider configuration. email-templates [Experimental] Import email template objects. diff --git a/test/client_cli/en/config-manager-push-authentication.test.js b/test/client_cli/en/config-manager-push-authentication.test.js new file mode 100644 index 000000000..c93adb89b --- /dev/null +++ b/test/client_cli/en/config-manager-push-authentication.test.js @@ -0,0 +1,10 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager push authentication --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config-manager push authentication' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); diff --git a/test/e2e/__snapshots__/config-manager-push-authentication.e2e.test.js.snap b/test/e2e/__snapshots__/config-manager-push-authentication.e2e.test.js.snap new file mode 100644 index 000000000..a30bb6b5d --- /dev/null +++ b/test/e2e/__snapshots__/config-manager-push-authentication.e2e.test.js.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`frodo config-manager pulls authentication "frodo config-manager push authentication -D test/e2e/exports/fr-config-manager/forgeops -m forgeops": should import the authentication into forgeops" 1`] = `""`; + +exports[`frodo config-manager pulls authentication "frodo config-manager push authentication -r alpha -D test/e2e/exports/fr-config-manager/forgeops -m forgeops": should import an authentication config by realm into forgeops" 1`] = `""`; diff --git a/test/e2e/config-manager-push-authentication.e2e.test.js b/test/e2e/config-manager-push-authentication.e2e.test.js new file mode 100644 index 000000000..8cfa00bbe --- /dev/null +++ b/test/e2e/config-manager-push-authentication.e2e.test.js @@ -0,0 +1,78 @@ +/** + * Follow this process to write e2e tests for the CLI project: + * + * 1. Test if all the necessary mocks for your tests already exist. + * In mock mode, run the command you want to test with the same arguments + * and parameters exactly as you want to test it, for example: + * + * $ FRODO_MOCK=1 frodo conn save https://openam-frodo-dev.forgeblocks.com/am volker.scheuber@forgerock.com Sup3rS3cr3t! + * + * If your command completes without errors and with the expected results, + * all the required mocks already exist and you are good to write your + * test and skip to step #4. + * + * If, however, your command fails and you see errors like the one below, + * you know you need to record the mock responses first: + * + * [Polly] [adapter:node-http] Recording for the following request is not found and `recordIfMissing` is `false`. + * + * 2. Record mock responses for your exact command. + * In mock record mode, run the command you want to test with the same arguments + * and parameters exactly as you want to test it, for example: + * + * $ FRODO_MOCK=record frodo conn save https://openam-frodo-dev.forgeblocks.com/am volker.scheuber@forgerock.com Sup3rS3cr3t! + * + * Wait until you see all the Polly instances (mock recording adapters) have + * shutdown before you try to run step #1 again. + * Messages like these indicate mock recording adapters shutting down: + * + * Polly instance 'conn/4' stopping in 3s... + * Polly instance 'conn/4' stopping in 2s... + * Polly instance 'conn/save/3' stopping in 3s... + * Polly instance 'conn/4' stopping in 1s... + * Polly instance 'conn/save/3' stopping in 2s... + * Polly instance 'conn/4' stopped. + * Polly instance 'conn/save/3' stopping in 1s... + * Polly instance 'conn/save/3' stopped. + * + * 3. Validate your freshly recorded mock responses are complete and working. + * Re-run the exact command you want to test in mock mode (see step #1). + * + * 4. Write your test. + * Make sure to use the exact command including number of arguments and params. + * + * 5. Commit both your test and your new recordings to the repository. + * Your tests are likely going to reside outside the frodo-lib project but + * the recordings must be committed to the frodo-lib project. + */ + +/* +// ForgeOps +FRODO_MOCK=record FRODO_NO_CACHE=1 FRODO_HOST=https://nightly.gcp.forgeops.com/am frodo config-manager push authentication -D test/e2e/exports/fr-config-manager/forgeops -m forgeops +FRODO_MOCK=record FRODO_NO_CACHE=1 FRODO_HOST=https://nightly.gcp.forgeops.com/am frodo config-manager push authentication -r alpha -D test/e2e/exports/fr-config-manager/forgeops -m forgeops +*/ + +import cp from 'child_process'; +import { promisify } from 'util'; +import { getEnv, removeAnsiEscapeCodes } from './utils/TestUtils'; +import { forgeops_connection as fc } from './utils/TestConfig'; + +const exec = promisify(cp.exec); + +process.env['FRODO_MOCK'] = '1'; +const forgeopsEnv = getEnv(fc); + +const allDirectory = "test/e2e/exports/fr-config-manager/forgeops"; + +describe('frodo config-manager pulls authentication', () => { + test(`"frodo config-manager push authentication -D ${allDirectory} -m forgeops": should import the authentication into forgeops"`, async () => { + const CMD = `frodo config-manager push authentication -D ${allDirectory} -m forgeops`; + const { stdout } = await exec(CMD, forgeopsEnv); + expect(removeAnsiEscapeCodes(stdout)).toMatchSnapshot(); + }); + test(`"frodo config-manager push authentication -r alpha -D ${allDirectory} -m forgeops": should import an authentication config by realm into forgeops"`, async () => { + const CMD = `frodo config-manager push authentication -r alpha -D ${allDirectory} -m forgeops`; + const { stdout } = await exec(CMD, forgeopsEnv); + expect(removeAnsiEscapeCodes(stdout)).toMatchSnapshot(); + }); +}); diff --git a/test/e2e/exports/fr-config-manager/forgeops/realms/alpha/realm-config/authentication.json b/test/e2e/exports/fr-config-manager/forgeops/realms/alpha/realm-config/authentication.json new file mode 100644 index 000000000..414532457 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/forgeops/realms/alpha/realm-config/authentication.json @@ -0,0 +1,66 @@ +{ + "_id": "", + "_rev": "1552144906", + "_type": { + "_id": "EMPTY", + "collection": false, + "name": "Core" + }, + "accountlockout": { + "lockoutDuration": 0, + "lockoutDurationMultiplier": 1, + "lockoutWarnUserCount": 0, + "loginFailureCount": 5, + "loginFailureDuration": 300, + "loginFailureLockoutMode": false, + "storeInvalidAttemptsInDataStore": true + }, + "core": { + "adminAuthModule": "ldapService", + "orgConfig": "ldapService" + }, + "general": { + "defaultAuthLevel": 0, + "identityType": [ + "agent", + "user" + ], + "locale": "en_US", + "statelessSessionsEnabled": false, + "twoFactorRequired": false, + "userStatusCallbackPlugins": [] + }, + "postauthprocess": { + "loginFailureUrl": [], + "loginPostProcessClass": [], + "loginSuccessUrl": [ + "/am/console" + ], + "userAttributeSessionMapping": [], + "usernameGeneratorClass": "com.sun.identity.authentication.spi.DefaultUserIDGenerator", + "usernameGeneratorEnabled": true + }, + "security": { + "addClearSiteDataHeader": true, + "keyAlias": "test", + "moduleBasedAuthEnabled": true, + "sharedSecret": null, + "zeroPageLoginAllowedWithoutReferrer": true, + "zeroPageLoginEnabled": false, + "zeroPageLoginReferrerWhiteList": [] + }, + "trees": { + "authenticationSessionsMaxDuration": 5, + "authenticationSessionsStateManagement": "JWT", + "authenticationSessionsWhitelist": false, + "authenticationTreeCookieHttpOnly": true, + "suspendedAuthenticationTimeout": 5 + }, + "userprofile": { + "aliasAttributeName": [ + "uid" + ], + "defaultRole": [], + "dynamicProfileCreation": "false" + } +} diff --git a/test/e2e/exports/fr-config-manager/forgeops/realms/bravo/realm-config/authentication.json b/test/e2e/exports/fr-config-manager/forgeops/realms/bravo/realm-config/authentication.json new file mode 100644 index 000000000..414532457 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/forgeops/realms/bravo/realm-config/authentication.json @@ -0,0 +1,66 @@ +{ + "_id": "", + "_rev": "1552144906", + "_type": { + "_id": "EMPTY", + "collection": false, + "name": "Core" + }, + "accountlockout": { + "lockoutDuration": 0, + "lockoutDurationMultiplier": 1, + "lockoutWarnUserCount": 0, + "loginFailureCount": 5, + "loginFailureDuration": 300, + "loginFailureLockoutMode": false, + "storeInvalidAttemptsInDataStore": true + }, + "core": { + "adminAuthModule": "ldapService", + "orgConfig": "ldapService" + }, + "general": { + "defaultAuthLevel": 0, + "identityType": [ + "agent", + "user" + ], + "locale": "en_US", + "statelessSessionsEnabled": false, + "twoFactorRequired": false, + "userStatusCallbackPlugins": [] + }, + "postauthprocess": { + "loginFailureUrl": [], + "loginPostProcessClass": [], + "loginSuccessUrl": [ + "/am/console" + ], + "userAttributeSessionMapping": [], + "usernameGeneratorClass": "com.sun.identity.authentication.spi.DefaultUserIDGenerator", + "usernameGeneratorEnabled": true + }, + "security": { + "addClearSiteDataHeader": true, + "keyAlias": "test", + "moduleBasedAuthEnabled": true, + "sharedSecret": null, + "zeroPageLoginAllowedWithoutReferrer": true, + "zeroPageLoginEnabled": false, + "zeroPageLoginReferrerWhiteList": [] + }, + "trees": { + "authenticationSessionsMaxDuration": 5, + "authenticationSessionsStateManagement": "JWT", + "authenticationSessionsWhitelist": false, + "authenticationTreeCookieHttpOnly": true, + "suspendedAuthenticationTimeout": 5 + }, + "userprofile": { + "aliasAttributeName": [ + "uid" + ], + "defaultRole": [], + "dynamicProfileCreation": "false" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_D_m_314327836/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_D_m_314327836/am_1076162899/recording.har new file mode 100644 index 000000000..ec92877a5 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_D_m_314327836/am_1076162899/recording.har @@ -0,0 +1,945 @@ +{ + "log": { + "_recordingName": "config-manager/push/authentication/0_D_m/am", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccd7a5defd0fdeaa986a2b54642d911a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-ffed6347-21d6-4e64-b264-eccbdd4728c7" + }, + { + "name": "accept-api-version", + "value": "resource=1.1" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 370, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/*" + }, + "response": { + "bodySize": 587, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 587, + "text": "{\"_id\":\"*\",\"_rev\":\"2075994313\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"iPlanetDirectoryPro\",\"secureCookie\":true,\"forgotPassword\":\"false\",\"forgotUsername\":\"false\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"false\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"refererWhitelist\":[],\"allowedWithoutReferer\":true},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"nodeDesignerXuiEnabled\":true}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:24:59 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "587" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.1" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"2075994313\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:24:59.024Z", + "time": 12, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 12 + } + }, + { + "_id": "9f5671275c36a1c0090d0df26ce0e93f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 2, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-ffed6347-21d6-4e64-b264-eccbdd4728c7" + }, + { + "name": "accept-api-version", + "value": "resource=2.0, protocol=1.0" + }, + { + "name": "x-openam-username", + "value": "amadmin" + }, + { + "name": "x-openam-password", + "value": "41ghjnKpNFAFU/HXw82HbFbitYNOOJ0g" + }, + { + "name": "content-length", + "value": "2" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 497, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/authenticate" + }, + "response": { + "bodySize": 167, + "content": { + "mimeType": "application/json", + "size": 167, + "text": "{\"tokenId\":\"\",\"successUrl\":\"/am/console\",\"realm\":\"/\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "iPlanetDirectoryPro", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "amlbcookie", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:24:59 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "content-length", + "value": "167" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "iPlanetDirectoryPro=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "amlbcookie=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=2.1" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 693, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:24:59.042Z", + "time": 21, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 21 + } + }, + { + "_id": "6a3744385d3fd7416ea7089e610fa7e7", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 128, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-ffed6347-21d6-4e64-b264-eccbdd4728c7" + }, + { + "name": "accept-api-version", + "value": "resource=4.0" + }, + { + "name": "content-length", + "value": "128" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"tokenId\":\"\"}" + }, + "queryString": [ + { + "name": "_action", + "value": "getSessionInfo" + } + ], + "url": "https://platform.dev.trivir.com/am/json/realms/root/sessions/?_action=getSessionInfo" + }, + "response": { + "bodySize": 291, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 291, + "text": "{\"username\":\"amadmin\",\"universalId\":\"id=amadmin,ou=user,ou=am-config\",\"realm\":\"/\",\"latestAccessTime\":\"2026-03-31T22:24:59Z\",\"maxIdleExpirationTime\":\"2026-03-31T22:54:59Z\",\"maxSessionExpirationTime\":\"2026-04-01T00:24:58Z\",\"properties\":{\"AMCtxId\":\"87bd5796-6c1a-4d13-8c2b-a1619ca81517-49302\"}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:24:59 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "291" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=4.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 610, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:24:59.070Z", + "time": 6, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 6 + } + }, + { + "_id": "6125d0328ad0dcaee55f73fd8b22ca14", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-ffed6347-21d6-4e64-b264-eccbdd4728c7" + }, + { + "name": "accept-api-version", + "value": "resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 520, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/version" + }, + "response": { + "bodySize": 257, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 257, + "text": "{\"_id\":\"version\",\"_rev\":\"-466575464\",\"version\":\"8.0.1\",\"fullVersion\":\"ForgeRock Access Management 8.0.1 Build b59bc0908346197b0c33afcb9e733d0400feeea1 (2025-April-15 11:37)\",\"revision\":\"b59bc0908346197b0c33afcb9e733d0400feeea1\",\"date\":\"2025-April-15 11:37\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:24:59 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "257" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-466575464\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:24:59.083Z", + "time": 5, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 5 + } + }, + { + "_id": "17daf6be3ac8f188ac301329a0f5d553", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 1296, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-ffed6347-21d6-4e64-b264-eccbdd4728c7" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "1296" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 589, + "httpVersion": "HTTP/1.1", + "method": "PUT", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"_id\":\"\",\"_type\":{\"_id\":\"EMPTY\",\"collection\":false,\"name\":\"Core\"},\"accountlockout\":{\"lockoutDuration\":0,\"lockoutDurationMultiplier\":1,\"lockoutWarnUserCount\":0,\"loginFailureCount\":5,\"loginFailureDuration\":300,\"loginFailureLockoutMode\":false,\"storeInvalidAttemptsInDataStore\":true},\"core\":{\"adminAuthModule\":\"ldapService\",\"orgConfig\":\"ldapService\"},\"general\":{\"defaultAuthLevel\":0,\"identityType\":[\"agent\",\"user\"],\"locale\":\"en_US\",\"statelessSessionsEnabled\":false,\"twoFactorRequired\":false,\"userStatusCallbackPlugins\":[]},\"postauthprocess\":{\"loginFailureUrl\":[],\"loginPostProcessClass\":[],\"loginSuccessUrl\":[\"/am/console\"],\"userAttributeSessionMapping\":[],\"usernameGeneratorClass\":\"com.sun.identity.authentication.spi.DefaultUserIDGenerator\",\"usernameGeneratorEnabled\":true},\"security\":{\"addClearSiteDataHeader\":true,\"keyAlias\":\"test\",\"moduleBasedAuthEnabled\":true,\"sharedSecret\":null,\"zeroPageLoginAllowedWithoutReferrer\":true,\"zeroPageLoginEnabled\":false,\"zeroPageLoginReferrerWhiteList\":[]},\"trees\":{\"authenticationSessionsMaxDuration\":5,\"authenticationSessionsStateManagement\":\"JWT\",\"authenticationSessionsWhitelist\":false,\"authenticationTreeCookieHttpOnly\":true,\"suspendedAuthenticationTimeout\":5},\"userprofile\":{\"aliasAttributeName\":[\"uid\"],\"defaultRole\":[],\"dynamicProfileCreation\":\"false\"}}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/realms/alpha/realm-config/authentication" + }, + "response": { + "bodySize": 1437, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1437, + "text": "{\"_id\":\"\",\"_rev\":\"-754038573\",\"security\":{\"zeroPageLoginReferrerWhiteList\":[],\"moduleBasedAuthEnabled\":true,\"zeroPageLoginEnabled\":false,\"zeroPageLoginAllowedWithoutReferrer\":true,\"sharedSecret\":null,\"addClearSiteDataHeader\":true,\"keyAlias\":\"test\"},\"postauthprocess\":{\"loginPostProcessClass\":[],\"userAttributeSessionMapping\":[],\"usernameGeneratorClass\":\"com.sun.identity.authentication.spi.DefaultUserIDGenerator\",\"usernameGeneratorEnabled\":true,\"loginSuccessUrl\":[\"/am/console\"],\"loginFailureUrl\":[]},\"trees\":{\"suspendedAuthenticationTimeout\":5,\"authenticationSessionsStateManagement\":\"JWT\",\"authenticationSessionsMaxDuration\":5,\"authenticationTreeCookieHttpOnly\":true,\"authenticationSessionsWhitelist\":false},\"accountlockout\":{\"loginFailureLockoutMode\":false,\"storeInvalidAttemptsInDataStore\":true,\"invalidAttemptsDataAttributeName\":\"fr-attr-str4\",\"lockoutDurationMultiplier\":1,\"lockoutWarnUserCount\":0,\"loginFailureDuration\":300,\"lockoutDuration\":0,\"lockoutAttributeValue\":\"locked\",\"lockoutAttributeName\":\"fr-attr-str3\",\"loginFailureCount\":5},\"core\":{\"adminAuthModule\":\"ldapService\",\"orgConfig\":\"ldapService\"},\"general\":{\"userStatusCallbackPlugins\":[],\"locale\":\"en_US\",\"identityType\":[\"agent\",\"user\"],\"defaultAuthLevel\":0,\"statelessSessionsEnabled\":false,\"twoFactorRequired\":false},\"userprofile\":{\"defaultRole\":[],\"dynamicProfileCreation\":\"false\",\"aliasAttributeName\":[\"uid\"]},\"_type\":{\"_id\":\"EMPTY\",\"name\":\"Core\",\"collection\":false}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:24:59 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1437" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-754038573\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:24:59.163Z", + "time": 23, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 23 + } + }, + { + "_id": "f7992e3fab7717565414df08c45fd4e1", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 1296, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-ffed6347-21d6-4e64-b264-eccbdd4728c7" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "1296" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 589, + "httpVersion": "HTTP/1.1", + "method": "PUT", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"_id\":\"\",\"_type\":{\"_id\":\"EMPTY\",\"collection\":false,\"name\":\"Core\"},\"accountlockout\":{\"lockoutDuration\":0,\"lockoutDurationMultiplier\":1,\"lockoutWarnUserCount\":0,\"loginFailureCount\":5,\"loginFailureDuration\":300,\"loginFailureLockoutMode\":false,\"storeInvalidAttemptsInDataStore\":true},\"core\":{\"adminAuthModule\":\"ldapService\",\"orgConfig\":\"ldapService\"},\"general\":{\"defaultAuthLevel\":0,\"identityType\":[\"agent\",\"user\"],\"locale\":\"en_US\",\"statelessSessionsEnabled\":false,\"twoFactorRequired\":false,\"userStatusCallbackPlugins\":[]},\"postauthprocess\":{\"loginFailureUrl\":[],\"loginPostProcessClass\":[],\"loginSuccessUrl\":[\"/am/console\"],\"userAttributeSessionMapping\":[],\"usernameGeneratorClass\":\"com.sun.identity.authentication.spi.DefaultUserIDGenerator\",\"usernameGeneratorEnabled\":true},\"security\":{\"addClearSiteDataHeader\":true,\"keyAlias\":\"test\",\"moduleBasedAuthEnabled\":true,\"sharedSecret\":null,\"zeroPageLoginAllowedWithoutReferrer\":true,\"zeroPageLoginEnabled\":false,\"zeroPageLoginReferrerWhiteList\":[]},\"trees\":{\"authenticationSessionsMaxDuration\":5,\"authenticationSessionsStateManagement\":\"JWT\",\"authenticationSessionsWhitelist\":false,\"authenticationTreeCookieHttpOnly\":true,\"suspendedAuthenticationTimeout\":5},\"userprofile\":{\"aliasAttributeName\":[\"uid\"],\"defaultRole\":[],\"dynamicProfileCreation\":\"false\"}}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/realms/bravo/realm-config/authentication" + }, + "response": { + "bodySize": 1316, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1316, + "text": "{\"_id\":\"\",\"_rev\":\"1552144906\",\"security\":{\"zeroPageLoginReferrerWhiteList\":[],\"moduleBasedAuthEnabled\":true,\"zeroPageLoginEnabled\":false,\"zeroPageLoginAllowedWithoutReferrer\":true,\"sharedSecret\":null,\"addClearSiteDataHeader\":true,\"keyAlias\":\"test\"},\"postauthprocess\":{\"loginPostProcessClass\":[],\"userAttributeSessionMapping\":[],\"usernameGeneratorClass\":\"com.sun.identity.authentication.spi.DefaultUserIDGenerator\",\"usernameGeneratorEnabled\":true,\"loginSuccessUrl\":[\"/am/console\"],\"loginFailureUrl\":[]},\"trees\":{\"suspendedAuthenticationTimeout\":5,\"authenticationSessionsStateManagement\":\"JWT\",\"authenticationSessionsMaxDuration\":5,\"authenticationTreeCookieHttpOnly\":true,\"authenticationSessionsWhitelist\":false},\"accountlockout\":{\"loginFailureLockoutMode\":false,\"storeInvalidAttemptsInDataStore\":true,\"lockoutDurationMultiplier\":1,\"lockoutWarnUserCount\":0,\"loginFailureDuration\":300,\"lockoutDuration\":0,\"loginFailureCount\":5},\"core\":{\"adminAuthModule\":\"ldapService\",\"orgConfig\":\"ldapService\"},\"general\":{\"userStatusCallbackPlugins\":[],\"locale\":\"en_US\",\"identityType\":[\"agent\",\"user\"],\"defaultAuthLevel\":0,\"statelessSessionsEnabled\":false,\"twoFactorRequired\":false},\"userprofile\":{\"defaultRole\":[],\"dynamicProfileCreation\":\"false\",\"aliasAttributeName\":[\"uid\"]},\"_type\":{\"_id\":\"EMPTY\",\"name\":\"Core\",\"collection\":false}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:24:59 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1316" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"1552144906\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:24:59.193Z", + "time": 28, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 28 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_D_m_314327836/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_D_m_314327836/oauth2_393036114/recording.har new file mode 100644 index 000000000..051eecfab --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_D_m_314327836/oauth2_393036114/recording.har @@ -0,0 +1,289 @@ +{ + "log": { + "_recordingName": "config-manager/push/authentication/0_D_m/oauth2", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "a684e2f67fd67a4263878c3124af167a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 365, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-ffed6347-21d6-4e64-b264-eccbdd4728c7" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "365" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 565, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&scope=fr:idm:* openid&response_type=code&client_id=idm-admin-ui&csrf=tmKwRw_U1gq05TIYQSyccHN_t-U.*AAJTSQACMDIAAlNLABx2eGUvQlE4Z3l6aE1sSFFlN2hocW1LSUVNNWM9AAR0eXBlAANDVFMAAlMxAAIwMQ..*&decision=allow&code_challenge=6mcJkTgbKo2KA8USaV3S9I4GjS5k_FzrahNdCRK_DVA&code_challenge_method=S256" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/authorize" + }, + "response": { + "bodySize": 0, + "content": { + "mimeType": "text/plain", + "size": 0 + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "expires": "1970-01-01T00:00:00.000Z", + "httpOnly": true, + "name": "OAUTH_REQUEST_ATTRIBUTES", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:24:59 GMT" + }, + { + "name": "content-length", + "value": "0" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "OAUTH_REQUEST_ATTRIBUTES=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "location", + "value": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=m1m-n79INh8eS7qkWTYkG6tEn5A&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 673, + "httpVersion": "HTTP/1.1", + "redirectURL": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=m1m-n79INh8eS7qkWTYkG6tEn5A&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui", + "status": 302, + "statusText": "Found" + }, + "startedDateTime": "2026-03-31T22:24:59.095Z", + "time": 15, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 15 + } + }, + { + "_id": "ff75519a93ccab829f8ee8cf5e92b49f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 224, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-ffed6347-21d6-4e64-b264-eccbdd4728c7" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-length", + "value": "224" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "client_id=idm-admin-ui&redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&grant_type=authorization_code&code=m1m-n79INh8eS7qkWTYkG6tEn5A&code_verifier=NDDfnD28R1HlpQNTDA60vVr6TUfJHw74e5tnObREwuo" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/access_token" + }, + "response": { + "bodySize": 1249, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1249, + "text": "{\"access_token\":\"\",\"scope\":\"openid fr:idm:*\",\"id_token\":\"\",\"token_type\":\"Bearer\",\"expires_in\":239}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:24:59 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1249" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 405, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:24:59.116Z", + "time": 38, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 38 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_r_D_m_3443305505/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_r_D_m_3443305505/am_1076162899/recording.har new file mode 100644 index 000000000..7cf3cc93c --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_r_D_m_3443305505/am_1076162899/recording.har @@ -0,0 +1,788 @@ +{ + "log": { + "_recordingName": "config-manager/push/authentication/0_r_D_m/am", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccd7a5defd0fdeaa986a2b54642d911a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-457f5259-e4c9-4228-81e4-1613da674deb" + }, + { + "name": "accept-api-version", + "value": "resource=1.1" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 370, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/*" + }, + "response": { + "bodySize": 587, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 587, + "text": "{\"_id\":\"*\",\"_rev\":\"2075994313\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"iPlanetDirectoryPro\",\"secureCookie\":true,\"forgotPassword\":\"false\",\"forgotUsername\":\"false\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"false\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"refererWhitelist\":[],\"allowedWithoutReferer\":true},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"nodeDesignerXuiEnabled\":true}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:25:28 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "587" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.1" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"2075994313\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:25:27.911Z", + "time": 12, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 12 + } + }, + { + "_id": "9f5671275c36a1c0090d0df26ce0e93f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 2, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-457f5259-e4c9-4228-81e4-1613da674deb" + }, + { + "name": "accept-api-version", + "value": "resource=2.0, protocol=1.0" + }, + { + "name": "x-openam-username", + "value": "amadmin" + }, + { + "name": "x-openam-password", + "value": "41ghjnKpNFAFU/HXw82HbFbitYNOOJ0g" + }, + { + "name": "content-length", + "value": "2" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 497, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/authenticate" + }, + "response": { + "bodySize": 167, + "content": { + "mimeType": "application/json", + "size": 167, + "text": "{\"tokenId\":\"\",\"successUrl\":\"/am/console\",\"realm\":\"/\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "iPlanetDirectoryPro", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "amlbcookie", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:25:28 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "content-length", + "value": "167" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "iPlanetDirectoryPro=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "amlbcookie=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=2.1" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 693, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:25:27.931Z", + "time": 25, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 25 + } + }, + { + "_id": "7a2803b95b7b030f104baf5a89ef50c3", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 128, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-457f5259-e4c9-4228-81e4-1613da674deb" + }, + { + "name": "accept-api-version", + "value": "resource=4.0" + }, + { + "name": "content-length", + "value": "128" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 437, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"tokenId\":\"\"}" + }, + "queryString": [ + { + "name": "_action", + "value": "getSessionInfo" + } + ], + "url": "https://platform.dev.trivir.com/am/json/realms/root/realms/alpha/sessions/?_action=getSessionInfo" + }, + "response": { + "bodySize": 291, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 291, + "text": "{\"username\":\"amadmin\",\"universalId\":\"id=amadmin,ou=user,ou=am-config\",\"realm\":\"/\",\"latestAccessTime\":\"2026-03-31T22:25:28Z\",\"maxIdleExpirationTime\":\"2026-03-31T22:55:28Z\",\"maxSessionExpirationTime\":\"2026-04-01T00:25:27Z\",\"properties\":{\"AMCtxId\":\"87bd5796-6c1a-4d13-8c2b-a1619ca81517-49379\"}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:25:28 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "291" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=4.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 610, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:25:27.966Z", + "time": 7, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 7 + } + }, + { + "_id": "6125d0328ad0dcaee55f73fd8b22ca14", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-457f5259-e4c9-4228-81e4-1613da674deb" + }, + { + "name": "accept-api-version", + "value": "resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 520, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/version" + }, + "response": { + "bodySize": 257, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 257, + "text": "{\"_id\":\"version\",\"_rev\":\"-466575464\",\"version\":\"8.0.1\",\"fullVersion\":\"ForgeRock Access Management 8.0.1 Build b59bc0908346197b0c33afcb9e733d0400feeea1 (2025-April-15 11:37)\",\"revision\":\"b59bc0908346197b0c33afcb9e733d0400feeea1\",\"date\":\"2025-April-15 11:37\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:25:28 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "257" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-466575464\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:25:27.981Z", + "time": 6, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 6 + } + }, + { + "_id": "17daf6be3ac8f188ac301329a0f5d553", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 1296, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-457f5259-e4c9-4228-81e4-1613da674deb" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "1296" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 589, + "httpVersion": "HTTP/1.1", + "method": "PUT", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"_id\":\"\",\"_type\":{\"_id\":\"EMPTY\",\"collection\":false,\"name\":\"Core\"},\"accountlockout\":{\"lockoutDuration\":0,\"lockoutDurationMultiplier\":1,\"lockoutWarnUserCount\":0,\"loginFailureCount\":5,\"loginFailureDuration\":300,\"loginFailureLockoutMode\":false,\"storeInvalidAttemptsInDataStore\":true},\"core\":{\"adminAuthModule\":\"ldapService\",\"orgConfig\":\"ldapService\"},\"general\":{\"defaultAuthLevel\":0,\"identityType\":[\"agent\",\"user\"],\"locale\":\"en_US\",\"statelessSessionsEnabled\":false,\"twoFactorRequired\":false,\"userStatusCallbackPlugins\":[]},\"postauthprocess\":{\"loginFailureUrl\":[],\"loginPostProcessClass\":[],\"loginSuccessUrl\":[\"/am/console\"],\"userAttributeSessionMapping\":[],\"usernameGeneratorClass\":\"com.sun.identity.authentication.spi.DefaultUserIDGenerator\",\"usernameGeneratorEnabled\":true},\"security\":{\"addClearSiteDataHeader\":true,\"keyAlias\":\"test\",\"moduleBasedAuthEnabled\":true,\"sharedSecret\":null,\"zeroPageLoginAllowedWithoutReferrer\":true,\"zeroPageLoginEnabled\":false,\"zeroPageLoginReferrerWhiteList\":[]},\"trees\":{\"authenticationSessionsMaxDuration\":5,\"authenticationSessionsStateManagement\":\"JWT\",\"authenticationSessionsWhitelist\":false,\"authenticationTreeCookieHttpOnly\":true,\"suspendedAuthenticationTimeout\":5},\"userprofile\":{\"aliasAttributeName\":[\"uid\"],\"defaultRole\":[],\"dynamicProfileCreation\":\"false\"}}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/realms/alpha/realm-config/authentication" + }, + "response": { + "bodySize": 1437, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1437, + "text": "{\"_id\":\"\",\"_rev\":\"-754038573\",\"security\":{\"zeroPageLoginReferrerWhiteList\":[],\"moduleBasedAuthEnabled\":true,\"zeroPageLoginEnabled\":false,\"zeroPageLoginAllowedWithoutReferrer\":true,\"sharedSecret\":null,\"addClearSiteDataHeader\":true,\"keyAlias\":\"test\"},\"postauthprocess\":{\"loginPostProcessClass\":[],\"userAttributeSessionMapping\":[],\"usernameGeneratorClass\":\"com.sun.identity.authentication.spi.DefaultUserIDGenerator\",\"usernameGeneratorEnabled\":true,\"loginSuccessUrl\":[\"/am/console\"],\"loginFailureUrl\":[]},\"trees\":{\"suspendedAuthenticationTimeout\":5,\"authenticationSessionsStateManagement\":\"JWT\",\"authenticationSessionsMaxDuration\":5,\"authenticationTreeCookieHttpOnly\":true,\"authenticationSessionsWhitelist\":false},\"accountlockout\":{\"loginFailureLockoutMode\":false,\"storeInvalidAttemptsInDataStore\":true,\"invalidAttemptsDataAttributeName\":\"fr-attr-str4\",\"lockoutDurationMultiplier\":1,\"lockoutWarnUserCount\":0,\"loginFailureDuration\":300,\"lockoutDuration\":0,\"lockoutAttributeValue\":\"locked\",\"lockoutAttributeName\":\"fr-attr-str3\",\"loginFailureCount\":5},\"core\":{\"adminAuthModule\":\"ldapService\",\"orgConfig\":\"ldapService\"},\"general\":{\"userStatusCallbackPlugins\":[],\"locale\":\"en_US\",\"identityType\":[\"agent\",\"user\"],\"defaultAuthLevel\":0,\"statelessSessionsEnabled\":false,\"twoFactorRequired\":false},\"userprofile\":{\"defaultRole\":[],\"dynamicProfileCreation\":\"false\",\"aliasAttributeName\":[\"uid\"]},\"_type\":{\"_id\":\"EMPTY\",\"name\":\"Core\",\"collection\":false}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:25:28 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1437" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-754038573\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:25:28.057Z", + "time": 20, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 20 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_r_D_m_3443305505/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_r_D_m_3443305505/oauth2_393036114/recording.har new file mode 100644 index 000000000..8807849f9 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/push_2272264157/authentication_2600143457/0_r_D_m_3443305505/oauth2_393036114/recording.har @@ -0,0 +1,289 @@ +{ + "log": { + "_recordingName": "config-manager/push/authentication/0_r_D_m/oauth2", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "a684e2f67fd67a4263878c3124af167a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 365, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-457f5259-e4c9-4228-81e4-1613da674deb" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "365" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 565, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&scope=fr:idm:* openid&response_type=code&client_id=idm-admin-ui&csrf=OZfkb1NUb_XVoTTcEaJ4WHv7FnY.*AAJTSQACMDIAAlNLABxkRm42M2RWQktFSTZINVVuWkIvZHZ6bUNpT0U9AAR0eXBlAANDVFMAAlMxAAIwMQ..*&decision=allow&code_challenge=j-UazCtn5hubmtIgxPB8Ydo4dtalzWdqPKEdBwTNYYs&code_challenge_method=S256" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/authorize" + }, + "response": { + "bodySize": 0, + "content": { + "mimeType": "text/plain", + "size": 0 + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "expires": "1970-01-01T00:00:00.000Z", + "httpOnly": true, + "name": "OAUTH_REQUEST_ATTRIBUTES", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:25:28 GMT" + }, + { + "name": "content-length", + "value": "0" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "OAUTH_REQUEST_ATTRIBUTES=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "location", + "value": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=s2w7bsBUElJVW93AosqQmdpnDfI&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 672, + "httpVersion": "HTTP/1.1", + "redirectURL": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=s2w7bsBUElJVW93AosqQmdpnDfI&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui", + "status": 302, + "statusText": "Found" + }, + "startedDateTime": "2026-03-31T22:25:27.995Z", + "time": 14, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 14 + } + }, + { + "_id": "ff75519a93ccab829f8ee8cf5e92b49f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 224, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-34" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-457f5259-e4c9-4228-81e4-1613da674deb" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-length", + "value": "224" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "client_id=idm-admin-ui&redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&grant_type=authorization_code&code=s2w7bsBUElJVW93AosqQmdpnDfI&code_verifier=l6yWrk5ubXogQUIzmPHuDA22-NScXnRd7eOWuXa5UP8" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/access_token" + }, + "response": { + "bodySize": 1249, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1249, + "text": "{\"access_token\":\"\",\"scope\":\"openid fr:idm:*\",\"id_token\":\"\",\"token_type\":\"Bearer\",\"expires_in\":239}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Tue, 31 Mar 2026 22:25:28 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1249" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 403, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-03-31T22:25:28.015Z", + "time": 35, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 35 + } + } + ], + "pages": [], + "version": "1.2" + } +} From 3ce0613a0744336e971a577ff7319bf79025022e Mon Sep 17 00:00:00 2001 From: dallinjsevy Date: Sun, 25 Jun 2023 15:20:06 -0600 Subject: [PATCH 02/44] feat: Add config-manager push connector-definitions command --- ...nfig-manager-push-connector-definitions.ts | 52 ++ .../config-manager-push.ts | 2 + .../FrConfigConnectorDefinitionsOps.ts | 43 ++ ...er-push-connector-definitions.test.js.snap | 27 + .../config-manager-push.test.js.snap | 45 +- ...manager-push-connector-definitions.test.js | 10 + ...ush-connector-definitions.e2e.test.js.snap | 15 + ...ger-push-connector-definitions.e2e.test.js | 80 +++ .../forgeops/sync/connectors/csv.json | 91 +++ .../forgeops/sync/connectors/salesforce.json | 91 +++ .../am_1076162899/recording.har | 631 ++++++++++++++++++ .../oauth2_393036114/recording.har | 289 ++++++++ .../openidm_3290118515/recording.har | 328 +++++++++ .../am_1076162899/recording.har | 631 ++++++++++++++++++ .../oauth2_393036114/recording.har | 289 ++++++++ .../openidm_3290118515/recording.har | 167 +++++ 16 files changed, 2769 insertions(+), 22 deletions(-) create mode 100644 src/cli/config-manager/config-manager-push/config-manager-push-connector-definitions.ts create mode 100644 test/client_cli/en/__snapshots__/config-manager-push-connector-definitions.test.js.snap create mode 100644 test/client_cli/en/config-manager-push-connector-definitions.test.js create mode 100644 test/e2e/__snapshots__/config-manager-push-connector-definitions.e2e.test.js.snap create mode 100644 test/e2e/config-manager-push-connector-definitions.e2e.test.js create mode 100644 test/e2e/exports/fr-config-manager/forgeops/sync/connectors/csv.json create mode 100644 test/e2e/exports/fr-config-manager/forgeops/sync/connectors/salesforce.json create mode 100644 test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/am_1076162899/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/oauth2_393036114/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/openidm_3290118515/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/am_1076162899/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/oauth2_393036114/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/openidm_3290118515/recording.har diff --git a/src/cli/config-manager/config-manager-push/config-manager-push-connector-definitions.ts b/src/cli/config-manager/config-manager-push/config-manager-push-connector-definitions.ts new file mode 100644 index 000000000..da6545402 --- /dev/null +++ b/src/cli/config-manager/config-manager-push/config-manager-push-connector-definitions.ts @@ -0,0 +1,52 @@ +import { frodo } from '@rockcarver/frodo-lib'; +import { Option } from 'commander'; + +import { configManagerImportConnectors } from '../../../configManagerOps/FrConfigConnectorDefinitionsOps'; +import { getTokens } from '../../../ops/AuthenticateOps'; +import { verboseMessage } from '../../../utils/Console'; +import { FrodoCommand } from '../../FrodoCommand'; + +const { CLOUD_DEPLOYMENT_TYPE_KEY, FORGEOPS_DEPLOYMENT_TYPE_KEY } = + frodo.utils.constants; + +const deploymentTypes = [ + CLOUD_DEPLOYMENT_TYPE_KEY, + FORGEOPS_DEPLOYMENT_TYPE_KEY, +]; + +export default function setup() { + const program = new FrodoCommand( + 'frodo config-manager push connector-definitions', + [], + deploymentTypes + ); + + program + .description('Import connector definitions.') + .addOption( + new Option( + '-n, --name ', + 'Connector definition name; imports only the specified connector definition.' + ) + ) + .action(async (host, realm, user, password, options, command) => { + command.handleDefaultArgsAndOpts( + host, + realm, + user, + password, + options, + command + ); + + if (await getTokens(false, true, deploymentTypes)) { + verboseMessage('Importing connector definitions'); + const outcome = await configManagerImportConnectors(options.name); + if (!outcome) process.exitCode = 1; + } else { + process.exitCode = 1; + } + }); + + return program; +} diff --git a/src/cli/config-manager/config-manager-push/config-manager-push.ts b/src/cli/config-manager/config-manager-push/config-manager-push.ts index 0e9c55345..953868e32 100644 --- a/src/cli/config-manager/config-manager-push/config-manager-push.ts +++ b/src/cli/config-manager/config-manager-push/config-manager-push.ts @@ -1,6 +1,7 @@ import { FrodoStubCommand } from '../../FrodoCommand'; import AccessConfig from './config-manager-push-access-config'; import Audit from './config-manager-push-audit'; +import ConnectorDefinitions from './config-manager-push-connector-definitions'; import CookieDomains from './config-manager-push-cookie-domain'; import EmailProvider from './config-manager-push-email-provider'; import EmailTemplates from './config-manager-push-email-templates'; @@ -39,6 +40,7 @@ export default function setup() { program.addCommand(CookieDomains().name('cookie-domains')); program.addCommand(ServiceObjects().name('service-objects')); program.addCommand(UiConfig().name('ui-config')); + program.addCommand(ConnectorDefinitions().name('connector-definitions')); return program; } diff --git a/src/configManagerOps/FrConfigConnectorDefinitionsOps.ts b/src/configManagerOps/FrConfigConnectorDefinitionsOps.ts index a6619a21b..fa45e73f3 100644 --- a/src/configManagerOps/FrConfigConnectorDefinitionsOps.ts +++ b/src/configManagerOps/FrConfigConnectorDefinitionsOps.ts @@ -1,10 +1,12 @@ import { frodo } from '@rockcarver/frodo-lib'; import { ConnectorSkeleton } from '@rockcarver/frodo-lib/types/ops/ConnectorOps'; +import fs from 'fs'; import { printError, verboseMessage } from '../utils/Console'; const { connector } = frodo.idm; const { getFilePath, saveJsonToFile } = frodo.utils; +const { importConfigEntities } = frodo.idm.config; type ByName = { connectorName: string }; type BySkeleton = { c: ConnectorSkeleton }; @@ -74,3 +76,44 @@ export async function configManagerExportConnectorDefinitionsAll(): Promise} true if successful, false otherwise + */ +export async function configManagerImportConnectors( + name?: string +): Promise { + try { + const connMappingDir = getFilePath('sync/connectors/'); + const connMappingFiles = fs.readdirSync(connMappingDir); + const connMappingImportData = { idm: {} }; + + if (name) { + const filePath = getFilePath(`sync/connectors/${name}.json`); + const fileData = fs.readFileSync(filePath, 'utf8'); + const importData = JSON.parse(fileData); + const id = importData._id; + connMappingImportData.idm[id] = importData; + await importConfigEntities(connMappingImportData); + } else { + for (const connMappingFile of connMappingFiles) { + const filePath = getFilePath(`sync/connectors/`); + const fileData = fs.readFileSync( + `${filePath}/${connMappingFile}`, + 'utf-8' + ); + const importData = JSON.parse(fileData); + const id = importData._id; + connMappingImportData.idm[id] = importData; + } + await importConfigEntities(connMappingImportData); + } + + return true; + } catch (error) { + printError(error, `Error exporting mappings to files`); + } + return false; +} diff --git a/test/client_cli/en/__snapshots__/config-manager-push-connector-definitions.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-push-connector-definitions.test.js.snap new file mode 100644 index 000000000..fdb45d014 --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-push-connector-definitions.test.js.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config-manager push connector-definitions' should be expected english 1`] = ` +"Usage: frodo config-manager push connector-definitions [options] [host] [realm] [username] [password] + +[Experimental] Import connector definitions. + +Arguments: + host AM base URL, e.g.: https://cdk.iam.example.com/am. To use a + connection profile, just specify a unique substring or + alias. + realm Realm. Specify realm as '/' for the root realm or 'realm' + or '/parent/child' otherwise. (default: "alpha" for + Identity Cloud tenants, "/" otherwise.) + username Username to login with. Must be an admin user with + appropriate rights to manage authentication journeys/trees. + password Password. + +Options: + -n, --name Connector definition name; imports only the specified + connector definition. + -h, --help Help + -hh, --help-more Help with all options. + -hhh, --help-all Help with all options, environment variables, and usage + examples. +" +`; diff --git a/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap index 0bba29ad7..0cb8e44c3 100644 --- a/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap +++ b/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap @@ -7,29 +7,30 @@ exports[`CLI help interface for 'config-manager push' should be expected english compatible with fr-config-manager). Options: - -h, --help Help - -hh, --help-more Help with all options. - -hhh, --help-all Help with all options, environment variables, and usage - examples. + -h, --help Help + -hh, --help-more Help with all options. + -hhh, --help-all Help with all options, environment variables, and usage + examples. Commands: - access-config [Experimental] Import access configuration. - audit [Experimental] Import audit configuration. - cookie-domains [Experimental] Import cookie domains. - email-provider [Experimental] Import email provider configuration. - email-templates [Experimental] Import email template objects. - endpoints [Experimental] Import custom endpoints objects. - help display help for command - internal-roles [Experimental] Import internal roles. - kba [Experimental] Import kba configuration. - locales [Experimental] Import custom locales objects. - managed-objects [Experimental] Import managed objects. - org-privileges [Experimental] Import organization privileges config. - password-policy [Experimental] Import password-policy objects. - schedules [Experimental] Import schedules. - service-objects [Experimental] Import service objects. - terms-and-conditions [Experimental] Import terms and conditions. - themes [Experimental] Import themes. - ui-config [Experimental] Import UI configuration. + access-config [Experimental] Import access configuration. + audit [Experimental] Import audit configuration. + connector-definitions [Experimental] Import connector definitions. + cookie-domains [Experimental] Import cookie domains. + email-provider [Experimental] Import email provider configuration. + email-templates [Experimental] Import email template objects. + endpoints [Experimental] Import custom endpoints objects. + help display help for command + internal-roles [Experimental] Import internal roles. + kba [Experimental] Import kba configuration. + locales [Experimental] Import custom locales objects. + managed-objects [Experimental] Import managed objects. + org-privileges [Experimental] Import organization privileges config. + password-policy [Experimental] Import password-policy objects. + schedules [Experimental] Import schedules. + service-objects [Experimental] Import service objects. + terms-and-conditions [Experimental] Import terms and conditions. + themes [Experimental] Import themes. + ui-config [Experimental] Import UI configuration. " `; diff --git a/test/client_cli/en/config-manager-push-connector-definitions.test.js b/test/client_cli/en/config-manager-push-connector-definitions.test.js new file mode 100644 index 000000000..d46ab7729 --- /dev/null +++ b/test/client_cli/en/config-manager-push-connector-definitions.test.js @@ -0,0 +1,10 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager push connector-definitions --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config-manager push connector-definitions' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); \ No newline at end of file diff --git a/test/e2e/__snapshots__/config-manager-push-connector-definitions.e2e.test.js.snap b/test/e2e/__snapshots__/config-manager-push-connector-definitions.e2e.test.js.snap new file mode 100644 index 000000000..5a0bd4384 --- /dev/null +++ b/test/e2e/__snapshots__/config-manager-push-connector-definitions.e2e.test.js.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`frodo config-manager push connector-definitions "frodo config-manager push connector-definitions -D test/e2e/exports/fr-config-manager/forgeops -m forgeops": should import the connector definitions into forgeops" 1`] = `""`; + +exports[`frodo config-manager push connector-definitions "frodo config-manager push connector-definitions -D test/e2e/exports/fr-config-manager/forgeops -m forgeops": should import the connector definitions into forgeops" 2`] = ` +"Experimental feature in use: 'frodo config-manager push connector-definitions'. This feature may change without notice. +" +`; + +exports[`frodo config-manager push connector-definitions "frodo config-manager push connector-definitions -n csv -D test/e2e/exports/fr-config-manager/forgeops -m forgeops": should import the csv connector definition into forgeops" 1`] = `""`; + +exports[`frodo config-manager push connector-definitions "frodo config-manager push connector-definitions -n csv -D test/e2e/exports/fr-config-manager/forgeops -m forgeops": should import the csv connector definition into forgeops" 2`] = ` +"Experimental feature in use: 'frodo config-manager push connector-definitions'. This feature may change without notice. +" +`; diff --git a/test/e2e/config-manager-push-connector-definitions.e2e.test.js b/test/e2e/config-manager-push-connector-definitions.e2e.test.js new file mode 100644 index 000000000..93f7ed20f --- /dev/null +++ b/test/e2e/config-manager-push-connector-definitions.e2e.test.js @@ -0,0 +1,80 @@ +/** + * Follow this process to write e2e tests for the CLI project: + * + * 1. Test if all the necessary mocks for your tests already exist. + * In mock mode, run the command you want to test with the same arguments + * and parameters exactly as you want to test it, for example: + * + * $ FRODO_MOCK=1 frodo conn save https://openam-frodo-dev.forgeblocks.com/am volker.scheuber@forgerock.com Sup3rS3cr3t! + * + * If your command completes without errors and with the expected results, + * all the required mocks already exist and you are good to write your + * test and skip to step #4. + * + * If, however, your command fails and you see errors like the one below, + * you know you need to record the mock responses first: + * + * [Polly] [adapter:node-http] Recording for the following request is not found and `recordIfMissing` is `false`. + * + * 2. Record mock responses for your exact command. + * In mock record mode, run the command you want to test with the same arguments + * and parameters exactly as you want to test it, for example: + * + * $ FRODO_MOCK=record frodo conn save https://openam-frodo-dev.forgeblocks.com/am volker.scheuber@forgerock.com Sup3rS3cr3t! + * + * Wait until you see all the Polly instances (mock recording adapters) have + * shutdown before you try to run step #1 again. + * Messages like these indicate mock recording adapters shutting down: + * + * Polly instance 'conn/4' stopping in 3s... + * Polly instance 'conn/4' stopping in 2s... + * Polly instance 'conn/save/3' stopping in 3s... + * Polly instance 'conn/4' stopping in 1s... + * Polly instance 'conn/save/3' stopping in 2s... + * Polly instance 'conn/4' stopped. + * Polly instance 'conn/save/3' stopping in 1s... + * Polly instance 'conn/save/3' stopped. + * + * 3. Validate your freshly recorded mock responses are complete and working. + * Re-run the exact command you want to test in mock mode (see step #1). + * + * 4. Write your test. + * Make sure to use the exact command including number of arguments and params. + * + * 5. Commit both your test and your new recordings to the repository. + * Your tests are likely going to reside outside the frodo-lib project but + * the recordings must be committed to the frodo-lib project. + */ + +/* +// ForgeOps +FRODO_MOCK=record FRODO_NO_CACHE=1 FRODO_HOST=https://nightly.gcp.forgeops.com/am frodo config-manager push connector-definitions -D test/e2e/exports/fr-config-manager/forgeops -m forgeops +FRODO_MOCK=record FRODO_NO_CACHE=1 FRODO_HOST=https://nightly.gcp.forgeops.com/am frodo config-manager push connector-definitions -n csv -D test/e2e/exports/fr-config-manager/forgeops -m forgeops +*/ + +import cp from 'child_process'; +import { promisify } from 'util'; +import { getEnv, removeAnsiEscapeCodes } from './utils/TestUtils'; +import { forgeops_connection as fc } from './utils/TestConfig'; + +const exec = promisify(cp.exec); + +process.env['FRODO_MOCK'] = '1'; +const forgeopsEnv = getEnv(fc); + +const allDirectory = "test/e2e/exports/fr-config-manager/forgeops"; + +describe('frodo config-manager push connector-definitions', () => { + test(`"frodo config-manager push connector-definitions -D ${allDirectory} -m forgeops": should import the connector definitions into forgeops"`, async () => { + const CMD = `frodo config-manager push connector-definitions -D ${allDirectory} -m forgeops`; + const { stdout, stderr } = await exec(CMD, forgeopsEnv); + expect(removeAnsiEscapeCodes(stdout)).toMatchSnapshot(); + expect(removeAnsiEscapeCodes(stderr)).toMatchSnapshot(); + }); + test(`"frodo config-manager push connector-definitions -n csv -D ${allDirectory} -m forgeops": should import the csv connector definition into forgeops"`, async () => { + const CMD = `frodo config-manager push connector-definitions -n csv -D ${allDirectory} -m forgeops`; + const { stdout, stderr } = await exec(CMD, forgeopsEnv); + expect(removeAnsiEscapeCodes(stdout)).toMatchSnapshot(); + expect(removeAnsiEscapeCodes(stderr)).toMatchSnapshot(); + }); +}); \ No newline at end of file diff --git a/test/e2e/exports/fr-config-manager/forgeops/sync/connectors/csv.json b/test/e2e/exports/fr-config-manager/forgeops/sync/connectors/csv.json new file mode 100644 index 000000000..991ec9cd6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/forgeops/sync/connectors/csv.json @@ -0,0 +1,91 @@ +{ + "_id": "provisioner.openicf/csv", + "configurationProperties": { + "csvFile": "/home/trivir/Work/frodo-cli/test.csv", + "escapeCharacter": "\\", + "fieldDelimiter": ",", + "headerPassword": "password", + "headerUid": "userName", + "newlineString": "\\n", + "quoteCharacter": "\"", + "spaceReplacementString": "_", + "syncFileRetentionCount": "3" + }, + "connectorRef": { + "bundleName": "org.forgerock.openicf.connectors.csvfile-connector", + "bundleVersion": "1.5.20.34", + "connectorHostRef": "rcs", + "connectorName": "org.forgerock.openicf.csvfile.CSVFileConnector", + "displayName": "CSV File Connector", + "systemType": "provisioner.openicf" + }, + "enabled": false, + "objectTypes": { + "__ACCOUNT__": { + "$schema": "http://json-schema.org/draft-03/schema", + "id": "__ACCOUNT__", + "nativeType": "__ACCOUNT__", + "properties": { + "__NAME__": { + "nativeName": "__NAME__", + "nativeType": "string", + "type": "string" + }, + "activeDate": { + "nativeName": "activeDate", + "nativeType": "string", + "type": "string" + }, + "email": { + "nativeName": "email", + "nativeType": "string", + "type": "string" + }, + "firstName": { + "nativeName": "firstName", + "nativeType": "string", + "type": "string" + }, + "lastName": { + "nativeName": "lastName", + "nativeType": "string", + "type": "string" + } + }, + "type": "object" + } + }, + "operationTimeout": { + "AUTHENTICATE": -1, + "CREATE": -1, + "DELETE": -1, + "GET": -1, + "RESOLVEUSERNAME": -1, + "SCHEMA": -1, + "SCRIPT_ON_CONNECTOR": -1, + "SCRIPT_ON_RESOURCE": -1, + "SEARCH": -1, + "SYNC": -1, + "TEST": -1, + "UPDATE": -1, + "VALIDATE": -1 + }, + "resultsHandlerConfig": { + "enableAttributesToGetSearchResultsHandler": true, + "enableCaseInsensitiveFilter": false, + "enableFilteredResultsHandler": false, + "enableNormalizingResultsHandler": false + }, + "syncFailureHandler": { + "maxRetries": 0, + "postRetryAction": { + "script": { + "globals": { + "message": "hello world!" + }, + "source": "/*\n* This is a test script\n*/\nconsole.log(message);", + "type": "text/javascript" + } + } + } +} diff --git a/test/e2e/exports/fr-config-manager/forgeops/sync/connectors/salesforce.json b/test/e2e/exports/fr-config-manager/forgeops/sync/connectors/salesforce.json new file mode 100644 index 000000000..6c5ce9007 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/forgeops/sync/connectors/salesforce.json @@ -0,0 +1,91 @@ +{ + "_id": "provisioner.openicf/salesforce", + "configurationProperties": { + "clientId": "key", + "clientSecret": { + "$crypto": { + "type": "x-simple-encryption", + "value": { + "cipher": "AES/CBC/PKCS5Padding", + "data": "40bgEWtIvhh9z41Q7AkSDA==", + "iv": "A1alWb/ADDU71HIEbeYHCw==", + "keySize": 16, + "mac": "QnaZr/1qtYufWX1eJ+hU6g==", + "purpose": "idm.config.encryption", + "salt": "e90Jq3pJVPbLVu5jVnt9rQ==", + "stableId": "openidm-sym-default" + } + } + }, + "connectTimeout": 120000, + "grantType": "refresh_token", + "instanceUrl": "", + "loginUrl": "https://test.salesforce.com/services/oauth2/token", + "maximumConnections": 10, + "proxyHost": null, + "proxyPassword": null, + "proxyPort": 3128, + "proxyUri": null, + "proxyUsername": null, + "refreshToken": null, + "supportedFeatureLicenses": [ + "UserPermissionsChatterAnswersUser", + "UserPermissionsInteractionUser", + "UserPermissionsKnowledgeUser", + "UserPermissionsLiveAgentUser", + "UserPermissionsMarketingUser", + "UserPermissionsOfflineUser", + "UserPermissionsSFContentUser", + "UserPermissionsSupportUser", + "UserPermissionsSiteforceContributorUser", + "UserPermissionsSiteforcePublisherUser", + "UserPermissionsWorkDotComUserFeature" + ], + "supportedObjectTypes": [ + "User" + ], + "version": 48 + }, + "connectorRef": { + "bundleName": "org.forgerock.openicf.connectors.salesforce-connector", + "bundleVersion": "1.5.20.28", + "connectorHostRef": "", + "connectorName": "org.forgerock.openicf.connectors.salesforce.SalesforceConnector", + "displayName": "Salesforce Connector", + "systemType": "provisioner.openicf" + }, + "enabled": false, + "operationTimeout": { + "AUTHENTICATE": -1, + "CREATE": -1, + "DELETE": -1, + "GET": -1, + "RESOLVEUSERNAME": -1, + "SCHEMA": -1, + "SCRIPT_ON_CONNECTOR": -1, + "SCRIPT_ON_RESOURCE": -1, + "SEARCH": -1, + "SYNC": -1, + "TEST": -1, + "UPDATE": -1, + "VALIDATE": -1 + }, + "resultsHandlerConfig": { + "enableAttributesToGetSearchResultsHandler": true, + "enableCaseInsensitiveFilter": false, + "enableFilteredResultsHandler": false, + "enableNormalizingResultsHandler": false + }, + "syncFailureHandler": { + "maxRetries": 5, + "postRetryAction": { + "script": { + "globals": { + "message": "hello world!" + }, + "source": "/*\n* This is a test script\n*/\nprintln \"$message\"", + "type": "groovy" + } + } + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/am_1076162899/recording.har new file mode 100644 index 000000000..6867bbdc8 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/am_1076162899/recording.har @@ -0,0 +1,631 @@ +{ + "log": { + "_recordingName": "config-manager/push/connector-definitions/0_D_m/am", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccd7a5defd0fdeaa986a2b54642d911a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-769f72f1-200e-48b2-86a8-a6245e6cbe31" + }, + { + "name": "accept-api-version", + "value": "resource=1.1" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 370, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/*" + }, + "response": { + "bodySize": 585, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 585, + "text": "{\"_id\":\"*\",\"_rev\":\"-2120245986\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"iPlanetDirectoryPro\",\"secureCookie\":true,\"forgotPassword\":\"true\",\"forgotUsername\":\"true\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"true\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"refererWhitelist\":[],\"allowedWithoutReferer\":true},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"nodeDesignerXuiEnabled\":true}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:46:04 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "585" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.1" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-2120245986\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:46:04.072Z", + "time": 41, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 41 + } + }, + { + "_id": "9f5671275c36a1c0090d0df26ce0e93f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 2, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-769f72f1-200e-48b2-86a8-a6245e6cbe31" + }, + { + "name": "accept-api-version", + "value": "resource=2.0, protocol=1.0" + }, + { + "name": "x-openam-username", + "value": "amadmin" + }, + { + "name": "x-openam-password", + "value": "41ghjnKpNFAFU/HXw82HbFbitYNOOJ0g" + }, + { + "name": "content-length", + "value": "2" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 497, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/authenticate" + }, + "response": { + "bodySize": 167, + "content": { + "mimeType": "application/json", + "size": 167, + "text": "{\"tokenId\":\"\",\"successUrl\":\"/am/console\",\"realm\":\"/\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "iPlanetDirectoryPro", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "amlbcookie", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:46:04 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "content-length", + "value": "167" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "iPlanetDirectoryPro=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "amlbcookie=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=2.1" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 693, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:46:04.122Z", + "time": 20, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 20 + } + }, + { + "_id": "6a3744385d3fd7416ea7089e610fa7e7", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 128, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-769f72f1-200e-48b2-86a8-a6245e6cbe31" + }, + { + "name": "accept-api-version", + "value": "resource=4.0" + }, + { + "name": "content-length", + "value": "128" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"tokenId\":\"\"}" + }, + "queryString": [ + { + "name": "_action", + "value": "getSessionInfo" + } + ], + "url": "https://platform.dev.trivir.com/am/json/realms/root/sessions/?_action=getSessionInfo" + }, + "response": { + "bodySize": 291, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 291, + "text": "{\"username\":\"amadmin\",\"universalId\":\"id=amadmin,ou=user,ou=am-config\",\"realm\":\"/\",\"latestAccessTime\":\"2026-04-09T22:46:04Z\",\"maxIdleExpirationTime\":\"2026-04-09T23:16:04Z\",\"maxSessionExpirationTime\":\"2026-04-10T00:46:03Z\",\"properties\":{\"AMCtxId\":\"c092b79d-e82d-486c-a671-af3d7b4f2f6e-54023\"}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:46:04 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "291" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=4.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 610, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:46:04.152Z", + "time": 5, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 5 + } + }, + { + "_id": "6125d0328ad0dcaee55f73fd8b22ca14", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-769f72f1-200e-48b2-86a8-a6245e6cbe31" + }, + { + "name": "accept-api-version", + "value": "resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 520, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/version" + }, + "response": { + "bodySize": 257, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 257, + "text": "{\"_id\":\"version\",\"_rev\":\"-466575464\",\"version\":\"8.0.1\",\"fullVersion\":\"ForgeRock Access Management 8.0.1 Build b59bc0908346197b0c33afcb9e733d0400feeea1 (2025-April-15 11:37)\",\"revision\":\"b59bc0908346197b0c33afcb9e733d0400feeea1\",\"date\":\"2025-April-15 11:37\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:46:04 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "257" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-466575464\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:46:04.165Z", + "time": 6, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 6 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/oauth2_393036114/recording.har new file mode 100644 index 000000000..1e975d0d6 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/oauth2_393036114/recording.har @@ -0,0 +1,289 @@ +{ + "log": { + "_recordingName": "config-manager/push/connector-definitions/0_D_m/oauth2", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "a684e2f67fd67a4263878c3124af167a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 365, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-769f72f1-200e-48b2-86a8-a6245e6cbe31" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "365" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 565, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&scope=fr:idm:* openid&response_type=code&client_id=idm-admin-ui&csrf=19kOoFSbfAzmbsz6rjZs3YhQQjc.*AAJTSQACMDIAAlNLABw4MXR2c1BvRUVuY1hyUUlRNWNNZjV2bHljaFU9AAR0eXBlAANDVFMAAlMxAAIwMQ..*&decision=allow&code_challenge=CZWRX6zc7Kw1qO4gHBZnddanfONKHIc_KXQYl7xk1wQ&code_challenge_method=S256" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/authorize" + }, + "response": { + "bodySize": 0, + "content": { + "mimeType": "text/plain", + "size": 0 + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "expires": "1970-01-01T00:00:00.000Z", + "httpOnly": true, + "name": "OAUTH_REQUEST_ATTRIBUTES", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:46:04 GMT" + }, + { + "name": "content-length", + "value": "0" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "OAUTH_REQUEST_ATTRIBUTES=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "location", + "value": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=UjQtXznELNNnj1kKmu1Q-qLbHSU&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 673, + "httpVersion": "HTTP/1.1", + "redirectURL": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=UjQtXznELNNnj1kKmu1Q-qLbHSU&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui", + "status": 302, + "statusText": "Found" + }, + "startedDateTime": "2026-04-09T22:46:04.180Z", + "time": 15, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 15 + } + }, + { + "_id": "ff75519a93ccab829f8ee8cf5e92b49f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 224, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-769f72f1-200e-48b2-86a8-a6245e6cbe31" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-length", + "value": "224" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "client_id=idm-admin-ui&redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&grant_type=authorization_code&code=UjQtXznELNNnj1kKmu1Q-qLbHSU&code_verifier=kac5BLY2em_RB8ph_X4lyn0_-Ue6xFp1dVChPGRm5Sw" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/access_token" + }, + "response": { + "bodySize": 1249, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1249, + "text": "{\"access_token\":\"\",\"scope\":\"openid fr:idm:*\",\"id_token\":\"\",\"token_type\":\"Bearer\",\"expires_in\":239}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:46:04 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1249" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 405, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:46:04.204Z", + "time": 35, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 35 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/openidm_3290118515/recording.har b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/openidm_3290118515/recording.har new file mode 100644 index 000000000..cbc6d3103 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_D_m_314327836/openidm_3290118515/recording.har @@ -0,0 +1,328 @@ +{ + "log": { + "_recordingName": "config-manager/push/connector-definitions/0_D_m/openidm", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "b917ac2d5128951ef6e28dea20ebe6f6", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 1725, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-769f72f1-200e-48b2-86a8-a6245e6cbe31" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "content-length", + "value": "1725" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 427, + "httpVersion": "HTTP/1.1", + "method": "PUT", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"_id\":\"provisioner.openicf/csv\",\"configurationProperties\":{\"csvFile\":\"/home/trivir/Work/frodo-cli/test.csv\",\"escapeCharacter\":\"\\\\\",\"fieldDelimiter\":\",\",\"headerPassword\":\"password\",\"headerUid\":\"userName\",\"newlineString\":\"\\\\n\",\"quoteCharacter\":\"\\\"\",\"spaceReplacementString\":\"_\",\"syncFileRetentionCount\":\"3\"},\"connectorRef\":{\"bundleName\":\"org.forgerock.openicf.connectors.csvfile-connector\",\"bundleVersion\":\"1.5.20.34\",\"connectorHostRef\":\"rcs\",\"connectorName\":\"org.forgerock.openicf.csvfile.CSVFileConnector\",\"displayName\":\"CSV File Connector\",\"systemType\":\"provisioner.openicf\"},\"enabled\":false,\"objectTypes\":{\"__ACCOUNT__\":{\"$schema\":\"http://json-schema.org/draft-03/schema\",\"id\":\"__ACCOUNT__\",\"nativeType\":\"__ACCOUNT__\",\"properties\":{\"__NAME__\":{\"nativeName\":\"__NAME__\",\"nativeType\":\"string\",\"type\":\"string\"},\"activeDate\":{\"nativeName\":\"activeDate\",\"nativeType\":\"string\",\"type\":\"string\"},\"email\":{\"nativeName\":\"email\",\"nativeType\":\"string\",\"type\":\"string\"},\"firstName\":{\"nativeName\":\"firstName\",\"nativeType\":\"string\",\"type\":\"string\"},\"lastName\":{\"nativeName\":\"lastName\",\"nativeType\":\"string\",\"type\":\"string\"}},\"type\":\"object\"}},\"operationTimeout\":{\"AUTHENTICATE\":-1,\"CREATE\":-1,\"DELETE\":-1,\"GET\":-1,\"RESOLVEUSERNAME\":-1,\"SCHEMA\":-1,\"SCRIPT_ON_CONNECTOR\":-1,\"SCRIPT_ON_RESOURCE\":-1,\"SEARCH\":-1,\"SYNC\":-1,\"TEST\":-1,\"UPDATE\":-1,\"VALIDATE\":-1},\"resultsHandlerConfig\":{\"enableAttributesToGetSearchResultsHandler\":true,\"enableCaseInsensitiveFilter\":false,\"enableFilteredResultsHandler\":false,\"enableNormalizingResultsHandler\":false},\"syncFailureHandler\":{\"maxRetries\":0,\"postRetryAction\":{\"script\":{\"globals\":{\"message\":\"hello world!\"},\"source\":\"/*\\n* This is a test script\\n*/\\nconsole.log(message);\",\"type\":\"text/javascript\"}}}}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/openidm/config/provisioner.openicf/csv" + }, + "response": { + "bodySize": 1725, + "content": { + "mimeType": "application/json;charset=utf-8", + "size": 1725, + "text": "{\"_id\":\"provisioner.openicf/csv\",\"configurationProperties\":{\"csvFile\":\"/home/trivir/Work/frodo-cli/test.csv\",\"escapeCharacter\":\"\\\\\",\"fieldDelimiter\":\",\",\"headerPassword\":\"password\",\"headerUid\":\"userName\",\"newlineString\":\"\\\\n\",\"quoteCharacter\":\"\\\"\",\"spaceReplacementString\":\"_\",\"syncFileRetentionCount\":\"3\"},\"connectorRef\":{\"bundleName\":\"org.forgerock.openicf.connectors.csvfile-connector\",\"bundleVersion\":\"1.5.20.34\",\"connectorHostRef\":\"rcs\",\"connectorName\":\"org.forgerock.openicf.csvfile.CSVFileConnector\",\"displayName\":\"CSV File Connector\",\"systemType\":\"provisioner.openicf\"},\"enabled\":false,\"objectTypes\":{\"__ACCOUNT__\":{\"$schema\":\"http://json-schema.org/draft-03/schema\",\"id\":\"__ACCOUNT__\",\"nativeType\":\"__ACCOUNT__\",\"properties\":{\"__NAME__\":{\"nativeName\":\"__NAME__\",\"nativeType\":\"string\",\"type\":\"string\"},\"activeDate\":{\"nativeName\":\"activeDate\",\"nativeType\":\"string\",\"type\":\"string\"},\"email\":{\"nativeName\":\"email\",\"nativeType\":\"string\",\"type\":\"string\"},\"firstName\":{\"nativeName\":\"firstName\",\"nativeType\":\"string\",\"type\":\"string\"},\"lastName\":{\"nativeName\":\"lastName\",\"nativeType\":\"string\",\"type\":\"string\"}},\"type\":\"object\"}},\"operationTimeout\":{\"AUTHENTICATE\":-1,\"CREATE\":-1,\"DELETE\":-1,\"GET\":-1,\"RESOLVEUSERNAME\":-1,\"SCHEMA\":-1,\"SCRIPT_ON_CONNECTOR\":-1,\"SCRIPT_ON_RESOURCE\":-1,\"SEARCH\":-1,\"SYNC\":-1,\"TEST\":-1,\"UPDATE\":-1,\"VALIDATE\":-1},\"resultsHandlerConfig\":{\"enableAttributesToGetSearchResultsHandler\":true,\"enableCaseInsensitiveFilter\":false,\"enableFilteredResultsHandler\":false,\"enableNormalizingResultsHandler\":false},\"syncFailureHandler\":{\"maxRetries\":0,\"postRetryAction\":{\"script\":{\"globals\":{\"message\":\"hello world!\"},\"source\":\"/*\\n* This is a test script\\n*/\\nconsole.log(message);\",\"type\":\"text/javascript\"}}}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/openidm", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:46:04 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=utf-8" + }, + { + "name": "content-length", + "value": "1725" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/openidm; Secure; HttpOnly" + }, + { + "name": "vary", + "value": "Origin" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "location", + "value": "https://platform.dev.trivir.com/openidm/config/provisioner.openicf/provisioner.openicf/csv" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "DENY" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 740, + "httpVersion": "HTTP/1.1", + "redirectURL": "https://platform.dev.trivir.com/openidm/config/provisioner.openicf/provisioner.openicf/csv", + "status": 201, + "statusText": "Created" + }, + "startedDateTime": "2026-04-09T22:46:04.248Z", + "time": 20, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 20 + } + }, + { + "_id": "1e943a38444f37a9f96bef6a27bc6f23", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 2004, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-769f72f1-200e-48b2-86a8-a6245e6cbe31" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "content-length", + "value": "2004" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 434, + "httpVersion": "HTTP/1.1", + "method": "PUT", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"_id\":\"provisioner.openicf/salesforce\",\"configurationProperties\":{\"clientId\":\"key\",\"clientSecret\":{\"$crypto\":{\"type\":\"x-simple-encryption\",\"value\":{\"cipher\":\"AES/CBC/PKCS5Padding\",\"data\":\"40bgEWtIvhh9z41Q7AkSDA==\",\"iv\":\"A1alWb/ADDU71HIEbeYHCw==\",\"keySize\":16,\"mac\":\"QnaZr/1qtYufWX1eJ+hU6g==\",\"purpose\":\"idm.config.encryption\",\"salt\":\"e90Jq3pJVPbLVu5jVnt9rQ==\",\"stableId\":\"openidm-sym-default\"}}},\"connectTimeout\":120000,\"grantType\":\"refresh_token\",\"instanceUrl\":\"\",\"loginUrl\":\"https://test.salesforce.com/services/oauth2/token\",\"maximumConnections\":10,\"proxyHost\":null,\"proxyPassword\":null,\"proxyPort\":3128,\"proxyUri\":null,\"proxyUsername\":null,\"refreshToken\":null,\"supportedFeatureLicenses\":[\"UserPermissionsChatterAnswersUser\",\"UserPermissionsInteractionUser\",\"UserPermissionsKnowledgeUser\",\"UserPermissionsLiveAgentUser\",\"UserPermissionsMarketingUser\",\"UserPermissionsOfflineUser\",\"UserPermissionsSFContentUser\",\"UserPermissionsSupportUser\",\"UserPermissionsSiteforceContributorUser\",\"UserPermissionsSiteforcePublisherUser\",\"UserPermissionsWorkDotComUserFeature\"],\"supportedObjectTypes\":[\"User\"],\"version\":48},\"connectorRef\":{\"bundleName\":\"org.forgerock.openicf.connectors.salesforce-connector\",\"bundleVersion\":\"1.5.20.28\",\"connectorHostRef\":\"\",\"connectorName\":\"org.forgerock.openicf.connectors.salesforce.SalesforceConnector\",\"displayName\":\"Salesforce Connector\",\"systemType\":\"provisioner.openicf\"},\"enabled\":false,\"operationTimeout\":{\"AUTHENTICATE\":-1,\"CREATE\":-1,\"DELETE\":-1,\"GET\":-1,\"RESOLVEUSERNAME\":-1,\"SCHEMA\":-1,\"SCRIPT_ON_CONNECTOR\":-1,\"SCRIPT_ON_RESOURCE\":-1,\"SEARCH\":-1,\"SYNC\":-1,\"TEST\":-1,\"UPDATE\":-1,\"VALIDATE\":-1},\"resultsHandlerConfig\":{\"enableAttributesToGetSearchResultsHandler\":true,\"enableCaseInsensitiveFilter\":false,\"enableFilteredResultsHandler\":false,\"enableNormalizingResultsHandler\":false},\"syncFailureHandler\":{\"maxRetries\":5,\"postRetryAction\":{\"script\":{\"globals\":{\"message\":\"hello world!\"},\"source\":\"/*\\n* This is a test script\\n*/\\nprintln \\\"$message\\\"\",\"type\":\"groovy\"}}}}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/openidm/config/provisioner.openicf/salesforce" + }, + "response": { + "bodySize": 2004, + "content": { + "mimeType": "application/json;charset=utf-8", + "size": 2004, + "text": "{\"_id\":\"provisioner.openicf/salesforce\",\"configurationProperties\":{\"clientId\":\"key\",\"clientSecret\":{\"$crypto\":{\"type\":\"x-simple-encryption\",\"value\":{\"cipher\":\"AES/CBC/PKCS5Padding\",\"data\":\"40bgEWtIvhh9z41Q7AkSDA==\",\"iv\":\"A1alWb/ADDU71HIEbeYHCw==\",\"keySize\":16,\"mac\":\"QnaZr/1qtYufWX1eJ+hU6g==\",\"purpose\":\"idm.config.encryption\",\"salt\":\"e90Jq3pJVPbLVu5jVnt9rQ==\",\"stableId\":\"openidm-sym-default\"}}},\"connectTimeout\":120000,\"grantType\":\"refresh_token\",\"instanceUrl\":\"\",\"loginUrl\":\"https://test.salesforce.com/services/oauth2/token\",\"maximumConnections\":10,\"proxyHost\":null,\"proxyPassword\":null,\"proxyPort\":3128,\"proxyUri\":null,\"proxyUsername\":null,\"refreshToken\":null,\"supportedFeatureLicenses\":[\"UserPermissionsChatterAnswersUser\",\"UserPermissionsInteractionUser\",\"UserPermissionsKnowledgeUser\",\"UserPermissionsLiveAgentUser\",\"UserPermissionsMarketingUser\",\"UserPermissionsOfflineUser\",\"UserPermissionsSFContentUser\",\"UserPermissionsSupportUser\",\"UserPermissionsSiteforceContributorUser\",\"UserPermissionsSiteforcePublisherUser\",\"UserPermissionsWorkDotComUserFeature\"],\"supportedObjectTypes\":[\"User\"],\"version\":48},\"connectorRef\":{\"bundleName\":\"org.forgerock.openicf.connectors.salesforce-connector\",\"bundleVersion\":\"1.5.20.28\",\"connectorHostRef\":\"\",\"connectorName\":\"org.forgerock.openicf.connectors.salesforce.SalesforceConnector\",\"displayName\":\"Salesforce Connector\",\"systemType\":\"provisioner.openicf\"},\"enabled\":false,\"operationTimeout\":{\"AUTHENTICATE\":-1,\"CREATE\":-1,\"DELETE\":-1,\"GET\":-1,\"RESOLVEUSERNAME\":-1,\"SCHEMA\":-1,\"SCRIPT_ON_CONNECTOR\":-1,\"SCRIPT_ON_RESOURCE\":-1,\"SEARCH\":-1,\"SYNC\":-1,\"TEST\":-1,\"UPDATE\":-1,\"VALIDATE\":-1},\"resultsHandlerConfig\":{\"enableAttributesToGetSearchResultsHandler\":true,\"enableCaseInsensitiveFilter\":false,\"enableFilteredResultsHandler\":false,\"enableNormalizingResultsHandler\":false},\"syncFailureHandler\":{\"maxRetries\":5,\"postRetryAction\":{\"script\":{\"globals\":{\"message\":\"hello world!\"},\"source\":\"/*\\n* This is a test script\\n*/\\nprintln \\\"$message\\\"\",\"type\":\"groovy\"}}}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/openidm", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:46:04 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=utf-8" + }, + { + "name": "content-length", + "value": "2004" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/openidm; Secure; HttpOnly" + }, + { + "name": "vary", + "value": "Origin" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "location", + "value": "https://platform.dev.trivir.com/openidm/config/provisioner.openicf/provisioner.openicf/salesforce" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "DENY" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 746, + "httpVersion": "HTTP/1.1", + "redirectURL": "https://platform.dev.trivir.com/openidm/config/provisioner.openicf/provisioner.openicf/salesforce", + "status": 201, + "statusText": "Created" + }, + "startedDateTime": "2026-04-09T22:46:04.277Z", + "time": 12, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 12 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/am_1076162899/recording.har new file mode 100644 index 000000000..a38dcd07d --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/am_1076162899/recording.har @@ -0,0 +1,631 @@ +{ + "log": { + "_recordingName": "config-manager/push/connector-definitions/0_n_D_m/am", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccd7a5defd0fdeaa986a2b54642d911a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-1eb66775-02b1-404c-b002-64df83027df6" + }, + { + "name": "accept-api-version", + "value": "resource=1.1" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 370, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/*" + }, + "response": { + "bodySize": 585, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 585, + "text": "{\"_id\":\"*\",\"_rev\":\"-2120245986\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"iPlanetDirectoryPro\",\"secureCookie\":true,\"forgotPassword\":\"true\",\"forgotUsername\":\"true\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"true\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"refererWhitelist\":[],\"allowedWithoutReferer\":true},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"nodeDesignerXuiEnabled\":true}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:50:57 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "585" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.1" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-2120245986\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 632, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:50:57.571Z", + "time": 32, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 32 + } + }, + { + "_id": "9f5671275c36a1c0090d0df26ce0e93f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 2, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-1eb66775-02b1-404c-b002-64df83027df6" + }, + { + "name": "accept-api-version", + "value": "resource=2.0, protocol=1.0" + }, + { + "name": "x-openam-username", + "value": "amadmin" + }, + { + "name": "x-openam-password", + "value": "41ghjnKpNFAFU/HXw82HbFbitYNOOJ0g" + }, + { + "name": "content-length", + "value": "2" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 497, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/authenticate" + }, + "response": { + "bodySize": 167, + "content": { + "mimeType": "application/json", + "size": 167, + "text": "{\"tokenId\":\"\",\"successUrl\":\"/am/console\",\"realm\":\"/\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "iPlanetDirectoryPro", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "amlbcookie", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:50:57 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "content-length", + "value": "167" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "iPlanetDirectoryPro=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "amlbcookie=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=2.1" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 693, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:50:57.610Z", + "time": 17, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 17 + } + }, + { + "_id": "6a3744385d3fd7416ea7089e610fa7e7", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 128, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-1eb66775-02b1-404c-b002-64df83027df6" + }, + { + "name": "accept-api-version", + "value": "resource=4.0" + }, + { + "name": "content-length", + "value": "128" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"tokenId\":\"\"}" + }, + "queryString": [ + { + "name": "_action", + "value": "getSessionInfo" + } + ], + "url": "https://platform.dev.trivir.com/am/json/realms/root/sessions/?_action=getSessionInfo" + }, + "response": { + "bodySize": 291, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 291, + "text": "{\"username\":\"amadmin\",\"universalId\":\"id=amadmin,ou=user,ou=am-config\",\"realm\":\"/\",\"latestAccessTime\":\"2026-04-09T22:50:57Z\",\"maxIdleExpirationTime\":\"2026-04-09T23:20:57Z\",\"maxSessionExpirationTime\":\"2026-04-10T00:50:56Z\",\"properties\":{\"AMCtxId\":\"c092b79d-e82d-486c-a671-af3d7b4f2f6e-54355\"}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:50:57 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "291" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=4.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 609, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:50:57.634Z", + "time": 6, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 6 + } + }, + { + "_id": "6125d0328ad0dcaee55f73fd8b22ca14", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-1eb66775-02b1-404c-b002-64df83027df6" + }, + { + "name": "accept-api-version", + "value": "resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 520, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/version" + }, + "response": { + "bodySize": 257, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 257, + "text": "{\"_id\":\"version\",\"_rev\":\"-466575464\",\"version\":\"8.0.1\",\"fullVersion\":\"ForgeRock Access Management 8.0.1 Build b59bc0908346197b0c33afcb9e733d0400feeea1 (2025-April-15 11:37)\",\"revision\":\"b59bc0908346197b0c33afcb9e733d0400feeea1\",\"date\":\"2025-April-15 11:37\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:50:57 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "257" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-466575464\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:50:57.649Z", + "time": 6, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 6 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/oauth2_393036114/recording.har new file mode 100644 index 000000000..8d381a589 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/oauth2_393036114/recording.har @@ -0,0 +1,289 @@ +{ + "log": { + "_recordingName": "config-manager/push/connector-definitions/0_n_D_m/oauth2", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "a684e2f67fd67a4263878c3124af167a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 365, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-1eb66775-02b1-404c-b002-64df83027df6" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "365" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 565, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&scope=fr:idm:* openid&response_type=code&client_id=idm-admin-ui&csrf=JCWraMhpBVR0A0ZtutKj8R57Bqs.*AAJTSQACMDIAAlNLABxlN3hxWEsveGUwdkRsQStuMXNVemtmYytyNlk9AAR0eXBlAANDVFMAAlMxAAIwMQ..*&decision=allow&code_challenge=B5kXEUyMEXrMiVdasvTOIy5ecRLaEHw3hMvuoxei59c&code_challenge_method=S256" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/authorize" + }, + "response": { + "bodySize": 0, + "content": { + "mimeType": "text/plain", + "size": 0 + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "expires": "1970-01-01T00:00:00.000Z", + "httpOnly": true, + "name": "OAUTH_REQUEST_ATTRIBUTES", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:50:57 GMT" + }, + { + "name": "content-length", + "value": "0" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "OAUTH_REQUEST_ATTRIBUTES=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "location", + "value": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=lp4GBc7C75FOdEdJ46WWNu4uL-4&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 673, + "httpVersion": "HTTP/1.1", + "redirectURL": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=lp4GBc7C75FOdEdJ46WWNu4uL-4&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui", + "status": 302, + "statusText": "Found" + }, + "startedDateTime": "2026-04-09T22:50:57.663Z", + "time": 11, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 11 + } + }, + { + "_id": "ff75519a93ccab829f8ee8cf5e92b49f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 224, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-1eb66775-02b1-404c-b002-64df83027df6" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-length", + "value": "224" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "client_id=idm-admin-ui&redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&grant_type=authorization_code&code=lp4GBc7C75FOdEdJ46WWNu4uL-4&code_verifier=uReCui_i8iq7mViQKf4a9IlDx8t2raOVDoNKClzSmXg" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/access_token" + }, + "response": { + "bodySize": 1249, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1249, + "text": "{\"access_token\":\"\",\"scope\":\"openid fr:idm:*\",\"id_token\":\"\",\"token_type\":\"Bearer\",\"expires_in\":239}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:50:57 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1249" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 405, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:50:57.683Z", + "time": 33, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 33 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/openidm_3290118515/recording.har b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/openidm_3290118515/recording.har new file mode 100644 index 000000000..2dc2345f2 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/push_2272264157/connector-definitions_449858571/0_n_D_m_1348920437/openidm_3290118515/recording.har @@ -0,0 +1,167 @@ +{ + "log": { + "_recordingName": "config-manager/push/connector-definitions/0_n_D_m/openidm", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "b917ac2d5128951ef6e28dea20ebe6f6", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 1725, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-1eb66775-02b1-404c-b002-64df83027df6" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "content-length", + "value": "1725" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 427, + "httpVersion": "HTTP/1.1", + "method": "PUT", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"_id\":\"provisioner.openicf/csv\",\"configurationProperties\":{\"csvFile\":\"/home/trivir/Work/frodo-cli/test.csv\",\"escapeCharacter\":\"\\\\\",\"fieldDelimiter\":\",\",\"headerPassword\":\"password\",\"headerUid\":\"userName\",\"newlineString\":\"\\\\n\",\"quoteCharacter\":\"\\\"\",\"spaceReplacementString\":\"_\",\"syncFileRetentionCount\":\"3\"},\"connectorRef\":{\"bundleName\":\"org.forgerock.openicf.connectors.csvfile-connector\",\"bundleVersion\":\"1.5.20.34\",\"connectorHostRef\":\"rcs\",\"connectorName\":\"org.forgerock.openicf.csvfile.CSVFileConnector\",\"displayName\":\"CSV File Connector\",\"systemType\":\"provisioner.openicf\"},\"enabled\":false,\"objectTypes\":{\"__ACCOUNT__\":{\"$schema\":\"http://json-schema.org/draft-03/schema\",\"id\":\"__ACCOUNT__\",\"nativeType\":\"__ACCOUNT__\",\"properties\":{\"__NAME__\":{\"nativeName\":\"__NAME__\",\"nativeType\":\"string\",\"type\":\"string\"},\"activeDate\":{\"nativeName\":\"activeDate\",\"nativeType\":\"string\",\"type\":\"string\"},\"email\":{\"nativeName\":\"email\",\"nativeType\":\"string\",\"type\":\"string\"},\"firstName\":{\"nativeName\":\"firstName\",\"nativeType\":\"string\",\"type\":\"string\"},\"lastName\":{\"nativeName\":\"lastName\",\"nativeType\":\"string\",\"type\":\"string\"}},\"type\":\"object\"}},\"operationTimeout\":{\"AUTHENTICATE\":-1,\"CREATE\":-1,\"DELETE\":-1,\"GET\":-1,\"RESOLVEUSERNAME\":-1,\"SCHEMA\":-1,\"SCRIPT_ON_CONNECTOR\":-1,\"SCRIPT_ON_RESOURCE\":-1,\"SEARCH\":-1,\"SYNC\":-1,\"TEST\":-1,\"UPDATE\":-1,\"VALIDATE\":-1},\"resultsHandlerConfig\":{\"enableAttributesToGetSearchResultsHandler\":true,\"enableCaseInsensitiveFilter\":false,\"enableFilteredResultsHandler\":false,\"enableNormalizingResultsHandler\":false},\"syncFailureHandler\":{\"maxRetries\":0,\"postRetryAction\":{\"script\":{\"globals\":{\"message\":\"hello world!\"},\"source\":\"/*\\n* This is a test script\\n*/\\nconsole.log(message);\",\"type\":\"text/javascript\"}}}}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/openidm/config/provisioner.openicf/csv" + }, + "response": { + "bodySize": 1725, + "content": { + "mimeType": "application/json;charset=utf-8", + "size": 1725, + "text": "{\"_id\":\"provisioner.openicf/csv\",\"configurationProperties\":{\"csvFile\":\"/home/trivir/Work/frodo-cli/test.csv\",\"escapeCharacter\":\"\\\\\",\"fieldDelimiter\":\",\",\"headerPassword\":\"password\",\"headerUid\":\"userName\",\"newlineString\":\"\\\\n\",\"quoteCharacter\":\"\\\"\",\"spaceReplacementString\":\"_\",\"syncFileRetentionCount\":\"3\"},\"connectorRef\":{\"bundleName\":\"org.forgerock.openicf.connectors.csvfile-connector\",\"bundleVersion\":\"1.5.20.34\",\"connectorHostRef\":\"rcs\",\"connectorName\":\"org.forgerock.openicf.csvfile.CSVFileConnector\",\"displayName\":\"CSV File Connector\",\"systemType\":\"provisioner.openicf\"},\"enabled\":false,\"objectTypes\":{\"__ACCOUNT__\":{\"$schema\":\"http://json-schema.org/draft-03/schema\",\"id\":\"__ACCOUNT__\",\"nativeType\":\"__ACCOUNT__\",\"properties\":{\"__NAME__\":{\"nativeName\":\"__NAME__\",\"nativeType\":\"string\",\"type\":\"string\"},\"activeDate\":{\"nativeName\":\"activeDate\",\"nativeType\":\"string\",\"type\":\"string\"},\"email\":{\"nativeName\":\"email\",\"nativeType\":\"string\",\"type\":\"string\"},\"firstName\":{\"nativeName\":\"firstName\",\"nativeType\":\"string\",\"type\":\"string\"},\"lastName\":{\"nativeName\":\"lastName\",\"nativeType\":\"string\",\"type\":\"string\"}},\"type\":\"object\"}},\"operationTimeout\":{\"AUTHENTICATE\":-1,\"CREATE\":-1,\"DELETE\":-1,\"GET\":-1,\"RESOLVEUSERNAME\":-1,\"SCHEMA\":-1,\"SCRIPT_ON_CONNECTOR\":-1,\"SCRIPT_ON_RESOURCE\":-1,\"SEARCH\":-1,\"SYNC\":-1,\"TEST\":-1,\"UPDATE\":-1,\"VALIDATE\":-1},\"resultsHandlerConfig\":{\"enableAttributesToGetSearchResultsHandler\":true,\"enableCaseInsensitiveFilter\":false,\"enableFilteredResultsHandler\":false,\"enableNormalizingResultsHandler\":false},\"syncFailureHandler\":{\"maxRetries\":0,\"postRetryAction\":{\"script\":{\"globals\":{\"message\":\"hello world!\"},\"source\":\"/*\\n* This is a test script\\n*/\\nconsole.log(message);\",\"type\":\"text/javascript\"}}}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/openidm", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Thu, 09 Apr 2026 22:50:57 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=utf-8" + }, + { + "name": "content-length", + "value": "1725" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/openidm; Secure; HttpOnly" + }, + { + "name": "vary", + "value": "Origin" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "DENY" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 638, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-09T22:50:57.723Z", + "time": 26, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 26 + } + } + ], + "pages": [], + "version": "1.2" + } +} From 368a9034019bbe8c1b952999b1046bea4e3fba9b Mon Sep 17 00:00:00 2001 From: brycentrivir Date: Mon, 13 Apr 2026 16:25:20 -0600 Subject: [PATCH 03/44] feat: add config-manager-pull command for custom nodes --- .../config-manager-pull-custom-nodes.ts | 58 + .../config-manager-pull.ts | 2 + .../FrConfigCustomNodesOps.ts | 47 + ...fig-manager-pull-custom-nodes.test.js.snap | 30 + .../config-manager-pull-custom-nodes.test.js | 10 + ...manager-pull-custom-nodes.e2e.test.js.snap | 1668 +++++++++++++++++ ...nfig-manager-pull-custom-nodes.e2e.test.js | 71 + .../am_1076162899/recording.har | 780 ++++++++ .../oauth2_393036114/recording.har | 289 +++ .../am_1076162899/recording.har | 780 ++++++++ .../oauth2_393036114/recording.har | 289 +++ 11 files changed, 4024 insertions(+) create mode 100644 src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts create mode 100644 src/configManagerOps/FrConfigCustomNodesOps.ts create mode 100644 test/client_cli/en/__snapshots__/config-manager-pull-custom-nodes.test.js.snap create mode 100644 test/client_cli/en/config-manager-pull-custom-nodes.test.js create mode 100644 test/e2e/__snapshots__/config-manager-pull-custom-nodes.e2e.test.js.snap create mode 100644 test/e2e/config-manager-pull-custom-nodes.e2e.test.js create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/am_1076162899/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/oauth2_393036114/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/am_1076162899/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/oauth2_393036114/recording.har diff --git a/src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts b/src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts new file mode 100644 index 000000000..3861cd5b6 --- /dev/null +++ b/src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts @@ -0,0 +1,58 @@ +import { frodo } from '@rockcarver/frodo-lib'; +import { Option } from 'commander'; + +import { configManagerExportCustomNodes } from '../../../configManagerOps/FrConfigCustomNodesOps'; +import { getTokens } from '../../../ops/AuthenticateOps'; +import { printMessage, verboseMessage } from '../../../utils/Console'; +import { FrodoCommand } from '../../FrodoCommand'; + +const { CLOUD_DEPLOYMENT_TYPE_KEY, FORGEOPS_DEPLOYMENT_TYPE_KEY } = + frodo.utils.constants; + +const deploymentTypes = [ + CLOUD_DEPLOYMENT_TYPE_KEY, + FORGEOPS_DEPLOYMENT_TYPE_KEY, +]; + +export default function setup() { + const program = new FrodoCommand( + 'frodo config-manager pull custom-nodes', + [], + deploymentTypes + ); + + program + .description('Export custom nodes.') + .addOption( + new Option( + '-n, --node-name ', + 'Custom node display name. If specified, only one custom node is exported.' + ) + ) + .action(async (host, realm, user, password, options, command) => { + command.handleDefaultArgsAndOpts( + host, + realm, + user, + password, + options, + command + ); + + if (await getTokens(false, true, deploymentTypes)) { + if (options.nodeName) { + verboseMessage( + `Fetching custom node with name '${options.nodeName}'` + ); + } else { + verboseMessage('Fetching custom nodes'); + } + const outcome = await configManagerExportCustomNodes(options.nodeName); + if (!outcome) process.exitCode = 1; + } else { + process.exitCode = 1; + } + }); + + return program; +} diff --git a/src/cli/config-manager/config-manager-pull/config-manager-pull.ts b/src/cli/config-manager/config-manager-pull/config-manager-pull.ts index d27bc80da..fb9327378 100644 --- a/src/cli/config-manager/config-manager-pull/config-manager-pull.ts +++ b/src/cli/config-manager/config-manager-pull/config-manager-pull.ts @@ -10,6 +10,7 @@ import ConnectorMappings from './config-manager-pull-connector-mappings'; import CookieDomains from './config-manager-pull-cookie-domains'; import CORS from './config-manager-pull-cors'; import CSP from './config-manager-pull-csp'; +import CustomNodes from './config-manager-pull-custom-nodes'; import EmailProvider from './config-manager-pull-email-provider'; import EmailTemplates from './config-manager-pull-email-templates'; import Endpoints from './config-manager-pull-endpoints'; @@ -52,6 +53,7 @@ export default function setup() { program.addCommand(CookieDomains().name('cookie-domains')); program.addCommand(CORS().name('cors')); program.addCommand(CSP().name('csp')); + program.addCommand(CustomNodes().name('custom-nodes')); program.addCommand(EmailProvider().name('email-provider')); program.addCommand(EmailTemplates().name('email-templates')); program.addCommand(Endpoints().name('endpoints')); diff --git a/src/configManagerOps/FrConfigCustomNodesOps.ts b/src/configManagerOps/FrConfigCustomNodesOps.ts new file mode 100644 index 000000000..91db0016c --- /dev/null +++ b/src/configManagerOps/FrConfigCustomNodesOps.ts @@ -0,0 +1,47 @@ +import { frodo } from '@rockcarver/frodo-lib'; + +import { printError } from '../utils/Console'; + +const { saveJsonToFile, getFilePath, saveTextToFile } = frodo.utils; +const { readCustomNode, readCustomNodes } = frodo.authn.node; + +/** + * Export all custom nodes to 'custom-nodes/nodes' directory. + * Each custom node will be exported as a JSON file with a reference to its script file. + * The script content will be saved in a separate .js file. + * @param {string} name Optional display name of a custom node to export. If not provided, all custom nodes will be exported. + * @returns {Promise} True if export was successful + */ +export async function configManagerExportCustomNodes( + name?: string +): Promise { + try { + let customNodes; + if (name) { + const customNode = await readCustomNode(undefined, name); + customNodes = [customNode]; + } else { + customNodes = await readCustomNodes(); + } + + for (const node of customNodes) { + const nodeDir = getFilePath( + `custom-nodes/nodes/${node.displayName}/`, + true + ); + const scriptFileName = `${node.displayName}.js`; + const jsonFileName = `${node.displayName}.json`; + + saveTextToFile(`${node.script}`, nodeDir + scriptFileName); + node.script = { file: scriptFileName }; + + const filePath = nodeDir + jsonFileName; + saveJsonToFile(node, filePath, false); + } + + return true; + } catch (error) { + printError(error); + return false; + } +} diff --git a/test/client_cli/en/__snapshots__/config-manager-pull-custom-nodes.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-pull-custom-nodes.test.js.snap new file mode 100644 index 000000000..6c25f6123 --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-pull-custom-nodes.test.js.snap @@ -0,0 +1,30 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config-manager pull custom-nodes' should be expected english 1`] = ` +"Usage: frodo config-manager pull custom-nodes [options] [host] [realm] [username] [password] + +[Experimental] Export custom nodes. + +Arguments: + host AM base URL, e.g.: + https://cdk.iam.example.com/am. To use a + connection profile, just specify a unique + substring or alias. + realm Realm. Specify realm as '/' for the root realm or + 'realm' or '/parent/child' otherwise. (default: + "alpha" for Identity Cloud tenants, "/" + otherwise.) + username Username to login with. Must be an admin user + with appropriate rights to manage authentication + journeys/trees. + password Password. + +Options: + -n, --node-name Custom node display name. If specified, only one + custom node is exported. + -h, --help Help + -hh, --help-more Help with all options. + -hhh, --help-all Help with all options, environment variables, and + usage examples. +" +`; diff --git a/test/client_cli/en/config-manager-pull-custom-nodes.test.js b/test/client_cli/en/config-manager-pull-custom-nodes.test.js new file mode 100644 index 000000000..a9f4fdaaa --- /dev/null +++ b/test/client_cli/en/config-manager-pull-custom-nodes.test.js @@ -0,0 +1,10 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager pull custom-nodes --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config-manager pull custom-nodes' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); \ No newline at end of file diff --git a/test/e2e/__snapshots__/config-manager-pull-custom-nodes.e2e.test.js.snap b/test/e2e/__snapshots__/config-manager-pull-custom-nodes.e2e.test.js.snap new file mode 100644 index 000000000..612368810 --- /dev/null +++ b/test/e2e/__snapshots__/config-manager-pull-custom-nodes.e2e.test.js.snap @@ -0,0 +1,1668 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style. 1`] = `0`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style. 2`] = `""`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/ALU/ALU.js 1`] = ` +"var SCRIPT_OUTCOMES = { + SUCCESS: 'Success' +}; + +var OPERATORS = { + ADD: "ADD", + SUBTRACT: "SUBTRACT", + MULTIPLY: "MULTIPLY", + DIVIDE: "DIVIDE" +} + +function main() { + var a = Number(properties.a); + var b = Number(properties.b); + switch (properties.operator) { + case OPERATORS.ADD: + nodeState.putShared("z", a + b); + break; + case OPERATORS.SUBTRACT: + nodeState.putShared("z", a - b); + break; + case OPERATORS.MULTIPLY: + nodeState.putShared("z", a * b); + break; + case OPERATORS.DIVIDE: + if (b == 0) throw new Error("Cannot divide by 0"); + nodeState.putShared("z", a / b); + break; + default: throw new Error("Unknown operator."); + } + action.goTo(SCRIPT_OUTCOMES.SUCCESS); +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/ALU/ALU.json 1`] = ` +{ + "_id": "c6063fb2f5dc42dd9772bedc93898bd8-1", + "description": "Simple ALU that performs basic binary math operations. Expects an "x" and "y" value on the shared state, and will produce a new "z" value on the shared state as output.", + "displayName": "ALU", + "errorOutcome": true, + "inputs": [ + "x", + "y", + ], + "outcomes": [ + "Success", + ], + "outputs": [ + "z", + ], + "properties": { + "operator": { + "defaultValue": "ADD", + "description": "The operation to perform.", + "multivalued": false, + "options": { + "ADD": "+", + "DIVIDE": "/", + "MULTIPLY": "*", + "SUBTRACT": "-", + }, + "required": true, + "title": "Operator", + "type": "STRING", + }, + }, + "script": { + "file": "ALU.js", + }, + "serviceName": "c6063fb2f5dc42dd9772bedc93898bd8", + "tags": [ + "math", + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Display Callback/Display Callback.js 1`] = ` +"var SCRIPT_OUTCOMES = { + OUTCOME: 'outcome' +}; + +var CALLBACKS = { + BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: "BOOLEAN_ATTRIBUTE_INPUT_CALLBACK", + CHOICE_CALLBACK: "CHOICE_CALLBACK", + CONFIRMATION_CALLBACK: "CONFIRMATION_CALLBACK", + CONSENT_MAPPING_CALLBACK: "CONSENT_MAPPING_CALLBACK", + DEVICE_PROFILE_CALLBACK: "DEVICE_PROFILE_CALLBACK", + HIDDEN_VALUE_CALLBACK: "HIDDEN_VALUE_CALLBACK", + HTTP_CALLBACK: "HTTP_CALLBACK", + IDP_CALLBACK: "IDP_CALLBACK", + KBA_CREATE_CALLBACK: "KBA_CREATE_CALLBACK", + LANGUAGE_CALLBACK: "LANGUAGE_CALLBACK", + METADATA_CALLBACK: "METADATA_CALLBACK", + NAME_CALLBACK: "NAME_CALLBACK", + NUMBER_ATTRIBUTE_INPUT_CALLBACK: "NUMBER_ATTRIBUTE_INPUT_CALLBACK", + PASSWORD_CALLBACK: "PASSWORD_CALLBACK", + POLLING_WAIT_CALLBACK: "POLLING_WAIT_CALLBACK", + REDIRECT_CALLBACK: "REDIRECT_CALLBACK", + SCRIPT_TEXT_OUTPUT_CALLBACK: "SCRIPT_TEXT_OUTPUT_CALLBACK", + SELECT_IDP_CALLBACK: "SELECT_IDP_CALLBACK", + STRING_ATTRIBUTE_INPUT_CALLBACK: "STRING_ATTRIBUTE_INPUT_CALLBACK", + SUSPENDED_TEXT_OUTPUT_CALLBACK: "SUSPENDED_TEXT_OUTPUT_CALLBACK", + TERMS_AND_CONDITIONS_CALLBACK: "TERMS_AND_CONDITIONS_CALLBACK", + TEXT_INPUT_CALLBACK: "TEXT_INPUT_CALLBACK", + TEXT_OUTPUT_CALLBACK: "TEXT_OUTPUT_CALLBACK", + VALIDATED_PASSWORD_CALLBACK: "VALIDATED_PASSWORD_CALLBACK", + VALIDATED_USERNAME_CALLBACK: "VALIDATED_USERNAME_CALLBACK", + X509_CERTIFICATE_CALLBACK: "X509_CERTIFICATE_CALLBACK" +} + +function isStringPresent(value) { + return value; +} + +function getString(value) { + return value || ''; +} + +function isArrayPresent(value) { + return value; +} + +function getArray(value) { + return value ? JSON.parse(value) : []; +} + +function isObjectPresent(value) { + return value; +} + +function getObject(value) { + return value ? JSON.parse(value) : {}; +} + +function isIntPresent(value) { + return value; +} + +function getInt(value) { + return value ? parseInt(value) : 0; +} + +function isDoublePresent(value) { + return value; +} + +function getDouble(value) { + return value ? parseFloat(value) : 0.0; +} + +function isBooleanPresent(value) { + return value; +} + +function getBoolean(value) { + return value ? value.toLowerCase() === 'true' : false; +} + +function setProperty(value) { + if (properties.sharedProperty) nodeState.putShared(properties.sharedProperty, value); + if (properties.transientProperty) nodeState.putTransient(properties.transientProperty, value); + if (properties.objectSharedProperty) { + var attributes = {}; + attributes[properties.objectSharedProperty] = value; + nodeState.mergeShared({ + objectAttributes: attributes + }); + } + if (properties.objectTransientProperty) { + var attributes = {}; + attributes[properties.objectTransientProperty] = value; + nodeState.mergeTransient({ + objectAttributes: attributes + }); + } +} + +function booleanAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getBoolean(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required); + } +} + +function choiceCallback() { + var prompt = getString(properties.options.prompt); + var choices = getArray(properties.options.choices); + var defaultChoice = getInt(properties.options.defaultChoice); + var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed); + callbacksBuilder.choiceCallback(prompt, choices, defaultChoice, multipleSelectionsAllowed); +} + +function confirmationCallback() { + var prompt = getString(properties.options.prompt); + var messageType = getInt(properties.options.messageType); + var options = getArray(properties.options.options); + var optionType = getInt(properties.options.optionType); + var defaultOption = getInt(properties.options.defaultOption); + if (isStringPresent(properties.options.prompt)) { + if (isIntPresent(properties.options.optionType)) { + callbacksBuilder.confirmationCallback(prompt, messageType, optionType, defaultOption); + } else { + callbacksBuilder.confirmationCallback(prompt, messageType, options, defaultOption); + } + } else { + if (isIntPresent(properties.options.optionType)) { + callbacksBuilder.confirmationCallback(messageType, optionType, defaultOption); + } else { + callbacksBuilder.confirmationCallback(messageType, options, defaultOption); + } + } +} + +function consentMappingCallback() { + var config = getObject(properties.options.config); + var message = getString(properties.options.message); + var isRequired = getBoolean(properties.options.isRequired); + var name = getString(properties.options.name); + var displayName = getString(properties.options.displayName); + var icon = getString(properties.options.icon); + var accessLevel = getString(properties.options.accessLevel); + var titles = getArray(properties.options.titles); + if (isObjectPresent(properties.options.prompt)) { + callbacksBuilder.consentMappingCallback(config, message, isRequired); + } else { + callbacksBuilder.consentMappingCallback(name, displayName, icon, accessLevel, titles, message, isRequired); + } +} + +function deviceProfileCallback() { + var metadata = getBoolean(properties.options.metadata); + var location = getBoolean(properties.options.location); + var message = getString(properties.options.message); + callbacksBuilder.deviceProfileCallback(metadata, location, message); +} + +function hiddenValueCallback() { + var id = getString(properties.options.id); + var value = getString(properties.options.value); + callbacksBuilder.hiddenValueCallback(id, value); +} + +function httpCallback() { + var authorizationHeader = getString(properties.options.authorizationHeader); + var negotiationHeader = getString(properties.options.negotiationHeader); + var authRHeader = getString(properties.options.authRHeader); + var negoName = getString(properties.options.negoName); + var negoValue = getString(properties.options.negoValue); + if (isStringPresent(properties.options.authorizationHeader) || isStringPresent(properties.options.negotiationHeader)) { + var errorCode = getString(properties.options.errorCode); + callbacksBuilder.httpCallback(authorizationHeader, negotiationHeader, errorCode); + } else { + var errorCode = getInt(properties.options.errorCode); + callbacksBuilder.httpCallback(authRHeader, negoName, negoValue, errorCode); + } +} + +function idPCallback() { + var provider = getString(properties.options.provider); + var clientId = getString(properties.options.clientId); + var redirectUri = getString(properties.options.redirectUri); + var scope = getArray(properties.options.scope); + var nonce = getString(properties.options.nonce); + var request = getString(properties.options.request); + var requestUri = getString(properties.options.requestUri); + var acrValues = getArray(properties.options.acrValues); + var requestNativeAppForUserInfo = getBoolean(properties.options.requestNativeAppForUserInfo); + var token = getString(properties.options.token); + var tokenType = getString(properties.options.tokenType); + if (isStringPresent(properties.options.token) || isStringPresent(properties.options.tokenType)) { + callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo, token, tokenType); + } else { + callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo); + } +} + +function kbaCreateCallback() { + var prompt = getString(properties.options.prompt); + var predefinedQuestions = getArray(properties.options.predefinedQuestions); + var allowUserDefinedQuestions = getBoolean(properties.options.allowUserDefinedQuestions); + callbacksBuilder.kbaCreateCallback(prompt, predefinedQuestions, allowUserDefinedQuestions); +} + +function languageCallback() { + var language = getString(properties.options.language); + var country = getString(properties.options.country); + callbacksBuilder.languageCallback(language, country); +} + +function metadataCallback() { + var outputValue = getObject(properties.options.outputValue); + callbacksBuilder.metadataCallback(outputValue); +} + +function nameCallback() { + var prompt = getString(properties.options.prompt); + var defaultName = getString(properties.options.defaultName); + if (isStringPresent(properties.options.defaultName)) { + callbacksBuilder.nameCallback(prompt, defaultName); + } else { + callbacksBuilder.nameCallback(prompt); + } +} + +function numberAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getDouble(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required); + } +} + +function passwordCallback() { + var prompt = getString(properties.options.prompt); + var echoOn = getBoolean(properties.options.echoOn); + callbacksBuilder.passwordCallback(prompt, echoOn); +} + +function pollingWaitCallback() { + var waitTime = getString(properties.options.waitTime); + var message = getString(properties.options.message); + callbacksBuilder.pollingWaitCallback(waitTime, message); +} + +function redirectCallback() { + throw new Error('Not Implemented'); +} + +function scriptTextOutputCallback() { + var message = getString(properties.options.message); + callbacksBuilder.scriptTextOutputCallback(message); +} + +function selectIdPCallback() { + var providers = getObject(properties.options.providers); + callbacksBuilder.selectIdPCallback(providers); +} + +function stringAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getString(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required); + } +} + +function suspendedTextOutputCallback() { + var messageType = getInt(properties.options.messageType); + var message = getString(properties.options.message); + callbacksBuilder.suspendedTextOutputCallback(messageType, message); +} + +function termsAndConditionsCallback() { + var version = getString(properties.options.version); + var terms = getString(properties.options.terms); + var createDate = getString(properties.options.createDate); + callbacksBuilder.termsAndConditionsCallback(version, terms, createDate); +} + +function textInputCallback() { + var prompt = getString(properties.options.prompt); + var defaultText = getString(properties.options.defaultText); + if (isStringPresent(properties.options.defaultText)) { + callbacksBuilder.textInputCallback(prompt, defaultText); + } else { + callbacksBuilder.textInputCallback(prompt); + } +} + +function textOutputCallback() { + var messageType = getString(properties.options.messageType); + var message = getString(properties.options.message); + callbacksBuilder.textOutputCallback(messageType, message); +} + +function validatedPasswordCallback() { + var prompt = getString(properties.options.prompt); + var echoOn = getBoolean(properties.options.echoOn); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isArrayPresent(properties.options.failedPolicies)) { + callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly); + } +} + +function validatedUsernameCallback() { + var prompt = getString(properties.options.prompt); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isArrayPresent(properties.options.failedPolicies)) { + callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly); + } +} + +function x509CertificateCallback() { + throw new Error('Not Implemented'); +} + +function getBooleanAttributeInputCallback() { + setProperty(callbacks.getBooleanAttributeInputCallbacks().get(0)); +} + +function getChoiceCallback() { + var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed); + var selections = callbacks.getChoiceCallbacks().get(0); + setProperty(multipleSelectionsAllowed ? selections : selections[0]); +} + +function getConfirmationCallback() { + setProperty(callbacks.getConfirmationCallbacks().get(0)); +} + +function getConsentMappingCallback() { + setProperty(callbacks.getConsentMappingCallbacks().get(0)); +} + +function getDeviceProfileCallback() { + setProperty(callbacks.getDeviceProfileCallbacks().get(0)); +} + +function getHiddenValueCallback() { + var id = getString(properties.options.id); + setProperty(callbacks.getHiddenValueCallbacks().get(id)); +} + +function getHttpCallback() { + setProperty(callbacks.getHttpCallbacks().get(0)); +} + +function getIdPCallback() { + setProperty(callbacks.getIdpCallbacks().get(0)); +} + +function getKbaCreateCallback() { + setProperty(callbacks.getKbaCreateCallbacks().get(0)); +} + +function getLanguageCallback() { + setProperty(callbacks.getLanguageCallbacks().get(0)); +} + +function getNameCallback() { + setProperty(callbacks.getNameCallbacks().get(0)); +} + +function getNumberAttributeInputCallback() { + setProperty(callbacks.getNumberAttributeInputCallbacks().get(0)); +} + +function getPasswordCallback() { + setProperty(callbacks.getPasswordCallbacks().get(0)); +} + +function getSelectIdPCallback() { + setProperty(callbacks.getSelectIdPCallbacks().get(0)); +} + +function getStringAttributeInputCallback() { + setProperty(callbacks.getStringAttributeInputCallbacks().get(0)); +} + +function getTermsAndConditionsCallback() { + setProperty(callbacks.getTermsAndConditionsCallbacks().get(0)); +} + +function getTextInputCallback() { + setProperty(callbacks.getTextInputCallbacks().get(0)); +} + +function getValidatedPasswordCallback() { + setProperty(callbacks.getValidatedPasswordCallbacks().get(0)); +} + +function getValidatedUsernameCallback() { + setProperty(callbacks.getValidatedUsernameCallbacks().get(0)); +} + +function getX509CertificateCallback() { + setProperty(callbacks.getX509CertificateCallbacks().get(0)); +} + +function main() { + if (!callbacks.isEmpty()) { + switch (properties.callback) { + case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: getBooleanAttributeInputCallback(); break; + case CALLBACKS.CHOICE_CALLBACK: getChoiceCallback(); break; + case CALLBACKS.CONFIRMATION_CALLBACK: getConfirmationCallback(); break; + case CALLBACKS.CONSENT_MAPPING_CALLBACK: getConsentMappingCallback(); break; + case CALLBACKS.DEVICE_PROFILE_CALLBACK: getDeviceProfileCallback(); break; + case CALLBACKS.HIDDEN_VALUE_CALLBACK: getHiddenValueCallback(); break; + case CALLBACKS.HTTP_CALLBACK: getHttpCallback(); break; + case CALLBACKS.IDP_CALLBACK: getIdPCallback(); break; + case CALLBACKS.KBA_CREATE_CALLBACK: getKbaCreateCallback(); break; + case CALLBACKS.LANGUAGE_CALLBACK: getLanguageCallback(); break; + case CALLBACKS.NAME_CALLBACK: getNameCallback(); break; + case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: getNumberAttributeInputCallback(); break; + case CALLBACKS.PASSWORD_CALLBACK: getPasswordCallback(); break; + case CALLBACKS.SELECT_IDP_CALLBACK: getSelectIdPCallback(); break; + case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: getStringAttributeInputCallback(); break; + case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: getTermsAndConditionsCallback(); break; + case CALLBACKS.TEXT_INPUT_CALLBACK: getTextInputCallback(); break; + case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: getValidatedPasswordCallback(); break; + case CALLBACKS.VALIDATED_USERNAME_CALLBACK: getValidatedUsernameCallback(); break; + case CALLBACKS.X509_CERTIFICATE_CALLBACK: getX509CertificateCallback(); break; + default: break; + } + action.goTo(SCRIPT_OUTCOMES.OUTCOME); + return; + } + + switch (properties.callback) { + case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: booleanAttributeInputCallback(); break; + case CALLBACKS.CHOICE_CALLBACK: choiceCallback(); break; + case CALLBACKS.CONFIRMATION_CALLBACK: confirmationCallback(); break; + case CALLBACKS.CONSENT_MAPPING_CALLBACK: consentMappingCallback(); break; + case CALLBACKS.DEVICE_PROFILE_CALLBACK: deviceProfileCallback(); break; + case CALLBACKS.HIDDEN_VALUE_CALLBACK: hiddenValueCallback(); break; + case CALLBACKS.HTTP_CALLBACK: httpCallback(); break; + case CALLBACKS.IDP_CALLBACK: idPCallback(); break; + case CALLBACKS.KBA_CREATE_CALLBACK: kbaCreateCallback(); break; + case CALLBACKS.LANGUAGE_CALLBACK: languageCallback(); break; + case CALLBACKS.METADATA_CALLBACK: metadataCallback(); break; + case CALLBACKS.NAME_CALLBACK: nameCallback(); break; + case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: numberAttributeInputCallback(); break; + case CALLBACKS.PASSWORD_CALLBACK: passwordCallback(); break; + case CALLBACKS.POLLING_WAIT_CALLBACK: pollingWaitCallback(); break; + case CALLBACKS.REDIRECT_CALLBACK: redirectCallback(); break; + case CALLBACKS.SCRIPT_TEXT_OUTPUT_CALLBACK: scriptTextOutputCallback(); break; + case CALLBACKS.SELECT_IDP_CALLBACK: selectIdPCallback(); break; + case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: stringAttributeInputCallback(); break; + case CALLBACKS.SUSPENDED_TEXT_OUTPUT_CALLBACK: suspendedTextOutputCallback(); break; + case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: termsAndConditionsCallback(); break; + case CALLBACKS.TEXT_INPUT_CALLBACK: textInputCallback(); break; + case CALLBACKS.TEXT_OUTPUT_CALLBACK: textOutputCallback(); break; + case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: validatedPasswordCallback(); break; + case CALLBACKS.VALIDATED_USERNAME_CALLBACK: validatedUsernameCallback(); break; + case CALLBACKS.X509_CERTIFICATE_CALLBACK: x509CertificateCallback(); break; + default: throw new Error('Unknown Callback'); // Should never reach this case + } +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Display Callback/Display Callback.json 1`] = ` +{ + "_id": "ef81b1a52c914710b3388caebfe7233a-1", + "description": "Displays custom callback to the page", + "displayName": "Display Callback", + "errorOutcome": false, + "inputs": [], + "outcomes": [ + "outcome", + ], + "outputs": [], + "properties": { + "callback": { + "description": "The callback to display", + "multivalued": false, + "options": { + "BOOLEAN_ATTRIBUTE_INPUT_CALLBACK": "booleanAttributeInputCallback", + "CHOICE_CALLBACK": "choiceCallback", + "CONFIRMATION_CALLBACK": "confirmationCallback", + "CONSENT_MAPPING_CALLBACK": "consentMappingCallback", + "DEVICE_PROFILE_CALLBACK": "deviceProfileCallback", + "HIDDEN_VALUE_CALLBACK": "hiddenValueCallback", + "HTTP_CALLBACK": "httpCallback", + "IDP_CALLBACK": "idPCallback", + "KBA_CREATE_CALLBACK": "kbaCreateCallback", + "LANGUAGE_CALLBACK": "languageCallback", + "METADATA_CALLBACK": "metadataCallback", + "NAME_CALLBACK": "nameCallback", + "NUMBER_ATTRIBUTE_INPUT_CALLBACK": "numberAttributeInputCallback", + "PASSWORD_CALLBACK": "passwordCallback", + "POLLING_WAIT_CALLBACK": "pollingWaitCallback", + "REDIRECT_CALLBACK": "redirectCallback", + "SCRIPT_TEXT_OUTPUT_CALLBACK": "scriptTextOutputCallback", + "SELECT_IDP_CALLBACK": "selectIdPCallback", + "STRING_ATTRIBUTE_INPUT_CALLBACK": "stringAttributeInputCallback", + "SUSPENDED_TEXT_OUTPUT_CALLBACK": "suspendedTextOutputCallback", + "TERMS_AND_CONDITIONS_CALLBACK": "termsAndConditionsCallback", + "TEXT_INPUT_CALLBACK": "textInputCallback", + "TEXT_OUTPUT_CALLBACK": "textOutputCallback", + "VALIDATED_PASSWORD_CALLBACK": "validatedPasswordCallback", + "VALIDATED_USERNAME_CALLBACK": "validatedUsernameCallback", + "X509_CERTIFICATE_CALLBACK": "x509CertificateCallback", + }, + "required": true, + "title": "Callback", + "type": "STRING", + }, + "objectSharedProperty": { + "description": "The objectAttributes property on the shared state to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Object Attributes Shared Property", + "type": "STRING", + }, + "objectTransientProperty": { + "description": "The objectAttributes property on the transient state to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Object Attributes Transient Property", + "type": "STRING", + }, + "options": { + "description": "The options containing the parameters for the callback (see documentation for possible parameters: https://docs.pingidentity.com/pingoneaic/latest/am-scripting/scripting-api-node.html#scripting-api-node-callbacks). + +For example, for textOutputCallback, the options could be: { messageType: 0, message: "Hello World!" }. + +Note that for required parameters that are not specified in the options will use default values based on the type of the parameter ("" for Strings, [] for Arrays, {} for Objects, 0 for Ints, 0.0 for Doubles, and false for Booleans).", + "multivalued": false, + "required": true, + "title": "Options", + "type": "OBJECT", + }, + "sharedProperty": { + "description": "The shared state property to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Shared State Property", + "type": "STRING", + }, + "transientProperty": { + "description": "The transient state property to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Transient State Property", + "type": "STRING", + }, + }, + "script": { + "file": "Display Callback.js", + }, + "serviceName": "ef81b1a52c914710b3388caebfe7233a", + "tags": [ + "callback", + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Display State/Display State.js 1`] = ` +"var SCRIPT_OUTCOMES = { + OUTCOME: "outcome" +}; + +function main() { + if (!callbacks.isEmpty()) { + action.goTo(SCRIPT_OUTCOMES.OUTCOME); + return; + } + var keySet = nodeState.keys(); // Java Set + var keys = Array.from(keySet); // Make it into JavaScript array + debugState = {}; + for (var i in keys) { + var k = new String(keys[i]); + var item = nodeState.get(k); + if (typeof item === "object") { + debugState[k] = nodeState.getObject(k); + } else { + debugState[k] = nodeState.get(k); + } + } + if (properties.displayFormat === "JSON") { + callbacksBuilder.textOutputCallback(0, \`
\${JSON.stringify(debugState, null, 2)}
\`); + return; + } + callbacksBuilder.textOutputCallback(0, \`\${Array.from(Object.keys(debugState).map(k => \`\`))}
KeyValue
\${k}
\${debugState[k]}
\`); +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Display State/Display State.json 1`] = ` +{ + "_id": "8ab9f1aad4b4460a9c45d15fb148e221-1", + "description": "Debug node that displays the shared and transient state of the journey for debugging purposes.", + "displayName": "Display State", + "errorOutcome": false, + "inputs": [], + "outcomes": [ + "outcome", + ], + "outputs": [], + "properties": { + "displayFormat": { + "defaultValue": "TABLE", + "description": "The format in which to display the states.", + "multivalued": false, + "options": { + "JSON": "Raw JSON", + "TABLE": "HTML Table", + }, + "required": true, + "title": "Display Format", + "type": "STRING", + }, + }, + "script": { + "file": "Display State.js", + }, + "serviceName": "8ab9f1aad4b4460a9c45d15fb148e221", + "tags": [ + "debug", + "testing", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Generate JWT/Generate JWT.js 1`] = ` +"var aud = properties.audience; +var iss = properties.issuer; +var validity = properties.validity; +var esv = properties.signingkey; + +var signingkey = systemEnv.getProperty(esv); + +var username = nodeState.get("username"); + +var data = { + jwtType:"SIGNED", + jwsAlgorithm: "HS256", + issuer: iss, + subject: username, + audience: aud, + type: "JWT", + validityMinutes: validity, + signingKey: signingkey +}; + +var jwt = jwtAssertion.generateJwt(data); + +if (jwt !== null && jwt.length > 0) { + nodeState.putShared("assertionJwt" , jwt); + action.goTo("True"); +} else { + action.goTo("False"); +} +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Generate JWT/Generate JWT.json 1`] = ` +{ + "_id": "e5ad0110c8ee4dafaae983003cd05d4a-1", + "description": "Generate a signed JWT using the HMAC SHA-256 algorithm.", + "displayName": "Generate JWT", + "errorOutcome": true, + "inputs": [], + "outcomes": [ + "True", + "False", + ], + "outputs": [], + "properties": { + "audience": { + "description": "The audience (aud) claim", + "multivalued": false, + "required": true, + "title": "Audience", + "type": "STRING", + }, + "issuer": { + "description": "The issuer (iss) claim", + "multivalued": false, + "required": true, + "title": "Issuer", + "type": "STRING", + }, + "signingkey": { + "defaultValue": "esv.signing.key", + "description": "The secret label for the HMAC signing key", + "multivalued": false, + "required": true, + "title": "HMAC Signing Key", + "type": "STRING", + }, + "validity": { + "defaultValue": 5, + "description": "", + "multivalued": false, + "required": true, + "title": "Validity (minutes)", + "type": "NUMBER", + }, + }, + "script": { + "file": "Generate JWT.js", + }, + "serviceName": "e5ad0110c8ee4dafaae983003cd05d4a", + "tags": [ + "Utilities", + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Has Session AM/Has Session AM.js 1`] = ` +"var SCRIPT_OUTCOMES = { + TRUE: 'True', + FALSE: 'False' +} + +function main() { + action.goTo(typeof existingSession === "undefined" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE); +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Has Session AM/Has Session AM.json 1`] = ` +{ + "_id": "session-1", + "description": "Checks if the user has a current session.", + "displayName": "Has Session AM", + "errorOutcome": false, + "inputs": [], + "outcomes": [ + "True", + "False", + ], + "outputs": [], + "properties": {}, + "script": { + "file": "Has Session AM.js", + }, + "serviceName": "session", + "tags": [ + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Has Session/Has Session.js 1`] = ` +"var SCRIPT_OUTCOMES = { + TRUE: 'True', + FALSE: 'False' +} + +function main() { + action.goTo(typeof existingSession === "undefined" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE); +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Has Session/Has Session.json 1`] = ` +{ + "_id": "c605506774a848f7877b4d17a453bd39-1", + "description": "Checks if the user has a current session.", + "displayName": "Has Session", + "errorOutcome": false, + "inputs": [], + "outcomes": [ + "True", + "False", + ], + "outputs": [], + "properties": {}, + "script": { + "file": "Has Session.js", + }, + "serviceName": "c605506774a848f7877b4d17a453bd39", + "tags": [ + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Vector ALU/Vector ALU.js 1`] = ` +"var SCRIPT_OUTCOMES = { + SUCCESS: 'Success' +}; + +var OPERATORS = { + ADD: "ADD", + SUBTRACT: "SUBTRACT", + DOT: "DOT", + CROSS: "CROSS" +} + +function add(a, b) { + return a.map((v, i) => v + b[i]); +} + +function subtract(a, b) { + return a.map((v, i) => v - b[i]); +} + +function dot(a, b) { + return a.reduce((sum, v, i) => sum + v * b[i], 0); +} + +function cross(a, b) { + return [ + a[1] * b[2] - a[2] * b[1], + a[2] * b[0] - a[0] * b[2], + a[0] * b[1] - a[1] * b[0] + ]; +} + +function main() { + if (properties.a.length !== properties.b.length) throw new Error("Vectors not the same dimension."); + switch (properties.operator) { + case OPERATORS.ADD: + nodeState.putShared("c", add(properties.a, properties.b)); + break; + case OPERATORS.SUBTRACT: + nodeState.putShared("c", subtract(properties.a, properties.b)); + break; + case OPERATORS.DOT: + nodeState.putShared("c", dot(properties.a, properties.b)); + break; + case OPERATORS.CROSS: + if (properties.a.length !== 3) throw new Error("Vectors not dimension 3 for cross product"); + nodeState.putShared("c", cross(properties.a, properties.b)); + break; + default: throw new Error("Unknown operator."); + } + action.goTo(SCRIPT_OUTCOMES.SUCCESS); +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.: configManagerPullCustomNodesDir0/custom-nodes/nodes/Vector ALU/Vector ALU.json 1`] = ` +{ + "_id": "c15e2efb3deb4d4ea338c74a6440b69f-1", + "description": "Simple ALU that performs basic binary vector math operations. Outputs the result onto the shared state with key "c".", + "displayName": "Vector ALU", + "errorOutcome": true, + "inputs": [], + "outcomes": [ + "Success", + ], + "outputs": [ + "c", + ], + "properties": { + "a": { + "defaultValue": [ + 1, + 2, + 3, + ], + "description": "Left vector operand", + "multivalued": true, + "required": true, + "title": "A", + "type": "NUMBER", + }, + "b": { + "defaultValue": [ + 4, + 5, + 6, + ], + "description": "Right vector operand", + "multivalued": true, + "required": true, + "title": "B", + "type": "NUMBER", + }, + "operator": { + "defaultValue": "DOT", + "description": "The binary operation to perform on the vectors.", + "multivalued": false, + "options": { + "ADD": "+", + "CROSS": "X", + "DOT": ".", + "SUBTRACT": "-", + }, + "required": true, + "title": "Operator", + "type": "STRING", + }, + }, + "script": { + "file": "Vector ALU.js", + }, + "serviceName": "c15e2efb3deb4d4ea338c74a6440b69f", + "tags": [ + "math", + "vector", + "utilities", + ], +} +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops": should export custom node named: Display Callback 1`] = `0`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops": should export custom node named: Display Callback 2`] = `""`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops": should export custom node named: Display Callback: configManagerPullCustomNodesDir1/custom-nodes/nodes/Display Callback/Display Callback.js 1`] = ` +"var SCRIPT_OUTCOMES = { + OUTCOME: 'outcome' +}; + +var CALLBACKS = { + BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: "BOOLEAN_ATTRIBUTE_INPUT_CALLBACK", + CHOICE_CALLBACK: "CHOICE_CALLBACK", + CONFIRMATION_CALLBACK: "CONFIRMATION_CALLBACK", + CONSENT_MAPPING_CALLBACK: "CONSENT_MAPPING_CALLBACK", + DEVICE_PROFILE_CALLBACK: "DEVICE_PROFILE_CALLBACK", + HIDDEN_VALUE_CALLBACK: "HIDDEN_VALUE_CALLBACK", + HTTP_CALLBACK: "HTTP_CALLBACK", + IDP_CALLBACK: "IDP_CALLBACK", + KBA_CREATE_CALLBACK: "KBA_CREATE_CALLBACK", + LANGUAGE_CALLBACK: "LANGUAGE_CALLBACK", + METADATA_CALLBACK: "METADATA_CALLBACK", + NAME_CALLBACK: "NAME_CALLBACK", + NUMBER_ATTRIBUTE_INPUT_CALLBACK: "NUMBER_ATTRIBUTE_INPUT_CALLBACK", + PASSWORD_CALLBACK: "PASSWORD_CALLBACK", + POLLING_WAIT_CALLBACK: "POLLING_WAIT_CALLBACK", + REDIRECT_CALLBACK: "REDIRECT_CALLBACK", + SCRIPT_TEXT_OUTPUT_CALLBACK: "SCRIPT_TEXT_OUTPUT_CALLBACK", + SELECT_IDP_CALLBACK: "SELECT_IDP_CALLBACK", + STRING_ATTRIBUTE_INPUT_CALLBACK: "STRING_ATTRIBUTE_INPUT_CALLBACK", + SUSPENDED_TEXT_OUTPUT_CALLBACK: "SUSPENDED_TEXT_OUTPUT_CALLBACK", + TERMS_AND_CONDITIONS_CALLBACK: "TERMS_AND_CONDITIONS_CALLBACK", + TEXT_INPUT_CALLBACK: "TEXT_INPUT_CALLBACK", + TEXT_OUTPUT_CALLBACK: "TEXT_OUTPUT_CALLBACK", + VALIDATED_PASSWORD_CALLBACK: "VALIDATED_PASSWORD_CALLBACK", + VALIDATED_USERNAME_CALLBACK: "VALIDATED_USERNAME_CALLBACK", + X509_CERTIFICATE_CALLBACK: "X509_CERTIFICATE_CALLBACK" +} + +function isStringPresent(value) { + return value; +} + +function getString(value) { + return value || ''; +} + +function isArrayPresent(value) { + return value; +} + +function getArray(value) { + return value ? JSON.parse(value) : []; +} + +function isObjectPresent(value) { + return value; +} + +function getObject(value) { + return value ? JSON.parse(value) : {}; +} + +function isIntPresent(value) { + return value; +} + +function getInt(value) { + return value ? parseInt(value) : 0; +} + +function isDoublePresent(value) { + return value; +} + +function getDouble(value) { + return value ? parseFloat(value) : 0.0; +} + +function isBooleanPresent(value) { + return value; +} + +function getBoolean(value) { + return value ? value.toLowerCase() === 'true' : false; +} + +function setProperty(value) { + if (properties.sharedProperty) nodeState.putShared(properties.sharedProperty, value); + if (properties.transientProperty) nodeState.putTransient(properties.transientProperty, value); + if (properties.objectSharedProperty) { + var attributes = {}; + attributes[properties.objectSharedProperty] = value; + nodeState.mergeShared({ + objectAttributes: attributes + }); + } + if (properties.objectTransientProperty) { + var attributes = {}; + attributes[properties.objectTransientProperty] = value; + nodeState.mergeTransient({ + objectAttributes: attributes + }); + } +} + +function booleanAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getBoolean(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required); + } +} + +function choiceCallback() { + var prompt = getString(properties.options.prompt); + var choices = getArray(properties.options.choices); + var defaultChoice = getInt(properties.options.defaultChoice); + var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed); + callbacksBuilder.choiceCallback(prompt, choices, defaultChoice, multipleSelectionsAllowed); +} + +function confirmationCallback() { + var prompt = getString(properties.options.prompt); + var messageType = getInt(properties.options.messageType); + var options = getArray(properties.options.options); + var optionType = getInt(properties.options.optionType); + var defaultOption = getInt(properties.options.defaultOption); + if (isStringPresent(properties.options.prompt)) { + if (isIntPresent(properties.options.optionType)) { + callbacksBuilder.confirmationCallback(prompt, messageType, optionType, defaultOption); + } else { + callbacksBuilder.confirmationCallback(prompt, messageType, options, defaultOption); + } + } else { + if (isIntPresent(properties.options.optionType)) { + callbacksBuilder.confirmationCallback(messageType, optionType, defaultOption); + } else { + callbacksBuilder.confirmationCallback(messageType, options, defaultOption); + } + } +} + +function consentMappingCallback() { + var config = getObject(properties.options.config); + var message = getString(properties.options.message); + var isRequired = getBoolean(properties.options.isRequired); + var name = getString(properties.options.name); + var displayName = getString(properties.options.displayName); + var icon = getString(properties.options.icon); + var accessLevel = getString(properties.options.accessLevel); + var titles = getArray(properties.options.titles); + if (isObjectPresent(properties.options.prompt)) { + callbacksBuilder.consentMappingCallback(config, message, isRequired); + } else { + callbacksBuilder.consentMappingCallback(name, displayName, icon, accessLevel, titles, message, isRequired); + } +} + +function deviceProfileCallback() { + var metadata = getBoolean(properties.options.metadata); + var location = getBoolean(properties.options.location); + var message = getString(properties.options.message); + callbacksBuilder.deviceProfileCallback(metadata, location, message); +} + +function hiddenValueCallback() { + var id = getString(properties.options.id); + var value = getString(properties.options.value); + callbacksBuilder.hiddenValueCallback(id, value); +} + +function httpCallback() { + var authorizationHeader = getString(properties.options.authorizationHeader); + var negotiationHeader = getString(properties.options.negotiationHeader); + var authRHeader = getString(properties.options.authRHeader); + var negoName = getString(properties.options.negoName); + var negoValue = getString(properties.options.negoValue); + if (isStringPresent(properties.options.authorizationHeader) || isStringPresent(properties.options.negotiationHeader)) { + var errorCode = getString(properties.options.errorCode); + callbacksBuilder.httpCallback(authorizationHeader, negotiationHeader, errorCode); + } else { + var errorCode = getInt(properties.options.errorCode); + callbacksBuilder.httpCallback(authRHeader, negoName, negoValue, errorCode); + } +} + +function idPCallback() { + var provider = getString(properties.options.provider); + var clientId = getString(properties.options.clientId); + var redirectUri = getString(properties.options.redirectUri); + var scope = getArray(properties.options.scope); + var nonce = getString(properties.options.nonce); + var request = getString(properties.options.request); + var requestUri = getString(properties.options.requestUri); + var acrValues = getArray(properties.options.acrValues); + var requestNativeAppForUserInfo = getBoolean(properties.options.requestNativeAppForUserInfo); + var token = getString(properties.options.token); + var tokenType = getString(properties.options.tokenType); + if (isStringPresent(properties.options.token) || isStringPresent(properties.options.tokenType)) { + callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo, token, tokenType); + } else { + callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo); + } +} + +function kbaCreateCallback() { + var prompt = getString(properties.options.prompt); + var predefinedQuestions = getArray(properties.options.predefinedQuestions); + var allowUserDefinedQuestions = getBoolean(properties.options.allowUserDefinedQuestions); + callbacksBuilder.kbaCreateCallback(prompt, predefinedQuestions, allowUserDefinedQuestions); +} + +function languageCallback() { + var language = getString(properties.options.language); + var country = getString(properties.options.country); + callbacksBuilder.languageCallback(language, country); +} + +function metadataCallback() { + var outputValue = getObject(properties.options.outputValue); + callbacksBuilder.metadataCallback(outputValue); +} + +function nameCallback() { + var prompt = getString(properties.options.prompt); + var defaultName = getString(properties.options.defaultName); + if (isStringPresent(properties.options.defaultName)) { + callbacksBuilder.nameCallback(prompt, defaultName); + } else { + callbacksBuilder.nameCallback(prompt); + } +} + +function numberAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getDouble(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required); + } +} + +function passwordCallback() { + var prompt = getString(properties.options.prompt); + var echoOn = getBoolean(properties.options.echoOn); + callbacksBuilder.passwordCallback(prompt, echoOn); +} + +function pollingWaitCallback() { + var waitTime = getString(properties.options.waitTime); + var message = getString(properties.options.message); + callbacksBuilder.pollingWaitCallback(waitTime, message); +} + +function redirectCallback() { + throw new Error('Not Implemented'); +} + +function scriptTextOutputCallback() { + var message = getString(properties.options.message); + callbacksBuilder.scriptTextOutputCallback(message); +} + +function selectIdPCallback() { + var providers = getObject(properties.options.providers); + callbacksBuilder.selectIdPCallback(providers); +} + +function stringAttributeInputCallback() { + var name = getString(properties.options.name); + var prompt = getString(properties.options.prompt); + var value = getString(properties.options.value); + var required = getBoolean(properties.options.required); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) { + if (isArrayPresent(failedPolicies)) { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly); + } + } else if (isArrayPresent(failedPolicies)) { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, failedPolicies); + } else { + callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required); + } +} + +function suspendedTextOutputCallback() { + var messageType = getInt(properties.options.messageType); + var message = getString(properties.options.message); + callbacksBuilder.suspendedTextOutputCallback(messageType, message); +} + +function termsAndConditionsCallback() { + var version = getString(properties.options.version); + var terms = getString(properties.options.terms); + var createDate = getString(properties.options.createDate); + callbacksBuilder.termsAndConditionsCallback(version, terms, createDate); +} + +function textInputCallback() { + var prompt = getString(properties.options.prompt); + var defaultText = getString(properties.options.defaultText); + if (isStringPresent(properties.options.defaultText)) { + callbacksBuilder.textInputCallback(prompt, defaultText); + } else { + callbacksBuilder.textInputCallback(prompt); + } +} + +function textOutputCallback() { + var messageType = getString(properties.options.messageType); + var message = getString(properties.options.message); + callbacksBuilder.textOutputCallback(messageType, message); +} + +function validatedPasswordCallback() { + var prompt = getString(properties.options.prompt); + var echoOn = getBoolean(properties.options.echoOn); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isArrayPresent(properties.options.failedPolicies)) { + callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly); + } +} + +function validatedUsernameCallback() { + var prompt = getString(properties.options.prompt); + var policies = getObject(properties.options.policies); + var validateOnly = getBoolean(properties.options.validateOnly); + var failedPolicies = getArray(properties.options.failedPolicies); + if (isArrayPresent(properties.options.failedPolicies)) { + callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly, failedPolicies); + } else { + callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly); + } +} + +function x509CertificateCallback() { + throw new Error('Not Implemented'); +} + +function getBooleanAttributeInputCallback() { + setProperty(callbacks.getBooleanAttributeInputCallbacks().get(0)); +} + +function getChoiceCallback() { + var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed); + var selections = callbacks.getChoiceCallbacks().get(0); + setProperty(multipleSelectionsAllowed ? selections : selections[0]); +} + +function getConfirmationCallback() { + setProperty(callbacks.getConfirmationCallbacks().get(0)); +} + +function getConsentMappingCallback() { + setProperty(callbacks.getConsentMappingCallbacks().get(0)); +} + +function getDeviceProfileCallback() { + setProperty(callbacks.getDeviceProfileCallbacks().get(0)); +} + +function getHiddenValueCallback() { + var id = getString(properties.options.id); + setProperty(callbacks.getHiddenValueCallbacks().get(id)); +} + +function getHttpCallback() { + setProperty(callbacks.getHttpCallbacks().get(0)); +} + +function getIdPCallback() { + setProperty(callbacks.getIdpCallbacks().get(0)); +} + +function getKbaCreateCallback() { + setProperty(callbacks.getKbaCreateCallbacks().get(0)); +} + +function getLanguageCallback() { + setProperty(callbacks.getLanguageCallbacks().get(0)); +} + +function getNameCallback() { + setProperty(callbacks.getNameCallbacks().get(0)); +} + +function getNumberAttributeInputCallback() { + setProperty(callbacks.getNumberAttributeInputCallbacks().get(0)); +} + +function getPasswordCallback() { + setProperty(callbacks.getPasswordCallbacks().get(0)); +} + +function getSelectIdPCallback() { + setProperty(callbacks.getSelectIdPCallbacks().get(0)); +} + +function getStringAttributeInputCallback() { + setProperty(callbacks.getStringAttributeInputCallbacks().get(0)); +} + +function getTermsAndConditionsCallback() { + setProperty(callbacks.getTermsAndConditionsCallbacks().get(0)); +} + +function getTextInputCallback() { + setProperty(callbacks.getTextInputCallbacks().get(0)); +} + +function getValidatedPasswordCallback() { + setProperty(callbacks.getValidatedPasswordCallbacks().get(0)); +} + +function getValidatedUsernameCallback() { + setProperty(callbacks.getValidatedUsernameCallbacks().get(0)); +} + +function getX509CertificateCallback() { + setProperty(callbacks.getX509CertificateCallbacks().get(0)); +} + +function main() { + if (!callbacks.isEmpty()) { + switch (properties.callback) { + case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: getBooleanAttributeInputCallback(); break; + case CALLBACKS.CHOICE_CALLBACK: getChoiceCallback(); break; + case CALLBACKS.CONFIRMATION_CALLBACK: getConfirmationCallback(); break; + case CALLBACKS.CONSENT_MAPPING_CALLBACK: getConsentMappingCallback(); break; + case CALLBACKS.DEVICE_PROFILE_CALLBACK: getDeviceProfileCallback(); break; + case CALLBACKS.HIDDEN_VALUE_CALLBACK: getHiddenValueCallback(); break; + case CALLBACKS.HTTP_CALLBACK: getHttpCallback(); break; + case CALLBACKS.IDP_CALLBACK: getIdPCallback(); break; + case CALLBACKS.KBA_CREATE_CALLBACK: getKbaCreateCallback(); break; + case CALLBACKS.LANGUAGE_CALLBACK: getLanguageCallback(); break; + case CALLBACKS.NAME_CALLBACK: getNameCallback(); break; + case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: getNumberAttributeInputCallback(); break; + case CALLBACKS.PASSWORD_CALLBACK: getPasswordCallback(); break; + case CALLBACKS.SELECT_IDP_CALLBACK: getSelectIdPCallback(); break; + case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: getStringAttributeInputCallback(); break; + case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: getTermsAndConditionsCallback(); break; + case CALLBACKS.TEXT_INPUT_CALLBACK: getTextInputCallback(); break; + case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: getValidatedPasswordCallback(); break; + case CALLBACKS.VALIDATED_USERNAME_CALLBACK: getValidatedUsernameCallback(); break; + case CALLBACKS.X509_CERTIFICATE_CALLBACK: getX509CertificateCallback(); break; + default: break; + } + action.goTo(SCRIPT_OUTCOMES.OUTCOME); + return; + } + + switch (properties.callback) { + case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: booleanAttributeInputCallback(); break; + case CALLBACKS.CHOICE_CALLBACK: choiceCallback(); break; + case CALLBACKS.CONFIRMATION_CALLBACK: confirmationCallback(); break; + case CALLBACKS.CONSENT_MAPPING_CALLBACK: consentMappingCallback(); break; + case CALLBACKS.DEVICE_PROFILE_CALLBACK: deviceProfileCallback(); break; + case CALLBACKS.HIDDEN_VALUE_CALLBACK: hiddenValueCallback(); break; + case CALLBACKS.HTTP_CALLBACK: httpCallback(); break; + case CALLBACKS.IDP_CALLBACK: idPCallback(); break; + case CALLBACKS.KBA_CREATE_CALLBACK: kbaCreateCallback(); break; + case CALLBACKS.LANGUAGE_CALLBACK: languageCallback(); break; + case CALLBACKS.METADATA_CALLBACK: metadataCallback(); break; + case CALLBACKS.NAME_CALLBACK: nameCallback(); break; + case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: numberAttributeInputCallback(); break; + case CALLBACKS.PASSWORD_CALLBACK: passwordCallback(); break; + case CALLBACKS.POLLING_WAIT_CALLBACK: pollingWaitCallback(); break; + case CALLBACKS.REDIRECT_CALLBACK: redirectCallback(); break; + case CALLBACKS.SCRIPT_TEXT_OUTPUT_CALLBACK: scriptTextOutputCallback(); break; + case CALLBACKS.SELECT_IDP_CALLBACK: selectIdPCallback(); break; + case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: stringAttributeInputCallback(); break; + case CALLBACKS.SUSPENDED_TEXT_OUTPUT_CALLBACK: suspendedTextOutputCallback(); break; + case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: termsAndConditionsCallback(); break; + case CALLBACKS.TEXT_INPUT_CALLBACK: textInputCallback(); break; + case CALLBACKS.TEXT_OUTPUT_CALLBACK: textOutputCallback(); break; + case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: validatedPasswordCallback(); break; + case CALLBACKS.VALIDATED_USERNAME_CALLBACK: validatedUsernameCallback(); break; + case CALLBACKS.X509_CERTIFICATE_CALLBACK: x509CertificateCallback(); break; + default: throw new Error('Unknown Callback'); // Should never reach this case + } +} + +main(); +" +`; + +exports[`frodo config-manager pull custom-nodes "frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops": should export custom node named: Display Callback: configManagerPullCustomNodesDir1/custom-nodes/nodes/Display Callback/Display Callback.json 1`] = ` +{ + "_id": "ef81b1a52c914710b3388caebfe7233a-1", + "description": "Displays custom callback to the page", + "displayName": "Display Callback", + "errorOutcome": false, + "inputs": [], + "outcomes": [ + "outcome", + ], + "outputs": [], + "properties": { + "callback": { + "description": "The callback to display", + "multivalued": false, + "options": { + "BOOLEAN_ATTRIBUTE_INPUT_CALLBACK": "booleanAttributeInputCallback", + "CHOICE_CALLBACK": "choiceCallback", + "CONFIRMATION_CALLBACK": "confirmationCallback", + "CONSENT_MAPPING_CALLBACK": "consentMappingCallback", + "DEVICE_PROFILE_CALLBACK": "deviceProfileCallback", + "HIDDEN_VALUE_CALLBACK": "hiddenValueCallback", + "HTTP_CALLBACK": "httpCallback", + "IDP_CALLBACK": "idPCallback", + "KBA_CREATE_CALLBACK": "kbaCreateCallback", + "LANGUAGE_CALLBACK": "languageCallback", + "METADATA_CALLBACK": "metadataCallback", + "NAME_CALLBACK": "nameCallback", + "NUMBER_ATTRIBUTE_INPUT_CALLBACK": "numberAttributeInputCallback", + "PASSWORD_CALLBACK": "passwordCallback", + "POLLING_WAIT_CALLBACK": "pollingWaitCallback", + "REDIRECT_CALLBACK": "redirectCallback", + "SCRIPT_TEXT_OUTPUT_CALLBACK": "scriptTextOutputCallback", + "SELECT_IDP_CALLBACK": "selectIdPCallback", + "STRING_ATTRIBUTE_INPUT_CALLBACK": "stringAttributeInputCallback", + "SUSPENDED_TEXT_OUTPUT_CALLBACK": "suspendedTextOutputCallback", + "TERMS_AND_CONDITIONS_CALLBACK": "termsAndConditionsCallback", + "TEXT_INPUT_CALLBACK": "textInputCallback", + "TEXT_OUTPUT_CALLBACK": "textOutputCallback", + "VALIDATED_PASSWORD_CALLBACK": "validatedPasswordCallback", + "VALIDATED_USERNAME_CALLBACK": "validatedUsernameCallback", + "X509_CERTIFICATE_CALLBACK": "x509CertificateCallback", + }, + "required": true, + "title": "Callback", + "type": "STRING", + }, + "objectSharedProperty": { + "description": "The objectAttributes property on the shared state to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Object Attributes Shared Property", + "type": "STRING", + }, + "objectTransientProperty": { + "description": "The objectAttributes property on the transient state to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Object Attributes Transient Property", + "type": "STRING", + }, + "options": { + "description": "The options containing the parameters for the callback (see documentation for possible parameters: https://docs.pingidentity.com/pingoneaic/latest/am-scripting/scripting-api-node.html#scripting-api-node-callbacks). + +For example, for textOutputCallback, the options could be: { messageType: 0, message: "Hello World!" }. + +Note that for required parameters that are not specified in the options will use default values based on the type of the parameter ("" for Strings, [] for Arrays, {} for Objects, 0 for Ints, 0.0 for Doubles, and false for Booleans).", + "multivalued": false, + "required": true, + "title": "Options", + "type": "OBJECT", + }, + "sharedProperty": { + "description": "The shared state property to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Shared State Property", + "type": "STRING", + }, + "transientProperty": { + "description": "The transient state property to put the callback input into (if applicable)", + "multivalued": false, + "required": false, + "title": "Transient State Property", + "type": "STRING", + }, + }, + "script": { + "file": "Display Callback.js", + }, + "serviceName": "ef81b1a52c914710b3388caebfe7233a", + "tags": [ + "callback", + "utilities", + ], +} +`; diff --git a/test/e2e/config-manager-pull-custom-nodes.e2e.test.js b/test/e2e/config-manager-pull-custom-nodes.e2e.test.js new file mode 100644 index 000000000..9ca8b5329 --- /dev/null +++ b/test/e2e/config-manager-pull-custom-nodes.e2e.test.js @@ -0,0 +1,71 @@ +/** + * Follow this process to write e2e tests for the CLI project: + * + * 1. Test if all the necessary mocks for your tests already exist. + * In mock mode, run the command you want to test with the same arguments + * and parameters exactly as you want to test it, for example: + * + * $ FRODO_MOCK=1 frodo conn save https://openam-frodo-dev.forgeblocks.com/am volker.scheuber@forgerock.com Sup3rS3cr3t! + * + * If your command completes without errors and with the expected results, + * all the required mocks already exist and you are good to write your + * test and skip to step #4. + * + * If, however, your command fails and you see errors like the one below, + * you know you need to record the mock responses first: + * + * [Polly] [adapter:node-http] Recording for the following request is not found and `recordIfMissing` is `false`. + * + * 2. Record mock responses for your exact command. + * In mock record mode, run the command you want to test with the same arguments + * and parameters exactly as you want to test it, for example: + * + * $ FRODO_MOCK=record frodo conn save https://openam-frodo-dev.forgeblocks.com/am volker.scheuber@forgerock.com Sup3rS3cr3t! + * + * Wait until you see all the Polly instances (mock recording adapters) have + * shutdown before you try to run step #1 again. + * Messages like these indicate mock recording adapters shutting down: + * + * Polly instance 'conn/4' stopping in 3s... + * Polly instance 'conn/4' stopping in 2s... + * Polly instance 'conn/save/3' stopping in 3s... + * Polly instance 'conn/4' stopping in 1s... + * Polly instance 'conn/save/3' stopping in 2s... + * Polly instance 'conn/4' stopped. + * Polly instance 'conn/save/3' stopping in 1s... + * Polly instance 'conn/save/3' stopped. + * + * 3. Validate your freshly recorded mock responses are complete and working. + * Re-run the exact command you want to test in mock mode (see step #1). + * + * 4. Write your test. + * Make sure to use the exact command including number of arguments and params. + * + * 5. Commit both your test and your new recordings to the repository. + * Your tests are likely going to reside outside the frodo-lib project but + * the recordings must be committed to the frodo-lib project. + */ + +/* +FRODO_MOCK=record FRODO_NO_CACHE=1 FRODO_HOST=https://nightly.gcp.forgeops.com/am frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops +FRODO_MOCK=record FRODO_NO_CACHE=1 FRODO_HOST=https://nightly.gcp.forgeops.com/am frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops +*/ + +import { getEnv, testExport } from './utils/TestUtils'; +import { forgeops_connection as fc } from './utils/TestConfig'; + +process.env['FRODO_MOCK'] = '1'; +const env = getEnv(fc); + +describe('frodo config-manager pull custom-nodes', () => { + test(`"frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir0 -m forgeops": should export all custom-nodes in fr-config manager style.`, async () => { + const dirName = 'configManagerPullCustomNodesDir0'; + const CMD = `frodo config-manager pull custom-nodes -D ${dirName} -m forgeops`; + await testExport(CMD, env, undefined, undefined, dirName, false); + }); + test(`"frodo config-manager pull custom-nodes -D configManagerPullCustomNodesDir1 -n 'Display Callback' -m forgeops": should export custom node named: Display Callback`, async () => { + const dirName = 'configManagerPullCustomNodesDir1'; + const CMD = `frodo config-manager pull custom-nodes -D ${dirName} -n 'Display Callback' -m forgeops`; + await testExport(CMD, env, undefined, undefined, dirName, false); + }); +}); \ No newline at end of file diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/am_1076162899/recording.har new file mode 100644 index 000000000..ddcad469b --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/am_1076162899/recording.har @@ -0,0 +1,780 @@ +{ + "log": { + "_recordingName": "config-manager/pull/custom-nodes/0_D_m/am", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccd7a5defd0fdeaa986a2b54642d911a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "resource=1.1" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 370, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/*" + }, + "response": { + "bodySize": 587, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 587, + "text": "{\"_id\":\"*\",\"_rev\":\"2075994313\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"iPlanetDirectoryPro\",\"secureCookie\":true,\"forgotPassword\":\"false\",\"forgotUsername\":\"false\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"false\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"refererWhitelist\":[],\"allowedWithoutReferer\":true},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"nodeDesignerXuiEnabled\":true}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "587" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.1" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"2075994313\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.521Z", + "time": 12, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 12 + } + }, + { + "_id": "9f5671275c36a1c0090d0df26ce0e93f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 2, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "resource=2.0, protocol=1.0" + }, + { + "name": "x-openam-username", + "value": "amadmin" + }, + { + "name": "x-openam-password", + "value": "41ghjnKpNFAFU/HXw82HbFbitYNOOJ0g" + }, + { + "name": "content-length", + "value": "2" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 497, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/authenticate" + }, + "response": { + "bodySize": 167, + "content": { + "mimeType": "application/json", + "size": 167, + "text": "{\"tokenId\":\"\",\"successUrl\":\"/am/console\",\"realm\":\"/\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "iPlanetDirectoryPro", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "amlbcookie", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "content-length", + "value": "167" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "iPlanetDirectoryPro=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "amlbcookie=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=2.1" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 693, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.539Z", + "time": 24, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 24 + } + }, + { + "_id": "6a3744385d3fd7416ea7089e610fa7e7", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 128, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "resource=4.0" + }, + { + "name": "content-length", + "value": "128" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"tokenId\":\"\"}" + }, + "queryString": [ + { + "name": "_action", + "value": "getSessionInfo" + } + ], + "url": "https://platform.dev.trivir.com/am/json/realms/root/sessions/?_action=getSessionInfo" + }, + "response": { + "bodySize": 291, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 291, + "text": "{\"username\":\"amadmin\",\"universalId\":\"id=amadmin,ou=user,ou=am-config\",\"realm\":\"/\",\"latestAccessTime\":\"2026-04-13T22:11:13Z\",\"maxIdleExpirationTime\":\"2026-04-13T22:41:13Z\",\"maxSessionExpirationTime\":\"2026-04-14T00:11:12Z\",\"properties\":{\"AMCtxId\":\"d65b280f-e163-4042-871b-1d0ffe1512eb-12065\"}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "291" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=4.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 610, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.570Z", + "time": 8, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 8 + } + }, + { + "_id": "6125d0328ad0dcaee55f73fd8b22ca14", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 520, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/version" + }, + "response": { + "bodySize": 257, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 257, + "text": "{\"_id\":\"version\",\"_rev\":\"-466575464\",\"version\":\"8.0.1\",\"fullVersion\":\"ForgeRock Access Management 8.0.1 Build b59bc0908346197b0c33afcb9e733d0400feeea1 (2025-April-15 11:37)\",\"revision\":\"b59bc0908346197b0c33afcb9e733d0400feeea1\",\"date\":\"2025-April-15 11:37\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "257" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-466575464\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.583Z", + "time": 6, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 6 + } + }, + { + "_id": "e6efe3392d787815b92258f4573fd0b4", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 556, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_queryFilter", + "value": "true" + } + ], + "url": "https://platform.dev.trivir.com/am/json/node-designer/node-type?_queryFilter=true" + }, + "response": { + "bodySize": 33591, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 33591, + "text": "{\"result\":[{\"_id\":\"c6063fb2f5dc42dd9772bedc93898bd8-1\",\"_rev\":\"1733504144\",\"serviceName\":\"c6063fb2f5dc42dd9772bedc93898bd8\",\"displayName\":\"ALU\",\"description\":\"Simple ALU that performs basic binary math operations. Expects an \\\"x\\\" and \\\"y\\\" value on the shared state, and will produce a new \\\"z\\\" value on the shared state as output.\",\"outcomes\":[\"Success\"],\"outputs\":[\"z\"],\"inputs\":[\"x\",\"y\"],\"script\":\"var SCRIPT_OUTCOMES = {\\n SUCCESS: 'Success'\\n};\\n\\nvar OPERATORS = {\\n ADD: \\\"ADD\\\",\\n SUBTRACT: \\\"SUBTRACT\\\",\\n MULTIPLY: \\\"MULTIPLY\\\",\\n DIVIDE: \\\"DIVIDE\\\"\\n}\\n\\nfunction main() {\\n var a = Number(properties.a);\\n var b = Number(properties.b);\\n switch (properties.operator) {\\n case OPERATORS.ADD:\\n nodeState.putShared(\\\"z\\\", a + b);\\n break;\\n case OPERATORS.SUBTRACT:\\n nodeState.putShared(\\\"z\\\", a - b);\\n break;\\n case OPERATORS.MULTIPLY:\\n nodeState.putShared(\\\"z\\\", a * b);\\n break;\\n case OPERATORS.DIVIDE:\\n if (b == 0) throw new Error(\\\"Cannot divide by 0\\\");\\n nodeState.putShared(\\\"z\\\", a / b);\\n break;\\n default: throw new Error(\\\"Unknown operator.\\\");\\n }\\n action.goTo(SCRIPT_OUTCOMES.SUCCESS);\\n}\\n\\nmain();\\n\",\"errorOutcome\":true,\"tags\":[\"math\",\"utilities\"],\"properties\":{\"operator\":{\"title\":\"Operator\",\"description\":\"The operation to perform.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"ADD\",\"options\":{\"ADD\":\"+\",\"MULTIPLY\":\"*\",\"SUBTRACT\":\"-\",\"DIVIDE\":\"/\"},\"multivalued\":false}}},{\"_id\":\"8ab9f1aad4b4460a9c45d15fb148e221-1\",\"_rev\":\"1713151721\",\"serviceName\":\"8ab9f1aad4b4460a9c45d15fb148e221\",\"displayName\":\"Display State\",\"description\":\"Debug node that displays the shared and transient state of the journey for debugging purposes.\",\"outcomes\":[\"outcome\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n OUTCOME: \\\"outcome\\\"\\n};\\n\\nfunction main() {\\n if (!callbacks.isEmpty()) {\\n action.goTo(SCRIPT_OUTCOMES.OUTCOME);\\n return;\\n }\\n var keySet = nodeState.keys(); // Java Set\\n var keys = Array.from(keySet); // Make it into JavaScript array\\n debugState = {};\\n for (var i in keys) {\\n var k = new String(keys[i]);\\n var item = nodeState.get(k);\\n if (typeof item === \\\"object\\\") {\\n debugState[k] = nodeState.getObject(k);\\n } else {\\n debugState[k] = nodeState.get(k);\\n }\\n }\\n if (properties.displayFormat === \\\"JSON\\\") {\\n callbacksBuilder.textOutputCallback(0, `
${JSON.stringify(debugState, null, 2)}
`);\\n return;\\n }\\n callbacksBuilder.textOutputCallback(0, `${Array.from(Object.keys(debugState).map(k => ``))}
KeyValue
${k}
${debugState[k]}
`);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"debug\",\"testing\"],\"properties\":{\"displayFormat\":{\"title\":\"Display Format\",\"description\":\"The format in which to display the states.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"TABLE\",\"options\":{\"TABLE\":\"HTML Table\",\"JSON\":\"Raw JSON\"},\"multivalued\":false}}},{\"_id\":\"c605506774a848f7877b4d17a453bd39-1\",\"_rev\":\"1583432423\",\"serviceName\":\"c605506774a848f7877b4d17a453bd39\",\"displayName\":\"Has Session\",\"description\":\"Checks if the user has a current session.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n TRUE: 'True',\\n FALSE: 'False'\\n}\\n\\nfunction main() {\\n action.goTo(typeof existingSession === \\\"undefined\\\" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"utilities\"],\"properties\":{}},{\"_id\":\"session-1\",\"_rev\":\"1248028795\",\"serviceName\":\"session\",\"displayName\":\"Has Session AM\",\"description\":\"Checks if the user has a current session.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n TRUE: 'True',\\n FALSE: 'False'\\n}\\n\\nfunction main() {\\n action.goTo(typeof existingSession === \\\"undefined\\\" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"utilities\"],\"properties\":{}},{\"_id\":\"c15e2efb3deb4d4ea338c74a6440b69f-1\",\"_rev\":\"-2034215288\",\"serviceName\":\"c15e2efb3deb4d4ea338c74a6440b69f\",\"displayName\":\"Vector ALU\",\"description\":\"Simple ALU that performs basic binary vector math operations. Outputs the result onto the shared state with key \\\"c\\\".\",\"outcomes\":[\"Success\"],\"outputs\":[\"c\"],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n SUCCESS: 'Success'\\n};\\n\\nvar OPERATORS = {\\n ADD: \\\"ADD\\\",\\n SUBTRACT: \\\"SUBTRACT\\\",\\n DOT: \\\"DOT\\\",\\n CROSS: \\\"CROSS\\\"\\n}\\n\\nfunction add(a, b) {\\n return a.map((v, i) => v + b[i]);\\n}\\n\\nfunction subtract(a, b) {\\n return a.map((v, i) => v - b[i]);\\n}\\n\\nfunction dot(a, b) {\\n return a.reduce((sum, v, i) => sum + v * b[i], 0);\\n}\\n\\nfunction cross(a, b) {\\n return [\\n a[1] * b[2] - a[2] * b[1],\\n a[2] * b[0] - a[0] * b[2],\\n a[0] * b[1] - a[1] * b[0]\\n ];\\n}\\n\\nfunction main() {\\n if (properties.a.length !== properties.b.length) throw new Error(\\\"Vectors not the same dimension.\\\");\\n switch (properties.operator) {\\n case OPERATORS.ADD:\\n nodeState.putShared(\\\"c\\\", add(properties.a, properties.b));\\n break;\\n case OPERATORS.SUBTRACT:\\n nodeState.putShared(\\\"c\\\", subtract(properties.a, properties.b));\\n break;\\n case OPERATORS.DOT:\\n nodeState.putShared(\\\"c\\\", dot(properties.a, properties.b));\\n break;\\n case OPERATORS.CROSS:\\n if (properties.a.length !== 3) throw new Error(\\\"Vectors not dimension 3 for cross product\\\");\\n nodeState.putShared(\\\"c\\\", cross(properties.a, properties.b));\\n break;\\n default: throw new Error(\\\"Unknown operator.\\\");\\n }\\n action.goTo(SCRIPT_OUTCOMES.SUCCESS);\\n}\\n\\nmain();\\n\",\"errorOutcome\":true,\"tags\":[\"math\",\"vector\",\"utilities\"],\"properties\":{\"a\":{\"title\":\"A\",\"description\":\"Left vector operand\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":[1,2,3],\"multivalued\":true},\"b\":{\"title\":\"B\",\"description\":\"Right vector operand\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":[4,5,6],\"multivalued\":true},\"operator\":{\"title\":\"Operator\",\"description\":\"The binary operation to perform on the vectors.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"DOT\",\"options\":{\"ADD\":\"+\",\"CROSS\":\"X\",\"DOT\":\".\",\"SUBTRACT\":\"-\"},\"multivalued\":false}}},{\"_id\":\"e5ad0110c8ee4dafaae983003cd05d4a-1\",\"_rev\":\"573016413\",\"serviceName\":\"e5ad0110c8ee4dafaae983003cd05d4a\",\"displayName\":\"Generate JWT\",\"description\":\"Generate a signed JWT using the HMAC SHA-256 algorithm.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var aud = properties.audience;\\nvar iss = properties.issuer;\\nvar validity = properties.validity;\\nvar esv = properties.signingkey;\\n\\nvar signingkey = systemEnv.getProperty(esv);\\n\\nvar username = nodeState.get(\\\"username\\\");\\n\\nvar data = {\\n jwtType:\\\"SIGNED\\\",\\n jwsAlgorithm: \\\"HS256\\\",\\n issuer: iss,\\n subject: username,\\n audience: aud,\\n type: \\\"JWT\\\",\\n validityMinutes: validity,\\n signingKey: signingkey\\n};\\n\\nvar jwt = jwtAssertion.generateJwt(data);\\n\\nif (jwt !== null && jwt.length > 0) {\\n nodeState.putShared(\\\"assertionJwt\\\" , jwt);\\n action.goTo(\\\"True\\\");\\n} else {\\n action.goTo(\\\"False\\\");\\n}\\n\",\"errorOutcome\":true,\"tags\":[\"Utilities\",\"utilities\"],\"properties\":{\"audience\":{\"title\":\"Audience\",\"description\":\"The audience (aud) claim\",\"type\":\"STRING\",\"required\":true,\"multivalued\":false},\"issuer\":{\"title\":\"Issuer\",\"description\":\"The issuer (iss) claim\",\"type\":\"STRING\",\"required\":true,\"multivalued\":false},\"signingkey\":{\"title\":\"HMAC Signing Key\",\"description\":\"The secret label for the HMAC signing key\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"esv.signing.key\",\"multivalued\":false},\"validity\":{\"title\":\"Validity (minutes)\",\"description\":\"\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":5,\"multivalued\":false}}},{\"_id\":\"ef81b1a52c914710b3388caebfe7233a-1\",\"_rev\":\"1723458869\",\"serviceName\":\"ef81b1a52c914710b3388caebfe7233a\",\"displayName\":\"Display Callback\",\"description\":\"Displays custom callback to the page\",\"outcomes\":[\"outcome\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n OUTCOME: 'outcome'\\n};\\n\\nvar CALLBACKS = {\\n\\tBOOLEAN_ATTRIBUTE_INPUT_CALLBACK: \\\"BOOLEAN_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tCHOICE_CALLBACK: \\\"CHOICE_CALLBACK\\\",\\n\\tCONFIRMATION_CALLBACK: \\\"CONFIRMATION_CALLBACK\\\",\\n\\tCONSENT_MAPPING_CALLBACK: \\\"CONSENT_MAPPING_CALLBACK\\\",\\n\\tDEVICE_PROFILE_CALLBACK: \\\"DEVICE_PROFILE_CALLBACK\\\",\\n\\tHIDDEN_VALUE_CALLBACK: \\\"HIDDEN_VALUE_CALLBACK\\\",\\n\\tHTTP_CALLBACK: \\\"HTTP_CALLBACK\\\",\\n\\tIDP_CALLBACK: \\\"IDP_CALLBACK\\\",\\n\\tKBA_CREATE_CALLBACK: \\\"KBA_CREATE_CALLBACK\\\",\\n\\tLANGUAGE_CALLBACK: \\\"LANGUAGE_CALLBACK\\\",\\n\\tMETADATA_CALLBACK: \\\"METADATA_CALLBACK\\\",\\n\\tNAME_CALLBACK: \\\"NAME_CALLBACK\\\",\\n\\tNUMBER_ATTRIBUTE_INPUT_CALLBACK: \\\"NUMBER_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tPASSWORD_CALLBACK: \\\"PASSWORD_CALLBACK\\\",\\n\\tPOLLING_WAIT_CALLBACK: \\\"POLLING_WAIT_CALLBACK\\\",\\n REDIRECT_CALLBACK: \\\"REDIRECT_CALLBACK\\\",\\n\\tSCRIPT_TEXT_OUTPUT_CALLBACK: \\\"SCRIPT_TEXT_OUTPUT_CALLBACK\\\",\\n\\tSELECT_IDP_CALLBACK: \\\"SELECT_IDP_CALLBACK\\\",\\n\\tSTRING_ATTRIBUTE_INPUT_CALLBACK: \\\"STRING_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tSUSPENDED_TEXT_OUTPUT_CALLBACK: \\\"SUSPENDED_TEXT_OUTPUT_CALLBACK\\\",\\n\\tTERMS_AND_CONDITIONS_CALLBACK: \\\"TERMS_AND_CONDITIONS_CALLBACK\\\",\\n\\tTEXT_INPUT_CALLBACK: \\\"TEXT_INPUT_CALLBACK\\\",\\n\\tTEXT_OUTPUT_CALLBACK: \\\"TEXT_OUTPUT_CALLBACK\\\",\\n\\tVALIDATED_PASSWORD_CALLBACK: \\\"VALIDATED_PASSWORD_CALLBACK\\\",\\n\\tVALIDATED_USERNAME_CALLBACK: \\\"VALIDATED_USERNAME_CALLBACK\\\",\\n\\tX509_CERTIFICATE_CALLBACK: \\\"X509_CERTIFICATE_CALLBACK\\\"\\n}\\n\\nfunction isStringPresent(value) {\\n return value;\\n}\\n\\nfunction getString(value) {\\n return value || '';\\n}\\n\\nfunction isArrayPresent(value) {\\n return value;\\n}\\n\\nfunction getArray(value) {\\n return value ? JSON.parse(value) : [];\\n}\\n\\nfunction isObjectPresent(value) {\\n return value;\\n}\\n\\nfunction getObject(value) {\\n return value ? JSON.parse(value) : {};\\n}\\n\\nfunction isIntPresent(value) {\\n return value;\\n}\\n\\nfunction getInt(value) {\\n return value ? parseInt(value) : 0;\\n}\\n\\nfunction isDoublePresent(value) {\\n return value;\\n}\\n\\nfunction getDouble(value) {\\n return value ? parseFloat(value) : 0.0;\\n}\\n\\nfunction isBooleanPresent(value) {\\n return value;\\n}\\n\\nfunction getBoolean(value) {\\n return value ? value.toLowerCase() === 'true' : false;\\n}\\n\\nfunction setProperty(value) {\\n if (properties.sharedProperty) nodeState.putShared(properties.sharedProperty, value);\\n if (properties.transientProperty) nodeState.putTransient(properties.transientProperty, value);\\n if (properties.objectSharedProperty) {\\n var attributes = {};\\n attributes[properties.objectSharedProperty] = value;\\n nodeState.mergeShared({\\n objectAttributes: attributes\\n });\\n }\\n if (properties.objectTransientProperty) {\\n var attributes = {};\\n attributes[properties.objectTransientProperty] = value;\\n nodeState.mergeTransient({\\n objectAttributes: attributes\\n });\\n }\\n}\\n\\nfunction booleanAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getBoolean(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction choiceCallback() {\\n var prompt = getString(properties.options.prompt);\\n var choices = getArray(properties.options.choices);\\n var defaultChoice = getInt(properties.options.defaultChoice);\\n var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed);\\n callbacksBuilder.choiceCallback(prompt, choices, defaultChoice, multipleSelectionsAllowed);\\n}\\n\\nfunction confirmationCallback() {\\n var prompt = getString(properties.options.prompt);\\n var messageType = getInt(properties.options.messageType);\\n var options = getArray(properties.options.options);\\n var optionType = getInt(properties.options.optionType);\\n var defaultOption = getInt(properties.options.defaultOption);\\n if (isStringPresent(properties.options.prompt)) {\\n if (isIntPresent(properties.options.optionType)) {\\n callbacksBuilder.confirmationCallback(prompt, messageType, optionType, defaultOption);\\n } else {\\n callbacksBuilder.confirmationCallback(prompt, messageType, options, defaultOption);\\n }\\n } else {\\n if (isIntPresent(properties.options.optionType)) {\\n callbacksBuilder.confirmationCallback(messageType, optionType, defaultOption);\\n } else {\\n callbacksBuilder.confirmationCallback(messageType, options, defaultOption);\\n }\\n }\\n}\\n\\nfunction consentMappingCallback() {\\n var config = getObject(properties.options.config);\\n var message = getString(properties.options.message);\\n var isRequired = getBoolean(properties.options.isRequired);\\n var name = getString(properties.options.name);\\n var displayName = getString(properties.options.displayName);\\n var icon = getString(properties.options.icon);\\n var accessLevel = getString(properties.options.accessLevel);\\n var titles = getArray(properties.options.titles);\\n if (isObjectPresent(properties.options.prompt)) {\\n callbacksBuilder.consentMappingCallback(config, message, isRequired);\\n } else {\\n callbacksBuilder.consentMappingCallback(name, displayName, icon, accessLevel, titles, message, isRequired);\\n }\\n}\\n\\nfunction deviceProfileCallback() {\\n var metadata = getBoolean(properties.options.metadata);\\n var location = getBoolean(properties.options.location);\\n var message = getString(properties.options.message);\\n callbacksBuilder.deviceProfileCallback(metadata, location, message);\\n}\\n\\nfunction hiddenValueCallback() {\\n var id = getString(properties.options.id);\\n var value = getString(properties.options.value);\\n callbacksBuilder.hiddenValueCallback(id, value);\\n}\\n\\nfunction httpCallback() {\\n var authorizationHeader = getString(properties.options.authorizationHeader);\\n var negotiationHeader = getString(properties.options.negotiationHeader);\\n var authRHeader = getString(properties.options.authRHeader);\\n var negoName = getString(properties.options.negoName);\\n var negoValue = getString(properties.options.negoValue);\\n if (isStringPresent(properties.options.authorizationHeader) || isStringPresent(properties.options.negotiationHeader)) {\\n var errorCode = getString(properties.options.errorCode);\\n callbacksBuilder.httpCallback(authorizationHeader, negotiationHeader, errorCode);\\n } else {\\n var errorCode = getInt(properties.options.errorCode);\\n callbacksBuilder.httpCallback(authRHeader, negoName, negoValue, errorCode);\\n }\\n}\\n\\nfunction idPCallback() {\\n var provider = getString(properties.options.provider);\\n var clientId = getString(properties.options.clientId);\\n var redirectUri = getString(properties.options.redirectUri);\\n var scope = getArray(properties.options.scope);\\n var nonce = getString(properties.options.nonce);\\n var request = getString(properties.options.request);\\n var requestUri = getString(properties.options.requestUri);\\n var acrValues = getArray(properties.options.acrValues);\\n var requestNativeAppForUserInfo = getBoolean(properties.options.requestNativeAppForUserInfo);\\n var token = getString(properties.options.token);\\n var tokenType = getString(properties.options.tokenType);\\n if (isStringPresent(properties.options.token) || isStringPresent(properties.options.tokenType)) {\\n callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo, token, tokenType);\\n } else {\\n callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo);\\n }\\n}\\n\\nfunction kbaCreateCallback() {\\n var prompt = getString(properties.options.prompt);\\n var predefinedQuestions = getArray(properties.options.predefinedQuestions);\\n var allowUserDefinedQuestions = getBoolean(properties.options.allowUserDefinedQuestions);\\n callbacksBuilder.kbaCreateCallback(prompt, predefinedQuestions, allowUserDefinedQuestions);\\n}\\n\\nfunction languageCallback() {\\n var language = getString(properties.options.language);\\n var country = getString(properties.options.country);\\n callbacksBuilder.languageCallback(language, country);\\n}\\n\\nfunction metadataCallback() {\\n var outputValue = getObject(properties.options.outputValue);\\n callbacksBuilder.metadataCallback(outputValue);\\n}\\n\\nfunction nameCallback() {\\n var prompt = getString(properties.options.prompt);\\n var defaultName = getString(properties.options.defaultName);\\n if (isStringPresent(properties.options.defaultName)) {\\n callbacksBuilder.nameCallback(prompt, defaultName);\\n } else {\\n callbacksBuilder.nameCallback(prompt);\\n }\\n}\\n\\nfunction numberAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getDouble(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction passwordCallback() {\\n var prompt = getString(properties.options.prompt);\\n var echoOn = getBoolean(properties.options.echoOn);\\n callbacksBuilder.passwordCallback(prompt, echoOn);\\n}\\n\\nfunction pollingWaitCallback() {\\n var waitTime = getString(properties.options.waitTime);\\n var message = getString(properties.options.message);\\n callbacksBuilder.pollingWaitCallback(waitTime, message);\\n}\\n\\nfunction redirectCallback() {\\n throw new Error('Not Implemented');\\n}\\n\\nfunction scriptTextOutputCallback() {\\n var message = getString(properties.options.message);\\n callbacksBuilder.scriptTextOutputCallback(message);\\n}\\n\\nfunction selectIdPCallback() {\\n var providers = getObject(properties.options.providers);\\n callbacksBuilder.selectIdPCallback(providers);\\n}\\n\\nfunction stringAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getString(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction suspendedTextOutputCallback() {\\n var messageType = getInt(properties.options.messageType);\\n var message = getString(properties.options.message);\\n callbacksBuilder.suspendedTextOutputCallback(messageType, message);\\n}\\n\\nfunction termsAndConditionsCallback() {\\n var version = getString(properties.options.version);\\n var terms = getString(properties.options.terms);\\n var createDate = getString(properties.options.createDate);\\n callbacksBuilder.termsAndConditionsCallback(version, terms, createDate);\\n}\\n\\nfunction textInputCallback() {\\n var prompt = getString(properties.options.prompt);\\n var defaultText = getString(properties.options.defaultText);\\n if (isStringPresent(properties.options.defaultText)) {\\n callbacksBuilder.textInputCallback(prompt, defaultText);\\n } else {\\n callbacksBuilder.textInputCallback(prompt);\\n }\\n}\\n\\nfunction textOutputCallback() {\\n var messageType = getString(properties.options.messageType);\\n var message = getString(properties.options.message);\\n callbacksBuilder.textOutputCallback(messageType, message);\\n}\\n\\nfunction validatedPasswordCallback() {\\n var prompt = getString(properties.options.prompt);\\n var echoOn = getBoolean(properties.options.echoOn);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isArrayPresent(properties.options.failedPolicies)) {\\n callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly);\\n }\\n}\\n\\nfunction validatedUsernameCallback() {\\n var prompt = getString(properties.options.prompt);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isArrayPresent(properties.options.failedPolicies)) {\\n callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly);\\n }\\n}\\n\\nfunction x509CertificateCallback() {\\n throw new Error('Not Implemented');\\n}\\n\\nfunction getBooleanAttributeInputCallback() {\\n setProperty(callbacks.getBooleanAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getChoiceCallback() {\\n var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed);\\n var selections = callbacks.getChoiceCallbacks().get(0);\\n setProperty(multipleSelectionsAllowed ? selections : selections[0]);\\n}\\n\\nfunction getConfirmationCallback() {\\n setProperty(callbacks.getConfirmationCallbacks().get(0));\\n}\\n\\nfunction getConsentMappingCallback() {\\n setProperty(callbacks.getConsentMappingCallbacks().get(0));\\n}\\n\\nfunction getDeviceProfileCallback() {\\n setProperty(callbacks.getDeviceProfileCallbacks().get(0));\\n}\\n\\nfunction getHiddenValueCallback() {\\n var id = getString(properties.options.id);\\n setProperty(callbacks.getHiddenValueCallbacks().get(id));\\n}\\n\\nfunction getHttpCallback() {\\n setProperty(callbacks.getHttpCallbacks().get(0));\\n}\\n\\nfunction getIdPCallback() {\\n setProperty(callbacks.getIdpCallbacks().get(0));\\n}\\n\\nfunction getKbaCreateCallback() {\\n setProperty(callbacks.getKbaCreateCallbacks().get(0));\\n}\\n\\nfunction getLanguageCallback() {\\n setProperty(callbacks.getLanguageCallbacks().get(0));\\n}\\n\\nfunction getNameCallback() {\\n setProperty(callbacks.getNameCallbacks().get(0));\\n}\\n\\nfunction getNumberAttributeInputCallback() {\\n setProperty(callbacks.getNumberAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getPasswordCallback() {\\n setProperty(callbacks.getPasswordCallbacks().get(0));\\n}\\n\\nfunction getSelectIdPCallback() {\\n setProperty(callbacks.getSelectIdPCallbacks().get(0));\\n}\\n\\nfunction getStringAttributeInputCallback() {\\n setProperty(callbacks.getStringAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getTermsAndConditionsCallback() {\\n setProperty(callbacks.getTermsAndConditionsCallbacks().get(0));\\n}\\n\\nfunction getTextInputCallback() {\\n setProperty(callbacks.getTextInputCallbacks().get(0));\\n}\\n\\nfunction getValidatedPasswordCallback() {\\n setProperty(callbacks.getValidatedPasswordCallbacks().get(0));\\n}\\n\\nfunction getValidatedUsernameCallback() {\\n setProperty(callbacks.getValidatedUsernameCallbacks().get(0));\\n}\\n\\nfunction getX509CertificateCallback() {\\n setProperty(callbacks.getX509CertificateCallbacks().get(0));\\n}\\n\\nfunction main() {\\n if (!callbacks.isEmpty()) {\\n switch (properties.callback) {\\n case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: getBooleanAttributeInputCallback(); break;\\n case CALLBACKS.CHOICE_CALLBACK: getChoiceCallback(); break;\\n case CALLBACKS.CONFIRMATION_CALLBACK: getConfirmationCallback(); break;\\n case CALLBACKS.CONSENT_MAPPING_CALLBACK: getConsentMappingCallback(); break;\\n case CALLBACKS.DEVICE_PROFILE_CALLBACK: getDeviceProfileCallback(); break;\\n case CALLBACKS.HIDDEN_VALUE_CALLBACK: getHiddenValueCallback(); break;\\n case CALLBACKS.HTTP_CALLBACK: getHttpCallback(); break;\\n case CALLBACKS.IDP_CALLBACK: getIdPCallback(); break;\\n case CALLBACKS.KBA_CREATE_CALLBACK: getKbaCreateCallback(); break;\\n case CALLBACKS.LANGUAGE_CALLBACK: getLanguageCallback(); break;\\n case CALLBACKS.NAME_CALLBACK: getNameCallback(); break;\\n case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: getNumberAttributeInputCallback(); break;\\n case CALLBACKS.PASSWORD_CALLBACK: getPasswordCallback(); break;\\n case CALLBACKS.SELECT_IDP_CALLBACK: getSelectIdPCallback(); break;\\n case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: getStringAttributeInputCallback(); break;\\n case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: getTermsAndConditionsCallback(); break;\\n case CALLBACKS.TEXT_INPUT_CALLBACK: getTextInputCallback(); break;\\n case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: getValidatedPasswordCallback(); break;\\n case CALLBACKS.VALIDATED_USERNAME_CALLBACK: getValidatedUsernameCallback(); break;\\n case CALLBACKS.X509_CERTIFICATE_CALLBACK: getX509CertificateCallback(); break;\\n default: break;\\n }\\n action.goTo(SCRIPT_OUTCOMES.OUTCOME);\\n return;\\n }\\n\\n switch (properties.callback) {\\n case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: booleanAttributeInputCallback(); break;\\n case CALLBACKS.CHOICE_CALLBACK: choiceCallback(); break;\\n case CALLBACKS.CONFIRMATION_CALLBACK: confirmationCallback(); break;\\n case CALLBACKS.CONSENT_MAPPING_CALLBACK: consentMappingCallback(); break;\\n case CALLBACKS.DEVICE_PROFILE_CALLBACK: deviceProfileCallback(); break;\\n case CALLBACKS.HIDDEN_VALUE_CALLBACK: hiddenValueCallback(); break;\\n case CALLBACKS.HTTP_CALLBACK: httpCallback(); break;\\n case CALLBACKS.IDP_CALLBACK: idPCallback(); break;\\n case CALLBACKS.KBA_CREATE_CALLBACK: kbaCreateCallback(); break;\\n case CALLBACKS.LANGUAGE_CALLBACK: languageCallback(); break;\\n case CALLBACKS.METADATA_CALLBACK: metadataCallback(); break;\\n case CALLBACKS.NAME_CALLBACK: nameCallback(); break;\\n case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: numberAttributeInputCallback(); break;\\n case CALLBACKS.PASSWORD_CALLBACK: passwordCallback(); break;\\n case CALLBACKS.POLLING_WAIT_CALLBACK: pollingWaitCallback(); break;\\n case CALLBACKS.REDIRECT_CALLBACK: redirectCallback(); break;\\n case CALLBACKS.SCRIPT_TEXT_OUTPUT_CALLBACK: scriptTextOutputCallback(); break;\\n case CALLBACKS.SELECT_IDP_CALLBACK: selectIdPCallback(); break;\\n case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: stringAttributeInputCallback(); break;\\n case CALLBACKS.SUSPENDED_TEXT_OUTPUT_CALLBACK: suspendedTextOutputCallback(); break;\\n case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: termsAndConditionsCallback(); break;\\n case CALLBACKS.TEXT_INPUT_CALLBACK: textInputCallback(); break;\\n case CALLBACKS.TEXT_OUTPUT_CALLBACK: textOutputCallback(); break;\\n case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: validatedPasswordCallback(); break;\\n case CALLBACKS.VALIDATED_USERNAME_CALLBACK: validatedUsernameCallback(); break;\\n case CALLBACKS.X509_CERTIFICATE_CALLBACK: x509CertificateCallback(); break;\\n default: throw new Error('Unknown Callback'); // Should never reach this case\\n }\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"callback\",\"utilities\"],\"properties\":{\"callback\":{\"title\":\"Callback\",\"description\":\"The callback to display\",\"type\":\"STRING\",\"required\":true,\"options\":{\"METADATA_CALLBACK\":\"metadataCallback\",\"TERMS_AND_CONDITIONS_CALLBACK\":\"termsAndConditionsCallback\",\"NUMBER_ATTRIBUTE_INPUT_CALLBACK\":\"numberAttributeInputCallback\",\"TEXT_OUTPUT_CALLBACK\":\"textOutputCallback\",\"SCRIPT_TEXT_OUTPUT_CALLBACK\":\"scriptTextOutputCallback\",\"CONSENT_MAPPING_CALLBACK\":\"consentMappingCallback\",\"STRING_ATTRIBUTE_INPUT_CALLBACK\":\"stringAttributeInputCallback\",\"IDP_CALLBACK\":\"idPCallback\",\"VALIDATED_PASSWORD_CALLBACK\":\"validatedPasswordCallback\",\"SELECT_IDP_CALLBACK\":\"selectIdPCallback\",\"POLLING_WAIT_CALLBACK\":\"pollingWaitCallback\",\"NAME_CALLBACK\":\"nameCallback\",\"SUSPENDED_TEXT_OUTPUT_CALLBACK\":\"suspendedTextOutputCallback\",\"REDIRECT_CALLBACK\":\"redirectCallback\",\"X509_CERTIFICATE_CALLBACK\":\"x509CertificateCallback\",\"PASSWORD_CALLBACK\":\"passwordCallback\",\"TEXT_INPUT_CALLBACK\":\"textInputCallback\",\"BOOLEAN_ATTRIBUTE_INPUT_CALLBACK\":\"booleanAttributeInputCallback\",\"CONFIRMATION_CALLBACK\":\"confirmationCallback\",\"CHOICE_CALLBACK\":\"choiceCallback\",\"DEVICE_PROFILE_CALLBACK\":\"deviceProfileCallback\",\"HIDDEN_VALUE_CALLBACK\":\"hiddenValueCallback\",\"HTTP_CALLBACK\":\"httpCallback\",\"VALIDATED_USERNAME_CALLBACK\":\"validatedUsernameCallback\",\"KBA_CREATE_CALLBACK\":\"kbaCreateCallback\",\"LANGUAGE_CALLBACK\":\"languageCallback\"},\"multivalued\":false},\"objectSharedProperty\":{\"title\":\"Object Attributes Shared Property\",\"description\":\"The objectAttributes property on the shared state to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"objectTransientProperty\":{\"title\":\"Object Attributes Transient Property\",\"description\":\"The objectAttributes property on the transient state to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"options\":{\"title\":\"Options\",\"description\":\"The options containing the parameters for the callback (see documentation for possible parameters: https://docs.pingidentity.com/pingoneaic/latest/am-scripting/scripting-api-node.html#scripting-api-node-callbacks). \\n\\nFor example, for textOutputCallback, the options could be: { messageType: 0, message: \\\"Hello World!\\\" }. \\n\\nNote that for required parameters that are not specified in the options will use default values based on the type of the parameter (\\\"\\\" for Strings, [] for Arrays, {} for Objects, 0 for Ints, 0.0 for Doubles, and false for Booleans).\",\"type\":\"OBJECT\",\"required\":true,\"multivalued\":false},\"sharedProperty\":{\"title\":\"Shared State Property\",\"description\":\"The shared state property to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"transientProperty\":{\"title\":\"Transient State Property\",\"description\":\"The transient state property to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false}}}],\"resultCount\":7,\"pagedResultsCookie\":null,\"totalPagedResultsPolicy\":\"EXACT\",\"totalPagedResults\":7,\"remainingPagedResults\":-1}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "transfer-encoding", + "value": "chunked" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "protocol=2.1,resource=1.0, resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 644, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.677Z", + "time": 9, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 9 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/oauth2_393036114/recording.har new file mode 100644 index 000000000..b34b30eda --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_m_314327836/oauth2_393036114/recording.har @@ -0,0 +1,289 @@ +{ + "log": { + "_recordingName": "config-manager/pull/custom-nodes/0_D_m/oauth2", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "a684e2f67fd67a4263878c3124af167a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 365, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "365" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 565, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&scope=fr:idm:* openid&response_type=code&client_id=idm-admin-ui&csrf=TZTPpCLGkex90Xi3gF9X9bnWlPQ.*AAJTSQACMDIAAlNLABw2VnJPSmdBcXdZNWNacXhtM0ZOOGdqNC9oNVU9AAR0eXBlAANDVFMAAlMxAAIwMQ..*&decision=allow&code_challenge=ZByMVKUzuPfJ54tcv4ytC8jLxg8Vp2InlKA_Xoe_RGo&code_challenge_method=S256" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/authorize" + }, + "response": { + "bodySize": 0, + "content": { + "mimeType": "text/plain", + "size": 0 + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "expires": "1970-01-01T00:00:00.000Z", + "httpOnly": true, + "name": "OAUTH_REQUEST_ATTRIBUTES", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-length", + "value": "0" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "OAUTH_REQUEST_ATTRIBUTES=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "location", + "value": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=yidr7CqLl83wCrLAUtbTVLECXxo&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 673, + "httpVersion": "HTTP/1.1", + "redirectURL": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=yidr7CqLl83wCrLAUtbTVLECXxo&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui", + "status": 302, + "statusText": "Found" + }, + "startedDateTime": "2026-04-13T22:11:13.596Z", + "time": 19, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 19 + } + }, + { + "_id": "ff75519a93ccab829f8ee8cf5e92b49f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 224, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-57641519-67ef-4da6-8b71-2538f4143c60" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-length", + "value": "224" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "client_id=idm-admin-ui&redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&grant_type=authorization_code&code=yidr7CqLl83wCrLAUtbTVLECXxo&code_verifier=MMypQYIABQU7mcr6pH2fb5qrX9BJKGHvI8tJ_1jL7V0" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/access_token" + }, + "response": { + "bodySize": 1249, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1249, + "text": "{\"access_token\":\"\",\"scope\":\"openid fr:idm:*\",\"id_token\":\"\",\"token_type\":\"Bearer\",\"expires_in\":239}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:13 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1249" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 404, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:13.622Z", + "time": 46, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 46 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/am_1076162899/recording.har new file mode 100644 index 000000000..94f535f1b --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/am_1076162899/recording.har @@ -0,0 +1,780 @@ +{ + "log": { + "_recordingName": "config-manager/pull/custom-nodes/0_D_n_m/am", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccd7a5defd0fdeaa986a2b54642d911a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "resource=1.1" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 370, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/*" + }, + "response": { + "bodySize": 587, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 587, + "text": "{\"_id\":\"*\",\"_rev\":\"2075994313\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"iPlanetDirectoryPro\",\"secureCookie\":true,\"forgotPassword\":\"false\",\"forgotUsername\":\"false\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"false\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"refererWhitelist\":[],\"allowedWithoutReferer\":true},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"nodeDesignerXuiEnabled\":true}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:37 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "587" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.1" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"2075994313\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:37.978Z", + "time": 14, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 14 + } + }, + { + "_id": "9f5671275c36a1c0090d0df26ce0e93f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 2, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "resource=2.0, protocol=1.0" + }, + { + "name": "x-openam-username", + "value": "amadmin" + }, + { + "name": "x-openam-password", + "value": "41ghjnKpNFAFU/HXw82HbFbitYNOOJ0g" + }, + { + "name": "content-length", + "value": "2" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 497, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{}" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/realms/root/authenticate" + }, + "response": { + "bodySize": 167, + "content": { + "mimeType": "application/json", + "size": 167, + "text": "{\"tokenId\":\"\",\"successUrl\":\"/am/console\",\"realm\":\"/\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "iPlanetDirectoryPro", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + }, + { + "httpOnly": true, + "name": "amlbcookie", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:37 GMT" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "content-length", + "value": "167" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "iPlanetDirectoryPro=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "amlbcookie=; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=2.1" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 693, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:37.997Z", + "time": 18, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 18 + } + }, + { + "_id": "6a3744385d3fd7416ea7089e610fa7e7", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 128, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "resource=4.0" + }, + { + "name": "content-length", + "value": "128" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/json", + "params": [], + "text": "{\"tokenId\":\"\"}" + }, + "queryString": [ + { + "name": "_action", + "value": "getSessionInfo" + } + ], + "url": "https://platform.dev.trivir.com/am/json/realms/root/sessions/?_action=getSessionInfo" + }, + "response": { + "bodySize": 291, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 291, + "text": "{\"username\":\"amadmin\",\"universalId\":\"id=amadmin,ou=user,ou=am-config\",\"realm\":\"/\",\"latestAccessTime\":\"2026-04-13T22:11:37Z\",\"maxIdleExpirationTime\":\"2026-04-13T22:41:37Z\",\"maxSessionExpirationTime\":\"2026-04-14T00:11:36Z\",\"properties\":{\"AMCtxId\":\"d65b280f-e163-4042-871b-1d0ffe1512eb-12127\"}}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:37 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "291" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=4.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 609, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:38.021Z", + "time": 8, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 8 + } + }, + { + "_id": "6125d0328ad0dcaee55f73fd8b22ca14", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 520, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://platform.dev.trivir.com/am/json/serverinfo/version" + }, + "response": { + "bodySize": 257, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 257, + "text": "{\"_id\":\"version\",\"_rev\":\"-466575464\",\"version\":\"8.0.1\",\"fullVersion\":\"ForgeRock Access Management 8.0.1 Build b59bc0908346197b0c33afcb9e733d0400feeea1 (2025-April-15 11:37)\",\"revision\":\"b59bc0908346197b0c33afcb9e733d0400feeea1\",\"date\":\"2025-April-15 11:37\"}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:37 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "257" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-466575464\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 631, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:38.036Z", + "time": 6, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 6 + } + }, + { + "_id": "e6efe3392d787815b92258f4573fd0b4", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 556, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_queryFilter", + "value": "true" + } + ], + "url": "https://platform.dev.trivir.com/am/json/node-designer/node-type?_queryFilter=true" + }, + "response": { + "bodySize": 33591, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 33591, + "text": "{\"result\":[{\"_id\":\"c6063fb2f5dc42dd9772bedc93898bd8-1\",\"_rev\":\"1733504144\",\"serviceName\":\"c6063fb2f5dc42dd9772bedc93898bd8\",\"displayName\":\"ALU\",\"description\":\"Simple ALU that performs basic binary math operations. Expects an \\\"x\\\" and \\\"y\\\" value on the shared state, and will produce a new \\\"z\\\" value on the shared state as output.\",\"outcomes\":[\"Success\"],\"outputs\":[\"z\"],\"inputs\":[\"x\",\"y\"],\"script\":\"var SCRIPT_OUTCOMES = {\\n SUCCESS: 'Success'\\n};\\n\\nvar OPERATORS = {\\n ADD: \\\"ADD\\\",\\n SUBTRACT: \\\"SUBTRACT\\\",\\n MULTIPLY: \\\"MULTIPLY\\\",\\n DIVIDE: \\\"DIVIDE\\\"\\n}\\n\\nfunction main() {\\n var a = Number(properties.a);\\n var b = Number(properties.b);\\n switch (properties.operator) {\\n case OPERATORS.ADD:\\n nodeState.putShared(\\\"z\\\", a + b);\\n break;\\n case OPERATORS.SUBTRACT:\\n nodeState.putShared(\\\"z\\\", a - b);\\n break;\\n case OPERATORS.MULTIPLY:\\n nodeState.putShared(\\\"z\\\", a * b);\\n break;\\n case OPERATORS.DIVIDE:\\n if (b == 0) throw new Error(\\\"Cannot divide by 0\\\");\\n nodeState.putShared(\\\"z\\\", a / b);\\n break;\\n default: throw new Error(\\\"Unknown operator.\\\");\\n }\\n action.goTo(SCRIPT_OUTCOMES.SUCCESS);\\n}\\n\\nmain();\\n\",\"errorOutcome\":true,\"tags\":[\"math\",\"utilities\"],\"properties\":{\"operator\":{\"title\":\"Operator\",\"description\":\"The operation to perform.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"ADD\",\"options\":{\"ADD\":\"+\",\"MULTIPLY\":\"*\",\"SUBTRACT\":\"-\",\"DIVIDE\":\"/\"},\"multivalued\":false}}},{\"_id\":\"8ab9f1aad4b4460a9c45d15fb148e221-1\",\"_rev\":\"1713151721\",\"serviceName\":\"8ab9f1aad4b4460a9c45d15fb148e221\",\"displayName\":\"Display State\",\"description\":\"Debug node that displays the shared and transient state of the journey for debugging purposes.\",\"outcomes\":[\"outcome\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n OUTCOME: \\\"outcome\\\"\\n};\\n\\nfunction main() {\\n if (!callbacks.isEmpty()) {\\n action.goTo(SCRIPT_OUTCOMES.OUTCOME);\\n return;\\n }\\n var keySet = nodeState.keys(); // Java Set\\n var keys = Array.from(keySet); // Make it into JavaScript array\\n debugState = {};\\n for (var i in keys) {\\n var k = new String(keys[i]);\\n var item = nodeState.get(k);\\n if (typeof item === \\\"object\\\") {\\n debugState[k] = nodeState.getObject(k);\\n } else {\\n debugState[k] = nodeState.get(k);\\n }\\n }\\n if (properties.displayFormat === \\\"JSON\\\") {\\n callbacksBuilder.textOutputCallback(0, `
${JSON.stringify(debugState, null, 2)}
`);\\n return;\\n }\\n callbacksBuilder.textOutputCallback(0, `${Array.from(Object.keys(debugState).map(k => ``))}
KeyValue
${k}
${debugState[k]}
`);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"debug\",\"testing\"],\"properties\":{\"displayFormat\":{\"title\":\"Display Format\",\"description\":\"The format in which to display the states.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"TABLE\",\"options\":{\"TABLE\":\"HTML Table\",\"JSON\":\"Raw JSON\"},\"multivalued\":false}}},{\"_id\":\"c605506774a848f7877b4d17a453bd39-1\",\"_rev\":\"1583432423\",\"serviceName\":\"c605506774a848f7877b4d17a453bd39\",\"displayName\":\"Has Session\",\"description\":\"Checks if the user has a current session.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n TRUE: 'True',\\n FALSE: 'False'\\n}\\n\\nfunction main() {\\n action.goTo(typeof existingSession === \\\"undefined\\\" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"utilities\"],\"properties\":{}},{\"_id\":\"session-1\",\"_rev\":\"1248028795\",\"serviceName\":\"session\",\"displayName\":\"Has Session AM\",\"description\":\"Checks if the user has a current session.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n TRUE: 'True',\\n FALSE: 'False'\\n}\\n\\nfunction main() {\\n action.goTo(typeof existingSession === \\\"undefined\\\" ? SCRIPT_OUTCOMES.FALSE : SCRIPT_OUTCOMES.TRUE);\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"utilities\"],\"properties\":{}},{\"_id\":\"c15e2efb3deb4d4ea338c74a6440b69f-1\",\"_rev\":\"-2034215288\",\"serviceName\":\"c15e2efb3deb4d4ea338c74a6440b69f\",\"displayName\":\"Vector ALU\",\"description\":\"Simple ALU that performs basic binary vector math operations. Outputs the result onto the shared state with key \\\"c\\\".\",\"outcomes\":[\"Success\"],\"outputs\":[\"c\"],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n SUCCESS: 'Success'\\n};\\n\\nvar OPERATORS = {\\n ADD: \\\"ADD\\\",\\n SUBTRACT: \\\"SUBTRACT\\\",\\n DOT: \\\"DOT\\\",\\n CROSS: \\\"CROSS\\\"\\n}\\n\\nfunction add(a, b) {\\n return a.map((v, i) => v + b[i]);\\n}\\n\\nfunction subtract(a, b) {\\n return a.map((v, i) => v - b[i]);\\n}\\n\\nfunction dot(a, b) {\\n return a.reduce((sum, v, i) => sum + v * b[i], 0);\\n}\\n\\nfunction cross(a, b) {\\n return [\\n a[1] * b[2] - a[2] * b[1],\\n a[2] * b[0] - a[0] * b[2],\\n a[0] * b[1] - a[1] * b[0]\\n ];\\n}\\n\\nfunction main() {\\n if (properties.a.length !== properties.b.length) throw new Error(\\\"Vectors not the same dimension.\\\");\\n switch (properties.operator) {\\n case OPERATORS.ADD:\\n nodeState.putShared(\\\"c\\\", add(properties.a, properties.b));\\n break;\\n case OPERATORS.SUBTRACT:\\n nodeState.putShared(\\\"c\\\", subtract(properties.a, properties.b));\\n break;\\n case OPERATORS.DOT:\\n nodeState.putShared(\\\"c\\\", dot(properties.a, properties.b));\\n break;\\n case OPERATORS.CROSS:\\n if (properties.a.length !== 3) throw new Error(\\\"Vectors not dimension 3 for cross product\\\");\\n nodeState.putShared(\\\"c\\\", cross(properties.a, properties.b));\\n break;\\n default: throw new Error(\\\"Unknown operator.\\\");\\n }\\n action.goTo(SCRIPT_OUTCOMES.SUCCESS);\\n}\\n\\nmain();\\n\",\"errorOutcome\":true,\"tags\":[\"math\",\"vector\",\"utilities\"],\"properties\":{\"a\":{\"title\":\"A\",\"description\":\"Left vector operand\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":[1,2,3],\"multivalued\":true},\"b\":{\"title\":\"B\",\"description\":\"Right vector operand\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":[4,5,6],\"multivalued\":true},\"operator\":{\"title\":\"Operator\",\"description\":\"The binary operation to perform on the vectors.\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"DOT\",\"options\":{\"ADD\":\"+\",\"CROSS\":\"X\",\"DOT\":\".\",\"SUBTRACT\":\"-\"},\"multivalued\":false}}},{\"_id\":\"e5ad0110c8ee4dafaae983003cd05d4a-1\",\"_rev\":\"573016413\",\"serviceName\":\"e5ad0110c8ee4dafaae983003cd05d4a\",\"displayName\":\"Generate JWT\",\"description\":\"Generate a signed JWT using the HMAC SHA-256 algorithm.\",\"outcomes\":[\"True\",\"False\"],\"outputs\":[],\"inputs\":[],\"script\":\"var aud = properties.audience;\\nvar iss = properties.issuer;\\nvar validity = properties.validity;\\nvar esv = properties.signingkey;\\n\\nvar signingkey = systemEnv.getProperty(esv);\\n\\nvar username = nodeState.get(\\\"username\\\");\\n\\nvar data = {\\n jwtType:\\\"SIGNED\\\",\\n jwsAlgorithm: \\\"HS256\\\",\\n issuer: iss,\\n subject: username,\\n audience: aud,\\n type: \\\"JWT\\\",\\n validityMinutes: validity,\\n signingKey: signingkey\\n};\\n\\nvar jwt = jwtAssertion.generateJwt(data);\\n\\nif (jwt !== null && jwt.length > 0) {\\n nodeState.putShared(\\\"assertionJwt\\\" , jwt);\\n action.goTo(\\\"True\\\");\\n} else {\\n action.goTo(\\\"False\\\");\\n}\\n\",\"errorOutcome\":true,\"tags\":[\"Utilities\",\"utilities\"],\"properties\":{\"audience\":{\"title\":\"Audience\",\"description\":\"The audience (aud) claim\",\"type\":\"STRING\",\"required\":true,\"multivalued\":false},\"issuer\":{\"title\":\"Issuer\",\"description\":\"The issuer (iss) claim\",\"type\":\"STRING\",\"required\":true,\"multivalued\":false},\"signingkey\":{\"title\":\"HMAC Signing Key\",\"description\":\"The secret label for the HMAC signing key\",\"type\":\"STRING\",\"required\":true,\"defaultValue\":\"esv.signing.key\",\"multivalued\":false},\"validity\":{\"title\":\"Validity (minutes)\",\"description\":\"\",\"type\":\"NUMBER\",\"required\":true,\"defaultValue\":5,\"multivalued\":false}}},{\"_id\":\"ef81b1a52c914710b3388caebfe7233a-1\",\"_rev\":\"1723458869\",\"serviceName\":\"ef81b1a52c914710b3388caebfe7233a\",\"displayName\":\"Display Callback\",\"description\":\"Displays custom callback to the page\",\"outcomes\":[\"outcome\"],\"outputs\":[],\"inputs\":[],\"script\":\"var SCRIPT_OUTCOMES = {\\n OUTCOME: 'outcome'\\n};\\n\\nvar CALLBACKS = {\\n\\tBOOLEAN_ATTRIBUTE_INPUT_CALLBACK: \\\"BOOLEAN_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tCHOICE_CALLBACK: \\\"CHOICE_CALLBACK\\\",\\n\\tCONFIRMATION_CALLBACK: \\\"CONFIRMATION_CALLBACK\\\",\\n\\tCONSENT_MAPPING_CALLBACK: \\\"CONSENT_MAPPING_CALLBACK\\\",\\n\\tDEVICE_PROFILE_CALLBACK: \\\"DEVICE_PROFILE_CALLBACK\\\",\\n\\tHIDDEN_VALUE_CALLBACK: \\\"HIDDEN_VALUE_CALLBACK\\\",\\n\\tHTTP_CALLBACK: \\\"HTTP_CALLBACK\\\",\\n\\tIDP_CALLBACK: \\\"IDP_CALLBACK\\\",\\n\\tKBA_CREATE_CALLBACK: \\\"KBA_CREATE_CALLBACK\\\",\\n\\tLANGUAGE_CALLBACK: \\\"LANGUAGE_CALLBACK\\\",\\n\\tMETADATA_CALLBACK: \\\"METADATA_CALLBACK\\\",\\n\\tNAME_CALLBACK: \\\"NAME_CALLBACK\\\",\\n\\tNUMBER_ATTRIBUTE_INPUT_CALLBACK: \\\"NUMBER_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tPASSWORD_CALLBACK: \\\"PASSWORD_CALLBACK\\\",\\n\\tPOLLING_WAIT_CALLBACK: \\\"POLLING_WAIT_CALLBACK\\\",\\n REDIRECT_CALLBACK: \\\"REDIRECT_CALLBACK\\\",\\n\\tSCRIPT_TEXT_OUTPUT_CALLBACK: \\\"SCRIPT_TEXT_OUTPUT_CALLBACK\\\",\\n\\tSELECT_IDP_CALLBACK: \\\"SELECT_IDP_CALLBACK\\\",\\n\\tSTRING_ATTRIBUTE_INPUT_CALLBACK: \\\"STRING_ATTRIBUTE_INPUT_CALLBACK\\\",\\n\\tSUSPENDED_TEXT_OUTPUT_CALLBACK: \\\"SUSPENDED_TEXT_OUTPUT_CALLBACK\\\",\\n\\tTERMS_AND_CONDITIONS_CALLBACK: \\\"TERMS_AND_CONDITIONS_CALLBACK\\\",\\n\\tTEXT_INPUT_CALLBACK: \\\"TEXT_INPUT_CALLBACK\\\",\\n\\tTEXT_OUTPUT_CALLBACK: \\\"TEXT_OUTPUT_CALLBACK\\\",\\n\\tVALIDATED_PASSWORD_CALLBACK: \\\"VALIDATED_PASSWORD_CALLBACK\\\",\\n\\tVALIDATED_USERNAME_CALLBACK: \\\"VALIDATED_USERNAME_CALLBACK\\\",\\n\\tX509_CERTIFICATE_CALLBACK: \\\"X509_CERTIFICATE_CALLBACK\\\"\\n}\\n\\nfunction isStringPresent(value) {\\n return value;\\n}\\n\\nfunction getString(value) {\\n return value || '';\\n}\\n\\nfunction isArrayPresent(value) {\\n return value;\\n}\\n\\nfunction getArray(value) {\\n return value ? JSON.parse(value) : [];\\n}\\n\\nfunction isObjectPresent(value) {\\n return value;\\n}\\n\\nfunction getObject(value) {\\n return value ? JSON.parse(value) : {};\\n}\\n\\nfunction isIntPresent(value) {\\n return value;\\n}\\n\\nfunction getInt(value) {\\n return value ? parseInt(value) : 0;\\n}\\n\\nfunction isDoublePresent(value) {\\n return value;\\n}\\n\\nfunction getDouble(value) {\\n return value ? parseFloat(value) : 0.0;\\n}\\n\\nfunction isBooleanPresent(value) {\\n return value;\\n}\\n\\nfunction getBoolean(value) {\\n return value ? value.toLowerCase() === 'true' : false;\\n}\\n\\nfunction setProperty(value) {\\n if (properties.sharedProperty) nodeState.putShared(properties.sharedProperty, value);\\n if (properties.transientProperty) nodeState.putTransient(properties.transientProperty, value);\\n if (properties.objectSharedProperty) {\\n var attributes = {};\\n attributes[properties.objectSharedProperty] = value;\\n nodeState.mergeShared({\\n objectAttributes: attributes\\n });\\n }\\n if (properties.objectTransientProperty) {\\n var attributes = {};\\n attributes[properties.objectTransientProperty] = value;\\n nodeState.mergeTransient({\\n objectAttributes: attributes\\n });\\n }\\n}\\n\\nfunction booleanAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getBoolean(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.booleanAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction choiceCallback() {\\n var prompt = getString(properties.options.prompt);\\n var choices = getArray(properties.options.choices);\\n var defaultChoice = getInt(properties.options.defaultChoice);\\n var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed);\\n callbacksBuilder.choiceCallback(prompt, choices, defaultChoice, multipleSelectionsAllowed);\\n}\\n\\nfunction confirmationCallback() {\\n var prompt = getString(properties.options.prompt);\\n var messageType = getInt(properties.options.messageType);\\n var options = getArray(properties.options.options);\\n var optionType = getInt(properties.options.optionType);\\n var defaultOption = getInt(properties.options.defaultOption);\\n if (isStringPresent(properties.options.prompt)) {\\n if (isIntPresent(properties.options.optionType)) {\\n callbacksBuilder.confirmationCallback(prompt, messageType, optionType, defaultOption);\\n } else {\\n callbacksBuilder.confirmationCallback(prompt, messageType, options, defaultOption);\\n }\\n } else {\\n if (isIntPresent(properties.options.optionType)) {\\n callbacksBuilder.confirmationCallback(messageType, optionType, defaultOption);\\n } else {\\n callbacksBuilder.confirmationCallback(messageType, options, defaultOption);\\n }\\n }\\n}\\n\\nfunction consentMappingCallback() {\\n var config = getObject(properties.options.config);\\n var message = getString(properties.options.message);\\n var isRequired = getBoolean(properties.options.isRequired);\\n var name = getString(properties.options.name);\\n var displayName = getString(properties.options.displayName);\\n var icon = getString(properties.options.icon);\\n var accessLevel = getString(properties.options.accessLevel);\\n var titles = getArray(properties.options.titles);\\n if (isObjectPresent(properties.options.prompt)) {\\n callbacksBuilder.consentMappingCallback(config, message, isRequired);\\n } else {\\n callbacksBuilder.consentMappingCallback(name, displayName, icon, accessLevel, titles, message, isRequired);\\n }\\n}\\n\\nfunction deviceProfileCallback() {\\n var metadata = getBoolean(properties.options.metadata);\\n var location = getBoolean(properties.options.location);\\n var message = getString(properties.options.message);\\n callbacksBuilder.deviceProfileCallback(metadata, location, message);\\n}\\n\\nfunction hiddenValueCallback() {\\n var id = getString(properties.options.id);\\n var value = getString(properties.options.value);\\n callbacksBuilder.hiddenValueCallback(id, value);\\n}\\n\\nfunction httpCallback() {\\n var authorizationHeader = getString(properties.options.authorizationHeader);\\n var negotiationHeader = getString(properties.options.negotiationHeader);\\n var authRHeader = getString(properties.options.authRHeader);\\n var negoName = getString(properties.options.negoName);\\n var negoValue = getString(properties.options.negoValue);\\n if (isStringPresent(properties.options.authorizationHeader) || isStringPresent(properties.options.negotiationHeader)) {\\n var errorCode = getString(properties.options.errorCode);\\n callbacksBuilder.httpCallback(authorizationHeader, negotiationHeader, errorCode);\\n } else {\\n var errorCode = getInt(properties.options.errorCode);\\n callbacksBuilder.httpCallback(authRHeader, negoName, negoValue, errorCode);\\n }\\n}\\n\\nfunction idPCallback() {\\n var provider = getString(properties.options.provider);\\n var clientId = getString(properties.options.clientId);\\n var redirectUri = getString(properties.options.redirectUri);\\n var scope = getArray(properties.options.scope);\\n var nonce = getString(properties.options.nonce);\\n var request = getString(properties.options.request);\\n var requestUri = getString(properties.options.requestUri);\\n var acrValues = getArray(properties.options.acrValues);\\n var requestNativeAppForUserInfo = getBoolean(properties.options.requestNativeAppForUserInfo);\\n var token = getString(properties.options.token);\\n var tokenType = getString(properties.options.tokenType);\\n if (isStringPresent(properties.options.token) || isStringPresent(properties.options.tokenType)) {\\n callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo, token, tokenType);\\n } else {\\n callbacksBuilder.idPCallback(provider, clientId, redirectUri, scope, nonce, request, requestUri, acrValues, requestNativeAppForUserInfo);\\n }\\n}\\n\\nfunction kbaCreateCallback() {\\n var prompt = getString(properties.options.prompt);\\n var predefinedQuestions = getArray(properties.options.predefinedQuestions);\\n var allowUserDefinedQuestions = getBoolean(properties.options.allowUserDefinedQuestions);\\n callbacksBuilder.kbaCreateCallback(prompt, predefinedQuestions, allowUserDefinedQuestions);\\n}\\n\\nfunction languageCallback() {\\n var language = getString(properties.options.language);\\n var country = getString(properties.options.country);\\n callbacksBuilder.languageCallback(language, country);\\n}\\n\\nfunction metadataCallback() {\\n var outputValue = getObject(properties.options.outputValue);\\n callbacksBuilder.metadataCallback(outputValue);\\n}\\n\\nfunction nameCallback() {\\n var prompt = getString(properties.options.prompt);\\n var defaultName = getString(properties.options.defaultName);\\n if (isStringPresent(properties.options.defaultName)) {\\n callbacksBuilder.nameCallback(prompt, defaultName);\\n } else {\\n callbacksBuilder.nameCallback(prompt);\\n }\\n}\\n\\nfunction numberAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getDouble(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.numberAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction passwordCallback() {\\n var prompt = getString(properties.options.prompt);\\n var echoOn = getBoolean(properties.options.echoOn);\\n callbacksBuilder.passwordCallback(prompt, echoOn);\\n}\\n\\nfunction pollingWaitCallback() {\\n var waitTime = getString(properties.options.waitTime);\\n var message = getString(properties.options.message);\\n callbacksBuilder.pollingWaitCallback(waitTime, message);\\n}\\n\\nfunction redirectCallback() {\\n throw new Error('Not Implemented');\\n}\\n\\nfunction scriptTextOutputCallback() {\\n var message = getString(properties.options.message);\\n callbacksBuilder.scriptTextOutputCallback(message);\\n}\\n\\nfunction selectIdPCallback() {\\n var providers = getObject(properties.options.providers);\\n callbacksBuilder.selectIdPCallback(providers);\\n}\\n\\nfunction stringAttributeInputCallback() {\\n var name = getString(properties.options.name);\\n var prompt = getString(properties.options.prompt);\\n var value = getString(properties.options.value);\\n var required = getBoolean(properties.options.required);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isBooleanPresent(properties.options.validateOnly) || isObjectPresent(properties.options.policies)) {\\n if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, policies, validateOnly);\\n }\\n } else if (isArrayPresent(failedPolicies)) {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required, failedPolicies);\\n } else {\\n callbacksBuilder.stringAttributeInputCallback(name, prompt, value, required);\\n }\\n}\\n\\nfunction suspendedTextOutputCallback() {\\n var messageType = getInt(properties.options.messageType);\\n var message = getString(properties.options.message);\\n callbacksBuilder.suspendedTextOutputCallback(messageType, message);\\n}\\n\\nfunction termsAndConditionsCallback() {\\n var version = getString(properties.options.version);\\n var terms = getString(properties.options.terms);\\n var createDate = getString(properties.options.createDate);\\n callbacksBuilder.termsAndConditionsCallback(version, terms, createDate);\\n}\\n\\nfunction textInputCallback() {\\n var prompt = getString(properties.options.prompt);\\n var defaultText = getString(properties.options.defaultText);\\n if (isStringPresent(properties.options.defaultText)) {\\n callbacksBuilder.textInputCallback(prompt, defaultText);\\n } else {\\n callbacksBuilder.textInputCallback(prompt);\\n }\\n}\\n\\nfunction textOutputCallback() {\\n var messageType = getString(properties.options.messageType);\\n var message = getString(properties.options.message);\\n callbacksBuilder.textOutputCallback(messageType, message);\\n}\\n\\nfunction validatedPasswordCallback() {\\n var prompt = getString(properties.options.prompt);\\n var echoOn = getBoolean(properties.options.echoOn);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isArrayPresent(properties.options.failedPolicies)) {\\n callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.validatedPasswordCallback(prompt, echoOn, policies, validateOnly);\\n }\\n}\\n\\nfunction validatedUsernameCallback() {\\n var prompt = getString(properties.options.prompt);\\n var policies = getObject(properties.options.policies);\\n var validateOnly = getBoolean(properties.options.validateOnly);\\n var failedPolicies = getArray(properties.options.failedPolicies);\\n if (isArrayPresent(properties.options.failedPolicies)) {\\n callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly, failedPolicies);\\n } else {\\n callbacksBuilder.validatedUsernameCallback(prompt, policies, validateOnly);\\n }\\n}\\n\\nfunction x509CertificateCallback() {\\n throw new Error('Not Implemented');\\n}\\n\\nfunction getBooleanAttributeInputCallback() {\\n setProperty(callbacks.getBooleanAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getChoiceCallback() {\\n var multipleSelectionsAllowed = getBoolean(properties.options.multipleSelectionsAllowed);\\n var selections = callbacks.getChoiceCallbacks().get(0);\\n setProperty(multipleSelectionsAllowed ? selections : selections[0]);\\n}\\n\\nfunction getConfirmationCallback() {\\n setProperty(callbacks.getConfirmationCallbacks().get(0));\\n}\\n\\nfunction getConsentMappingCallback() {\\n setProperty(callbacks.getConsentMappingCallbacks().get(0));\\n}\\n\\nfunction getDeviceProfileCallback() {\\n setProperty(callbacks.getDeviceProfileCallbacks().get(0));\\n}\\n\\nfunction getHiddenValueCallback() {\\n var id = getString(properties.options.id);\\n setProperty(callbacks.getHiddenValueCallbacks().get(id));\\n}\\n\\nfunction getHttpCallback() {\\n setProperty(callbacks.getHttpCallbacks().get(0));\\n}\\n\\nfunction getIdPCallback() {\\n setProperty(callbacks.getIdpCallbacks().get(0));\\n}\\n\\nfunction getKbaCreateCallback() {\\n setProperty(callbacks.getKbaCreateCallbacks().get(0));\\n}\\n\\nfunction getLanguageCallback() {\\n setProperty(callbacks.getLanguageCallbacks().get(0));\\n}\\n\\nfunction getNameCallback() {\\n setProperty(callbacks.getNameCallbacks().get(0));\\n}\\n\\nfunction getNumberAttributeInputCallback() {\\n setProperty(callbacks.getNumberAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getPasswordCallback() {\\n setProperty(callbacks.getPasswordCallbacks().get(0));\\n}\\n\\nfunction getSelectIdPCallback() {\\n setProperty(callbacks.getSelectIdPCallbacks().get(0));\\n}\\n\\nfunction getStringAttributeInputCallback() {\\n setProperty(callbacks.getStringAttributeInputCallbacks().get(0));\\n}\\n\\nfunction getTermsAndConditionsCallback() {\\n setProperty(callbacks.getTermsAndConditionsCallbacks().get(0));\\n}\\n\\nfunction getTextInputCallback() {\\n setProperty(callbacks.getTextInputCallbacks().get(0));\\n}\\n\\nfunction getValidatedPasswordCallback() {\\n setProperty(callbacks.getValidatedPasswordCallbacks().get(0));\\n}\\n\\nfunction getValidatedUsernameCallback() {\\n setProperty(callbacks.getValidatedUsernameCallbacks().get(0));\\n}\\n\\nfunction getX509CertificateCallback() {\\n setProperty(callbacks.getX509CertificateCallbacks().get(0));\\n}\\n\\nfunction main() {\\n if (!callbacks.isEmpty()) {\\n switch (properties.callback) {\\n case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: getBooleanAttributeInputCallback(); break;\\n case CALLBACKS.CHOICE_CALLBACK: getChoiceCallback(); break;\\n case CALLBACKS.CONFIRMATION_CALLBACK: getConfirmationCallback(); break;\\n case CALLBACKS.CONSENT_MAPPING_CALLBACK: getConsentMappingCallback(); break;\\n case CALLBACKS.DEVICE_PROFILE_CALLBACK: getDeviceProfileCallback(); break;\\n case CALLBACKS.HIDDEN_VALUE_CALLBACK: getHiddenValueCallback(); break;\\n case CALLBACKS.HTTP_CALLBACK: getHttpCallback(); break;\\n case CALLBACKS.IDP_CALLBACK: getIdPCallback(); break;\\n case CALLBACKS.KBA_CREATE_CALLBACK: getKbaCreateCallback(); break;\\n case CALLBACKS.LANGUAGE_CALLBACK: getLanguageCallback(); break;\\n case CALLBACKS.NAME_CALLBACK: getNameCallback(); break;\\n case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: getNumberAttributeInputCallback(); break;\\n case CALLBACKS.PASSWORD_CALLBACK: getPasswordCallback(); break;\\n case CALLBACKS.SELECT_IDP_CALLBACK: getSelectIdPCallback(); break;\\n case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: getStringAttributeInputCallback(); break;\\n case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: getTermsAndConditionsCallback(); break;\\n case CALLBACKS.TEXT_INPUT_CALLBACK: getTextInputCallback(); break;\\n case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: getValidatedPasswordCallback(); break;\\n case CALLBACKS.VALIDATED_USERNAME_CALLBACK: getValidatedUsernameCallback(); break;\\n case CALLBACKS.X509_CERTIFICATE_CALLBACK: getX509CertificateCallback(); break;\\n default: break;\\n }\\n action.goTo(SCRIPT_OUTCOMES.OUTCOME);\\n return;\\n }\\n\\n switch (properties.callback) {\\n case CALLBACKS.BOOLEAN_ATTRIBUTE_INPUT_CALLBACK: booleanAttributeInputCallback(); break;\\n case CALLBACKS.CHOICE_CALLBACK: choiceCallback(); break;\\n case CALLBACKS.CONFIRMATION_CALLBACK: confirmationCallback(); break;\\n case CALLBACKS.CONSENT_MAPPING_CALLBACK: consentMappingCallback(); break;\\n case CALLBACKS.DEVICE_PROFILE_CALLBACK: deviceProfileCallback(); break;\\n case CALLBACKS.HIDDEN_VALUE_CALLBACK: hiddenValueCallback(); break;\\n case CALLBACKS.HTTP_CALLBACK: httpCallback(); break;\\n case CALLBACKS.IDP_CALLBACK: idPCallback(); break;\\n case CALLBACKS.KBA_CREATE_CALLBACK: kbaCreateCallback(); break;\\n case CALLBACKS.LANGUAGE_CALLBACK: languageCallback(); break;\\n case CALLBACKS.METADATA_CALLBACK: metadataCallback(); break;\\n case CALLBACKS.NAME_CALLBACK: nameCallback(); break;\\n case CALLBACKS.NUMBER_ATTRIBUTE_INPUT_CALLBACK: numberAttributeInputCallback(); break;\\n case CALLBACKS.PASSWORD_CALLBACK: passwordCallback(); break;\\n case CALLBACKS.POLLING_WAIT_CALLBACK: pollingWaitCallback(); break;\\n case CALLBACKS.REDIRECT_CALLBACK: redirectCallback(); break;\\n case CALLBACKS.SCRIPT_TEXT_OUTPUT_CALLBACK: scriptTextOutputCallback(); break;\\n case CALLBACKS.SELECT_IDP_CALLBACK: selectIdPCallback(); break;\\n case CALLBACKS.STRING_ATTRIBUTE_INPUT_CALLBACK: stringAttributeInputCallback(); break;\\n case CALLBACKS.SUSPENDED_TEXT_OUTPUT_CALLBACK: suspendedTextOutputCallback(); break;\\n case CALLBACKS.TERMS_AND_CONDITIONS_CALLBACK: termsAndConditionsCallback(); break;\\n case CALLBACKS.TEXT_INPUT_CALLBACK: textInputCallback(); break;\\n case CALLBACKS.TEXT_OUTPUT_CALLBACK: textOutputCallback(); break;\\n case CALLBACKS.VALIDATED_PASSWORD_CALLBACK: validatedPasswordCallback(); break;\\n case CALLBACKS.VALIDATED_USERNAME_CALLBACK: validatedUsernameCallback(); break;\\n case CALLBACKS.X509_CERTIFICATE_CALLBACK: x509CertificateCallback(); break;\\n default: throw new Error('Unknown Callback'); // Should never reach this case\\n }\\n}\\n\\nmain();\\n\",\"errorOutcome\":false,\"tags\":[\"callback\",\"utilities\"],\"properties\":{\"callback\":{\"title\":\"Callback\",\"description\":\"The callback to display\",\"type\":\"STRING\",\"required\":true,\"options\":{\"METADATA_CALLBACK\":\"metadataCallback\",\"TERMS_AND_CONDITIONS_CALLBACK\":\"termsAndConditionsCallback\",\"NUMBER_ATTRIBUTE_INPUT_CALLBACK\":\"numberAttributeInputCallback\",\"TEXT_OUTPUT_CALLBACK\":\"textOutputCallback\",\"SCRIPT_TEXT_OUTPUT_CALLBACK\":\"scriptTextOutputCallback\",\"CONSENT_MAPPING_CALLBACK\":\"consentMappingCallback\",\"STRING_ATTRIBUTE_INPUT_CALLBACK\":\"stringAttributeInputCallback\",\"IDP_CALLBACK\":\"idPCallback\",\"VALIDATED_PASSWORD_CALLBACK\":\"validatedPasswordCallback\",\"SELECT_IDP_CALLBACK\":\"selectIdPCallback\",\"POLLING_WAIT_CALLBACK\":\"pollingWaitCallback\",\"NAME_CALLBACK\":\"nameCallback\",\"SUSPENDED_TEXT_OUTPUT_CALLBACK\":\"suspendedTextOutputCallback\",\"REDIRECT_CALLBACK\":\"redirectCallback\",\"X509_CERTIFICATE_CALLBACK\":\"x509CertificateCallback\",\"PASSWORD_CALLBACK\":\"passwordCallback\",\"TEXT_INPUT_CALLBACK\":\"textInputCallback\",\"BOOLEAN_ATTRIBUTE_INPUT_CALLBACK\":\"booleanAttributeInputCallback\",\"CONFIRMATION_CALLBACK\":\"confirmationCallback\",\"CHOICE_CALLBACK\":\"choiceCallback\",\"DEVICE_PROFILE_CALLBACK\":\"deviceProfileCallback\",\"HIDDEN_VALUE_CALLBACK\":\"hiddenValueCallback\",\"HTTP_CALLBACK\":\"httpCallback\",\"VALIDATED_USERNAME_CALLBACK\":\"validatedUsernameCallback\",\"KBA_CREATE_CALLBACK\":\"kbaCreateCallback\",\"LANGUAGE_CALLBACK\":\"languageCallback\"},\"multivalued\":false},\"objectSharedProperty\":{\"title\":\"Object Attributes Shared Property\",\"description\":\"The objectAttributes property on the shared state to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"objectTransientProperty\":{\"title\":\"Object Attributes Transient Property\",\"description\":\"The objectAttributes property on the transient state to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"options\":{\"title\":\"Options\",\"description\":\"The options containing the parameters for the callback (see documentation for possible parameters: https://docs.pingidentity.com/pingoneaic/latest/am-scripting/scripting-api-node.html#scripting-api-node-callbacks). \\n\\nFor example, for textOutputCallback, the options could be: { messageType: 0, message: \\\"Hello World!\\\" }. \\n\\nNote that for required parameters that are not specified in the options will use default values based on the type of the parameter (\\\"\\\" for Strings, [] for Arrays, {} for Objects, 0 for Ints, 0.0 for Doubles, and false for Booleans).\",\"type\":\"OBJECT\",\"required\":true,\"multivalued\":false},\"sharedProperty\":{\"title\":\"Shared State Property\",\"description\":\"The shared state property to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false},\"transientProperty\":{\"title\":\"Transient State Property\",\"description\":\"The transient state property to put the callback input into (if applicable)\",\"type\":\"STRING\",\"required\":false,\"multivalued\":false}}}],\"resultCount\":7,\"pagedResultsCookie\":null,\"totalPagedResultsPolicy\":\"EXACT\",\"totalPagedResults\":7,\"remainingPagedResults\":-1}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:38 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "transfer-encoding", + "value": "chunked" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "protocol=2.1,resource=1.0, resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 643, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:38.121Z", + "time": 8, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 8 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/oauth2_393036114/recording.har new file mode 100644 index 000000000..06d46a68f --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/custom-nodes_3091214966/0_D_n_m_3294969001/oauth2_393036114/recording.har @@ -0,0 +1,289 @@ +{ + "log": { + "_recordingName": "config-manager/pull/custom-nodes/0_D_n_m/oauth2", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "a684e2f67fd67a4263878c3124af167a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 365, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "content-length", + "value": "365" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 565, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&scope=fr:idm:* openid&response_type=code&client_id=idm-admin-ui&csrf=nqXBJnakFDlQfqJ63GeMDj28iqs.*AAJTSQACMDIAAlNLABw2QTg5aTl6bGlqNzhqamdMLzZZVU5wZDY5T3M9AAR0eXBlAANDVFMAAlMxAAIwMQ..*&decision=allow&code_challenge=MDXqt6c4KfHPoXHhjueJybxpVLf0f-IsIfeeHEqEnTo&code_challenge_method=S256" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/authorize" + }, + "response": { + "bodySize": 0, + "content": { + "mimeType": "text/plain", + "size": 0 + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + }, + { + "expires": "1970-01-01T00:00:00.000Z", + "httpOnly": true, + "name": "OAUTH_REQUEST_ATTRIBUTES", + "path": "/", + "sameSite": "none", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:38 GMT" + }, + { + "name": "content-length", + "value": "0" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "OAUTH_REQUEST_ATTRIBUTES=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; Secure; HttpOnly; SameSite=none" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "location", + "value": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=2EfmesXRo_rOB64xgZGI_Rpt7sk&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 673, + "httpVersion": "HTTP/1.1", + "redirectURL": "https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html?code=2EfmesXRo_rOB64xgZGI_Rpt7sk&iss=https%3A%2F%2Fplatform.dev.trivir.com%2Fam%2Foauth2&client_id=idm-admin-ui", + "status": 302, + "statusText": "Found" + }, + "startedDateTime": "2026-04-13T22:11:38.048Z", + "time": 20, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 20 + } + }, + { + "_id": "ff75519a93ccab829f8ee8cf5e92b49f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 224, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-2bbd1177-cbbd-4974-972a-04dbc344d69a" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-length", + "value": "224" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 424, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "client_id=idm-admin-ui&redirect_uri=https://platform.dev.trivir.com/platform/appAuthHelperRedirect.html&grant_type=authorization_code&code=2EfmesXRo_rOB64xgZGI_Rpt7sk&code_verifier=MCcQh-8Acvr7RnDUugNPSwsUPGwsjtKnrNXGI5Y1EDA" + }, + "queryString": [], + "url": "https://platform.dev.trivir.com/am/oauth2/access_token" + }, + "response": { + "bodySize": 1249, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1249, + "text": "{\"access_token\":\"\",\"scope\":\"openid fr:idm:*\",\"id_token\":\"\",\"token_type\":\"Bearer\",\"expires_in\":239}" + }, + "cookies": [ + { + "httpOnly": true, + "name": "route", + "path": "/am", + "secure": true, + "value": "" + } + ], + "headers": [ + { + "name": "date", + "value": "Mon, 13 Apr 2026 22:11:38 GMT" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1249" + }, + { + "name": "connection", + "value": "keep-alive" + }, + { + "_fromType": "array", + "name": "set-cookie", + "value": "route=; Path=/am; Secure; HttpOnly" + }, + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains" + } + ], + "headersSize": 405, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-13T22:11:38.076Z", + "time": 35, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 35 + } + } + ], + "pages": [], + "version": "1.2" + } +} From da988b81d8b54c09887e5d0c5bdf6430fcc3fb25 Mon Sep 17 00:00:00 2001 From: Devin Holderness Date: Thu, 19 Mar 2026 12:13:00 -0600 Subject: [PATCH 04/44] add missing help menus for config-manager commands --- ...-manager-export-oauth2-agents.test.js.snap | 34 +++++++++++++++++++ ...manager-export-org-privileges.test.js.snap | 28 +++++++++++++++ .../config-manager-export-test.test.js.snap | 25 ++++++++++++++ ...-manager-push-password-policy.test.js.snap | 28 +++++++++++++++ ...onfig-manager-export-oauth2-agents.test.js | 11 ++++++ ...nfig-manager-export-org-privileges.test.js | 11 ++++++ .../en/config-manager-export-test.test.js | 11 ++++++ ...onfig-manager-push-password-policy.test.js | 11 ++++++ 8 files changed, 159 insertions(+) create mode 100644 test/client_cli/en/__snapshots__/config-manager-export-oauth2-agents.test.js.snap create mode 100644 test/client_cli/en/__snapshots__/config-manager-export-org-privileges.test.js.snap create mode 100644 test/client_cli/en/__snapshots__/config-manager-export-test.test.js.snap create mode 100644 test/client_cli/en/__snapshots__/config-manager-push-password-policy.test.js.snap create mode 100644 test/client_cli/en/config-manager-export-oauth2-agents.test.js create mode 100644 test/client_cli/en/config-manager-export-org-privileges.test.js create mode 100644 test/client_cli/en/config-manager-export-test.test.js create mode 100644 test/client_cli/en/config-manager-push-password-policy.test.js diff --git a/test/client_cli/en/__snapshots__/config-manager-export-oauth2-agents.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-export-oauth2-agents.test.js.snap new file mode 100644 index 000000000..1d00ce07a --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-export-oauth2-agents.test.js.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config export' should be expected english 1`] = ` +"Usage: frodo config-manager pull oauth2-agents [options] [host] [realm] [username] [password] + +[Experimental] Export OAuth2 Agents + +Arguments: + host AM base URL, e.g.: + https://cdk.iam.example.com/am. To use a + connection profile, just specify a unique + substring or alias. + realm Realm. Specify realm as '/' for the root realm + or 'realm' or '/parent/child' otherwise. + (default: "alpha" for Identity Cloud tenants, + "/" otherwise.) + username Username to login with. Must be an admin user + with appropriate rights to manage + authentication journeys/trees. + password Password. + +Options: + -f, --file The OAUTH2_AGENTS_CONFIG json file. ex: + "/home/trivir/Documents/oauth2-agents.json", or + "oauth2-agents.json" + -n, --agent-name Export specific agent using agentId/agentName. + -r, --realm Specifies the realm to export from. Only the + agents from this realm will be exported. + -h, --help Help + -hh, --help-more Help with all options. + -hhh, --help-all Help with all options, environment variables, + and usage examples. +" +`; diff --git a/test/client_cli/en/__snapshots__/config-manager-export-org-privileges.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-export-org-privileges.test.js.snap new file mode 100644 index 000000000..88a732058 --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-export-org-privileges.test.js.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config export' should be expected english 1`] = ` +"Usage: frodo config-manager pull org-privileges [options] [host] [realm] [username] [password] + +[Experimental] Export organization privileges config. + +Arguments: + host AM base URL, e.g.: https://cdk.iam.example.com/am. To use + a connection profile, just specify a unique substring or + alias. + realm Realm. Specify realm as '/' for the root realm or 'realm' + or '/parent/child' otherwise. (default: "alpha" for + Identity Cloud tenants, "/" otherwise.) + username Username to login with. Must be an admin user with + appropriate rights to manage authentication + journeys/trees. + password Password. + +Options: + -r, --realm Specifies the realm to export from. Only the entity + object from this realm will be exported. + -h, --help Help + -hh, --help-more Help with all options. + -hhh, --help-all Help with all options, environment variables, and usage + examples. +" +`; diff --git a/test/client_cli/en/__snapshots__/config-manager-export-test.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-export-test.test.js.snap new file mode 100644 index 000000000..a204f2234 --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-export-test.test.js.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config export' should be expected english 1`] = ` +"Usage: frodo config-manager pull test [options] [host] [realm] [username] [password] + +[Experimental] Test connection and authentication. + +Arguments: + host AM base URL, e.g.: https://cdk.iam.example.com/am. To use a + connection profile, just specify a unique substring or + alias. + realm Realm. Specify realm as '/' for the root realm or 'realm' or + '/parent/child' otherwise. (default: "alpha" for Identity + Cloud tenants, "/" otherwise.) + username Username to login with. Must be an admin user with + appropriate rights to manage authentication journeys/trees. + password Password. + +Options: + -h, --help Help + -hh, --help-more Help with all options. + -hhh, --help-all Help with all options, environment variables, and usage + examples. +" +`; diff --git a/test/client_cli/en/__snapshots__/config-manager-push-password-policy.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-push-password-policy.test.js.snap new file mode 100644 index 000000000..91fc71757 --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-push-password-policy.test.js.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config-manager push password-policy' should be expected english 1`] = ` +"Usage: frodo config-manager push password-policy [options] [host] [realm] [username] [password] + +[Experimental] Import password-policy objects. + +Arguments: + host AM base URL, e.g.: https://cdk.iam.example.com/am. To use + a connection profile, just specify a unique substring or + alias. + realm Realm. Specify realm as '/' for the root realm or 'realm' + or '/parent/child' otherwise. (default: "alpha" for + Identity Cloud tenants, "/" otherwise.) + username Username to login with. Must be an admin user with + appropriate rights to manage authentication + journeys/trees. + password Password. + +Options: + -r, --realm Specifies the realm to Import from. Only the entity + object from this realm will be imported. + -h, --help Help + -hh, --help-more Help with all options. + -hhh, --help-all Help with all options, environment variables, and usage + examples. +" +`; diff --git a/test/client_cli/en/config-manager-export-oauth2-agents.test.js b/test/client_cli/en/config-manager-export-oauth2-agents.test.js new file mode 100644 index 000000000..0b280cce0 --- /dev/null +++ b/test/client_cli/en/config-manager-export-oauth2-agents.test.js @@ -0,0 +1,11 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager pull oauth2-agents --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config export' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); + diff --git a/test/client_cli/en/config-manager-export-org-privileges.test.js b/test/client_cli/en/config-manager-export-org-privileges.test.js new file mode 100644 index 000000000..f7603af4b --- /dev/null +++ b/test/client_cli/en/config-manager-export-org-privileges.test.js @@ -0,0 +1,11 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager pull org-privileges --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config export' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); + diff --git a/test/client_cli/en/config-manager-export-test.test.js b/test/client_cli/en/config-manager-export-test.test.js new file mode 100644 index 000000000..f6000671b --- /dev/null +++ b/test/client_cli/en/config-manager-export-test.test.js @@ -0,0 +1,11 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager pull test --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config export' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); + diff --git a/test/client_cli/en/config-manager-push-password-policy.test.js b/test/client_cli/en/config-manager-push-password-policy.test.js new file mode 100644 index 000000000..3dce1d7b4 --- /dev/null +++ b/test/client_cli/en/config-manager-push-password-policy.test.js @@ -0,0 +1,11 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager push password-policy --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config-manager push password-policy' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); + From 8d9ad61e47b9d07095a2aae7b56bbb614a5517be Mon Sep 17 00:00:00 2001 From: Devin Holderness Date: Fri, 27 Mar 2026 13:51:06 -0600 Subject: [PATCH 05/44] do not export scheduler objects provided by the API --- src/configManagerOps/FrConfigSchedulesOps.ts | 72 ++++++++++---------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/src/configManagerOps/FrConfigSchedulesOps.ts b/src/configManagerOps/FrConfigSchedulesOps.ts index e256ac66e..cc21e78f7 100644 --- a/src/configManagerOps/FrConfigSchedulesOps.ts +++ b/src/configManagerOps/FrConfigSchedulesOps.ts @@ -26,43 +26,45 @@ export async function configManagerExportSchedules( function processSchedules(schedules, fileDir, name?) { try { schedules.forEach((schedule) => { - const scheduleName = schedule._id.split('/')[1]; - if (name && name !== scheduleName) { - return; - } - const scheduleDir = `${fileDir}/${scheduleName}`; - const scriptFilename = `${scheduleName}.js`; - if ( - schedule.invokeService === 'script' && - schedule.invokeContext.script.source - ) { - extractFrConfigDataToFile( - schedule.invokeContext.script.source, - scriptFilename, - scheduleDir - ); - delete schedule.invokeContext.script.source; - schedule.invokeContext.script.file = `${scriptFilename}`; - } else if ( - schedule.invokeService === 'taskscanner' && - schedule.invokeContext.task.script.source - ) { - extractFrConfigDataToFile( - schedule.invokeContext.task.script.source, - scriptFilename, - scheduleDir + if (schedule._id !== 'scheduler') { + const scheduleName = schedule._id.split('/')[1]; + if (name && name !== scheduleName) { + return; + } + const scheduleDir = `${fileDir}/${scheduleName}`; + const scriptFilename = `${scheduleName}.js`; + if ( + schedule.invokeService === 'script' && + schedule.invokeContext.script.source + ) { + extractFrConfigDataToFile( + schedule.invokeContext.script.source, + scriptFilename, + scheduleDir + ); + delete schedule.invokeContext.script.source; + schedule.invokeContext.script.file = `${scriptFilename}`; + } else if ( + schedule.invokeService === 'taskscanner' && + schedule.invokeContext.task.script.source + ) { + extractFrConfigDataToFile( + schedule.invokeContext.task.script.source, + scriptFilename, + scheduleDir + ); + delete schedule.invokeContext.task.script.source; + schedule.invokeContext.task.script.file = `${scriptFilename}`; + } + + const scheduleFilename = `${scheduleDir}/${scheduleName}.json`; + saveJsonToFile( + schedule, + getFilePath(scheduleFilename, true), + false, + true ); - delete schedule.invokeContext.task.script.source; - schedule.invokeContext.task.script.file = `${scriptFilename}`; } - - const scheduleFilename = `${scheduleDir}/${scheduleName}.json`; - saveJsonToFile( - schedule, - getFilePath(scheduleFilename, true), - false, - true - ); }); } catch (err) { printError(err); From 80b5a8ef5d89c698efaf70f886063d6cd5d34044 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 17:50:41 +0000 Subject: [PATCH 06/44] Updated changelog and version for release v4.0.0-45 --- CHANGELOG.md | 5 ++++- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d763c49a8..373e79d3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [4.0.0-45] - 2026-04-17 + ## [4.0.0-44] - 2026-04-17 ## [4.0.0-43] - 2026-04-08 @@ -2251,7 +2253,8 @@ Frodo CLI 2.x automatically refreshes session and access tokens before they expi - Fixed problem with adding connection profiles - Miscellaneous bug fixes -[unreleased]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-44...HEAD +[unreleased]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-45...HEAD +[4.0.0-45]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-44...v4.0.0-45 [4.0.0-44]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-43...v4.0.0-44 [4.0.0-43]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-42...v4.0.0-43 [4.0.0-42]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-41...v4.0.0-42 diff --git a/package-lock.json b/package-lock.json index f23c2a485..ae8bad5a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-44", + "version": "4.0.0-45", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-44", + "version": "4.0.0-45", "license": "MIT", "bin": { "frodo": "dist/launch.cjs" diff --git a/package.json b/package.json index f13e71b8d..828400fee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-44", + "version": "4.0.0-45", "type": "module", "description": "A command line interface to manage ForgeRock Identity Cloud tenants, ForgeOps deployments, and classic deployments.", "keywords": [ From d62d94e362604e0ca81e33a5bb4a0c0877727879 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 14:18:53 +0000 Subject: [PATCH 07/44] Initial plan From 7c7280323fc2299250d4ea9056e80a63bc521673 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 14:23:32 +0000 Subject: [PATCH 08/44] feat: add label-driven release bumping and integration batching workflow Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/bffe9455-7b9b-4c6a-be31-736a197a8347 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 204 ++++++++++++++++++++++++ .github/workflows/pipeline.yml | 97 ++++++++--- docs/CONTRIBUTE.md | 6 +- docs/INTEGRATION.md | 46 ++++++ docs/PIPELINE.md | 27 ++-- 5 files changed, 346 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/integration-batch.yml create mode 100644 docs/INTEGRATION.md diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml new file mode 100644 index 000000000..16dbf9737 --- /dev/null +++ b/.github/workflows/integration-batch.yml @@ -0,0 +1,204 @@ +name: Integration Batch + +on: + workflow_dispatch: + inputs: + dry_run: + description: "If true, do not push integration branch, edit PR labels/comments, or create/update integration PR." + required: false + default: false + type: boolean + +permissions: + contents: write + pull-requests: write + +concurrency: + group: integration-batch + cancel-in-progress: false + +jobs: + build-integration: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Configure git identity + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Resolve dry-run flag + id: dryrun + run: | + DRY_RUN="${{ github.event.inputs.dry_run || 'false' }}" + echo "dry_run=$DRY_RUN" >> "$GITHUB_OUTPUT" + echo "Dry run: $DRY_RUN" + + - name: Select open integration-batch PRs + id: candidates + env: + GH_TOKEN: ${{ github.token }} + run: | + prs_json="$(gh pr list --state open --label integration-batch --json number,isDraft,title,labels --jq ' + map( + select(.isDraft == false) + | select((.labels | map(.name) | index("integrated")) | not) + ) + | sort_by(.number) + ')" + echo "prs_json=$prs_json" >> "$GITHUB_OUTPUT" + echo "candidate_count=$(echo "$prs_json" | jq 'length')" >> "$GITHUB_OUTPUT" + + - name: Filter to successful combined status + id: selected + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + run: | + prs_json='${{ steps.candidates.outputs.prs_json }}' + + selected='[]' + skipped='[]' + + for pr in $(echo "$prs_json" | jq -r '.[].number'); do + head_sha="$(gh pr view "$pr" --repo "$REPO" --json headRefOid --jq .headRefOid)" + state="$(gh api -H "Accept: application/vnd.github+json" "/repos/$REPO/commits/$head_sha/status" | jq -r '.state')" + title="$(echo "$prs_json" | jq -r ".[] | select(.number==$pr) | .title")" + + if [ "$state" = "success" ]; then + selected="$(echo "$selected" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t}]')" + else + skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" --arg s "$state" '. + [{"number":$n,"title":$t,"reason":"checks not successful","state":$s}]')" + fi + done + + echo "selected=$selected" >> "$GITHUB_OUTPUT" + echo "skipped=$skipped" >> "$GITHUB_OUTPUT" + + - name: Reset integration branch to main + run: | + git fetch origin main + git checkout -B integration origin/main + + - name: Merge selected PRs + id: merge + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + selected='${{ steps.selected.outputs.selected }}' + dry_run='${{ steps.dryrun.outputs.dry_run }}' + + merged='[]' + merge_skipped='[]' + + for pr in $(echo "$selected" | jq -r '.[].number'); do + title="$(echo "$selected" | jq -r ".[] | select(.number==$pr) | .title")" + + echo "::group::Attempt merge PR #$pr - $title" + git fetch origin "pull/$pr/head:pr-$pr" + + if git merge --no-ff "pr-$pr" -m "Merge PR #$pr: $title"; then + merged="$(echo "$merged" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t}]')" + + if [ "$dry_run" != "true" ]; then + gh pr edit "$pr" --repo "$REPO" \ + --remove-label integration-batch \ + --remove-label integration-failed \ + --add-label integrated || true + gh pr comment "$pr" --repo "$REPO" --body "Included in \`integration\` branch by automation.\n\nRun: $RUN_URL" || true + fi + else + git merge --abort || true + merge_skipped="$(echo "$merge_skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"merge conflict"}]')" + + if [ "$dry_run" != "true" ]; then + gh pr edit "$pr" --repo "$REPO" \ + --remove-label integration-batch \ + --add-label integration-failed || true + gh pr comment "$pr" --repo "$REPO" --body "Skipped from automated \`integration\` batch due to a merge conflict. Please rebase against \`main\`, resolve conflicts, and re-add label \`integration-batch\`.\n\nRun: $RUN_URL" || true + fi + fi + + echo "::endgroup::" + done + + echo "merged=$merged" >> "$GITHUB_OUTPUT" + echo "merge_skipped=$merge_skipped" >> "$GITHUB_OUTPUT" + + - name: Set up Node + uses: actions/setup-node@v6 + with: + node-version: 24 + cache: npm + + - name: Bump @rockcarver/frodo-lib to @next + run: | + npm install @rockcarver/frodo-lib@next --save-exact + npm ci + + if ! git diff --quiet; then + git add package.json package-lock.json + git commit -m "chore: bump @rockcarver/frodo-lib to @next" + else + echo "No dependency changes detected." + fi + + - name: Push integration branch + if: ${{ steps.dryrun.outputs.dry_run != 'true' }} + run: | + git push origin integration --force-with-lease + + - name: Create or update PR integration -> main + if: ${{ steps.dryrun.outputs.dry_run != 'true' }} + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + run: | + merged='${{ steps.merge.outputs.merged }}' + skipped_checks='${{ steps.selected.outputs.skipped }}' + skipped_merge='${{ steps.merge.outputs.merge_skipped }}' + + included_list="$(echo "$merged" | jq -r '.[] | "- #\(.number): \(.title)"')" + skipped_checks_list="$(echo "$skipped_checks" | jq -r '.[] | "- #\(.number): \(.title) (state: \(.state))"')" + skipped_merge_list="$(echo "$skipped_merge" | jq -r '.[] | "- #\(.number): \(.title)"')" + + body=$'This PR is auto-generated from PRs labeled `integration-batch`.\n\n' + body+=$'## Included\n' + body+="${included_list:-"- (none)"}" + body+=$'\n\n## Skipped (checks not successful)\n' + body+="${skipped_checks_list:-"- (none)"}" + body+=$'\n\n## Skipped (merge conflicts)\n' + body+="${skipped_merge_list:-"- (none)"}" + body+=$'\n\nAlso bumps `@rockcarver/frodo-lib` to `@next`.\n' + + existing="$(gh pr list --repo "$REPO" --state open --head integration --base main --json number --jq '.[0].number // empty')" + if [ -n "$existing" ]; then + gh pr edit "$existing" --repo "$REPO" --title "integration" --body "$body" + else + gh pr create --repo "$REPO" --head integration --base main --title "integration" --body "$body" + fi + + - name: Job summary + if: always() + run: | + echo "### Integration batch results" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "**Dry run:** ${{ steps.dryrun.outputs.dry_run }}" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + + echo "**Merged into integration:**" >> "$GITHUB_STEP_SUMMARY" + echo '${{ steps.merge.outputs.merged }}' | jq -r '.[] | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true + echo "" >> "$GITHUB_STEP_SUMMARY" + + echo "**Skipped (checks not successful):**" >> "$GITHUB_STEP_SUMMARY" + echo '${{ steps.selected.outputs.skipped }}' | jq -r '.[] | "- #\(.number): \(.title) (state: \(.state))"' >> "$GITHUB_STEP_SUMMARY" || true + echo "" >> "$GITHUB_STEP_SUMMARY" + + echo "**Skipped (merge conflicts):**" >> "$GITHUB_STEP_SUMMARY" + echo '${{ steps.merge.outputs.merge_skipped }}' | jq -r '.[] | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index f891ae2d6..a0c5249d6 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -50,31 +50,84 @@ jobs: - name: Install dependencies run: npm ci - - name: 'Prepare Version Bump' - id: version-bump - uses: 'phips28/gh-action-bump-version@master' - with: - major-wording: 'MAJOR RELEASE' - minor-wording: 'MINOR RELEASE' - patch-wording: 'PATCH RELEASE' - rc-wording: '' - tag-prefix: 'v' - default: prerelease - preid: '' - bump-policy: 'ignore' - skip-commit: 'true' - skip-tag: 'true' - skip-push: 'true' + - name: 'Determine Release Bump Type' + id: release-bump env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + SHA: ${{ github.sha }} + run: | + if [ "${{ github.event_name }}" != "push" ] || [ "${{ github.ref }}" != "refs/heads/main" ]; then + echo "bumpType=prerelease" >> "$GITHUB_OUTPUT" + exit 0 + fi + + prs="$(gh api -H "Accept: application/vnd.github+json" "/repos/$REPO/commits/$SHA/pulls")" + pr_count="$(echo "$prs" | jq 'length')" + if [ "$pr_count" -ne 1 ]; then + echo "::error::Expected exactly one associated PR for commit $SHA on main, found $pr_count." + exit 1 + fi + + release_labels="$(echo "$prs" | jq -r '.[0].labels[].name | select(. == "release:patch" or . == "release:minor" or . == "release:major")')" + label_count="$(echo "$release_labels" | sed '/^$/d' | wc -l | tr -d ' ')" + if [ "$label_count" -gt 1 ]; then + echo "::error::PR has multiple release labels. Use exactly one of release:patch, release:minor, release:major." + exit 1 + fi + if [ "$label_count" -eq 0 ]; then + echo "bumpType=prerelease" >> "$GITHUB_OUTPUT" + exit 0 + fi + + label="$(echo "$release_labels" | head -n 1)" + case "$label" in + "release:patch") echo "bumpType=patch" >> "$GITHUB_OUTPUT" ;; + "release:minor") echo "bumpType=minor" >> "$GITHUB_OUTPUT" ;; + "release:major") echo "bumpType=major" >> "$GITHUB_OUTPUT" ;; + *) echo "::error::Unsupported release label: $label"; exit 1 ;; + esac + + - name: 'Apply Version Bump' + id: version-bump + run: | + current_version="$(node -p "require('./package.json').version")" + bump_type="${{ steps.release-bump.outputs.bumpType }}" + if [ -z "$bump_type" ]; then + echo "::error::Missing bump type." + exit 1 + fi + + case "$bump_type" in + prerelease) + new_version="$(node -p "require('semver').inc('$current_version','prerelease')")" + ;; + patch|minor|major) + new_version="$(node -p "require('semver').inc('$current_version','$bump_type')")" + ;; + *) + echo "::error::Unsupported bump type: $bump_type" + exit 1 + ;; + esac + + if [ -z "$new_version" ] || [ "$new_version" = "null" ]; then + echo "::error::Failed to compute new version from $current_version using bump type $bump_type." + exit 1 + fi + + npm version "$new_version" --no-git-tag-version --allow-same-version + echo "newTag=v$new_version" >> "$GITHUB_OUTPUT" + echo "newVersion=$new_version" >> "$GITHUB_OUTPUT" + if echo "$new_version" | grep -q '-'; then + echo "preRelease=true" >> "$GITHUB_OUTPUT" + else + echo "preRelease=false" >> "$GITHUB_OUTPUT" + fi - name: Update package-log.json after version bump run: npm i --package-lock-only - - name: 'Version From Tag' - id: version-from-tag - run: echo "version=$(echo '${{ steps.version-bump.outputs.newTag }}' | sed 's/v//')" >> "$GITHUB_OUTPUT" - - name: Build frodo-cli run: | npm run build @@ -98,8 +151,8 @@ jobs: outputs: newTag: ${{ steps.version-bump.outputs.newTag }} - newVersion: ${{ steps.version-from-tag.outputs.version }} - preRelease: ${{ contains(steps.version-bump.outputs.newTag, '-') }} + newVersion: ${{ steps.version-bump.outputs.newVersion }} + preRelease: ${{ steps.version-bump.outputs.preRelease }} test: name: 'Test' diff --git a/docs/CONTRIBUTE.md b/docs/CONTRIBUTE.md index 0eebb2772..89cfc888a 100644 --- a/docs/CONTRIBUTE.md +++ b/docs/CONTRIBUTE.md @@ -17,7 +17,7 @@ OR ### Prerequisites -- Node.js 18 or later, 20 or 22 recommended +- Node.js 20 or later (Node.js 24 recommended) - npm (included with Node.js) - A GUI editor is highly recommended. The current developers use [VSCode](https://code.visualstudio.com/), but you are welcome to others, like [Atom](https://atom.io/) or [Sublime](https://www.sublimetext.com/) too. The repository contains configuration files for VSCode's [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [prettier](https://prettier.io/) add-ons, which will automatically lint the code and apply coding styles when using VSCode. The same files may work for other editors with similar add-ons, but this has not been tested. @@ -99,6 +99,10 @@ npm run lint npm test ``` +## Integration batching + +Maintainers can batch eligible PRs into the `integration` branch using the [`integration-batch` workflow](../.github/workflows/integration-batch.yml). See [INTEGRATION.md](./INTEGRATION.md) for label semantics and workflow behavior. + ### Code structure and conventions Frodo CLI adheres to the following folder and file structure: diff --git a/docs/INTEGRATION.md b/docs/INTEGRATION.md new file mode 100644 index 000000000..203828a73 --- /dev/null +++ b/docs/INTEGRATION.md @@ -0,0 +1,46 @@ +# Integration Batching Workflow + +The [`integration-batch` workflow](../.github/workflows/integration-batch.yml) automates integration branch preparation by batching selected pull requests. + +## Labels + +- `integration-batch`: PR is queued for integration batching. +- `integrated`: PR was successfully merged into the `integration` branch by automation. +- `integration-failed`: automation attempted integration but hit a merge conflict. + +## Selection rules + +The workflow selects PRs that are: + +- open +- non-draft +- labeled `integration-batch` +- not labeled `integrated` +- in a `success` combined status state for the PR head SHA + +## Merge behavior + +Each run rebuilds `integration` from `main`, then attempts merge commits (`git merge --no-ff`) for selected PRs. + +- On successful merge: + - remove `integration-batch` + - remove `integration-failed` (if present) + - add `integrated` + - add a comment including the run URL +- On merge conflict: + - abort merge + - remove `integration-batch` + - add `integration-failed` + - add a comment asking the author to rebase and re-add `integration-batch` + +After merges, the workflow updates `@rockcarver/frodo-lib` to `@next`, commits lockfile changes when needed, pushes `integration`, and creates or updates an `integration -> main` PR titled `integration`. + +## Dry run mode + +When manually triggered, set `dry_run=true` to simulate batching without side effects: + +- does not push `integration` +- does not create/update the integration PR +- does not edit labels or post PR comments + +The workflow still computes candidate PRs and attempts merges locally so maintainers can validate batchability before a real run. diff --git a/docs/PIPELINE.md b/docs/PIPELINE.md index d87eb4274..34f15048a 100644 --- a/docs/PIPELINE.md +++ b/docs/PIPELINE.md @@ -12,13 +12,18 @@ This information is only actionable if you are an active contributor or maintain Frodo CLI adopted the principle of continuous integration. Therefore every push to the main branch in the [rockcarver/frodo-cli] repository triggers the automated release pipeline. -The pipeline determines the type of release - `prerelease`, `patch`, `minor`, `major` - for the push: - -- Scans the commit and PR comments for trigger phrases: - - `PATCH RELEASE` triggers a `patch` release - - `MINOR RELEASE` triggers a `minor` release - - `MAJOR RELEASE` triggers a `major` release - - Everything else triggers a `prerelease` +The pipeline determines the type of release - `prerelease`, `patch`, `minor`, `major` - for the push by looking up the pull request associated with the merged commit on `main`: + +- Uses exactly one merged PR associated with the pushed commit SHA. +- Uses PR labels: + - `release:patch` triggers a `patch` release + - `release:minor` triggers a `minor` release + - `release:major` triggers a `major` release + - No release label triggers a `prerelease` +- Fails if: + - no PR (direct push to `main`) is associated with the commit + - more than one PR is associated with the commit + - more than one `release:*` label is present on the merged PR - Bumps the version accordingly:
``.``.``-`` - Updates the [changelog](../CHANGELOG.md) file in [keep a changelog](https://keepachangelog.com/en/1.0.0/) format: @@ -27,11 +32,11 @@ The pipeline determines the type of release - `prerelease`, `patch`, `minor`, `m - Adds release details links ❗❗❗ IMPORTANT ❗❗❗
-Contributors are instructed to submit pull requests. Maintainers must make sure none of the commit comments nor the PR comment contain trigger phrases that would cause the pipeline to perform an undesired version bump and release. +Contributors are instructed to submit pull requests. Direct pushes to `main` are not supported by the automated release version-selection logic and will fail. ### Automatic Pre-Releases During Iterative Development -The default release type (if no specific and exact trigger phrases are used) results in a pre-release. Pre-releases are flagged with the label `Pre-release` on the [release page](../releases) indicating to users that these releases are not considered final or complete. +The default release type (if no specific release label is present) results in a pre-release. Pre-releases are flagged with the label `Pre-release` on the [release page](../releases) indicating to users that these releases are not considered final or complete. Pre-releases are a great way to publish the latest and greatest functionality but they are not fully polished, readme and changelog might not be updated and test coverage might not be complete. @@ -39,7 +44,7 @@ Pre-releases are a great way to publish the latest and greatest functionality bu Maintainers must validate PRs contain an updated `Unreleased` section in the[changelog](../CHANGELOG.md) before merging any PR. Changelog entries must adhere to the [keep a changelog](https://keepachangelog.com/en/1.0.0/) format. -Maintainers must use an appropriate trigger phrase (see: [Every Push Triggers A Release](#Every-Push-Triggers-A-Release)) in the PR title to trigger the appropriate automated version bump and release. +Maintainers must add an appropriate release label (see: [Every Push Triggers A Release](#Every-Push-Triggers-A-Release)) to the PR before merge to trigger the automated version bump and release. ❗❗❗ IMPORTANT ❗❗❗
Maintainers must adhere to the [guidelines set forth by the npm project](https://docs.npmjs.com/about-semantic-versioning#incrementing-semantic-versions-in-published-packages) to determine the appropriate release type: @@ -112,7 +117,7 @@ So to recover from that, the following needs to happen: - [package-lock.json](../package-lock.json) - Find the 2 occurances of the faulty version in package-lock.json and reset them to the `previous version` from before the faulty version bump 3. Commit your changes and create a new pull request -4. In the frodo repository, merge the PR and provide the appropriate comment to trigger the intended version bump +4. In the frodo repository, merge the PR and provide the appropriate release label (`release:patch`, `release:minor`, or `release:major`) to trigger the intended version bump 5. Remove the faulty release from npmjs.com This is important as without this step the faulty release will remain published on [npmjs.com](https://www.npmjs.com/package/@rockcarver/frodo-cli) (npm registry). - You must be a maintainer of the package on npmjs.com. From 1e3af6bd8e875178445a2c8ede3afd8f8601c006 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 14:24:52 +0000 Subject: [PATCH 09/44] chore: address workflow/docs review nits Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/bffe9455-7b9b-4c6a-be31-736a197a8347 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/workflows/pipeline.yml | 4 ++-- docs/PIPELINE.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index a0c5249d6..31c554da0 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -44,7 +44,7 @@ jobs: node-version: ${{ env.NODE_VERSION }} cache: 'npm' - - name: Update package-log.json before version bump + - name: Update package-lock.json before version bump run: npm i --package-lock-only - name: Install dependencies @@ -125,7 +125,7 @@ jobs: echo "preRelease=false" >> "$GITHUB_OUTPUT" fi - - name: Update package-log.json after version bump + - name: Update package-lock.json after version bump run: npm i --package-lock-only - name: Build frodo-cli diff --git a/docs/PIPELINE.md b/docs/PIPELINE.md index 34f15048a..6c207a7a7 100644 --- a/docs/PIPELINE.md +++ b/docs/PIPELINE.md @@ -42,7 +42,7 @@ Pre-releases are a great way to publish the latest and greatest functionality bu ### Triggering Patch, Minor, and Major Releases -Maintainers must validate PRs contain an updated `Unreleased` section in the[changelog](../CHANGELOG.md) before merging any PR. Changelog entries must adhere to the [keep a changelog](https://keepachangelog.com/en/1.0.0/) format. +Maintainers must validate PRs contain an updated `Unreleased` section in the [changelog](../CHANGELOG.md) before merging any PR. Changelog entries must adhere to the [keep a changelog](https://keepachangelog.com/en/1.0.0/) format. Maintainers must add an appropriate release label (see: [Every Push Triggers A Release](#Every-Push-Triggers-A-Release)) to the PR before merge to trigger the automated version bump and release. From d91603d93d64da245795f717b862c7fc7e8a80bf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 15:51:27 +0000 Subject: [PATCH 10/44] Initial plan From 75e5f783a1bd0f17f501a827a1a11856aebbd0b8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 15:54:44 +0000 Subject: [PATCH 11/44] fix: emit compact JSON outputs in integration-batch workflow Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/5d4695f5-a682-4fa4-a600-c6fadb110d31 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index 16dbf9737..6377c9ad5 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -50,7 +50,7 @@ jobs: ) | sort_by(.number) ')" - echo "prs_json=$prs_json" >> "$GITHUB_OUTPUT" + echo "prs_json=$(echo "$prs_json" | jq -c .)" >> "$GITHUB_OUTPUT" echo "candidate_count=$(echo "$prs_json" | jq 'length')" >> "$GITHUB_OUTPUT" - name: Filter to successful combined status @@ -76,8 +76,8 @@ jobs: fi done - echo "selected=$selected" >> "$GITHUB_OUTPUT" - echo "skipped=$skipped" >> "$GITHUB_OUTPUT" + echo "selected=$(echo "$selected" | jq -c .)" >> "$GITHUB_OUTPUT" + echo "skipped=$(echo "$skipped" | jq -c .)" >> "$GITHUB_OUTPUT" - name: Reset integration branch to main run: | @@ -128,8 +128,8 @@ jobs: echo "::endgroup::" done - echo "merged=$merged" >> "$GITHUB_OUTPUT" - echo "merge_skipped=$merge_skipped" >> "$GITHUB_OUTPUT" + echo "merged=$(echo "$merged" | jq -c .)" >> "$GITHUB_OUTPUT" + echo "merge_skipped=$(echo "$merge_skipped" | jq -c .)" >> "$GITHUB_OUTPUT" - name: Set up Node uses: actions/setup-node@v6 From 7dfc342207ce1be31c691679b2b81cc3fd78a491 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 16:36:31 +0000 Subject: [PATCH 12/44] Initial plan From 8e4c80ecc77168a74184b30098858af7c9cbc92d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 16:40:02 +0000 Subject: [PATCH 13/44] fix: use check-runs criteria for integration batch selection Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/005ec6e7-444c-4e13-830e-e6318832b0f5 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 26 ++++++++++++++++--------- docs/INTEGRATION.md | 4 +++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index 6377c9ad5..f91d270fc 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -53,7 +53,7 @@ jobs: echo "prs_json=$(echo "$prs_json" | jq -c .)" >> "$GITHUB_OUTPUT" echo "candidate_count=$(echo "$prs_json" | jq 'length')" >> "$GITHUB_OUTPUT" - - name: Filter to successful combined status + - name: Filter to successful check runs id: selected env: GH_TOKEN: ${{ github.token }} @@ -66,13 +66,21 @@ jobs: for pr in $(echo "$prs_json" | jq -r '.[].number'); do head_sha="$(gh pr view "$pr" --repo "$REPO" --json headRefOid --jq .headRefOid)" - state="$(gh api -H "Accept: application/vnd.github+json" "/repos/$REPO/commits/$head_sha/status" | jq -r '.state')" + checks_json="$(gh api -H "Accept: application/vnd.github+json" "/repos/$REPO/commits/$head_sha/check-runs")" title="$(echo "$prs_json" | jq -r ".[] | select(.number==$pr) | .title")" - if [ "$state" = "success" ]; then - selected="$(echo "$selected" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t}]')" + total_count="$(echo "$checks_json" | jq -r '.total_count')" + pending_count="$(echo "$checks_json" | jq '[.check_runs[] | select(.status != "completed")] | length')" + bad_conclusion_count="$(echo "$checks_json" | jq '[.check_runs[] | select(.status == "completed") | select(.conclusion != "success" and .conclusion != "skipped" and .conclusion != "neutral")] | length')" + + if [ "$total_count" -eq 0 ]; then + skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"no check runs found"}]')" + elif [ "$pending_count" -gt 0 ]; then + skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"checks pending"}]')" + elif [ "$bad_conclusion_count" -gt 0 ]; then + skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"checks not successful"}]')" else - skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" --arg s "$state" '. + [{"number":$n,"title":$t,"reason":"checks not successful","state":$s}]')" + selected="$(echo "$selected" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t}]')" fi done @@ -165,13 +173,13 @@ jobs: skipped_merge='${{ steps.merge.outputs.merge_skipped }}' included_list="$(echo "$merged" | jq -r '.[] | "- #\(.number): \(.title)"')" - skipped_checks_list="$(echo "$skipped_checks" | jq -r '.[] | "- #\(.number): \(.title) (state: \(.state))"')" + skipped_checks_list="$(echo "$skipped_checks" | jq -r '.[] | "- #\(.number): \(.title) (\(.reason))"')" skipped_merge_list="$(echo "$skipped_merge" | jq -r '.[] | "- #\(.number): \(.title)"')" body=$'This PR is auto-generated from PRs labeled `integration-batch`.\n\n' body+=$'## Included\n' body+="${included_list:-"- (none)"}" - body+=$'\n\n## Skipped (checks not successful)\n' + body+=$'\n\n## Skipped (checks)\n' body+="${skipped_checks_list:-"- (none)"}" body+=$'\n\n## Skipped (merge conflicts)\n' body+="${skipped_merge_list:-"- (none)"}" @@ -196,8 +204,8 @@ jobs: echo '${{ steps.merge.outputs.merged }}' | jq -r '.[] | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true echo "" >> "$GITHUB_STEP_SUMMARY" - echo "**Skipped (checks not successful):**" >> "$GITHUB_STEP_SUMMARY" - echo '${{ steps.selected.outputs.skipped }}' | jq -r '.[] | "- #\(.number): \(.title) (state: \(.state))"' >> "$GITHUB_STEP_SUMMARY" || true + echo "**Skipped (checks):**" >> "$GITHUB_STEP_SUMMARY" + echo '${{ steps.selected.outputs.skipped }}' | jq -r '.[] | "- #\(.number): \(.title) (\(.reason))"' >> "$GITHUB_STEP_SUMMARY" || true echo "" >> "$GITHUB_STEP_SUMMARY" echo "**Skipped (merge conflicts):**" >> "$GITHUB_STEP_SUMMARY" diff --git a/docs/INTEGRATION.md b/docs/INTEGRATION.md index 203828a73..d6efd365a 100644 --- a/docs/INTEGRATION.md +++ b/docs/INTEGRATION.md @@ -16,7 +16,9 @@ The workflow selects PRs that are: - non-draft - labeled `integration-batch` - not labeled `integrated` -- in a `success` combined status state for the PR head SHA +- with check runs present for the PR head SHA +- with all check runs in `completed` status +- with all completed check runs concluded as `success`, `skipped`, or `neutral` ## Merge behavior From 3ddfccb8cf290949239bee049ae0f3ea51eaf940 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 16:40:43 +0000 Subject: [PATCH 14/44] chore: harden check-runs parsing in integration workflow Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/005ec6e7-444c-4e13-830e-e6318832b0f5 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index f91d270fc..e2fba5b54 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -70,8 +70,8 @@ jobs: title="$(echo "$prs_json" | jq -r ".[] | select(.number==$pr) | .title")" total_count="$(echo "$checks_json" | jq -r '.total_count')" - pending_count="$(echo "$checks_json" | jq '[.check_runs[] | select(.status != "completed")] | length')" - bad_conclusion_count="$(echo "$checks_json" | jq '[.check_runs[] | select(.status == "completed") | select(.conclusion != "success" and .conclusion != "skipped" and .conclusion != "neutral")] | length')" + pending_count="$(echo "$checks_json" | jq '[.check_runs // [] | .[] | select(.status != "completed")] | length')" + bad_conclusion_count="$(echo "$checks_json" | jq '[.check_runs // [] | .[] | select(.status == "completed" and .conclusion != "success" and .conclusion != "skipped" and .conclusion != "neutral")] | length')" if [ "$total_count" -eq 0 ]; then skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"no check runs found"}]')" From 0a790fb5cca906b852dc0a66a7278ed499beec11 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 19:57:25 +0000 Subject: [PATCH 15/44] Initial plan From ee718fbd42e1a81f704067df7c67a87ff6977329 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:05:46 +0000 Subject: [PATCH 16/44] feat: automate integration batch merge conflict recovery Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/b6757a0d-dff7-4f92-a696-e8ddfcfc9c9a Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 290 ++++++++++++++++++ .github/integration/union-allowlist-extra.txt | 3 + .github/integration/union-blocklist.txt | 3 + .github/workflows/integration-batch.yml | 118 ++++--- docs/INTEGRATION.md | 15 +- 5 files changed, 381 insertions(+), 48 deletions(-) create mode 100755 .github/integration/scripts/merge_prs.sh create mode 100644 .github/integration/union-allowlist-extra.txt create mode 100644 .github/integration/union-blocklist.txt diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh new file mode 100755 index 000000000..c76c7d661 --- /dev/null +++ b/.github/integration/scripts/merge_prs.sh @@ -0,0 +1,290 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +INTEGRATION_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +ALLOWLIST_EXTRA_FILE="$INTEGRATION_DIR/union-allowlist-extra.txt" +BLOCKLIST_FILE="$INTEGRATION_DIR/union-blocklist.txt" + +PRS_JSON='[]' +PRS_LIST='' +DRY_RUN='false' +REPO='' + +usage() { + cat <&2 + usage >&2 + exit 1 + ;; + esac +done + +if [ -n "$PRS_LIST" ]; then + PRS_JSON="$(echo "$PRS_LIST" | jq -Rc 'split(" ") | map(select(length > 0)) | map({number:(tonumber)})')" +fi + +# Validate JSON shape. +PRS_JSON="$(echo "$PRS_JSON" | jq -c 'if type=="array" then . else error("prs-json must be an array") end')" +DRY_RUN="$(echo "$DRY_RUN" | tr '[:upper:]' '[:lower:]')" + +if [ -z "$REPO" ]; then + if git remote get-url origin >/dev/null 2>&1; then + REPO="$(git remote get-url origin | sed -E 's#.*github.com[:/]([^/]+/[^/.]+)(\.git)?$#\1#')" + fi +fi + +declare -A union_allowlist=() + +auto_detect_union_allowlist() { + while IFS= read -r file; do + [ -f "$file" ] || continue + if grep -Fq 'const program = new FrodoStubCommand(' "$file" && ! grep -Fq 'const program = new FrodoCommand(' "$file"; then + union_allowlist["$file"]=1 + fi + done < <(git ls-files 'src/cli/**') +} + +apply_exception_file() { + local file="$1" + local mode="$2" + [ -f "$file" ] || return 0 + + while IFS= read -r line || [ -n "$line" ]; do + line="${line%%#*}" + line="$(echo "$line" | sed -E 's/^\s+|\s+$//g')" + [ -n "$line" ] || continue + if [ "$mode" = "add" ]; then + union_allowlist["$line"]=1 + else + unset "union_allowlist[$line]" + fi + done < "$file" +} + +configure_union_attributes() { + local attributes_file=".git/info/attributes" + touch "$attributes_file" + { + echo "" + echo "# integration-batch union allowlist" + for file in "${!union_allowlist[@]}"; do + echo "$file merge=union" + done | sort + echo "# end integration-batch union allowlist" + } >> "$attributes_file" + + git config merge.union.driver true +} + +is_snapshot_path() { + local path="$1" + [[ "$path" == *.snap ]] || [[ "$path" == *"/__snapshots__/"* ]] +} + +is_snapshot_or_allowed_extra_conflict() { + local path="$1" + is_snapshot_path "$path" || [ "$path" = "package-lock.json" ] +} + +contains_conflict_markers() { + local file="$1" + grep -nE '<<<<<<<|=======|>>>>>>>' "$file" >/dev/null 2>&1 +} + +to_json_array() { + if [ "$#" -eq 0 ]; then + echo '[]' + return + fi + printf '%s\n' "$@" | jq -R . | jq -s . +} + +derive_snapshot_pattern() { + local path="$1" + local name + name="$(basename "$path")" + name="${name%.snap}" + name="$(echo "$name" | sed -E 's/\.(e2e\.)?(test|spec)\.js$//')" + echo "$name" +} + +auto_detect_union_allowlist +apply_exception_file "$ALLOWLIST_EXTRA_FILE" add +apply_exception_file "$BLOCKLIST_FILE" remove +configure_union_attributes + +merged='[]' +skipped='[]' +auto_resolved_conflicts='[]' +snapshot_patterns_global='[]' +snapshot_files_global='[]' +npm_ci_done='false' + +for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do + title="$(echo "$PRS_JSON" | jq -r ".[] | select(.number==$pr) | .title // \"\"")" + branch="$(echo "$PRS_JSON" | jq -r ".[] | select(.number==$pr) | .branch // \"\"")" + + if [ -z "$title" ] && [ -n "$REPO" ]; then + title="$(gh pr view "$pr" --repo "$REPO" --json title --jq .title 2>/dev/null || echo "")" + fi + + if [ -n "$branch" ]; then + git fetch origin "$branch:pr-$pr" + else + git fetch origin "pull/$pr/head:pr-$pr" + fi + + safe_title="$(printf '%s' "$title" | tr '\n' ' ')" + + if git merge --no-ff "pr-$pr" -m "Merge PR #$pr: $safe_title"; then + merged="$(echo "$merged" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t}]')" + continue + fi + + mapfile -t conflicted_files < <(git diff --name-only --diff-filter=U) + if [ "${#conflicted_files[@]}" -eq 0 ]; then + git merge --abort || true + skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"merge failed without conflicted files"}]')" + continue + fi + + all_union='true' + all_snapshot='true' + snapshot_conflicts=() + + for file in "${conflicted_files[@]}"; do + if [ -z "${union_allowlist[$file]+x}" ]; then + all_union='false' + fi + + if is_snapshot_or_allowed_extra_conflict "$file"; then + if is_snapshot_path "$file"; then + snapshot_conflicts+=("$file") + fi + else + all_snapshot='false' + fi + done + + if [ "$all_union" = 'true' ]; then + has_marker='false' + for file in "${conflicted_files[@]}"; do + if [ -f "$file" ] && contains_conflict_markers "$file"; then + has_marker='true' + break + fi + git add "$file" + done + + if [ "$has_marker" = 'true' ]; then + git merge --abort || true + skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"union allowlist conflict still contains markers"}]')" + continue + fi + + git commit --no-edit + merged="$(echo "$merged" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"auto_resolved":"union"}]')" + auto_resolved_conflicts="$(echo "$auto_resolved_conflicts" | jq --argjson n "$pr" --arg t "$title" --argjson f "$(to_json_array "${conflicted_files[@]}")" '. + [{"number":$n,"title":$t,"type":"union","files":$f}]')" + continue + fi + + if [ "$all_snapshot" = 'true' ] && [ "${#snapshot_conflicts[@]}" -gt 0 ]; then + for file in "${conflicted_files[@]}"; do + if is_snapshot_path "$file"; then + git checkout --theirs -- "$file" || true + elif [ "$file" = "package-lock.json" ]; then + git checkout --ours -- "$file" || true + fi + git add "$file" + done + + git commit --no-edit + + patterns='[]' + for file in "${snapshot_conflicts[@]}"; do + pattern="$(derive_snapshot_pattern "$file")" + if [ -n "$pattern" ]; then + patterns="$(echo "$patterns" | jq --arg p "$pattern" '. + [$p]')" + fi + done + patterns="$(echo "$patterns" | jq -c 'unique')" + + if [ "$(echo "$patterns" | jq 'length')" -gt 0 ]; then + if [ "$npm_ci_done" != 'true' ]; then + npm ci + npm_ci_done='true' + fi + + while IFS= read -r pattern; do + [ -n "$pattern" ] || continue + npm run test:update "$pattern" + done < <(echo "$patterns" | jq -r '.[]') + fi + + mapfile -t changed_snapshot_files < <(git status --porcelain | awk '{print $2}' | grep -E '(^|/)(__snapshots__/|.*\.snap$)' || true) + + if [ "${#changed_snapshot_files[@]}" -gt 0 ]; then + git add -- "${changed_snapshot_files[@]}" + git commit -m "test: update snapshots for integration conflict resolution" + fi + + merged="$(echo "$merged" | jq --argjson n "$pr" --arg t "$title" --argjson p "$patterns" --argjson f "$(to_json_array "${changed_snapshot_files[@]}")" '. + [{"number":$n,"title":$t,"auto_resolved":"snapshot","snapshot_patterns":$p,"snapshot_files":$f}]')" + auto_resolved_conflicts="$(echo "$auto_resolved_conflicts" | jq --argjson n "$pr" --arg t "$title" --argjson f "$(to_json_array "${conflicted_files[@]}")" '. + [{"number":$n,"title":$t,"type":"snapshot","files":$f}]')" + + snapshot_patterns_global="$(echo "$snapshot_patterns_global" | jq --argjson p "$patterns" '. + $p')" + snapshot_files_global="$(echo "$snapshot_files_global" | jq --argjson f "$(to_json_array "${changed_snapshot_files[@]}")" '. + $f')" + continue + fi + + git merge --abort || true + skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"merge conflict (non-auto-resolvable)"}]')" +done + +snapshot_patterns_global="$(echo "$snapshot_patterns_global" | jq -c 'map(select(length > 0)) | unique')" +snapshot_files_global="$(echo "$snapshot_files_global" | jq -c 'map(select(length > 0)) | unique')" + +jq -cn \ + --arg dry_run "$DRY_RUN" \ + --argjson merged "$(echo "$merged" | jq -c .)" \ + --argjson skipped "$(echo "$skipped" | jq -c .)" \ + --argjson auto_resolved_conflicts "$(echo "$auto_resolved_conflicts" | jq -c .)" \ + --argjson snapshot_patterns "$snapshot_patterns_global" \ + --argjson snapshot_files "$snapshot_files_global" \ + '{ + dry_run: ($dry_run == "true"), + merged: $merged, + skipped: $skipped, + auto_resolved_conflicts: $auto_resolved_conflicts, + snapshot_updates: { + patterns: $snapshot_patterns, + files: $snapshot_files + } + }' diff --git a/.github/integration/union-allowlist-extra.txt b/.github/integration/union-allowlist-extra.txt new file mode 100644 index 000000000..895ddf494 --- /dev/null +++ b/.github/integration/union-allowlist-extra.txt @@ -0,0 +1,3 @@ +# One path per line. Paths listed here are added to the generated union allowlist. +# Example: +# src/cli/example/example-command.ts diff --git a/.github/integration/union-blocklist.txt b/.github/integration/union-blocklist.txt new file mode 100644 index 000000000..7ba8fd564 --- /dev/null +++ b/.github/integration/union-blocklist.txt @@ -0,0 +1,3 @@ +# One path per line. Paths listed here are removed from the generated union allowlist. +# Example: +# src/cli/example/example-command.ts diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index e2fba5b54..adcf4722e 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -92,58 +92,58 @@ jobs: git fetch origin main git checkout -B integration origin/main + - name: Set up Node + uses: actions/setup-node@v6 + with: + node-version: 24 + cache: npm + - name: Merge selected PRs id: merge env: GH_TOKEN: ${{ github.token }} REPO: ${{ github.repository }} - RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} run: | selected='${{ steps.selected.outputs.selected }}' dry_run='${{ steps.dryrun.outputs.dry_run }}' - - merged='[]' - merge_skipped='[]' - - for pr in $(echo "$selected" | jq -r '.[].number'); do - title="$(echo "$selected" | jq -r ".[] | select(.number==$pr) | .title")" - - echo "::group::Attempt merge PR #$pr - $title" - git fetch origin "pull/$pr/head:pr-$pr" - - if git merge --no-ff "pr-$pr" -m "Merge PR #$pr: $title"; then - merged="$(echo "$merged" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t}]')" - - if [ "$dry_run" != "true" ]; then - gh pr edit "$pr" --repo "$REPO" \ - --remove-label integration-batch \ - --remove-label integration-failed \ - --add-label integrated || true - gh pr comment "$pr" --repo "$REPO" --body "Included in \`integration\` branch by automation.\n\nRun: $RUN_URL" || true - fi - else - git merge --abort || true - merge_skipped="$(echo "$merge_skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"merge conflict"}]')" - - if [ "$dry_run" != "true" ]; then - gh pr edit "$pr" --repo "$REPO" \ - --remove-label integration-batch \ - --add-label integration-failed || true - gh pr comment "$pr" --repo "$REPO" --body "Skipped from automated \`integration\` batch due to a merge conflict. Please rebase against \`main\`, resolve conflicts, and re-add label \`integration-batch\`.\n\nRun: $RUN_URL" || true - fi - fi - - echo "::endgroup::" + summary="$( + ./.github/integration/scripts/merge_prs.sh \ + --prs-json "$selected" \ + --dry-run "$dry_run" \ + --repo "$REPO" + )" + + echo "summary=$(echo "$summary" | jq -c .)" >> "$GITHUB_OUTPUT" + echo "merged=$(echo "$summary" | jq -c '.merged')" >> "$GITHUB_OUTPUT" + echo "merge_skipped=$(echo "$summary" | jq -c '.skipped')" >> "$GITHUB_OUTPUT" + echo "auto_resolved_conflicts=$(echo "$summary" | jq -c '.auto_resolved_conflicts')" >> "$GITHUB_OUTPUT" + echo "snapshot_updates=$(echo "$summary" | jq -c '.snapshot_updates')" >> "$GITHUB_OUTPUT" + + - name: Apply labels and comments + if: ${{ steps.dryrun.outputs.dry_run != 'true' }} + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + merged='${{ steps.merge.outputs.merged }}' + merge_skipped='${{ steps.merge.outputs.merge_skipped }}' + + for pr in $(echo "$merged" | jq -r '.[].number'); do + gh pr edit "$pr" --repo "$REPO" \ + --remove-label integration-batch \ + --remove-label integration-failed \ + --add-label integrated || true + gh pr comment "$pr" --repo "$REPO" --body "Included in \`integration\` branch by automation.\n\nRun: $RUN_URL" || true done - echo "merged=$(echo "$merged" | jq -c .)" >> "$GITHUB_OUTPUT" - echo "merge_skipped=$(echo "$merge_skipped" | jq -c .)" >> "$GITHUB_OUTPUT" - - - name: Set up Node - uses: actions/setup-node@v6 - with: - node-version: 24 - cache: npm + for pr in $(echo "$merge_skipped" | jq -r '.[].number'); do + reason="$(echo "$merge_skipped" | jq -r ".[] | select(.number==$pr) | .reason")" + gh pr edit "$pr" --repo "$REPO" \ + --remove-label integration-batch \ + --add-label integration-failed || true + gh pr comment "$pr" --repo "$REPO" --body "Skipped from automated \`integration\` batch due to: $reason. Please rebase against \`main\`, resolve conflicts, and re-add label \`integration-batch\`.\n\nRun: $RUN_URL" || true + done - name: Bump @rockcarver/frodo-lib to @next run: | @@ -171,10 +171,16 @@ jobs: merged='${{ steps.merge.outputs.merged }}' skipped_checks='${{ steps.selected.outputs.skipped }}' skipped_merge='${{ steps.merge.outputs.merge_skipped }}' + auto_resolved='${{ steps.merge.outputs.auto_resolved_conflicts }}' + snapshot_updates='${{ steps.merge.outputs.snapshot_updates }}' included_list="$(echo "$merged" | jq -r '.[] | "- #\(.number): \(.title)"')" skipped_checks_list="$(echo "$skipped_checks" | jq -r '.[] | "- #\(.number): \(.title) (\(.reason))"')" - skipped_merge_list="$(echo "$skipped_merge" | jq -r '.[] | "- #\(.number): \(.title)"')" + skipped_merge_list="$(echo "$skipped_merge" | jq -r '.[] | "- #\(.number): \(.title) (\(.reason))"')" + auto_union_list="$(echo "$auto_resolved" | jq -r '.[] | select(.type=="union") | "- #\(.number): \(.title)"')" + auto_snapshot_list="$(echo "$auto_resolved" | jq -r '.[] | select(.type=="snapshot") | "- #\(.number): \(.title)"')" + snapshot_patterns_list="$(echo "$snapshot_updates" | jq -r '.patterns[]? | "- \(.)"')" + snapshot_files_list="$(echo "$snapshot_updates" | jq -r '.files[]? | "- \(.)"')" body=$'This PR is auto-generated from PRs labeled `integration-batch`.\n\n' body+=$'## Included\n' @@ -183,6 +189,14 @@ jobs: body+="${skipped_checks_list:-"- (none)"}" body+=$'\n\n## Skipped (merge conflicts)\n' body+="${skipped_merge_list:-"- (none)"}" + body+=$'\n\n## Auto-resolved conflicts (union)\n' + body+="${auto_union_list:-"- (none)"}" + body+=$'\n\n## Auto-resolved conflicts (snapshots)\n' + body+="${auto_snapshot_list:-"- (none)"}" + body+=$'\n\n## Snapshot update patterns run\n' + body+="${snapshot_patterns_list:-"- (none)"}" + body+=$'\n\n## Snapshot files updated\n' + body+="${snapshot_files_list:-"- (none)"}" body+=$'\n\nAlso bumps `@rockcarver/frodo-lib` to `@next`.\n' existing="$(gh pr list --repo "$REPO" --state open --head integration --base main --json number --jq '.[0].number // empty')" @@ -209,4 +223,20 @@ jobs: echo "" >> "$GITHUB_STEP_SUMMARY" echo "**Skipped (merge conflicts):**" >> "$GITHUB_STEP_SUMMARY" - echo '${{ steps.merge.outputs.merge_skipped }}' | jq -r '.[] | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true + echo '${{ steps.merge.outputs.merge_skipped }}' | jq -r '.[] | "- #\(.number): \(.title) (\(.reason))"' >> "$GITHUB_STEP_SUMMARY" || true + echo "" >> "$GITHUB_STEP_SUMMARY" + + echo "**Auto-resolved conflicts (union):**" >> "$GITHUB_STEP_SUMMARY" + echo '${{ steps.merge.outputs.auto_resolved_conflicts }}' | jq -r '.[] | select(.type=="union") | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true + echo "" >> "$GITHUB_STEP_SUMMARY" + + echo "**Auto-resolved conflicts (snapshots):**" >> "$GITHUB_STEP_SUMMARY" + echo '${{ steps.merge.outputs.auto_resolved_conflicts }}' | jq -r '.[] | select(.type=="snapshot") | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true + echo "" >> "$GITHUB_STEP_SUMMARY" + + echo "**Snapshot update patterns run:**" >> "$GITHUB_STEP_SUMMARY" + echo '${{ steps.merge.outputs.snapshot_updates }}' | jq -r '.patterns[]? | "- \(.)"' >> "$GITHUB_STEP_SUMMARY" || true + echo "" >> "$GITHUB_STEP_SUMMARY" + + echo "**Snapshot files updated:**" >> "$GITHUB_STEP_SUMMARY" + echo '${{ steps.merge.outputs.snapshot_updates }}' | jq -r '.files[]? | "- \(.)"' >> "$GITHUB_STEP_SUMMARY" || true diff --git a/docs/INTEGRATION.md b/docs/INTEGRATION.md index d6efd365a..312597a9b 100644 --- a/docs/INTEGRATION.md +++ b/docs/INTEGRATION.md @@ -30,10 +30,17 @@ Each run rebuilds `integration` from `main`, then attempts merge commits (`git m - add `integrated` - add a comment including the run URL - On merge conflict: - - abort merge - - remove `integration-batch` - - add `integration-failed` - - add a comment asking the author to rebase and re-add `integration-batch` + - if all conflicted files are in the auto-generated union allowlist, conflicts are auto-resolved by union merge + - if conflicts are snapshot-only (`*.snap` / `__snapshots__`, optionally with `package-lock.json`), merge is completed and targeted `npm run test:update ` commands are executed, then updated snapshots are committed to `integration` + - otherwise merge is aborted, `integration-failed` is applied, and the author is asked to rebase and re-add `integration-batch` + +Union allowlist generation runs on every workflow execution: + +- includes `src/cli/**` files containing `const program = new FrodoStubCommand(` +- excludes any file containing `const program = new FrodoCommand(` +- applies manual overrides from: + - `.github/integration/union-allowlist-extra.txt` + - `.github/integration/union-blocklist.txt` After merges, the workflow updates `@rockcarver/frodo-lib` to `@next`, commits lockfile changes when needed, pushes `integration`, and creates or updates an `integration -> main` PR titled `integration`. From bfd9ba9c2ec5f5b3f320cbc30829c9474a761bab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:08:12 +0000 Subject: [PATCH 17/44] fix: address review feedback for integration merge automation Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/b6757a0d-dff7-4f92-a696-e8ddfcfc9c9a Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 22 +++++++++++----------- .github/workflows/integration-batch.yml | 13 +++++++------ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh index c76c7d661..588023b99 100755 --- a/.github/integration/scripts/merge_prs.sh +++ b/.github/integration/scripts/merge_prs.sh @@ -91,15 +91,13 @@ apply_exception_file() { configure_union_attributes() { local attributes_file=".git/info/attributes" - touch "$attributes_file" { - echo "" echo "# integration-batch union allowlist" for file in "${!union_allowlist[@]}"; do echo "$file merge=union" done | sort echo "# end integration-batch union allowlist" - } >> "$attributes_file" + } > "$attributes_file" git config merge.union.driver true } @@ -116,7 +114,7 @@ is_snapshot_or_allowed_extra_conflict() { contains_conflict_markers() { local file="$1" - grep -nE '<<<<<<<|=======|>>>>>>>' "$file" >/dev/null 2>&1 + grep -nE '^(<{7}|={7}|>{7})' "$file" >/dev/null 2>&1 } to_json_array() { @@ -132,15 +130,10 @@ derive_snapshot_pattern() { local name name="$(basename "$path")" name="${name%.snap}" - name="$(echo "$name" | sed -E 's/\.(e2e\.)?(test|spec)\.js$//')" + name="$(echo "$name" | sed -E 's/\.(e2e\.)?(test|spec)\.(js|ts)$//')" echo "$name" } -auto_detect_union_allowlist -apply_exception_file "$ALLOWLIST_EXTRA_FILE" add -apply_exception_file "$BLOCKLIST_FILE" remove -configure_union_attributes - merged='[]' skipped='[]' auto_resolved_conflicts='[]' @@ -149,6 +142,13 @@ snapshot_files_global='[]' npm_ci_done='false' for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do + unset union_allowlist + declare -A union_allowlist=() + auto_detect_union_allowlist + apply_exception_file "$ALLOWLIST_EXTRA_FILE" add + apply_exception_file "$BLOCKLIST_FILE" remove + configure_union_attributes + title="$(echo "$PRS_JSON" | jq -r ".[] | select(.number==$pr) | .title // \"\"")" branch="$(echo "$PRS_JSON" | jq -r ".[] | select(.number==$pr) | .branch // \"\"")" @@ -249,7 +249,7 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do done < <(echo "$patterns" | jq -r '.[]') fi - mapfile -t changed_snapshot_files < <(git status --porcelain | awk '{print $2}' | grep -E '(^|/)(__snapshots__/|.*\.snap$)' || true) + mapfile -t changed_snapshot_files < <(git diff --name-only | grep -E '(^|/)(__snapshots__/|.*\.snap$)' || true) if [ "${#changed_snapshot_files[@]}" -gt 0 ]; then git add -- "${changed_snapshot_files[@]}" diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index adcf4722e..5f558aacf 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -106,12 +106,13 @@ jobs: run: | selected='${{ steps.selected.outputs.selected }}' dry_run='${{ steps.dryrun.outputs.dry_run }}' - summary="$( - ./.github/integration/scripts/merge_prs.sh \ - --prs-json "$selected" \ - --dry-run "$dry_run" \ - --repo "$REPO" - )" + output_file="$(mktemp)" + ./.github/integration/scripts/merge_prs.sh \ + --prs-json "$selected" \ + --dry-run "$dry_run" \ + --repo "$REPO" > "$output_file" + summary="$(cat "$output_file")" + rm -f "$output_file" echo "summary=$(echo "$summary" | jq -c .)" >> "$GITHUB_OUTPUT" echo "merged=$(echo "$summary" | jq -c '.merged')" >> "$GITHUB_OUTPUT" From ed1f6bbb044fa759148774fe13570595d9f1bd8f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:36:22 +0000 Subject: [PATCH 18/44] fix: apply PR review feedback for merge script output handling Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/6c18d667-cd05-4469-9cad-ac46e0cead23 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 39 +++++++++++++++++++----- .github/workflows/integration-batch.yml | 11 +++++-- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh index 588023b99..b9be6cbd7 100755 --- a/.github/integration/scripts/merge_prs.sh +++ b/.github/integration/scripts/merge_prs.sh @@ -54,6 +54,8 @@ fi # Validate JSON shape. PRS_JSON="$(echo "$PRS_JSON" | jq -c 'if type=="array" then . else error("prs-json must be an array") end')" DRY_RUN="$(echo "$DRY_RUN" | tr '[:upper:]' '[:lower:]')" +exec 3>&1 +exec 1>&2 if [ -z "$REPO" ]; then if git remote get-url origin >/dev/null 2>&1; then @@ -91,15 +93,36 @@ apply_exception_file() { configure_union_attributes() { local attributes_file=".git/info/attributes" + local begin_marker="# integration-batch union allowlist" + local end_marker="# end integration-batch union allowlist" + local preserved_file + local new_file + mkdir -p "$(dirname "$attributes_file")" + preserved_file="$(mktemp)" + new_file="$(mktemp)" + + if [ -f "$attributes_file" ]; then + awk -v begin="$begin_marker" -v end="$end_marker" ' + $0 == begin { skip=1; next } + $0 == end { skip=0; next } + !skip { print } + ' "$attributes_file" > "$preserved_file" + fi + { - echo "# integration-batch union allowlist" + if [ -s "$preserved_file" ]; then + cat "$preserved_file" + printf '\n' + fi + echo "$begin_marker" for file in "${!union_allowlist[@]}"; do echo "$file merge=union" done | sort - echo "# end integration-batch union allowlist" - } > "$attributes_file" + echo "$end_marker" + } > "$new_file" - git config merge.union.driver true + mv "$new_file" "$attributes_file" + rm -f "$preserved_file" } is_snapshot_path() { @@ -201,7 +224,7 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do has_marker='true' break fi - git add "$file" + git add -A -- "$file" done if [ "$has_marker" = 'true' ]; then @@ -223,7 +246,7 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do elif [ "$file" = "package-lock.json" ]; then git checkout --ours -- "$file" || true fi - git add "$file" + git add -A -- "$file" done git commit --no-edit @@ -245,7 +268,7 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do while IFS= read -r pattern; do [ -n "$pattern" ] || continue - npm run test:update "$pattern" + npm run test:update -- "$pattern" done < <(echo "$patterns" | jq -r '.[]') fi @@ -287,4 +310,4 @@ jq -cn \ patterns: $snapshot_patterns, files: $snapshot_files } - }' + }' >&3 diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index 5f558aacf..5544d75e4 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -111,10 +111,17 @@ jobs: --prs-json "$selected" \ --dry-run "$dry_run" \ --repo "$REPO" > "$output_file" - summary="$(cat "$output_file")" + summary="$(awk 'NF { line = $0 } END { print line }' "$output_file")" rm -f "$output_file" - echo "summary=$(echo "$summary" | jq -c .)" >> "$GITHUB_OUTPUT" + if [ -z "$summary" ]; then + echo "merge_prs.sh did not emit a JSON summary on stdout" >&2 + exit 1 + fi + + summary="$(echo "$summary" | jq -c .)" + + echo "summary=$summary" >> "$GITHUB_OUTPUT" echo "merged=$(echo "$summary" | jq -c '.merged')" >> "$GITHUB_OUTPUT" echo "merge_skipped=$(echo "$summary" | jq -c '.skipped')" >> "$GITHUB_OUTPUT" echo "auto_resolved_conflicts=$(echo "$summary" | jq -c '.auto_resolved_conflicts')" >> "$GITHUB_OUTPUT" From 03b49e65ad2d402cc46a2be0015dd35738b916f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:49:26 +0000 Subject: [PATCH 19/44] Initial plan From 500a411f29922c2d2cdda0bc3f09aac066865fe4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:53:49 +0000 Subject: [PATCH 20/44] fix: auto-regenerate lockfile on integration merge conflicts Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/d68f2baa-7a6f-4d19-8db5-8dc3bc2dd5b8 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 94 +++++++++++++++++++----- .github/workflows/integration-batch.yml | 22 ++++++ docs/INTEGRATION.md | 1 + 3 files changed, 99 insertions(+), 18 deletions(-) diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh index b9be6cbd7..cfca96e70 100755 --- a/.github/integration/scripts/merge_prs.sh +++ b/.github/integration/scripts/merge_prs.sh @@ -130,11 +130,6 @@ is_snapshot_path() { [[ "$path" == *.snap ]] || [[ "$path" == *"/__snapshots__/"* ]] } -is_snapshot_or_allowed_extra_conflict() { - local path="$1" - is_snapshot_path "$path" || [ "$path" = "package-lock.json" ] -} - contains_conflict_markers() { local file="$1" grep -nE '^(<{7}|={7}|>{7})' "$file" >/dev/null 2>&1 @@ -163,6 +158,28 @@ auto_resolved_conflicts='[]' snapshot_patterns_global='[]' snapshot_files_global='[]' npm_ci_done='false' +lockfile_regeneration_attempted='false' +lockfile_regeneration_updated='false' +lockfile_regeneration_prs='[]' + +regenerate_lockfile() { + local pr="$1" + local title="$2" + local updated='false' + + lockfile_regeneration_attempted='true' + + npm i --package-lock-only + + if ! git diff --quiet -- package-lock.json; then + git add package-lock.json + git commit -m "chore: regenerate package-lock.json after merge conflict" + updated='true' + lockfile_regeneration_updated='true' + fi + + lockfile_regeneration_prs="$(echo "$lockfile_regeneration_prs" | jq --argjson n "$pr" --arg t "$title" --argjson u "$([ "$updated" = 'true' ] && echo true || echo false)" '. + [{"number":$n,"title":$t,"updated":$u}]')" +} for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do unset union_allowlist @@ -201,25 +218,32 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do all_union='true' all_snapshot='true' + has_lockfile_conflict='false' + non_lock_conflicts=() snapshot_conflicts=() for file in "${conflicted_files[@]}"; do + if [ "$file" = "package-lock.json" ]; then + has_lockfile_conflict='true' + continue + fi + + non_lock_conflicts+=("$file") + if [ -z "${union_allowlist[$file]+x}" ]; then all_union='false' fi - if is_snapshot_or_allowed_extra_conflict "$file"; then - if is_snapshot_path "$file"; then - snapshot_conflicts+=("$file") - fi + if is_snapshot_path "$file"; then + snapshot_conflicts+=("$file") else all_snapshot='false' fi done - if [ "$all_union" = 'true' ]; then + if [ "$all_union" = 'true' ] && [ "${#non_lock_conflicts[@]}" -gt 0 ]; then has_marker='false' - for file in "${conflicted_files[@]}"; do + for file in "${non_lock_conflicts[@]}"; do if [ -f "$file" ] && contains_conflict_markers "$file"; then has_marker='true' break @@ -233,24 +257,39 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do continue fi + if [ "$has_lockfile_conflict" = 'true' ]; then + git checkout --ours -- package-lock.json || true + git add package-lock.json + fi + git commit --no-edit + + if [ "$has_lockfile_conflict" = 'true' ]; then + regenerate_lockfile "$pr" "$title" + fi + merged="$(echo "$merged" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"auto_resolved":"union"}]')" auto_resolved_conflicts="$(echo "$auto_resolved_conflicts" | jq --argjson n "$pr" --arg t "$title" --argjson f "$(to_json_array "${conflicted_files[@]}")" '. + [{"number":$n,"title":$t,"type":"union","files":$f}]')" continue fi - if [ "$all_snapshot" = 'true' ] && [ "${#snapshot_conflicts[@]}" -gt 0 ]; then - for file in "${conflicted_files[@]}"; do - if is_snapshot_path "$file"; then - git checkout --theirs -- "$file" || true - elif [ "$file" = "package-lock.json" ]; then - git checkout --ours -- "$file" || true - fi + if [ "$all_snapshot" = 'true' ] && [ "${#snapshot_conflicts[@]}" -gt 0 ] && [ "${#snapshot_conflicts[@]}" -eq "${#non_lock_conflicts[@]}" ]; then + for file in "${snapshot_conflicts[@]}"; do + git checkout --theirs -- "$file" || true git add -A -- "$file" done + if [ "$has_lockfile_conflict" = 'true' ]; then + git checkout --ours -- package-lock.json || true + git add package-lock.json + fi + git commit --no-edit + if [ "$has_lockfile_conflict" = 'true' ]; then + regenerate_lockfile "$pr" "$title" + fi + patterns='[]' for file in "${snapshot_conflicts[@]}"; do pattern="$(derive_snapshot_pattern "$file")" @@ -287,6 +326,17 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do continue fi + if [ "$has_lockfile_conflict" = 'true' ] && [ "${#non_lock_conflicts[@]}" -eq 0 ]; then + git checkout --ours -- package-lock.json || true + git add package-lock.json + git commit --no-edit + regenerate_lockfile "$pr" "$title" + + merged="$(echo "$merged" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"auto_resolved":"lockfile"}]')" + auto_resolved_conflicts="$(echo "$auto_resolved_conflicts" | jq --argjson n "$pr" --arg t "$title" --argjson f "$(to_json_array "${conflicted_files[@]}")" '. + [{"number":$n,"title":$t,"type":"lockfile","files":$f}]')" + continue + fi + git merge --abort || true skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"merge conflict (non-auto-resolvable)"}]')" done @@ -301,6 +351,9 @@ jq -cn \ --argjson auto_resolved_conflicts "$(echo "$auto_resolved_conflicts" | jq -c .)" \ --argjson snapshot_patterns "$snapshot_patterns_global" \ --argjson snapshot_files "$snapshot_files_global" \ + --arg lockfile_attempted "$lockfile_regeneration_attempted" \ + --arg lockfile_updated "$lockfile_regeneration_updated" \ + --argjson lockfile_prs "$(echo "$lockfile_regeneration_prs" | jq -c .)" \ '{ dry_run: ($dry_run == "true"), merged: $merged, @@ -309,5 +362,10 @@ jq -cn \ snapshot_updates: { patterns: $snapshot_patterns, files: $snapshot_files + }, + lockfile_regeneration: { + attempted: ($lockfile_attempted == "true"), + updated: ($lockfile_updated == "true"), + prs: $lockfile_prs } }' >&3 diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index 5544d75e4..25b26bf53 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -126,6 +126,7 @@ jobs: echo "merge_skipped=$(echo "$summary" | jq -c '.skipped')" >> "$GITHUB_OUTPUT" echo "auto_resolved_conflicts=$(echo "$summary" | jq -c '.auto_resolved_conflicts')" >> "$GITHUB_OUTPUT" echo "snapshot_updates=$(echo "$summary" | jq -c '.snapshot_updates')" >> "$GITHUB_OUTPUT" + echo "lockfile_regeneration=$(echo "$summary" | jq -c '.lockfile_regeneration')" >> "$GITHUB_OUTPUT" - name: Apply labels and comments if: ${{ steps.dryrun.outputs.dry_run != 'true' }} @@ -181,14 +182,17 @@ jobs: skipped_merge='${{ steps.merge.outputs.merge_skipped }}' auto_resolved='${{ steps.merge.outputs.auto_resolved_conflicts }}' snapshot_updates='${{ steps.merge.outputs.snapshot_updates }}' + lockfile_regeneration='${{ steps.merge.outputs.lockfile_regeneration }}' included_list="$(echo "$merged" | jq -r '.[] | "- #\(.number): \(.title)"')" skipped_checks_list="$(echo "$skipped_checks" | jq -r '.[] | "- #\(.number): \(.title) (\(.reason))"')" skipped_merge_list="$(echo "$skipped_merge" | jq -r '.[] | "- #\(.number): \(.title) (\(.reason))"')" auto_union_list="$(echo "$auto_resolved" | jq -r '.[] | select(.type=="union") | "- #\(.number): \(.title)"')" auto_snapshot_list="$(echo "$auto_resolved" | jq -r '.[] | select(.type=="snapshot") | "- #\(.number): \(.title)"')" + auto_lockfile_list="$(echo "$auto_resolved" | jq -r '.[] | select(.type=="lockfile") | "- #\(.number): \(.title)"')" snapshot_patterns_list="$(echo "$snapshot_updates" | jq -r '.patterns[]? | "- \(.)"')" snapshot_files_list="$(echo "$snapshot_updates" | jq -r '.files[]? | "- \(.)"')" + lockfile_regen_list="$(echo "$lockfile_regeneration" | jq -r '.prs[]? | "- #\(.number): \(.title)\(if .updated then " (updated package-lock.json)" else " (no lockfile diff)" end)"')" body=$'This PR is auto-generated from PRs labeled `integration-batch`.\n\n' body+=$'## Included\n' @@ -201,10 +205,18 @@ jobs: body+="${auto_union_list:-"- (none)"}" body+=$'\n\n## Auto-resolved conflicts (snapshots)\n' body+="${auto_snapshot_list:-"- (none)"}" + body+=$'\n\n## Auto-resolved conflicts (package-lock.json)\n' + body+="${auto_lockfile_list:-"- (none)"}" body+=$'\n\n## Snapshot update patterns run\n' body+="${snapshot_patterns_list:-"- (none)"}" body+=$'\n\n## Snapshot files updated\n' body+="${snapshot_files_list:-"- (none)"}" + body+=$'\n\n## package-lock.json regeneration\n' + body+="Attempted: $(echo "$lockfile_regeneration" | jq -r '.attempted')" + body+=$'\n' + body+="Updated: $(echo "$lockfile_regeneration" | jq -r '.updated')" + body+=$'\n' + body+="${lockfile_regen_list:-"- (none)"}" body+=$'\n\nAlso bumps `@rockcarver/frodo-lib` to `@next`.\n' existing="$(gh pr list --repo "$REPO" --state open --head integration --base main --json number --jq '.[0].number // empty')" @@ -242,9 +254,19 @@ jobs: echo '${{ steps.merge.outputs.auto_resolved_conflicts }}' | jq -r '.[] | select(.type=="snapshot") | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true echo "" >> "$GITHUB_STEP_SUMMARY" + echo "**Auto-resolved conflicts (package-lock.json):**" >> "$GITHUB_STEP_SUMMARY" + echo '${{ steps.merge.outputs.auto_resolved_conflicts }}' | jq -r '.[] | select(.type=="lockfile") | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "**Snapshot update patterns run:**" >> "$GITHUB_STEP_SUMMARY" echo '${{ steps.merge.outputs.snapshot_updates }}' | jq -r '.patterns[]? | "- \(.)"' >> "$GITHUB_STEP_SUMMARY" || true echo "" >> "$GITHUB_STEP_SUMMARY" echo "**Snapshot files updated:**" >> "$GITHUB_STEP_SUMMARY" echo '${{ steps.merge.outputs.snapshot_updates }}' | jq -r '.files[]? | "- \(.)"' >> "$GITHUB_STEP_SUMMARY" || true + echo "" >> "$GITHUB_STEP_SUMMARY" + + echo "**package-lock.json regeneration:**" >> "$GITHUB_STEP_SUMMARY" + echo "Attempted: $(echo '${{ steps.merge.outputs.lockfile_regeneration }}' | jq -r '.attempted')" >> "$GITHUB_STEP_SUMMARY" + echo "Updated: $(echo '${{ steps.merge.outputs.lockfile_regeneration }}' | jq -r '.updated')" >> "$GITHUB_STEP_SUMMARY" + echo '${{ steps.merge.outputs.lockfile_regeneration }}' | jq -r '.prs[]? | "- #\(.number): \(.title)\(if .updated then " (updated package-lock.json)" else " (no lockfile diff)" end)"' >> "$GITHUB_STEP_SUMMARY" || true diff --git a/docs/INTEGRATION.md b/docs/INTEGRATION.md index 312597a9b..c19c1a713 100644 --- a/docs/INTEGRATION.md +++ b/docs/INTEGRATION.md @@ -32,6 +32,7 @@ Each run rebuilds `integration` from `main`, then attempts merge commits (`git m - On merge conflict: - if all conflicted files are in the auto-generated union allowlist, conflicts are auto-resolved by union merge - if conflicts are snapshot-only (`*.snap` / `__snapshots__`, optionally with `package-lock.json`), merge is completed and targeted `npm run test:update ` commands are executed, then updated snapshots are committed to `integration` + - if `package-lock.json` is conflicted (including lockfile-only conflicts), automation checks out one side to complete the merge, runs `npm i --package-lock-only`, and commits the regenerated lockfile to `integration` - otherwise merge is aborted, `integration-failed` is applied, and the author is asked to rebase and re-add `integration-batch` Union allowlist generation runs on every workflow execution: From 905b91553487aa1bd5194974d4b37250f03908a9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:54:32 +0000 Subject: [PATCH 21/44] chore: simplify snapshot conflict condition Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/d68f2baa-7a6f-4d19-8db5-8dc3bc2dd5b8 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh index cfca96e70..9d993d2a2 100755 --- a/.github/integration/scripts/merge_prs.sh +++ b/.github/integration/scripts/merge_prs.sh @@ -273,7 +273,7 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do continue fi - if [ "$all_snapshot" = 'true' ] && [ "${#snapshot_conflicts[@]}" -gt 0 ] && [ "${#snapshot_conflicts[@]}" -eq "${#non_lock_conflicts[@]}" ]; then + if [ "$all_snapshot" = 'true' ] && [ "${#snapshot_conflicts[@]}" -gt 0 ]; then for file in "${snapshot_conflicts[@]}"; do git checkout --theirs -- "$file" || true git add -A -- "$file" From f58b157f9f8017bd6ecf5d5fa15284149631bd89 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:55:10 +0000 Subject: [PATCH 22/44] fix: add lockfile regeneration failure handling Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/d68f2baa-7a6f-4d19-8db5-8dc3bc2dd5b8 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh index 9d993d2a2..1ffd06f43 100755 --- a/.github/integration/scripts/merge_prs.sh +++ b/.github/integration/scripts/merge_prs.sh @@ -169,7 +169,10 @@ regenerate_lockfile() { lockfile_regeneration_attempted='true' - npm i --package-lock-only + if ! npm i --package-lock-only; then + echo "Failed to regenerate package-lock.json after merge conflict for PR #$pr." >&2 + exit 1 + fi if ! git diff --quiet -- package-lock.json; then git add package-lock.json @@ -241,6 +244,7 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do fi done + # Keep lockfile-only conflicts on the dedicated lockfile recovery path below. if [ "$all_union" = 'true' ] && [ "${#non_lock_conflicts[@]}" -gt 0 ]; then has_marker='false' for file in "${non_lock_conflicts[@]}"; do From 0999ca9dac696a94d5cfda3b3028b41432061a75 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:55:54 +0000 Subject: [PATCH 23/44] chore: refine lockfile regeneration diagnostics Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/d68f2baa-7a6f-4d19-8db5-8dc3bc2dd5b8 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh index 1ffd06f43..18884e6dd 100755 --- a/.github/integration/scripts/merge_prs.sh +++ b/.github/integration/scripts/merge_prs.sh @@ -165,23 +165,23 @@ lockfile_regeneration_prs='[]' regenerate_lockfile() { local pr="$1" local title="$2" - local updated='false' + local updated_bool='false' lockfile_regeneration_attempted='true' if ! npm i --package-lock-only; then - echo "Failed to regenerate package-lock.json after merge conflict for PR #$pr." >&2 + echo "Failed to regenerate package-lock.json after merge conflict for PR #$pr. See npm output above for details." >&2 exit 1 fi if ! git diff --quiet -- package-lock.json; then git add package-lock.json git commit -m "chore: regenerate package-lock.json after merge conflict" - updated='true' + updated_bool='true' lockfile_regeneration_updated='true' fi - lockfile_regeneration_prs="$(echo "$lockfile_regeneration_prs" | jq --argjson n "$pr" --arg t "$title" --argjson u "$([ "$updated" = 'true' ] && echo true || echo false)" '. + [{"number":$n,"title":$t,"updated":$u}]')" + lockfile_regeneration_prs="$(echo "$lockfile_regeneration_prs" | jq --argjson n "$pr" --arg t "$title" --argjson u "$updated_bool" '. + [{"number":$n,"title":$t,"updated":$u}]')" } for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do @@ -244,7 +244,7 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do fi done - # Keep lockfile-only conflicts on the dedicated lockfile recovery path below. + # Keep lockfile-only conflicts for the [ "$has_lockfile_conflict" = 'true' ] && [ "${#non_lock_conflicts[@]}" -eq 0 ] block below. if [ "$all_union" = 'true' ] && [ "${#non_lock_conflicts[@]}" -gt 0 ]; then has_marker='false' for file in "${non_lock_conflicts[@]}"; do From e7c9c5ce7a90e0be800591c9571a86030a96e730 Mon Sep 17 00:00:00 2001 From: Volker Scheuber Date: Sun, 19 Apr 2026 17:38:45 -0600 Subject: [PATCH 24/44] Update .github/integration/scripts/merge_prs.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh index 18884e6dd..ff4f4fad7 100755 --- a/.github/integration/scripts/merge_prs.sh +++ b/.github/integration/scripts/merge_prs.sh @@ -170,8 +170,15 @@ regenerate_lockfile() { lockfile_regeneration_attempted='true' if ! npm i --package-lock-only; then - echo "Failed to regenerate package-lock.json after merge conflict for PR #$pr. See npm output above for details." >&2 - exit 1 + echo "Failed to regenerate package-lock.json after merge conflict for PR #$pr. Rolling back merge and marking PR as skipped. See npm output above for details." >&2 + lockfile_regeneration_prs="$(echo "$lockfile_regeneration_prs" | jq --argjson n "$pr" --arg t "$title" --argjson u "$updated_bool" '. + [{"number":$n,"title":$t,"updated":$u}]')" + skipped="$(echo "$skipped" | jq --argjson n "$pr" --arg t "$title" '. + [{"number":$n,"title":$t,"reason":"lockfile_regeneration_failed"}]')" + if git rev-parse --verify ORIG_HEAD >/dev/null 2>&1; then + git reset --hard ORIG_HEAD >/dev/null + else + git reset --hard HEAD^ >/dev/null + fi + return 0 fi if ! git diff --quiet -- package-lock.json; then From d122f0b2f9b013a8acf72fa30de39ef36de0a897 Mon Sep 17 00:00:00 2001 From: Volker Scheuber Date: Sun, 19 Apr 2026 17:39:25 -0600 Subject: [PATCH 25/44] Update .github/workflows/integration-batch.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index 25b26bf53..72864536d 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -255,7 +255,7 @@ jobs: echo "" >> "$GITHUB_STEP_SUMMARY" echo "**Auto-resolved conflicts (package-lock.json):**" >> "$GITHUB_STEP_SUMMARY" - echo '${{ steps.merge.outputs.auto_resolved_conflicts }}' | jq -r '.[] | select(.type=="lockfile") | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true + echo '${{ steps.merge.outputs.lockfile_regeneration }}' | jq -r '.prs[]? | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true echo "" >> "$GITHUB_STEP_SUMMARY" echo "**Snapshot update patterns run:**" >> "$GITHUB_STEP_SUMMARY" From 09251ff7c667d06f11a8821fafce4e47d6750938 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 23:39:26 +0000 Subject: [PATCH 26/44] fix: report lockfile auto-resolution from regeneration summary Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/03a79a5c-8878-43a4-99c6-b135c83d697a Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index 72864536d..f64e26181 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -189,7 +189,7 @@ jobs: skipped_merge_list="$(echo "$skipped_merge" | jq -r '.[] | "- #\(.number): \(.title) (\(.reason))"')" auto_union_list="$(echo "$auto_resolved" | jq -r '.[] | select(.type=="union") | "- #\(.number): \(.title)"')" auto_snapshot_list="$(echo "$auto_resolved" | jq -r '.[] | select(.type=="snapshot") | "- #\(.number): \(.title)"')" - auto_lockfile_list="$(echo "$auto_resolved" | jq -r '.[] | select(.type=="lockfile") | "- #\(.number): \(.title)"')" + auto_lockfile_list="$(echo "$lockfile_regeneration" | jq -r '.prs[]? | "- #\(.number): \(.title)"')" snapshot_patterns_list="$(echo "$snapshot_updates" | jq -r '.patterns[]? | "- \(.)"')" snapshot_files_list="$(echo "$snapshot_updates" | jq -r '.files[]? | "- \(.)"')" lockfile_regen_list="$(echo "$lockfile_regeneration" | jq -r '.prs[]? | "- #\(.number): \(.title)\(if .updated then " (updated package-lock.json)" else " (no lockfile diff)" end)"')" From a381b66f6732d5ec44ad4936f4457b535b1de848 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 23:50:55 +0000 Subject: [PATCH 27/44] Initial plan From 8d7045abe3f3e5f43e87c5a58e6325b7d7e35877 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 23:53:38 +0000 Subject: [PATCH 28/44] fix: prepare frodo cli before snapshot updates in integration batching Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/007ea63d-538a-4668-8f60-5ef6be9e8edd Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 31 +++++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh index ff4f4fad7..447fbeab3 100755 --- a/.github/integration/scripts/merge_prs.sh +++ b/.github/integration/scripts/merge_prs.sh @@ -158,6 +158,7 @@ auto_resolved_conflicts='[]' snapshot_patterns_global='[]' snapshot_files_global='[]' npm_ci_done='false' +snapshot_test_env_ready='false' lockfile_regeneration_attempted='false' lockfile_regeneration_updated='false' lockfile_regeneration_prs='[]' @@ -191,6 +192,31 @@ regenerate_lockfile() { lockfile_regeneration_prs="$(echo "$lockfile_regeneration_prs" | jq --argjson n "$pr" --arg t "$title" --argjson u "$updated_bool" '. + [{"number":$n,"title":$t,"updated":$u}]')" } +prepare_snapshot_test_environment() { + if [ "$snapshot_test_env_ready" = 'true' ]; then + return 0 + fi + + if [ "$npm_ci_done" != 'true' ]; then + npm ci + npm_ci_done='true' + fi + + npm run build:only + npm i -g + + npm_global_bin="$(npm bin -g 2>/dev/null || true)" + if [ -z "$npm_global_bin" ]; then + npm_global_bin="$(npm prefix -g)/bin" + fi + export PATH="$npm_global_bin:$PATH" + if [ -n "${GITHUB_PATH:-}" ] && [ -n "$npm_global_bin" ]; then + echo "$npm_global_bin" >> "$GITHUB_PATH" + fi + + snapshot_test_env_ready='true' +} + for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do unset union_allowlist declare -A union_allowlist=() @@ -311,10 +337,7 @@ for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do patterns="$(echo "$patterns" | jq -c 'unique')" if [ "$(echo "$patterns" | jq 'length')" -gt 0 ]; then - if [ "$npm_ci_done" != 'true' ]; then - npm ci - npm_ci_done='true' - fi + prepare_snapshot_test_environment while IFS= read -r pattern; do [ -n "$pattern" ] || continue From fc9794ad78f7eb4353c0d68de665ad22f4243ea9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 00:00:23 +0000 Subject: [PATCH 29/44] fix: rebuild frodo before each snapshot update batch Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/33742e8e-9a11-4f6f-acde-e4cf97ba40a7 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh index 447fbeab3..86a0e5835 100755 --- a/.github/integration/scripts/merge_prs.sh +++ b/.github/integration/scripts/merge_prs.sh @@ -158,7 +158,6 @@ auto_resolved_conflicts='[]' snapshot_patterns_global='[]' snapshot_files_global='[]' npm_ci_done='false' -snapshot_test_env_ready='false' lockfile_regeneration_attempted='false' lockfile_regeneration_updated='false' lockfile_regeneration_prs='[]' @@ -193,10 +192,6 @@ regenerate_lockfile() { } prepare_snapshot_test_environment() { - if [ "$snapshot_test_env_ready" = 'true' ]; then - return 0 - fi - if [ "$npm_ci_done" != 'true' ]; then npm ci npm_ci_done='true' @@ -205,16 +200,11 @@ prepare_snapshot_test_environment() { npm run build:only npm i -g - npm_global_bin="$(npm bin -g 2>/dev/null || true)" - if [ -z "$npm_global_bin" ]; then - npm_global_bin="$(npm prefix -g)/bin" - fi + npm_global_bin="$(npm prefix -g)/bin" export PATH="$npm_global_bin:$PATH" - if [ -n "${GITHUB_PATH:-}" ] && [ -n "$npm_global_bin" ]; then + if [ -n "${GITHUB_PATH:-}" ]; then echo "$npm_global_bin" >> "$GITHUB_PATH" fi - - snapshot_test_env_ready='true' } for pr in $(echo "$PRS_JSON" | jq -r '.[].number'); do From 9a3b688151e1fac6f86bc9413e01a522d684cc2c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 00:01:17 +0000 Subject: [PATCH 30/44] fix: refresh frodo install on each snapshot update pass Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/33742e8e-9a11-4f6f-acde-e4cf97ba40a7 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/integration/scripts/merge_prs.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/integration/scripts/merge_prs.sh b/.github/integration/scripts/merge_prs.sh index 86a0e5835..e3e8040b4 100755 --- a/.github/integration/scripts/merge_prs.sh +++ b/.github/integration/scripts/merge_prs.sh @@ -200,10 +200,18 @@ prepare_snapshot_test_environment() { npm run build:only npm i -g - npm_global_bin="$(npm prefix -g)/bin" - export PATH="$npm_global_bin:$PATH" - if [ -n "${GITHUB_PATH:-}" ]; then - echo "$npm_global_bin" >> "$GITHUB_PATH" + npm_global_prefix="$(npm prefix -g 2>/dev/null || true)" + if [ -n "$npm_global_prefix" ]; then + npm_global_bin="$npm_global_prefix/bin" + export PATH="$npm_global_bin:$PATH" + if [ -n "${GITHUB_PATH:-}" ] && [ -n "$npm_global_bin" ]; then + echo "$npm_global_bin" >> "$GITHUB_PATH" + fi + fi + + if ! command -v frodo >/dev/null 2>&1; then + echo "frodo CLI not found on PATH after npm i -g" >&2 + return 1 fi } From f257f92df5f4919333650e0f2273da1de28cbf85 Mon Sep 17 00:00:00 2001 From: Volker Scheuber Date: Sun, 19 Apr 2026 19:48:59 -0600 Subject: [PATCH 31/44] refactor: remove unused printMessage import from config-manager-pull-custom-nodes --- .../config-manager-pull/config-manager-pull-custom-nodes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts b/src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts index 3861cd5b6..322aa0a94 100644 --- a/src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts +++ b/src/cli/config-manager/config-manager-pull/config-manager-pull-custom-nodes.ts @@ -3,7 +3,7 @@ import { Option } from 'commander'; import { configManagerExportCustomNodes } from '../../../configManagerOps/FrConfigCustomNodesOps'; import { getTokens } from '../../../ops/AuthenticateOps'; -import { printMessage, verboseMessage } from '../../../utils/Console'; +import { verboseMessage } from '../../../utils/Console'; import { FrodoCommand } from '../../FrodoCommand'; const { CLOUD_DEPLOYMENT_TYPE_KEY, FORGEOPS_DEPLOYMENT_TYPE_KEY } = From a8979efd60954ca5aa8e6e1b84ba42acde75672e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 02:23:36 +0000 Subject: [PATCH 32/44] Initial plan From 5007543c81f6608addcd7072fb41be71a1d94593 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 02:27:23 +0000 Subject: [PATCH 33/44] feat: run post-push integration tests in integration-batch workflow Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/bacafc00-796c-465f-85d7-8744d6ff52fc Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 37 +++++++++++++++++++++++++ docs/INTEGRATION.md | 5 +++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index f64e26181..11a5b467b 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -167,10 +167,26 @@ jobs: fi - name: Push integration branch + id: push_integration if: ${{ steps.dryrun.outputs.dry_run != 'true' }} run: | git push origin integration --force-with-lease + - name: Full test suite on integration branch + id: integration_full_tests + if: ${{ steps.dryrun.outputs.dry_run != 'true' }} + run: | + npm ci + npm run build:only + npm i -g + npm_global_bin="$(npm bin -g 2>/dev/null || true)" + if [ -z "$npm_global_bin" ]; then + npm_global_bin="$(npm prefix -g)/bin" + fi + echo "$npm_global_bin" >> "$GITHUB_PATH" + export PATH="$npm_global_bin:$PATH" + npm test + - name: Create or update PR integration -> main if: ${{ steps.dryrun.outputs.dry_run != 'true' }} env: @@ -234,6 +250,27 @@ jobs: echo "**Dry run:** ${{ steps.dryrun.outputs.dry_run }}" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" + if [ '${{ steps.dryrun.outputs.dry_run }}' = 'true' ]; then + echo "**Integration branch push:** skipped (dry run)" >> "$GITHUB_STEP_SUMMARY" + echo "**Full test suite on integration:** skipped (dry run)" >> "$GITHUB_STEP_SUMMARY" + else + case '${{ steps.push_integration.outcome }}' in + success) push_status='pushed' ;; + failure) push_status='failed' ;; + skipped) push_status='skipped' ;; + *) push_status='unknown' ;; + esac + case '${{ steps.integration_full_tests.outcome }}' in + success) test_status='passed' ;; + failure) test_status='failed' ;; + skipped) test_status='skipped' ;; + *) test_status='unknown' ;; + esac + echo "**Integration branch push:** $push_status" >> "$GITHUB_STEP_SUMMARY" + echo "**Full test suite on integration:** $test_status" >> "$GITHUB_STEP_SUMMARY" + fi + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "**Merged into integration:**" >> "$GITHUB_STEP_SUMMARY" echo '${{ steps.merge.outputs.merged }}' | jq -r '.[] | "- #\(.number): \(.title)"' >> "$GITHUB_STEP_SUMMARY" || true echo "" >> "$GITHUB_STEP_SUMMARY" diff --git a/docs/INTEGRATION.md b/docs/INTEGRATION.md index c19c1a713..f15e4559a 100644 --- a/docs/INTEGRATION.md +++ b/docs/INTEGRATION.md @@ -43,7 +43,9 @@ Union allowlist generation runs on every workflow execution: - `.github/integration/union-allowlist-extra.txt` - `.github/integration/union-blocklist.txt` -After merges, the workflow updates `@rockcarver/frodo-lib` to `@next`, commits lockfile changes when needed, pushes `integration`, and creates or updates an `integration -> main` PR titled `integration`. +After merges, the workflow updates `@rockcarver/frodo-lib` to `@next`, commits lockfile changes when needed, pushes `integration`, runs the full test suite on `integration`, and then creates or updates an `integration -> main` PR titled `integration`. + +Because `integration` is pushed before the full test suite runs, the branch can be temporarily red until the test stage finishes. ## Dry run mode @@ -52,5 +54,6 @@ When manually triggered, set `dry_run=true` to simulate batching without side ef - does not push `integration` - does not create/update the integration PR - does not edit labels or post PR comments +- does not run the post-push full test suite on `integration` The workflow still computes candidate PRs and attempts merges locally so maintainers can validate batchability before a real run. From 660825f39c61d39f6df5a9abbc88d2d4a0d18a3f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 02:28:07 +0000 Subject: [PATCH 34/44] chore: harden npm global bin resolution in integration test step Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/bacafc00-796c-465f-85d7-8744d6ff52fc Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index 11a5b467b..eac45447d 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -183,6 +183,10 @@ jobs: if [ -z "$npm_global_bin" ]; then npm_global_bin="$(npm prefix -g)/bin" fi + if [ -z "$npm_global_bin" ]; then + echo "Unable to resolve npm global bin path" >&2 + exit 1 + fi echo "$npm_global_bin" >> "$GITHUB_PATH" export PATH="$npm_global_bin:$PATH" npm test From 32b113447350de4c25525998f1317216e5cba42c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 02:51:13 +0000 Subject: [PATCH 35/44] test: update snapshots for integration conflict resolution --- .../client_cli/en/__snapshots__/config-manager-push.test.js.snap | 1 + 1 file changed, 1 insertion(+) diff --git a/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap index 0cb8e44c3..c079ca13f 100644 --- a/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap +++ b/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap @@ -15,6 +15,7 @@ Options: Commands: access-config [Experimental] Import access configuration. audit [Experimental] Import audit configuration. + authentication [Experimental] Import authentication objects. connector-definitions [Experimental] Import connector definitions. cookie-domains [Experimental] Import cookie domains. email-provider [Experimental] Import email provider configuration. From f5424997a4faba45ac1e60f1262634b162979df1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 03:13:46 +0000 Subject: [PATCH 36/44] Updated changelog and version for release v4.0.0-46 --- CHANGELOG.md | 5 ++++- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 373e79d3f..d1351faa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [4.0.0-46] - 2026-04-20 + ## [4.0.0-45] - 2026-04-17 ## [4.0.0-44] - 2026-04-17 @@ -2253,7 +2255,8 @@ Frodo CLI 2.x automatically refreshes session and access tokens before they expi - Fixed problem with adding connection profiles - Miscellaneous bug fixes -[unreleased]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-45...HEAD +[unreleased]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-46...HEAD +[4.0.0-46]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-45...v4.0.0-46 [4.0.0-45]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-44...v4.0.0-45 [4.0.0-44]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-43...v4.0.0-44 [4.0.0-43]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-42...v4.0.0-43 diff --git a/package-lock.json b/package-lock.json index ae8bad5a8..8888472a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-45", + "version": "4.0.0-46", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-45", + "version": "4.0.0-46", "license": "MIT", "bin": { "frodo": "dist/launch.cjs" diff --git a/package.json b/package.json index 828400fee..9f4b5fde4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-45", + "version": "4.0.0-46", "type": "module", "description": "A command line interface to manage ForgeRock Identity Cloud tenants, ForgeOps deployments, and classic deployments.", "keywords": [ From 8ffc2fe0fcfee06885c57c88c7c35fd4db2f845e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 04:04:47 +0000 Subject: [PATCH 37/44] Updated changelog and version for release v4.0.0-47 --- CHANGELOG.md | 5 ++++- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1351faa8..0b7ea578d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [4.0.0-47] - 2026-04-20 + ## [4.0.0-46] - 2026-04-20 ## [4.0.0-45] - 2026-04-17 @@ -2255,7 +2257,8 @@ Frodo CLI 2.x automatically refreshes session and access tokens before they expi - Fixed problem with adding connection profiles - Miscellaneous bug fixes -[unreleased]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-46...HEAD +[unreleased]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-47...HEAD +[4.0.0-47]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-46...v4.0.0-47 [4.0.0-46]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-45...v4.0.0-46 [4.0.0-45]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-44...v4.0.0-45 [4.0.0-44]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-43...v4.0.0-44 diff --git a/package-lock.json b/package-lock.json index 8888472a8..07815f070 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-46", + "version": "4.0.0-47", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-46", + "version": "4.0.0-47", "license": "MIT", "bin": { "frodo": "dist/launch.cjs" diff --git a/package.json b/package.json index 9f4b5fde4..05da6ad32 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-46", + "version": "4.0.0-47", "type": "module", "description": "A command line interface to manage ForgeRock Identity Cloud tenants, ForgeOps deployments, and classic deployments.", "keywords": [ From d5e93f4bb352f5bb829ccee1e3b11113e2fc885b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 12:33:04 +0000 Subject: [PATCH 38/44] Initial plan From 60ae871e94adb77dacd88aaf3fc45e4409bdbc76 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 12:38:46 +0000 Subject: [PATCH 39/44] ci: label integration PR when snapshot updates are present Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/785c4a92-f59d-43b8-850f-044d533d3e97 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 23 +++++++++++++++++++++++ docs/INTEGRATION.md | 1 + 2 files changed, 24 insertions(+) diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index eac45447d..fb00cc2c7 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -192,6 +192,7 @@ jobs: npm test - name: Create or update PR integration -> main + id: integration_pr if: ${{ steps.dryrun.outputs.dry_run != 'true' }} env: GH_TOKEN: ${{ github.token }} @@ -242,8 +243,30 @@ jobs: existing="$(gh pr list --repo "$REPO" --state open --head integration --base main --json number --jq '.[0].number // empty')" if [ -n "$existing" ]; then gh pr edit "$existing" --repo "$REPO" --title "integration" --body "$body" + integration_pr_number="$existing" else gh pr create --repo "$REPO" --head integration --base main --title "integration" --body "$body" + integration_pr_number="$(gh pr list --repo "$REPO" --state open --head integration --base main --json number --jq '.[0].number // empty')" + fi + + if [ -z "$integration_pr_number" ]; then + echo "Failed to determine integration PR number" >&2 + exit 1 + fi + echo "number=$integration_pr_number" >> "$GITHUB_OUTPUT" + + - name: Label integration PR for snapshot review + if: ${{ steps.dryrun.outputs.dry_run != 'true' }} + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + run: | + snapshot_updates='${{ steps.merge.outputs.snapshot_updates }}' + integration_pr_number='${{ steps.integration_pr.outputs.number }}' + snapshot_file_count="$(echo "$snapshot_updates" | jq '.files | length')" + + if [ "$snapshot_file_count" -gt 0 ]; then + gh pr edit "$integration_pr_number" --repo "$REPO" --add-label integration-needs-snapshot-review fi - name: Job summary diff --git a/docs/INTEGRATION.md b/docs/INTEGRATION.md index f15e4559a..1cd62181e 100644 --- a/docs/INTEGRATION.md +++ b/docs/INTEGRATION.md @@ -7,6 +7,7 @@ The [`integration-batch` workflow](../.github/workflows/integration-batch.yml) a - `integration-batch`: PR is queued for integration batching. - `integrated`: PR was successfully merged into the `integration` branch by automation. - `integration-failed`: automation attempted integration but hit a merge conflict. +- `integration-needs-snapshot-review`: applied to the generated `integration -> main` PR when snapshot auto-recovery updates snapshot files. ## Selection rules From c58071e9b0320c24d29993ad3ab60c78d333efb6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 12:41:47 +0000 Subject: [PATCH 40/44] ci: add snapshot-review label to generated integration PR Agent-Logs-Url: https://github.com/rockcarver/frodo-cli/sessions/785c4a92-f59d-43b8-850f-044d533d3e97 Co-authored-by: vscheuber <28791378+vscheuber@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index fb00cc2c7..dc3288fdb 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -245,8 +245,8 @@ jobs: gh pr edit "$existing" --repo "$REPO" --title "integration" --body "$body" integration_pr_number="$existing" else - gh pr create --repo "$REPO" --head integration --base main --title "integration" --body "$body" - integration_pr_number="$(gh pr list --repo "$REPO" --state open --head integration --base main --json number --jq '.[0].number // empty')" + created_pr_url="$(gh pr create --repo "$REPO" --head integration --base main --title "integration" --body "$body")" + integration_pr_number="$(gh pr view "$created_pr_url" --repo "$REPO" --json number --jq '.number')" fi if [ -z "$integration_pr_number" ]; then @@ -263,7 +263,7 @@ jobs: run: | snapshot_updates='${{ steps.merge.outputs.snapshot_updates }}' integration_pr_number='${{ steps.integration_pr.outputs.number }}' - snapshot_file_count="$(echo "$snapshot_updates" | jq '.files | length')" + snapshot_file_count="$(echo "$snapshot_updates" | jq -r '(.files // []) | length' 2>/dev/null || echo 0)" if [ "$snapshot_file_count" -gt 0 ]; then gh pr edit "$integration_pr_number" --repo "$REPO" --add-label integration-needs-snapshot-review From 71b8ed1772e6b1a59df3af5c29c5906ffc8a2f70 Mon Sep 17 00:00:00 2001 From: Volker Scheuber Date: Mon, 20 Apr 2026 20:02:38 -0600 Subject: [PATCH 41/44] Update .github/workflows/integration-batch.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/integration-batch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-batch.yml b/.github/workflows/integration-batch.yml index dc3288fdb..8b6086a0b 100644 --- a/.github/workflows/integration-batch.yml +++ b/.github/workflows/integration-batch.yml @@ -266,7 +266,7 @@ jobs: snapshot_file_count="$(echo "$snapshot_updates" | jq -r '(.files // []) | length' 2>/dev/null || echo 0)" if [ "$snapshot_file_count" -gt 0 ]; then - gh pr edit "$integration_pr_number" --repo "$REPO" --add-label integration-needs-snapshot-review + gh pr edit "$integration_pr_number" --repo "$REPO" --add-label integration-needs-snapshot-review || true fi - name: Job summary From a088b07cba1f1e0149cbb80f16080068bcd27fc2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 02:34:19 +0000 Subject: [PATCH 42/44] Updated changelog and version for release v4.0.0-48 --- CHANGELOG.md | 5 ++++- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b7ea578d..51f52f350 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [4.0.0-48] - 2026-04-21 + ## [4.0.0-47] - 2026-04-20 ## [4.0.0-46] - 2026-04-20 @@ -2257,7 +2259,8 @@ Frodo CLI 2.x automatically refreshes session and access tokens before they expi - Fixed problem with adding connection profiles - Miscellaneous bug fixes -[unreleased]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-47...HEAD +[unreleased]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-48...HEAD +[4.0.0-48]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-47...v4.0.0-48 [4.0.0-47]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-46...v4.0.0-47 [4.0.0-46]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-45...v4.0.0-46 [4.0.0-45]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-44...v4.0.0-45 diff --git a/package-lock.json b/package-lock.json index 07815f070..afed536ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-47", + "version": "4.0.0-48", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-47", + "version": "4.0.0-48", "license": "MIT", "bin": { "frodo": "dist/launch.cjs" diff --git a/package.json b/package.json index 05da6ad32..55020d29e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rockcarver/frodo-cli", - "version": "4.0.0-47", + "version": "4.0.0-48", "type": "module", "description": "A command line interface to manage ForgeRock Identity Cloud tenants, ForgeOps deployments, and classic deployments.", "keywords": [ From e372807d88b8441632921c7cb5bc7cb5189d3ee2 Mon Sep 17 00:00:00 2001 From: Devin Holderness Date: Fri, 3 Apr 2026 14:22:57 -0600 Subject: [PATCH 43/44] -n flag added to secret pull --- .../config-manager-pull-secrets.ts | 15 +- src/configManagerOps/FrConfigSecretOps.ts | 24 +- ...config-manager-export-secrets.test.js.snap | 27 +- ...ig-manager-export-secrets.e2e.test.js.snap | 14 + .../config-manager-export-secrets.e2e.test.js | 6 + .../am_1076162899/recording.har | 312 +++++++++++++++++ .../environment_1072573434/recording.har | 331 ++++++++++++++++++ .../oauth2_393036114/recording.har | 146 ++++++++ .../openidm_3290118515/recording.har | 310 ++++++++++++++++ 9 files changed, 1164 insertions(+), 21 deletions(-) create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/am_1076162899/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/environment_1072573434/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/oauth2_393036114/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/openidm_3290118515/recording.har diff --git a/src/cli/config-manager/config-manager-pull/config-manager-pull-secrets.ts b/src/cli/config-manager/config-manager-pull/config-manager-pull-secrets.ts index ec4a69658..445fd61e5 100644 --- a/src/cli/config-manager/config-manager-pull/config-manager-pull-secrets.ts +++ b/src/cli/config-manager/config-manager-pull/config-manager-pull-secrets.ts @@ -4,6 +4,7 @@ import { configManagerExportSecrets } from '../../../configManagerOps/FrConfigSe import { getTokens } from '../../../ops/AuthenticateOps'; import { printMessage, verboseMessage } from '../../../utils/Console'; import { FrodoCommand } from '../../FrodoCommand'; +import { Option } from 'commander'; const { CLOUD_DEPLOYMENT_TYPE_KEY, FORGEOPS_DEPLOYMENT_TYPE_KEY } = frodo.utils.constants; @@ -22,6 +23,18 @@ export default function setup() { program .description('Export secrets.') + .addOption( + new Option( + '-n, --name ', + 'Name of the secret.' + ) + ) + .addOption( + new Option( + '-a, --active-only', + 'Export only active secrets.' + ) + ) .action(async (host, realm, user, password, options, command) => { command.handleDefaultArgsAndOpts( host, @@ -34,7 +47,7 @@ export default function setup() { if (await getTokens(false, true, deploymentTypes)) { verboseMessage('Exporting secrets'); - const outcome = await configManagerExportSecrets(options); + const outcome = await configManagerExportSecrets(options.name); if (!outcome) process.exitCode = 1; } // unrecognized combination of options or no options diff --git a/src/configManagerOps/FrConfigSecretOps.ts b/src/configManagerOps/FrConfigSecretOps.ts index 231f9fa09..69e713d29 100644 --- a/src/configManagerOps/FrConfigSecretOps.ts +++ b/src/configManagerOps/FrConfigSecretOps.ts @@ -12,13 +12,6 @@ import { const { getFilePath, saveJsonToFile } = frodo.utils; const { readSecrets, exportSecret } = frodo.cloud.secret; -/** - * Export all secrets to individual files in fr-config-manager format - * @param {boolean} includeMeta true to include metadata, false otherwise. Default: true - * @param {boolean} includeActiveValues include active value of secret (default: false) - * @param {string} target Host URL of target environment to encrypt secret value for - * @returns {Promise} true if successful, false otherwise - */ type FrConfigSecret = SecretSkeleton & { valueBase64: string; }; @@ -31,7 +24,16 @@ async function getFrConfigSecrets(): Promise { })); } +/** + * Export all secrets to individual files in fr-config-manager format + * @param {boolean} includeMeta true to include metadata, false otherwise. Default: true + * @param {boolean} includeActiveValues include active value of secret (default: false) + * @param {string} target Host URL of target environment to encrypt secret value for + * @param {string} name secret name + * @returns {Promise} true if successful, false otherwise + */ export async function configManagerExportSecrets( + name?: string, target?: string ): Promise { let secrets: FrConfigSecret[] = []; @@ -43,6 +45,14 @@ export async function configManagerExportSecrets( try { secrets = await getFrConfigSecrets(); secrets.sort((a, b) => a._id.localeCompare(b._id)); + if (name) { + const match = secrets.find((s) => s._id === name); + if (!match) { + stopProgressIndicator(spinnerId, `Secret '${name}' not found.`, 'fail'); + return false; + } + secrets = [match]; + } stopProgressIndicator( spinnerId, `Successfully read ${secrets.length} secrets.`, diff --git a/test/client_cli/en/__snapshots__/config-manager-export-secrets.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-export-secrets.test.js.snap index 6105598a0..8b15c501a 100644 --- a/test/client_cli/en/__snapshots__/config-manager-export-secrets.test.js.snap +++ b/test/client_cli/en/__snapshots__/config-manager-export-secrets.test.js.snap @@ -6,20 +6,21 @@ exports[`CLI help interface for 'config export' should be expected english 1`] = [Experimental] Export secrets. Arguments: - host AM base URL, e.g.: https://cdk.iam.example.com/am. To use a - connection profile, just specify a unique substring or - alias. - realm Realm. Specify realm as '/' for the root realm or 'realm' or - '/parent/child' otherwise. (default: "alpha" for Identity - Cloud tenants, "/" otherwise.) - username Username to login with. Must be an admin user with - appropriate rights to manage authentication journeys/trees. - password Password. + host AM base URL, e.g.: https://cdk.iam.example.com/am. To use a + connection profile, just specify a unique substring or + alias. + realm Realm. Specify realm as '/' for the root realm or 'realm' + or '/parent/child' otherwise. (default: "alpha" for + Identity Cloud tenants, "/" otherwise.) + username Username to login with. Must be an admin user with + appropriate rights to manage authentication journeys/trees. + password Password. Options: - -h, --help Help - -hh, --help-more Help with all options. - -hhh, --help-all Help with all options, environment variables, and usage - examples. + -n, --name Name of the secret. + -h, --help Help + -hh, --help-more Help with all options. + -hhh, --help-all Help with all options, environment variables, and usage + examples. " `; diff --git a/test/e2e/__snapshots__/config-manager-export-secrets.e2e.test.js.snap b/test/e2e/__snapshots__/config-manager-export-secrets.e2e.test.js.snap index f6e4d765a..02e85d7cb 100644 --- a/test/e2e/__snapshots__/config-manager-export-secrets.e2e.test.js.snap +++ b/test/e2e/__snapshots__/config-manager-export-secrets.e2e.test.js.snap @@ -153,3 +153,17 @@ exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secret "valueBase64": "\${ESV_VOLKERS_TEST_SECRET}", } `; + +exports[`frodo config-manager pulls "frodo config-manager pull secrets -n esv-test -D secretTestDir": should export the secret with name esv-test in fr-config-manager style" 1`] = `0`; + +exports[`frodo config-manager pulls "frodo config-manager pull secrets -n esv-test -D secretTestDir": should export the secret with name esv-test in fr-config-manager style" 2`] = `""`; + +exports[`frodo config-manager pulls "frodo config-manager pull secrets -n esv-test -D secretTestDir": should export the secret with name esv-test in fr-config-manager style": secretTestDir/esvs/secrets/esv-test.json 1`] = ` +{ + "_id": "esv-test", + "description": "test", + "encoding": "generic", + "useInPlaceholders": true, + "valueBase64": "\${ESV_TEST}", +} +`; diff --git a/test/e2e/config-manager-export-secrets.e2e.test.js b/test/e2e/config-manager-export-secrets.e2e.test.js index ad045584a..9a877316d 100644 --- a/test/e2e/config-manager-export-secrets.e2e.test.js +++ b/test/e2e/config-manager-export-secrets.e2e.test.js @@ -66,4 +66,10 @@ describe('frodo config-manager pulls', () => { const CMD = `frodo config-manager pull secrets -D ${dirName}`; await testExport(CMD, env, undefined, undefined, dirName, false); }); + test('"frodo config-manager pull secrets -n esv-test -D secretTestDir": should export the secret with name esv-test in fr-config-manager style"', async () => { + const secretName = 'esv-test'; + const dirName = 'secretTestDir'; + const CMD = `frodo config-manager pull secrets -n ${secretName} -D ${dirName}`; + await testExport(CMD, env, undefined, undefined, dirName, false); + }); }); \ No newline at end of file diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/am_1076162899/recording.har new file mode 100644 index 000000000..c947c3a06 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/am_1076162899/recording.har @@ -0,0 +1,312 @@ +{ + "log": { + "_recordingName": "config-manager/pull/secrets/0_n_D/am", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccd7a5defd0fdeaa986a2b54642d911a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-35" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + }, + { + "name": "accept-api-version", + "value": "resource=1.1" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 388, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/am/json/serverinfo/*" + }, + "response": { + "bodySize": 615, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 615, + "text": "{\"_id\":\"*\",\"_rev\":\"1955877839\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"6ac6499e9da2071\",\"secureCookie\":true,\"forgotPassword\":\"false\",\"forgotUsername\":\"false\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"false\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"allowedWithoutReferer\":true,\"refererWhitelist\":[]},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"cloudOnlyFeaturesEnabled\":true,\"oauth2AIAgentsEnabled\":false}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "content-security-policy-report-only", + "value": "frame-ancestors 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.1" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"1955877839\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "615" + }, + { + "name": "date", + "value": "Fri, 03 Apr 2026 20:03:59 GMT" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 787, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-03T20:03:59.741Z", + "time": 249, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 249 + } + }, + { + "_id": "6125d0328ad0dcaee55f73fd8b22ca14", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-35" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + }, + { + "name": "accept-api-version", + "value": "resource=1.0" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1916, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/am/json/serverinfo/version" + }, + "response": { + "bodySize": 275, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 275, + "text": "{\"_id\":\"version\",\"_rev\":\"-824275682\",\"version\":\"9.0.0-SNAPSHOT\",\"fullVersion\":\"ForgeRock Access Management 9.0.0-SNAPSHOT Build 75a770de430656acd9cf271c54af448902e5589a (2026-March-25 18:41)\",\"revision\":\"75a770de430656acd9cf271c54af448902e5589a\",\"date\":\"2026-March-25 18:41\"}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "content-security-policy-report-only", + "value": "frame-ancestors 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-824275682\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "275" + }, + { + "name": "date", + "value": "Fri, 03 Apr 2026 20:04:00 GMT" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 787, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-03T20:04:00.173Z", + "time": 148, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 148 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/environment_1072573434/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/environment_1072573434/recording.har new file mode 100644 index 000000000..cd493117c --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/environment_1072573434/recording.har @@ -0,0 +1,331 @@ +{ + "log": { + "_recordingName": "config-manager/pull/secrets/0_n_D/environment", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccc7ec61c2094114d7917814bb19b83b", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-35" + }, + { + "name": "accept-api-version", + "value": "protocol=1.0,resource=1.0" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1867, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/environment/scopes/service-accounts" + }, + "response": { + "bodySize": 1975, + "content": { + "mimeType": "application/json; charset=utf-8", + "size": 1975, + "text": "[{\"scope\":\"fr:am:*\",\"description\":\"All Access Management APIs\"},{\"scope\":\"fr:autoaccess:*\",\"description\":\"All Auto Access APIs\"},{\"scope\":\"fr:idc:analytics:*\",\"description\":\"All Analytics APIs\"},{\"scope\":\"fr:idc:certificate:*\",\"description\":\"All TLS certificate APIs\",\"childScopes\":[{\"scope\":\"fr:idc:certificate:read\",\"description\":\"Read TLS certificates\"}]},{\"scope\":\"fr:idc:content-security-policy:*\",\"description\":\"All content security policy APIs\",\"childScopes\":[{\"scope\":\"fr:idc:content-security-policy:read\",\"description\":\"Read content security policy\"}]},{\"scope\":\"fr:idc:cookie-domain:*\",\"description\":\"All cookie domain APIs\",\"childScopes\":[{\"scope\":\"fr:idc:cookie-domain:read\",\"description\":\"Read cookie domains\"}]},{\"scope\":\"fr:idc:custom-domain:*\",\"description\":\"All custom domain APIs\",\"childScopes\":[{\"scope\":\"fr:idc:custom-domain:read\",\"description\":\"Read custom domains\"}]},{\"scope\":\"fr:idc:dataset:*\",\"description\":\"All dataset deletion APIs\",\"childScopes\":[{\"scope\":\"fr:idc:dataset:read\",\"description\":\"Read dataset deletions\"}]},{\"scope\":\"fr:idc:esv:*\",\"description\":\"All ESV APIs\",\"childScopes\":[{\"scope\":\"fr:idc:esv:read\",\"description\":\"Read ESVs, excluding values of secrets\"},{\"scope\":\"fr:idc:esv:update\",\"description\":\"Create, modify, and delete ESVs\"},{\"scope\":\"fr:idc:esv:restart\",\"description\":\"Restart workloads that consume ESVs\"}]},{\"scope\":\"fr:idc:promotion:*\",\"description\":\"All configuration promotion APIs\",\"childScopes\":[{\"scope\":\"fr:idc:promotion:read\",\"description\":\"Read configuration promotion\"}]},{\"scope\":\"fr:idc:release:*\",\"description\":\"All product release APIs\",\"childScopes\":[{\"scope\":\"fr:idc:release:read\",\"description\":\"Read product release\"}]},{\"scope\":\"fr:idc:sso-cookie:*\",\"description\":\"All SSO cookie APIs\",\"childScopes\":[{\"scope\":\"fr:idc:sso-cookie:read\",\"description\":\"Read SSO cookie\"}]},{\"scope\":\"fr:idc:ws:admin\",\"description\":\"All PingFederate APIs\"},{\"scope\":\"fr:idm:*\",\"description\":\"All Identity Management APIs\"}]" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "content-type", + "value": "application/json; charset=utf-8" + }, + { + "name": "content-length", + "value": "1975" + }, + { + "name": "etag", + "value": "W/\"7b7-9oeZSONSS8Sn+SSr15TXAygvvcE\"" + }, + { + "name": "date", + "value": "Fri, 03 Apr 2026 20:04:00 GMT" + }, + { + "name": "x-forgerock-transactionid", + "value": "eb566b3b-586b-402a-bbf1-d65038fe8497" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 413, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-03T20:04:00.333Z", + "time": 76, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 76 + } + }, + { + "_id": "a24d647eb74a9e69a6b0bd9ed23dc6ce", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-35" + }, + { + "name": "accept-api-version", + "value": "protocol=1.0,resource=1.0" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1851, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets" + }, + "response": { + "bodySize": 1674, + "content": { + "mimeType": "application/json", + "size": 1674, + "text": "{\"pagedResultsCookie\":null,\"remainingPagedResults\":-1,\"result\":[{\"_id\":\"esv-osaic-fradmin-serviceclient-secret\",\"activeVersion\":\"1\",\"description\":\"Used in OSUserLogin journey. Not sure what this is used for.\\n\\n1/12/2026 Dylan Berry\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-13T19:30:38.743047Z\",\"lastChangedBy\":\"Frodo-SA-1773261131370\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-push-aws-sns-access-key-id\",\"activeVersion\":\"1\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-13T19:30:39.673227Z\",\"lastChangedBy\":\"Frodo-SA-1773261131370\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-push-aws-sns-access-key-secret\",\"activeVersion\":\"1\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-13T19:30:40.637978Z\",\"lastChangedBy\":\"Frodo-SA-1773261131370\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-sns-access-key-id\",\"activeVersion\":\"1\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-13T19:30:41.602432Z\",\"lastChangedBy\":\"Frodo-SA-1773261131370\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-sns-access-key-secret\",\"activeVersion\":\"1\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-13T19:30:42.847978Z\",\"lastChangedBy\":\"Frodo-SA-1773261131370\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-test\",\"activeVersion\":\"1\",\"description\":\"test\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-30T19:45:08.231563Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}],\"resultCount\":6,\"totalPagedResults\":-1,\"totalPagedResultsPolicy\":\"NONE\"}" + }, + "cookies": [], + "headers": [ + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "date", + "value": "Fri, 03 Apr 2026 20:04:00 GMT" + }, + { + "name": "content-length", + "value": "1674" + }, + { + "name": "x-forgerock-transactionid", + "value": "7574b573-13d4-4aa8-a20e-f6405cac8716" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 326, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-03T20:04:00.498Z", + "time": 167, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 167 + } + }, + { + "_id": "764536c00fd6a03a419ab64846c65bfa", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-35" + }, + { + "name": "accept-api-version", + "value": "protocol=1.0,resource=1.0" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1860, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test" + }, + "response": { + "bodySize": 223, + "content": { + "mimeType": "application/json", + "size": 223, + "text": "{\"_id\":\"esv-test\",\"activeVersion\":\"1\",\"description\":\"test\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-30T19:45:08.231563Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" + }, + "cookies": [], + "headers": [ + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "date", + "value": "Fri, 03 Apr 2026 20:04:00 GMT" + }, + { + "name": "content-length", + "value": "223" + }, + { + "name": "x-forgerock-transactionid", + "value": "5ca2e49e-1723-49aa-bd68-5ecbdc614bf8" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 325, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-03T20:04:00.688Z", + "time": 201, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 201 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/oauth2_393036114/recording.har new file mode 100644 index 000000000..0f3ba79b8 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/oauth2_393036114/recording.har @@ -0,0 +1,146 @@ +{ + "log": { + "_recordingName": "config-manager/pull/secrets/0_n_D/oauth2", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ff75519a93ccab829f8ee8cf5e92b49f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 1329, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-35" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-length", + "value": "1329" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 443, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "assertion=&client_id=service-account&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=fr:idc:custom-domain:* fr:idc:release:* fr:idc:sso-cookie:* fr:am:* fr:autoaccess:* fr:idc:content-security-policy:* fr:idc:esv:* fr:idc:certificate:* fr:idm:* fr:idc:analytics:* fr:idc:cookie-domain:* fr:idc:promotion:*" + }, + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/am/oauth2/access_token" + }, + "response": { + "bodySize": 1787, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1787, + "text": "{\"access_token\":\"\",\"scope\":\"fr:idc:custom-domain:* fr:idc:release:* fr:idc:sso-cookie:* fr:am:* fr:autoaccess:* fr:idc:content-security-policy:* fr:idc:esv:* fr:idc:certificate:* fr:idm:* fr:idc:analytics:* fr:idc:cookie-domain:* fr:idc:promotion:*\",\"token_type\":\"Bearer\",\"expires_in\":899}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "content-security-policy-report-only", + "value": "frame-ancestors 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1787" + }, + { + "name": "date", + "value": "Fri, 03 Apr 2026 20:04:00 GMT" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 561, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-03T20:04:00.032Z", + "time": 126, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 126 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/openidm_3290118515/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/openidm_3290118515/recording.har new file mode 100644 index 000000000..e7497e1eb --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/openidm_3290118515/recording.har @@ -0,0 +1,310 @@ +{ + "log": { + "_recordingName": "config-manager/pull/secrets/0_n_D/openidm", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "9cb8561357870863838a9948da32d1e8", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-35" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1928, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_fields", + "value": "*" + } + ], + "url": "https://openam-frodo-dev.forgeblocks.com/openidm/managed/svcacct/22e714dc-a1b0-4f61-819c-148df8ed5fe6?_fields=%2A" + }, + "response": { + "bodySize": 1437, + "content": { + "mimeType": "application/json;charset=utf-8", + "size": 1437, + "text": "{\"_id\":\"22e714dc-a1b0-4f61-819c-148df8ed5fe6\",\"_rev\":\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\",\"accountStatus\":\"active\",\"name\":\"devin_svc\",\"description\":null,\"scopes\":[\"fr:am:*\",\"fr:idm:*\",\"fr:autoaccess:*\",\"fr:idc:analytics:*\",\"fr:idc:certificate:*\",\"fr:idc:certificate:read\",\"fr:idc:content-security-policy:*\",\"fr:idc:content-security-policy:read\",\"fr:idc:cookie-domain:*\",\"fr:idc:cookie-domain:read\",\"fr:idc:custom-domain:*\",\"fr:idc:custom-domain:read\",\"fr:idc:esv:*\",\"fr:idc:promotion:*\",\"fr:idc:promotion:read\",\"fr:idc:release:*\",\"fr:idc:release:read\",\"fr:idc:sso-cookie:*\",\"fr:idc:sso-cookie:read\"],\"jwks\":\"{\\\"keys\\\":[{\\\"e\\\":\\\"AQAB\\\",\\\"kty\\\":\\\"RSA\\\",\\\"n\\\":\\\"mbFgXRafUw0vumgdyXkNSLt7eO-iShWEnJaZQftnHAEyFv0-13aUd5bNd4ccMKjxfCCj2pzfruKsvcsY1MSDuQgvhgap5jo-gfmebWmGBFiwOL1_wQkrR8sL_JaGnBIbidoHJ-3wVv4nSEJ96wmOYdGo4OkY6hoICnT653cpw4Zw66DSUb6RWzxcxLFBtvhn2Y2_Q1nuU6nowPG1rcCJ_JcoW3zW_OG4Yt5WcIPzLUwfMbXw1grRPZg4Qqxpbo7vIrlExB6iQ-LdARG8_0rPpH_SUcAizR_c0Vp3SMhLg5pi_gVR9dU42WBGpJT6u3uO9kuOC6noJThg5F7M1drlhgasFtGioi2iCsTBitJPjXAEW-Do34Y2KB0bGJ1bLZNkyRJY3VLfYH8dO7FwIPpVCpHSOG7ml6YmYDIFymvCuB8e5rQS_xUb1PEK2YK1TC0ne_uvyb1lZ2RrGfzGZigtC4MJ_Rd4v-r4Z8BbCbykS-zqbEoCjsRUtcVmwBJGiln_Y9MpT42j6EaNxb5hJDAAGx98u57gQ4TcqyAeNOCPNt2QOddtsmcaQlkN9DKYKlLcMp9OQ6SqaFtY-LKoyq7fIYf8v_2uXZFjqmqokKxWFMfLIHj33B4bdRgRWitpeS2x1xZX_FylumYChE2daiRxRvA-kVcMYWMwAkSZcbU9Ovs\\\"}]}\",\"maxCachingTime\":\"15\",\"maxIdleTime\":\"15\",\"maxSessionTime\":\"15\",\"quotaLimit\":\"5\"}" + }, + "cookies": [], + "headers": [ + { + "name": "date", + "value": "Fri, 03 Apr 2026 20:04:00 GMT" + }, + { + "name": "vary", + "value": "Origin" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "content-type", + "value": "application/json;charset=utf-8" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "DENY" + }, + { + "name": "content-length", + "value": "1437" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 683, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-03T20:04:00.171Z", + "time": 87, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 87 + } + }, + { + "_id": "9cb8561357870863838a9948da32d1e8", + "_order": 1, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-35" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1928, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_fields", + "value": "*" + } + ], + "url": "https://openam-frodo-dev.forgeblocks.com/openidm/managed/svcacct/22e714dc-a1b0-4f61-819c-148df8ed5fe6?_fields=%2A" + }, + "response": { + "bodySize": 1437, + "content": { + "mimeType": "application/json;charset=utf-8", + "size": 1437, + "text": "{\"_id\":\"22e714dc-a1b0-4f61-819c-148df8ed5fe6\",\"_rev\":\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\",\"accountStatus\":\"active\",\"name\":\"devin_svc\",\"description\":null,\"scopes\":[\"fr:am:*\",\"fr:idm:*\",\"fr:autoaccess:*\",\"fr:idc:analytics:*\",\"fr:idc:certificate:*\",\"fr:idc:certificate:read\",\"fr:idc:content-security-policy:*\",\"fr:idc:content-security-policy:read\",\"fr:idc:cookie-domain:*\",\"fr:idc:cookie-domain:read\",\"fr:idc:custom-domain:*\",\"fr:idc:custom-domain:read\",\"fr:idc:esv:*\",\"fr:idc:promotion:*\",\"fr:idc:promotion:read\",\"fr:idc:release:*\",\"fr:idc:release:read\",\"fr:idc:sso-cookie:*\",\"fr:idc:sso-cookie:read\"],\"jwks\":\"{\\\"keys\\\":[{\\\"e\\\":\\\"AQAB\\\",\\\"kty\\\":\\\"RSA\\\",\\\"n\\\":\\\"mbFgXRafUw0vumgdyXkNSLt7eO-iShWEnJaZQftnHAEyFv0-13aUd5bNd4ccMKjxfCCj2pzfruKsvcsY1MSDuQgvhgap5jo-gfmebWmGBFiwOL1_wQkrR8sL_JaGnBIbidoHJ-3wVv4nSEJ96wmOYdGo4OkY6hoICnT653cpw4Zw66DSUb6RWzxcxLFBtvhn2Y2_Q1nuU6nowPG1rcCJ_JcoW3zW_OG4Yt5WcIPzLUwfMbXw1grRPZg4Qqxpbo7vIrlExB6iQ-LdARG8_0rPpH_SUcAizR_c0Vp3SMhLg5pi_gVR9dU42WBGpJT6u3uO9kuOC6noJThg5F7M1drlhgasFtGioi2iCsTBitJPjXAEW-Do34Y2KB0bGJ1bLZNkyRJY3VLfYH8dO7FwIPpVCpHSOG7ml6YmYDIFymvCuB8e5rQS_xUb1PEK2YK1TC0ne_uvyb1lZ2RrGfzGZigtC4MJ_Rd4v-r4Z8BbCbykS-zqbEoCjsRUtcVmwBJGiln_Y9MpT42j6EaNxb5hJDAAGx98u57gQ4TcqyAeNOCPNt2QOddtsmcaQlkN9DKYKlLcMp9OQ6SqaFtY-LKoyq7fIYf8v_2uXZFjqmqokKxWFMfLIHj33B4bdRgRWitpeS2x1xZX_FylumYChE2daiRxRvA-kVcMYWMwAkSZcbU9Ovs\\\"}]}\",\"maxCachingTime\":\"15\",\"maxIdleTime\":\"15\",\"maxSessionTime\":\"15\",\"quotaLimit\":\"5\"}" + }, + "cookies": [], + "headers": [ + { + "name": "date", + "value": "Fri, 03 Apr 2026 20:04:00 GMT" + }, + { + "name": "vary", + "value": "Origin" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "content-type", + "value": "application/json;charset=utf-8" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "DENY" + }, + { + "name": "content-length", + "value": "1437" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 683, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-03T20:04:00.418Z", + "time": 64, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 64 + } + } + ], + "pages": [], + "version": "1.2" + } +} From dea6f7d34234032e5a7517009de20a3fe5a22c8e Mon Sep 17 00:00:00 2001 From: Devin Holderness Date: Tue, 14 Apr 2026 12:51:44 -0600 Subject: [PATCH 44/44] -a flag added to secret pull --- .../config-manager-pull-secrets.ts | 19 +- src/configManagerOps/FrConfigSecretOps.ts | 66 +- ...config-manager-export-secrets.test.js.snap | 1 + ...config-manager-export-all.e2e.test.js.snap | 150 -- ...ig-manager-export-secrets.e2e.test.js.snap | 174 +-- .../config-manager-export-secrets.e2e.test.js | 5 + .../am_1076162899/recording.har | 56 +- .../environment_1072573434/recording.har | 1354 +---------------- .../oauth2_393036114/recording.har | 20 +- .../openidm_3290118515/recording.har | 62 +- .../am_1076162899/recording.har | 312 ++++ .../environment_1072573434/recording.har | 331 ++++ .../oauth2_393036114/recording.har | 146 ++ .../openidm_3290118515/recording.har | 310 ++++ .../am_1076162899/recording.har | 42 +- .../environment_1072573434/recording.har | 161 +- .../oauth2_393036114/recording.har | 14 +- .../openidm_3290118515/recording.har | 32 +- 18 files changed, 1489 insertions(+), 1766 deletions(-) create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/am_1076162899/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/environment_1072573434/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/oauth2_393036114/recording.har create mode 100644 test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/openidm_3290118515/recording.har diff --git a/src/cli/config-manager/config-manager-pull/config-manager-pull-secrets.ts b/src/cli/config-manager/config-manager-pull/config-manager-pull-secrets.ts index 445fd61e5..46d6d8453 100644 --- a/src/cli/config-manager/config-manager-pull/config-manager-pull-secrets.ts +++ b/src/cli/config-manager/config-manager-pull/config-manager-pull-secrets.ts @@ -1,10 +1,10 @@ import { frodo } from '@rockcarver/frodo-lib'; +import { Option } from 'commander'; import { configManagerExportSecrets } from '../../../configManagerOps/FrConfigSecretOps'; import { getTokens } from '../../../ops/AuthenticateOps'; import { printMessage, verboseMessage } from '../../../utils/Console'; import { FrodoCommand } from '../../FrodoCommand'; -import { Option } from 'commander'; const { CLOUD_DEPLOYMENT_TYPE_KEY, FORGEOPS_DEPLOYMENT_TYPE_KEY } = frodo.utils.constants; @@ -23,17 +23,9 @@ export default function setup() { program .description('Export secrets.') + .addOption(new Option('-n, --name ', 'Name of the secret.')) .addOption( - new Option( - '-n, --name ', - 'Name of the secret.' - ) - ) - .addOption( - new Option( - '-a, --active-only', - 'Export only active secrets.' - ) + new Option('-a, --active-only', 'Export secrets without version history.') ) .action(async (host, realm, user, password, options, command) => { command.handleDefaultArgsAndOpts( @@ -47,7 +39,10 @@ export default function setup() { if (await getTokens(false, true, deploymentTypes)) { verboseMessage('Exporting secrets'); - const outcome = await configManagerExportSecrets(options.name); + const outcome = await configManagerExportSecrets( + options.name, + options.activeOnly + ); if (!outcome) process.exitCode = 1; } // unrecognized combination of options or no options diff --git a/src/configManagerOps/FrConfigSecretOps.ts b/src/configManagerOps/FrConfigSecretOps.ts index 69e713d29..a84a9405b 100644 --- a/src/configManagerOps/FrConfigSecretOps.ts +++ b/src/configManagerOps/FrConfigSecretOps.ts @@ -10,82 +10,80 @@ import { } from '../utils/Console'; const { getFilePath, saveJsonToFile } = frodo.utils; -const { readSecrets, exportSecret } = frodo.cloud.secret; +const { readSecrets, readVersionsOfSecret, exportSecret } = frodo.cloud.secret; type FrConfigSecret = SecretSkeleton & { valueBase64: string; }; -async function getFrConfigSecrets(): Promise { - const originalSecrets = await readSecrets(); - return originalSecrets.map((secret) => ({ - ...secret, - valueBase64: `\${${secret._id.toUpperCase().replace(/-/g, '_')}}`, - })); -} - /** * Export all secrets to individual files in fr-config-manager format - * @param {boolean} includeMeta true to include metadata, false otherwise. Default: true - * @param {boolean} includeActiveValues include active value of secret (default: false) - * @param {string} target Host URL of target environment to encrypt secret value for - * @param {string} name secret name + * @param {string} name secret name. If not specified, will export all secrets + * @param {boolean} activeOnly true to exclude secret version history. Default: false * @returns {Promise} true if successful, false otherwise */ export async function configManagerExportSecrets( name?: string, - target?: string + activeOnly?: boolean ): Promise { - let secrets: FrConfigSecret[] = []; + let secrets: FrConfigSecret[]; const spinnerId = createProgressIndicator( 'indeterminate', 0, `Reading secrets...` ); try { - secrets = await getFrConfigSecrets(); - secrets.sort((a, b) => a._id.localeCompare(b._id)); + const allSecrets = (await readSecrets()).map((secret) => ({ + ...secret, + valueBase64: `\${${secret._id.toUpperCase().replace(/-/g, '_')}}`, + })); if (name) { - const match = secrets.find((s) => s._id === name); + const match = allSecrets.find((s) => s._id === name); if (!match) { stopProgressIndicator(spinnerId, `Secret '${name}' not found.`, 'fail'); return false; } secrets = [match]; + } else { + secrets = allSecrets.sort((a, b) => a._id.localeCompare(b._id)); } - stopProgressIndicator( - spinnerId, - `Successfully read ${secrets.length} secrets.`, - 'success' - ); - const indicatorId = createProgressIndicator( - 'determinate', - secrets.length, - 'Exporting secrets' - ); + updateProgressIndicator(spinnerId, `Saving secrets...`); for (const secret of secrets) { const exportData: SecretsExportInterface = await exportSecret( secret._id, - false, - target + false ); const [secretKey] = Object.keys(exportData.secret); const fullSecret = exportData.secret[secretKey] as FrConfigSecret; - const cleanSecret = { + const cleanSecret: Record = { _id: fullSecret._id, description: fullSecret.description, encoding: fullSecret.encoding, useInPlaceholders: fullSecret.useInPlaceholders, - valueBase64: `\${${secret._id.toUpperCase().replace(/-/g, '_')}}`, + valueBase64: secret.valueBase64, }; + if (!activeOnly) { + const versions = await readVersionsOfSecret(secret._id); + const baseKey = secret._id.toUpperCase().replace(/-/g, '_'); + delete cleanSecret.valueBase64; + cleanSecret.versions = versions + .sort((a, b) => Number(a.version) - Number(b.version)) + .map(({ version }) => ({ + valueBase64: `\${${baseKey}_${version}}`, + version, + })); + } saveJsonToFile( cleanSecret, getFilePath(`esvs/secrets/${secret._id}.json`, true), false ); - updateProgressIndicator(indicatorId, `Exported secret ${secret._id}`); } - stopProgressIndicator(indicatorId, `${secrets.length} secrets exported.`); + stopProgressIndicator( + spinnerId, + `${secrets.length} secrets exported.`, + 'success' + ); return true; } catch (error) { stopProgressIndicator( diff --git a/test/client_cli/en/__snapshots__/config-manager-export-secrets.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-export-secrets.test.js.snap index 8b15c501a..0f4cbc90e 100644 --- a/test/client_cli/en/__snapshots__/config-manager-export-secrets.test.js.snap +++ b/test/client_cli/en/__snapshots__/config-manager-export-secrets.test.js.snap @@ -17,6 +17,7 @@ Arguments: password Password. Options: + -a, --active-only Export secrets without version history. -n, --name Name of the secret. -h, --help Help -hh, --help-more Help with all options. diff --git a/test/e2e/__snapshots__/config-manager-export-all.e2e.test.js.snap b/test/e2e/__snapshots__/config-manager-export-all.e2e.test.js.snap index d459962f2..3ede361c9 100644 --- a/test/e2e/__snapshots__/config-manager-export-all.e2e.test.js.snap +++ b/test/e2e/__snapshots__/config-manager-export-all.e2e.test.js.snap @@ -910,156 +910,6 @@ exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": } `; -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-admin-token.json 1`] = ` -{ - "_id": "esv-admin-token", - "description": "Long-lived admin token", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_ADMIN_TOKEN}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-brando-pingone.json 1`] = ` -{ - "_id": "esv-brando-pingone", - "description": "This is to show the connection between PingOne and AIC. ", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_BRANDO_PINGONE}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-sean-test.json 1`] = ` -{ - "_id": "esv-sean-test", - "description": "", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_SEAN_TEST}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-secret-import-test1.json 1`] = ` -{ - "_id": "esv-secret-import-test1", - "description": "Secret Import Test 1", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_SECRET_IMPORT_TEST1}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-secret-import-test2.json 1`] = ` -{ - "_id": "esv-secret-import-test2", - "description": "Secret Import Test 2", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_SECRET_IMPORT_TEST2}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-test-client-cert.json 1`] = ` -{ - "_id": "esv-test-client-cert", - "description": "Test HTTP Client client cert", - "encoding": "pem", - "useInPlaceholders": false, - "valueBase64": "\${ESV_TEST_CLIENT_CERT}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-test-secret.json 1`] = ` -{ - "_id": "esv-test-secret", - "description": "This is a test secret containing a simple string value.", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-test-secret-cert-pem.json 1`] = ` -{ - "_id": "esv-test-secret-cert-pem", - "description": "This is a test secret from a pem encoded cert file.", - "encoding": "pem", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_CERT_PEM}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-test-secret-cert-pem-raw.json 1`] = ` -{ - "_id": "esv-test-secret-cert-pem-raw", - "description": "This is a test secret from a pem encoded cert file (raw).", - "encoding": "pem", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_CERT_PEM_RAW}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-test-secret-euler.json 1`] = ` -{ - "_id": "esv-test-secret-euler", - "description": "A test secret containing the value of Euler's number", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_EULER}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-test-secret-file-base64hmac.json 1`] = ` -{ - "_id": "esv-test-secret-file-base64hmac", - "description": "This is a test secret from base64 encoded hmac key file.", - "encoding": "base64hmac", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_FILE_BASE64HMAC}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-test-secret-file-base64hmac-raw.json 1`] = ` -{ - "_id": "esv-test-secret-file-base64hmac-raw", - "description": "This is a test secret from base64 encoded hmac key file (raw).", - "encoding": "base64hmac", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_FILE_BASE64HMAC_RAW}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-test-secret-pi.json 1`] = ` -{ - "_id": "esv-test-secret-pi", - "description": "Secret that contains the value of pi", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_PI}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-test-secret-pi-generic.json 1`] = ` -{ - "_id": "esv-test-secret-pi-generic", - "description": "", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_PI_GENERIC}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/secrets/esv-volkers-test-secret.json 1`] = ` -{ - "_id": "esv-volkers-test-secret", - "description": "Volker's test secret", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_VOLKERS_TEST_SECRET}", -} -`; - exports[`frodo config-manager pulls "frodo config-manager pull all -D allDir1": should export all config in fr-config-manager style": allDir1/esvs/variables/esv-blue-piller.json 1`] = ` { "_id": "esv-blue-piller", diff --git a/test/e2e/__snapshots__/config-manager-export-secrets.e2e.test.js.snap b/test/e2e/__snapshots__/config-manager-export-secrets.e2e.test.js.snap index 02e85d7cb..3dfb76cb8 100644 --- a/test/e2e/__snapshots__/config-manager-export-secrets.e2e.test.js.snap +++ b/test/e2e/__snapshots__/config-manager-export-secrets.e2e.test.js.snap @@ -4,153 +4,40 @@ exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secret exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style" 2`] = `""`; -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-admin-token.json 1`] = ` +exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-test.json 1`] = ` { - "_id": "esv-admin-token", - "description": "Long-lived admin token", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_ADMIN_TOKEN}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-brando-pingone.json 1`] = ` -{ - "_id": "esv-brando-pingone", - "description": "This is to show the connection between PingOne and AIC. ", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_BRANDO_PINGONE}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-sean-test.json 1`] = ` -{ - "_id": "esv-sean-test", - "description": "", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_SEAN_TEST}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-secret-import-test1.json 1`] = ` -{ - "_id": "esv-secret-import-test1", - "description": "Secret Import Test 1", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_SECRET_IMPORT_TEST1}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-secret-import-test2.json 1`] = ` -{ - "_id": "esv-secret-import-test2", - "description": "Secret Import Test 2", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_SECRET_IMPORT_TEST2}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-test-client-cert.json 1`] = ` -{ - "_id": "esv-test-client-cert", - "description": "Test HTTP Client client cert", - "encoding": "pem", - "useInPlaceholders": false, - "valueBase64": "\${ESV_TEST_CLIENT_CERT}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-test-secret.json 1`] = ` -{ - "_id": "esv-test-secret", - "description": "This is a test secret containing a simple string value.", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-test-secret-cert-pem.json 1`] = ` -{ - "_id": "esv-test-secret-cert-pem", - "description": "This is a test secret from a pem encoded cert file.", - "encoding": "pem", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_CERT_PEM}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-test-secret-cert-pem-raw.json 1`] = ` -{ - "_id": "esv-test-secret-cert-pem-raw", - "description": "This is a test secret from a pem encoded cert file (raw).", - "encoding": "pem", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_CERT_PEM_RAW}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-test-secret-euler.json 1`] = ` -{ - "_id": "esv-test-secret-euler", - "description": "A test secret containing the value of Euler's number", + "_id": "esv-test", + "description": "test", "encoding": "generic", "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_EULER}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-test-secret-file-base64hmac.json 1`] = ` -{ - "_id": "esv-test-secret-file-base64hmac", - "description": "This is a test secret from base64 encoded hmac key file.", - "encoding": "base64hmac", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_FILE_BASE64HMAC}", + "versions": [ + { + "valueBase64": "\${ESV_TEST_1}", + "version": "1", + }, + { + "valueBase64": "\${ESV_TEST_2}", + "version": "2", + }, + { + "valueBase64": "\${ESV_TEST_3}", + "version": "3", + }, + ], } `; -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-test-secret-file-base64hmac-raw.json 1`] = ` -{ - "_id": "esv-test-secret-file-base64hmac-raw", - "description": "This is a test secret from base64 encoded hmac key file (raw).", - "encoding": "base64hmac", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_FILE_BASE64HMAC_RAW}", -} -`; +exports[`frodo config-manager pulls "frodo config-manager pull secrets -a -D secretTestDir": should export the secrets in fr-config-manager style without version history" 1`] = `0`; -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-test-secret-pi.json 1`] = ` -{ - "_id": "esv-test-secret-pi", - "description": "Secret that contains the value of pi", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_PI}", -} -`; +exports[`frodo config-manager pulls "frodo config-manager pull secrets -a -D secretTestDir": should export the secrets in fr-config-manager style without version history" 2`] = `""`; -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-test-secret-pi-generic.json 1`] = ` +exports[`frodo config-manager pulls "frodo config-manager pull secrets -a -D secretTestDir": should export the secrets in fr-config-manager style without version history": secretTestDir/esvs/secrets/esv-test.json 1`] = ` { - "_id": "esv-test-secret-pi-generic", - "description": "", - "encoding": "generic", - "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST_SECRET_PI_GENERIC}", -} -`; - -exports[`frodo config-manager pulls "frodo config-manager pull secrets -D secretTestDir": should export the secrets in fr-config-manager style": secretTestDir/esvs/secrets/esv-volkers-test-secret.json 1`] = ` -{ - "_id": "esv-volkers-test-secret", - "description": "Volker's test secret", + "_id": "esv-test", + "description": "test", "encoding": "generic", "useInPlaceholders": true, - "valueBase64": "\${ESV_VOLKERS_TEST_SECRET}", + "valueBase64": "\${ESV_TEST}", } `; @@ -164,6 +51,19 @@ exports[`frodo config-manager pulls "frodo config-manager pull secrets -n esv-te "description": "test", "encoding": "generic", "useInPlaceholders": true, - "valueBase64": "\${ESV_TEST}", + "versions": [ + { + "valueBase64": "\${ESV_TEST_1}", + "version": "1", + }, + { + "valueBase64": "\${ESV_TEST_2}", + "version": "2", + }, + { + "valueBase64": "\${ESV_TEST_3}", + "version": "3", + }, + ], } `; diff --git a/test/e2e/config-manager-export-secrets.e2e.test.js b/test/e2e/config-manager-export-secrets.e2e.test.js index 9a877316d..0a713c97a 100644 --- a/test/e2e/config-manager-export-secrets.e2e.test.js +++ b/test/e2e/config-manager-export-secrets.e2e.test.js @@ -72,4 +72,9 @@ describe('frodo config-manager pulls', () => { const CMD = `frodo config-manager pull secrets -n ${secretName} -D ${dirName}`; await testExport(CMD, env, undefined, undefined, dirName, false); }); + test('"frodo config-manager pull secrets -a -D secretTestDir": should export the secrets in fr-config-manager style without version history"', async () => { + const dirName = 'secretTestDir'; + const CMD = `frodo config-manager pull secrets -a -D ${dirName}`; + await testExport(CMD, env, undefined, undefined, dirName, false); + }); }); \ No newline at end of file diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/am_1076162899/recording.har index a277a80d4..161c07fae 100644 --- a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/am_1076162899/recording.har +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/am_1076162899/recording.har @@ -25,11 +25,11 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "x-forgerock-transactionid", - "value": "frodo-93c9cba5-db71-435f-bc8c-352f35d7263a" + "value": "frodo-b5cace15-6bd6-463d-95eb-ab3d1d98f98f" }, { "name": "accept-api-version", @@ -44,18 +44,18 @@ "value": "openam-frodo-dev.forgeblocks.com" } ], - "headersSize": 385, + "headersSize": 388, "httpVersion": "HTTP/1.1", "method": "GET", "queryString": [], "url": "https://openam-frodo-dev.forgeblocks.com/am/json/serverinfo/*" }, "response": { - "bodySize": 553, + "bodySize": 615, "content": { "mimeType": "application/json;charset=UTF-8", - "size": 553, - "text": "{\"_id\":\"*\",\"_rev\":\"1874515102\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"6ac6499e9da2071\",\"secureCookie\":true,\"forgotPassword\":\"false\",\"forgotUsername\":\"false\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"false\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"refererWhitelist\":[],\"allowedWithoutReferer\":true},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[]}" + "size": 615, + "text": "{\"_id\":\"*\",\"_rev\":\"1955877839\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"6ac6499e9da2071\",\"secureCookie\":true,\"forgotPassword\":\"false\",\"forgotUsername\":\"false\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"false\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"allowedWithoutReferer\":true,\"refererWhitelist\":[]},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"cloudOnlyFeaturesEnabled\":true,\"oauth2AIAgentsEnabled\":false}" }, "cookies": [], "headers": [ @@ -93,7 +93,7 @@ }, { "name": "etag", - "value": "\"1874515102\"" + "value": "\"1955877839\"" }, { "name": "expires", @@ -109,15 +109,15 @@ }, { "name": "content-length", - "value": "553" + "value": "615" }, { "name": "date", - "value": "Mon, 23 Jun 2025 23:22:02 GMT" + "value": "Tue, 14 Apr 2026 18:46:44 GMT" }, { "name": "x-forgerock-transactionid", - "value": "frodo-93c9cba5-db71-435f-bc8c-352f35d7263a" + "value": "frodo-b5cace15-6bd6-463d-95eb-ab3d1d98f98f" }, { "name": "strict-transport-security", @@ -142,8 +142,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2025-06-23T23:22:02.223Z", - "time": 150, + "startedDateTime": "2026-04-14T18:46:44.752Z", + "time": 182, "timings": { "blocked": -1, "connect": -1, @@ -151,7 +151,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 150 + "wait": 182 } }, { @@ -172,11 +172,11 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "x-forgerock-transactionid", - "value": "frodo-93c9cba5-db71-435f-bc8c-352f35d7263a" + "value": "frodo-b5cace15-6bd6-463d-95eb-ab3d1d98f98f" }, { "name": "accept-api-version", @@ -195,18 +195,18 @@ "value": "openam-frodo-dev.forgeblocks.com" } ], - "headersSize": 1913, + "headersSize": 1916, "httpVersion": "HTTP/1.1", "method": "GET", "queryString": [], "url": "https://openam-frodo-dev.forgeblocks.com/am/json/serverinfo/version" }, "response": { - "bodySize": 273, + "bodySize": 276, "content": { "mimeType": "application/json;charset=UTF-8", - "size": 273, - "text": "{\"_id\":\"version\",\"_rev\":\"-750667214\",\"version\":\"8.0.0-SNAPSHOT\",\"fullVersion\":\"ForgeRock Access Management 8.0.0-SNAPSHOT Build 2afa9838c3cd077e075ad764cf803942edda1c9a (2025-June-05 16:09)\",\"revision\":\"2afa9838c3cd077e075ad764cf803942edda1c9a\",\"date\":\"2025-June-05 16:09\"}" + "size": 276, + "text": "{\"_id\":\"version\",\"_rev\":\"-1876078088\",\"version\":\"9.0.0-SNAPSHOT\",\"fullVersion\":\"ForgeRock Access Management 9.0.0-SNAPSHOT Build 2a2686af9631bd8d8866c92ea2411814899acefd (2026-March-30 15:23)\",\"revision\":\"2a2686af9631bd8d8866c92ea2411814899acefd\",\"date\":\"2026-March-30 15:23\"}" }, "cookies": [], "headers": [ @@ -244,7 +244,7 @@ }, { "name": "etag", - "value": "\"-750667214\"" + "value": "\"-1876078088\"" }, { "name": "expires", @@ -260,15 +260,15 @@ }, { "name": "content-length", - "value": "273" + "value": "276" }, { "name": "date", - "value": "Mon, 23 Jun 2025 23:22:02 GMT" + "value": "Tue, 14 Apr 2026 18:46:45 GMT" }, { "name": "x-forgerock-transactionid", - "value": "frodo-93c9cba5-db71-435f-bc8c-352f35d7263a" + "value": "frodo-b5cace15-6bd6-463d-95eb-ab3d1d98f98f" }, { "name": "strict-transport-security", @@ -284,17 +284,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 787, + "headersSize": 763, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2025-06-23T23:22:02.485Z", - "time": 121, + "startedDateTime": "2026-04-14T18:46:45.166Z", + "time": 148, "timings": { "blocked": -1, "connect": -1, @@ -302,7 +302,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 121 + "wait": 148 } } ], diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/environment_1072573434/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/environment_1072573434/recording.har index 479da2c58..4a9127ee4 100644 --- a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/environment_1072573434/recording.har +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/environment_1072573434/recording.har @@ -8,7 +8,7 @@ }, "entries": [ { - "_id": "a24d647eb74a9e69a6b0bd9ed23dc6ce", + "_id": "ccc7ec61c2094114d7917814bb19b83b", "_order": 0, "cache": {}, "request": { @@ -25,7 +25,7 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "accept-api-version", @@ -44,139 +44,44 @@ "value": "openam-frodo-dev.forgeblocks.com" } ], - "headersSize": 1848, + "headersSize": 1867, "httpVersion": "HTTP/1.1", "method": "GET", "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets" + "url": "https://openam-frodo-dev.forgeblocks.com/environment/scopes/service-accounts" }, "response": { - "bodySize": 4311, + "bodySize": 1975, "content": { - "mimeType": "application/json", - "size": 4311, - "text": "{\"pagedResultsCookie\":null,\"remainingPagedResults\":-1,\"result\":[{\"_id\":\"esv-admin-token\",\"activeVersion\":\"1\",\"description\":\"Long-lived admin token\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-03-20T14:46:13.461793Z\",\"lastChangedBy\":\"ba58ff99-76d3-4c69-9c4a-7f150ac70e2c\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-brando-pingone\",\"activeVersion\":\"4\",\"description\":\"This is to show the connection between PingOne and AIC. \",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-06-24T00:44:06.154598Z\",\"lastChangedBy\":\"Frodo-SA-1701393386423\",\"loaded\":true,\"loadedVersion\":\"4\",\"useInPlaceholders\":true},{\"_id\":\"esv-sean-test\",\"activeVersion\":\"1\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2025-04-11T21:35:33.98194Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-secret-import-test1\",\"activeVersion\":\"1\",\"description\":\"Secret Import Test 1\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-06-22T01:13:13.904591Z\",\"lastChangedBy\":\"volker.scheuber@forgerock.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-secret-import-test2\",\"activeVersion\":\"1\",\"description\":\"Secret Import Test 2\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-06-22T01:13:41.914076Z\",\"lastChangedBy\":\"volker.scheuber@forgerock.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-test-client-cert\",\"activeVersion\":\"1\",\"description\":\"Test HTTP Client client cert\",\"encoding\":\"pem\",\"lastChangeDate\":\"2025-06-12T20:19:16.975613Z\",\"lastChangedBy\":\"Frodo-SA-1725981758244\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":false},{\"_id\":\"esv-test-secret\",\"activeVersion\":\"1\",\"description\":\"This is a test secret containing a simple string value.\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-07-05T17:53:53.682578Z\",\"lastChangedBy\":\"Frodo-SA-1701393386423\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-test-secret-cert-pem\",\"activeVersion\":\"1\",\"description\":\"This is a test secret from a pem encoded cert file.\",\"encoding\":\"pem\",\"lastChangeDate\":\"2024-01-20T03:48:49.005574Z\",\"lastChangedBy\":\"6bac97fb-0665-4ba9-b66c-1cf70e074d72\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-test-secret-cert-pem-raw\",\"activeVersion\":\"1\",\"description\":\"This is a test secret from a pem encoded cert file (raw).\",\"encoding\":\"pem\",\"lastChangeDate\":\"2024-01-20T03:49:20.270526Z\",\"lastChangedBy\":\"6bac97fb-0665-4ba9-b66c-1cf70e074d72\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-test-secret-euler\",\"activeVersion\":\"1\",\"description\":\"A test secret containing the value of Euler's number\",\"encoding\":\"generic\",\"lastChangeDate\":\"2023-12-14T15:27:34.607038Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-test-secret-file-base64hmac\",\"activeVersion\":\"1\",\"description\":\"This is a test secret from base64 encoded hmac key file.\",\"encoding\":\"base64hmac\",\"lastChangeDate\":\"2024-01-20T03:46:37.42544Z\",\"lastChangedBy\":\"6bac97fb-0665-4ba9-b66c-1cf70e074d72\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-test-secret-file-base64hmac-raw\",\"activeVersion\":\"1\",\"description\":\"This is a test secret from base64 encoded hmac key file (raw).\",\"encoding\":\"base64hmac\",\"lastChangeDate\":\"2024-01-20T03:47:03.695151Z\",\"lastChangedBy\":\"6bac97fb-0665-4ba9-b66c-1cf70e074d72\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-test-secret-pi\",\"activeVersion\":\"1\",\"description\":\"Secret that contains the value of pi\",\"encoding\":\"generic\",\"lastChangeDate\":\"2023-12-14T15:22:28.519043Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-test-secret-pi-generic\",\"activeVersion\":\"3\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-07-15T03:20:09.136266Z\",\"lastChangedBy\":\"Frodo-SA-1701393386423\",\"loaded\":true,\"loadedVersion\":\"3\",\"useInPlaceholders\":true},{\"_id\":\"esv-volkers-test-secret\",\"activeVersion\":\"10\",\"description\":\"Volker's test secret\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-06-26T01:37:06.116117Z\",\"lastChangedBy\":\"Frodo-SA-1701393386423\",\"loaded\":true,\"loadedVersion\":\"10\",\"useInPlaceholders\":true}],\"resultCount\":15,\"totalPagedResults\":-1,\"totalPagedResultsPolicy\":\"NONE\"}" + "mimeType": "application/json; charset=utf-8", + "size": 1975, + "text": "[{\"scope\":\"fr:am:*\",\"description\":\"All Access Management APIs\"},{\"scope\":\"fr:autoaccess:*\",\"description\":\"All Auto Access APIs\"},{\"scope\":\"fr:idc:analytics:*\",\"description\":\"All Analytics APIs\"},{\"scope\":\"fr:idc:certificate:*\",\"description\":\"All TLS certificate APIs\",\"childScopes\":[{\"scope\":\"fr:idc:certificate:read\",\"description\":\"Read TLS certificates\"}]},{\"scope\":\"fr:idc:content-security-policy:*\",\"description\":\"All content security policy APIs\",\"childScopes\":[{\"scope\":\"fr:idc:content-security-policy:read\",\"description\":\"Read content security policy\"}]},{\"scope\":\"fr:idc:cookie-domain:*\",\"description\":\"All cookie domain APIs\",\"childScopes\":[{\"scope\":\"fr:idc:cookie-domain:read\",\"description\":\"Read cookie domains\"}]},{\"scope\":\"fr:idc:custom-domain:*\",\"description\":\"All custom domain APIs\",\"childScopes\":[{\"scope\":\"fr:idc:custom-domain:read\",\"description\":\"Read custom domains\"}]},{\"scope\":\"fr:idc:dataset:*\",\"description\":\"All dataset deletion APIs\",\"childScopes\":[{\"scope\":\"fr:idc:dataset:read\",\"description\":\"Read dataset deletions\"}]},{\"scope\":\"fr:idc:esv:*\",\"description\":\"All ESV APIs\",\"childScopes\":[{\"scope\":\"fr:idc:esv:read\",\"description\":\"Read ESVs, excluding values of secrets\"},{\"scope\":\"fr:idc:esv:update\",\"description\":\"Create, modify, and delete ESVs\"},{\"scope\":\"fr:idc:esv:restart\",\"description\":\"Restart workloads that consume ESVs\"}]},{\"scope\":\"fr:idc:promotion:*\",\"description\":\"All configuration promotion APIs\",\"childScopes\":[{\"scope\":\"fr:idc:promotion:read\",\"description\":\"Read configuration promotion\"}]},{\"scope\":\"fr:idc:release:*\",\"description\":\"All product release APIs\",\"childScopes\":[{\"scope\":\"fr:idc:release:read\",\"description\":\"Read product release\"}]},{\"scope\":\"fr:idc:sso-cookie:*\",\"description\":\"All SSO cookie APIs\",\"childScopes\":[{\"scope\":\"fr:idc:sso-cookie:read\",\"description\":\"Read SSO cookie\"}]},{\"scope\":\"fr:idc:ws:admin\",\"description\":\"All PingFederate APIs\"},{\"scope\":\"fr:idm:*\",\"description\":\"All Identity Management APIs\"}]" }, "cookies": [], "headers": [ { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:02 GMT" - }, - { - "name": "x-forgerock-transactionid", - "value": "8f42156a-40ee-4ce3-8e23-3062cba9ef55" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - }, - { - "name": "transfer-encoding", - "value": "chunked" - } - ], - "headersSize": 332, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:02.682Z", - "time": 241, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 241 - } - }, - { - "_id": "6f6fa199a3b2b45773ec762a6aaef513", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" + "name": "x-frame-options", + "value": "SAMEORIGIN" }, { "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " + "value": "application/json; charset=utf-8" }, { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" + "name": "content-length", + "value": "1975" }, { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1864, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-admin-token" - }, - "response": { - "bodySize": 267, - "content": { - "mimeType": "application/json", - "size": 267, - "text": "{\"_id\":\"esv-admin-token\",\"activeVersion\":\"1\",\"description\":\"Long-lived admin token\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-03-20T14:46:13.461793Z\",\"lastChangedBy\":\"ba58ff99-76d3-4c69-9c4a-7f150ac70e2c\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" + "name": "etag", + "value": "W/\"7b7-9oeZSONSS8Sn+SSr15TXAygvvcE\"" }, { "name": "date", - "value": "Mon, 23 Jun 2025 23:22:03 GMT" - }, - { - "name": "content-length", - "value": "267" + "value": "Tue, 14 Apr 2026 18:46:45 GMT" }, { "name": "x-forgerock-transactionid", - "value": "450786af-9144-4287-85f1-12d180d155cd" + "value": "d5700479-7908-4826-9e8f-94c4b83a96ad" }, { "name": "strict-transport-security", @@ -192,17 +97,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 325, + "headersSize": 388, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2025-06-23T23:22:02.931Z", - "time": 193, + "startedDateTime": "2026-04-14T18:46:45.330Z", + "time": 74, "timings": { "blocked": -1, "connect": -1, @@ -210,11 +115,11 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 193 + "wait": 74 } }, { - "_id": "fc70796aba78406c1b497972e519e4df", + "_id": "a24d647eb74a9e69a6b0bd9ed23dc6ce", "_order": 0, "cache": {}, "request": { @@ -231,7 +136,7 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "accept-api-version", @@ -250,18 +155,18 @@ "value": "openam-frodo-dev.forgeblocks.com" } ], - "headersSize": 1867, + "headersSize": 1851, "httpVersion": "HTTP/1.1", "method": "GET", "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-brando-pingone" + "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets" }, "response": { - "bodySize": 290, + "bodySize": 361, "content": { "mimeType": "application/json", - "size": 290, - "text": "{\"_id\":\"esv-brando-pingone\",\"activeVersion\":\"4\",\"description\":\"This is to show the connection between PingOne and AIC. \",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-06-24T00:44:06.154598Z\",\"lastChangedBy\":\"Frodo-SA-1701393386423\",\"loaded\":true,\"loadedVersion\":\"4\",\"useInPlaceholders\":true}" + "size": 361, + "text": "{\"pagedResultsCookie\":null,\"remainingPagedResults\":-1,\"result\":[{\"_id\":\"esv-test\",\"activeVersion\":\"3\",\"description\":\"test\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-04-13T17:24:40.840844Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"3\",\"useInPlaceholders\":true}],\"resultCount\":1,\"totalPagedResults\":-1,\"totalPagedResultsPolicy\":\"NONE\"}" }, "cookies": [], "headers": [ @@ -271,15 +176,15 @@ }, { "name": "date", - "value": "Mon, 23 Jun 2025 23:22:03 GMT" + "value": "Tue, 14 Apr 2026 18:46:45 GMT" }, { "name": "content-length", - "value": "290" + "value": "361" }, { "name": "x-forgerock-transactionid", - "value": "475cf14e-9742-4c80-ae5f-764731c7475a" + "value": "1f99b992-3ffc-448c-b9be-d1b4d14c2b32" }, { "name": "strict-transport-security", @@ -295,17 +200,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 325, + "headersSize": 300, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2025-06-23T23:22:03.133Z", - "time": 158, + "startedDateTime": "2026-04-14T18:46:45.506Z", + "time": 256, "timings": { "blocked": -1, "connect": -1, @@ -313,11 +218,11 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 158 + "wait": 256 } }, { - "_id": "681dceffb34f31a95f94793a125c330b", + "_id": "764536c00fd6a03a419ab64846c65bfa", "_order": 0, "cache": {}, "request": { @@ -334,7 +239,7 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "accept-api-version", @@ -353,18 +258,18 @@ "value": "openam-frodo-dev.forgeblocks.com" } ], - "headersSize": 1862, + "headersSize": 1860, "httpVersion": "HTTP/1.1", "method": "GET", "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-sean-test" + "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test" }, "response": { "bodySize": 223, "content": { "mimeType": "application/json", "size": 223, - "text": "{\"_id\":\"esv-sean-test\",\"activeVersion\":\"1\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2025-04-11T21:35:33.98194Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" + "text": "{\"_id\":\"esv-test\",\"activeVersion\":\"3\",\"description\":\"test\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-04-13T17:24:40.840844Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"3\",\"useInPlaceholders\":true}" }, "cookies": [], "headers": [ @@ -374,7 +279,7 @@ }, { "name": "date", - "value": "Mon, 23 Jun 2025 23:22:03 GMT" + "value": "Tue, 14 Apr 2026 18:46:45 GMT" }, { "name": "content-length", @@ -382,110 +287,7 @@ }, { "name": "x-forgerock-transactionid", - "value": "c925fb33-5994-4a1a-9a02-6b6d9fd06ef5" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:03.297Z", - "time": 168, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 168 - } - }, - { - "_id": "158ca6baeb73ca72ca5a92072e5cc8ea", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1872, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-secret-import-test1" - }, - "response": { - "bodySize": 266, - "content": { - "mimeType": "application/json", - "size": 266, - "text": "{\"_id\":\"esv-secret-import-test1\",\"activeVersion\":\"1\",\"description\":\"Secret Import Test 1\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-06-22T01:13:13.904591Z\",\"lastChangedBy\":\"volker.scheuber@forgerock.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:03 GMT" - }, - { - "name": "content-length", - "value": "266" - }, - { - "name": "x-forgerock-transactionid", - "value": "92dcc3d3-f224-4a15-a229-7b5233015adf" + "value": "09508e03-1831-40fb-832b-78488786fc6a" }, { "name": "strict-transport-security", @@ -501,17 +303,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 325, + "headersSize": 300, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2025-06-23T23:22:03.470Z", - "time": 140, + "startedDateTime": "2026-04-14T18:46:45.774Z", + "time": 213, "timings": { "blocked": -1, "connect": -1, @@ -519,11 +321,11 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 140 + "wait": 213 } }, { - "_id": "a5ca9e9d93804eab09728c17b9ceb3ab", + "_id": "d5e5902db7ff3a513a98dcd537e1059d", "_order": 0, "cache": {}, "request": { @@ -540,110 +342,7 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1872, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-secret-import-test2" - }, - "response": { - "bodySize": 266, - "content": { - "mimeType": "application/json", - "size": 266, - "text": "{\"_id\":\"esv-secret-import-test2\",\"activeVersion\":\"1\",\"description\":\"Secret Import Test 2\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-06-22T01:13:41.914076Z\",\"lastChangedBy\":\"volker.scheuber@forgerock.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:03 GMT" - }, - { - "name": "content-length", - "value": "266" - }, - { - "name": "x-forgerock-transactionid", - "value": "64ea3781-042e-4ace-81b2-e0c94048dcbc" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:03.614Z", - "time": 138, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 138 - } - }, - { - "_id": "4755051cf62fc4f9843712d25f71e1dd", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "accept-api-version", @@ -666,941 +365,14 @@ "httpVersion": "HTTP/1.1", "method": "GET", "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test-client-cert" - }, - "response": { - "bodySize": 261, - "content": { - "mimeType": "application/json", - "size": 261, - "text": "{\"_id\":\"esv-test-client-cert\",\"activeVersion\":\"1\",\"description\":\"Test HTTP Client client cert\",\"encoding\":\"pem\",\"lastChangeDate\":\"2025-06-12T20:19:16.975613Z\",\"lastChangedBy\":\"Frodo-SA-1725981758244\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":false}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:03 GMT" - }, - { - "name": "content-length", - "value": "261" - }, - { - "name": "x-forgerock-transactionid", - "value": "6ab63e8e-6d65-4fb2-b9de-dbb6d434f152" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:03.758Z", - "time": 152, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 152 - } - }, - { - "_id": "0b347f3163c26e50f02a2c38a0f934f8", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1864, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test-secret" - }, - "response": { - "bodySize": 286, - "content": { - "mimeType": "application/json", - "size": 286, - "text": "{\"_id\":\"esv-test-secret\",\"activeVersion\":\"1\",\"description\":\"This is a test secret containing a simple string value.\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-07-05T17:53:53.682578Z\",\"lastChangedBy\":\"Frodo-SA-1701393386423\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:04 GMT" - }, - { - "name": "content-length", - "value": "286" - }, - { - "name": "x-forgerock-transactionid", - "value": "59513888-71b3-4945-82b2-20ebe3b93bac" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:03.914Z", - "time": 148, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 148 - } - }, - { - "_id": "f1a36f0c8c23ad2517859948b275031d", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1873, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test-secret-cert-pem" - }, - "response": { - "bodySize": 301, - "content": { - "mimeType": "application/json", - "size": 301, - "text": "{\"_id\":\"esv-test-secret-cert-pem\",\"activeVersion\":\"1\",\"description\":\"This is a test secret from a pem encoded cert file.\",\"encoding\":\"pem\",\"lastChangeDate\":\"2024-01-20T03:48:49.005574Z\",\"lastChangedBy\":\"6bac97fb-0665-4ba9-b66c-1cf70e074d72\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:04 GMT" - }, - { - "name": "content-length", - "value": "301" - }, - { - "name": "x-forgerock-transactionid", - "value": "ac52bd75-7fb9-455a-a6c9-eb6df63d38b8" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:04.068Z", - "time": 242, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 242 - } - }, - { - "_id": "7ef6862dfbad2070cfc0d0d9e027abaf", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1877, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test-secret-cert-pem-raw" - }, - "response": { - "bodySize": 311, - "content": { - "mimeType": "application/json", - "size": 311, - "text": "{\"_id\":\"esv-test-secret-cert-pem-raw\",\"activeVersion\":\"1\",\"description\":\"This is a test secret from a pem encoded cert file (raw).\",\"encoding\":\"pem\",\"lastChangeDate\":\"2024-01-20T03:49:20.270526Z\",\"lastChangedBy\":\"6bac97fb-0665-4ba9-b66c-1cf70e074d72\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:04 GMT" - }, - { - "name": "content-length", - "value": "311" - }, - { - "name": "x-forgerock-transactionid", - "value": "bcc789e3-8199-474c-ae89-a04d4fe7dc6f" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:04.314Z", - "time": 141, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 141 - } - }, - { - "_id": "b3545751d0a5c20d5944f2da8b0f8780", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1870, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test-secret-euler" - }, - "response": { - "bodySize": 284, - "content": { - "mimeType": "application/json", - "size": 284, - "text": "{\"_id\":\"esv-test-secret-euler\",\"activeVersion\":\"1\",\"description\":\"A test secret containing the value of Euler's number\",\"encoding\":\"generic\",\"lastChangeDate\":\"2023-12-14T15:27:34.607038Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:04 GMT" - }, - { - "name": "content-length", - "value": "284" - }, - { - "name": "x-forgerock-transactionid", - "value": "61c33e1a-4851-4946-95c4-1ad3dccc43a3" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:04.459Z", - "time": 143, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 143 - } - }, - { - "_id": "2d836ff76d6fdc45d7ae14af5082ad95", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1880, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test-secret-file-base64hmac" - }, - "response": { - "bodySize": 319, - "content": { - "mimeType": "application/json", - "size": 319, - "text": "{\"_id\":\"esv-test-secret-file-base64hmac\",\"activeVersion\":\"1\",\"description\":\"This is a test secret from base64 encoded hmac key file.\",\"encoding\":\"base64hmac\",\"lastChangeDate\":\"2024-01-20T03:46:37.42544Z\",\"lastChangedBy\":\"6bac97fb-0665-4ba9-b66c-1cf70e074d72\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:04 GMT" - }, - { - "name": "content-length", - "value": "319" - }, - { - "name": "x-forgerock-transactionid", - "value": "6ceb599e-8412-44f7-8a4d-cd5baa57c3a3" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:04.607Z", - "time": 153, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 153 - } - }, - { - "_id": "6e59d85b5f0bc2faf34e221c77a3df5b", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1884, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test-secret-file-base64hmac-raw" - }, - "response": { - "bodySize": 330, - "content": { - "mimeType": "application/json", - "size": 330, - "text": "{\"_id\":\"esv-test-secret-file-base64hmac-raw\",\"activeVersion\":\"1\",\"description\":\"This is a test secret from base64 encoded hmac key file (raw).\",\"encoding\":\"base64hmac\",\"lastChangeDate\":\"2024-01-20T03:47:03.695151Z\",\"lastChangedBy\":\"6bac97fb-0665-4ba9-b66c-1cf70e074d72\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:04 GMT" - }, - { - "name": "content-length", - "value": "330" - }, - { - "name": "x-forgerock-transactionid", - "value": "c65f9d47-ac1a-4705-ac61-1f8cd883acfe" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:04.765Z", - "time": 156, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 156 - } - }, - { - "_id": "bd4a792e01ef8010ccddbc990f9d0df5", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1867, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test-secret-pi" - }, - "response": { - "bodySize": 265, - "content": { - "mimeType": "application/json", - "size": 265, - "text": "{\"_id\":\"esv-test-secret-pi\",\"activeVersion\":\"1\",\"description\":\"Secret that contains the value of pi\",\"encoding\":\"generic\",\"lastChangeDate\":\"2023-12-14T15:22:28.519043Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:05 GMT" - }, - { - "name": "content-length", - "value": "265" - }, - { - "name": "x-forgerock-transactionid", - "value": "3904c9ce-722c-473c-b871-67edb4f32395" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:04.926Z", - "time": 138, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 138 - } - }, - { - "_id": "d97e1fd9e83a63bc5b930dc683bb58a7", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1875, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test-secret-pi-generic" - }, - "response": { - "bodySize": 242, - "content": { - "mimeType": "application/json", - "size": 242, - "text": "{\"_id\":\"esv-test-secret-pi-generic\",\"activeVersion\":\"3\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-07-15T03:20:09.136266Z\",\"lastChangedBy\":\"Frodo-SA-1701393386423\",\"loaded\":true,\"loadedVersion\":\"3\",\"useInPlaceholders\":true}" - }, - "cookies": [], - "headers": [ - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "date", - "value": "Mon, 23 Jun 2025 23:22:05 GMT" - }, - { - "name": "content-length", - "value": "242" - }, - { - "name": "x-forgerock-transactionid", - "value": "ae75919a-58d6-4e29-abee-696ab0d48aef" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains; preload;" - }, - { - "name": "x-robots-tag", - "value": "none" - }, - { - "name": "via", - "value": "1.1 google" - }, - { - "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" - } - ], - "headersSize": 325, - "httpVersion": "HTTP/1.1", - "redirectURL": "", - "status": 200, - "statusText": "OK" - }, - "startedDateTime": "2025-06-23T23:22:05.069Z", - "time": 145, - "timings": { - "blocked": -1, - "connect": -1, - "dns": -1, - "receive": 0, - "send": 0, - "ssl": -1, - "wait": 145 - } - }, - { - "_id": "9ce7353c2284116f1a5627e3c65d9f54", - "_order": 0, - "cache": {}, - "request": { - "bodySize": 0, - "cookies": [], - "headers": [ - { - "name": "accept", - "value": "application/json, text/plain, */*" - }, - { - "name": "content-type", - "value": "application/json" - }, - { - "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" - }, - { - "name": "accept-api-version", - "value": "protocol=1.0,resource=1.0" - }, - { - "name": "authorization", - "value": "Bearer " - }, - { - "name": "accept-encoding", - "value": "gzip, compress, deflate, br" - }, - { - "name": "host", - "value": "openam-frodo-dev.forgeblocks.com" - } - ], - "headersSize": 1872, - "httpVersion": "HTTP/1.1", - "method": "GET", - "queryString": [], - "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-volkers-test-secret" + "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test/versions" }, "response": { - "bodySize": 261, + "bodySize": 282, "content": { "mimeType": "application/json", - "size": 261, - "text": "{\"_id\":\"esv-volkers-test-secret\",\"activeVersion\":\"10\",\"description\":\"Volker's test secret\",\"encoding\":\"generic\",\"lastChangeDate\":\"2024-06-26T01:37:06.116117Z\",\"lastChangedBy\":\"Frodo-SA-1701393386423\",\"loaded\":true,\"loadedVersion\":\"10\",\"useInPlaceholders\":true}" + "size": 282, + "text": "[{\"createDate\":\"2026-04-13T17:24:30.893036Z\",\"loaded\":false,\"status\":\"ENABLED\",\"version\":\"3\"},{\"createDate\":\"2026-04-13T17:23:45.594504Z\",\"loaded\":false,\"status\":\"DISABLED\",\"version\":\"2\"},{\"createDate\":\"2026-03-30T19:45:07.816536Z\",\"loaded\":false,\"status\":\"ENABLED\",\"version\":\"1\"}]" }, "cookies": [], "headers": [ @@ -1610,15 +382,15 @@ }, { "name": "date", - "value": "Mon, 23 Jun 2025 23:22:05 GMT" + "value": "Tue, 14 Apr 2026 18:46:46 GMT" }, { "name": "content-length", - "value": "261" + "value": "282" }, { "name": "x-forgerock-transactionid", - "value": "f06557cb-d323-4b3b-80bc-8dc155135b53" + "value": "85749807-6567-4967-b34e-a8e6d68a58f6" }, { "name": "strict-transport-security", @@ -1634,17 +406,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 325, + "headersSize": 300, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2025-06-23T23:22:05.219Z", - "time": 167, + "startedDateTime": "2026-04-14T18:46:45.996Z", + "time": 339, "timings": { "blocked": -1, "connect": -1, @@ -1652,7 +424,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 167 + "wait": 339 } } ], diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/oauth2_393036114/recording.har index 3e6b6105e..81b5bedbc 100644 --- a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/oauth2_393036114/recording.har +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/oauth2_393036114/recording.har @@ -25,11 +25,11 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "x-forgerock-transactionid", - "value": "frodo-93c9cba5-db71-435f-bc8c-352f35d7263a" + "value": "frodo-b5cace15-6bd6-463d-95eb-ab3d1d98f98f" }, { "name": "accept-api-version", @@ -48,13 +48,13 @@ "value": "openam-frodo-dev.forgeblocks.com" } ], - "headersSize": 440, + "headersSize": 443, "httpVersion": "HTTP/1.1", "method": "POST", "postData": { "mimeType": "application/x-www-form-urlencoded", "params": [], - "text": "assertion=&client_id=service-account&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=fr:am:* fr:autoaccess:* fr:idc:esv:* fr:idc:analytics:* fr:idc:custom-domain:* fr:idc:release:* fr:idc:sso-cookie:* fr:idc:content-security-policy:* fr:idc:certificate:* fr:idm:* fr:idc:cookie-domain:* fr:idc:promotion:*" + "text": "assertion=&client_id=service-account&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=fr:idc:custom-domain:* fr:idc:release:* fr:idc:sso-cookie:* fr:am:* fr:autoaccess:* fr:idc:content-security-policy:* fr:idc:esv:* fr:idc:certificate:* fr:idm:* fr:idc:analytics:* fr:idc:cookie-domain:* fr:idc:promotion:*" }, "queryString": [], "url": "https://openam-frodo-dev.forgeblocks.com/am/oauth2/access_token" @@ -64,7 +64,7 @@ "content": { "mimeType": "application/json;charset=UTF-8", "size": 1787, - "text": "{\"access_token\":\"\",\"scope\":\"fr:am:* fr:autoaccess:* fr:idc:esv:* fr:idc:analytics:* fr:idc:custom-domain:* fr:idc:release:* fr:idc:sso-cookie:* fr:idc:content-security-policy:* fr:idc:certificate:* fr:idm:* fr:idc:cookie-domain:* fr:idc:promotion:*\",\"token_type\":\"Bearer\",\"expires_in\":899}" + "text": "{\"access_token\":\"\",\"scope\":\"fr:idc:custom-domain:* fr:idc:release:* fr:idc:sso-cookie:* fr:am:* fr:autoaccess:* fr:idc:content-security-policy:* fr:idc:esv:* fr:idc:certificate:* fr:idm:* fr:idc:analytics:* fr:idc:cookie-domain:* fr:idc:promotion:*\",\"token_type\":\"Bearer\",\"expires_in\":899}" }, "cookies": [], "headers": [ @@ -98,11 +98,11 @@ }, { "name": "date", - "value": "Mon, 23 Jun 2025 23:22:02 GMT" + "value": "Tue, 14 Apr 2026 18:46:45 GMT" }, { "name": "x-forgerock-transactionid", - "value": "frodo-93c9cba5-db71-435f-bc8c-352f35d7263a" + "value": "frodo-b5cace15-6bd6-463d-95eb-ab3d1d98f98f" }, { "name": "strict-transport-security", @@ -127,8 +127,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2025-06-23T23:22:02.387Z", - "time": 90, + "startedDateTime": "2026-04-14T18:46:44.970Z", + "time": 162, "timings": { "blocked": -1, "connect": -1, @@ -136,7 +136,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 90 + "wait": 162 } } ], diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/openidm_3290118515/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/openidm_3290118515/recording.har index d97f6e34b..7b6622a9a 100644 --- a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/openidm_3290118515/recording.har +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_D_2157136892/openidm_3290118515/recording.har @@ -25,11 +25,11 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "x-forgerock-transactionid", - "value": "frodo-93c9cba5-db71-435f-bc8c-352f35d7263a" + "value": "frodo-b5cace15-6bd6-463d-95eb-ab3d1d98f98f" }, { "name": "authorization", @@ -44,7 +44,7 @@ "value": "openam-frodo-dev.forgeblocks.com" } ], - "headersSize": 1925, + "headersSize": 1928, "httpVersion": "HTTP/1.1", "method": "GET", "queryString": [ @@ -53,20 +53,20 @@ "value": "*" } ], - "url": "https://openam-frodo-dev.forgeblocks.com/openidm/managed/svcacct/a2b4d68f-ca4a-4078-b2d8-f610b54623a5?_fields=%2A" + "url": "https://openam-frodo-dev.forgeblocks.com/openidm/managed/svcacct/22e714dc-a1b0-4f61-819c-148df8ed5fe6?_fields=%2A" }, "response": { - "bodySize": 1371, + "bodySize": 1437, "content": { "mimeType": "application/json;charset=utf-8", - "size": 1371, - "text": "{\"_id\":\"a2b4d68f-ca4a-4078-b2d8-f610b54623a5\",\"_rev\":\"3a3bb2d9-1302-40f4-9e5f-a1dc6aff6ac0-3429\",\"accountStatus\":\"active\",\"name\":\"Frodo-SA-1748967688823\",\"description\":\"phales@trivir.com's Frodo Service Account\",\"scopes\":[\"fr:am:*\",\"fr:idc:analytics:*\",\"fr:autoaccess:*\",\"fr:idc:certificate:*\",\"fr:idc:content-security-policy:*\",\"fr:idc:cookie-domain:*\",\"fr:idc:custom-domain:*\",\"fr:idc:esv:*\",\"fr:idm:*\",\"fr:idc:promotion:*\",\"fr:idc:release:*\",\"fr:idc:sso-cookie:*\"],\"jwks\":\"{\\\"keys\\\":[{\\\"kty\\\":\\\"RSA\\\",\\\"kid\\\":\\\"jyXSlOCC0dQkPAMD8PV9st_PI9v640HDNWPyDAlQLic\\\",\\\"alg\\\":\\\"RS256\\\",\\\"e\\\":\\\"AQAB\\\",\\\"n\\\":\\\"s2QM7rmK4k0Yoth7ybP6p-ud0ENpXtJBg21cUCMnlnNZXpxBkKWpjk75x9EQJzO2RpN35Nigi0tGShxP0HnyOrpUFl2_d02NPD1iAgiMw8-63bgJ6sc09zNdr5wX2tm1vigeZXN0GvjGLrjywf167g3O53gxL_7GwuTH5B-Y4Mxd65mg2wa5Q14533iXJGyf5soku2nVRz2DsZrSUo7tQYkdtxlSdIAa6HDtQCyUDQh2l6BMOaJXU2PIFwdnpcNyrZiIq_Au3oeFX94zDHCeUbbdrF2-jyGOCMMtNEGcdJkgXkLFkLyQcwMPcPeknjKCapTASrEG-kXWutxWmItRRqdAQCG2iV7pNtums7ryxmL4U3w7RWyDINYT9RbihDp3gG4TpCSEVvt2M-Q8wMmjCoUPkoNV9iqfQa3ErgYo9ISAO7tPEMiZlbH4Zr5p43ugSPG50gOyc1YcUc-lCMkgZhjiQazDVjshSIYDGfUJQeDMCNlR424gMNoL4DccqBNL9zOC9_a2fyrjtQBOI04UqLdC7rELnjGdhHHSwrVm62DD2fgySgD3UhOuBekHXn4v2i5viRbXdxfpMinJ14d3lhf-QYcBR2cNxH-6X6HB6j6n2Q2W6LiBBe84rDmLLNVW5kExDD2ra-p8fZGFVZkUw6Fyd67W5eOJXKng7Hi8TXE\\\"}]}\",\"maxCachingTime\":\"15\",\"maxIdleTime\":\"15\",\"maxSessionTime\":\"15\",\"quotaLimit\":\"5\"}" + "size": 1437, + "text": "{\"_id\":\"22e714dc-a1b0-4f61-819c-148df8ed5fe6\",\"_rev\":\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\",\"accountStatus\":\"active\",\"name\":\"devin_svc\",\"description\":null,\"scopes\":[\"fr:am:*\",\"fr:idm:*\",\"fr:autoaccess:*\",\"fr:idc:analytics:*\",\"fr:idc:certificate:*\",\"fr:idc:certificate:read\",\"fr:idc:content-security-policy:*\",\"fr:idc:content-security-policy:read\",\"fr:idc:cookie-domain:*\",\"fr:idc:cookie-domain:read\",\"fr:idc:custom-domain:*\",\"fr:idc:custom-domain:read\",\"fr:idc:esv:*\",\"fr:idc:promotion:*\",\"fr:idc:promotion:read\",\"fr:idc:release:*\",\"fr:idc:release:read\",\"fr:idc:sso-cookie:*\",\"fr:idc:sso-cookie:read\"],\"jwks\":\"{\\\"keys\\\":[{\\\"e\\\":\\\"AQAB\\\",\\\"kty\\\":\\\"RSA\\\",\\\"n\\\":\\\"mbFgXRafUw0vumgdyXkNSLt7eO-iShWEnJaZQftnHAEyFv0-13aUd5bNd4ccMKjxfCCj2pzfruKsvcsY1MSDuQgvhgap5jo-gfmebWmGBFiwOL1_wQkrR8sL_JaGnBIbidoHJ-3wVv4nSEJ96wmOYdGo4OkY6hoICnT653cpw4Zw66DSUb6RWzxcxLFBtvhn2Y2_Q1nuU6nowPG1rcCJ_JcoW3zW_OG4Yt5WcIPzLUwfMbXw1grRPZg4Qqxpbo7vIrlExB6iQ-LdARG8_0rPpH_SUcAizR_c0Vp3SMhLg5pi_gVR9dU42WBGpJT6u3uO9kuOC6noJThg5F7M1drlhgasFtGioi2iCsTBitJPjXAEW-Do34Y2KB0bGJ1bLZNkyRJY3VLfYH8dO7FwIPpVCpHSOG7ml6YmYDIFymvCuB8e5rQS_xUb1PEK2YK1TC0ne_uvyb1lZ2RrGfzGZigtC4MJ_Rd4v-r4Z8BbCbykS-zqbEoCjsRUtcVmwBJGiln_Y9MpT42j6EaNxb5hJDAAGx98u57gQ4TcqyAeNOCPNt2QOddtsmcaQlkN9DKYKlLcMp9OQ6SqaFtY-LKoyq7fIYf8v_2uXZFjqmqokKxWFMfLIHj33B4bdRgRWitpeS2x1xZX_FylumYChE2daiRxRvA-kVcMYWMwAkSZcbU9Ovs\\\"}]}\",\"maxCachingTime\":\"15\",\"maxIdleTime\":\"15\",\"maxSessionTime\":\"15\",\"quotaLimit\":\"5\"}" }, "cookies": [], "headers": [ { "name": "date", - "value": "Mon, 23 Jun 2025 23:22:02 GMT" + "value": "Tue, 14 Apr 2026 18:46:45 GMT" }, { "name": "vary", @@ -94,7 +94,7 @@ }, { "name": "etag", - "value": "\"3a3bb2d9-1302-40f4-9e5f-a1dc6aff6ac0-3429\"" + "value": "\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\"" }, { "name": "expires", @@ -114,11 +114,11 @@ }, { "name": "content-length", - "value": "1371" + "value": "1437" }, { "name": "x-forgerock-transactionid", - "value": "frodo-93c9cba5-db71-435f-bc8c-352f35d7263a" + "value": "frodo-b5cace15-6bd6-463d-95eb-ab3d1d98f98f" }, { "name": "strict-transport-security", @@ -137,14 +137,14 @@ "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" } ], - "headersSize": 682, + "headersSize": 683, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2025-06-23T23:22:02.484Z", - "time": 90, + "startedDateTime": "2026-04-14T18:46:45.161Z", + "time": 92, "timings": { "blocked": -1, "connect": -1, @@ -152,7 +152,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 90 + "wait": 92 } }, { @@ -173,11 +173,11 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/3.3.0" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "x-forgerock-transactionid", - "value": "frodo-93c9cba5-db71-435f-bc8c-352f35d7263a" + "value": "frodo-b5cace15-6bd6-463d-95eb-ab3d1d98f98f" }, { "name": "authorization", @@ -192,7 +192,7 @@ "value": "openam-frodo-dev.forgeblocks.com" } ], - "headersSize": 1925, + "headersSize": 1928, "httpVersion": "HTTP/1.1", "method": "GET", "queryString": [ @@ -201,20 +201,20 @@ "value": "*" } ], - "url": "https://openam-frodo-dev.forgeblocks.com/openidm/managed/svcacct/a2b4d68f-ca4a-4078-b2d8-f610b54623a5?_fields=%2A" + "url": "https://openam-frodo-dev.forgeblocks.com/openidm/managed/svcacct/22e714dc-a1b0-4f61-819c-148df8ed5fe6?_fields=%2A" }, "response": { - "bodySize": 1371, + "bodySize": 1437, "content": { "mimeType": "application/json;charset=utf-8", - "size": 1371, - "text": "{\"_id\":\"a2b4d68f-ca4a-4078-b2d8-f610b54623a5\",\"_rev\":\"3a3bb2d9-1302-40f4-9e5f-a1dc6aff6ac0-3429\",\"accountStatus\":\"active\",\"name\":\"Frodo-SA-1748967688823\",\"description\":\"phales@trivir.com's Frodo Service Account\",\"scopes\":[\"fr:am:*\",\"fr:idc:analytics:*\",\"fr:autoaccess:*\",\"fr:idc:certificate:*\",\"fr:idc:content-security-policy:*\",\"fr:idc:cookie-domain:*\",\"fr:idc:custom-domain:*\",\"fr:idc:esv:*\",\"fr:idm:*\",\"fr:idc:promotion:*\",\"fr:idc:release:*\",\"fr:idc:sso-cookie:*\"],\"jwks\":\"{\\\"keys\\\":[{\\\"kty\\\":\\\"RSA\\\",\\\"kid\\\":\\\"jyXSlOCC0dQkPAMD8PV9st_PI9v640HDNWPyDAlQLic\\\",\\\"alg\\\":\\\"RS256\\\",\\\"e\\\":\\\"AQAB\\\",\\\"n\\\":\\\"s2QM7rmK4k0Yoth7ybP6p-ud0ENpXtJBg21cUCMnlnNZXpxBkKWpjk75x9EQJzO2RpN35Nigi0tGShxP0HnyOrpUFl2_d02NPD1iAgiMw8-63bgJ6sc09zNdr5wX2tm1vigeZXN0GvjGLrjywf167g3O53gxL_7GwuTH5B-Y4Mxd65mg2wa5Q14533iXJGyf5soku2nVRz2DsZrSUo7tQYkdtxlSdIAa6HDtQCyUDQh2l6BMOaJXU2PIFwdnpcNyrZiIq_Au3oeFX94zDHCeUbbdrF2-jyGOCMMtNEGcdJkgXkLFkLyQcwMPcPeknjKCapTASrEG-kXWutxWmItRRqdAQCG2iV7pNtums7ryxmL4U3w7RWyDINYT9RbihDp3gG4TpCSEVvt2M-Q8wMmjCoUPkoNV9iqfQa3ErgYo9ISAO7tPEMiZlbH4Zr5p43ugSPG50gOyc1YcUc-lCMkgZhjiQazDVjshSIYDGfUJQeDMCNlR424gMNoL4DccqBNL9zOC9_a2fyrjtQBOI04UqLdC7rELnjGdhHHSwrVm62DD2fgySgD3UhOuBekHXn4v2i5viRbXdxfpMinJ14d3lhf-QYcBR2cNxH-6X6HB6j6n2Q2W6LiBBe84rDmLLNVW5kExDD2ra-p8fZGFVZkUw6Fyd67W5eOJXKng7Hi8TXE\\\"}]}\",\"maxCachingTime\":\"15\",\"maxIdleTime\":\"15\",\"maxSessionTime\":\"15\",\"quotaLimit\":\"5\"}" + "size": 1437, + "text": "{\"_id\":\"22e714dc-a1b0-4f61-819c-148df8ed5fe6\",\"_rev\":\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\",\"accountStatus\":\"active\",\"name\":\"devin_svc\",\"description\":null,\"scopes\":[\"fr:am:*\",\"fr:idm:*\",\"fr:autoaccess:*\",\"fr:idc:analytics:*\",\"fr:idc:certificate:*\",\"fr:idc:certificate:read\",\"fr:idc:content-security-policy:*\",\"fr:idc:content-security-policy:read\",\"fr:idc:cookie-domain:*\",\"fr:idc:cookie-domain:read\",\"fr:idc:custom-domain:*\",\"fr:idc:custom-domain:read\",\"fr:idc:esv:*\",\"fr:idc:promotion:*\",\"fr:idc:promotion:read\",\"fr:idc:release:*\",\"fr:idc:release:read\",\"fr:idc:sso-cookie:*\",\"fr:idc:sso-cookie:read\"],\"jwks\":\"{\\\"keys\\\":[{\\\"e\\\":\\\"AQAB\\\",\\\"kty\\\":\\\"RSA\\\",\\\"n\\\":\\\"mbFgXRafUw0vumgdyXkNSLt7eO-iShWEnJaZQftnHAEyFv0-13aUd5bNd4ccMKjxfCCj2pzfruKsvcsY1MSDuQgvhgap5jo-gfmebWmGBFiwOL1_wQkrR8sL_JaGnBIbidoHJ-3wVv4nSEJ96wmOYdGo4OkY6hoICnT653cpw4Zw66DSUb6RWzxcxLFBtvhn2Y2_Q1nuU6nowPG1rcCJ_JcoW3zW_OG4Yt5WcIPzLUwfMbXw1grRPZg4Qqxpbo7vIrlExB6iQ-LdARG8_0rPpH_SUcAizR_c0Vp3SMhLg5pi_gVR9dU42WBGpJT6u3uO9kuOC6noJThg5F7M1drlhgasFtGioi2iCsTBitJPjXAEW-Do34Y2KB0bGJ1bLZNkyRJY3VLfYH8dO7FwIPpVCpHSOG7ml6YmYDIFymvCuB8e5rQS_xUb1PEK2YK1TC0ne_uvyb1lZ2RrGfzGZigtC4MJ_Rd4v-r4Z8BbCbykS-zqbEoCjsRUtcVmwBJGiln_Y9MpT42j6EaNxb5hJDAAGx98u57gQ4TcqyAeNOCPNt2QOddtsmcaQlkN9DKYKlLcMp9OQ6SqaFtY-LKoyq7fIYf8v_2uXZFjqmqokKxWFMfLIHj33B4bdRgRWitpeS2x1xZX_FylumYChE2daiRxRvA-kVcMYWMwAkSZcbU9Ovs\\\"}]}\",\"maxCachingTime\":\"15\",\"maxIdleTime\":\"15\",\"maxSessionTime\":\"15\",\"quotaLimit\":\"5\"}" }, "cookies": [], "headers": [ { "name": "date", - "value": "Mon, 23 Jun 2025 23:22:02 GMT" + "value": "Tue, 14 Apr 2026 18:46:45 GMT" }, { "name": "vary", @@ -242,7 +242,7 @@ }, { "name": "etag", - "value": "\"3a3bb2d9-1302-40f4-9e5f-a1dc6aff6ac0-3429\"" + "value": "\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\"" }, { "name": "expires", @@ -262,11 +262,11 @@ }, { "name": "content-length", - "value": "1371" + "value": "1437" }, { "name": "x-forgerock-transactionid", - "value": "frodo-93c9cba5-db71-435f-bc8c-352f35d7263a" + "value": "frodo-b5cace15-6bd6-463d-95eb-ab3d1d98f98f" }, { "name": "strict-transport-security", @@ -282,17 +282,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 682, + "headersSize": 658, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2025-06-23T23:22:02.612Z", - "time": 66, + "startedDateTime": "2026-04-14T18:46:45.414Z", + "time": 68, "timings": { "blocked": -1, "connect": -1, @@ -300,7 +300,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 66 + "wait": 68 } } ], diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/am_1076162899/recording.har new file mode 100644 index 000000000..f713a7fe8 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/am_1076162899/recording.har @@ -0,0 +1,312 @@ +{ + "log": { + "_recordingName": "config-manager/pull/secrets/0_a_D/am", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccd7a5defd0fdeaa986a2b54642d911a", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-d10d232d-0e23-4038-88cf-2b732557f830" + }, + { + "name": "accept-api-version", + "value": "resource=1.1" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 388, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/am/json/serverinfo/*" + }, + "response": { + "bodySize": 615, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 615, + "text": "{\"_id\":\"*\",\"_rev\":\"1955877839\",\"domains\":[],\"protectedUserAttributes\":[\"telephoneNumber\",\"mail\"],\"cookieName\":\"6ac6499e9da2071\",\"secureCookie\":true,\"forgotPassword\":\"false\",\"forgotUsername\":\"false\",\"kbaEnabled\":\"false\",\"selfRegistration\":\"false\",\"lang\":\"en-US\",\"successfulUserRegistrationDestination\":\"default\",\"socialImplementations\":[],\"referralsEnabled\":\"false\",\"zeroPageLogin\":{\"enabled\":false,\"allowedWithoutReferer\":true,\"refererWhitelist\":[]},\"realm\":\"/\",\"xuiUserSessionValidationEnabled\":true,\"fileBasedConfiguration\":true,\"userIdAttributes\":[],\"cloudOnlyFeaturesEnabled\":true,\"oauth2AIAgentsEnabled\":false}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "content-security-policy-report-only", + "value": "frame-ancestors 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.1" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"1955877839\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "615" + }, + { + "name": "date", + "value": "Tue, 14 Apr 2026 18:43:33 GMT" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-d10d232d-0e23-4038-88cf-2b732557f830" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 787, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-14T18:43:33.328Z", + "time": 427, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 427 + } + }, + { + "_id": "6125d0328ad0dcaee55f73fd8b22ca14", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-d10d232d-0e23-4038-88cf-2b732557f830" + }, + { + "name": "accept-api-version", + "value": "resource=1.0" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1916, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/am/json/serverinfo/version" + }, + "response": { + "bodySize": 276, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 276, + "text": "{\"_id\":\"version\",\"_rev\":\"-1876078088\",\"version\":\"9.0.0-SNAPSHOT\",\"fullVersion\":\"ForgeRock Access Management 9.0.0-SNAPSHOT Build 2a2686af9631bd8d8866c92ea2411814899acefd (2026-March-30 15:23)\",\"revision\":\"2a2686af9631bd8d8866c92ea2411814899acefd\",\"date\":\"2026-March-30 15:23\"}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "content-security-policy-report-only", + "value": "frame-ancestors 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"-1876078088\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "276" + }, + { + "name": "date", + "value": "Tue, 14 Apr 2026 18:43:34 GMT" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-d10d232d-0e23-4038-88cf-2b732557f830" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 788, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-14T18:43:33.950Z", + "time": 147, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 147 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/environment_1072573434/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/environment_1072573434/recording.har new file mode 100644 index 000000000..a2c636234 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/environment_1072573434/recording.har @@ -0,0 +1,331 @@ +{ + "log": { + "_recordingName": "config-manager/pull/secrets/0_a_D/environment", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ccc7ec61c2094114d7917814bb19b83b", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "accept-api-version", + "value": "protocol=1.0,resource=1.0" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1867, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/environment/scopes/service-accounts" + }, + "response": { + "bodySize": 1975, + "content": { + "mimeType": "application/json; charset=utf-8", + "size": 1975, + "text": "[{\"scope\":\"fr:am:*\",\"description\":\"All Access Management APIs\"},{\"scope\":\"fr:autoaccess:*\",\"description\":\"All Auto Access APIs\"},{\"scope\":\"fr:idc:analytics:*\",\"description\":\"All Analytics APIs\"},{\"scope\":\"fr:idc:certificate:*\",\"description\":\"All TLS certificate APIs\",\"childScopes\":[{\"scope\":\"fr:idc:certificate:read\",\"description\":\"Read TLS certificates\"}]},{\"scope\":\"fr:idc:content-security-policy:*\",\"description\":\"All content security policy APIs\",\"childScopes\":[{\"scope\":\"fr:idc:content-security-policy:read\",\"description\":\"Read content security policy\"}]},{\"scope\":\"fr:idc:cookie-domain:*\",\"description\":\"All cookie domain APIs\",\"childScopes\":[{\"scope\":\"fr:idc:cookie-domain:read\",\"description\":\"Read cookie domains\"}]},{\"scope\":\"fr:idc:custom-domain:*\",\"description\":\"All custom domain APIs\",\"childScopes\":[{\"scope\":\"fr:idc:custom-domain:read\",\"description\":\"Read custom domains\"}]},{\"scope\":\"fr:idc:dataset:*\",\"description\":\"All dataset deletion APIs\",\"childScopes\":[{\"scope\":\"fr:idc:dataset:read\",\"description\":\"Read dataset deletions\"}]},{\"scope\":\"fr:idc:esv:*\",\"description\":\"All ESV APIs\",\"childScopes\":[{\"scope\":\"fr:idc:esv:read\",\"description\":\"Read ESVs, excluding values of secrets\"},{\"scope\":\"fr:idc:esv:update\",\"description\":\"Create, modify, and delete ESVs\"},{\"scope\":\"fr:idc:esv:restart\",\"description\":\"Restart workloads that consume ESVs\"}]},{\"scope\":\"fr:idc:promotion:*\",\"description\":\"All configuration promotion APIs\",\"childScopes\":[{\"scope\":\"fr:idc:promotion:read\",\"description\":\"Read configuration promotion\"}]},{\"scope\":\"fr:idc:release:*\",\"description\":\"All product release APIs\",\"childScopes\":[{\"scope\":\"fr:idc:release:read\",\"description\":\"Read product release\"}]},{\"scope\":\"fr:idc:sso-cookie:*\",\"description\":\"All SSO cookie APIs\",\"childScopes\":[{\"scope\":\"fr:idc:sso-cookie:read\",\"description\":\"Read SSO cookie\"}]},{\"scope\":\"fr:idc:ws:admin\",\"description\":\"All PingFederate APIs\"},{\"scope\":\"fr:idm:*\",\"description\":\"All Identity Management APIs\"}]" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "content-type", + "value": "application/json; charset=utf-8" + }, + { + "name": "content-length", + "value": "1975" + }, + { + "name": "etag", + "value": "W/\"7b7-9oeZSONSS8Sn+SSr15TXAygvvcE\"" + }, + { + "name": "date", + "value": "Tue, 14 Apr 2026 18:43:34 GMT" + }, + { + "name": "x-forgerock-transactionid", + "value": "69249b1e-4283-4bb7-9d46-ad9160fe0d46" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 413, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-14T18:43:34.114Z", + "time": 81, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 81 + } + }, + { + "_id": "a24d647eb74a9e69a6b0bd9ed23dc6ce", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "accept-api-version", + "value": "protocol=1.0,resource=1.0" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1851, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets" + }, + "response": { + "bodySize": 361, + "content": { + "mimeType": "application/json", + "size": 361, + "text": "{\"pagedResultsCookie\":null,\"remainingPagedResults\":-1,\"result\":[{\"_id\":\"esv-test\",\"activeVersion\":\"3\",\"description\":\"test\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-04-13T17:24:40.840844Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"3\",\"useInPlaceholders\":true}],\"resultCount\":1,\"totalPagedResults\":-1,\"totalPagedResultsPolicy\":\"NONE\"}" + }, + "cookies": [], + "headers": [ + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "date", + "value": "Tue, 14 Apr 2026 18:43:34 GMT" + }, + { + "name": "content-length", + "value": "361" + }, + { + "name": "x-forgerock-transactionid", + "value": "8ce5cb69-153d-4332-845a-498d9160ebac" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 325, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-14T18:43:34.310Z", + "time": 178, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 178 + } + }, + { + "_id": "764536c00fd6a03a419ab64846c65bfa", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "accept-api-version", + "value": "protocol=1.0,resource=1.0" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1860, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test" + }, + "response": { + "bodySize": 223, + "content": { + "mimeType": "application/json", + "size": 223, + "text": "{\"_id\":\"esv-test\",\"activeVersion\":\"3\",\"description\":\"test\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-04-13T17:24:40.840844Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"3\",\"useInPlaceholders\":true}" + }, + "cookies": [], + "headers": [ + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "date", + "value": "Tue, 14 Apr 2026 18:43:34 GMT" + }, + { + "name": "content-length", + "value": "223" + }, + { + "name": "x-forgerock-transactionid", + "value": "26c5d872-3ce9-4679-95bc-11c2039128f6" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 325, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-14T18:43:34.495Z", + "time": 178, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 178 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/oauth2_393036114/recording.har new file mode 100644 index 000000000..4e65c55bc --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/oauth2_393036114/recording.har @@ -0,0 +1,146 @@ +{ + "log": { + "_recordingName": "config-manager/pull/secrets/0_a_D/oauth2", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "ff75519a93ccab829f8ee8cf5e92b49f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 1329, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-d10d232d-0e23-4038-88cf-2b732557f830" + }, + { + "name": "accept-api-version", + "value": "protocol=2.1,resource=1.0" + }, + { + "name": "content-length", + "value": "1329" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 443, + "httpVersion": "HTTP/1.1", + "method": "POST", + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [], + "text": "assertion=&client_id=service-account&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=fr:idc:custom-domain:* fr:idc:release:* fr:idc:sso-cookie:* fr:am:* fr:autoaccess:* fr:idc:content-security-policy:* fr:idc:esv:* fr:idc:certificate:* fr:idm:* fr:idc:analytics:* fr:idc:cookie-domain:* fr:idc:promotion:*" + }, + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/am/oauth2/access_token" + }, + "response": { + "bodySize": 1787, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 1787, + "text": "{\"access_token\":\"\",\"scope\":\"fr:idc:custom-domain:* fr:idc:release:* fr:idc:sso-cookie:* fr:am:* fr:autoaccess:* fr:idc:content-security-policy:* fr:idc:esv:* fr:idc:certificate:* fr:idm:* fr:idc:analytics:* fr:idc:cookie-domain:* fr:idc:promotion:*\",\"token_type\":\"Bearer\",\"expires_in\":899}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "content-security-policy-report-only", + "value": "frame-ancestors 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "1787" + }, + { + "name": "date", + "value": "Tue, 14 Apr 2026 18:43:33 GMT" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-d10d232d-0e23-4038-88cf-2b732557f830" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 561, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-14T18:43:33.786Z", + "time": 146, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 146 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/openidm_3290118515/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/openidm_3290118515/recording.har new file mode 100644 index 000000000..fe78dcf64 --- /dev/null +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_a_D_2174189264/openidm_3290118515/recording.har @@ -0,0 +1,310 @@ +{ + "log": { + "_recordingName": "config-manager/pull/secrets/0_a_D/openidm", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "9cb8561357870863838a9948da32d1e8", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-d10d232d-0e23-4038-88cf-2b732557f830" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1928, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_fields", + "value": "*" + } + ], + "url": "https://openam-frodo-dev.forgeblocks.com/openidm/managed/svcacct/22e714dc-a1b0-4f61-819c-148df8ed5fe6?_fields=%2A" + }, + "response": { + "bodySize": 1437, + "content": { + "mimeType": "application/json;charset=utf-8", + "size": 1437, + "text": "{\"_id\":\"22e714dc-a1b0-4f61-819c-148df8ed5fe6\",\"_rev\":\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\",\"accountStatus\":\"active\",\"name\":\"devin_svc\",\"description\":null,\"scopes\":[\"fr:am:*\",\"fr:idm:*\",\"fr:autoaccess:*\",\"fr:idc:analytics:*\",\"fr:idc:certificate:*\",\"fr:idc:certificate:read\",\"fr:idc:content-security-policy:*\",\"fr:idc:content-security-policy:read\",\"fr:idc:cookie-domain:*\",\"fr:idc:cookie-domain:read\",\"fr:idc:custom-domain:*\",\"fr:idc:custom-domain:read\",\"fr:idc:esv:*\",\"fr:idc:promotion:*\",\"fr:idc:promotion:read\",\"fr:idc:release:*\",\"fr:idc:release:read\",\"fr:idc:sso-cookie:*\",\"fr:idc:sso-cookie:read\"],\"jwks\":\"{\\\"keys\\\":[{\\\"e\\\":\\\"AQAB\\\",\\\"kty\\\":\\\"RSA\\\",\\\"n\\\":\\\"mbFgXRafUw0vumgdyXkNSLt7eO-iShWEnJaZQftnHAEyFv0-13aUd5bNd4ccMKjxfCCj2pzfruKsvcsY1MSDuQgvhgap5jo-gfmebWmGBFiwOL1_wQkrR8sL_JaGnBIbidoHJ-3wVv4nSEJ96wmOYdGo4OkY6hoICnT653cpw4Zw66DSUb6RWzxcxLFBtvhn2Y2_Q1nuU6nowPG1rcCJ_JcoW3zW_OG4Yt5WcIPzLUwfMbXw1grRPZg4Qqxpbo7vIrlExB6iQ-LdARG8_0rPpH_SUcAizR_c0Vp3SMhLg5pi_gVR9dU42WBGpJT6u3uO9kuOC6noJThg5F7M1drlhgasFtGioi2iCsTBitJPjXAEW-Do34Y2KB0bGJ1bLZNkyRJY3VLfYH8dO7FwIPpVCpHSOG7ml6YmYDIFymvCuB8e5rQS_xUb1PEK2YK1TC0ne_uvyb1lZ2RrGfzGZigtC4MJ_Rd4v-r4Z8BbCbykS-zqbEoCjsRUtcVmwBJGiln_Y9MpT42j6EaNxb5hJDAAGx98u57gQ4TcqyAeNOCPNt2QOddtsmcaQlkN9DKYKlLcMp9OQ6SqaFtY-LKoyq7fIYf8v_2uXZFjqmqokKxWFMfLIHj33B4bdRgRWitpeS2x1xZX_FylumYChE2daiRxRvA-kVcMYWMwAkSZcbU9Ovs\\\"}]}\",\"maxCachingTime\":\"15\",\"maxIdleTime\":\"15\",\"maxSessionTime\":\"15\",\"quotaLimit\":\"5\"}" + }, + "cookies": [], + "headers": [ + { + "name": "date", + "value": "Tue, 14 Apr 2026 18:43:33 GMT" + }, + { + "name": "vary", + "value": "Origin" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "content-type", + "value": "application/json;charset=utf-8" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "DENY" + }, + { + "name": "content-length", + "value": "1437" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-d10d232d-0e23-4038-88cf-2b732557f830" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 683, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-14T18:43:33.946Z", + "time": 90, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 90 + } + }, + { + "_id": "9cb8561357870863838a9948da32d1e8", + "_order": 1, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-d10d232d-0e23-4038-88cf-2b732557f830" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1928, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_fields", + "value": "*" + } + ], + "url": "https://openam-frodo-dev.forgeblocks.com/openidm/managed/svcacct/22e714dc-a1b0-4f61-819c-148df8ed5fe6?_fields=%2A" + }, + "response": { + "bodySize": 1437, + "content": { + "mimeType": "application/json;charset=utf-8", + "size": 1437, + "text": "{\"_id\":\"22e714dc-a1b0-4f61-819c-148df8ed5fe6\",\"_rev\":\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\",\"accountStatus\":\"active\",\"name\":\"devin_svc\",\"description\":null,\"scopes\":[\"fr:am:*\",\"fr:idm:*\",\"fr:autoaccess:*\",\"fr:idc:analytics:*\",\"fr:idc:certificate:*\",\"fr:idc:certificate:read\",\"fr:idc:content-security-policy:*\",\"fr:idc:content-security-policy:read\",\"fr:idc:cookie-domain:*\",\"fr:idc:cookie-domain:read\",\"fr:idc:custom-domain:*\",\"fr:idc:custom-domain:read\",\"fr:idc:esv:*\",\"fr:idc:promotion:*\",\"fr:idc:promotion:read\",\"fr:idc:release:*\",\"fr:idc:release:read\",\"fr:idc:sso-cookie:*\",\"fr:idc:sso-cookie:read\"],\"jwks\":\"{\\\"keys\\\":[{\\\"e\\\":\\\"AQAB\\\",\\\"kty\\\":\\\"RSA\\\",\\\"n\\\":\\\"mbFgXRafUw0vumgdyXkNSLt7eO-iShWEnJaZQftnHAEyFv0-13aUd5bNd4ccMKjxfCCj2pzfruKsvcsY1MSDuQgvhgap5jo-gfmebWmGBFiwOL1_wQkrR8sL_JaGnBIbidoHJ-3wVv4nSEJ96wmOYdGo4OkY6hoICnT653cpw4Zw66DSUb6RWzxcxLFBtvhn2Y2_Q1nuU6nowPG1rcCJ_JcoW3zW_OG4Yt5WcIPzLUwfMbXw1grRPZg4Qqxpbo7vIrlExB6iQ-LdARG8_0rPpH_SUcAizR_c0Vp3SMhLg5pi_gVR9dU42WBGpJT6u3uO9kuOC6noJThg5F7M1drlhgasFtGioi2iCsTBitJPjXAEW-Do34Y2KB0bGJ1bLZNkyRJY3VLfYH8dO7FwIPpVCpHSOG7ml6YmYDIFymvCuB8e5rQS_xUb1PEK2YK1TC0ne_uvyb1lZ2RrGfzGZigtC4MJ_Rd4v-r4Z8BbCbykS-zqbEoCjsRUtcVmwBJGiln_Y9MpT42j6EaNxb5hJDAAGx98u57gQ4TcqyAeNOCPNt2QOddtsmcaQlkN9DKYKlLcMp9OQ6SqaFtY-LKoyq7fIYf8v_2uXZFjqmqokKxWFMfLIHj33B4bdRgRWitpeS2x1xZX_FylumYChE2daiRxRvA-kVcMYWMwAkSZcbU9Ovs\\\"}]}\",\"maxCachingTime\":\"15\",\"maxIdleTime\":\"15\",\"maxSessionTime\":\"15\",\"quotaLimit\":\"5\"}" + }, + "cookies": [], + "headers": [ + { + "name": "date", + "value": "Tue, 14 Apr 2026 18:43:34 GMT" + }, + { + "name": "vary", + "value": "Origin" + }, + { + "name": "cache-control", + "value": "no-store" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "content-type", + "value": "application/json;charset=utf-8" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "etag", + "value": "\"a7781fd3-a121-40b3-97c6-2e657ac720d2-34841\"" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-frame-options", + "value": "DENY" + }, + { + "name": "content-length", + "value": "1437" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-d10d232d-0e23-4038-88cf-2b732557f830" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + } + ], + "headersSize": 683, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-14T18:43:34.210Z", + "time": 71, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 71 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/am_1076162899/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/am_1076162899/recording.har index c947c3a06..c0f7a1fc6 100644 --- a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/am_1076162899/recording.har +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/am_1076162899/recording.har @@ -25,11 +25,11 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/4.0.0-35" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "x-forgerock-transactionid", - "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + "value": "frodo-78afa40d-7620-4cc4-a740-f26a21707d6f" }, { "name": "accept-api-version", @@ -113,11 +113,11 @@ }, { "name": "date", - "value": "Fri, 03 Apr 2026 20:03:59 GMT" + "value": "Tue, 14 Apr 2026 18:47:56 GMT" }, { "name": "x-forgerock-transactionid", - "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + "value": "frodo-78afa40d-7620-4cc4-a740-f26a21707d6f" }, { "name": "strict-transport-security", @@ -142,8 +142,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2026-04-03T20:03:59.741Z", - "time": 249, + "startedDateTime": "2026-04-14T18:47:56.334Z", + "time": 188, "timings": { "blocked": -1, "connect": -1, @@ -151,7 +151,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 249 + "wait": 188 } }, { @@ -172,11 +172,11 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/4.0.0-35" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "x-forgerock-transactionid", - "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + "value": "frodo-78afa40d-7620-4cc4-a740-f26a21707d6f" }, { "name": "accept-api-version", @@ -202,11 +202,11 @@ "url": "https://openam-frodo-dev.forgeblocks.com/am/json/serverinfo/version" }, "response": { - "bodySize": 275, + "bodySize": 276, "content": { "mimeType": "application/json;charset=UTF-8", - "size": 275, - "text": "{\"_id\":\"version\",\"_rev\":\"-824275682\",\"version\":\"9.0.0-SNAPSHOT\",\"fullVersion\":\"ForgeRock Access Management 9.0.0-SNAPSHOT Build 75a770de430656acd9cf271c54af448902e5589a (2026-March-25 18:41)\",\"revision\":\"75a770de430656acd9cf271c54af448902e5589a\",\"date\":\"2026-March-25 18:41\"}" + "size": 276, + "text": "{\"_id\":\"version\",\"_rev\":\"-1876078088\",\"version\":\"9.0.0-SNAPSHOT\",\"fullVersion\":\"ForgeRock Access Management 9.0.0-SNAPSHOT Build 2a2686af9631bd8d8866c92ea2411814899acefd (2026-March-30 15:23)\",\"revision\":\"2a2686af9631bd8d8866c92ea2411814899acefd\",\"date\":\"2026-March-30 15:23\"}" }, "cookies": [], "headers": [ @@ -244,7 +244,7 @@ }, { "name": "etag", - "value": "\"-824275682\"" + "value": "\"-1876078088\"" }, { "name": "expires", @@ -260,15 +260,15 @@ }, { "name": "content-length", - "value": "275" + "value": "276" }, { "name": "date", - "value": "Fri, 03 Apr 2026 20:04:00 GMT" + "value": "Tue, 14 Apr 2026 18:47:56 GMT" }, { "name": "x-forgerock-transactionid", - "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + "value": "frodo-78afa40d-7620-4cc4-a740-f26a21707d6f" }, { "name": "strict-transport-security", @@ -284,17 +284,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 787, + "headersSize": 763, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2026-04-03T20:04:00.173Z", - "time": 148, + "startedDateTime": "2026-04-14T18:47:56.715Z", + "time": 147, "timings": { "blocked": -1, "connect": -1, @@ -302,7 +302,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 148 + "wait": 147 } } ], diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/environment_1072573434/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/environment_1072573434/recording.har index cd493117c..d0d5b1323 100644 --- a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/environment_1072573434/recording.har +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/environment_1072573434/recording.har @@ -25,7 +25,7 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/4.0.0-35" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "accept-api-version", @@ -77,11 +77,11 @@ }, { "name": "date", - "value": "Fri, 03 Apr 2026 20:04:00 GMT" + "value": "Tue, 14 Apr 2026 18:47:56 GMT" }, { "name": "x-forgerock-transactionid", - "value": "eb566b3b-586b-402a-bbf1-d65038fe8497" + "value": "d389a3d9-ee85-4a9f-8673-a45716e93c84" }, { "name": "strict-transport-security", @@ -97,17 +97,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 413, + "headersSize": 388, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2026-04-03T20:04:00.333Z", - "time": 76, + "startedDateTime": "2026-04-14T18:47:56.878Z", + "time": 85, "timings": { "blocked": -1, "connect": -1, @@ -115,7 +115,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 76 + "wait": 85 } }, { @@ -136,7 +136,7 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/4.0.0-35" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "accept-api-version", @@ -162,11 +162,11 @@ "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets" }, "response": { - "bodySize": 1674, + "bodySize": 361, "content": { "mimeType": "application/json", - "size": 1674, - "text": "{\"pagedResultsCookie\":null,\"remainingPagedResults\":-1,\"result\":[{\"_id\":\"esv-osaic-fradmin-serviceclient-secret\",\"activeVersion\":\"1\",\"description\":\"Used in OSUserLogin journey. Not sure what this is used for.\\n\\n1/12/2026 Dylan Berry\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-13T19:30:38.743047Z\",\"lastChangedBy\":\"Frodo-SA-1773261131370\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-push-aws-sns-access-key-id\",\"activeVersion\":\"1\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-13T19:30:39.673227Z\",\"lastChangedBy\":\"Frodo-SA-1773261131370\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-push-aws-sns-access-key-secret\",\"activeVersion\":\"1\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-13T19:30:40.637978Z\",\"lastChangedBy\":\"Frodo-SA-1773261131370\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-sns-access-key-id\",\"activeVersion\":\"1\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-13T19:30:41.602432Z\",\"lastChangedBy\":\"Frodo-SA-1773261131370\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-sns-access-key-secret\",\"activeVersion\":\"1\",\"description\":\"\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-13T19:30:42.847978Z\",\"lastChangedBy\":\"Frodo-SA-1773261131370\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true},{\"_id\":\"esv-test\",\"activeVersion\":\"1\",\"description\":\"test\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-30T19:45:08.231563Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}],\"resultCount\":6,\"totalPagedResults\":-1,\"totalPagedResultsPolicy\":\"NONE\"}" + "size": 361, + "text": "{\"pagedResultsCookie\":null,\"remainingPagedResults\":-1,\"result\":[{\"_id\":\"esv-test\",\"activeVersion\":\"3\",\"description\":\"test\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-04-13T17:24:40.840844Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"3\",\"useInPlaceholders\":true}],\"resultCount\":1,\"totalPagedResults\":-1,\"totalPagedResultsPolicy\":\"NONE\"}" }, "cookies": [], "headers": [ @@ -176,15 +176,15 @@ }, { "name": "date", - "value": "Fri, 03 Apr 2026 20:04:00 GMT" + "value": "Tue, 14 Apr 2026 18:47:57 GMT" }, { "name": "content-length", - "value": "1674" + "value": "361" }, { "name": "x-forgerock-transactionid", - "value": "7574b573-13d4-4aa8-a20e-f6405cac8716" + "value": "f474dcac-14f7-4c0e-b99f-e2b112cdfa8b" }, { "name": "strict-transport-security", @@ -200,17 +200,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 326, + "headersSize": 300, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2026-04-03T20:04:00.498Z", - "time": 167, + "startedDateTime": "2026-04-14T18:47:57.064Z", + "time": 233, "timings": { "blocked": -1, "connect": -1, @@ -218,7 +218,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 167 + "wait": 233 } }, { @@ -239,7 +239,7 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/4.0.0-35" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "accept-api-version", @@ -269,7 +269,7 @@ "content": { "mimeType": "application/json", "size": 223, - "text": "{\"_id\":\"esv-test\",\"activeVersion\":\"1\",\"description\":\"test\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-03-30T19:45:08.231563Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"1\",\"useInPlaceholders\":true}" + "text": "{\"_id\":\"esv-test\",\"activeVersion\":\"3\",\"description\":\"test\",\"encoding\":\"generic\",\"lastChangeDate\":\"2026-04-13T17:24:40.840844Z\",\"lastChangedBy\":\"phales@trivir.com\",\"loaded\":true,\"loadedVersion\":\"3\",\"useInPlaceholders\":true}" }, "cookies": [], "headers": [ @@ -279,7 +279,7 @@ }, { "name": "date", - "value": "Fri, 03 Apr 2026 20:04:00 GMT" + "value": "Tue, 14 Apr 2026 18:47:57 GMT" }, { "name": "content-length", @@ -287,7 +287,7 @@ }, { "name": "x-forgerock-transactionid", - "value": "5ca2e49e-1723-49aa-bd68-5ecbdc614bf8" + "value": "9a949f36-ac95-4aca-90a3-ee721e77953e" }, { "name": "strict-transport-security", @@ -303,17 +303,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 325, + "headersSize": 300, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2026-04-03T20:04:00.688Z", - "time": 201, + "startedDateTime": "2026-04-14T18:47:57.310Z", + "time": 193, "timings": { "blocked": -1, "connect": -1, @@ -321,7 +321,110 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 201 + "wait": 193 + } + }, + { + "_id": "d5e5902db7ff3a513a98dcd537e1059d", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/4.0.0-36" + }, + { + "name": "accept-api-version", + "value": "protocol=1.0,resource=1.0" + }, + { + "name": "authorization", + "value": "Bearer " + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.forgeblocks.com" + } + ], + "headersSize": 1869, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [], + "url": "https://openam-frodo-dev.forgeblocks.com/environment/secrets/esv-test/versions" + }, + "response": { + "bodySize": 282, + "content": { + "mimeType": "application/json", + "size": 282, + "text": "[{\"createDate\":\"2026-04-13T17:24:30.893036Z\",\"loaded\":false,\"status\":\"ENABLED\",\"version\":\"3\"},{\"createDate\":\"2026-04-13T17:23:45.594504Z\",\"loaded\":false,\"status\":\"DISABLED\",\"version\":\"2\"},{\"createDate\":\"2026-03-30T19:45:07.816536Z\",\"loaded\":false,\"status\":\"ENABLED\",\"version\":\"1\"}]" + }, + "cookies": [], + "headers": [ + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "date", + "value": "Tue, 14 Apr 2026 18:47:57 GMT" + }, + { + "name": "content-length", + "value": "282" + }, + { + "name": "x-forgerock-transactionid", + "value": "a95cfe01-41a9-4b9b-82cc-5533bcdf8a0a" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload;" + }, + { + "name": "x-robots-tag", + "value": "none" + }, + { + "name": "via", + "value": "1.1 google" + }, + { + "name": "alt-svc", + "value": "h3=\":443\"; ma=2592000" + } + ], + "headersSize": 300, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2026-04-14T18:47:57.510Z", + "time": 270, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 270 } } ], diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/oauth2_393036114/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/oauth2_393036114/recording.har index 0f3ba79b8..fa502b9ba 100644 --- a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/oauth2_393036114/recording.har +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/oauth2_393036114/recording.har @@ -25,11 +25,11 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/4.0.0-35" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "x-forgerock-transactionid", - "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + "value": "frodo-78afa40d-7620-4cc4-a740-f26a21707d6f" }, { "name": "accept-api-version", @@ -98,11 +98,11 @@ }, { "name": "date", - "value": "Fri, 03 Apr 2026 20:04:00 GMT" + "value": "Tue, 14 Apr 2026 18:47:56 GMT" }, { "name": "x-forgerock-transactionid", - "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + "value": "frodo-78afa40d-7620-4cc4-a740-f26a21707d6f" }, { "name": "strict-transport-security", @@ -127,8 +127,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2026-04-03T20:04:00.032Z", - "time": 126, + "startedDateTime": "2026-04-14T18:47:56.554Z", + "time": 140, "timings": { "blocked": -1, "connect": -1, @@ -136,7 +136,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 126 + "wait": 140 } } ], diff --git a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/openidm_3290118515/recording.har b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/openidm_3290118515/recording.har index e7497e1eb..b8c0e2f70 100644 --- a/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/openidm_3290118515/recording.har +++ b/test/e2e/mocks/config-manager_4167095917/pull_2167214206/secrets_3084510534/0_n_D_3738999489/openidm_3290118515/recording.har @@ -25,11 +25,11 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/4.0.0-35" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "x-forgerock-transactionid", - "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + "value": "frodo-78afa40d-7620-4cc4-a740-f26a21707d6f" }, { "name": "authorization", @@ -66,7 +66,7 @@ "headers": [ { "name": "date", - "value": "Fri, 03 Apr 2026 20:04:00 GMT" + "value": "Tue, 14 Apr 2026 18:47:56 GMT" }, { "name": "vary", @@ -118,7 +118,7 @@ }, { "name": "x-forgerock-transactionid", - "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + "value": "frodo-78afa40d-7620-4cc4-a740-f26a21707d6f" }, { "name": "strict-transport-security", @@ -143,8 +143,8 @@ "status": 200, "statusText": "OK" }, - "startedDateTime": "2026-04-03T20:04:00.171Z", - "time": 87, + "startedDateTime": "2026-04-14T18:47:56.712Z", + "time": 80, "timings": { "blocked": -1, "connect": -1, @@ -152,7 +152,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 87 + "wait": 80 } }, { @@ -173,11 +173,11 @@ }, { "name": "user-agent", - "value": "@rockcarver/frodo-lib/4.0.0-35" + "value": "@rockcarver/frodo-lib/4.0.0-36" }, { "name": "x-forgerock-transactionid", - "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + "value": "frodo-78afa40d-7620-4cc4-a740-f26a21707d6f" }, { "name": "authorization", @@ -214,7 +214,7 @@ "headers": [ { "name": "date", - "value": "Fri, 03 Apr 2026 20:04:00 GMT" + "value": "Tue, 14 Apr 2026 18:47:57 GMT" }, { "name": "vary", @@ -266,7 +266,7 @@ }, { "name": "x-forgerock-transactionid", - "value": "frodo-4ac1a9bb-ac74-4ee2-8b0a-83c0f08cad29" + "value": "frodo-78afa40d-7620-4cc4-a740-f26a21707d6f" }, { "name": "strict-transport-security", @@ -282,17 +282,17 @@ }, { "name": "alt-svc", - "value": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + "value": "h3=\":443\"; ma=2592000" } ], - "headersSize": 683, + "headersSize": 658, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2026-04-03T20:04:00.418Z", - "time": 64, + "startedDateTime": "2026-04-14T18:47:56.977Z", + "time": 70, "timings": { "blocked": -1, "connect": -1, @@ -300,7 +300,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 64 + "wait": 70 } } ],