Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RiskRuleService with Notion #2468

Merged
merged 3 commits into from
Jun 24, 2024
Merged

RiskRuleService with Notion #2468

merged 3 commits into from
Jun 24, 2024

Conversation

MatanYadaev
Copy link
Collaborator

@MatanYadaev MatanYadaev commented Jun 20, 2024

Summary by CodeRabbit

  • New Features

    • Integrated Notion API with a new NotionService for retrieving and transforming database records.
    • Added RiskRuleService for handling and retrieving risk rule records.
  • Configuration

    • Introduced NOTION_API_KEY to environment configuration files.
  • Dependencies

    • Updated dependencies to include @notionhq/client and string-ts.
    • Removed @nestjs/serve-static dependency.

Copy link

changeset-bot bot commented Jun 20, 2024

⚠️ No Changeset found

Latest commit: e07a058

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

Copy link
Contributor

coderabbitai bot commented Jun 20, 2024

Walkthrough

The recent updates to the workflows-service mainly introduce new integrations and enhancements. Notably, new dependencies such as @notionhq/client and string-ts were added, and ballerine-nestjs-typebox was reintroduced. An optional environment variable NOTION_API_KEY was added to support Notion API interactions. Two new services, NotionService and RiskRuleService, were created, offering enhanced capabilities for managing and retrieving data from the Notion API and handling risk rules respectively.

Changes

Files Change Summary
services/workflows-service/package.json Updated dependencies: added @notionhq/client, string-ts, removed @nestjs/serve-static. Reintroduced ballerine-nestjs-typebox.
services/workflows-service/src/env.ts Added a new optional field NOTION_API_KEY to serverEnvSchema.
services/workflows-service/src/notion.service.ts Introduced NotionService class to interact with Notion API for database records retrieval and transformation.
services/workflows-service/src/risk-rule.service.ts Introduced RiskRuleService class to handle risk rules with defined schemas and a method to retrieve risk rule records.
services/workflows-service/.env.example Added an example environment variable NOTION_API_KEY.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller
    participant NotionService
    participant NotionAPI

    Client->>Controller: Request to get database records
    Controller->>NotionService: Get all records for `databaseId`
    NotionService->>NotionAPI: Request records from Notion API
    NotionAPI-->>NotionService: Respond with records
    NotionService->>Controller: Transform and provide records
    Controller-->>Client: Send transformed records
Loading
sequenceDiagram
    participant Client
    participant Controller
    participant RiskRuleService

    Client->>Controller: Request all risk rules
    Controller->>RiskRuleService: Find all risk rules
    RiskRuleService-->>Controller: Return risk rules
    Controller-->>Client: Send risk rules
Loading

Poem

In the code where workflows fly,
A notion key now in the sky,
With strings and rules, the data flows,
To Notion’s door, where knowledge grows,
Rabbits cheer, in lines so neat,
For services now complete!
🌟📜✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
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>.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @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.

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 as 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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration 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.

Copy link
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.

Actionable comments posted: 3

Outside diff range and nitpick comments (1)
services/workflows-service/src/risk-rule.service.ts (1)

6-11: Ensure that the RuleSchema covers all necessary fields and types as expected. Consider adding comments to describe each field for better maintainability.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 260e7d5 and bc008cd.

Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
Files selected for processing (5)
  • services/workflows-service/package.json (4 hunks)
  • services/workflows-service/prisma/data-migrations (1 hunks)
  • services/workflows-service/src/env.ts (1 hunks)
  • services/workflows-service/src/notion.service.ts (1 hunks)
  • services/workflows-service/src/risk-rule.service.ts (1 hunks)
Files skipped from review due to trivial changes (1)
  • services/workflows-service/prisma/data-migrations
Additional comments not posted (9)
services/workflows-service/src/risk-rule.service.ts (3)

13-16: The RuleSetSchema looks well-defined. Verify that the operations and the structure align with the business logic.


