Skip to content

Conversation

@ancheetah
Copy link
Collaborator

@ancheetah ancheetah commented Nov 27, 2025

JIRA Ticket

https://pingidentity.atlassian.net/browse/SDKS-4284

Description

Adds helper function to get allowUserDefinedQuestions flag. Adds tests.
Added changeset

Summary by CodeRabbit

  • New Features
    • Added support for custom, user-defined security questions in knowledge-based authentication (KBA) workflows, allowing users to create personalized security questions beyond predefined options.

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Nov 27, 2025

🦋 Changeset detected

Latest commit: e99b374

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
@forgerock/journey-client Patch
@forgerock/davinci-client Patch
@forgerock/oidc-client Patch
@forgerock/protect Patch
@forgerock/sdk-types Patch
@forgerock/sdk-utilities Patch
@forgerock/iframe-manager Patch
@forgerock/sdk-logger Patch
@forgerock/sdk-oidc Patch
@forgerock/sdk-request-middleware Patch
@forgerock/storage Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Nov 27, 2025

Walkthrough

The changes add support for user-defined KBA (Knowledge-Based Authentication) questions by introducing an allowUserDefinedQuestions flag to the KBA callback payload, implementing a public accessor method in the client library, updating E2E tests to verify the functionality, and extending the changeset configuration to ignore additional packages.

Changes

Cohort / File(s) Summary
Changeset configuration
.changeset/config.json, .changeset/eleven-baboons-battle.md
Updated package ignore list to include @forgerock/journey-app and @forgerock/journey-suites; added patch release note for @forgerock/journey-client documenting new KBA allowUserDefinedQuestions flag support.
Client library implementation
packages/journey-client/src/lib/callbacks/kba-create-callback.ts, packages/journey-client/src/lib/callbacks/kba-create-callback.test.ts
Added new isAllowedUserDefinedQuestions(): boolean public accessor method to KbaCreateCallback that reads the allowUserDefinedQuestions payload field (defaults to false); added corresponding test case verifying accessor returns true.
E2E test updates
e2e/journey-app/components/kba-create.ts, e2e/journey-suites/src/registration.test.ts
Enhanced E2E components to support optional user-defined question input; updated registration test to verify custom KBA question flow with dynamic question entry and answer validation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as KBA UI Component
    participant CB as KbaCreateCallback
    
    User->>UI: Access KBA question form
    UI->>CB: Check isAllowedUserDefinedQuestions()
    CB-->>UI: Returns allowUserDefinedQuestions flag
    
    alt User-defined option enabled
        User->>UI: Select "user-defined" choice
        UI->>UI: Show custom question input
        User->>UI: Enter custom question text
        User->>UI: Enter answer
        UI->>CB: Update callback with custom values
    else Predefined question
        User->>UI: Select predefined question
        User->>UI: Enter answer
        UI->>CB: Update callback with predefined choice
    end
    
    CB-->>User: Callback submitted
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Multiple file types: Mix of configuration, library implementation, and E2E tests requires context switching
  • Cohesive feature: All changes collectively implement a single feature (user-defined KBA questions), making the narrative clear
  • Implementation complexity: Adding a new accessor method and flag support is straightforward, but E2E test logic changes warrant verification
  • Specific areas requiring attention:
    • Verify that the allowUserDefinedQuestions flag payload structure aligns with backend expectations
    • Confirm E2E test assertions in registration.test.ts properly validate both custom and predefined question flows
    • Validate that the UI component gracefully handles the flag when false (disables user-defined option)

Poem

🐰 A question arose, so custom and free,
"Why not let users define what to ask me?"
With a flag and accessor, the feature took flight,
E2E tests hopping—all verified right!
Knowledge now bends to each bunny's delight. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding support for the KBA allowUserDefinedQuestions flag to journey-client.
Description check ✅ Passed The description includes the required JIRA ticket link and describes the changes, though it is brief and lacks specific implementation details.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch SDKS-4284-fix-kba

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link
Contributor

nx-cloud bot commented Nov 27, 2025

View your CI Pipeline Execution ↗ for commit e99b374

