Giter Site home page Giter Site logo

rockcarver / frodo-lib Goto Github PK

View Code? Open in Web Editor NEW
9.0 9.0 16.0 15.45 MB

A library to manage ForgeRock Identity Cloud tenants, ForgeOps deployments, and classic deployments.

License: MIT License

JavaScript 0.10% TypeScript 99.90%
am cicd devops export forgeops forgerock identity-cloud idm import library openam openidm

frodo-lib's People

Contributors

afalahi avatar atomicsamurai avatar brain-hol avatar conorbarford-ping avatar gh-action-bump-version avatar github-actions[bot] avatar hfranklin avatar justinchinfr avatar meesvandongen avatar mhjmaas avatar patrickdiligentforgerock avatar phalestrivir avatar sayers-pi avatar storem avatar vscheuber avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

frodo-lib's Issues

Implement testing

Given the nonfunctional nature of this ticket, I will omit the template, this ticket adds jest and a series of tests to

  • test the Interface (Interface tests)
  • test the results of an action taken using Frodo (Functional tests)
  • the internal workings (unit tests)

Fix skipped tests

6 Tests recently merged which are now skipped using test.skip( - They are either untestable due to design flaw (from the perspective of pure functions) or stubs.

To get a full output to add --verbse to package.json

"scripts": {
    "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --verbose"
  },

See comments consider refactoring test or implementation:

Refactor use of util.format

util.format

Supports %s C style replacement but JavaScript itself supports template literals which are clearer to see the expected output and don't need an import.
A function can be used for composure.

const journeyURLTemplate =
  '%s/json%s/realm-config/authentication/authenticationtrees/trees/%s';
const nodeURLTemplate =
  '%s/json%s/realm-config/authentication/authenticationtrees/nodes/%s/%s';
  
// five minutes later
const urlString = util.format(
  queryAllTreesURLTemplate,
  storage.session.getTenant(),
  getCurrentRealmPath()
);

const response = await generateAmApi(getTreeApiConfig())
    .get(urlString, {
      withCredentials: true,
    })

Becomes

const journeyURLTemplate = ({ host, treename }) => `${host}/json%s/realm-config/authentication/authenticationtrees/trees/${treename}`;
const nodeURLTemplate = ({host, something, somethingElse}) => `${host}/json%s/realm-config/authentication/authenticationtrees/nodes/${something}/${somethingElse}`;

const response = await generateAmApi(getTreeApiConfig())
    .get(journeyURLTemplate({ host, treename }), {
      withCredentials: true,
    })

list scripts --filter

Is your feature request related to a problem? Please describe.
Im building a little utility library ForgeRocket-ignite for CS_common to patch Rhino environments with Lodash like convenience and a more es6 compliment std library among other tree shakeable options.

The library works:

  1. customize
  2. build
  3. deploy
  4. inject selected feature(s) to the selected script(s)

Frodo is a key actor in this, as it is the engine for most remote interactions, ignite itself is just the wizard and cli clients

The problem, This is JavaScript decision-node only library, I need to be able to filter out the groovy and the N/A JavaScript giving me only relevant JavaScript scripts to inject this library/its features into

Describe the solution you'd like
case: I want all JavaScript > Decision Nodes
frodo scripts --list --language=javascript --ofType='decisionNode'

Describe alternatives you've considered
Not doing this and being sad

Additional context
Want a demo, ask me any time :D

Add override switch when importing Journeys to automatically overwrite linked config such as scripts where the name matches but UUID is different.

When trying to import a journey were there are other related artifacts such as scripts, secondary social providers, email templates, etc., if the UUID of these linked objects are different, the import fails. It would be great to have an option to force these linked artifacts to be updated during the import if the names are the same and UUIDs are different.

src folder reorg?

For simplicity, perhaps we can flatten src move all utils, templates parallel with ops?

Some thoughts on OPS
We have recontextualized frodo and are striving to create a separation from client and lib, a fresh start.. so I propose that we change the name ops which to me sounds like dev-ops to bindings or public, technically it's API but as the API is referring to REST calls its a little confusing.

log tail switch takes unusually long to return

In v0.6.1 the cmd below starts printing results in a few seconds. In v0.7.0 the same cmd takes several mins to begin returning results.

Steps to reproduce the behavior:

  1. Run command from v0.7.0 /frodo logs tail hc
  2. Run command from v0.6.1 /frodo logs tail hc

Expected behavior - The tail begins returning in roughly the same amount of time for either frodo versions.

  • OS: macos

Provide analyze feature

frodo should provide analyze feature to generate a report for current deployment. This report should provide:

  1. List of journeys
  2. Customizations including Scripted and Java nodes, if any
  3. Applications: OAuth2, SAML entities, Policies
  4. Identity sources

Investigate impact of OPENAM-19064 on script command

A bug which may affect the ability to save Access Management Script Changes. This issue impacts existing scripts, and does not affect newly created scripts. As a temporary workaround to update an existing script, a new script can be created with the existing scripts data copied to it, and then updated. Related Jira Ticket OPENAM-19064.

A new ForgeRock SDK install command

Is your feature request related to a problem? Please describe.
The ForgeRock SDK is a great and valid option used by many ForgeRock customers and there is a great set of tutorials but its all very manual, It would be great if the SDK could be setup automatically by running a command.

frodo sdk install --centralized-login

Describe the solution you'd like

This result of the command could be a configured OAuthClient and Cors config, with even a generated basic set of connection options to plug straight into your code.

Handle ESVs

Frodo should handle ESVs:

  • Detect referenced ESVs and export the ESV itself so it can be re-imported
  • If the ESV value can be exported, Frodo should do that (potentially ask?)
  • If the ESV value cannot be exports (secrets) just export the ESV definition
  • On import of any configuration artifact Frodo supports (journeys, IDM config, agent profiles, etc.) import any referenced ESVs previously exported
  • etc.

Create build scripts for all platforms.

I think we can do more on the macos build I did not foresee the need to build binaries locally from any branch and therefore haven't checked-in the cert we use in github to sign the app. But I will check it in so we can create a gulp or a build script for all the platforms so you can run an npm run build

Description of journey import clarification...

Describe the bug
The help mentions -f, --file Name of the file to write the exported journey(s) to. Ignored with -A.
I believe it is required for read during import as well - minor nit.
Likewise to import what is required? a -f and -t? for a single tree in a single JSON? An example please!

Full Realm Exports

Is your feature request related to a problem? Please describe.
Most times when working with clients, we feel in the need to generate a full realm exports and sometimes a full solution export (with all realms and customizations). While a full realm export is possible with Amster, it is preferred to use just one tool, and Frodo is better.

Describe the solution you'd like
I would like to be able to do single and multiple Full-Realm exports.

Describe alternatives you've considered
Full-Realm exports must include everything from the original realm configuration (services, scripts, agents, clients, journeys, etc.).

Additional context
It should be great to have a parameter to select wether to export one realm or all. Also the import command should be able to import a Full-Realm export.

Implement admin command

The command should be a platform admin command and support a litany of admin functions in the form of sub-commands, like:

  • allow designation of any oauth2 client as an admin client (aadd as static user mapping to authentication.json)
  • allow listing of oauth2 admin clients
  • find and fix errors in managed.json (missing flattenProperties flag of org model RDVPs)
  • show/hide all generic extension attributes that are unmodified
  • connect multiple cloud (IDM) instances by configuring CREST proxy
  • support pairs of tenants first
  • triangles later
  • more later
  • etc.

I see these platform admin sub commands as something different than "playbooks" or "packages" we want to support, where one can export and import a number of configuration artifacts.

These platform admin commands are the things that:

  • we always need, always do, but manually and require a FR PHD
  • things that are tedious and boring and manual (like hiding 40 extension attributes so they don't show in the user profile) or unhiding them
  • tasks that require several config changes to create a function or behavior that is common and considered an admin task
  • DANGEROUS tasks that can tear down a tenant if they are done manually and wrong

refactor: pure functions

What?

I would like to shoot for all functions to become pure functions to aid with the testing effort.

Why?

Pure functions have controllable inputs and no external dependencies (apart from modules) this means:

  • They're easier to reason about.
  • They're easier to combine.
  • They're easier to test.
  • They're easier to debug.
  • They're easier to parallelize.
  • They're documentable

Specifically why?

The global state should be passed into a function, decoupling it and allowing testable function calls

what does it look like

Using an object based pattern for varadic args

// Case 1: varadic shorthand
const {host, realm, password} = fromSomeSource;
authenticate({ host, realm, user, password });

// Case 2: setup a profile of stuff
const credentials = {username: 'foo', password: 'bar'};
// called
authenticate({ host, realm, ...credentials });

// Case 3: A test
test("set state to a bad realm", () => {
    const result = () => authenticate({ realm: 234, ...args});
    expect(result).toThrow();
})

Why use an object and de-structuring everywhere?

  1. argument order does not matter nor does the way they are passed
  2. arguments are clearly labeled
  3. Global state can be completely removed in favor of passing objects around
  4. you can combine how they are passed
  5. names of things stay consistent because the names of arguments are pre-determined upstream

state (storage) reform

linked to #37

There is a well-intentioned false getter and setter paradigm used in the storage of the application but it just adds complexity

Not just opinion

  1. consider the below file SessionStorage.js

The main problem I can see here is that getters and setters are supposed to promote immutability/encapsulation by controlling what's private and public. This concept is considerably easier to achieve in a language such as Java.

In JavaScript, although now it is possible to do something similar with Symbol we still exposed the property raw which allows direct modification of the object which suggests that the approach is flawed and at some point, raw was exposed to allow direct modification, the final reason for getters and setters is to give some expectation of properties that change and their names, defining them, but In my example bellow I use JS doc to tell the editor what properties are expected, I also generate docs from this, I finally define true immutability using defineProperty

const _sessionStorage = {}

export default {
    session: {
        setItem: (key, value) => _sessionStorage[key] = value,
        getItem: (key) => _sessionStorage[key],
        removeItem: (key) => delete _sessionStorage[key],
        raw: _sessionStorage,
        setUsername: (value) => _sessionStorage["username"] = value,
        getUsername: () => _sessionStorage["username"],
        setPassword: (value) => _sessionStorage["password"] = value,
        getPassword: () => _sessionStorage["password"],
        setTenant: (value) => _sessionStorage["tenant"] = value,
        getTenant: () => _sessionStorage["tenant"],
        setDeploymentType: (value) => _sessionStorage["deploymentType"] = value,
        getDeploymentType: () => _sessionStorage["deploymentType"],
        setRealm: (value) => _sessionStorage["realm"] = value,
        getRealm: () => _sessionStorage["realm"],
        setCookieName: (value) => _sessionStorage["cookieName"] = value,
        getCookieName: () => _sessionStorage["cookieName"],
        setCookieValue: (value) => _sessionStorage["cookieValue"] = value,
        getCookieValue: () => _sessionStorage["cookieValue"],
        setBearerToken: (value) => _sessionStorage["bearerToken"] = value,
        getBearerToken: () => _sessionStorage["bearerToken"],
        setLogApiKey: (value) => _sessionStorage["logApiKey"] = value,
        getLogApiKey: () => _sessionStorage["logApiKey"],
        setLogApiSecret: (value) => _sessionStorage["logApiSecret"] = value,
        getLogApiSecret: () => _sessionStorage["logApiSecret"],
        setAmVersion: (value) => _sessionStorage["amVersion"] = value,
        getAmVersion: () => _sessionStorage["amVersion"],
        setFrodoVersion: (value) => _sessionStorage["frodoVersion"] = value,
        getFrodoVersion: () => _sessionStorage["frodoVersion"],
        setAllowInsecureConnection: (value) => _sessionStorage["insecure"] = value,
        getAllowInsecureConnection: () => _sessionStorage["insecure"],
    }
}

vs
2. JS doc and plain old JavaScript

/**
 * @typedef {Object} GlobalState
 * @property {boolean} allowInsecureConnection `true` enable HTTP.\
`{ allowInsecureConnection: false }` disable http and enable HTTPS.
 * @property {string} amVersion which version of ForgeRock Access Management (AM) is in use.
 * @property {string} bearerToken The bearer Token, a predominant type of access token used with OAuth 2.0.
 * @property {string} cookieName After auth you will have a cookie with a name and value, this is the name.
 * @property {string} cookieValue After auth you will have a cookie with a name and value, this is the value.
 * @property {"classic"|"cloud"|"forgeops"} deploymentType choose the context of the target environment
- `classic`  A classic Access Management-only deployment with custom layout and configuration.
- `cloud`    A ForgeRock Identity Cloud environment.
- `forgeops` A ForgeOps CDK or CDM deployment.
 * @property {string} frodoVersion The version of lib-frodo, this cannot be changed.
 * @property {string} host What is the url of the tenant?
 * @property {string} logApiKey You provide a generated logging API key from the tenent.
 * @property {string} logApiSecret You provide a generated logging API secret from the tenent.
 * @property {string} password The password of the admin user.
 * @property {string} realm which realm do the frodo commands affect?
 * @property {string} username The username of the admin user.
 */

/**
 * @type {GlobalState}
 */
const globalState = {
  allowInsecureConnection: false,
  amVersion: '',
  bearerToken: '',
  cookieName: '',
  cookieValue: '',
  deploymentType: '',
  host: '',
  logApiKey: '',
  logApiSecret: '',
  password: '',
  realm: '',
  username: '',
};

Object.defineProperty('frodoVersion', globalState, {
  value: packageJSON.version,
  writable: false,
  configurable: false,
});

export default globalState;

frodo-cli binary builds are broken

There appears to be a pipeline issue causing the frodo-cli binary builds to be faulty:

Run dist/bin/linux/frodo -v
/snapshot/dist/node_modules/@rockcarver/frodo-lib/cjs/index.js:1
import fs from 'fs';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (node:vm:355:18)
    at wrapSafe (node:internal/modules/cjs/loader:1040:15)
    at Module._compile (node:internal/modules/cjs/loader:1076:27)
    at Module._compile (pkg/prelude/bootstrap.js:1937:32)
    at Module._extensions..js (node:internal/modules/cjs/loader:1166:10)
    at Module.load (node:internal/modules/cjs/loader:988:32)
    at Module._load (node:internal/modules/cjs/loader:834:12)
    at Module.require (node:internal/modules/cjs/loader:1012:19)
    at Module.require (pkg/prelude/bootstrap.js:1855:31)
    at require (node:internal/modules/cjs/helpers:102:18)

Node.js v18.5.0
Error: Process completed with exit code 1.

Create lib-frodo and separate from client-frodo-cli

Is your feature request related to a problem? Please describe.
frodo once had a frodolibs package and a cli that didn't do anything without. I believe that a central lib which I will call lib-frodo can be a provider for a plethora of applications which I will refer to as clients:

  • frodo GUI
  • a vscode extension
  • the existing cli tool
  • interactive cli tool (a wizard)
  • customer, and staff micro tooling and libraries including ForgeRocket-ignite
  • infrastructure-pipeline tooling

Describe the solution you'd like
lib-frodo should be part of a frodo monorepo where official clients are all kept in a client's folder.

Describe alternatives you've considered
I currently scrape the stdout of frodo cli which isn't elegant for my current library and my plan for an electron GUI would be harder to achieve, it works but it's not as easy to develop tools around Frodo

missing cjs directory

Describe the bug
v0.11.1-4 is missing the cjs directory

To Reproduce
Steps to reproduce the behavior:

  1. npm i @rockcarver/[email protected]
  2. Verify if the node_modules/@rockcarver/frodo-lib/cjs folder does not exist

Expected behavior
cjs folder should exist for commonjs projects

Readme tweaks

Add circular links to frodo-lib and frodo-cli respectively describing the relationship

Add a section for known clients for those looking for how to implement frodo-lib:

  • frodo-cli โ€“ ForgeRock unofficial

Add how to implement frodo-lib section

Any other ideas?

Make lib stateless

Remove the concept of global state storage from lib and pass all storage which should be stated, in as pure functions for testing and purposes relating to individual client requirements.

// some client

const state = {
    username: '',
    password: '',
}

someOpsBinding({
    state
});

Why?

I have a client that only does anything with scripts, instead of just passing state into a couple of opsBindings functions I have to import a reference to lib-state and use some getters and setters which already expose a raw key.

Export and Import ESVs from ID Cloud

Is your feature request related to a problem? Please describe.
There are many scenarios in ID Cloud where the ability to use ESVs between environments comes in handy. As part of moving between environments it would be nice to be able to move ESVs (secrets and potentially values) as well using frodo

Describe the solution you'd like
frodo esv export -D file1.json env1
frodo esv import -D file1.json env2

above would move esvs from env1 to env2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.