Skip to content

feat(davinci-client): send FIDO errors to DaVinci (SDKS-4480) - #730

Open
ancheetah wants to merge 2 commits into
mainfrom
fido-errors-aj-2
Open

feat(davinci-client): send FIDO errors to DaVinci (SDKS-4480)#730
ancheetah wants to merge 2 commits into
mainfrom
fido-errors-aj-2

Conversation

@ancheetah

@ancheetah ancheetah commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

JIRA Ticket

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

Description

  • Adds support for sending FIDO errors to DaVinci with e2e tests (currently skipped but can be run manually)
  • Migrates MFA flow to new env and updates client IDs and flow policies in e2e tests
  • Fixes a false positive with password policy e2e test

Summary by CodeRabbit

  • New Features

    • Added consistent FIDO/WebAuthn error handling, including recognized error codes and fallback handling.
    • FIDO registration and authentication results now expose structured errors that can be forwarded to DaVinci.
    • Added optional FIDO client configuration, including logger settings.
  • Bug Fixes

    • FIDO cancellation, unsupported-device, timeout, and credential failures now continue through the expected flow and display error states correctly.
    • Improved handling when no credential is returned.
  • Tests

    • Expanded coverage for FIDO success, cancellation, and error scenarios across supported flows.

@changeset-bot

changeset-bot Bot commented Jul 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: da1c018

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

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

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

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

FIDO registration and authentication now convert WebAuthn exceptions into structured errors, propagate them through DaVinci collectors and action requests, and expose updated public types. Unit and end-to-end tests cover error mapping, reducer handling, request construction, and canceled WebAuthn prompts.

Changes

FIDO error flow