Command Status Duration Result
nx run-many -t build --no-agents ✅ Succeeded <1s View ↗
nx affected -t build lint test e2e-ci ✅ Succeeded 2m 9s View ↗

☁️ Nx Cloud last updated this comment at 2025-11-27 03:08:48 UTC

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/journey-client/src/lib/callbacks/kba-create-callback.test.ts (1)

27-31: Unit coverage for allowUserDefinedQuestions is appropriate

Extending the fixture payload with allowUserDefinedQuestions: true and asserting isAllowedUserDefinedQuestions() returns true gives direct coverage of the new accessor and wiring. Shared payload usage across tests is acceptable here since none depend on default values.

If you want to harden tests further, you could add a small separate test for the default false behavior when the flag is omitted.

Also applies to: 58-61

e2e/journey-app/components/kba-create.ts (1)

37-43: Conditional user-defined option wiring looks good

Appending the "user-defined" option only when isAllowedUserDefinedQuestions() is true is a clean way to gate the custom-question path off the callback payload, and the value/text are consistent with how the tests drive the select.

You might consider hoisting the sentinel 'user-defined' string into a small local constant to avoid drift between the option setup and the comparison in the change handler.

e2e/journey-suites/src/registration.test.ts (1)

44-49: Custom KBA question flow and console assertions line up with the UI

Driving security question 7 via the "user-defined" option, then asserting the corresponding console messages for both questions and answers, matches the behavior implemented in the KBA component and gives good end-to-end coverage of the new flag-driven path.

The inline comment above the Answer 8 fill still mentions "Pizza" while the test uses "AAA Engineering"; consider updating the comment to avoid confusion during future maintenance.

Also applies to: 67-70

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6358d9a and e99b374.

📒 Files selected for processing (6)
  • .changeset/config.json (1 hunks)
  • .changeset/eleven-baboons-battle.md (1 hunks)
  • e2e/journey-app/components/kba-create.ts (2 hunks)
  • e2e/journey-suites/src/registration.test.ts (2 hunks)
  • packages/journey-client/src/lib/callbacks/kba-create-callback.test.ts (2 hunks)
  • packages/journey-client/src/lib/callbacks/kba-create-callback.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-22T15:14:00.044Z
Learnt from: ryanbas21
Repo: ForgeRock/ping-javascript-sdk PR: 430
File: packages/journey-client/src/lib/callbacks/name-callback.ts:9-15
Timestamp: 2025-10-22T15:14:00.044Z
Learning: In packages/journey-client, callback classes are internal implementation details not part of the public API. The callbacks barrel (src/lib/callbacks/index.ts) intentionally only exports the base JourneyCallback class. Internal code imports concrete callback classes directly from their individual files (e.g., factory.ts, journey-client.ts).

Applied to files:

  • packages/journey-client/src/lib/callbacks/kba-create-callback.ts
  • packages/journey-client/src/lib/callbacks/kba-create-callback.test.ts
🧬 Code graph analysis (1)
packages/journey-client/src/lib/callbacks/kba-create-callback.test.ts (1)
packages/journey-client/src/lib/callbacks/kba-create-callback.ts (1)
  • KbaCreateCallback (14-68)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Mend Code Security Check
🔇 Additional comments (3)
.changeset/eleven-baboons-battle.md (1)

1-5: Changeset entry is clear and correctly scoped

Patch bump for @forgerock/journey-client with a concise description of the new KBA flag support looks good and matches the code changes.

.changeset/config.json (1)

15-30: Ignoring journey-app and journey-suites in changesets makes sense

Adding @forgerock/journey-app and @forgerock/journey-suites to ignore is consistent with treating them as demo/e2e tooling and prevents unnecessary releases.

packages/journey-client/src/lib/callbacks/kba-create-callback.ts (1)

36-41: New accessor correctly surfaces the allowUserDefinedQuestions flag

isAllowedUserDefinedQuestions cleanly wraps getOutputByName with a false default, which is a safe fallback when the flag is absent and aligns with the existing callback API style.

