Skip to content

Fix: resource blocks console#2949

Merged
HarshMN2345 merged 2 commits intomainfrom
fix-resource-blocks-console
Mar 31, 2026
Merged

Fix: resource blocks console#2949
HarshMN2345 merged 2 commits intomainfrom
fix-resource-blocks-console

Conversation

@HarshMN2345
Copy link
Copy Markdown
Member

@HarshMN2345 HarshMN2345 commented Mar 31, 2026

What does this PR do?

(Provide a description of what this PR does.)

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work.)

Related PRs and Issues

(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)

Have you read the Contributing Guidelines on issues?

(Write your answer here.)

Summary by CodeRabbit

  • New Features

    • Added enhanced access control validations for teams, users, databases, tables, functions, messages, providers, topics, sites, buckets, and files to improve resource management across projects.
  • Chores

    • Updated documentation formatting for consistency.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

Walkthrough

This pull request introduces a resource-blocking authorization system and applies it across multiple routes. It adds three new functions to src/lib/helpers/project.ts: isProjectBlocked() (updated to detect global blocks via legacy or new formats), isResourceBlocked() (checks for matching blocks by type and ID), and guardResourceBlock() (validates and throws 403 errors when blocked). The new guardResourceBlock() function is then integrated into 11 route layout files (teams, users, databases, tables, functions, messages, messaging providers, messaging topics, sites, buckets, and files), where each route's load function now accepts a parent callback, retrieves the project context, and calls the guard with its respective resource type before returning data. Minor formatting adjustments are made to AGENTS.md and CLAUDE.md.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix: resource blocks console' is specific and directly related to the main changes, which involve adding resource blocking functionality to multiple console route handlers.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-resource-blocks-console

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.

@HarshMN2345 HarshMN2345 requested a review from ChiragAgg5k March 31, 2026 13:02
Copy link
Copy Markdown
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.

🧹 Nitpick comments (3)
src/lib/helpers/project.ts (2)

65-79: Missing validation for empty resourceId parameter.

If resourceId is an empty string, normalizedId.trim() will be "", and isResourceBlocked will attempt to match a block with an empty ID. This could lead to unexpected behavior if callers pass falsy values. Consider adding early-return guard:

🛡️ Proposed defensive check
 export function isResourceBlocked(
     project: Models.Project | null | undefined,
     resourceType: string,
     resourceId: string
 ): boolean {
     const normalizedType = resourceType.trim().toLowerCase();
     const normalizedId = resourceId.trim();
+
+    if (!normalizedType || !normalizedId) {
+        return false;
+    }

     return (project?.blocks ?? []).some((block) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/helpers/project.ts` around lines 65 - 79, The function
isResourceBlocked currently normalizes resourceId but doesn't guard against an
empty string, allowing matches against empty IDs; update isResourceBlocked to
trim and normalize resourceId first and if the resulting normalizedId is an
empty string (or falsy) return false immediately before iterating blocks (leave
normalization of resourceType as-is), so callers passing an empty or whitespace
resourceId cannot incorrectly match a block.

81-95: Guard function uses error() which throws - ensure callers handle appropriately.

The guardResourceBlock function calls SvelteKit's error(403, ...) which throws an exception. This is the correct pattern for SvelteKit load functions. However, the function signature doesn't indicate it throws (no never return type for the blocked path).

Additionally, the function lacks a return statement after the guard check - this is fine since error() throws, but adding an explicit return type annotation would improve clarity:

📝 Consider explicit return type
 export function guardResourceBlock(
     project: Models.Project | null | undefined,
     resourceType: string | string[],
     resourceId: string
-) {
+): void {
     const resourceTypes = Array.isArray(resourceType) ? resourceType : [resourceType];
     const isBlocked = resourceTypes.some((type) => isResourceBlocked(project, type, resourceId));

     if (isBlocked) {
         error(403, {
             type: 'general_resource_blocked',
             message: 'This resource page cannot be accessed.'
         });
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/helpers/project.ts` around lines 81 - 95, guardResourceBlock calls
SvelteKit's error(...) which throws; update the function signature for
guardResourceBlock to include an explicit return type (e.g., ": void") and add a
brief JSDoc noting it will throw a 403 via error(...) when
isResourceBlocked(...) returns true so callers (load functions) can handle that
exception; keep the existing call to error(...) and the use of isResourceBlocked
and resourceTypes unchanged.
src/routes/(console)/project-[region]-[project]/auth/user-[user]/+layout.ts (1)

11-11: Create a ResourceType enum for compile-time validation of resource type strings.

The guardResourceBlock function accepts resourceType as an untyped string parameter. While isResourceBlocked normalizes the type string with trim().toLowerCase(), it performs strict equality comparison (type === normalizedType). A typo like 'user' instead of 'users' would pass compilation, be normalized to 'user', then silently fail to match the actual block data containing 'users', allowing a blocked resource to be accessed undetected.

Defining a ResourceType enum in $lib/helpers/project.ts with the values used across all layout files ('users', 'sites', 'databases', 'topics', 'tables', 'collections', 'providers', 'messages', 'buckets', 'files', 'functions', 'teams') would provide compile-time safety across all 11 call sites.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/`(console)/project-[region]-[project]/auth/user-[user]/+layout.ts
at line 11, The call to guardResourceBlock(project, 'users', params.user) (and
other similar calls) uses raw strings for resourceType which allows typos like
'user' to compile but fail matching at runtime; to fix, add a ResourceType enum
in $lib/helpers/project.ts containing the canonical values
('users','sites','databases','topics','tables','collections','providers','messages','buckets','files','functions','teams'),
change guardResourceBlock and isResourceBlocked to accept ResourceType (or a
typed alias) instead of string, and update all 11 call sites to pass
ResourceType.<...> enum members (e.g., ResourceType.Users) so the compiler
enforces correct resource type names and prevents silent mismatches in
isResourceBlocked and guardResourceBlock.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/lib/helpers/project.ts`:
- Around line 65-79: The function isResourceBlocked currently normalizes
resourceId but doesn't guard against an empty string, allowing matches against
empty IDs; update isResourceBlocked to trim and normalize resourceId first and
if the resulting normalizedId is an empty string (or falsy) return false
immediately before iterating blocks (leave normalization of resourceType as-is),
so callers passing an empty or whitespace resourceId cannot incorrectly match a
block.
- Around line 81-95: guardResourceBlock calls SvelteKit's error(...) which
throws; update the function signature for guardResourceBlock to include an
explicit return type (e.g., ": void") and add a brief JSDoc noting it will throw
a 403 via error(...) when isResourceBlocked(...) returns true so callers (load
functions) can handle that exception; keep the existing call to error(...) and
the use of isResourceBlocked and resourceTypes unchanged.

In `@src/routes/`(console)/project-[region]-[project]/auth/user-[user]/+layout.ts:
- Line 11: The call to guardResourceBlock(project, 'users', params.user) (and
other similar calls) uses raw strings for resourceType which allows typos like
'user' to compile but fail matching at runtime; to fix, add a ResourceType enum
in $lib/helpers/project.ts containing the canonical values
('users','sites','databases','topics','tables','collections','providers','messages','buckets','files','functions','teams'),
change guardResourceBlock and isResourceBlocked to accept ResourceType (or a
typed alias) instead of string, and update all 11 call sites to pass
ResourceType.<...> enum members (e.g., ResourceType.Users) so the compiler
enforces correct resource type names and prevents silent mismatches in
isResourceBlocked and guardResourceBlock.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 40a40f3b-0f6b-4f4a-854b-ab6eb7f305b7

📥 Commits

Reviewing files that changed from the base of the PR and between ff79de3 and 0a89a98.

📒 Files selected for processing (14)
  • AGENTS.md
  • CLAUDE.md
  • src/lib/helpers/project.ts
  • src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/auth/user-[user]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/functions/function-[function]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/messaging/message-[message]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/messaging/providers/provider-[provider]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/messaging/topics/topic-[topic]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/sites/site-[site]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+layout.ts
  • src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/file-[file]/+layout.ts

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 31, 2026

Greptile Summary

This PR fixes a bug where any resource-level block (e.g. a blocked bucket or function) was incorrectly causing the entire project console to show the "Project is currently blocked" overlay. The root cause was that isProjectBlocked previously returned true whenever project.blocks had any entries, regardless of whether those entries were project-global or resource-specific.

What changed:

  • isProjectBlocked now only returns true for global project blocks (legacy empty-type/id blocks, or resourceType === 'projects' with no resourceId), fixing the false-positive console block.
  • Two new helpers — isResourceBlocked and guardResourceBlock — implement per-resource access control by throwing a SvelteKit error(403, { type: 'general_resource_blocked', ... }).
  • guardResourceBlock is wired into 11 +layout.ts load functions (teams, users, databases, tables/collections, functions, messages, providers, topics, sites, buckets, files), each calling parent() to retrieve the project and checking the relevant resource ID before making any SDK calls.
  • The +error.svelte already handles general_resource_blocked with a dedicated "Access blocked" UI, confirming this was a pre-planned integration.
  • Cosmetic: trailing spaces trimmed in AGENTS.md table; blank line added in CLAUDE.md.

Key observations:

  • isResourceBlocked does not include the status !== 'paused' guard that isProjectBlocked has, which could cause a 403 error page to appear instead of the paused-project overlay for paused projects that also have resource-level blocks.
  • The resource-type strings passed to guardResourceBlock ('teams', 'buckets', 'files', etc.) are hardcoded across 11 call-sites; if the backend uses different casing or naming they will silently fail.

Confidence Score: 5/5

Safe to merge — the core logic is correct, the error-page integration was already in place, and both findings are P2 quality-of-life concerns rather than present defects.

All findings are P2: (1) the missing status !== 'paused' guard in isResourceBlocked is an edge-case UX inconsistency that would only manifest for paused projects that also carry resource-level blocks; (2) the hardcoded resource-type strings are a maintainability concern, not a correctness bug. No P0/P1 issues were found.

src/lib/helpers/project.ts — the two new exported helpers are the heart of the change and warrant attention for the paused-status guard and resource-type string hardcoding.

Important Files Changed

Filename Overview
src/lib/helpers/project.ts Core fix: isProjectBlocked now only fires on global-level blocks (not resource-specific ones); two new helpers isResourceBlocked and guardResourceBlock added for per-resource access control — isResourceBlocked lacks the status !== 'paused' guard that isProjectBlocked has.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.ts Guards table/collection resources using both 'tables' and 'collections' resource types to cover both database backends.
src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/+layout.ts Adds guardResourceBlock for teams; uses parent() to obtain project and throws 403 before SDK fetch if the team is blocked.
src/routes/(console)/project-[region]-[project]/auth/user-[user]/+layout.ts Adds guardResourceBlock for users; correctly placed before the Promise.all SDK calls.
src/routes/(console)/project-[region]-[project]/functions/function-[function]/+layout.ts Adds guardResourceBlock for functions; placed after depends() registrations and before SDK calls.
src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.ts Adds guardResourceBlock for databases; early-exits before the tablesDB.get() call when blocked.
src/routes/(console)/project-[region]-[project]/messaging/message-[message]/+layout.ts Adds guardResourceBlock for messages.
src/routes/(console)/project-[region]-[project]/messaging/providers/provider-[provider]/+layout.ts Adds guardResourceBlock for messaging providers.
src/routes/(console)/project-[region]-[project]/messaging/topics/topic-[topic]/+layout.ts Adds guardResourceBlock for messaging topics.
src/routes/(console)/project-[region]-[project]/sites/site-[site]/+layout.ts Adds guardResourceBlock for sites.
src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+layout.ts Adds guardResourceBlock for storage buckets.
src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/file-[file]/+layout.ts Adds guardResourceBlock for individual files within a bucket.
AGENTS.md Cosmetic: trailing spaces removed from a markdown table's Status column.
CLAUDE.md Cosmetic: blank line added before @AGENTS.md directive.

Reviews (1): Last reviewed commit: "can be projects too" | Re-trigger Greptile

Comment on lines +65 to +78
export function isResourceBlocked(
project: Models.Project | null | undefined,
resourceType: string,
resourceId: string
): boolean {
const normalizedType = resourceType.trim().toLowerCase();
const normalizedId = resourceId.trim();

return (project?.blocks ?? []).some((block) => {
const type = block.resourceType?.trim().toLowerCase();
const id = block.resourceId?.trim();

return type === normalizedType && id === normalizedId;
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 isResourceBlocked skips the paused-project guard

isProjectBlocked explicitly returns false for paused projects (project?.status !== 'paused') so that the "project paused" overlay is shown instead of the blocked-project overlay. isResourceBlocked has no equivalent guard, so a paused project that also carries a resource-level block will trigger a 403 error page instead of the paused overlay when a user navigates to that resource.

If paused projects should never surface resource-level 403s (and let the parent layout's paused UI take over), consider mirroring the status guard:

export function isResourceBlocked(
    project: Models.Project | null | undefined,
    resourceType: string,
    resourceId: string
): boolean {
    if (project?.status === 'paused') return false;

    const normalizedType = resourceType.trim().toLowerCase();
    const normalizedId = resourceId.trim();

    return (project?.blocks ?? []).some((block) => {
        const type = block.resourceType?.trim().toLowerCase();
        const id = block.resourceId?.trim();

        return type === normalizedType && id === normalizedId;
    });
}

Comment on lines +81 to 95
export function guardResourceBlock(
project: Models.Project | null | undefined,
resourceType: string | string[],
resourceId: string
) {
const resourceTypes = Array.isArray(resourceType) ? resourceType : [resourceType];
const isBlocked = resourceTypes.some((type) => isResourceBlocked(project, type, resourceId));

if (isBlocked) {
error(403, {
type: 'general_resource_blocked',
message: 'This resource page cannot be accessed.'
});
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Hardcoded resource-type strings need to match backend values exactly

The resource type strings passed to guardResourceBlock across all layout files ('teams', 'users', 'databases', 'functions', 'buckets', 'files', 'messages', 'providers', 'topics', 'sites', 'tables', 'collections') are compared case-insensitively against block.resourceType. If the backend sends different casing or naming, the check silently passes and the block is never enforced.

Consider centralising these strings in an enum or const object alongside Dependencies in $lib/constants, e.g.:

export const BlockResourceType = {
    TEAMS: 'teams',
    USERS: 'users',
    DATABASES: 'databases',
    FUNCTIONS: 'functions',
    BUCKETS: 'buckets',
    FILES: 'files',
    MESSAGES: 'messages',
    PROVIDERS: 'providers',
    TOPICS: 'topics',
    SITES: 'sites',
    TABLES: 'tables',
    COLLECTIONS: 'collections',
} as const;

This makes them easy to audit against the API contract and prevents typos across the 11 call-sites.

@HarshMN2345 HarshMN2345 merged commit 767a0f6 into main Mar 31, 2026
5 checks passed
@HarshMN2345 HarshMN2345 deleted the fix-resource-blocks-console branch March 31, 2026 13:07
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