Skip to content

Conversation

jzsfkzm
Copy link
Contributor

@jzsfkzm jzsfkzm commented Sep 30, 2025

refs #1946

Summary by CodeRabbit

  • New Features

    • Adds a token-based authentication flow as an alternative to certificates (behind a feature flag).
    • Introduces a Create/Regenerate Token button with loading feedback and warnings for missing or expired tokens.
  • Chores

    • Adds a feature flag to control the token-based flow rollout.
    • Extends analytics to track token creation events.
  • Tests

    • Adds comprehensive tests covering token lifecycle, expiration handling, and button behavior, alongside existing certificate tests.

Copy link

coderabbitai bot commented Sep 30, 2025

Walkthrough

Adds JWT-based token flow gated by a feature flag to CreateCertificateButton, introduces a new useJwt hook with tests, updates analytics events and feature flags, exports SettingsProvider context type, and extends wallet types to store tokens. Tests updated/added to cover token lifecycle, UI states, and expiration handling.

Changes

Cohort / File(s) Summary
CreateCertificateButton JWT integration
apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx, apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
Component now gates between certificate and JWT token flows via useFlag("jwt_instead_of_cert"); integrates useJwt for token creation/state, adjusts button/warning text and spinners. Tests extended to cover token UI, creation, and expiration warnings with mocked useJwt/useFlag.
New JWT hook + tests
apps/deploy-web/src/hooks/useJwt.ts, apps/deploy-web/src/hooks/useJwt.spec.tsx
Adds useJwt hook managing local token load/store, decode, expiration, creation, and analytics tracking. Exposes localToken, isLocalTokenExpired, isCreatingToken, createToken, setLocalToken. Comprehensive tests for lifecycle, errors, and multi-wallet selection.
Settings context type export
apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx
Changes ContextType to exported type; structure unchanged.
Analytics event update
apps/deploy-web/src/services/analytics/analytics.service.ts
Extends AnalyticsEvent union with "create_jwt".
Feature flag addition
apps/deploy-web/src/types/feature-flags.ts
Adds "jwt_instead_of_cert" to FeatureFlag union.
Wallet token storage
apps/deploy-web/src/utils/walletUtils.ts
Adds optional token?: string to BaseLocalWallet, propagating to LocalWallet types.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as CreateCertificateButton
  participant Flag as useFlag("jwt_instead_of_cert")
  participant JWT as useJwt
  participant Cert as useCertificate
  participant Wallet as Storage/Wallet
  participant JwtSvc as JwtToken Service
  participant Analytics

  User->>UI: Click button
  UI->>Flag: Check flag
  alt JWT enabled
    UI->>JWT: createToken()
    JWT->>Wallet: Load active wallet
    JWT->>JwtSvc: Build + sign JWT
    JwtSvc-->>JWT: token
    JWT->>Wallet: Persist token
    JWT->>Analytics: track("create_jwt")
    JWT-->>UI: isCreatingToken=false, localToken updated
    UI-->>User: Token created/regenerated
  else Certificate flow
    UI->>Cert: createCertificate()
    Cert-->>UI: isCreatingCert=false, localCert updated
    UI-->>User: Certificate created/regenerated
  end

  note over UI,JWT: Warning text reflects expired/missing token or cert
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • stalniy
  • ygrishajev

Poem

I hop between certs and tokens, neat,
A flag flips paths beneath my feet.
New hooks bloom where wallets dwell,
JWTs signed—hush, don’t tell!
Analytics squeak: create_jwt!
I twitch my nose—reviews all set. 🐇✨

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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly captures the primary user-facing feature introduced by this pull request—the ability to manually create a token—without extraneous details or vague phrasing, and aligns directly with the core changes in both the UI and related hooks.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@jzsfkzm jzsfkzm force-pushed the features/1946-jwt-button branch from d85121b to 3706ff7 Compare September 30, 2025 15:15
dependencies?: typeof DEPENDENCIES;
};

export const JwtProvider: React.FC<Props> = ({ children, dependencies: d = DEPENDENCIES }) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

