Skip to content

Implement dashboard permissions validation and add end-to-end tests for dashboard access#1712

Merged
Artuomka merged 1 commit intomainfrom
backend_dashboards_permissions
Apr 9, 2026
Merged

Implement dashboard permissions validation and add end-to-end tests for dashboard access#1712
Artuomka merged 1 commit intomainfrom
backend_dashboards_permissions

Conversation

@Artuomka
Copy link
Copy Markdown
Collaborator

@Artuomka Artuomka commented Apr 9, 2026

Summary by CodeRabbit

  • New Features

    • Implemented granular per-dashboard permission validation for enhanced authorization control
    • Enhanced connection-level permission verification for improved access management
  • Tests

    • Added comprehensive end-to-end tests covering dashboard listing and read permission enforcement across multiple authorization scenarios

Copilot AI review requested due to automatic review settings April 9, 2026 09:34
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

This pull request extends dashboard operations with Cedar-based authorization enforcement. The find-all-dashboards use case now retrieves dashboards and filters them based per-dashboard Cedar authorization checks requiring userId. The dashboard-read guard additionally validates user connection membership when no specific dashboard ID is present. Comprehensive E2E tests validate the authorization behavior across various permission scenarios.

Changes

Cohort / File(s) Summary
Dashboard Authorization Logic
backend/src/entities/visualizations/dashboard/use-cases/find-all-dashboards.use.case.ts, backend/src/guards/dashboard-read.guard.ts
Integrated Cedar authorization checks into dashboard retrieval and access control. The use case now filters dashboards based on per-dashboard Cedar validation; the guard extends its control flow to check user connection membership when dashboard ID is absent.
Dashboard Permissions E2E Tests
backend/test/ava-tests/saas-tests/saas-dashboard-permissions-e2e.test.ts
New comprehensive test suite validating dashboard listing and read authorization via Cedar policies, covering user permission scenarios including empty results, permitted dashboards, and forbidden access cases.

Sequence Diagrams

sequenceDiagram
    participant Client
    participant UseCase as Find-All-Dashboards<br/>Use Case
    participant DB as Connection<br/>Repository
    participant Cedar as Cedar Auth<br/>Service
    participant Mapper as Dashboard<br/>Mapper

    Client->>UseCase: Request dashboards<br/>(connectionId, userId)
    UseCase->>DB: Get all dashboards<br/>for connection
    DB-->>UseCase: List of dashboards
    
    loop For each dashboard
        UseCase->>Cedar: Validate<br/>(DashboardRead,<br/>connectionId,<br/>dashboardId)
        Cedar-->>UseCase: Authorization<br/>result
        alt Authorized
            UseCase->>UseCase: Include in results
        else Not Authorized
            UseCase->>UseCase: Exclude from results
        end
    end
    
    UseCase->>Mapper: Convert to DTOs
    Mapper-->>UseCase: FoundDashboardDto[]
    UseCase-->>Client: Filtered dashboard list
Loading
sequenceDiagram
    participant Client
    participant Guard as Dashboard-Read<br/>Guard
    participant DB as Connection<br/>Repository
    participant Cedar as Cedar Auth<br/>Service

    Client->>Guard: Request (dashboardId,<br/>connectionId)
    
    alt dashboardId present
        Guard->>Cedar: Validate<br/>(DashboardRead)
        Cedar-->>Guard: Result
        alt Authorized
            Guard-->>Client: Allow
        else Not Authorized
            Guard-->>Client: ForbiddenException
        end
    else dashboardId missing
        Guard->>DB: Is user from<br/>connection?
        DB-->>Guard: Result
        alt User belongs
            Guard-->>Client: Allow
        else User excluded
            Guard-->>Client: ForbiddenException
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop hop, dashboards now align,
With Cedar's checks so fine,
Each user sees what they should see,
Authorization wild and free!
Permissions tested, locked up tight,
The rabbit built this right! 🔐

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Security Check ❓ Inconclusive Cannot verify guard logic and use-case implementation without access to the specified source files. Provide the current implementation files for DashboardReadGuard and FindAllDashboards use case for security review.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: implementing dashboard permissions validation logic and adding comprehensive end-to-end tests for dashboard access control.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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 backend_dashboards_permissions

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.

Copy link
Copy Markdown

@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

🧹 Nitpick comments (1)
backend/test/ava-tests/saas-tests/saas-dashboard-permissions-e2e.test.ts (1)

1-1: Clarify or remove the eslint-disable comment.

The @typescript-eslint/no-unused-vars disable comment appears to be for _testUtils on line 21, which is declared but not used in this test file. Consider either:

  1. Using _testUtils if needed for test utilities, or
  2. Removing both the variable declaration and the disable comment if it's not required.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/test/ava-tests/saas-tests/saas-dashboard-permissions-e2e.test.ts` at
line 1, Remove or clarify the unnecessary eslint-disable comment and the unused
variable: locate the top-of-file eslint directive "/* eslint-disable
`@typescript-eslint/no-unused-vars` */" and the unused symbol "_testUtils"
(declared around line 21) in the saas-dashboard-permissions-e2e.test.ts file;
either delete the eslint-disable line and the "_testUtils" declaration if the
helper is not needed, or instead keep "_testUtils" and actually use it in the
test to justify the ignore—ensure no other unused-vars disables remain and run
the linter to confirm the warning is resolved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/test/ava-tests/saas-tests/saas-dashboard-permissions-e2e.test.ts`:
- Around line 183-229: The failing CI is due to Biome formatting issues in this
test block; run the project's formatter (e.g., npx biome format --write or the
repo's format script) and reformat the file containing the test.serial block
(the test that uses
createConnectionsAndInviteNewUserInNewGroupWithTableDifferentConnectionGroupReadOnlyPermissions,
cedarPolicy, savePolicyResponse, listDashboards) so indentation, line breaks,
and spacing match the project's style, then stage and commit the formatted file.

---

Nitpick comments:
In `@backend/test/ava-tests/saas-tests/saas-dashboard-permissions-e2e.test.ts`:
- Line 1: Remove or clarify the unnecessary eslint-disable comment and the
unused variable: locate the top-of-file eslint directive "/* eslint-disable
`@typescript-eslint/no-unused-vars` */" and the unused symbol "_testUtils"
(declared around line 21) in the saas-dashboard-permissions-e2e.test.ts file;
either delete the eslint-disable line and the "_testUtils" declaration if the
helper is not needed, or instead keep "_testUtils" and actually use it in the
test to justify the ignore—ensure no other unused-vars disables remain and run
the linter to confirm the warning is resolved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f3ac0177-342f-467e-8745-50b106d3ba4c

📥 Commits

Reviewing files that changed from the base of the PR and between 2678ae6 and 19596fb.

📒 Files selected for processing (3)
  • backend/src/entities/visualizations/dashboard/use-cases/find-all-dashboards.use.case.ts
  • backend/src/guards/dashboard-read.guard.ts
  • backend/test/ava-tests/saas-tests/saas-dashboard-permissions-e2e.test.ts

Comment on lines +183 to +229
test.serial(
`${currentTest} should return empty array when user has no dashboard read permissions`,
async (t) => {
try {
const testData =
await createConnectionsAndInviteNewUserInNewGroupWithTableDifferentConnectionGroupReadOnlyPermissions(app);
const connectionId = testData.connections.firstId;
const groupId = testData.groups.createdGroupId;

// Admin creates a dashboard
const createDashboard = await request(app.getHttpServer())
.post(`/dashboards/${connectionId}`)
.send({ name: 'Hidden Dashboard' })
.set('Cookie', testData.users.adminUserToken)
.set('masterpwd', 'ahalaimahalai')
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(createDashboard.status, 201);

// Save cedar policy with connection read only, no dashboard permissions
const cedarPolicy = `permit(\n principal,\n action == RocketAdmin::Action::"connection:read",\n resource == RocketAdmin::Connection::"${connectionId}"\n);`;

const savePolicyResponse = await request(app.getHttpServer())
.post(`/connection/cedar-policy/${connectionId}`)
.send({ cedarPolicy, groupId })
.set('Cookie', testData.users.adminUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(savePolicyResponse.status, 201);

// Simple user lists dashboards — should get empty array
const listDashboards = await request(app.getHttpServer())
.get(`/dashboards/${connectionId}`)
.set('Cookie', testData.users.simpleUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(listDashboards.status, 200);
t.is(listDashboards.body.length, 0);
} catch (error) {
console.error(error);
throw error;
}
},
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix formatting to resolve pipeline failure.

The CI pipeline is failing due to Biome formatting issues in lines 181-263. Please run your formatter (e.g., npx biome format --write or equivalent project command) to fix the formatting discrepancies.

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

In `@backend/test/ava-tests/saas-tests/saas-dashboard-permissions-e2e.test.ts`
around lines 183 - 229, The failing CI is due to Biome formatting issues in this
test block; run the project's formatter (e.g., npx biome format --write or the
repo's format script) and reformat the file containing the test.serial block
(the test that uses
createConnectionsAndInviteNewUserInNewGroupWithTableDifferentConnectionGroupReadOnlyPermissions,
cedarPolicy, savePolicyResponse, listDashboards) so indentation, line breaks,
and spacing match the project's style, then stage and commit the formatted file.

@Artuomka Artuomka enabled auto-merge April 9, 2026 09:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds Cedar-based authorization enforcement for dashboard listing and introduces end-to-end tests to verify that dashboard access is correctly allowed/denied per-dashboard.

Changes:

  • Add E2E coverage for listing and reading dashboards under Cedar policies (allowed, filtered, empty, forbidden cases).
  • Update DashboardReadGuard behavior for routes without dashboardId by validating connection membership.
  • Filter GET /dashboards/:connectionId results by per-dashboard Cedar dashboard:read authorization.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
backend/test/ava-tests/saas-tests/saas-dashboard-permissions-e2e.test.ts New E2E tests covering dashboard list/read behavior under Cedar policies.
backend/src/guards/dashboard-read.guard.ts Allow dashboard-list requests to proceed when user belongs to the connection (no dashboardId), while keeping per-dashboard read checks for specific dashboard routes.
backend/src/entities/visualizations/dashboard/use-cases/find-all-dashboards.use.case.ts Add per-dashboard Cedar authorization filtering to ensure only permitted dashboards are returned from list endpoint.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 38 to 40
const dashboards =
await this._dbContext.dashboardRepository.findAllDashboardsWithWidgetsByConnectionId(connectionId);

Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

findAllDashboardsWithWidgetsByConnectionId loads widgets for every dashboard before authorization filtering. With per-dashboard Cedar checks added below, this can fetch potentially large widget payloads for dashboards the caller is not allowed to see, increasing DB load and response time. Consider fetching only dashboard metadata/IDs first, filter by permissions, then load widgets only for the allowed dashboards.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +50
const accessChecks = await Promise.all(
dashboards.map((dashboard) =>
this.cedarAuthService.validate({
userId,
action: CedarAction.DashboardRead,
connectionId,
dashboardId: dashboard.id,
}),
),
);
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

This does one cedarAuthService.validate call per dashboard and runs them all concurrently via Promise.all. validate() performs DB lookups (user suspension + group membership) and Cedar evaluation, so this becomes an N-per-dashboard query/CPU pattern and can overwhelm the DB/pool for connections with many dashboards. Consider adding a batch/streamed validation path that reuses the loaded userGroups/policies once per request (or at least limiting concurrency).

Copilot uses AI. Check for mistakes.
@Artuomka Artuomka merged commit bc7e6cf into main Apr 9, 2026
22 of 23 checks passed
@Artuomka Artuomka deleted the backend_dashboards_permissions branch April 9, 2026 09:45
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