18-29: The transformation using deepCamelKeys is a good practice for consistent data formatting. Ensure that all fields expected from the Notion API are correctly mapped and transformed.


31-47: The type definition for RiskRuleRecord is comprehensive. Ensure that all these fields are indeed utilized and necessary.

#!/bin/bash
# Description: Check for unused fields in RiskRuleRecord across the codebase.

# Search for usages of RiskRuleRecord fields
rg --type typescript "RiskRuleRecord"
services/workflows-service/src/notion.service.ts (2)

29-49: The method getAllDatabaseRecordsValues is robust and handles data transformation well. Ensure that the error handling is sufficient when the schema parsing fails.


71-112: The method transformNotionFieldToValue handles various Notion field types. Ensure that all types are supported and correctly handled. Consider adding a default case in the switch statement.

services/workflows-service/src/env.ts (1)

78-78: The addition of NOTION_API_KEY to serverEnvSchema is appropriate. Ensure that it is being used correctly across the application.

services/workflows-service/package.json (3)

64-64: The addition of @notionhq/client is necessary for the new Notion integration. Ensure that the version used is up-to-date and does not have known security vulnerabilities.


103-103: The addition of string-ts is appropriate for handling string transformations. Verify that it is used appropriately throughout the project.


77-77: Reintroduction of ballerine-nestjs-typebox should be validated to ensure that it is compatible with other dependencies and the current project structure.

#!/bin/bash
# Description: Verify compatibility of ballerine-nestjs-typebox with other dependencies.

# Check for issues related to dependency compatibility
npm audit

Comment on lines 49 to 69
@Injectable()
export class RiskRuleService {
constructor(private readonly notionService: NotionService) {}

public async findAll({
databaseId,
source,
}: {
databaseId: string;
source: 'notion';
}): Promise<RiskRuleRecord[]> {
if (source === 'notion') {
return await this.notionService.getAllDatabaseRecordsValues({
databaseId,
schema: NotionRiskRuleRecordSchema,
});
}

throw new Error('Unsupported source');
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The findAll method in RiskRuleService effectively utilizes the NotionService. However, consider adding error handling for potential API failures or unexpected data formats.

+ try {
    return await this.notionService.getAllDatabaseRecordsValues({
      databaseId,
      schema: NotionRiskRuleRecordSchema,
    });
+ } catch (error) {
+   // Log error and handle it appropriately
+   throw new Error('Failed to fetch data from Notion');
+ }
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
@Injectable()
export class RiskRuleService {
constructor(private readonly notionService: NotionService) {}
public async findAll({
databaseId,
source,
}: {
databaseId: string;
source: 'notion';
}): Promise<RiskRuleRecord[]> {
if (source === 'notion') {
return await this.notionService.getAllDatabaseRecordsValues({
databaseId,
schema: NotionRiskRuleRecordSchema,
});
}
throw new Error('Unsupported source');
}
}
@Injectable()
export class RiskRuleService {
constructor(private readonly notionService: NotionService) {}
public async findAll({
databaseId,
source,
}: {
databaseId: string;
source: 'notion';
}): Promise<RiskRuleRecord[]> {
if (source === 'notion') {
try {
return await this.notionService.getAllDatabaseRecordsValues({
databaseId,
schema: NotionRiskRuleRecordSchema,
});
} catch (error) {
// Log error and handle it appropriately
throw new Error('Failed to fetch data from Notion');
}
}
throw new Error('Unsupported source');
}
}

Comment on lines 16 to 27
constructor(
private readonly configService: ConfigService,
private readonly logger: AppLoggerService,
) {
if (!env.NOTION_API_KEY) {
throw new Error('NOTION_API_KEY is not set');
}

this.client = new Client({
auth: this.configService.get(env.NOTION_API_KEY),
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The constructor checks for the NOTION_API_KEY and initializes the Notion client. Ensure that the error message is informative and that the API key is being fetched correctly.

- throw new Error('NOTION_API_KEY is not set');
+ throw new Error('NOTION_API_KEY is not set. Please configure it in the environment variables.');
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
constructor(
private readonly configService: ConfigService,
private readonly logger: AppLoggerService,
) {
if (!env.NOTION_API_KEY) {
throw new Error('NOTION_API_KEY is not set');
}
this.client = new Client({
auth: this.configService.get(env.NOTION_API_KEY),
});
}
constructor(
private readonly configService: ConfigService,
private readonly logger: AppLoggerService,
) {
if (!env.NOTION_API_KEY) {
throw new Error('NOTION_API_KEY is not set. Please configure it in the environment variables.');
}
this.client = new Client({
auth: this.configService.get(env.NOTION_API_KEY),
});
}

private readonly configService: ConfigService,
private readonly logger: AppLoggerService,
) {
if (!env.NOTION_API_KEY) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it make sense to allow this variable as optional and once the service is initialized you will throw an exception?

Copy link
Collaborator

@liorzam liorzam Jun 22, 2024

Choose a reason for hiding this comment

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

My solution is to create a provider that dynamically selects the appropriate service based on the configuration

something like:

export const dynamicServiceProvider: Provider = {
  provide: NotionService,
  useFactory: (configService: ConfigService) => {
    const key = configService.get<string>('NOTION_KEY');
    if (key) {
      return new NotionService();
    }
    return new MockNotionService();
  },
  inject: [ConfigService],
};

MockNotionService can throw error when a concrete service api is called

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I prefer it to be required so in production if you will forget to set the env var it won't provision the pod. The alternative you suggested will notify only when a user tries to use the feature.

@ballerine-io ballerine-io deleted a comment from coderabbitai bot Jun 23, 2024
Copy link
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.

Actionable comments posted: 4

Outside diff range and nitpick comments (1)
services/workflows-service/src/risk-rule.service.ts (1)

14-17: Consider simplifying the recursive definition in RuleSetSchema.

The recursive definition using z.lazy() is valid but can be complex to understand and maintain. If the nesting of rules isn't deeply required, consider flattening the structure or providing additional documentation on its intended use to aid in maintainability.

Also applies to: 19-22

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between bc008cd and b6f5968.

Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
Files selected for processing (4)
  • services/workflows-service/package.json (3 hunks)
  • services/workflows-service/src/env.ts (1 hunks)
  • services/workflows-service/src/notion.service.ts (1 hunks)
  • services/workflows-service/src/risk-rule.service.ts (1 hunks)
Files skipped from review as they are similar to previous changes (3)
  • services/workflows-service/package.json
  • services/workflows-service/src/env.ts
  • services/workflows-service/src/notion.service.ts

Comment on lines +24 to +32
const isJsonString = (value: string) => {
try {
JSON.parse(value);

return true;
} catch (e) {
return false;
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Utility function isJsonString lacks clarity in purpose.

This function is used to validate JSON strings, but its placement and naming could be improved for better clarity and reusability. Consider moving it to a common utility module and renaming it to reflect its functionality more clearly, such as isValidJsonString.

Comment on lines +34 to +59
const NotionRiskRuleRecordSchema = z
.object({
ID: z.string().min(1),
'Rule set': z
.string()
.refine(isJsonString, 'Not a valid JSON string')
.transform(value => JSON.parse(value))
.pipe(RuleSetSchema),
Domain: z.string().min(1),
Indicator: z.string().min(1),
'Risk level': z.enum(['positive', 'moderate', 'critical']),
'Base risk score': z.number().min(0).max(100),
'Additional risk score': z.number().min(0).max(100),
'Min risk score': z.number().min(0).max(100),
'Max risk score': z.number().min(0).max(100),
})
.transform(value => ({
id: value.ID,
ruleSet: value['Rule set'],
domain: value.Domain,
indicator: value.Indicator,
baseRiskScore: value['Base risk score'],
additionalRiskScore: value['Additional risk score'],
minRiskScore: value['Min risk score'],
maxRiskScore: value['Max risk score'],
}));
Copy link
Contributor

Choose a reason for hiding this comment

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

Optimize the transformation logic in NotionRiskRuleRecordSchema.

The transformation logic in NotionRiskRuleRecordSchema is quite dense and mixes validation with transformation. This can be split into separate steps or methods to enhance readability and maintainability.

- .transform(value => ({
+ .transform(value => parseNotionRiskRuleRecord(value))

And then define parseNotionRiskRuleRecord in a more modular fashion.

Committable suggestion was skipped due to low confidence.

Comment on lines +61 to +97
@Injectable()
export class RiskRuleService {
constructor(
private readonly notionService: NotionService,
private readonly logger: AppLoggerService,
) {}

public async findAll({ databaseId, source }: { databaseId: string; source: 'notion' }) {
if (source === 'notion') {
const records = await this.notionService.getAllDatabaseRecordsValues({
databaseId,
});

const validatedRecords = [];

for (const record of records) {
const validatedRecord = NotionRiskRuleRecordSchema.safeParse(record);

if (!validatedRecord.success) {
this.logger.error('Notion risk rule record schema validation failed', {
databaseId,
record,
error: validatedRecord.error,
});

continue;
}

validatedRecords.push(validatedRecord.data);
}

return validatedRecords;
}

throw new Error('Unsupported source');
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Enhance error handling and logging in findAll method.

The method handles errors locally but does not re-throw them, potentially hiding failures from callers. Consider re-throwing the errors or handling them in a way that callers can react appropriately.

+ } catch (error) {
+   this.logger.error('Failed to process records', { error });
+   throw error; // Re-throw to ensure the caller is aware of the failure.
+ }
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
@Injectable()
export class RiskRuleService {
constructor(
private readonly notionService: NotionService,
private readonly logger: AppLoggerService,
) {}
public async findAll({ databaseId, source }: { databaseId: string; source: 'notion' }) {
if (source === 'notion') {
const records = await this.notionService.getAllDatabaseRecordsValues({
databaseId,
});
const validatedRecords = [];
for (const record of records) {
const validatedRecord = NotionRiskRuleRecordSchema.safeParse(record);
if (!validatedRecord.success) {
this.logger.error('Notion risk rule record schema validation failed', {
databaseId,
record,
error: validatedRecord.error,
});
continue;
}
validatedRecords.push(validatedRecord.data);
}
return validatedRecords;
}
throw new Error('Unsupported source');
}
}
public async findAll({ databaseId, source }: { databaseId: string; source: 'notion' }) {
try {
if (source === 'notion') {
const records = await this.notionService.getAllDatabaseRecordsValues({
databaseId,
});
const validatedRecords = [];
for (const record of records) {
const validatedRecord = NotionRiskRuleRecordSchema.safeParse(record);
if (!validatedRecord.success) {
this.logger.error('Notion risk rule record schema validation failed', {
databaseId,
record,
error: validatedRecord.error,
});
continue;
}
validatedRecords.push(validatedRecord.data);
}
return validatedRecords;
}
throw new Error('Unsupported source');
} catch (error) {
this.logger.error('Failed to process records', { error });
throw error; // Re-throw to ensure the caller is aware of the failure.
}
}

@ballerine-io ballerine-io deleted a comment from coderabbitai bot Jun 23, 2024
Copy link
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.

Actionable comments posted: 2

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between b6f5968 and e07a058.

Files selected for processing (1)
  • services/workflows-service/.env.example (1 hunks)
Additional context used
Gitleaks
services/workflows-service/.env.example

36-37: Detected a Generic API Key, potentially exposing access to various services and sensitive operations. (generic-api-key)

@@ -34,3 +34,4 @@ COLLECTION_FLOW_URL=http://localhost:5201
WEB_UI_SDK_URL=http://localhost:5202
#HASHING_KEY_SECRET="$2b$10$FovZTB91/QQ4Yu28nvL8e."
HASHING_KEY_SECRET_BASE64=JDJiJDEwJDNFeWtwWEs4QkdiczlRaWFwLkM4Vk8=
NOTION_API_KEY=secret
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure NOTION_API_KEY is securely managed in production.

The static analysis tool flagged the API key as a potential security risk. It's crucial to ensure that in production, the API key is not hardcoded but securely managed, possibly using secrets management tools or environment-specific configurations.

Tools
Gitleaks

36-37: Detected a Generic API Key, potentially exposing access to various services and sensitive operations. (generic-api-key)


Document the placeholder nature of NOTION_API_KEY.

The value secret for NOTION_API_KEY appears to be a placeholder. It would be beneficial to add a comment indicating that this value should be replaced with an actual API key in a real deployment.

- NOTION_API_KEY=secret
+ NOTION_API_KEY=secret # Replace with your actual Notion API key
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
NOTION_API_KEY=secret
NOTION_API_KEY=secret # Replace with your actual Notion API key
Tools
Gitleaks

36-37: Detected a Generic API Key, potentially exposing access to various services and sensitive operations. (generic-api-key)

@MatanYadaev MatanYadaev changed the base branch from dev to bal-2130-epic-rule-engine June 24, 2024 09:28
@MatanYadaev MatanYadaev merged commit 44e77c8 into bal-2130-epic-rule-engine Jun 24, 2024
9 checks passed
@MatanYadaev MatanYadaev deleted the bal-2253 branch June 24, 2024 09:29
@liorzam liorzam mentioned this pull request Jun 24, 2024
alonp99 added a commit that referenced this pull request Jul 11, 2024
* feat: rule engine

* feat: rule engine 2

* feat: rule engine - last year

* fix: eslint

* feat: new rule engine

* feat: new rule engine v2 tests

* feat: export RuleEngine

* feat: prettier and eslint

* RiskRuleService with Notion (#2468)

* feat: risk-rule-service

* fix: pr comments

* fix: tests

* feat: added parsing of rulegine

* feat: generated risk rules plugin logic

* fix: add company registered last year

* added risk rules plugin to common plugins

* feat: removed unnecessary objects in workflow service as they moved to comoon

* feat: fixed eslint

* feat: updated plugin params

* fixed riskRule service

* feat: updated invoked plugin and persistence logic

* feat: added riskIndicatorsByDomain

* fixed workflow service test

* feat: updated rules plugin stracture

* feat: add exists operator

* Please enter the commit message for your changes. Lines starting

* Changes to be committed:
	modified:   ../../packages/workflow-core/src/lib/plugins/common-plugin/risk-rules-plugin.ts
	modified:   src/rule-engine/risk-rule.service.ts

* fix: exists

* fix: import types

* fix: backoffice mock data

* fix: backoffice mock data

* feat: bad merge fix

* Added NOT EQUALS, IN and NOT_IN operations to rule engine (#2512)

* feat: added NOT EQUALS operation to rule engine

* feat: added IN and NOT_IN operations for the rule engine

* feat: customizing for new codebase

* feat: small fixes

* fix: types

* fix: types for notion service

* fix: ci

* fix: ci

* feat: reworked ts service & updated schema (WIP) (#2495)

* feat: reworked ts service & updated schema

* feat: updated array insertion strategy

* fix: fixed i18next initialization

* fix: fixed tests & minor refactor

* fix(conflicts): resolve

---------

Co-authored-by: Alon Peretz <Alonp99@gmail.com>

---------

Co-authored-by: Lior Zamir <liorz@ballerine.com>
Co-authored-by: liorzam <6435752+liorzam@users.noreply.github.com>
Co-authored-by: Matan Yadaev <matan.yed@gmail.com>
Co-authored-by: Tomer Shvadron <tomers@ballerine.com>
Co-authored-by: Illia Rudniev <cheskmr@gmail.com>
Co-authored-by: Alon Peretz <Alonp99@gmail.com>
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.

None yet

2 participants