Skip to content

Resolve runtime product name in passkey flow templates#2997

Open
RushanNanayakkara wants to merge 1 commit into
thunder-id:mainfrom
RushanNanayakkara:claude/passkey-rp-name-runtime-config
Open

Resolve runtime product name in passkey flow templates#2997
RushanNanayakkara wants to merge 1 commit into
thunder-id:mainfrom
RushanNanayakkara:claude/passkey-rp-name-runtime-config

Conversation

@RushanNanayakkara
Copy link
Copy Markdown
Contributor

@RushanNanayakkara RushanNanayakkara commented May 26, 2026

Summary

Fixes #2995.

Resolves the only end-user-visible surface that the existing configuration.brand.productName mechanism could not previously reach: the WebAuthn passkey relying-party name shipped in the flow-builder seed JSON.

What changed

  • Replaced the literal "ThunderID" with the "{{productName}}" placeholder in 12 lines across 4 seed JSON files (flows/data/templates.json, login-flow/data/{templates,executors,widgets}.json).
  • useGetFlowBuilderCoreResources and useGetLoginFlowBuilderResources now resolve the placeholder at load time using the existing updateTemplatePlaceholderReferences util and config.brand.product_name from useConfig().
  • Updated existing tests to mock useConfig, and added a substitution assertion in useGetFlowBuilderCoreResources.test.ts.

No new util, no new placeholder syntax — reuses the {{key}} mechanism already present for ID generation and i18n. Hook return shapes are unchanged.

Note: this replaces #2996, which got disconnected when its fork branch was renamed. Same diff, single squashed commit.

Test plan

  • pnpm test useGetFlowBuilderCoreResources useGetLoginFlowBuilderResources — 38/38 passing
  • Full pnpm test and pnpm lint in frontend/apps/console — covered by CI
  • Manual: with configuration.brand.productName overridden in Helm values, instantiate a passkey-based template and verify the relying-party-name field defaults to the configured product name in the Passkey properties panel.
  • Manual: register a passkey using the resulting flow and confirm the OS-rendered passkey dialog reads the configured product name (not the literal "ThunderID").

Summary by CodeRabbit

  • New Features

    • Flow and login builders now substitute the configured product name into shipped templates, executors, steps and widgets, replacing hardcoded relying-party names for passkey flows.
  • Tests

    • Test suites now mock configuration, relax exact-fixture assertions to presence/length checks, and add assertions verifying product-name placeholders are resolved at runtime.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0ebb9e4e-24d5-4a8d-a3a4-8efe6063beb6

📥 Commits

Reviewing files that changed from the base of the PR and between 81010c4 and c54bf81.

📒 Files selected for processing (10)
  • frontend/apps/console/src/features/flows/api/__tests__/useGetFlowBuilderCoreResources.test.ts
  • frontend/apps/console/src/features/flows/api/__tests__/useGetFlowsMeta.test.ts
  • frontend/apps/console/src/features/flows/api/useGetFlowBuilderCoreResources.ts
  • frontend/apps/console/src/features/flows/api/useGetFlowsMeta.ts
  • frontend/apps/console/src/features/flows/data/templates.json
  • frontend/apps/console/src/features/login-flow/api/__tests__/useGetLoginFlowBuilderResources.test.ts
  • frontend/apps/console/src/features/login-flow/api/useGetLoginFlowBuilderResources.ts
  • frontend/apps/console/src/features/login-flow/data/executors.json
  • frontend/apps/console/src/features/login-flow/data/templates.json
  • frontend/apps/console/src/features/login-flow/data/widgets.json
✅ Files skipped from review due to trivial changes (1)
  • frontend/apps/console/src/features/login-flow/data/executors.json
🚧 Files skipped from review as they are similar to previous changes (9)
  • frontend/apps/console/src/features/login-flow/data/widgets.json
  • frontend/apps/console/src/features/login-flow/api/useGetLoginFlowBuilderResources.ts
  • frontend/apps/console/src/features/flows/api/tests/useGetFlowBuilderCoreResources.test.ts
  • frontend/apps/console/src/features/login-flow/api/tests/useGetLoginFlowBuilderResources.test.ts
  • frontend/apps/console/src/features/flows/api/tests/useGetFlowsMeta.test.ts
  • frontend/apps/console/src/features/flows/api/useGetFlowBuilderCoreResources.ts
  • frontend/apps/console/src/features/flows/api/useGetFlowsMeta.ts
  • frontend/apps/console/src/features/flows/data/templates.json
  • frontend/apps/console/src/features/login-flow/data/templates.json