Layer / File(s) Summary
Public FIDO and collector contracts
packages/davinci-client/src/lib/fido/*, packages/davinci-client/src/lib/*types.ts, packages/davinci-client/api-report/*, packages/davinci-client/src/types.ts
Adds FidoClientConfig, FidoErrorCode, and FIDO GenericError unions across exported contracts.
FIDO error conversion and client handling
packages/davinci-client/src/lib/fido/fido.ts, packages/davinci-client/src/lib/fido/fido.utils.ts, packages/davinci-client/src/lib/fido/*.test.ts
Maps WebAuthn exceptions to standardized errors, logs derived codes, and tests registration, authentication, null credentials, unknown errors, and logger configuration.
Collector and DaVinci request propagation
packages/davinci-client/src/lib/davinci.api.ts, packages/davinci-client/src/lib/davinci.utils.ts, packages/davinci-client/src/lib/node.reducer.ts, packages/davinci-client/src/lib/*.test.ts
Accepts FIDO errors in reducers and sends them through transformActionRequest instead of form submission.
End-to-end FIDO and flow validation
e2e/davinci-suites/src/fido.test.ts, e2e/davinci-app/components/fido.ts, e2e/davinci-app/server-configs.ts, e2e/davinci-suites/src/password-policy.test.ts, .changeset/*
Adds canceled-prompt scenarios, updates virtual-authenticator lifecycle handling, adjusts password-policy navigation, and records a minor release.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant FidoClient
  participant WebAuthn
  participant DaVinci
  Browser->>FidoClient: Start registration or authentication
  FidoClient->>WebAuthn: Request credential
  WebAuthn-->>FidoClient: Credential or DOMException
  FidoClient->>DaVinci: Submit formatted value or fido_error action
  DaVinci-->>Browser: Updated flow response
Loading

Possibly related PRs

Suggested reviewers: cerebrl

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: forwarding FIDO errors to DaVinci.
Description check ✅ Passed The description matches the template with a Jira ticket and a clear change summary, though it omits explicit changeset details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fido-errors-aj-2

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.

@nx-cloud

nx-cloud Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit da1c018

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

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-07-29 21:30:07 UTC

@pkg-pr-new

pkg-pr-new Bot commented Jul 29, 2026

Copy link
Copy Markdown

Open in StackBlitz

@forgerock/davinci-client

pnpm add https://pkg.pr.new/@forgerock/davinci-client@730

@forgerock/device-client

pnpm add https://pkg.pr.new/@forgerock/device-client@730

@forgerock/journey-client

pnpm add https://pkg.pr.new/@forgerock/journey-client@730

@forgerock/oidc-client

pnpm add https://pkg.pr.new/@forgerock/oidc-client@730

@forgerock/protect

pnpm add https://pkg.pr.new/@forgerock/protect@730

@forgerock/sdk-types

pnpm add https://pkg.pr.new/@forgerock/sdk-types@730

@forgerock/sdk-utilities

pnpm add https://pkg.pr.new/@forgerock/sdk-utilities@730

@forgerock/iframe-manager

pnpm add https://pkg.pr.new/@forgerock/iframe-manager@730

@forgerock/sdk-logger

pnpm add https://pkg.pr.new/@forgerock/sdk-logger@730

@forgerock/sdk-oidc

pnpm add https://pkg.pr.new/@forgerock/sdk-oidc@730

@forgerock/sdk-request-middleware

pnpm add https://pkg.pr.new/@forgerock/sdk-request-middleware@730

@forgerock/storage

pnpm add https://pkg.pr.new/@forgerock/storage@730

commit: da1c018

@codecov-commenter

codecov-commenter commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.02655% with 35 lines in your changes missing coverage. Please review.
✅ Project coverage is 23.73%. Comparing base (fc0caf2) to head (da1c018).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
packages/davinci-client/src/lib/davinci.api.ts 0.00% 19 Missing ⚠️
packages/davinci-client/src/lib/fido/fido.ts 72.72% 12 Missing ⚠️
packages/davinci-client/src/lib/davinci.utils.ts 25.00% 3 Missing ⚠️
packages/davinci-client/src/types.ts 0.00% 1 Missing ⚠️

❌ Your project status has failed because the head coverage (23.73%) 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     #730      +/-   ##
==========================================
+ Coverage   23.26%   23.73%   +0.46%     
==========================================
  Files         161      162       +1     
  Lines       25661    25714      +53     
  Branches     1626     1661      +35     
==========================================
+ Hits         5970     6103     +133     
+ Misses      19691    19611      -80     
Files with missing lines Coverage Δ
packages/davinci-client/src/lib/client.types.ts 100.00% <ø> (ø)
packages/davinci-client/src/lib/collector.types.ts 100.00% <ø> (ø)
packages/davinci-client/src/lib/davinci.types.ts 100.00% <ø> (ø)
packages/davinci-client/src/lib/fido/fido.types.ts 100.00% <100.00%> (ø)
packages/davinci-client/src/lib/fido/fido.utils.ts 99.24% <100.00%> (+0.28%) ⬆️
packages/davinci-client/src/lib/node.reducer.ts 74.60% <100.00%> (+0.40%) ⬆️
packages/davinci-client/src/types.ts 11.11% <0.00%> (-1.39%) ⬇️
packages/davinci-client/src/lib/davinci.utils.ts 85.48% <25.00%> (-0.93%) ⬇️
packages/davinci-client/src/lib/fido/fido.ts 85.32% <72.72%> (+84.45%) ⬆️
packages/davinci-client/src/lib/davinci.api.ts 27.85% <0.00%> (-1.69%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Deployed 6de8880 to https://ForgeRock.github.io/ping-javascript-sdk/pr-730/6de88803e5d841888adfb38e7bbcdebd7aa4000f branch gh-pages in ForgeRock/ping-javascript-sdk

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle Size Analysis

📦 Bundle Size Analysis

🚨 Significant Changes

🔺 @forgerock/davinci-client - 56.9 KB (+1.7 KB, +3.2%)

🆕 New Packages

🆕 @forgerock/journey-client - 92.6 KB (new)
🆕 @forgerock/journey-client - 0.0 KB (new)
🆕 @forgerock/device-client - 10.0 KB (new)
🆕 @forgerock/device-client - 0.0 KB (new)

➖ No Changes

@forgerock/sdk-types - 9.1 KB
@forgerock/sdk-logger - 1.6 KB
@forgerock/iframe-manager - 3.2 KB
@forgerock/sdk-oidc - 5.7 KB
@forgerock/storage - 1.5 KB
@forgerock/sdk-request-middleware - 4.6 KB
@forgerock/sdk-utilities - 18.6 KB
@forgerock/oidc-client - 35.3 KB
@forgerock/protect - 144.6 KB


14 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

@ancheetah
ancheetah marked this pull request as ready for review July 29, 2026 20:19
Base automatically changed from SDKS-5100-metadata-collector to main July 29, 2026 21:05

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/davinci-client/src/lib/davinci.api.ts (1)

172-198: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Prioritize pending FIDO errors over metadata collectors.

hasMetadataCollector is evaluated before fidoErrorCollector, so a node with both collectors sends state.node.client?.action instead of the FIDO error code, and transformActionRequest excludes FIDO collectors from formData. This can discard FIDO error information; move the FIDO error branch first.

Also add coverage for the FIDO-only error path and the combined MetadataCollector + FIDO error case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci-client/src/lib/davinci.api.ts` around lines 172 - 198,
Update the request-body selection in the no-body branch so the
fidoErrorCollector condition is evaluated before hasMetadataCollector, ensuring
pending FIDO errors use their error code even when both collectors exist; retain
transformSubmitRequest as the fallback. Add coverage for both FIDO-only errors
and the combined MetadataCollector plus FIDO error scenario.
🧹 Nitpick comments (3)
packages/davinci-client/src/lib/fido/fido.test.ts (2)

55-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the repeated navigator.credentials mock setup into a helper.

The Object.defineProperty(navigator, 'credentials', {...}) block is duplicated across ~12 test cases.

♻️ Suggested helper
function mockCredentials(methods: Partial<CredentialsContainer>) {
  Object.defineProperty(navigator, 'credentials', {
    value: methods,
    writable: true,
    configurable: true,
  });
}

Also applies to: 77-83, 96-104

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci-client/src/lib/fido/fido.test.ts` around lines 55 - 63,
Extract the duplicated navigator.credentials Object.defineProperty setup into a
shared mockCredentials helper in fido.test.ts, accepting the required partial
CredentialsContainer methods and preserving writable/configurable behavior.
Replace each repeated setup across the affected tests with this helper,
including the cases around the existing mockCreate definitions.

53-240: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the "no options provided" branches.

No test calls register()/authenticate() with falsy options, leaving the early-return branches in fido.ts (lines ~47-53 and ~104-110) untested — this lines up with the PR's own Codecov note of 12 missing-coverage lines in fido.ts.

✅ Suggested additional tests
it('should return GenericError when register is called without options', async () => {
  const fidoClient = fido(silentConfig);
  const result = await fidoClient.register(undefined as unknown as FidoRegistrationOptions);
  expect(isGenericError(result)).toBe(true);
});

it('should return GenericError when authenticate is called without options', async () => {
  const fidoClient = fido(silentConfig);
  const result = await fidoClient.authenticate(undefined as unknown as FidoAuthenticationOptions);
  expect(isGenericError(result)).toBe(true);
});

Also applies to: 242-429

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci-client/src/lib/fido/fido.test.ts` around lines 53 - 240, Add
tests covering the falsy-options early-return branches in the fido client: call
register and authenticate with undefined options, then assert each result is a
GenericError. Place these cases alongside the existing register and authenticate
tests, using the existing fidoClient setup and type casts as needed.
packages/davinci-client/src/lib/davinci.utils.test.ts (1)

215-253: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the new FIDO exclusion branch in transformActionRequest.

This suite still only exercises transformActionRequest with an empty collectors array, so the new filter that excludes FidoRegistrationCollector/FidoAuthenticationCollector from formData (davinci.utils.ts lines 99-103) is untested — this lines up with the coverage gap Codecov flagged for davinci.utils.ts.

it('should exclude FIDO collectors from formData', () => {
  const node: ContinueNode = {
    /* ... */
    client: {
      action: 'SIGNON',
      collectors: [
        {
          category: 'ObjectValueAutoCollector',
          type: 'FidoRegistrationCollector',
          input: { key: 'fido2-registration', value: {} },
          // ...
        },
      ],
      status: 'continue',
    },
    // ...
  };
  const result = transformActionRequest(node, 'TEST_ACTION', logger({ level: 'none' }));
  expect(result.parameters.data.formData).toEqual({});
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci-client/src/lib/davinci.utils.test.ts` around lines 215 -
253, Add a test case alongside the existing transformActionRequest coverage that
supplies FidoRegistrationCollector and FidoAuthenticationCollector entries in
node.client.collectors, then verifies transformActionRequest returns an empty
parameters.data.formData. Reuse the existing ContinueNode setup and logger, and
cover both FIDO collector types so the exclusion branch is fully exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/thirty-badgers-lick.md:
- Line 5: Correct the typo in the changeset description by replacing
“DOMExeceptions” with “DOMExceptions”; leave the rest of the text unchanged.

In `@e2e/davinci-suites/src/password-policy.test.ts`:
- Line 75: Update the cleanup failure throw in the test-user deletion flow to
preserve native Error details instead of relying on JSON.stringify(err). Use the
error’s message and/or stack, with a safe fallback for non-Error values, while
retaining the email context and [cleanup] prefix.

In `@packages/davinci-client/src/lib/node.reducer.test.ts`:
- Around line 1270-1348: Rename the FIDO error test title at
packages/davinci-client/src/lib/node.reducer.test.ts:1270-1348 to state that the
GenericError is stored in collector.input.value, not collector.error. Apply the
same title correction to the authentication test at
packages/davinci-client/src/lib/node.reducer.test.ts:2178-2249; no assertion or
reducer changes are needed.

---

Outside diff comments:
In `@packages/davinci-client/src/lib/davinci.api.ts`:
- Around line 172-198: Update the request-body selection in the no-body branch
so the fidoErrorCollector condition is evaluated before hasMetadataCollector,
ensuring pending FIDO errors use their error code even when both collectors
exist; retain transformSubmitRequest as the fallback. Add coverage for both
FIDO-only errors and the combined MetadataCollector plus FIDO error scenario.

---

Nitpick comments:
In `@packages/davinci-client/src/lib/davinci.utils.test.ts`:
- Around line 215-253: Add a test case alongside the existing
transformActionRequest coverage that supplies FidoRegistrationCollector and
FidoAuthenticationCollector entries in node.client.collectors, then verifies
transformActionRequest returns an empty parameters.data.formData. Reuse the
existing ContinueNode setup and logger, and cover both FIDO collector types so
the exclusion branch is fully exercised.

In `@packages/davinci-client/src/lib/fido/fido.test.ts`:
- Around line 55-63: Extract the duplicated navigator.credentials
Object.defineProperty setup into a shared mockCredentials helper in
fido.test.ts, accepting the required partial CredentialsContainer methods and
preserving writable/configurable behavior. Replace each repeated setup across
the affected tests with this helper, including the cases around the existing
mockCreate definitions.
- Around line 53-240: Add tests covering the falsy-options early-return branches
in the fido client: call register and authenticate with undefined options, then
assert each result is a GenericError. Place these cases alongside the existing
register and authenticate tests, using the existing fidoClient setup and type
casts as needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d515f1aa-e45e-4e0a-b2df-73a168ce8cf2

📥 Commits

Reviewing files that changed from the base of the PR and between f705d4d and da1c018.

📒 Files selected for processing (21)
  • .changeset/thirty-badgers-lick.md
  • e2e/davinci-app/components/fido.ts
  • e2e/davinci-app/server-configs.ts
  • e2e/davinci-suites/src/fido.test.ts
  • e2e/davinci-suites/src/password-policy.test.ts
  • packages/davinci-client/api-report/davinci-client.api.md
  • packages/davinci-client/api-report/davinci-client.types.api.md
  • packages/davinci-client/src/lib/client.types.ts
  • packages/davinci-client/src/lib/collector.types.ts
  • packages/davinci-client/src/lib/davinci.api.ts
  • packages/davinci-client/src/lib/davinci.types.ts
  • packages/davinci-client/src/lib/davinci.utils.test.ts
  • packages/davinci-client/src/lib/davinci.utils.ts
  • packages/davinci-client/src/lib/fido/fido.test.ts
  • packages/davinci-client/src/lib/fido/fido.ts
  • packages/davinci-client/src/lib/fido/fido.types.test.ts
  • packages/davinci-client/src/lib/fido/fido.types.ts
  • packages/davinci-client/src/lib/fido/fido.utils.ts
  • packages/davinci-client/src/lib/node.reducer.test.ts
  • packages/davinci-client/src/lib/node.reducer.ts
  • packages/davinci-client/src/types.ts

'@forgerock/davinci-client': minor
---

Catch FIDO/WebAuthn DOMExeceptions and send them to DaVinci

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Typo: "DOMExeceptions" → "DOMExceptions".

✏️ Proposed fix
-Catch FIDO/WebAuthn DOMExeceptions and send them to DaVinci
+Catch FIDO/WebAuthn DOMExceptions and send them to DaVinci
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Catch FIDO/WebAuthn DOMExeceptions and send them to DaVinci
Catch FIDO/WebAuthn DOMExceptions and send them to DaVinci
🧰 Tools
🪛 LanguageTool

[grammar] ~5-~5: Ensure spelling is correct
Context: ...client': minor --- Catch FIDO/WebAuthn DOMExeceptions and send them to DaVinci

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/thirty-badgers-lick.md at line 5, Correct the typo in the
changeset description by replacing “DOMExeceptions” with “DOMExceptions”; leave
the rest of the text unchanged.

Source: Linters/SAST tools

await deleteTestUser(page, email);
} catch (err) {
console.error(`[cleanup] Failed to delete test user ${email}:`, err);
throw new Error(`[cleanup] Failed to delete test user ${email}: ${JSON.stringify(err)}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

