Skip to content

Conversation

@ymc9
Copy link
Member

@ymc9 ymc9 commented Sep 14, 2025

Summary by CodeRabbit

  • New Features

    • Consistent policy enforcement added to reads and mutations (SELECT, INSERT, UPDATE, DELETE) via automatic policy filters.
    • Conflict-time updates now respect update policies; on-conflict update conditions are merged with policy filters.
    • INSERT with conflict-returning now limits returned data to ID fields when applicable.
  • Tests

    • Added policy tests covering delete and update flows, including query-builder and on-conflict scenarios.
  • Refactor

    • Consolidated and reorganized policy override logic for clarity.

Copilot AI review requested due to automatic review settings September 14, 2025 05:52
@coderabbitai
Copy link

coderabbitai bot commented Sep 14, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds policy-enforcement transforms in PolicyHandler to apply read and mutation filters (SELECT/INSERT/UPDATE/DELETE), consolidates override logic, and adds tests covering policy-gated delete and query-builder update (including on-conflict updates).

Changes

Cohort / File(s) Summary
Policy enforcement core
packages/runtime/src/plugins/policy/policy-handler.ts
Adds regioned overrides for query transforms; applies per-table read filters to SELECTs; augments INSERT onConflict.updateWhere and limits returning to ID-only when appropriate; injects policy filters into UPDATE and DELETE where clauses; retains pre-create checks; removes duplicate implementations and adds helper regions.
Policy CRUD tests: delete
packages/runtime/test/policy/crud/delete.test.ts
New tests validating policy-gated deletes via top-level API and query builder, asserting not-found on disallowed deletes and correct row counts after deletions.
Policy CRUD tests: update
packages/runtime/test/policy/crud/update.test.ts
Adds query-builder tests for UPDATE and insert...onConflict doUpdateSet under an update policy (x > 1), verifying affected row counts and final row values.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

I nibble through queries, a rabbit so sly,
I stitch in the filters before reads go by.
On conflict I check, on delete I guard,
Returning just IDs when rules hit hard.
Hops, tests, and carrots—policy safely applied. 🥕🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title is concise, follows conventional-commit style, and accurately describes a primary change in the changeset—adding policy support for "insert on conflict update" as implemented in PolicyHandler; it is clear and relevant to reviewers, although the PR also includes broader policy transform updates for reads and other mutations.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/policy-insert-on-conflict

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c7bfb3 and 076562e.

📒 Files selected for processing (1)
  • packages/runtime/src/plugins/policy/policy-handler.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
{packages,samples,tests}/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place packages only under packages/, samples/, or tests/

Files:

  • packages/runtime/src/plugins/policy/policy-handler.ts
🧬 Code graph analysis (1)
packages/runtime/src/plugins/policy/policy-handler.ts (2)
packages/runtime/src/plugins/policy/utils.ts (1)
  • conjunction (49-67)
packages/runtime/src/client/query-utils.ts (1)
  • getIdFields (57-60)
⏰ 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). (1)
  • GitHub Check: build-test (20.x)
🔇 Additional comments (2)
packages/runtime/src/plugins/policy/policy-handler.ts (2)

209-217: LGTM: update policy conjoined with existing WHERE.

Policy is applied post-transform and preserves user predicates via conjunction. Looks correct.

Do we ever produce aliased UPDATE targets (e.g., UPDATE tbl AS t ... FROM ...)? If yes, we may need to qualify columns via alias in buildPolicyFilter to avoid ambiguity. Worth a quick check in dialects/tests.


219-227: LGTM: delete policy conjoined with existing WHERE.

Matches update semantics and respects single-from constraint enforced by getMutationModel.


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.

@claude
Copy link

claude bot commented Sep 14, 2025

Claude finished @ymc9's task —— View job


Code Review: Insert on Conflict Update Feature

I'll review this PR that adds support for "insert on conflict update" functionality to the policy system.

Todo List

  • Read and analyze the policy-handler.ts changes
  • Review the new delete.test.ts file
  • Review the updated update.test.ts file
  • Provide feedback on code quality and best practices
  • Check for potential bugs and security issues
  • Assess performance considerations
  • Evaluate test coverage

Code Review Analysis

Policy Handler Changes (policy-handler.ts)

The main changes are in the transformInsertQuery method (lines 164-206), specifically handling the onConflict clause:

✅ Code Quality & Best Practices

  1. Clean Implementation: The logic correctly handles "insert on conflict update" by applying policy filters to the updateWhere clause of the conflict resolution.

  2. Proper Policy Application: The code correctly applies update policies to the conflict update scenario:

    const filter = this.buildPolicyFilter(mutationModel, undefined, 'update');
  3. Consistent Pattern: Uses the same conjunction pattern as other query transformations to combine existing conditions with policy filters.

🔍 Potential Issues

  1. Type Safety: The onConflict object is being spread and modified, but TypeScript types aren't being preserved:

    onConflict = {
        ...onConflict,
        updateWhere: WhereNode.create(/* ... */),
    };

    Consider using proper typing for the onConflict structure.

  2. Edge Case: The code assumes that if onConflict.updates exists, it's an update scenario. This should be robust, but a more explicit check might be beneficial.

🛡️ Security Considerations

The implementation correctly applies access control policies to conflict resolution updates, which is crucial for maintaining data security. Users cannot bypass update policies through conflict resolution.

⚡ Performance Considerations

The policy filter is only built once per query and reused, which is efficient. No performance concerns identified.

Test Coverage Analysis

delete.test.ts - New File

  • Coverage: Basic delete policy tests with both ORM and query builder approaches
  • Quality: Well-structured with clear test cases
  • Completeness: Covers the essential delete scenarios

update.test.ts - Enhanced File

The new "insert on conflict do update" tests (lines 997-1051) are comprehensive:

  1. Policy Enforcement: Tests that update policies are properly enforced during conflict resolution
  2. Query Builder Integration: Tests both with and without WHERE clauses in conflict resolution
  3. Edge Cases: Covers scenarios where updates are not allowed due to policy restrictions

🔧 Test Quality Assessment

  • Well-structured: Tests follow consistent patterns and use descriptive names
  • Comprehensive: Cover multiple scenarios including policy violations and successful updates
  • Integration: Test both high-level ORM and low-level query builder APIs

Summary & Recommendations

✅ Strengths

  1. Clean, well-integrated implementation
  2. Proper security enforcement through policy application
  3. Comprehensive test coverage including edge cases
  4. Consistent with existing codebase patterns

⚠️ Minor Improvements

  1. Consider adding explicit type annotations for the onConflict object manipulation
  2. Could add a comment explaining the policy application logic in the conflict resolution

🎯 Overall Assessment

This is a solid implementation that properly extends ZenStack's policy system to handle "insert on conflict update" scenarios. The code maintains security guarantees while providing the expected functionality. Test coverage is thorough and follows good practices.

Recommendation: ✅ Approve - Ready to merge with high confidence.


Copy link
Contributor

Copilot AI left a comment

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 adds support for "insert on conflict update" (upsert) operations to the policy system, extending policy enforcement to cover the update portion of upsert queries.

  • Added policy filter application to the "on conflict do update" portion of insert queries
  • Restructured the PolicyHandler class with better organization using region comments
  • Added comprehensive test coverage for both query builder updates and insert-on-conflict-update scenarios

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/runtime/src/plugins/policy/policy-handler.ts Enhanced transformInsertQuery to apply update policies to conflict resolution and reorganized methods with region comments
packages/runtime/test/policy/crud/update.test.ts Added test cases for query builder updates and insert-on-conflict-update policy enforcement
packages/runtime/test/policy/crud/delete.test.ts New test file covering delete policy enforcement for both standard and query builder operations

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@claude
Copy link

claude bot commented Sep 14, 2025

Claude finished @ymc9's task —— View job


Code Review: Insert on Conflict Update Feature

I've reviewed this PR that adds support for "insert on conflict update" functionality to the policy system.

Todo List

  • Read and analyze the policy-handler.ts changes
  • Review the new delete.test.ts file
  • Review the updated update.test.ts file
  • Provide feedback on code quality and best practices
  • Check for potential bugs and security issues
  • Assess performance considerations
  • Evaluate test coverage

Code Review Analysis

Policy Handler Changes (policy-handler.ts:164-206)

The main changes are in the transformInsertQuery method, specifically handling the onConflict clause.

✅ Code Quality & Best Practices

  1. Clean Implementation: The logic correctly handles "insert on conflict update" by applying policy filters to the updateWhere clause of the conflict resolution.

  2. Proper Policy Application: The code correctly applies update policies to the conflict update scenario using the same buildPolicyFilter pattern.

  3. Consistent Pattern: Uses the same conjunction pattern as other query transformations to combine existing conditions with policy filters.

  4. Good Code Organization: The addition of region comments improves code readability and navigation.

⚠️ Critical Issue Found

Bug in onConflict Handling - There's a potential issue identified by the Copilot review that needs addressing:

The onConflict modifications happen after calling super.transformInsertQuery(processedNode) at line 189, but the modified onConflict object is created and processed before passing to super. This appears to be working correctly based on the test results.

However, the flow could be clearer. The current implementation:

  1. Modifies onConflict if it exists (lines 167-184)
  2. Creates processedNode with updated onConflict (line 187)
  3. Passes processedNode to super (line 189)

This is actually correct, but the Copilot concern highlights that the logic flow could be more explicit.

🛡️ Security Assessment

Excellent Security Implementation: The code properly applies access control policies to conflict resolution updates, preventing users from bypassing update policies through upsert operations. This maintains data security integrity.

⚡ Performance Considerations

  • Policy filter is built once per query and reused efficiently
  • No performance concerns identified in the implementation
  • Query transformation happens at compile-time, not runtime

Test Coverage Analysis

delete.test.ts - New File (Lines 1-51)

  • Coverage: Basic delete policy tests with both ORM and query builder approaches
  • Quality: Well-structured with clear test cases for policy enforcement
  • Completeness: Covers essential delete scenarios including edge cases

update.test.ts - Enhanced Tests (Lines 997-1051)

The new "insert on conflict do update" tests are comprehensive:

  1. Policy Enforcement: Tests that update policies are properly enforced during conflict resolution
  2. Query Builder Integration: Tests both with and without WHERE clauses in conflict resolution
  3. Edge Cases: Covers scenarios where updates are not allowed due to policy restrictions
  4. Realistic Scenarios: Tests real-world upsert patterns with proper assertions

🔧 Test Quality Assessment

  • Well-structured: Tests follow consistent patterns with descriptive names
  • Comprehensive: Cover multiple scenarios including policy violations and successful updates
  • Integration: Test both high-level ORM and low-level query builder APIs
  • Edge Case Coverage: Include tests for non-updatable records and mixed scenarios

🎯 Overall Assessment

✅ Strengths

  1. Robust Security: Proper policy enforcement prevents security bypasses
  2. Comprehensive Testing: Thorough test coverage including edge cases
  3. Clean Implementation: Well-integrated with existing codebase patterns
  4. Performance Conscious: Efficient query transformation approach

⚠️ Minor Suggestions

  1. The onConflict logic flow is correct but could benefit from a comment explaining the policy application
  2. Consider adding explicit type annotations for better TypeScript support

🏆 Recommendation

✅ APPROVE - This is a solid, secure implementation that properly extends ZenStack's policy system to handle upsert scenarios. The code maintains security guarantees while providing expected functionality. Test coverage is thorough and follows good practices.

The implementation correctly prevents policy bypass through conflict resolution, which is crucial for maintaining data security in real-world applications.


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 (7)
packages/runtime/src/plugins/policy/policy-handler.ts (6)

194-206: Returning rewrite: alias-awareness and “returning all” edge cases.

If callers use aliased updates/deletes or returningAll(), processReadBack may emit selections referencing an alias while your read-back FROM doesn’t set one. Consider normalizing: collect concrete column names (no alias), or reuse the same alias in the read-back SELECT.


232-240: onlyReturningId may misclassify when selections contain aliases/expressions.

Collector-based equality against raw idFields can return false negatives/positives if selections alias ID columns or include expressions. Consider normalizing selections to underlying column names before the subset check.


242-254: Skip pre-create check when create is unconditionally allowed.

For inserts with unconditional-allow policy, enforcePreCreatePolicy is unnecessary overhead if we’re only gating read-back. Cache constCondition from above and skip this path when it’s true.


265-273: Pre-create evaluation and defaults.

Setting non-provided fields to null for policy evaluation can diverge from actual DB defaults/computed columns and wrongly deny creates. Consider incorporating schema defaults (if available) when synthesizing the VALUES row for checks.


385-411: Read-back with aliased mutations.

If an UPDATE/DELETE was built with a table alias, reusing node.returning.selections against a plain FROM TableNode.create(table) can reference a missing alias. Mirror the alias or dequalify selections.


432-447: DELETE support limited to single FROM.

Throwing on multi-table DELETEs (USING) is fine for now; consider documenting this constraint or guarding earlier to improve error messaging.

packages/runtime/test/policy/crud/delete.test.ts (1)

29-50: Nice query builder assertions. Consider adding a targeted deleteMany(where) case.

A small extra: assert that deleteMany({ where: { x: { gt: 0 } } }) respects policy and matches affected row count.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7b9ad3 and 8c7bfb3.

📒 Files selected for processing (3)
  • packages/runtime/src/plugins/policy/policy-handler.ts (2 hunks)
  • packages/runtime/test/policy/crud/delete.test.ts (1 hunks)
  • packages/runtime/test/policy/crud/update.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
{packages,samples,tests}/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place packages only under packages/, samples/, or tests/

Files:

  • packages/runtime/test/policy/crud/delete.test.ts
  • packages/runtime/test/policy/crud/update.test.ts
  • packages/runtime/src/plugins/policy/policy-handler.ts
🧬 Code graph analysis (3)
packages/runtime/test/policy/crud/delete.test.ts (1)
packages/runtime/test/policy/utils.ts (1)
  • createPolicyTestClient (14-25)
packages/runtime/test/policy/crud/update.test.ts (1)
packages/runtime/test/policy/utils.ts (1)
  • createPolicyTestClient (14-25)
packages/runtime/src/plugins/policy/policy-handler.ts (2)
packages/runtime/src/plugins/policy/utils.ts (1)
  • conjunction (49-67)
packages/runtime/src/client/query-utils.ts (1)
  • getIdFields (57-60)
⏰ 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: claude-review
  • GitHub Check: build-test (20.x)
🔇 Additional comments (4)
packages/runtime/test/policy/crud/delete.test.ts (1)

5-27: Good coverage for top-level delete and deleteMany.

Scenarios validate both deny and allow paths and resulting counts. Looks solid.

packages/runtime/test/policy/crud/update.test.ts (2)

957-996: Query builder simple update: assertions align with injected policy filter.

Verifies both targeted and blanket updates under x > 1. Looks good.


997-1051: Upsert do-update tests: great—covers with/without WHERE and non-updatable vs updatable rows.

This effectively exercises the new policy injection for ON CONFLICT DO UPDATE.

If you adjust policy-handler per my onConflict transformation comment, please re-run these two tests to confirm counts unchanged.

packages/runtime/src/plugins/policy/policy-handler.ts (1)

169-184: No change needed — updateWhere is correct.
Verified: Kysely's OnConflictNode defines updateWhere for DO UPDATE ... WHERE, so the code's use of onConflict.updateWhere is valid.

@ymc9 ymc9 merged commit dc18713 into dev Sep 14, 2025
7 checks passed
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.

2 participants