Comment on lines +64 to +85
const selectedQuestion = (event.target as HTMLInputElement).value;
if (selectedQuestion === 'user-defined') {
// If user-defined option is selected, prompt for custom question
const customQuestionLabel = document.createElement('label');
customQuestionLabel.htmlFor = `${collectorKey}-question-user-defined`;
customQuestionLabel.innerText = 'Type your question ' + idx + ':';

const customQuestionInput = document.createElement('input');
customQuestionInput.type = 'text';
customQuestionInput.id = `${collectorKey}-question-user-defined`;
customQuestionInput.placeholder = 'Type your question';

container.lastElementChild?.before(customQuestionLabel);
container.lastElementChild?.before(customQuestionInput);
customQuestionInput.addEventListener('input', (e) => {
callback.setQuestion((e.target as HTMLInputElement).value);
console.log('Custom question ' + idx + ':', callback.getInputValue(0));
});
} else {
callback.setQuestion((event.target as HTMLInputElement).value);
console.log('Selected question ' + idx + ':', callback.getInputValue(0));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix DOM insertion order and avoid duplicate custom question inputs

The dynamic custom-question handling works functionally, but there are a couple of rough edges:

  • Using container.lastElementChild?.before(...) inserts the custom label/input between the answer label and answer input, so the “Answer N” label is visually separated from its input.
  • Each time the user re-selects the “user-defined” option, a new label/input pair and event listener are created; nothing prevents duplicates.

You can keep behavior the same while improving UX and robustness by:

  • Anchoring the custom fields directly after the question <select>.
  • Creating the custom input only once per component.
  • Typing the event target as HTMLSelectElement and using a change listener which is more idiomatic for <select>.

For example:

-  questionInput.addEventListener('input', (event) => {
-    const selectedQuestion = (event.target as HTMLInputElement).value;
+  questionInput.addEventListener('change', (event) => {
+    const selectEl = event.target as HTMLSelectElement;
+    const selectedQuestion = selectEl.value;
     if (selectedQuestion === 'user-defined') {
-      // If user-defined option is selected, prompt for custom question
-      const customQuestionLabel = document.createElement('label');
-      customQuestionLabel.htmlFor = `${collectorKey}-question-user-defined`;
-      customQuestionLabel.innerText = 'Type your question ' + idx + ':';
-
-      const customQuestionInput = document.createElement('input');
-      customQuestionInput.type = 'text';
-      customQuestionInput.id = `${collectorKey}-question-user-defined`;
-      customQuestionInput.placeholder = 'Type your question';
-
-      container.lastElementChild?.before(customQuestionLabel);
-      container.lastElementChild?.before(customQuestionInput);
-      customQuestionInput.addEventListener('input', (e) => {
-        callback.setQuestion((e.target as HTMLInputElement).value);
-        console.log('Custom question ' + idx + ':', callback.getInputValue(0));
-      });
+      // If user-defined option is selected, prompt for custom question
+      let customQuestionInput = container.querySelector<HTMLInputElement>(
+        `#${collectorKey}-question-user-defined`,
+      );
+
+      if (!customQuestionInput) {
+        const customQuestionLabel = document.createElement('label');
+        customQuestionLabel.htmlFor = `${collectorKey}-question-user-defined`;
+        customQuestionLabel.innerText = 'Type your question ' + idx + ':';
+
+        customQuestionInput = document.createElement('input');
+        customQuestionInput.type = 'text';
+        customQuestionInput.id = `${collectorKey}-question-user-defined`;
+        customQuestionInput.placeholder = 'Type your question';
+
+        // Insert the custom question fields immediately after the select
+        questionInput.after(customQuestionLabel, customQuestionInput);
+
+        customQuestionInput.addEventListener('input', (e) => {
+          callback.setQuestion((e.target as HTMLInputElement).value);
+          console.log('Custom question ' + idx + ':', callback.getInputValue(0));
+        });
+      }
     } else {
-      callback.setQuestion((event.target as HTMLInputElement).value);
+      callback.setQuestion(selectEl.value);
       console.log('Selected question ' + idx + ':', callback.getInputValue(0));
     }
   });

This keeps the console output and tests intact while tightening the DOM behavior.

Also applies to: 88-90

🤖 Prompt for AI Agents
In e2e/journey-app/components/kba-create.ts around lines 64-85 (and similarly
lines 88-90), the select handling inserts duplicate custom inputs and places
them before the answer label/input; change the listener to use a "change" event
on an HTMLSelectElement, type the event target as HTMLSelectElement, and anchor
the custom label/input directly after the question <select> (e.g.,
insertAdjacentElement or nextSibling insertion) instead of using
container.lastElementChild.before(...). Ensure you only create the custom
label/input once by checking for an existing element with the user-defined id
(or querySelector) and reuse it (and its event listener) on subsequent
selections; when switching away from "user-defined" hide or remove the existing
custom input and update callback.setQuestion(...) from the select's value or the
persistent custom input's value accordingly.

@codecov-commenter
Copy link

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 18.81%. Comparing base (b89ad58) to head (e99b374).
⚠️ Report is 7 commits behind head on main.

❌ Your project status has failed because the head coverage (18.81%) is below the target coverage (40.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #500      +/-   ##
==========================================
+ Coverage   18.79%   18.81%   +0.02%     
==========================================
  Files         140      140              
  Lines       27640    27647       +7     
  Branches      980      981       +1     
==========================================
+ Hits         5195     5202       +7     
  Misses      22445    22445              
Files with missing lines Coverage Δ
...ey-client/src/lib/callbacks/kba-create-callback.ts 94.11% <100.00%> (+0.67%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 27, 2025

Open in StackBlitz

@forgerock/davinci-client

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/davinci-client@500

@forgerock/oidc-client

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/oidc-client@500

@forgerock/protect

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/protect@500

@forgerock/sdk-types

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/sdk-types@500

@forgerock/sdk-utilities

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/sdk-utilities@500

@forgerock/iframe-manager

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/iframe-manager@500

@forgerock/sdk-logger

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/sdk-logger@500

@forgerock/sdk-oidc

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/sdk-oidc@500

@forgerock/sdk-request-middleware

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/sdk-request-middleware@500

@forgerock/storage

pnpm add https://pkg.pr.new/ForgeRock/ping-javascript-sdk/@forgerock/storage@500

commit: e99b374

@github-actions
Copy link
Contributor

Deployed 4595a14 to https://ForgeRock.github.io/ping-javascript-sdk/pr-500/4595a140668121ec13b9c766fb8764870a4ac723 branch gh-pages in ForgeRock/ping-javascript-sdk

@github-actions
Copy link
Contributor

📦 Bundle Size Analysis

📦 Bundle Size Analysis

🚨 Significant Changes

🔻 @forgerock/journey-client - 0.0 KB (-82.4 KB, -100.0%)

📊 Minor Changes

📈 @forgerock/journey-client - 82.4 KB (+0.1 KB)

➖ No Changes

@forgerock/device-client - 9.2 KB
@forgerock/oidc-client - 23.4 KB
@forgerock/protect - 150.1 KB
@forgerock/sdk-utilities - 7.5 KB
@forgerock/sdk-types - 8.0 KB
@forgerock/storage - 1.4 KB
@forgerock/sdk-logger - 1.6 KB
@forgerock/iframe-manager - 2.4 KB
@forgerock/sdk-request-middleware - 4.5 KB
@forgerock/sdk-oidc - 2.6 KB
@forgerock/davinci-client - 39.5 KB


13 packages analyzed • Baseline from latest main build

Legend

🆕 New package
🔺 Size increased
🔻 Size decreased
➖ No change

ℹ️ How bundle sizes are calculated
  • Current Size: Total gzipped size of all files in the package's dist directory
  • Baseline: Comparison against the latest build from the main branch
  • Files included: All build outputs except source maps and TypeScript build cache
  • Exclusions: .map, .tsbuildinfo, and .d.ts.map files

🔄 Updated automatically on each push to this PR

Copy link
Collaborator

@ryanbas21 ryanbas21 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 looks great.

@ancheetah ancheetah merged commit b6d3630 into main Dec 2, 2025
8 checks passed
@ancheetah ancheetah deleted the SDKS-4284-fix-kba branch December 2, 2025 19:18
@ryanbas21 ryanbas21 mentioned this pull request Dec 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants