Skip to content

Conversation

@nikochiko
Copy link
Member

Q/A checklist

  • I have tested my UI changes on mobile and they look acceptable
  • I have tested changes to the workflows in both the API and the UI
  • I have done a code review of my changes and looked at each line of the diff + the references of each function I have changed
  • My changes have not increased the import time of the server
How to check import time?

time python -c 'import server'

You can visualize this using tuna:

python3 -X importtime -c 'import server' 2> out.log && tuna out.log

To measure import time for a specific library:

$ time python -c 'import pandas'

________________________________________________________
Executed in    1.15 secs    fish           external
   usr time    2.22 secs   86.00 micros    2.22 secs
   sys time    0.72 secs  613.00 micros    0.72 secs

To reduce import times, import libraries that take a long time inside the functions that use them instead of at the top of the file:

def my_function():
    import pandas as pd
    ...

Legal Boilerplate

Look, I get it. The entity doing business as “Gooey.AI” and/or “Dara.network” was incorporated in the State of Delaware in 2020 as Dara Network Inc. and is gonna need some rights from me in order to utilize my contributions in this PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Dara Network Inc can use, modify, copy, and redistribute my contributions, under its choice of terms.

@coderabbitai
Copy link

coderabbitai bot commented Jul 3, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces user authorization logic to the BasePage class in daras_ai_v2/base.py by adding methods to check if a user is authorized to access a resource. The render method is modified to enforce authorization, returning early with a lock icon and access instructions if the user is unauthorized. Imports for text formatting and workspace subscription checks are added. Method signatures are updated with type hints and query optimizations. In daras_ai_v2/meta_content.py, the robots_tag_for_page function is changed to set nofollow and noindex flags if the page is unauthorized for anonymous users before applying existing tab-based logic. An unused conditional block is removed from recipes/VideoBots.py.

Possibly related PRs

Suggested reviewers

  • devxpy

📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d98bab7 and da3632c.

📒 Files selected for processing (1)
  • daras_ai_v2/base.py (6 hunks)
✨ 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

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.

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0ffb603 and bd330bf.

📒 Files selected for processing (1)
  • daras_ai_v2/base.py (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Analyze (python)
  • GitHub Check: test (3.10.12, 1.8.3)
🔇 Additional comments (2)
daras_ai_v2/base.py (2)

7-7: LGTM - Import addition is correct.

The dedent import is appropriately added for text formatting in the unauthorized message.


398-402: Excellent security implementation with early authorization check.

The early authorization check with immediate return is a best practice for security. This prevents unauthorized users from accessing any workflow data or functionality.

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: 1

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between bd330bf and df0ef47.

📒 Files selected for processing (3)
  • app_users/models.py (2 hunks)
  • daras_ai_v2/base.py (6 hunks)
  • daras_ai_v2/meta_content.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • daras_ai_v2/base.py
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: nikochiko
PR: GooeyAI/gooey-server#725
File: daras_ai_v2/base.py:343-376
Timestamp: 2025-07-04T07:34:01.107Z
Learning: In the Gooey.AI codebase, `pr.public_access` field is guaranteed to be non-null by database constraints, so null checks are not needed when accessing this field or converting it to WorkflowAccessLevel.
Learnt from: nikochiko
PR: GooeyAI/gooey-server#725
File: daras_ai_v2/base.py:343-376
Timestamp: 2025-07-04T07:34:01.107Z
Learning: In the Gooey.AI codebase, `pr.public_access` field is guaranteed to be non-null by database constraints (IntegerField with default value), so null checks are not needed when accessing this field or converting it to WorkflowAccessLevel.
🧬 Code Graph Analysis (1)
app_users/models.py (1)
workspaces/models.py (2)
  • Workspace (105-449)
  • WorkspaceMembership (452-535)
⏰ 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). (4)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (actions)
  • GitHub Check: Analyze (python)
  • GitHub Check: test (3.10.12, 1.8.3)
🔇 Additional comments (3)
daras_ai_v2/meta_content.py (1)

220-238: LGTM! Excellent security enhancement for search engine indexing.

The authorization check for anonymous users is well-implemented and aligns perfectly with the PR objectives. By checking page.is_user_authorized(None) first, the function ensures that private workflows are not indexed or followed by search engines, which is crucial for maintaining access control consistency.

The early return pattern with nofollow and noindex flags set to True for unauthorized pages is a solid defensive approach that prevents search engines from accessing content that anonymous users cannot view.

app_users/models.py (2)

19-19: LGTM - Import addition supports new functionality.

The addition of WorkspaceMembership to the import is necessary for the new cached_memberships property.


243-243: LGTM - Refactoring supports membership-based authorization.

The refactoring to derive workspaces from cached_memberships is logical and enables access to both workspace and membership data needed for authorization checks.

Comment on lines 245 to 259
@cached_property
def cached_memberships(self) -> dict[int, "WorkspaceMembership"]:
from workspaces.models import WorkspaceMembership

memberships = (
WorkspaceMembership.objects.select_related("workspace")
.filter(user=self, workspace__deleted__isnull=True)
.order_by("-workspace__is_personal", "-workspace__created_at")
)
if not memberships:
self.get_or_create_personal_workspace()
memberships = memberships.all() # refresh
assert memberships

return list(
Workspace.objects.filter(
memberships__user=self, memberships__deleted__isnull=True
).order_by("-is_personal", "-created_at")
) or [self.get_or_create_personal_workspace()[0]]
return {m.workspace.id: m for m in memberships}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize queryset refresh pattern and improve error handling.

The implementation has a few areas for improvement:

  1. Inefficient queryset refresh: The memberships.all() call forces unnecessary queryset evaluation just to refresh the queryset.
  2. Production-unsafe assertion: The assert statement could cause issues in production if the assumption fails.
  3. Ordering consideration: The ordering by workspace__created_at sorts by workspace creation date, not membership join date - verify this is intended.

Apply this diff to optimize the queryset handling and improve error handling:

-        if not memberships:
-            self.get_or_create_personal_workspace()
-            memberships = memberships.all()  # refresh
-            assert memberships
+        if not memberships.exists():
+            self.get_or_create_personal_workspace()
+            # Re-query to include the newly created membership
+            memberships = (
+                WorkspaceMembership.objects.select_related("workspace")
+                .filter(user=self, workspace__deleted__isnull=True)
+                .order_by("-workspace__is_personal", "-workspace__created_at")
+            )
+            if not memberships.exists():
+                raise ValueError("Failed to create personal workspace membership")

This change:

  • Uses exists() to check membership presence without forcing evaluation
  • Re-queries instead of relying on queryset refresh
  • Replaces assert with a proper exception that provides better error context
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@cached_property
def cached_memberships(self) -> dict[int, "WorkspaceMembership"]:
from workspaces.models import WorkspaceMembership
memberships = (
WorkspaceMembership.objects.select_related("workspace")
.filter(user=self, workspace__deleted__isnull=True)
.order_by("-workspace__is_personal", "-workspace__created_at")
)
if not memberships:
self.get_or_create_personal_workspace()
memberships = memberships.all() # refresh
assert memberships
return list(
Workspace.objects.filter(
memberships__user=self, memberships__deleted__isnull=True
).order_by("-is_personal", "-created_at")
) or [self.get_or_create_personal_workspace()[0]]
return {m.workspace.id: m for m in memberships}
@cached_property
def cached_memberships(self) -> dict[int, "WorkspaceMembership"]:
from workspaces.models import WorkspaceMembership
memberships = (
WorkspaceMembership.objects.select_related("workspace")
.filter(user=self, workspace__deleted__isnull=True)
.order_by("-workspace__is_personal", "-workspace__created_at")
)
if not memberships.exists():
self.get_or_create_personal_workspace()
# Re-query to include the newly created membership
memberships = (
WorkspaceMembership.objects.select_related("workspace")
.filter(user=self, workspace__deleted__isnull=True)
.order_by("-workspace__is_personal", "-workspace__created_at")
)
if not memberships.exists():
raise ValueError("Failed to create personal workspace membership")
return {m.workspace.id: m for m in memberships}
🤖 Prompt for AI Agents
In app_users/models.py around lines 245 to 259, the current method inefficiently
refreshes the queryset by calling memberships.all() and uses an assert statement
that is unsafe for production. To fix this, replace the check for memberships
with memberships.exists() to avoid unnecessary evaluation, then re-query the
memberships after creating the personal workspace instead of refreshing the old
queryset. Also, replace the assert statement with a proper exception that
clearly indicates the failure to retrieve memberships, providing better error
handling and context.


membership = user and user.cached_memberships.get(pr.workspace_id, None)
role = membership and WorkspaceRole(membership.role)
match pr.workspace_access, role:
Copy link
Member

@devxpy devxpy Jul 12, 2025

Choose a reason for hiding this comment

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

i believe all members should be able to see any run in their workspace including WorkflowAccessLevel.VIEW_ONLY ones. especially because we also dont really have a mechanism for an admin to grant access to a member

@nikochiko
Copy link
Member Author

done! @devxpy

@nikochiko nikochiko requested review from devxpy July 14, 2025 13:23
@nikochiko nikochiko assigned devxpy and unassigned nikochiko Jul 14, 2025
@nikochiko nikochiko merged commit 85e5cd1 into master Jul 15, 2025
3 of 4 checks passed
@nikochiko nikochiko deleted the lockdown branch July 15, 2025 08:47
@coderabbitai coderabbitai bot mentioned this pull request Jul 17, 2025
4 tasks
@coderabbitai coderabbitai bot mentioned this pull request Aug 11, 2025
4 tasks
@coderabbitai coderabbitai bot mentioned this pull request Aug 26, 2025
4 tasks
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.

3 participants