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

feat(gate)!: policies should affect visibility on introspection #963

Merged
merged 41 commits into from
Feb 6, 2025

Conversation

michael-0acf4
Copy link
Contributor

@michael-0acf4 michael-0acf4 commented Jan 16, 2025

This ended up becoming a full rewrite of the introspection logic.
For context, the old implementation generated types dynamically but also did a few parts statically (the __schema.types list). This worked as long as we assume all object types fields are not context dependent. Which resulted in a few bugs on injected fields.

In this new implementation, we "define" a type as required (it is added into the __schema.types list), still recursively but this allows emitting types with adhoc suffixes in demand depending on the policies or injections. Then when the type is refered we simply give a reference to it.

Migration notes

  • There can be multiple empty object scalars (vs only one previously)
  • Fields can be missing if not authorized
  • Type names depends on its shape (e.g.Foo missing a field would have different name than Foo with all its field), this extends to unions (depends on the variant names with each following the same naming rule)
  • The change comes with new or modified tests
  • Hard-to-understand functions have explanatory comments
  • End-user documentation is updated to reflect the change

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Enhanced GraphQL introspection now offers a more comprehensive and consistent schema view with refined field visibility controls.
    • New introspection queries and fragments improve the introspection capabilities of the GraphQL API.
    • Introduced new functions for managing type visibility and policies within the type graph context.
    • Added new test functions to validate introspection queries and their structures.
  • Refactor

    • Improved runtime initialization and error handling lead to a smoother query engine performance and more robust schema generation.
    • Code structure has been enhanced for better organization and clarity, particularly in type visibility management.
    • Modifications to authorization checks and policy evaluations enhance granularity and processing efficiency.
  • Tests

    • Expanded test coverage validates the new introspection enhancements and policy enforcement, ensuring reliable operation.
    • New tests focus on visibility checks and policy rule logic during introspection on complex and simple type graphs.
    • Added tests for introspection functionalities and visibility policies in various scenarios, ensuring comprehensive validation.

Copy link
Contributor

coderabbitai bot commented Jan 16, 2025

📝 Walkthrough

Walkthrough

The pull request introduces several changes across workflow configuration, computation logic, type graph runtime, introspection schema, and tests. Updates include minor workflow documentation and caching commands, enhanced null safety in the computation engine, and extensive refactoring of the TypeGraph runtime with new private properties, helper functions, and an introspection type emitter. The changes also update the initialization of runtime references in the Typegate class, revise the visitor pattern naming, and adjust introspection schemas and tests, including new queries and visibility functions. A documentation comment in the utilities file was also refined.

Changes

File(s) Change Summary
.github/workflows/tests.yml Minor update to the input description and addition of tests/introspection/common.ts to the caching command.
src/typegate/.../computation_engine.ts Modified registerResult to use nullish coalescing for safe assignment, ensuring robustness against null/undefined values.
src/typegate/.../typegraph.ts, helpers.ts, type_emitter.ts, visibility.ts Extensive refactoring: introduced private properties (#typeGen, #visibility), new helper functions, a new IntrospectionTypeEmitter class to manage GraphQL type emissions, and a TypeVisibility class for policy-based type visibility management.
src/typegate/.../mod.ts, src/typegate/.../typegraph/mod.ts Updated initialization logic in the Typegate and TypeGraph classes to use runtime reference data via the new prepareRuntimeReferences function and RuntimeRefData type.
src/typegate/.../visitor.ts Renamed the Path interface to VisitPath and updated associated function signatures for consistent visitor pattern usage.
src/typegate/.../introspection.json, .../introspection.py Revised introspection schema: updated property values and identifiers, and modified the kind field in Python introspection from required to optional.
tests/introspection/* Added new introspection query functions and tests in multiple files (e.g., common.ts, introspection_test.ts, visibility_complex, visibility_complex_test.ts, visibility_simple, and visibility_simple_test.ts) with updated expected structures.
tools/utils.ts Adjusted the documentation comment for the removeExtension function for improved clarity.

Sequence Diagram(s)

sequenceDiagram
    participant T as Typegate
    participant R as prepareRuntimeReferences
    participant TG as TypeGraph
    T->>R: Call prepareRuntimeReferences(secretManager)
    R-->>T: Return RuntimeRefData
    T->>TG: init(tgDS, secretManager, RuntimeRefData, introspectionData)
    TG-->>T: Runtime initialized with references
Loading
sequenceDiagram
    participant C as Client
    participant TG as TypeGraph
    participant ITE as IntrospectionTypeEmitter
    C->>TG: Request introspection schema
    TG->>ITE: Invoke emitRoot() for root schema
    ITE->>ITE: Process types and apply visibility policies
    ITE-->>TG: Return emitted schema
    TG-->>C: Deliver introspection result
Loading

Suggested reviewers

  • Natoandro
  • Yohe-Am
  • luckasRanarison

Tip

🌐 Web search-backed reviews and chat
  • We have enabled web search-based reviews and chat for all users. This feature allows CodeRabbit to access the latest documentation and information on the web.
  • You can disable this feature by setting web_search: false in the knowledge_base settings.
  • Please share any feedback in the Discord discussion.
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

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>, please review it.
    • 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 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 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 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. (Beta)
  • @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.

@michael-0acf4 michael-0acf4 changed the title feat(gate): policies should affect visibility on introspection feat(gate)!: policies should affect visibility on introspection Jan 16, 2025
@michael-0acf4 michael-0acf4 marked this pull request as ready for review February 4, 2025 17:28
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

🧹 Nitpick comments (24)
tests/introspection/visibility_complex.py (3)

9-14: Consider adding docstrings or inline comments for policy usage.

While this section is fairly self-explanatory, adding a brief comment explaining the purpose and effect of each policy (e.g., “passThrough” and “denyAll”) will enhance maintainability and clarity for future contributors.


77-99: Review cross-field and union expansions carefully.

Your unions combine multiple structured variants, including a self-referential type (rec_type_root) and an empty object. As your type graph expands, ensure that recursion is handled gracefully without introducing performance overhead or infinitely expanding payloads in real usage.


101-109: Consider separating read and update logic for clarity.

Currently, identity_read and identity_update share similar code patterns but differ in effect. Splitting them into distinct, well-documented methods (with more explicit naming or references) might improve maintainability and facilitate adding any future logic specific to read vs. update.

src/typegate/src/runtimes/typegraph.ts (1)

81-105: Refactor repeated logic in the “default” resolver case.

Lines 88–105 repeat the same pattern as 89–103. Factor this out into a helper function or unify the logic for clarity and maintainability.

src/typegate/src/runtimes/typegraph/visibility.ts (3)

45-54: Consider renaming or splitting the reset() behavior.

Your constructor invokes reset(), which reads like it’s re-initializing members plus visiting the type graph. Clarify whether “resetting” also re-scans for new policies each time, or introduce separate methods for scanning vs. clearing. This can make the lifecycle more transparent.


163-215: Avoid direct coupling of policy chain composition with field filtering.

filterAllowedFields composes policy results on the fly, which is fine for small objects. However, more complex or deeply nested objects may benefit from a centralized composition pass, improving performance by avoiding repetitive composition for each field.


218-225: Expand flattenRegardlessOfEffects.

If you add new effects beyond create, delete, read, update, or if you want to handle partial definitions, consider expanding logic to handle missing or unknown effect types to avoid future regressions.

src/typegate/src/typegate/mod.ts (3)

25-26: Use consistent import grouping and naming.
The new imports prepareRuntimeReferences and RuntimeRefData appear logically consistent, but consider grouping them with related imports like TypeGraph and SecretManager. This keeps the import sections more organized.


446-446: Abstract runtime reference creation.
This line introduces rtRefResolver, but the naming rtRefResolver might be improved to convey "runtimeReferencesResolver" or a more meaningful name that clarifies it returns the prepared references.


448-469: Streamline introspection initialization.
This block of code establishes a separate introspection TypeGraph if enableIntrospection is true. It’s a good approach for isolating introspection concerns, but watch out for possible duplication in logic. For example, consider extracting some repeated steps (e.g., calls to rtRefResolver, initFormatter) into helper functions to keep the method focused and maintainable.

src/typegate/src/typegraph/mod.ts (2)

173-173: Document changes to the init method signature.
Adding runtimeRefData: RuntimeRefData clarifies how runtime references are resolved, but consider adding a docstring explaining what the parameter is used for, particularly for future maintainers.


539-581: Isolate runtime reference logic and potential errors.
The new prepareRuntimeReferences function nicely refactors out the runtime setup. Some suggestions:

  1. Add error handling to gracefully report or recover if any particular runtime fails to initialize.
  2. Consider caching or memoizing results if multiple calls to prepareRuntimeReferences could happen for the same typegraph.
  3. Document what the function returns (the shape of RuntimeRefData) and how it's meant to be used.
src/typegate/src/runtimes/typegraph/type_emitter.ts (4)

1-46: Establish explicit separation of concerns.
This newly introduced file provides a class for generating introspection types. The extensive imports for type nodes, visibility, and helpers are appropriate, but ensure that the file remains focused on type emission. If logic for policy-level checks or advanced transformations grows significantly, consider a separate utility module to preserve single responsibility.


49-225: Confirm safe intermixing of checking and generation.
The IntrospectionTypeEmitter constructor (and subsequent methods like emitRoot and #filterWithInjectionAnPolicies) handle both filtering logic (policies/injections) and GraphQL schema creation. This is powerful but can become unwieldy if expanded. A recommended approach is to create a dedicated pre-check structure to handle all policy-based filtering before the actual schema emission.

🧰 Tools
🪛 Biome (1.9.4)

[error] 166-166: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


257-416: Handle unexpected type variants gracefully.
In methods like #emitScalar, #emitRawType, #emitWrapperAndReturnSchema, and the union-handling logic, you throw errors for unhandled or unexpected types. This is good for fail-fast, but consider a fallback or user-facing warning if partial introspection is possible. Doing so may provide more resilient schema outputs when the input typegraph is partially invalid or dynamically generated.


418-641: Ensure consistent naming conventions and factor out repeated logic.
The final sections ($requiredSchema, $fieldSchema, etc.) contain repeated patterns for referencing resolvers, building partial schemas, and handling placeholders. Consider factoring out repeated logic into well-named helper functions to keep each method small and easier to maintain. Also, double-check that naming conventions ($ prefix vs. #) remain consistent with your style guidelines.

tests/introspection/visibility_complex_test.ts (1)

45-45: Fix typo in test description.

There's a typo in the test description: "inivible" should be "invisible".

-    "have a few fields inivible without proper access",
+    "have a few fields invisible without proper access",
src/typegate/src/runtimes/typegraph/helpers.ts (3)

10-23: Consider adding input validation and error handling.

While the function correctly handles scalar types, it could benefit from additional input validation and more descriptive error messages.

 export function genOutputScalarVariantWrapper(type: TypeNode, idx: number) {
+  if (!type) {
+    throw new Error("Type parameter is required");
+  }
+  if (typeof idx !== "number" || idx < 0) {
+    throw new Error("Index must be a non-negative number");
+  }
   if (isScalar(type)) {
     const id = type.type;
     return {
       title: `_${id[0].toUpperCase()}${id.slice(1)}`,
       type: "object",
       properties: {
         [id]: idx,
       },
     } as ObjectNode;
   }
 
-  throw `"${type.title}" of type "${type.type}" is not a scalar`;
+  throw new Error(`Type "${type.title}" of type "${type.type}" is not a scalar`);
 }

32-45: Add JSDoc comments for better documentation.

The function would benefit from JSDoc comments explaining the purpose of each field and their relationship to the GraphQL spec.

+/**
+ * Returns a common structure for GraphQL fields based on the GraphQL spec.
+ * @see https://github.com/graphql/graphql-js/blob/main/src/type/introspection.ts
+ * @returns {Object} Object containing default implementations for field-related properties
+ */
 export function fieldCommon() {
   return {
     // https://github.com/graphql/graphql-js/blob/main/src/type/introspection.ts#L207
     name: () => null,
     specifiedByURL: () => null,
     // logic at https://github.com/graphql/graphql-js/blob/main/src/type/introspection.ts#L453-L490
     ofType: () => null,
     inputFields: () => null,
     fields: () => null,
     interfaces: () => [],
     possibleTypes: () => null,
     enumValues: () => null,
   };
 }

47-71: Consider using template literals for better readability.

The string concatenation in the policy description could be more readable using template literals.

   let ret = "\n\nPolicies:\n";
 
   if (policyNames.length > 0) {
-    ret += policyNames.map((p: string) => `- ${p}`).join("\n");
+    ret += policyNames.map((p: string) => `- ${p}`).join('\n');
   } else {
-    ret += "- inherit";
+    ret += '- inherit';
   }
 
-  return ret;
+  return `${ret}\n`;
tests/introspection/visibility_simple.py (2)

15-18: Consider adding type hints for better code clarity.

The helper function could benefit from type hints for better code clarity and maintainability.

-    def ctxread_or_pass_through(pol_name: str):
+    def ctxread_or_pass_through(pol_name: str) -> DenoRuntime.Policy:

20-71: Add docstring to explain the test structure.

The complex nested structure would benefit from a docstring explaining the purpose and structure of the test data.

     g.expose(
+        # Test structure:
+        # - a (allow)
+        #   - a_1
+        #     - a_11_deny_allowed (deny but accessible due to parent allow)
+        #     - a_12
+        #   - a_2
+        #     - a_21
+        # - b (pass_through)
+        #   - b_1
+        #     - b_11_deny (deny and not accessible)
+        #     - b_12
+        #   - b_2 (deny)
+        #     - b_21_allow_denied (allow but not accessible due to parent deny)
         ctxread_or_pass_through("root_policy"),
tests/introspection/common.ts (1)

104-113: Consider adding descriptions to the enumeration queries.

The enumerateTypes and enumerateTypesAndInspectFields functions could benefit from JSDoc comments explaining their specific use cases and differences.

+/**
+ * Enumerates all types in the schema with their names and kinds.
+ */
 export const enumerateTypes = () => gql`

+/**
+ * Enumerates all types in the schema and inspects their fields.
+ * More detailed than enumerateTypes but less verbose than fullIntrospection.
+ */
 export const enumerateTypesAndInspectFields = () => gql`

Also applies to: 116-128

src/typegate/src/typegraphs/introspection.py (1)

97-97: Key change: Made type kind optional to support visibility policies.

Making the kind field optional is crucial for implementing type visibility policies in introspection. This allows the system to selectively hide type information based on applied policies.

Consider documenting the visibility behavior in a comment to explain when and why a type's kind might be hidden.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 68cfb17 and 6649e67.

⛔ Files ignored due to path filters (8)
  • .ghjk/deno.lock is excluded by !**/*.lock
  • tests/introspection/__snapshots__/introspection_test.ts.snap is excluded by !**/*.snap
  • tests/introspection/__snapshots__/union_either_test.ts.snap is excluded by !**/*.snap
  • tests/introspection/__snapshots__/visibility_complex_test.ts.snap is excluded by !**/*.snap
  • tests/introspection/__snapshots__/visibility_simple_test.ts.snap is excluded by !**/*.snap
  • tests/simple/__snapshots__/class_syntax_test.ts.snap is excluded by !**/*.snap
  • tests/type_nodes/__snapshots__/either_test.ts.snap is excluded by !**/*.snap
  • tests/type_nodes/__snapshots__/union_test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (18)
  • .github/workflows/tests.yml (2 hunks)
  • src/typegate/src/engine/computation_engine.ts (1 hunks)
  • src/typegate/src/runtimes/typegraph.ts (2 hunks)
  • src/typegate/src/runtimes/typegraph/helpers.ts (1 hunks)
  • src/typegate/src/runtimes/typegraph/type_emitter.ts (1 hunks)
  • src/typegate/src/runtimes/typegraph/visibility.ts (1 hunks)
  • src/typegate/src/typegate/mod.ts (3 hunks)
  • src/typegate/src/typegraph/mod.ts (4 hunks)
  • src/typegate/src/typegraph/visitor.ts (1 hunks)
  • src/typegate/src/typegraphs/introspection.json (17 hunks)
  • src/typegate/src/typegraphs/introspection.py (1 hunks)
  • tests/introspection/common.ts (1 hunks)
  • tests/introspection/introspection_test.ts (6 hunks)
  • tests/introspection/visibility_complex.py (1 hunks)
  • tests/introspection/visibility_complex_test.ts (1 hunks)
  • tests/introspection/visibility_simple.py (1 hunks)
  • tests/introspection/visibility_simple_test.ts (1 hunks)
  • tools/utils.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • tools/utils.ts
  • .github/workflows/tests.yml
🧰 Additional context used
🪛 Biome (1.9.4)
src/typegate/src/runtimes/typegraph/type_emitter.ts

[error] 166-166: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 237-237: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: test-full
  • GitHub Check: test-website
  • GitHub Check: bulid-docker (linux/amd64, custom-ubuntu-large)
  • GitHub Check: lint-compat (macos-14, aarch64-apple-darwin, false)
  • GitHub Check: lint-compat (macos-13, x86_64-apple-darwin, false)
  • GitHub Check: pre-commit
🔇 Additional comments (18)
tests/introspection/visibility_complex.py (1)

20-34: Validate nested fields in test coverage.

The input structure contains nested fields, some with explicit default values (e.g., line 23). Ensure these nested and defaulted fields have test scenarios to confirm they behave as intended under all relevant policies.

src/typegate/src/runtimes/typegraph.ts (1)

128-138: Handle concurrency concerns in policy precomputation.

#withPrecomputeVisibility resets and precomputes all policies before returning. If multiple requests can invoke this method concurrently, ensure that shared state (#visibility and #typeGen) is updated safely, or clarify that concurrency is not applicable.

src/typegate/src/runtimes/typegraph/visibility.ts (1)

114-118: Gracefully handle re-computation scenarios.

You skip policy re-computation if #resolvedPolicy.size > 0. Clarify whether partial failures or partial completions can leave this map in a half-populated state on error, potentially causing inconsistent visibility. You might consider a transaction-like approach or clearing the state on error.

src/typegate/src/typegate/mod.ts (3)

54-54: Validate runtime modules.
Importing DenoRuntime is fine, but ensure it is indeed required in the rest of the code (particularly in the introspection logic). If it is used exclusively within the newly introduced preparatory references block, verify that there are no side effects impacting the broader code.


471-471: Clarify reference usage.
Storing tgRuntimeRefData in a local constant is helpful. Verify that other call sites or subsequent code blocks use these references consistently.


476-476: Ensure parallel usage.
When passing tgRuntimeRefData to TypeGraph.init(), double-check concurrency usage in other typegraph runtimes. If multiple TypeGraphs are initialized concurrently, verify there's no shared mutable state in tgRuntimeRefData that might inadvertently cause data races.

src/typegate/src/typegraph/mod.ts (2)

59-63: Promote clarity of runtime reference structures.
Defining RuntimeRefData is a positive step toward type safety and clarity. Ensure that properties like denoRuntimeIdx and denoRuntime stay in sync if the code ever reorders or modifies runtimes.


217-217: Leverage destructuring carefully.
Destructuring { denoRuntimeIdx, runtimeReferences, denoRuntime } is concise, but ensure that these fields are always defined in the returned data. If there's a chance the runtime might be missing or incorrectly configured, add a defensive check or an informative error message.

tests/introspection/visibility_simple_test.ts (3)

7-19: LGTM! Well-structured test case for authorized types.

The test case effectively validates the enumeration of authorized types with the pass_through policy.


21-31: LGTM! Clear test case for DENY policy.

The test case correctly verifies that only a dummy Query type is enumerated when root policy is set to DENY.


33-43: LGTM! Comprehensive test case for ALLOW policy.

The test case properly validates that all types are enumerated when root policy is set to ALLOW.

tests/introspection/visibility_complex_test.ts (2)

7-12: LGTM! Well-defined context object.

The context object clearly defines the control states for different scenarios.


14-37: LGTM! Comprehensive test case for type enumeration.

The test case effectively validates type enumeration both with and without context.

tests/introspection/common.ts (1)

6-101: LGTM! Well-structured introspection query with comprehensive type coverage.

The fullIntrospection query is well-organized and covers all essential schema elements including types, fields, arguments, interfaces, and directives.

src/typegate/src/typegraph/visitor.ts (1)

7-10: LGTM! Consistent renaming of Path to VisitPath.

The renaming is applied consistently across the interface definition and its usage in the visitor pattern implementation.

Also applies to: 14-15, 18-23

tests/introspection/introspection_test.ts (1)

238-242: LGTM! Simplified test using common introspection query.

Good refactoring to use the shared fullIntrospection query, improving maintainability.

src/typegate/src/engine/computation_engine.ts (1)

188-193: LGTM! Robust null handling improves introspection safety.

The addition of nullish coalescing operators (??) effectively prevents potential runtime errors when fields are not accessible due to policy restrictions. This change aligns well with the PR's objective of ensuring policies influence visibility during introspection.

src/typegate/src/typegraphs/introspection.json (1)

8-8: LGTM! Schema updates support policy-based visibility.

The increments in property values and the addition of the new optional type type_kind_type_kind_optional enhance the schema's ability to handle policy-based visibility during introspection. These changes are consistent and well-structured.

Also applies to: 61-68, 87-91

src/typegate/src/runtimes/typegraph.ts Outdated Show resolved Hide resolved
src/typegate/src/runtimes/typegraph.ts Outdated Show resolved Hide resolved
Copy link

codecov bot commented Feb 4, 2025

Codecov Report

Attention: Patch coverage is 87.63797% with 112 lines in your changes missing coverage. Please review.

Project coverage is 78.20%. Comparing base (82600b5) to head (4000ec4).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...rc/typegate/src/runtimes/typegraph/type_emitter.ts 89.35% 53 Missing ⚠️
src/typegate/src/runtimes/typegraph/visibility.ts 83.12% 27 Missing ⚠️
src/typegate/src/runtimes/typegraph/helpers.ts 70.00% 21 Missing ⚠️
src/typegate/src/runtimes/typegraph.ts 91.30% 6 Missing ⚠️
src/typegate/src/engine/computation_engine.ts 0.00% 2 Missing ⚠️
src/typegate/src/engine/planner/policies.ts 97.56% 1 Missing ⚠️
src/typegate/src/typegraph/mod.ts 97.29% 1 Missing ⚠️
tools/utils.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #963      +/-   ##
==========================================
+ Coverage   77.85%   78.20%   +0.35%     
==========================================
  Files         160      164       +4     
  Lines       19641    20030     +389     
  Branches     1969     2031      +62     
==========================================
+ Hits        15291    15664     +373     
- Misses       4329     4347      +18     
+ Partials       21       19       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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

🧹 Nitpick comments (6)
src/typegate/src/runtimes/typegraph/type_emitter.ts (2)

171-171: Use optional chaining for clarity.

Current code:

const injectionNode = (parentFunction?.injections ?? {})?.[fieldName] ?? null;

Suggestion:

- const injectionNode = (parentFunction?.injections ?? {})?.[fieldName] ?? null;
+ const injectionNode = parentFunction?.injections?.[fieldName] ?? null;

This reduces complexity and aligns with the recommendation from the static analysis tool.

🧰 Tools
🪛 Biome (1.9.4)

[error] 171-171: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


244-244: Use optional chaining to simplify the logic.

Current code:

const policies = (type.policies ?? {})[fieldName];

Suggestion:

- const policies = (type.policies ?? {})[fieldName];
+ const policies = type.policies?.[fieldName];

This handles a null or undefined type.policies more concisely and improves readability.

🧰 Tools
🪛 Biome (1.9.4)

[error] 244-244: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/typegate/src/typegate/mod.ts (1)

457-460: Consider decoupling type generator initialization from Deno runtime.

The type generator is tightly coupled with the Deno runtime. Consider introducing an abstraction layer to support different runtime environments.

A more flexible approach would be to:

  1. Define a runtime interface that different runtimes can implement
  2. Make the type generator work with this interface instead of a specific runtime
  3. This would make it easier to support other runtimes in the future
src/typegate/src/runtimes/typegraph.ts (3)

92-106: Remove code duplication in resolver handling.

The resolver and default cases contain identical code. Consider extracting the common logic into a separate method.

+  #resolveValue: Resolver = async ({ _: { parent } }) => {
+    const resolver = parent[stage.props.node];
+    return typeof resolver === "function"
+      ? await resolver()
+      : resolver;
+  }

   #delegate(stage: ComputeStage): Resolver {
     const name = stage.props.materializer?.name;
     switch (name) {
       case "getSchema":
         return this.#getSchemaResolver;
       case "getType":
         return this.#getTypeResolver;
       case "resolver":
-        return async ({ _: { parent } }) => {
-          const resolver = parent[stage.props.node];
-          const ret = typeof resolver === "function"
-            ? await resolver()
-            : resolver;
-          return ret;
-        };
+        return this.#resolveValue;
       default:
-        return async ({ _: { parent } }) => {
-          const resolver = parent[stage.props.node];
-          const ret = typeof resolver === "function"
-            ? await resolver()
-            : resolver;
-          return ret;
-        };
+        return this.#resolveValue;
     }
   }

114-114: Enhance schema description.

The current description ${root.type} typegraph is minimal. Consider including more informative details about the schema's purpose and capabilities.


127-129: Add error logging for type resolution failures.

When a type is not found, the code silently returns null. Consider logging a warning or debug information to help diagnose schema issues.

   #getTypeResolver: Resolver = ({ name }) => {
+    const type = this.#types.findType(name);
+    if (!type) {
+      console.debug(`Type "${name}" not found in schema`);
+    }
-    return this.#types.findType(name) ?? null;
+    return type ?? null;
   };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 988693f and 68542fd.

📒 Files selected for processing (3)
  • src/typegate/src/runtimes/typegraph.ts (2 hunks)
  • src/typegate/src/runtimes/typegraph/type_emitter.ts (1 hunks)
  • src/typegate/src/typegate/mod.ts (3 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/typegate/src/runtimes/typegraph/type_emitter.ts

[error] 171-171: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 244-244: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: bulid-docker (linux/arm64, custom-arm)
  • GitHub Check: lint-compat (macos-14, aarch64-apple-darwin, false)
  • GitHub Check: bulid-docker (linux/amd64, custom-ubuntu-large)
  • GitHub Check: lint-compat (macos-13, x86_64-apple-darwin, false)
  • GitHub Check: test-website
  • GitHub Check: test-full
  • GitHub Check: pre-commit
🔇 Additional comments (4)
src/typegate/src/typegate/mod.ts (1)

24-27: LGTM! Import changes align with PR objectives.

The new imports are properly organized and support the introspection logic rewrite.

Also applies to: 54-54

src/typegate/src/runtimes/typegraph.ts (3)

22-22: Consider initializing #typeGen in the constructor.

Initializing #typeGen as null could lead to runtime errors if methods are called before initTypeGenerator. Consider making initialization mandatory in the constructor or implementing a state machine pattern to prevent invalid states.


46-46: Address the FIXME comment about request handling.

The comment indicates a need for proper request state management.


131-138: LGTM! Clean implementation of visibility precomputation.

The method properly handles state reset and root emission before resolution.

src/typegate/src/typegate/mod.ts Show resolved Hide resolved
src/typegate/src/typegate/mod.ts Show resolved Hide resolved
src/typegate/src/runtimes/typegraph.ts Show resolved Hide resolved
src/typegate/src/runtimes/typegraph.ts Show resolved Hide resolved
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: 0

🧹 Nitpick comments (1)
src/typegate/src/engine/planner/policies.ts (1)

412-454: Consider adding error handling for empty check results.

While the refactored stage authorization correctly handles per-field results, it might be good to add explicit handling for the case when checkResults is empty.

 async #checkStageAuthorization(
   stageId: string,
   effect: EffectType,
   getResolverResult: GetResolverResult,
 ) {
   const selectedFields = this.#findSelectedFields(stageId);
   const checkResults = [];
+  if (selectedFields.length === 0) {
+    return checkResults; // Early return for no selected fields
+  }
   const policiesForStage = this.#stageToPolicies.get(stageId) ?? [];
   // ... rest of the function
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 68542fd and 4000ec4.

📒 Files selected for processing (2)
  • src/typegate/src/engine/planner/policies.ts (4 hunks)
  • tests/policies/policies_composition_test.ts (7 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: lint-compat (macos-14, aarch64-apple-darwin, false)
  • GitHub Check: bulid-docker (linux/arm64, custom-arm)
  • GitHub Check: test-website
  • GitHub Check: test-full
  • GitHub Check: lint-compat (macos-13, x86_64-apple-darwin, false)
  • GitHub Check: bulid-docker (linux/amd64, custom-ubuntu-large)
  • GitHub Check: pre-commit
🔇 Additional comments (5)
tests/policies/policies_composition_test.ts (2)

34-56: LGTM! Good test coverage for field-level authorization.

The new test case verifies that when control_value is set to "PASS", only the allowed field three is accessible while two is correctly denied.


20-22: LGTM! Consistent formatting.

The addition of trailing commas improves code consistency and makes future diffs cleaner.

Also applies to: 69-71, 87-89, 108-112, 132-136, 150-154, 203-208, 239-246, 273-278

src/typegate/src/engine/planner/policies.ts (3)

206-234: LGTM! Enhanced granularity in policy evaluation.

The refactored authorization logic now correctly handles per-field results, allowing for more precise control over field-level access. The switch-case structure properly handles all authorization outcomes.


243-248: LGTM! Simplified path construction.

The path construction logic has been simplified while maintaining the same functionality. The removal of the unused concernedField parameter reduces complexity.


461-461: LGTM! Improved field selection logic.

The simplified field selection logic is more readable and maintains the same functionality. The use of non-null assertion in the filter is safe here as we're explicitly returning either an object or null.

Also applies to: 464-465

import { ObjectNode, PolicyIndices } from "../../typegraph/types.ts";
import { isScalar, type TypeNode } from "../../typegraph/type_node.ts";

// Note: graphql UNION output does not support scalars, only OBJECT
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this wrapper only present on the introspection scheme or is it also used by the graphql API?

Also, make sure to update https://metatype.dev/docs/reference/graphql to explain more of the funky stuff we're doing.

Copy link
Contributor Author

@michael-0acf4 michael-0acf4 Feb 6, 2025

Choose a reason for hiding this comment

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

Is this wrapper only present on the introspection scheme or is it also used by the graphql API?

Just a wrapper.

Actually, this function is unused (I forgot to clean it up), it came from the old implementation but the logic is still applied on the Output UNION type under a specific case:

  • If the variants are all structs, we define it according to how UNION works in graphql. But then, when a variant is a struct with empty fields, it is considered as a custom scalar as GraphQL does not allow empty field objects either.. but then again, GraphQL does not allow scalars on the UNION, in that case we are forced to fallback to the same logic as this function (adhoc object with a dummy field).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some of these concerns might be better be discussed in MET-883

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

🧹 Nitpick comments (1)
src/typegate/src/typegate/mod.ts (1)

437-483: Consider adding documentation for the introspection initialization process.

The initQueryEngine method has been significantly refactored to handle introspection differently, but lacks documentation explaining the new approach.

Add JSDoc comments to explain:

  • The purpose of runtime reference preparation
  • The introspection initialization process
  • The relationship between type graph and introspection
+  /**
+   * Initializes the query engine with optional introspection support.
+   * 
+   * @param tgDS - The type graph data structure
+   * @param secretManager - Manager for handling secrets
+   * @param customRuntime - Optional custom runtime resolver
+   * @param enableIntrospection - Whether to enable introspection support
+   * @returns Initialized query engine
+   * 
+   * The initialization process involves:
+   * 1. Preparing runtime references for both introspection and type graph
+   * 2. Initializing introspection if enabled
+   * 3. Initializing the main type graph with the prepared references
+   */
   async initQueryEngine(
     tgDS: TypeGraphDS,
     secretManager: SecretManager,
     customRuntime: RuntimeResolver = {},
     enableIntrospection: boolean,
   ): Promise<QueryEngine> {
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4000ec4 and 6c1e678.

📒 Files selected for processing (2)
  • .github/workflows/tests.yml (2 hunks)
  • src/typegate/src/typegate/mod.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/tests.yml
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: bulid-docker (linux/arm64, custom-arm)
  • GitHub Check: bulid-docker (linux/amd64, custom-ubuntu-large)
  • GitHub Check: lint-compat (macos-14, aarch64-apple-darwin, false)
  • GitHub Check: test-full
  • GitHub Check: lint-compat (macos-13, x86_64-apple-darwin, false)
  • GitHub Check: test-website
  • GitHub Check: pre-commit
🔇 Additional comments (3)
src/typegate/src/typegate/mod.ts (3)

25-27: LGTM! Clean import organization.

The new imports are well-organized and properly scoped for the introspection logic rewrite.

Also applies to: 54-54


446-447: Add error handling for runtime reference preparation.

The rtRefResolver initialization could fail, but there's no error handling.


457-460: Add type safety check for Deno runtime.

The code assumes denoRuntime will always be present in introspectionRuntimeRefData.

src/typegate/src/typegate/mod.ts Show resolved Hide resolved
src/typegate/src/typegate/mod.ts Show resolved Hide resolved
@michael-0acf4 michael-0acf4 merged commit 4227fa0 into main Feb 6, 2025
11 of 12 checks passed
@michael-0acf4 michael-0acf4 deleted the policies-on-introspection branch February 6, 2025 16:28
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