📝 Walkthrough

Walkthrough

Static passkey templates now use a {{productName}} placeholder. Flow-builder, flows-meta, and login-flow hooks read config.brand.product_name via useConfig and resolve those placeholders at load time; tests mock useConfig to validate substitution and resource structure.

Changes

Passkey Relying-Party Brand Resolution

Layer / File(s) Summary
Flow builder core resources with brand placeholder resolution
frontend/apps/console/src/features/flows/api/useGetFlowBuilderCoreResources.ts, frontend/apps/console/src/features/flows/api/__tests__/useGetFlowBuilderCoreResources.test.ts, frontend/apps/console/src/features/flows/api/__tests__/useGetFlowsMeta.test.ts, frontend/apps/console/src/features/flows/api/useGetFlowsMeta.ts, frontend/apps/console/src/features/flows/data/templates.json
The flow-builder and flows-meta hooks read config.brand.product_name, run updateTemplatePlaceholderReferences to resolve {{productName}} in bundled flow resource JSON inside a useMemo dependent on the product name. Tests mock useConfig, assert placeholder substitution, and validate non-empty templates/widgets. Passkey templates in templates.json updated to use {{productName}}.
Login flow builder resources with brand placeholder resolution
frontend/apps/console/src/features/login-flow/api/useGetLoginFlowBuilderResources.ts, frontend/apps/console/src/features/login-flow/api/__tests__/useGetLoginFlowBuilderResources.test.ts, frontend/apps/console/src/features/login-flow/data/templates.json, frontend/apps/console/src/features/login-flow/data/executors.json, frontend/apps/console/src/features/login-flow/data/widgets.json
The login-flow hook derives productName from useConfig, runs updateTemplatePlaceholderReferences across templates/executors/widgets, merges resolved local resources onto coreResources with empty-array fallbacks inside a useMemo, and returns the memoized data. Tests mock useConfig and assert placeholder replacement. Passkey executors/templates/widgets updated to use {{productName}}.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • DonOmalVindula
  • jeradrutnam
  • brionmario
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: resolving the runtime product name in passkey flow templates instead of using a hardcoded value.
Description check ✅ Passed The description is comprehensive, including a clear summary, what changed, the approach, test plan, and rationale. It references the linked issue #2995 and explains the reuse of existing mechanisms.
Linked Issues check ✅ Passed The PR fully addresses issue #2995 by replacing hardcoded 'ThunderID' with '{{productName}}' placeholders in all 12 required locations across 4 seed JSON files and implementing placeholder resolution at load time via useConfig().
Out of Scope Changes check ✅ Passed All changes are directly scoped to resolving the linked issue: updating seed JSON files with placeholders and implementing placeholder substitution in the three resource-loading hooks. No unrelated changes detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

frontend/apps/console/src/features/flows/api/__tests__/useGetFlowBuilderCoreResources.test.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

frontend/apps/console/src/features/flows/api/__tests__/useGetFlowsMeta.test.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

frontend/apps/console/src/features/flows/api/useGetFlowBuilderCoreResources.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

  • 3 others

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.

Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (2)
frontend/apps/console/src/features/login-flow/api/__tests__/useGetLoginFlowBuilderResources.test.ts (1)

23-38: ⚡ Quick win

Add a login-flow placeholder substitution assertion.

You now mock product_name, but this suite still doesn’t assert that login-flow resources replace {{productName}}. Add one focused assertion so this path can’t regress silently.

Suggested direction
+  it('should resolve {{productName}} placeholders in login-flow resources', () => {
+    const {result} = renderHook(() => useGetLoginFlowBuilderResources());
+    const serialized = JSON.stringify(result.current.data);
+
+    expect(serialized).not.toContain('{{productName}}');
+    expect(serialized).toContain('TestProduct');
+  });

As per coding guidelines, **/*.{ts,tsx}: "Follow React/TypeScript frontend development guidelines including component patterns, testing, and linting as documented in docs/content/community/contributing/contributing-code/frontend-development/overview.mdx".

🤖 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
`@frontend/apps/console/src/features/login-flow/api/__tests__/useGetLoginFlowBuilderResources.test.ts`
around lines 23 - 38, The test mocks useConfig to set product_name to
'TestProduct' but doesn't assert that login-flow resources substitute the
{{productName}} placeholder; update the test in
useGetLoginFlowBuilderResources.test.ts to call the hook/function under test
(useGetLoginFlowBuilderResources) and add an assertion that at least one
returned resource string (e.g., labels, titles, or messages from the hook's
result) contains 'TestProduct' instead of '{{productName}}', ensuring the
placeholder replacement logic is exercised; reference the mocked useConfig
(product_name) and the placeholder '{{productName}}' in your assertion.
frontend/apps/console/src/features/flows/api/__tests__/useGetFlowBuilderCoreResources.test.ts (1)

105-110: ⚡ Quick win

Strengthen the widgets assertion to prevent false positives.

This now only checks array type; an empty widgets payload would still pass. Add a non-empty assertion here like templates.

Suggested patch
     it('should return data containing widgets resolved from JSON file', () => {
       const {result} = renderHook(() => useGetFlowBuilderCoreResources());

       const {data} = result.current;
       expect(Array.isArray(data.widgets)).toBe(true);
+      expect(data.widgets.length).toBeGreaterThan(0);
     });

As per coding guidelines, **/*.{ts,tsx}: "Follow React/TypeScript frontend development guidelines including component patterns, testing, and linting as documented in docs/content/community/contributing/contributing-code/frontend-development/overview.mdx".

🤖 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
`@frontend/apps/console/src/features/flows/api/__tests__/useGetFlowBuilderCoreResources.test.ts`
around lines 105 - 110, The test for useGetFlowBuilderCoreResources currently
only asserts that data.widgets is an array, which allows an empty array to pass;
update the test in the 'should return data containing widgets resolved from JSON
file' spec to assert the array is non-empty (for example, check
data.widgets.length > 0 or expect(data.widgets).not.toHaveLength(0)) and
optionally validate one expected property on the first widget (e.g., presence of
id or type) to ensure actual payload content; target the test in
useGetFlowBuilderCoreResources.test.ts and modify the assertion after obtaining
result.current.data to enforce non-empty widgets and a basic shape check.
🤖 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.

Nitpick comments:
In
`@frontend/apps/console/src/features/flows/api/__tests__/useGetFlowBuilderCoreResources.test.ts`:
- Around line 105-110: The test for useGetFlowBuilderCoreResources currently
only asserts that data.widgets is an array, which allows an empty array to pass;
update the test in the 'should return data containing widgets resolved from JSON
file' spec to assert the array is non-empty (for example, check
data.widgets.length > 0 or expect(data.widgets).not.toHaveLength(0)) and
optionally validate one expected property on the first widget (e.g., presence of
id or type) to ensure actual payload content; target the test in
useGetFlowBuilderCoreResources.test.ts and modify the assertion after obtaining
result.current.data to enforce non-empty widgets and a basic shape check.

In
`@frontend/apps/console/src/features/login-flow/api/__tests__/useGetLoginFlowBuilderResources.test.ts`:
- Around line 23-38: The test mocks useConfig to set product_name to
'TestProduct' but doesn't assert that login-flow resources substitute the
{{productName}} placeholder; update the test in
useGetLoginFlowBuilderResources.test.ts to call the hook/function under test
(useGetLoginFlowBuilderResources) and add an assertion that at least one
returned resource string (e.g., labels, titles, or messages from the hook's
result) contains 'TestProduct' instead of '{{productName}}', ensuring the
placeholder replacement logic is exercised; reference the mocked useConfig
(product_name) and the placeholder '{{productName}}' in your assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a1476248-9236-4fe5-9bf9-e76306a992b4

📥 Commits

Reviewing files that changed from the base of the PR and between 5b2b00d and e93f3ba.