JSON.stringify(err) loses the error detail for native Error objects.

Error instances don't enumerate message/stack, so JSON.stringify(err) typically serializes to {}, defeating the purpose of surfacing cleanup-failure details in the thrown error.

🐛 Proposed fix
-        throw new Error(`[cleanup] Failed to delete test user ${email}: ${JSON.stringify(err)}`);
+        throw new Error(
+          `[cleanup] Failed to delete test user ${email}: ${err instanceof Error ? err.message : String(err)}`,
+        );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
throw new Error(`[cleanup] Failed to delete test user ${email}: ${JSON.stringify(err)}`);
throw new Error(
`[cleanup] Failed to delete test user ${email}: ${err instanceof Error ? err.message : String(err)}`,
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/davinci-suites/src/password-policy.test.ts` at line 75, Update the
cleanup failure throw in the test-user deletion flow to preserve native Error
details instead of relying on JSON.stringify(err). Use the error’s message
and/or stack, with a safe fallback for non-Error values, while retaining the
email context and [cleanup] prefix.

Comment on lines +1270 to +1348
it('should store a GenericError on collector.error when a FIDO error is passed as value', () => {
const fidoError: GenericError = {
code: 'NotAllowedError',
error: 'registration_error',
message: 'FIDO registration failed: NotAllowedError',
type: 'fido_error',
};
const publicKeyCredentialCreationOptions: FidoRegistrationOptions = {
rp: { name: 'Example RP', id: 'example.com' },
user: { id: [1], displayName: 'Test User', name: 'testuser' },
challenge: [1, 2, 3, 4],
pubKeyCredParams: [{ type: 'public-key', alg: -7 }],
timeout: 60000,
authenticatorSelection: {
residentKey: 'required',
requireResidentKey: true,
userVerification: 'required',
},
attestation: 'none',
extensions: { credProps: true, hmacCreateSecret: true },
};
const action = {
type: 'node/update',
payload: {
id: 'fido2-registration-0',
value: fidoError,
},
};
const state: FidoRegistrationCollector[] = [
{
category: 'ObjectValueAutoCollector',
error: null,
type: 'FidoRegistrationCollector',
id: 'fido2-registration-0',
name: 'fido2-registration',
input: {
key: 'fido2-registration',
value: {},
type: 'FIDO2',
validation: null,
},
output: {
key: 'fido2-registration',
type: 'FIDO2',
config: {
publicKeyCredentialCreationOptions,
action: 'REGISTER',
trigger: 'BUTTON',
},
},
},
];

expect(nodeCollectorReducer(state, action)).toStrictEqual([
{
category: 'ObjectValueAutoCollector',
error: null,
type: 'FidoRegistrationCollector',
id: 'fido2-registration-0',
name: 'fido2-registration',
input: {
key: 'fido2-registration',
value: fidoError,
type: 'FIDO2',
validation: null,
},
output: {
key: 'fido2-registration',
type: 'FIDO2',
config: {
publicKeyCredentialCreationOptions,
action: 'REGISTER',
trigger: 'BUTTON',
},
},
},
]);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Both new FIDO-error test titles say "collector.error" but assert on input.value. In each test, error: null is unchanged before/after; the GenericError is actually stored in collector.input.value (per node.reducer.ts), not the top-level collector.error field. Rename both titles to reflect the actual behavior.

  • packages/davinci-client/src/lib/node.reducer.test.ts#L1270-L1348: rename 'should store a GenericError on collector.error when a FIDO error is passed as value' (registration) to describe storing on input.value instead.
  • packages/davinci-client/src/lib/node.reducer.test.ts#L2178-L2249: rename the identical title (authentication) the same way.
📍 Affects 1 file
  • packages/davinci-client/src/lib/node.reducer.test.ts#L1270-L1348 (this comment)
  • packages/davinci-client/src/lib/node.reducer.test.ts#L2178-L2249
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci-client/src/lib/node.reducer.test.ts` around lines 1270 -
1348, Rename the FIDO error test title at
packages/davinci-client/src/lib/node.reducer.test.ts:1270-1348 to state that the
GenericError is stored in collector.input.value, not collector.error. Apply the
same title correction to the authentication test at
packages/davinci-client/src/lib/node.reducer.test.ts:2178-2249; no assertion or
reducer changes are needed.

*/
export function fido(): FidoClient {
export function fido(config?: FidoClientConfig): FidoClient {
const log = loggerFn({ level: config?.logger?.level ?? 'error', custom: config?.logger?.custom });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why create a new logger instance here? Shouldn't we use the existing logger instance from the original config generation?

'ObjectValueAutoCollector',
'FidoRegistrationCollector',
FidoRegistrationInputValue,
FidoRegistrationInputValue | GenericError,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm guessing the above stems from this?

};
}

export interface FidoClient {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Wondering about the naming of FidoClient. This kind of goes against our original naming of a client / server model with naming things client.

Is this a Client or just Fido?

data: {
actionKey: action || node.client?.action || '',
...(Object.keys(formData ?? {}).length && { formData: formData }),
formData: formData ?? {},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This feels like it's breaking other functionality? we're changing formData to not be in an object?

@vatsalparikh vatsalparikh Jul 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the earlier case excluded formData key from the object if formData was empty, now we are sending {} if formData does not exist. I believe it is to cover for the Fido case where formData is empty always.

And we already send {} for formData for submit and we now are doing the same for action: https://github.com/ForgeRock/ping-javascript-sdk/blob/main/packages/davinci-client/src/lib/davinci.utils.ts#L74

@cerebrl cerebrl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think this looks good. I just have a comment on the GenericError bit, but it's not worth blocking the PR over it.

? PhoneNumberExtensionInputValue
: T extends { type: 'FidoRegistrationCollector' }
? FidoRegistrationInputValue
? FidoRegistrationInputValue | GenericError

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Would it be possible to have FidoRegistrationInputValue be inclusive of GenericError? In other words:

type FidoRegistrationInputValue = FidoRegistrationInputSuccessValue | GenericError;

That way, we don't have to pass around GenericError everywhere. If not, no big deal, but I figured it's worth asking.

'ObjectValueAutoCollector',
'FidoRegistrationCollector',
FidoRegistrationInputValue,
FidoRegistrationInputValue | GenericError,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yeah, these GenericErrors are sticking out like sore thumbs :)

@vatsalparikh vatsalparikh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code looks good!

Comment on lines 329 to +349
@@ -333,10 +341,12 @@ export const nodeCollectorReducer = createReducer(initialCollectorValues, (build
if (typeof action.payload.value !== 'object') {
throw new Error('Value argument must be an object');
}
if (!('assertionValue' in action.payload.value)) {
const isFidoError =
'type' in action.payload.value && action.payload.value.type === 'fido_error';
if (!isFidoError && !('assertionValue' in action.payload.value)) {
throw new Error('Value argument must contain an assertionValue property');
}
collector.input.value = action.payload.value;
collector.input.value = action.payload.value as FidoAuthenticationInputValue | GenericError;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We can simplify the code here like below

      if (
        collector.type === 'FidoRegistrationCollector' ||
        collector.type === 'FidoAuthenticationCollector'
      ) {
        if (typeof action.payload.id !== 'string') {
          throw new Error('Index argument must be a string');
        }
        if (typeof action.payload.value !== 'object') {
          throw new Error('Value argument must be an object');
        }
        const requiredProp =
          collector.type === 'FidoRegistrationCollector' ? 'attestationValue' : 'assertionValue';
        const isFidoError =
          'type' in action.payload.value && action.payload.value.type === 'fido_error';
        if (!isFidoError && !(requiredProp in action.payload.value)) {
          throw new Error(`Value argument must contain an ${requiredProp} property`);
        }
        collector.input.value = action.payload.value as
          | FidoRegistrationInputValue
          | FidoAuthenticationInputValue
          | GenericError;

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.

5 participants