Skip to content

feat: implement permission checks for qai requests and add tests#1818

Merged
Artuomka merged 1 commit into
mainfrom
backend_ai_requests_permissions
Jun 2, 2026
Merged

feat: implement permission checks for qai requests and add tests#1818
Artuomka merged 1 commit into
mainfrom
backend_ai_requests_permissions

Conversation

@Artuomka

@Artuomka Artuomka commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • AI assistant now enforces user data access permissions, ensuring it can only inspect tables and collections the user is authorized to read
    • Enhanced MongoDB aggregation pipeline analysis to properly extract and validate all referenced collections across multiple pipeline stages
  • Tests

    • Added comprehensive test coverage for MongoDB pipeline collection extraction, including edge cases and error handling

Copilot AI review requested due to automatic review settings June 2, 2026 10:16
@Artuomka Artuomka enabled auto-merge June 2, 2026 10:16
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces MongoDB pipeline collection extraction as a new AI tool, then integrates CedarPermissionsService throughout the request-info-from-table-with-ai-v7 use case to enforce table read permissions before allowing AI data inspection and filtering results by user access.

Changes

Permission-Aware AI Data Inspection

Layer / File(s) Summary
MongoDB Pipeline Collection Extraction Tool
backend/src/ai-core/tools/collect-mongo-pipeline-collections.ts, backend/test/ava-tests/non-saas-tests/non-saas-collect-mongo-pipeline-collections.test.ts
Implements collectMongoPipelineCollections() to parse aggregation pipelines and recursively extract collection names from $lookup, $graphLookup, and $unionWith stages. Returns { kind: 'tables', tables: Set } on success or { kind: 'indeterminate' } on parse failure. Comprehensive tests validate resolution across all stage forms and deduplication.
Dependency Setup for Permission-Guarded Inspection
backend/src/entities/ai/use-cases/request-info-from-table-with-ai-v7.use.case.ts (imports and constructor)
Expands @nestjs/common imports, adds collectMongoPipelineCollections import, injects CedarPermissionsService and permission-assertion utilities into the constructor to enable permission checks throughout the use case.
User Identity Threading
backend/src/entities/ai/use-cases/request-info-from-table-with-ai-v7.use.case.ts (implementation and processWithToolLoop)
Threads user_id from the implementation() entry point through processWithToolLoop into downstream executeToolCalls, establishing the user context required for permission enforcement.
Permission Enforcement on Tool Execution
backend/src/entities/ai/use-cases/request-info-from-table-with-ai-v7.use.case.ts (executeToolCalls branches)
Adds permission assertions before executing each tool: getTableStructure verifies base table access, executeRawSql checks all query-referenced tables, and executeAggregationPipeline asserts read permissions on base and pipeline-referenced collections.
Table Filtering and Permission Helpers
backend/src/entities/ai/use-cases/request-info-from-table-with-ai-v7.use.case.ts (getTableStructureInfo and helpers)
getTableStructureInfo now filters referenced/foreign table structures by per-table permission checks. New helpers assertUserCanReadTables and assertUserCanReadPipelineCollections centralize permission logic with fallback strategies.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A bunny hops through pipelines bright, 🐰
Parsing MongoDB stages with delight,
Permission checks guard every door,
So users see what they're meant for!
Tables filtered, access denied—
No secrets slip through! We're satisfied. ✨

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: implementing permission checks for QAI requests and adding corresponding tests, which aligns with the core changes across both the use case and test files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Security Check ✅ Passed Permission checks prevent execution of unauthorized queries, injection validation blocks SQL/MongoDB attacks, schema filtering prevents leakage, and fallback security ensures fail-closed behavior.

✏️ 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_ai_requests_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.

Copilot AI left a comment

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.

Pull request overview

This PR strengthens AI request safety by enforcing table/collection read permissions before executing AI-triggered database tooling, and introduces a MongoDB aggregation pipeline analyzer to identify referenced collections for permission checks.

Changes:

  • Add permission gating for AI tool calls (table structure inspection, raw SQL, Mongo aggregation) based on Cedar table read permissions.
  • Introduce collectMongoPipelineCollections to extract referenced MongoDB collections from $lookup / $graphLookup / $unionWith stages (including nested sub-pipelines).
  • Add AVA unit tests for Mongo pipeline collection collection.

Reviewed changes

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

File Description
backend/src/entities/ai/use-cases/request-info-from-table-with-ai-v7.use.case.ts Adds Cedar-based permission checks before AI tools can inspect schemas or execute SQL/Mongo queries.
backend/src/ai-core/tools/collect-mongo-pipeline-collections.ts Implements Mongo aggregation pipeline referenced-collection discovery used for permission enforcement.
backend/test/ava-tests/non-saas-tests/non-saas-collect-mongo-pipeline-collections.test.ts Adds unit coverage for Mongo pipeline referenced-collection discovery.

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

Comment on lines +20 to +37
if (key === '$lookup' || key === '$graphLookup') {
const from = (value as { from?: unknown })?.from;
if (typeof from === 'string' && from.length > 0) {
collected.add(from);
}
} else if (key === '$unionWith') {
// `$unionWith` accepts either a collection-name string or `{ coll: <name>, pipeline: [...] }`.
if (typeof value === 'string' && value.length > 0) {
collected.add(value);
} else {
const coll = (value as { coll?: unknown })?.coll;
if (typeof coll === 'string' && coll.length > 0) {
collected.add(coll);
}
}
}
collectReferencedCollections(value, collected);
}
Comment on lines +56 to +58
const collected = new Set<string>();
collectReferencedCollections(parsedPipeline, collected);
return { kind: 'tables', tables: Array.from(collected) };
Comment on lines +16 to +20
test('resolves a $lookup target collection', (t) => {
t.deepEqual(tablesOf('[{"$lookup":{"from":"salaries","localField":"id","foreignField":"user_id","as":"s"}}]'), [
'salaries',
]);
});
Comment on lines 252 to 308
@@ -256,6 +274,14 @@ export class RequestInfoFromTableWithAIUseCaseV7
'Invalid SQL query. Please ensure it is a read-only SELECT statement without any forbidden keywords.',
);
}
await assertUserCanReadQueryTables({
query,
connectionType: foundConnection.type as ConnectionTypesEnum,
connectionId: foundConnection.id,
validateTableRead: (referencedTableName) =>
this.cedarPermissions.improvedCheckTableRead(userId, foundConnection.id, referencedTableName),
listAllTableNames: async () => (await dataAccessObject.getTablesFromDB()).map((table) => table.tableName),
});
const wrappedQuery = wrapQueryWithLimit(query, foundConnection.type as ConnectionTypesEnum);
const queryResult = await dataAccessObject.executeRawQuery(wrappedQuery, inputTableName, userEmail);
result = encodeToToon(queryResult);
@@ -272,6 +298,13 @@ export class RequestInfoFromTableWithAIUseCaseV7
'Invalid MongoDB command. Please ensure it is a read-only aggregation pipeline without any forbidden keywords.',
);
}
await this.assertUserCanReadPipelineCollections(
pipeline,
inputTableName,
userId,
foundConnection.id,
dataAccessObject,
);
const pipelineResult = await dataAccessObject.executeRawQuery(pipeline, inputTableName, userEmail);

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/src/entities/ai/use-cases/request-info-from-table-with-ai-v7.use.case.ts (1)

345-396: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Filter the relation metadata before returning it.

Lines 345-349 load all relationship metadata, and Lines 392-393 return tableForeignKeys plus referencedTableNamesAndColumns unchanged. That still exposes unreadable table names and join-column details even when referencedTablesStructures/foreignTablesStructures are filtered out. Apply the same read check to those two collections, or omit unreadable entries entirely, before encoding the tool result.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/entities/ai/use-cases/request-info-from-table-with-ai-v7.use.case.ts`
around lines 345 - 396, Filter out unreadable entries from
referencedTableNamesAndColumns and tableForeignKeys before returning them: for
each entry in referencedTableNamesAndColumns and each foreignKey in
tableForeignKeys call this.cedarPermissions.improvedCheckTableRead(userId,
foundConnection.id, <table name>) and only include entries where the check
returns true (omitting or redacting join-column details for unreadable targets);
mirror the same per-table permission logic used to build
referencedTablesStructures and foreignTablesStructures so the returned
collections do not expose unreadable table names or join columns (use the same
userEmail/dao context if you need to re-check structure).
🧹 Nitpick comments (1)
backend/src/ai-core/tools/collect-mongo-pipeline-collections.ts (1)

9-38: 💤 Low value

Use arrow functions for the new top-level helpers.

Both additions are function declarations, which diverges from the repository's TS style and makes this utility layer inconsistent with the rest of the codebase.

As per coding guidelines, "Prefer arrow functions over function declarations".

Also applies to: 49-59

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/ai-core/tools/collect-mongo-pipeline-collections.ts` around lines
9 - 38, The top-level helper collectReferencedCollections is declared with a
function declaration; convert it to an arrow-function style (e.g., assign a
const to an arrow function) to follow the repo TS style, and do the same for the
other top-level helper in this file that was added around the same area (the
second function declaration referenced in the review). Keep the exact parameter
types and behavior unchanged (node: unknown, collected: Set<string>): void),
replace the function declaration with a const binding to an arrow function, and
export/usage should remain identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@backend/src/entities/ai/use-cases/request-info-from-table-with-ai-v7.use.case.ts`:
- Around line 345-396: Filter out unreadable entries from
referencedTableNamesAndColumns and tableForeignKeys before returning them: for
each entry in referencedTableNamesAndColumns and each foreignKey in
tableForeignKeys call this.cedarPermissions.improvedCheckTableRead(userId,
foundConnection.id, <table name>) and only include entries where the check
returns true (omitting or redacting join-column details for unreadable targets);
mirror the same per-table permission logic used to build
referencedTablesStructures and foreignTablesStructures so the returned
collections do not expose unreadable table names or join columns (use the same
userEmail/dao context if you need to re-check structure).

---

Nitpick comments:
In `@backend/src/ai-core/tools/collect-mongo-pipeline-collections.ts`:
- Around line 9-38: The top-level helper collectReferencedCollections is
declared with a function declaration; convert it to an arrow-function style
(e.g., assign a const to an arrow function) to follow the repo TS style, and do
the same for the other top-level helper in this file that was added around the
same area (the second function declaration referenced in the review). Keep the
exact parameter types and behavior unchanged (node: unknown, collected:
Set<string>): void), replace the function declaration with a const binding to an
arrow function, and export/usage should remain identical.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ee7c0efb-ef4e-4dd2-b08d-38d5b24dc392

📥 Commits

Reviewing files that changed from the base of the PR and between 4c8b7cb and 681610c.

📒 Files selected for processing (3)
  • backend/src/ai-core/tools/collect-mongo-pipeline-collections.ts
  • backend/src/entities/ai/use-cases/request-info-from-table-with-ai-v7.use.case.ts
  • backend/test/ava-tests/non-saas-tests/non-saas-collect-mongo-pipeline-collections.test.ts

@Artuomka Artuomka merged commit 7eac455 into main Jun 2, 2026
17 of 18 checks passed
@Artuomka Artuomka deleted the backend_ai_requests_permissions branch June 2, 2026 10:25
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