thought: I assume it's possible to solve this without adding one more Provider component. We can just write a hook which stores the state in jotai store and updates atoms

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thought: I assume it's possible to solve this without adding one more Provider component. We can just write a hook which stores the state in jotai store and updates atoms

Moved it to a hook. Logic now is it's checking a flag whether to render a cert button or a token button, not sure if that's ok or if it should work some other way. Let me know if you see anything please.

@jzsfkzm jzsfkzm force-pushed the features/1946-jwt-button branch 7 times, most recently from 7b23193 to 134abb2 Compare October 2, 2025 00:55
@jzsfkzm jzsfkzm marked this pull request as ready for review October 2, 2025 08:12
@jzsfkzm jzsfkzm requested a review from a team as a code owner October 2, 2025 08:12
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: 2

🧹 Nitpick comments (1)
apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx (1)

42-59: Consider explicit branching for JWT vs certificate logic.

The current implementation allows both JWT and certificate conditions to be evaluated even when isJwtEnabled is true. While the early returns prevent both warnings from showing, explicit if-else branching would make the mutual exclusivity clearer.

 const warningText = useMemo(() => {
   if (isJwtEnabled) {
     if (isLocalTokenExpired) return "Your token has expired. Please create a new one.";
     if (!localToken) return "You need to create a token to view deployment details.";
+    return undefined;
-  }
-
+  } else {
     if (isLocalCertExpired) return "Your certificate has expired. Please create a new one.";
     if (!localCert) return "You need to create a certificate to view deployment details.";
-
     return undefined;
+  }
 }, [isJwtEnabled, isLocalCertExpired, isLocalTokenExpired, localCert, localToken]);

Apply similar pattern to buttonText:

 const buttonText = useMemo(() => {
   if (isJwtEnabled) {
     return isLocalTokenExpired ? "Regenerate Token" : "Create Token";
+  } else {
+    return isLocalCertExpired ? "Regenerate Certificate" : "Create Certificate";
   }
-
-  return isLocalCertExpired ? "Regenerate Certificate" : "Create Certificate";
 }, [isJwtEnabled, isLocalCertExpired, isLocalTokenExpired]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5ac1d5 and 134abb2.

📒 Files selected for processing (9)
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (5 hunks)
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx (2 hunks)
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1 hunks)
  • apps/deploy-web/src/hooks/useJwt.spec.tsx (1 hunks)
  • apps/deploy-web/src/hooks/useJwt.ts (1 hunks)
  • apps/deploy-web/src/services/analytics/analytics.service.ts (1 hunks)
  • apps/deploy-web/src/types/feature-flags.ts (1 hunks)
  • apps/deploy-web/src/utils/TransactionMessageData.ts (2 hunks)
  • apps/deploy-web/src/utils/walletUtils.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/utils/TransactionMessageData.ts
  • apps/deploy-web/src/utils/walletUtils.ts
  • apps/deploy-web/src/types/feature-flags.ts
  • apps/deploy-web/src/hooks/useJwt.ts
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx
  • apps/deploy-web/src/hooks/useJwt.spec.tsx
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx
  • apps/deploy-web/src/services/analytics/analytics.service.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/utils/TransactionMessageData.ts
  • apps/deploy-web/src/utils/walletUtils.ts
  • apps/deploy-web/src/types/feature-flags.ts
  • apps/deploy-web/src/hooks/useJwt.ts
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx
  • apps/deploy-web/src/hooks/useJwt.spec.tsx
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx
  • apps/deploy-web/src/services/analytics/analytics.service.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/hooks/useJwt.spec.tsx
apps/{deploy-web,provider-console}/**/*.spec.tsx

📄 CodeRabbit inference engine (.cursor/rules/query-by-in-tests.mdc)

Use queryBy methods instead of getBy methods in test expectations in .spec.tsx files

Files:

  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/hooks/useJwt.spec.tsx
🧬 Code graph analysis (5)
apps/deploy-web/src/hooks/useJwt.ts (4)
apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx (1)
  • DEPENDENCIES (12-20)
packages/jwt/src/jwt-token.ts (1)
  • createToken (43-67)
apps/deploy-web/src/utils/TransactionMessageData.ts (1)
  • TransactionMessageData (21-309)