📒 Files selected for processing (8)
  • frontend/apps/console/src/features/flows/api/__tests__/useGetFlowBuilderCoreResources.test.ts
  • frontend/apps/console/src/features/flows/api/useGetFlowBuilderCoreResources.ts
  • frontend/apps/console/src/features/flows/data/templates.json
  • frontend/apps/console/src/features/login-flow/api/__tests__/useGetLoginFlowBuilderResources.test.ts
  • frontend/apps/console/src/features/login-flow/api/useGetLoginFlowBuilderResources.ts
  • frontend/apps/console/src/features/login-flow/data/executors.json
  • frontend/apps/console/src/features/login-flow/data/templates.json
  • frontend/apps/console/src/features/login-flow/data/widgets.json

@RushanNanayakkara RushanNanayakkara force-pushed the claude/passkey-rp-name-runtime-config branch from e93f3ba to fff0fb1 Compare May 26, 2026 01:15
@RushanNanayakkara
Copy link
Copy Markdown
Contributor Author

Thanks for the review @coderabbitai.

  • login-flow placeholder substitution test — added in useGetLoginFlowBuilderResources.test.ts. Extended the mocked templates payload with relyingPartyName: '{{productName}}' and asserted the serialised hook output contains 'TestProduct' and no remaining {{productName}} literal.
  • widgets length assertion in flows test — declined: frontend/apps/console/src/features/flows/data/widgets.json is currently an empty array ([]), so a length > 0 assertion would fail. Kept the array-shape check as the only safe invariant; the placeholder-substitution assertion already guards against regressions in the populated resource arrays.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

Tip

For best results, initiate chat on the files or code changes.

@RushanNanayakkara: Thanks for the update!

  • login-flow placeholder substitution test — great addition. Asserting that 'TestProduct' is present and no {{productName}} literal remains is exactly the right coverage.
  • widgets length assertion — the reasoning is completely valid. An empty array is a legitimate fixture state, and asserting length > 0 against it would produce a permanently failing test. The combination of the array-shape check and the placeholder-substitution assertion on the populated arrays provides solid regression protection.

Both points are well handled. 🐇

@codecov
Copy link
Copy Markdown

codecov Bot commented May 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@RushanNanayakkara RushanNanayakkara force-pushed the claude/passkey-rp-name-runtime-config branch from fff0fb1 to 81010c4 Compare May 26, 2026 01:40
@RushanNanayakkara
Copy link
Copy Markdown
Contributor Author

Self-spotted a regression while doing end-to-end browser verification: a third consumer of templates.json exists — useGetFlowsMeta (used by the flow-creation wizard, features/flows/api/useGetFlowsMeta.ts). Without applying the same substitution there, the wizard pipes the raw {{productName}} literal straight into the persisted flow JSON, e.g. "relyingPartyName": "{{productName}}", which would then surface to end users in the WebAuthn dialog.

Pushed the fix (81010c46d) — applied the same updateTemplatePlaceholderReferences pass in useGetFlowsMeta, updated the existing test to mock useConfig and added a substitution assertion (54/54 tests passing locally).

Confirmed end-to-end by creating a passkey-template flow against a deployment with product_name: 'TestProduct'-style override: the persisted flow now contains "relyingPartyName": "<configured product name>" instead of the literal placeholder.

Replaces the hardcoded "ThunderID" relyingPartyName string in flow
builder seed JSON with a {{productName}} placeholder, and resolves it
at hook-load time from config.brand.product_name. This is the only
end-user-visible surface that the existing brand configuration
mechanism could not previously reach -- the WebAuthn browser dialog
now reads the deployment's configured product name instead of the
literal "ThunderID".

Reuses the existing updateTemplatePlaceholderReferences util so no
new placeholder syntax or substitution machinery is introduced. The
hooks' return shapes are unchanged, and the admin-facing Passkey
properties panel continues to surface the resolved value as the
default (admins can still override it).
@RushanNanayakkara RushanNanayakkara force-pushed the claude/passkey-rp-name-runtime-config branch from 81010c4 to c54bf81 Compare May 27, 2026 09:38
* every consumer sees the correct value without further work.
*
* This function calls the GET method of the following endpoint to get the resources.
* - TODO: Fill this
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

shall we remove the todo comments?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since this is not part of the PR, better not to remove it without checking with the pending tasks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Passkey relying-party name should resolve from the configured brand productName

2 participants