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

fix: validate zod schema before update operation is executed #1051

Merged
merged 1 commit into from
Feb 24, 2024

Conversation

ymc9
Copy link
Member

@ymc9 ymc9 commented Feb 24, 2024

This makes sure transformation rules like @trim, @upper, @lower are effective for updates.

Fixes #1005

Summary by CodeRabbit

  • New Features

    • Enhanced data validation for create and update operations, ensuring more robust input checks.
    • Introduced a new @lower directive for field validation to enforce lowercasing.
    • Added @trim directive to fields for automatic trimming of whitespace.
  • Refactor

    • Improved handling of policy violations and permissions.
    • Refined input validation logic for better data integrity.
  • Tests

    • Expanded integration tests to cover new validation rules and directives.
    • Updated tests to reflect changes in data creation, update operations, and schema directives.

This makes sure transformation rules like `@trim`, `@upper`, `@lower` are effective for updates.
Copy link
Contributor

coderabbitai bot commented Feb 24, 2024

Walkthrough

Walkthrough

The recent updates focus on enhancing input validation logic, introducing new field validation directives, and refining data transformation rules across various operations. These changes aim to ensure data integrity and improve the robustness of create, update, and upsert operations with better handling of policy violations and permissions. Additionally, the introduction of directives like @lower and @trim in model fields underscores a commitment to data consistency and cleanliness.

Changes

Files Summary
packages/runtime/.../policy/handler.ts Enhanced input validation logic for create and update operations, with improved policy and permissions handling.
tests/integration/.../with-policy/field-validation.test.ts, tests/integration/.../with-policy/refactor.test.ts Introduced @lower directive for field validation, refined data creation/update operations, and implemented upsert tasks. Adjusted email casing and title trimming in various operations.
tests/integration/.../schema/refactor-pg.zmodel Added @lower and @trim directives to user, post, and comment model fields for data consistency.

Assessment against linked issues

Objective Addressed Explanation
Apply Zod transformation rules to "update" operation (#1005)
Ensure correct implementation and enforcement of transformation rules during updates (#1005)
Validate coverage of all relevant data transformations for update operation (#1005)
Test update operation to confirm functioning of transformation rules (#1005) The summary mentions enhancements and refinements in operations but does not explicitly confirm testing for the update operation's transformation rules.
Document updated transformation rules for "update" operation (#1005) No mention of documentation updates related to transformation rules.

The changes align well with the objectives of enhancing data integrity and consistency through improved validation and transformation rules. However, there's an unclear indication of thorough testing for the update operation's transformation rules and a lack of documentation updates, which are critical for maintenance and future reference.

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:

Note: Auto-reply has been disabled for this repository by the repository owner. The CodeRabbit bot will not respond to your comments unless it is explicitly tagged.

  • 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 tests 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 from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

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 a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @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.
  • The JSON schema for the configuration file is available here.
  • 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/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

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.

Review Status

Actionable comments generated: 5

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 4bf812e and 0b38848.
Files selected for processing (4)
  • packages/runtime/src/enhancements/policy/handler.ts (7 hunks)
  • tests/integration/tests/enhancements/with-policy/field-validation.test.ts (2 hunks)
  • tests/integration/tests/enhancements/with-policy/refactor.test.ts (14 hunks)
  • tests/integration/tests/schema/refactor-pg.zmodel (3 hunks)
Additional comments: 19
tests/integration/tests/schema/refactor-pg.zmodel (3)
  • 8-8: The addition of the @lower directive to the email field in the User model ensures that all email addresses are stored in lowercase, which is a good practice for consistency and avoiding case-sensitive issues during lookups or comparisons.
  • 55-55: Adding the @trim directive to the title field in the Post model is a good practice to remove any leading or trailing whitespace. This can help in maintaining data consistency and avoiding unexpected behavior due to spaces.
  • 70-70: Similarly, the addition of the @trim directive to the content field in the Comment model is beneficial for the same reasons mentioned for the Post model's title field. It ensures that the content is stored without leading or trailing whitespace.
tests/integration/tests/enhancements/with-policy/field-validation.test.ts (5)
  • 48-48: The addition of the @lower directive to the slug field in the Task model, combined with the existing @regex directive, ensures that slugs are stored in lowercase and adhere to the specified regex pattern. This is a good practice for URL slugs, enhancing consistency and predictability.
  • 511-526: The test case for creating userData with the @trim and @lower directives applied to text6 and @upper directive applied to text7 correctly validates the transformation rules. It's good to see comprehensive testing of these directives to ensure they work as expected.
  • 528-537: The update operation test for userData that checks the transformation of text6 and text7 with the @trim, @lower, and @upper directives also passes. This confirms the directives are correctly applied during update operations as well.
  • 579-593: The test for the upsert operation on the tasks model, specifically testing the @lower directive on the slug field, correctly demonstrates the directive's application in both creation and update scenarios. This is crucial for ensuring the PR objectives are met across different operation types.
  • 595-609: Similarly, the subsequent upsert operation test for updating the slug field in the tasks model validates the @lower directive's application. It's good to see thorough testing of these transformation rules in various scenarios.
tests/integration/tests/enhancements/with-policy/refactor.test.ts (9)
  • 216-229: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [208-226]

The test case for deeply nested creation success correctly trims the title of the post, aligning with the PR objectives to enforce Zod transformation rules. This test effectively validates the @trim directive's application in nested creation scenarios. However, ensure that similar transformation rules, such as @lower for email fields, are consistently applied and tested across all relevant scenarios to maintain data integrity and consistency.

  • 409-418: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [401-415]

The test case for createMany with skipDuplicates option demonstrates the correct application of the title trimming transformation rule. This aligns with the PR objectives and effectively tests the enforcement of Zod transformation rules in bulk creation scenarios. It's important to also verify that other transformation rules, if applicable to the data being tested, are enforced and tested in similar bulk operation scenarios.

  • 427-438: The createMany test case correctly applies the title trimming rule, validating the enforcement of Zod transformation rules in another bulk creation scenario. This consistency in applying and testing transformation rules across different operations is crucial for maintaining data integrity and consistency. Ensure that all transformation rules relevant to the data in question are similarly enforced and tested.
  • 583-586: The test case for updating nested posts includes both title trimming and updating other fields, demonstrating the correct application of transformation rules in nested update scenarios. This is in line with the PR objectives. To further enhance the test coverage, consider including scenarios where multiple transformation rules are applied simultaneously to different fields within the same update operation.
  • 611-628: The test case for updating with create includes trimming of the comment content, aligning with the PR objectives to enforce Zod transformation rules. This test effectively validates the application of transformation rules in complex update scenarios involving nested creation. Ensure that the test suite comprehensively covers all relevant transformation rules across various nested and complex update scenarios to maintain consistency and data integrity.
  • 660-668: The test case for updating with createMany correctly applies the title trimming rule, demonstrating the enforcement of Zod transformation rules in bulk update scenarios. This consistency in applying and testing transformation rules is crucial. To ensure comprehensive coverage, verify that all relevant transformation rules are enforced and tested in similar bulk operation scenarios, including updates and nested updates.
  • 748-754: The test case for updating a post's title with trimming demonstrates the correct application of transformation rules, aligning with the PR objectives. This test effectively validates the enforcement of Zod transformation rules in update scenarios. It's important to ensure that similar transformation rules are consistently applied and tested across all relevant update scenarios to maintain data integrity and consistency.
  • 825-832: The test case for updating with upsert correctly applies the title trimming rule during the update operation, aligning with the PR objectives. This demonstrates the effective enforcement of Zod transformation rules in upsert scenarios. Ensure that the test suite comprehensively covers the application of all relevant transformation rules in upsert operations, both in the update and create paths, to maintain data integrity and consistency.
  • 1120-1123: The test case for updateMany correctly applies the title trimming rule, aligning with the PR objectives to enforce Zod transformation rules in bulk update scenarios. This consistency in applying and testing transformation rules across different operations is crucial for maintaining data integrity. Ensure that all transformation rules relevant to the data in question are similarly enforced and tested in bulk update scenarios.
packages/runtime/src/enhancements/policy/handler.ts (2)
  • 792-798: The validateUpdateInputSchema method is correctly used to validate update payloads. However, ensure that the method is capable of handling complex nested update scenarios where non-literal fields might be present.

Consider adding tests or documentation examples that cover complex update scenarios, including nested updates and updates with non-literal fields (e.g., { increment: 1 }).

  • 1034-1062: The implementation of validateUpdateInputSchema method is robust, correctly filtering out non-literal fields before validation. This approach is essential for update operations where Prisma's special update operations (e.g., increment) are used. However, ensure that all potential non-literal fields are accounted for and that this method is consistently applied across all update operations.

@@ -467,7 +467,7 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
// Validates the given create payload against Zod schema if any
private validateCreateInputSchema(model: string, data: any) {
const schema = this.utils.getZodSchema(model, 'create');
if (schema) {
if (schema && data) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The validateCreateInputSchema method correctly applies Zod schema validation for create operations. However, consider adding error handling for cases where Zod schema is not defined but expected, to prevent silent failures.

if (schema && data) {
+   // Existing logic
} else {
+   throw new Error(`Zod schema for model '${model}' and operation 'create' not found.`);
}

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.

Suggested change
if (schema && data) {
if (schema && data) {
// Existing logic
} else {
throw new Error(`Zod schema for model '${model}' and operation 'create' not found.`);
}

Comment on lines +499 to +518
// go through create items, statically check input to determine if post-create
// check is needed, and also validate zod schema
let needPostCreateCheck = false;
for (const item of enumerate(args.data)) {
const validationResult = this.validateCreateInputSchema(this.model, item);
if (validationResult !== item) {
this.utils.replace(item, validationResult);
}

const inputCheck = this.utils.checkInputGuard(this.model, item, 'create');
if (inputCheck === false) {
// unconditionally deny
throw this.utils.deniedByPolicy(
this.model,
'create',
undefined,
CrudFailureReason.ACCESS_POLICY_VIOLATION
);
} else if (inputCheck === true) {
const r = this.validateCreateInputSchema(this.model, item);
if (r !== item) {
this.utils.replace(item, r);
}
// unconditionally allow
Copy link
Contributor

Choose a reason for hiding this comment

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

The loop for validating and checking input guards in createMany method is well-implemented. However, consider extracting this logic into a separate method to improve readability and maintainability, especially since similar patterns are used in other parts of the class.

+ private validateAndCheckInputGuards(model: string, data: any[]) {
+     let needPostCreateCheck = false;
+     for (const item of data) {
+         // Existing validation and check logic here
+     }
+     return needPostCreateCheck;
+ }
- // Original loop logic here

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.

Suggested change
// go through create items, statically check input to determine if post-create
// check is needed, and also validate zod schema
let needPostCreateCheck = false;
for (const item of enumerate(args.data)) {
const validationResult = this.validateCreateInputSchema(this.model, item);
if (validationResult !== item) {
this.utils.replace(item, validationResult);
}
const inputCheck = this.utils.checkInputGuard(this.model, item, 'create');
if (inputCheck === false) {
// unconditionally deny
throw this.utils.deniedByPolicy(
this.model,
'create',
undefined,
CrudFailureReason.ACCESS_POLICY_VIOLATION
);
} else if (inputCheck === true) {
const r = this.validateCreateInputSchema(this.model, item);
if (r !== item) {
this.utils.replace(item, r);
}
// unconditionally allow
private validateAndCheckInputGuards(model: string, data: any[]) {
let needPostCreateCheck = false;
for (const item of data) {
// Existing validation and check logic here
}
return needPostCreateCheck;
}

Comment on lines +1094 to +1095
args.data = this.validateUpdateInputSchema(this.model, args.data);

Copy link
Contributor

Choose a reason for hiding this comment

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

The use of validateUpdateInputSchema in updateMany method is appropriate. However, consider adding a comment explaining the rationale behind validating only literal fields, as this might not be immediately clear to other developers or future maintainers.

+ // Validate only literal fields to ensure compatibility with Prisma's special update operations
args.data = this.validateUpdateInputSchema(this.model, args.data);

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.

Suggested change
args.data = this.validateUpdateInputSchema(this.model, args.data);
// Validate only literal fields to ensure compatibility with Prisma's special update operations
args.data = this.validateUpdateInputSchema(this.model, args.data);

Comment on lines +147 to +155
data: { id: 1, email: 'User1@zenstack.dev' },
})
).rejects.toThrow(/not allowed to be read back/);

// success
await expect(user1Db.user.findUnique({ where: { id: 1 } })).toResolveTruthy();
await expect(user1Db.user.findUnique({ where: { id: 1 } })).resolves.toMatchObject({
// email to lower
email: '[email protected]',
});
Copy link
Contributor

Choose a reason for hiding this comment

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

The test case for user creation correctly enforces email casing rules as per the PR objectives. However, it's crucial to ensure that the rejection message for the .rejects.toThrow assertion is specific enough to accurately reflect the policy violation related to email formatting or other validation rules. This specificity aids in understanding the test's intent and ensures that the test fails for the right reasons.

Consider enhancing the rejection message to explicitly mention the reason for the policy violation, such as invalid email format or other specific validation failures.

Comment on lines +524 to +525
adminDb.user.update({ where: { id: 1 }, data: { email: 'User1[email protected]' } })
).resolves.toMatchObject({ email: '[email protected]' });
Copy link
Contributor

Choose a reason for hiding this comment

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

The test case for updating a single user's email demonstrates the correct application of the email casing rule, aligning with the PR objectives. However, it's essential to ensure that the test also covers scenarios where transformation rules might be violated, such as attempting to update with an improperly formatted email, to fully validate the robustness of the implementation.

Consider adding additional assertions or test cases to cover scenarios where updates might violate transformation rules, ensuring comprehensive testing of the enforcement mechanisms.

@ymc9 ymc9 merged commit 9db52db into dev Feb 24, 2024
3 checks passed
@ymc9 ymc9 deleted the fix/issue-1005 branch February 24, 2024 05:34
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.

1 participant