packages/http-sdk/src/tx-http/tx-http.service.ts (1)
  • signAndBroadcastTx (22-33)
apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (1)
apps/deploy-web/src/hooks/useJwt.ts (1)
  • LocalToken (12-15)
apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx (3)
apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx (1)
  • DEPENDENCIES (70-110)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (3)
  • DEPENDENCIES (63-68)
  • isLocalCertExpired (367-369)
  • localCert (363-365)
packages/jwt/src/jwt-token.ts (1)
  • createToken (43-67)
apps/deploy-web/src/hooks/useJwt.spec.tsx (3)
apps/deploy-web/src/hooks/useJwt.ts (1)
  • useJwt (27-127)
apps/deploy-web/src/utils/walletUtils.ts (1)
  • LocalWallet (27-27)
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (1)
  • AppDIContainer (18-18)
apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (2)
apps/deploy-web/src/context/WalletProvider/WalletProvider.tsx (1)
  • ContextType (42-59)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (1)
  • ContextType (38-59)
🔇 Additional comments (12)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)

40-40: LGTM!

The new "create_jwt" event type follows the existing naming convention and integrates cleanly with the JWT creation workflow introduced in this PR.

apps/deploy-web/src/utils/walletUtils.ts (1)

11-11: LGTM!

The optional token field appropriately extends the wallet interface to support JWT storage without introducing breaking changes.

apps/deploy-web/src/types/feature-flags.ts (1)

9-10: LGTM!

The new feature flag "jwt_instead_of_cert" clearly indicates its purpose and enables controlled rollout of the JWT-based authentication flow.

apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1)

32-32: LGTM!

Exporting ContextType follows the established pattern in other providers (e.g., WalletProvider, CertificateProvider) and enables proper type checking for external consumers.

apps/deploy-web/src/utils/TransactionMessageData.ts (1)

72-82: LGTM!

The getCreateJwtMsg helper follows the established pattern from getCreateCertificateMsg and correctly base64-encodes the JWT token string for transmission.

apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (2)

2-2: LGTM!

The new test cases comprehensively cover the JWT flow:

  • Token button rendering when feature flag is enabled
  • Token creation callback invocation
  • Token expiration warning display

All tests follow the existing patterns and coding guidelines.

Also applies to: 15-19, 31-39, 53-63


66-89: LGTM!

The test setup properly extends the dependency injection pattern to include JWT-related hooks (useJwt, useFlag) and parameters, maintaining consistency with the existing test infrastructure.

Also applies to: 118-131

apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx (3)

9-10: LGTM!

The dependency injection pattern is properly extended to include useJwt and useFlag hooks, maintaining consistency with the existing architecture.

Also applies to: 17-20, 29-32


38-41: LGTM!

The _createToken callback correctly mirrors the pattern established by _createCertificate, ensuring consistent behavior across both flows.


66-84: Verify className inconsistency is intentional.

Line 68 includes "ml-2" in the JWT button's className, while line 77 (certificate button) does not. Ensure this difference is intentional, as it may cause layout inconsistencies between the two flows.

apps/deploy-web/src/hooks/useJwt.spec.tsx (2)

1-279: LGTM!

Comprehensive test suite covering all critical paths:

  • Initial states and loading scenarios
  • Token expiration logic
  • Token creation (success and failure paths)
  • Edge cases (multiple wallets, decoding errors, missing tokens)
  • Error handling and transaction broadcast failures

The tests follow all coding guidelines and demonstrate thorough validation of the JWT workflow.


280-368: LGTM!

The test setup helper follows coding guidelines perfectly:

  • Single parameter with inline type definition
  • No shared state
  • No return type annotation
  • Positioned at the bottom of the describe block
  • Uses jest-mock-extended for dependency mocking
  • Comprehensive mock coverage of all dependencies

The mocking strategy effectively isolates the hook for unit testing.

const jwtToken = new d.JwtToken({} as any);
return jwtToken.decodeToken(localToken.token);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Stop casting to any when decoding the token

Line 51 constructs new d.JwtToken({} as any) solely to call decodeToken, which violates our “no any” TypeScript rule and sidesteps the dependencies the JwtToken ctor expects (wallet + signer). That leaves the instance in an invalid state and will break as soon as JwtToken touches those fields. Please switch to a decode helper that doesn’t require instantiation—e.g., expose or import a static decodeToken—instead of faking the ctor. As per coding guidelines.

const jwtToken = new d.JwtToken({} as any);
return jwtToken.decodeToken(localToken.token);
} catch (error) {
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

should this be reported to sentry? should any error be shown to a user?

setIsCreatingToken(false);

throw error;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

non-blocking. finally could be used to setIsCreatingToken(false); for all cases


const token = await jwtToken.createToken({
version: "v1",
iss: "https://example.com",
Copy link
Contributor

Choose a reason for hiding this comment

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

this seems to be failing the validation

image

Comment on lines 89 to 90
const message = TransactionMessageData.getCreateJwtMsg(address, token);
const response = await signAndBroadcastTx([message]);
Copy link
Contributor

Choose a reason for hiding this comment

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

FYI: token is created offchain, no need for trx

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm sorry, I don't understand this sentence, probably it's the lack of my knowledge. What do you mean? No signAndBroadcastTx needed here?

Copy link
Contributor

Choose a reason for hiding this comment

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

No worries

"offchain" means outside of blockchain and transaction is not needed. The whole point of adding JWT is to get rid of blockchain dependency, and trx -> shorthand for transaction (In this context blockchain transaction).

@jzsfkzm jzsfkzm force-pushed the features/1946-jwt-button branch from 134abb2 to e9f77f4 Compare October 7, 2025 15:29
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: 2

Caution

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

⚠️ Outside diff range comments (1)
apps/deploy-web/src/utils/walletUtils.ts (1)

7-13: Persisting JWT in localStorage expands XSS blast radius

In apps/deploy-web/src/utils/walletUtils.ts, BaseLocalWallet.token is saved and loaded via localStorage (getStorageWallets/updateStorageWallets around lines 92–111); move tokens to a more secure store (httpOnly cookie, sessionStorage for short-lived tokens, or in-memory) and ensure all tokens are purged on logout or wallet deletion.

♻️ Duplicate comments (2)
apps/deploy-web/src/hooks/useJwt.ts (2)

47-56: Stop instantiating JwtToken with as any just to decode

Don’t fake the ctor to call decode. Decode without constructing or inject a pure decode dependency.

As per coding guidelines.

Apply this diff to use a safe payload decoder:

-  const parsedLocalToken = useMemo(() => {
-    if (!localToken) return null;
-
-    try {
-      const jwtToken = new d.JwtToken({} as any);
-      return jwtToken.decodeToken(localToken.token);
-    } catch (error) {
-      return null;
-    }
-  }, [localToken]);
+  const parsedLocalToken = useMemo(() => {
+    if (!localToken) return null;
+    return decodeJwtPayload(localToken.token);
+  }, [localToken]);

Add this helper (outside the selected range):

function decodeJwtPayload(token: string): JwtTokenPayload | null {
  try {
    const parts = token.split(".");
    if (parts.length < 2) return null;
    const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
    const json = typeof atob === "function" ? atob(payload) : Buffer.from(payload, "base64").toString("utf8");
    return JSON.parse(json) as JwtTokenPayload;
  } catch {
    return null;
  }
}

70-108: Spinner can get stuck true on token creation errors

Errors thrown before the current try/finally leave isCreatingToken=true. Wrap the whole flow in try/finally.

 const createToken = useCallback(async () => {
   setIsCreatingToken(true);
-
-  const { pubkey } = await getAccount();
-
-  const jwtToken = new d.JwtToken({
-    signArbitrary,
-    address,
-    pubkey
-  });
-
-  const token = await jwtToken.createToken({
-    version: "v1",
-    iss: address,
-    exp: Math.floor(Date.now() / 1000) + 3600,
-    iat: Math.floor(Date.now() / 1000)
-  });
-
-  try {
-    const message = TransactionMessageData.getCreateJwtMsg(address, token);
-    const response = await signAndBroadcastTx([message]);
-    if (response) {
-      d.updateWallet(address, wallet => {
-        return {
-          ...wallet,
-          token
-        };
-      });
-      loadLocalToken();
-
-      analyticsService.track("create_jwt", {
-        category: "certificates",
-        label: "Created jwt"
-      });
-    }
-  } finally {
-    setIsCreatingToken(false);
-  }
+  try {
+    const { pubkey } = await getAccount();
+    const jwtToken = new d.JwtToken({ signArbitrary, address, pubkey });
+    const token = await jwtToken.createToken({
+      version: "v1",
+      iss: address,
+      exp: Math.floor(Date.now() / 1000) + 3600,
+      iat: Math.floor(Date.now() / 1000)
+    });
+    const message = TransactionMessageData.getCreateJwtMsg(address, token);
+    const response = await signAndBroadcastTx([message]);
+    if (response) {
+      d.updateWallet(address, wallet => ({ ...wallet, token }));
+      loadLocalToken();
+      analyticsService.track("create_jwt", { category: "certificates", label: "Created jwt" });
+    }
+  } finally {
+    setIsCreatingToken(false);
+  }
 }, [getAccount, signArbitrary, address, signAndBroadcastTx, d, loadLocalToken, analyticsService]);
🧹 Nitpick comments (3)
apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (2)

9-13: Use queryBy in expectations per test guidelines*

Switch getByRole to queryByRole in assertions.

As per coding guidelines.

-    expect(screen.getByRole("button", { name: /create certificate/i })).toBeInTheDocument();
+    expect(screen.queryByRole("button", { name: /create certificate/i })).toBeInTheDocument();

15-19: Use queryBy in expectations per test guidelines*

Switch getByRole to queryByRole in assertions.

As per coding guidelines.

-    expect(screen.getByRole("button", { name: /create token/i })).toBeInTheDocument();
+    expect(screen.queryByRole("button", { name: /create token/i })).toBeInTheDocument();
apps/deploy-web/src/hooks/useJwt.ts (1)

58-69: loadLocalToken doesn’t need to be async

It’s synchronous; drop async to avoid unnecessary Promise scheduling. Optionally use a for‑of loop instead of find+side effect.

-  const loadLocalToken = useCallback(async () => {
+  const loadLocalToken = useCallback(() => {
     const wallets = d.getStorageWallets();
-    wallets.find(wallet => {
+    wallets.find(wallet => {
       const token: LocalToken | null = wallet.token ? { token: wallet.token, address: wallet.address } : null;
       if (wallet.address === address) {
         setLocalToken(token);
         return true;
       }
     });
   }, [address]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 134abb2 and e9f77f4.

📒 Files selected for processing (9)
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (5 hunks)
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx (2 hunks)
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1 hunks)
  • apps/deploy-web/src/hooks/useJwt.spec.tsx (1 hunks)
  • apps/deploy-web/src/hooks/useJwt.ts (1 hunks)
  • apps/deploy-web/src/services/analytics/analytics.service.ts (1 hunks)
  • apps/deploy-web/src/types/feature-flags.ts (1 hunks)
  • apps/deploy-web/src/utils/TransactionMessageData.ts (3 hunks)
  • apps/deploy-web/src/utils/walletUtils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/deploy-web/src/utils/TransactionMessageData.ts
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx
  • apps/deploy-web/src/services/analytics/analytics.service.ts
  • apps/deploy-web/src/types/feature-flags.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/utils/walletUtils.ts
  • apps/deploy-web/src/hooks/useJwt.ts
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/hooks/useJwt.spec.tsx
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/utils/walletUtils.ts
  • apps/deploy-web/src/hooks/useJwt.ts
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/hooks/useJwt.spec.tsx
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/hooks/useJwt.spec.tsx
apps/{deploy-web,provider-console}/**/*.spec.tsx

📄 CodeRabbit inference engine (.cursor/rules/query-by-in-tests.mdc)

Use queryBy methods instead of getBy methods in test expectations in .spec.tsx files

Files:

  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/hooks/useJwt.spec.tsx
🧬 Code graph analysis (4)
apps/deploy-web/src/hooks/useJwt.ts (3)
packages/jwt/src/jwt-token.ts (1)
  • createToken (43-67)
apps/deploy-web/src/utils/TransactionMessageData.ts (1)
  • TransactionMessageData (22-310)
packages/http-sdk/src/tx-http/tx-http.service.ts (1)
  • signAndBroadcastTx (22-33)
apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (2)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (1)
  • LocalCert (13-17)
apps/deploy-web/src/hooks/useJwt.ts (1)
  • LocalToken (12-15)
apps/deploy-web/src/hooks/useJwt.spec.tsx (3)
apps/deploy-web/src/hooks/useJwt.ts (1)
  • useJwt (27-123)
apps/deploy-web/src/utils/walletUtils.ts (1)
  • LocalWallet (27-27)
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (1)
  • AppDIContainer (19-19)
apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx (3)
apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx (1)
  • DEPENDENCIES (70-110)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (3)
  • DEPENDENCIES (63-68)
  • isLocalCertExpired (369-371)
  • localCert (365-367)
packages/jwt/src/jwt-token.ts (1)
  • createToken (43-67)
⏰ 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). (2)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (2)
apps/deploy-web/src/hooks/useJwt.ts (1)

88-95: Confirm if broadcasting a tx is required for JWT creation

A prior review noted tokens are created off‑chain; if no on‑chain registration is needed, consider removing the tx path to reduce latency and failure modes.

apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx (1)

29-33: JWT gating and hook wiring look good

Flag check + useJwt integration and state wiring are coherent.

Comment on lines +324 to +334
const mockUseSettings = mock<SettingsProviderContextType>({
settings: {
apiEndpoint: "https://api.example.com",
rpcEndpoint: "https://rpc.example.com",
isCustomNode: false,
nodes: [],
selectedNode: null,
customNode: null,
isBlockchainDown: false
}
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Mock useSettings misses isSettingsInit; tests may not reflect intended state

setup(input).isSettingsInit isn’t passed into the mock, so token loading paths won’t run when expected.

Apply this diff:

 const mockUseSettings = mock<SettingsProviderContextType>({
   settings: {
     apiEndpoint: "https://api.example.com",
     rpcEndpoint: "https://rpc.example.com",
     isCustomNode: false,
     nodes: [],
     selectedNode: null,
     customNode: null,
     isBlockchainDown: false
-  }
+  },
+  isSettingsInit: input.isSettingsInit ?? true
 });
📝 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
const mockUseSettings = mock<SettingsProviderContextType>({
settings: {
apiEndpoint: "https://api.example.com",
rpcEndpoint: "https://rpc.example.com",
isCustomNode: false,
nodes: [],
selectedNode: null,
customNode: null,
isBlockchainDown: false
}
});
const mockUseSettings = mock<SettingsProviderContextType>({
settings: {
apiEndpoint: "https://api.example.com",
rpcEndpoint: "https://rpc.example.com",
isCustomNode: false,
nodes: [],
selectedNode: null,
customNode: null,
isBlockchainDown: false
},
isSettingsInit: input.isSettingsInit ?? true
});
🤖 Prompt for AI Agents
In apps/deploy-web/src/hooks/useJwt.spec.tsx around lines 324 to 334, the
mockUseSettings object lacks the isSettingsInit property so tests that rely on
setup(input).isSettingsInit won't drive the token-loading paths; update the mock
to include isSettingsInit: setup(input).isSettingsInit (or the corresponding
value from the test setup variable) alongside settings so the mock reflects the
intended initialization state and triggers the correct code paths.

useSettings: () => mockUseSettings,
getStorageWallets: mockGetStorageWallets,
updateWallet: mockUpdateWallet,
JwtToken: MockJwtToken as any
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Avoid as any in tests

Replace as any with a safe cast to the JwtToken constructor type.

As per coding guidelines.

-          JwtToken: MockJwtToken as any
+          JwtToken: MockJwtToken as unknown as typeof JwtToken

Add this import at the top of the file:

import { JwtToken } from "@akashnetwork/jwt";
🤖 Prompt for AI Agents
In apps/deploy-web/src/hooks/useJwt.spec.tsx around line 352, the test uses
"JwtToken: MockJwtToken as any" which violates the guideline to avoid `as any`;
import the JwtToken type from "@akashnetwork/jwt" at the top of the file and
replace the `as any` cast with a safe cast to the JwtToken constructor type
(e.g., cast MockJwtToken to the JwtToken constructor/interface) so the mock
matches the expected JwtToken shape.

@stalniy
Copy link
Contributor

stalniy commented Oct 8, 2025

hey @jzsfkzm don't spend time on this PR, it's on me from now

@jzsfkzm jzsfkzm force-pushed the features/1946-jwt-button branch from e9f77f4 to d516089 Compare October 8, 2025 14:35
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: 0

🧹 Nitpick comments (1)
apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (1)

15-19: Consider using queryByRole for the button expectation.

The test uses getByRole in the expectation on line 17. According to the coding guidelines for .spec.tsx files, prefer queryBy methods in test expectations for better error messages and explicit null checks.

As per coding guidelines.

Apply this diff:

   it("renders create token button", () => {
     setup({ isJwtEnabled: true });
-    expect(screen.getByRole("button", { name: /create token/i })).toBeInTheDocument();
+    expect(screen.queryByRole("button", { name: /create token/i })).toBeInTheDocument();
     expect(screen.queryByRole("alert")).toHaveTextContent(/You need to create a token to view deployment details./);
   });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9f77f4 and d516089.

📒 Files selected for processing (8)
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (5 hunks)
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx (2 hunks)
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1 hunks)
  • apps/deploy-web/src/hooks/useJwt.spec.tsx (1 hunks)
  • apps/deploy-web/src/hooks/useJwt.ts (1 hunks)
  • apps/deploy-web/src/services/analytics/analytics.service.ts (1 hunks)
  • apps/deploy-web/src/types/feature-flags.ts (1 hunks)
  • apps/deploy-web/src/utils/walletUtils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/deploy-web/src/utils/walletUtils.ts
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx
  • apps/deploy-web/src/hooks/useJwt.spec.tsx
  • apps/deploy-web/src/hooks/useJwt.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
apps/{deploy-web,provider-console}/**/*.spec.tsx

📄 CodeRabbit inference engine (.cursor/rules/query-by-in-tests.mdc)

Use queryBy methods instead of getBy methods in test expectations in .spec.tsx files

Files:

  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/services/analytics/analytics.service.ts
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx
  • apps/deploy-web/src/types/feature-flags.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/services/analytics/analytics.service.ts
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx
  • apps/deploy-web/src/types/feature-flags.ts
🧬 Code graph analysis (2)
apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (2)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (1)
  • LocalCert (13-17)
apps/deploy-web/src/hooks/useJwt.ts (1)
  • LocalToken (11-14)
apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (2)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (1)
  • ContextType (38-59)
apps/deploy-web/src/context/WalletProvider/WalletProvider.tsx (1)
  • ContextType (42-59)
⏰ 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). (2)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (7)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)

40-40: LGTM!

The new "create_jwt" event follows the existing naming convention and integrates cleanly with the analytics tracking system.

apps/deploy-web/src/types/feature-flags.ts (1)

9-10: LGTM!

The new "jwt_instead_of_cert" feature flag is clearly named and properly integrated into the union type.

apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1)

32-39: LGTM!

Exporting ContextType follows the established pattern used in other provider contexts (e.g., CertificateProviderContext, WalletProvider) and enables type-safe external usage without modifying the type structure.

apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (4)

31-39: LGTM!

The test properly verifies that createToken is invoked when the token button is clicked, providing good coverage for the JWT flow.


53-63: LGTM!

The test correctly validates the token expiration warning message, mirroring the certificate expiration test pattern.


65-89: LGTM!

The extended setup function follows coding guidelines:

  • Single parameter with inline type definition
  • No explicit return type
  • No shared state
  • Positioned at the bottom of the describe block

118-131: LGTM!

The mock implementations for useJwt and useFlag properly support the JWT/token test scenarios without using module-level jest.mock(), adhering to the coding guidelines.

@stalniy
Copy link
Contributor

stalniy commented Oct 9, 2025

@jzsfkzm thanks for your work on this PR, I'll move them into my local branch. Will close this in favor of a new one

@stalniy stalniy closed this Oct 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants