Skip to content
This repository was archived by the owner on Feb 8, 2026. It is now read-only.

feat: update plugin policy handling to use UUID and add payroll plugi…#84

Merged
johnnyluo merged 3 commits into
mainfrom
update-verifier-dep-1
Jun 6, 2025
Merged

feat: update plugin policy handling to use UUID and add payroll plugi…#84
johnnyluo merged 3 commits into
mainfrom
update-verifier-dep-1

Conversation

@johnnyluo

@johnnyluo johnnyluo commented Jun 6, 2025

Copy link
Copy Markdown
Contributor

…n integration

Summary by CodeRabbit

  • New Features

    • Added support for handling scheduled payroll plugin triggers.
    • Introduced a new configuration option for specifying a base configuration path in payroll worker settings.
  • Improvements

    • Enhanced validation and error handling for policy IDs by enforcing UUID format.
    • Streamlined policy management and signature verification for plugins.
    • Improved logging and error reporting for plugin policy operations.
  • Dependency Updates

    • Updated core dependencies to the latest versions for improved stability and compatibility.

Copilot AI review requested due to automatic review settings June 6, 2025 09:35
@coderabbitai

coderabbitai Bot commented Jun 6, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This set of changes refactors plugin policy handling throughout the codebase. It replaces string-based policy IDs with UUIDs in APIs, services, and storage layers, and updates policy input types from PluginPolicy to PluginPolicyCreateUpdate for creation and update operations. Signature verification logic is simplified, and plugin interfaces are adapted accordingly. New scheduler trigger handling is introduced in the payroll plugin.

Changes

Files/Paths Change Summary
api/plugin.go, service/policy.go, storage/db.go, storage/postgres/policy.go Refactor policy ID parameters from string to uuid.UUID; update method signatures and error handling for UUID parsing; unify policy input type for create/update operations; simplify signature verification logic.
plugin/dca/dca.go, plugin/payroll/policy.go, plugin/payroll/transaction.go Update method signatures to use PluginPolicyCreateUpdate instead of PluginPolicy; adjust internal logic and calls accordingly; add compile-time interface assertions for plugin interfaces.
plugin/payroll/transaction.go Add HandleSchedulerTrigger method for asynchronous scheduler event handling in the payroll plugin.
plugin/payroll/payroll.go Add compile-time interface assertion for PayrollPlugin implementation.
cmd/payroll/worker/config.go Add BaseConfigPath field to PayrollWorkerConfig struct.
cmd/payroll/worker/main.go Initialize payroll plugin with Postgres backend and base config path; set up scheduler trigger handler.
go.mod Update versions of github.com/vultisig/recipes and github.com/vultisig/verifier dependencies.

Sequence Diagram(s)

sequenceDiagram
    participant API
    participant Service
    participant Storage

    API->>API: Parse policyID as UUID
    API->>Service: GetPluginPolicy(ctx, policyID: UUID)
    Service->>Storage: GetPluginPolicy(ctx, id: UUID)
    Storage-->>Service: PluginPolicy
    Service-->>API: PluginPolicy
    API->>API: Bind request as PluginPolicyCreateUpdate
    API->>API: Convert to PluginPolicy for signature verification
    API->>API: Verify policy signature
Loading
sequenceDiagram
    participant Scheduler
    participant PayrollPlugin
    participant DB

    Scheduler->>PayrollPlugin: HandleSchedulerTrigger(ctx, task)
    PayrollPlugin->>DB: GetPluginPolicy(ctx, policyID: UUID)
    DB-->>PayrollPlugin: PluginPolicy
    PayrollPlugin-->>Scheduler: (processing continues or completes)
Loading

Possibly related PRs

Suggested reviewers

  • RaghavSood

Poem

In burrows deep, the plugins grow,
With UUIDs that clearly show,
Policies now create and update,
No more string IDs to debate!
Payroll and DCA, side by side,
Hop to the future, code as our guide.
🐇✨

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.

🔧 golangci-lint (1.64.8)

level=warning msg="[runner] Can't run linter goanalysis_metalinter: buildir: failed to load package session: could not load export data: no export data for "github.com/vultisig/go-wrappers/go-dkls/sessions""
level=error msg="Running error: can't run linter goanalysis_metalinter\nbuildir: failed to load package session: could not load export data: no export data for "github.com/vultisig/go-wrappers/go-dkls/sessions""

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copilot AI 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.

Pull Request Overview

This PR updates policy handling to use UUIDs and integrates a payroll plugin with scheduler tasks.

  • Switched plugin policy identifiers from string to uuid.UUID across storage, service, and API layers
  • Introduced PluginPolicyCreateUpdate type in plugin methods for create/update operations
  • Added a scheduler-trigger handler for the payroll plugin and updated worker configuration

Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
storage/postgres/policy.go Change Get/DeletePluginPolicyTx to accept uuid.UUID
storage/db.go Update DatabaseStorage interface signatures
service/policy.go Update service methods to use uuid.UUID
plugin/payroll/transaction.go Add HandleSchedulerTrigger and switch policy type
plugin/payroll/policy.go Use PluginPolicyCreateUpdate in validation methods
plugin/payroll/payroll.go Add plugin interface assertion
plugin/dca/dca.go Switch DCA plugin methods to PluginPolicyCreateUpdate and add assertion
cmd/payroll/worker/main.go Wire in payroll plugin and scheduler handler
cmd/payroll/worker/config.go Add BaseConfigPath for payroll plugin
api/plugin.go Parse uuid.UUID in endpoints and use CreateUpdate type
go.mod Bump recipes and verifier module versions
Comments suppressed due to low confidence (5)

plugin/payroll/payroll.go:8

  • Importing the plugin interface from verifier/plugin likely mismatches your actual plugin definition. It should align with the module path that defines plugin.Plugin (e.g., github.com/vultisig/plugin).
github.com/vultisig/verifier/plugin

api/plugin.go:70

  • You’re setting BillingRecipe to an empty string when constructing policyUpdate, which may drop existing billing configuration. Consider copying policy.BillingRecipe instead of hardcoding "".
BillingRecipe:        "",

plugin/dca/dca.go:24

  • As with the payroll plugin, this import likely mismatches your actual plugin interface module. Ensure you import the correct package that defines plugin.Plugin.
github.com/vultisig/verifier/plugin

plugin/payroll/transaction.go:13

  • Missing import for the Asynq package. You’re using *asynq.Task and asynq.SkipRetry but haven’t imported github.com/hibiken/asynq.
github.com/vultisig/vultiserver/contexthelper

cmd/payroll/worker/main.go:13

  • Import path looks incorrect (plugin/plugin/payroll). It should match the actual module path for your payroll plugin (e.g., github.com/vultisig/plugin/payroll).
github.com/vultisig/plugin/plugin/payroll

return fmt.Errorf("failed to get plugin policy: %s, %w", err, asynq.SkipRetry)
}
// propose transaction and get it signed
_ = pluginPolicy

Copilot AI Jun 6, 2025

Copy link

Choose a reason for hiding this comment

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

[nitpick] The placeholder _ = pluginPolicy is unused. You should implement the intended logic or remove this line to avoid confusion.

Suggested change
_ = pluginPolicy

Copilot uses AI. Check for mistakes.
Comment thread api/plugin.go

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

Actionable comments posted: 1

🔭 Outside diff range comments (5)
plugin/payroll/transaction.go (3)

55-100: ⚠️ Potential issue

Type mismatch for PolicyID breaks compilation

PluginKeysignRequest.PolicyID is declared as string, yet the builder passes a uuid.UUID:

PolicyID:         policy.ID,          // ← uuid.UUID

This fails to compile.

-PolicyID:         policy.ID,
+PolicyID:         policy.ID.String(),

Please audit all call-sites (DCAPlugin, API handlers, etc.) for the same issue.


175-186: ⚠️ Potential issue

Incorrect pre-sign value for v – EIP-155 signing will produce an invalid hash

When computing the RLP payload to hash you should store the chain-id, not chainId*2+35.
v = chainId (with empty r,s) is what EIP-155 specifies for the unsigned tx; the additive constant is applied only after the signature is produced.

-	V := new(big.Int).Set(chainIDInt)
-	V = V.Mul(V, big.NewInt(2))
-	V = V.Add(V, big.NewInt(35))
+	V := new(big.Int).Set(chainIDInt) // unsigned tx – plain chain-id

Using the inflated value will yield the wrong hash, causing the subsequent signature to be rejected by every client.


305-311: 🛠️ Refactor suggestion

convertData uses an un-initialised policy – potential zero chain-id

payrollPolicy is instantiated but never populated, so payrollPolicy.ChainID[0] is an empty string.
The fallback to originalTx.ChainId() is commented out, leaving chainID=0, which will break NewLondonSigner.

Either parse the recipe or derive the chain-id from originalTx until recipe parsing is wired.

api/plugin.go (1)

52-57: ⚠️ Potential issue

GetPluginPolicy now expects a uuid.UUID, not a string

storage.DatabaseStorage.GetPluginPolicy was switched to UUID, but the call site still passes req.PolicyID (string). Compile-time failure.

-policy, err := s.db.GetPluginPolicy(c.Request().Context(), req.PolicyID)
+uID, err := uuid.Parse(req.PolicyID)
+if err != nil {
+	return fmt.Errorf("invalid policy_id: %w", err)
+}
+policy, err := s.db.GetPluginPolicy(c.Request().Context(), uID)

Apply the same parsing in every place you fetch a policy by ID.

plugin/dca/dca.go (1)

274-357: ⚠️ Potential issue

PolicyID field suffers from the same UUID/string mismatch

Both ProposeTransactions and ValidateProposedTransactions embed policy.ID (uuid.UUID) into a string field.

-PolicyID: policy.ID,
+PolicyID: policy.ID.String(),

Search-replace across the entire plugin to fix.

🧹 Nitpick comments (5)
plugin/payroll/policy.go (2)

52-52: Address TODO comments for production readiness.

There are two TODO comments that should be resolved:

  • Line 52: Converting recipes to PayrollPolicy
  • Line 70: Clarification needed on token ID vs recipient address comparison logic

These indicate incomplete functionality that may affect correctness.

Would you like me to help implement the recipe conversion or clarify the comparison logic?

Also applies to: 70-70


85-85: Remove debug print statement.

The fmt.Printf("Decoded: %+v\n", v) statement should be removed before production deployment to avoid cluttering logs.

-		fmt.Printf("Decoded: %+v\n", v)
service/policy.go (1)

146-151: Consider updating method signature for consistency.

The GetPluginPolicyTransactionHistory method still accepts a string parameter and converts it to UUID internally, while other methods now accept uuid.UUID directly. This inconsistency breaks the pattern established by the broader UUID refactoring.

Consider updating the method signature to accept uuid.UUID directly:

-func (s *PolicyService) GetPluginPolicyTransactionHistory(ctx context.Context, policyID string) ([]types.TransactionHistory, error) {
-	// Convert string to UUID
-	policyUUID, err := uuid.Parse(policyID)
-	if err != nil {
-		return []types.TransactionHistory{}, fmt.Errorf("invalid policy_id: %s", policyID)
-	}
+func (s *PolicyService) GetPluginPolicyTransactionHistory(ctx context.Context, policyID uuid.UUID) ([]types.TransactionHistory, error) {
+	policyUUID := policyID
api/plugin.go (2)

72-74: Error message prints whole struct instead of hash

return fmt.Errorf("message hash does not match transaction hash. expected %s, got %s", txHash, req.Messages[0])

Second %s receives the entire KeysignMessage struct. Use the hash field:

-	return fmt.Errorf("message hash does not match transaction hash. expected %s, got %s", txHash, req.Messages[0])
+	return fmt.Errorf("message hash does not match transaction hash. expected %s, got %s", txHash, req.Messages[0].Hash)

340-369: verifyPolicySignature duplicates heavy vault I/O for every call

This method opens & decrypts the vault on every signature check, which occurs for every create/update/delete request.
Consider caching the decrypted vault per (publicKey, pluginID) pair for the lifetime of the request to eliminate redundant disk and decryption work.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 27441bc and da767f3.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (11)
  • api/plugin.go (10 hunks)
  • cmd/payroll/worker/config.go (1 hunks)
  • cmd/payroll/worker/main.go (2 hunks)
  • go.mod (1 hunks)
  • plugin/dca/dca.go (9 hunks)
  • plugin/payroll/payroll.go (1 hunks)
  • plugin/payroll/policy.go (2 hunks)
  • plugin/payroll/transaction.go (3 hunks)
  • service/policy.go (3 hunks)
  • storage/db.go (1 hunks)
  • storage/postgres/policy.go (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
plugin/payroll/payroll.go (1)
plugin/plugin.go (1)
  • Plugin (13-20)
plugin/payroll/policy.go (2)
plugin/payroll/payroll.go (1)
  • PayrollPlugin (15-21)
internal/types/keysign.go (1)
  • PluginKeysignRequest (7-12)
storage/postgres/policy.go (1)
storage/postgres/db.go (1)
  • PostgresBackend (19-21)
api/plugin.go (2)
internal/types/keysign.go (1)
  • PluginKeysignRequest (7-12)
api/server.go (1)
  • Server (32-45)
plugin/dca/dca.go (2)
plugin/plugin.go (1)
  • Plugin (13-20)
internal/types/keysign.go (1)
  • PluginKeysignRequest (7-12)
🔇 Additional comments (14)
cmd/payroll/worker/config.go (1)

24-24: LGTM! Clean configuration field addition.

The BaseConfigPath field follows proper Go conventions with appropriate struct tags and omitempty handling.

plugin/payroll/payroll.go (2)

8-8: Good practice: adding plugin package import for interface assertion.

The import is necessary to support the compile-time interface compliance check.


13-13:

Details

✅ Verification successful

Verify that PayrollPlugin implements all Plugin interface methods.

The compile-time assertion is excellent practice, but please ensure that PayrollPlugin implements all required methods from the plugin.Plugin interface.

Based on the relevant code snippet, the Plugin interface requires these methods:

  • FrontendSchema() embed.FS
  • GetRecipeSpecification() rtypes.RecipeSchema
  • ValidatePluginPolicy(policyDoc vtypes.PluginPolicy) error
  • ProposeTransactions(policy vtypes.PluginPolicy) ([]types.PluginKeysignRequest, error)
  • ValidateProposedTransactions(policy vtypes.PluginPolicy, txs []types.PluginKeysignRequest) error
  • SigningComplete(ctx context.Context, signature tss.KeysignResponse, signRequest types.PluginKeysignRequest, policy vtypes.PluginPolicy) error

🏁 Script executed:

#!/bin/bash
# Verify PayrollPlugin implements all Plugin interface methods
ast-grep --pattern $'func ($_ *PayrollPlugin) FrontendSchema() $_ {
  $$$
}'

ast-grep --pattern $'func ($_ *PayrollPlugin) GetRecipeSpecification() $_ {
  $$$
}'

ast-grep --pattern $'func ($_ *PayrollPlugin) ValidatePluginPolicy($_) $_ {
  $$$
}'

ast-grep --pattern $'func ($_ *PayrollPlugin) ProposeTransactions($_) $_ {
  $$$
}'

ast-grep --pattern $'func ($_ *PayrollPlugin) ValidateProposedTransactions($_, $_) $_ {
  $$$
}'

ast-grep --pattern $'func ($_ *PayrollPlugin) SigningComplete($_, $_, $_, $_) $_ {
  $$$
}'

Length of output: 17383


PayrollPlugin correctly implements the plugin.Plugin interface
All six required methods are present with matching signatures (FrontendSchema, GetRecipeSpecification, ValidatePluginPolicy, ProposeTransactions, ValidateProposedTransactions, and SigningComplete). The compile‐time assertion is satisfied—no further changes needed.

go.mod (1)

22-23:

Details

❓ Verification inconclusive

Verify the updated dependency versions are valid and secure.

The dependency updates use pseudo-versions based on git commits. Please ensure these commits exist and don't introduce breaking changes or security vulnerabilities.


🏁 Script executed:

#!/bin/bash
# Verify the updated dependencies exist and check for any security advisories
echo "Checking vultisig/recipes version..."
curl -s "https://api.github.com/repos/vultisig/recipes/commits/58772375f814" | jq '.sha, .commit.message, .commit.author.date'

echo "Checking vultisig/verifier version..."  
curl -s "https://api.github.com/repos/vultisig/verifier/commits/2f9ec25b5689" | jq '.sha, .commit.message, .commit.author.date'

# Check if modules can be fetched
go list -m github.com/vultisig/recipes@v0.0.0-20250604212709-58772375f814
go list -m github.com/vultisig/verifier@v0.0.0-20250606071917-2f9ec25b5689

Length of output: 1108


Dependencies validated successfully

  • Both pseudo-versions exist on GitHub and fetch correctly with go list:
    • recipes@v0.0.0-20250604212709-58772375f814
      • sha: 58772375f814733251481370991b84e706f578cd
      • date: 2025-06-04T21:27:09Z
      • message: “Merge pull request #18…engine: policy and transaction evaluation engine”
    • verifier@v0.0.0-20250606071917-2f9ec25b5689
      • sha: 2f9ec25b5689679738e1ee8aac2a62e011756f98
      • date: 2025-06-06T07:19:17Z
      • message: “Remove policy…remove PolicyID field from PluginKeysignRequest struct”

No errors were returned by go list.

Please review any code that depended on the now-removed PolicyID field in the verifier module and run your integration/security tests to confirm there are no breaking changes or new vulnerabilities.

cmd/payroll/worker/main.go (3)

13-13: LGTM! Proper import for payroll plugin integration.

The import is correctly added to support the payroll plugin initialization.


60-63: Good integration pattern with proper error handling.

The payroll plugin initialization follows the established pattern:

  • Uses the postgres backend dependency
  • Leverages the new BaseConfigPath configuration
  • Includes appropriate error handling consistent with other service initializations

73-73:

Details

✅ Verification successful

Verify HandleSchedulerTrigger method signature matches asynq handler requirements.

Please ensure that the HandleSchedulerTrigger method on PayrollPlugin has the correct signature for asynq task handling.


🏁 Script executed:

#!/bin/bash
# Verify HandleSchedulerTrigger method exists and has correct signature
ast-grep --pattern $'func ($_ *PayrollPlugin) HandleSchedulerTrigger($_, $_) $_ {
  $$$
}'

# Also search for any HandleSchedulerTrigger method definition
rg -A 5 "func.*HandleSchedulerTrigger"

Length of output: 2043


HandleSchedulerTrigger signature is correct

The HandleSchedulerTrigger method on PayrollPlugin is declared as

func (p *PayrollPlugin) HandleSchedulerTrigger(ctx context.Context, t *asynq.Task) error

which exactly matches the asynq.HandlerFunc signature. No changes are needed.

storage/db.go (1)

17-17: LGTM! Interface updated for improved type safety.

The change from string to uuid.UUID for policy ID parameters enhances type safety and ensures consistent UUID validation throughout the system.

Also applies to: 19-19

plugin/payroll/policy.go (1)

40-40: LGTM! Method signatures updated for policy type consistency.

The change from vtypes.PluginPolicy to vtypes.PluginPolicyCreateUpdate aligns with the broader refactoring to separate input types from stored policy types.

Also applies to: 199-199

storage/postgres/policy.go (2)

8-8: LGTM! UUID import added for type safety.

The addition of the github.com/google/uuid import supports the parameter type changes in the method signatures.


14-14: LGTM! Method signatures correctly updated for UUID usage.

The parameter type changes from string to uuid.UUID properly implement the interface updates and maintain the existing logic while improving type safety.

Also applies to: 155-155

service/policy.go (1)

20-20: LGTM! Service interface and implementation updated for UUID consistency.

The method signatures correctly updated to use uuid.UUID parameters, maintaining consistency with the storage layer changes while preserving all business logic.

Also applies to: 22-22, 110-110, 138-138

plugin/dca/dca.go (2)

51-52: Interface assertion may fail – signature list diverged

var _ plugin.Plugin = (*DCAPlugin)(nil) compiles only if the method set matches plugin.Plugin.
The local implementation now accepts PluginPolicyCreateUpdate, but the interface snippet (still in the repo) requires PluginPolicy.

Please verify the interface definition was updated across the codebase; otherwise builds will break.


362-415: completePolicy call needs the create/update type

ValidateProposedTransactions converts back to PluginPolicy in order to mark the policy completed:

if err := p.completePolicy(ctx, policy.ToPluginPolicy()); …

completePolicy ultimately persists the policy via UpdatePluginPolicyTx, which now accepts the newer type in other layers. Make sure these signatures are consistent to avoid mismatches.

Comment thread plugin/payroll/transaction.go

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

LGTM

@johnnyluo
johnnyluo merged commit e5a814a into main Jun 6, 2025
3 checks passed
@johnnyluo
johnnyluo deleted the update-verifier-dep-1 branch June 6, 2025 11:36
@coderabbitai coderabbitai Bot mentioned this pull request Jun 20, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants