Skip to content

Conversation

@adityachoudhari26
Copy link
Contributor

@adityachoudhari26 adityachoudhari26 commented May 10, 2025

Summary by CodeRabbit

  • New Features
    • Added support for asynchronous resolution of reference-type resource variables, allowing variables to reference values from related resources.
  • Bug Fixes
    • Improved consistency in variable path and version handling for resource variable references.
  • Refactor
    • Streamlined and centralized the logic for resolving resource variables, enhancing maintainability and reliability.
  • Tests
    • Updated tests to ensure correct handling of reference variables and dynamic versioning.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 10, 2025

Walkthrough

The changes introduce asynchronous resolution of resource variables, especially for reference-type variables, across multiple API endpoints and internal handlers. A new utility function, getReferenceVariableValue, centralizes the logic for resolving reference variables. Related test cases and exports are updated to support and verify this new asynchronous and unified approach.

Changes

File(s) Change Summary
apps/webservice/src/app/api/v1/resources/[resourceId]/route.ts Refactored the GET handler to asynchronously resolve resource variables, using getReferenceVariableValue for reference-type variables and supporting decryption for direct values.
apps/webservice/src/app/api/v1/workspaces/[workspaceId]/resources/identifier/[identifier]/route.ts Refactored variable resolution to be asynchronous and centralized using getReferenceVariableValue, removing manual nested lookups and lodash usage.
e2e/tests/api/resource-variables.spec.ts Updated test to normalize system prefix, use dynamic version strings, and adjust variable reference paths for consistency with new variable resolution logic.
packages/api/src/router/resources.ts Refactored the byId query handler to an async function, resolving reference variables asynchronously via getReferenceVariableValue and removing manual metadata/relationship logic.
packages/rule-engine/src/index.ts Added export for all public members from manager/variables/resolve-reference-variable.js, making the new reference variable resolver available.
packages/rule-engine/src/manager/variables/resolve-reference-variable.ts Introduced new async function getReferenceVariableValue to resolve reference resource variables, handling both attribute and metadata lookups, and returning default values when necessary.

Sequence Diagram(s)

sequenceDiagram
    participant API_Handler as API Handler (GET Resource)
    participant DB as Database
    participant RuleEngine as Rule Engine
    participant ReferenceResolver as getReferenceVariableValue

    API_Handler->>DB: Fetch resource by ID
    API_Handler->>DB: Fetch resource relationships
    loop For each variable
        alt valueType == "direct"
            API_Handler->>API_Handler: Decrypt or use raw value
        else valueType == "reference"
            API_Handler->>ReferenceResolver: getReferenceVariableValue(variable)
            ReferenceResolver->>DB: Fetch parent relationships & metadata
            ReferenceResolver-->>API_Handler: Resolved value or default
        else
            API_Handler->>API_Handler: Use default value
        end
    end
    API_Handler->>API_Handler: Construct variables object
    API_Handler-->>Client: Return resource with resolved variables
Loading

Suggested reviewers

  • jsbroks

Poem

In the warren of code, a new path appears,
Async bunnies hop, resolving all fears.
Reference or direct, they decrypt and they fetch,
With a promise or two, the right value they catch.
Now resources shine, with variables anew—
🐇 Hurrah for the clever things rabbits can do!

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 465f399 and 01b641f.

📒 Files selected for processing (1)
  • packages/rule-engine/src/manager/variables/resolve-reference-variable.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/rule-engine/src/manager/variables/resolve-reference-variable.ts
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Lint
  • GitHub Check: Typecheck
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/amd64)
✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 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.

Support

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

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.

@adityachoudhari26 adityachoudhari26 changed the title Reference variable working test fix: reference variable working test May 10, 2025
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

🧹 Nitpick comments (2)
packages/rule-engine/src/manager/variables/resolve-reference-variable.ts (1)

22-23: Review the use of _.get with an empty path array

Using _.get with an empty path array ([]) is unusual and may not behave as expected. It's unclear what value this is intended to retrieve from targetResource when the path is empty.

Consider simplifying this to directly use the target resource or clarify the intent:

- const resolvedValue = _.get(targetResource, [], variable.defaultValue);
+ const resolvedValue = targetResource || variable.defaultValue;
apps/webservice/src/app/api/v1/resources/[resourceId]/route.ts (1)

61-78: Consider adding error handling for async variable resolution

The implementation correctly handles different variable types and asynchronously resolves reference variables. However, there's no specific error handling for the async resolution process.

Consider adding try/catch blocks to handle potential errors in reference variable resolution:

 const variablesPromises = data.variables.map(async (v) => {
   if (v.valueType === "direct") {
     const strval = String(v.value);
     const value = v.sensitive
       ? variablesAES256().decrypt(strval)
       : v.value;
     return [v.key, value] as const;
   }

   if (v.valueType === "reference") {
+    try {
       const resolvedValue = await getReferenceVariableValue(
         v as schema.ReferenceResourceVariable,
       );
       return [v.key, resolvedValue] as const;
+    } catch (error) {
+      log.error(`Error resolving reference variable ${v.key}: ${error}`);
+      return [v.key, v.defaultValue] as const;
+    }
   }

   return [v.key, v.defaultValue] as const;
 });
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16d1b10 and f50ceca.

📒 Files selected for processing (6)
  • apps/webservice/src/app/api/v1/resources/[resourceId]/route.ts (2 hunks)
  • apps/webservice/src/app/api/v1/workspaces/[workspaceId]/resources/identifier/[identifier]/route.ts (2 hunks)
  • e2e/tests/api/resource-variables.spec.ts (5 hunks)
  • packages/api/src/router/resources.ts (3 hunks)
  • packages/rule-engine/src/index.ts (1 hunks)
  • packages/rule-engine/src/manager/variables/resolve-reference-variable.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{ts,tsx}`: **Note on Error Handling:** Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error...

**/*.{ts,tsx}: Note on Error Handling:
Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error handling. These are acceptable as long as they maintain clarity and predictability.

  • packages/rule-engine/src/index.ts
  • e2e/tests/api/resource-variables.spec.ts
  • apps/webservice/src/app/api/v1/workspaces/[workspaceId]/resources/identifier/[identifier]/route.ts
  • packages/api/src/router/resources.ts
  • apps/webservice/src/app/api/v1/resources/[resourceId]/route.ts
  • packages/rule-engine/src/manager/variables/resolve-reference-variable.ts
🧬 Code Graph Analysis (1)
apps/webservice/src/app/api/v1/resources/[resourceId]/route.ts (2)
packages/rule-engine/src/manager/variables/resolve-reference-variable.ts (1)
  • getReferenceVariableValue (7-29)
packages/db/src/schema/resource.ts (1)
  • ReferenceResourceVariable (514-514)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Typecheck
  • GitHub Check: Lint
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/amd64)
🔇 Additional comments (7)
packages/rule-engine/src/manager/variables/resolve-reference-variable.ts (1)

7-29: Well-structured implementation of reference variable resolution

The function correctly handles the resolution of reference variables by:

  1. Retrieving the resource relationships and metadata
  2. Finding the target resource based on the reference
  3. Gracefully handling missing resources or values with defaults
  4. Supporting both direct resource lookup and metadata path lookup
packages/rule-engine/src/index.ts (1)

8-8: Proper export of the new utility function

The new export correctly makes the getReferenceVariableValue function available to other modules, maintaining consistency with existing export patterns.

e2e/tests/api/resource-variables.spec.ts (3)

179-181: Case normalization improves consistency

Converting systemPrefix to lowercase ensures consistent matching of keys and references throughout the test, which helps prevent case-sensitive comparison issues.


190-190: Dynamic versioning improves test robustness

Replacing hardcoded version strings with dynamic versions based on the system prefix makes the tests more maintainable and adaptable to different test environments.

Also applies to: 208-208, 234-234, 236-236


218-218: Path simplification aligns with new implementation

Changing the path from ["metadata", "e2e-test"] to ["e2e-test"] correctly aligns with how the new getReferenceVariableValue function processes paths for metadata lookup.

apps/webservice/src/app/api/v1/resources/[resourceId]/route.ts (2)

70-75: Proper integration of async reference variable resolution

The integration of the getReferenceVariableValue function correctly handles reference-type variables, properly casting the variable to the expected type and resolving it asynchronously.


80-82: Efficient parallel resolution with Promise.all

Using Promise.all to resolve all variable promises in parallel is an efficient approach that maintains good performance while handling async operations.

Comment on lines +79 to +94
const resourceVariablesPromises = resource.variables.map(async (v) => {
if (v.valueType === "direct") {
const strval = String(v.value);
const value = v.sensitive ? variablesAES256().decrypt(strval) : v.value;
return [v.key, value] as const;
}

if (v.valueType === "reference") {
const resolvedValue = await getReferenceVariableValue(
v as schema.ReferenceResourceVariable,
);
return [v.key, resolvedValue] as const;
}

return [v.key, v.defaultValue] as const;
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add defensive handling when resolving reference variables

getReferenceVariableValue likely performs DB look-ups.
If it throws (e.g., broken relationship, missing target, DB timeout) the whole handler will bubble a 500 response and the caller receives no partial data, even though we have a sensible defaultValue on the variable object.

Consider wrapping the call in a try / catch and falling back to v.defaultValue while logging the incident for observability:

-      if (v.valueType === "reference") {
-        const resolvedValue = await getReferenceVariableValue(
-          v as schema.ReferenceResourceVariable,
-        );
-        return [v.key, resolvedValue] as const;
-      }
+      if (v.valueType === "reference") {
+        try {
+          const resolvedValue = await getReferenceVariableValue(
+            v as schema.ReferenceResourceVariable,
+          );
+          return [v.key, resolvedValue ?? v.defaultValue] as const;
+        } catch (err) {
+          // TODO: use your structured/logger instead of console
+          console.error(
+            `Failed to resolve reference variable '${v.key}' for resource ${resource.id}:`,
+            err,
+          );
+          return [v.key, v.defaultValue] as const;
+        }
+      }

This keeps the endpoint resilient and prevents a single bad reference from breaking the entire response.

Comment on lines +413 to +418
const resolvedReferenceVariables = await Promise.all(
referenceVariables.map(async (v) => {
const resolvedValue = await getReferenceVariableValue(v);
return { ...v, resolvedValue };
}),
),
);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Gracefully degrade when a reference variable cannot be resolved

Same resilience comment as for the REST handler: a single failing reference resolution should not break the whole response.
Wrap getReferenceVariableValue in a try / catch, log the error, and fall back to v.defaultValue (or null) so the API remains predictable.

Comment on lines +404 to +407
const directVariables = parsedVariables.filter(
(v): v is schema.DirectResourceVariable => v.valueType === "direct",
);

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Sensitive direct variables are returned encrypted

In the webservice route (apps/webservice/.../route.ts) direct variables are decrypted:

const value = v.sensitive ? variablesAES256().decrypt(strval) : v.value;

The TRPC byId query, however, forwards the cipher-text as-is.
Clients depending on byId will now receive different payloads than the REST handler, and, even worse, may inadvertently expose encrypted secrets in logs/UI.

Proposed fix:

+import { variablesAES256 } from "@ctrlplane/secrets";
...
-      const directVariables = parsedVariables.filter(
-        (v): v is schema.DirectResourceVariable => v.valueType === "direct",
-      );
+      const directVariables = parsedVariables
+        .filter(
+          (v): v is schema.DirectResourceVariable => v.valueType === "direct",
+        )
+        .map((v) => ({
+          ...v,
+          resolvedValue: v.sensitive
+            ? variablesAES256().decrypt(String(v.value))
+            : v.value,
+        }));

This aligns both endpoints, avoids leaking cipher-text, and gives callers a uniform resolvedValue shape similar to reference variables.

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 (2)
packages/rule-engine/src/manager/variables/resolve-reference-variable.ts (2)

1-6: Consider adding function documentation

Adding JSDoc comments to describe the function's purpose, parameters, and return value would improve maintainability and make the API clearer to other developers.

 import { getResourceParents } from "@ctrlplane/db/queries";
 
+/**
+ * Resolves the value of a reference resource variable by looking up the relationship target
+ * and retrieving the value at the specified path.
+ * 
+ * @param variable - The reference variable containing resourceId, reference, path, and defaultValue
+ * @returns The resolved value from the target resource or the default value if not found
+ */
 export const getReferenceVariableValue = async (

4-5: Consider dependency injection for better testability

The function currently depends on the global db client, which makes unit testing more difficult. Consider accepting the database client as a parameter for better testability and modularity.

 import { db } from "@ctrlplane/db/client";
 import { getResourceParents } from "@ctrlplane/db/queries";
 
-export const getReferenceVariableValue = async (
+export const getReferenceVariableValue = async (
+  dbClient = db,
   variable: schema.ReferenceResourceVariable,
 ) => {
   const { relationships, getTargetsWithMetadata } = await getResourceParents(
-    db,
+    dbClient,
     variable.resourceId,
   );
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f50ceca and 465f399.

📒 Files selected for processing (2)
  • e2e/tests/api/resource-variables.spec.ts (4 hunks)
  • packages/rule-engine/src/manager/variables/resolve-reference-variable.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • e2e/tests/api/resource-variables.spec.ts
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{ts,tsx}`: **Note on Error Handling:** Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error...

**/*.{ts,tsx}: Note on Error Handling:
Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error handling. These are acceptable as long as they maintain clarity and predictability.

  • packages/rule-engine/src/manager/variables/resolve-reference-variable.ts
🧬 Code Graph Analysis (1)
packages/rule-engine/src/manager/variables/resolve-reference-variable.ts (3)
packages/db/src/schema/resource.ts (1)
  • ReferenceResourceVariable (514-514)
packages/db/src/queries/get-resource-parents.ts (1)
  • getResourceParents (13-153)
packages/db/src/client.ts (1)
  • db (15-15)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Typecheck
  • GitHub Check: build (linux/amd64)
  • GitHub Check: Lint
  • GitHub Check: build (linux/amd64)
🔇 Additional comments (2)
packages/rule-engine/src/manager/variables/resolve-reference-variable.ts (2)

7-21: Well-structured implementation of reference variable resolution

The function correctly implements asynchronous resolution of reference variables by:

  1. Querying resource parents and their metadata
  2. Identifying the target resource based on the reference relationship
  3. Retrieving the value at the specified path, with appropriate fallback to default value

16-18: Good use of nullish coalescing and early return pattern

The code correctly handles potential null/undefined values with the nullish coalescing operator and early return, making the logic clear and defensive.

@adityachoudhari26 adityachoudhari26 merged commit ccb7baf into main May 10, 2025
5 of 7 checks passed
@adityachoudhari26 adityachoudhari26 deleted the reference-variable-working-test branch May 10, 2025 05:39
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