-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: security #57
docs: security #57
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThe changes introduced in this pull request include enhancements to the Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Middleware
participant QueryHandler
participant Database
User->>Middleware: Request to access orders
Middleware->>QueryHandler: Check user permissions
QueryHandler->>Database: Execute query for user orders
Database-->>QueryHandler: Return user-specific orders
QueryHandler-->>Middleware: Return filtered orders
Middleware-->>User: Provide access to orders
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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
🧹 Outside diff range and nitpick comments (16)
packages/docs/docs/200-security/query-middleware.md (2)
7-37
: LGTM: Well-structured example of adding a middlewareThe code example effectively demonstrates how to create and use a query middleware for enhancing security. It shows a practical use case of restricting order queries based on user context.
Consider adding a brief comment explaining the purpose of the
middleware<DB>()
function for readers who might be unfamiliar with the API. For example:// Create a new middleware for the database type DB const restrictOrdersByUser = middleware<DB>() .from('orders') // ... rest of the code
39-43
: LGTM: Clear explanation of middleware execution orderThis section effectively explains the sequence of operations during query execution, which is crucial for understanding the security context in which middlewares operate.
There's a minor grammatical issue in the last sentence. Consider revising it for clarity:
- This ensures that the middleware can inject additional parameters to the query as it's now happening in a safe context. + This ensures that the middleware can inject additional parameters into the query, as it's now operating in a safe context.🧰 Tools
🪛 LanguageTool
[uncategorized] ~43-~43: Possible missing comma found.
Context: ...can inject additional parameters to the query as it's now happening in a safe context...(AI_HYDRA_LEO_MISSING_COMMA)
packages/docs/docs/200-security/query-permissions.md (5)
1-36
: Great introduction and explanation of defining permissionsThe content in this section is clear, informative, and well-structured. The progression from simple string-based permissions to using TypeScript enums is logical and helps users understand the flexibility of the system.
There's a minor typo in the enum example:
- .requires(Roles.usersRead, Roles.usersWrite) + .requires(Permissions.usersRead, Permissions.usersWrite)Also, consider adding a brief explanation of why using an enum for permissions is beneficial (e.g., type safety, autocomplete support, easier refactoring).
🧰 Tools
🪛 Markdownlint
5-5: Expected: 250; Actual: 257
Line length(MD013, line-length)
38-54
: Clear explanation of role inheritanceThe section effectively explains how permissions accumulate when using sub-queries. The code example with users and pets is particularly illustrative.
To further enhance clarity:
Consider explicitly stating the total permissions required after the code example. For instance:
In this example, the user needs to have both the `users:read` and `pets:read` permissions to execute the query. The query engine will ensure that all required permissions are present before allowing execution.This reinforces the concept of permission accumulation and sets up the next section about query context.
56-65
: Good introduction to query context, with room for enhancementThe section effectively introduces the concept of passing a context object with permissions. To improve clarity and flow:
Consider expanding on how the query engine uses the context. For example:
The query engine uses this context to verify that the user has all the required permissions before executing the query.To smooth the transition to the next point, you could add:
To ensure comprehensive permission checking:Then, the existing line about recursive traversal would follow naturally.
These additions would provide a more complete picture of how the query context is used in the permission checking process.
67-69
: Expand on query registration for better clarityThe "Query registration" section touches on an important security aspect but could benefit from more detail and emphasis. Consider expanding this section as follows:
## Query registration When a query is registered, it is registered along with its permissions. This is a crucial security feature that ensures: 1. The integrity of permission requirements: A malicious client cannot modify the ACL requirements of a query after registration. 2. Centralized permission management: Permissions are defined at the query level, making it easier to audit and maintain security policies. This approach significantly enhances the overall security posture of your application by preventing unauthorized access and potential permission escalation attacks.This expansion provides more context on why query registration is important and how it contributes to the security of the system.
🧰 Tools
🪛 Markdownlint
69-69: null
Files should end with a single newline character(MD047, single-trailing-newline)
1-69
: Minor formatting improvementsTo adhere to common Markdown best practices:
Consider breaking the long line (line 5) into shorter segments for improved readability, although the current length doesn't significantly impact comprehension.
Add a newline character at the end of the file. This is a common best practice for text files and can prevent issues with some text processing tools.
These minor adjustments will improve the overall quality and consistency of the documentation.
🧰 Tools
🪛 Markdownlint
5-5: Expected: 250; Actual: 257
Line length(MD013, line-length)
69-69: null
Files should end with a single newline character(MD047, single-trailing-newline)
packages/docs/docs/200-security/index.md (1)
32-33
: Excellent addition for improved documentation structure.The new sentence provides a valuable link to more detailed information about registered queries, enhancing the document's overall structure and user navigation. This addition is well-placed and contributes to a more comprehensive understanding of SynthQL's security features.
Consider adding a brief description of what readers can expect to find in the linked document. For example:
You can read more about registered queries, including advanced usage and best practices, [here](/docs/security/registered-queries).This would give readers a clearer idea of the content they'll find, potentially increasing the likelihood of them exploring the additional documentation.
packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts (2)
55-62
: Approve the 'limit sql injection' test with a minor suggestion.The test case effectively checks for SQL injection vulnerability in the
limit
method. It correctly expects an error when a malicious string is passed as the limit.Consider adding a test that actually executes the query to ensure that the SQL injection is prevented at runtime as well. This would provide an additional layer of security validation.
64-71
: Approve the 'offset sql injection' test with suggestions for improvement.The test case effectively checks for SQL injection vulnerability in the
offset
method, similar to the previous test for thelimit
method.Consider the following improvements for both the 'limit' and 'offset' SQL injection tests:
Combine the tests into a single parameterized test to reduce code duplication. This will make it easier to maintain and extend these tests in the future.
Add tests that actually execute the queries to ensure runtime protection against SQL injection.
Test with various malicious input patterns to cover a wider range of potential SQL injection attempts.
Here's an example of how you could refactor these tests:
import { describe, it, expect } from 'vitest'; describe('SQL injection prevention', () => { const maliciousInputs = [ "1; DROP TABLE users; --", "1 OR 1=1", "(SELECT * FROM users)", "1' UNION SELECT username, password FROM users--" ]; const methods = ['limit', 'offset'] as const; methods.forEach(method => { describe(`${method} method`, () => { maliciousInputs.forEach(input => { it(`prevents SQL injection: ${input}`, () => { expect(() => { const query = from('actor') [method](input as unknown as number) .all(); executor.compile(query); }).toThrow(`Expected ${method} to be a number`); }); it(`prevents SQL injection at runtime: ${input}`, async () => { await expect(async () => { const query = from('actor') [method](input as unknown as number) .all(); await executor.execute(query, executeProps); }).rejects.toThrow(); }); }); }); }); });This refactored version provides more comprehensive testing while reducing code duplication.
packages/docs/docs/200-security/registered-queries.md (4)
27-51
: LGTM: Clear instructions with well-commented code exampleThis section provides clear instructions on how to register queries, including a helpful code example demonstrating query registration with parameters. The explanation of placeholder values is particularly useful.
Consider adding a brief note about the importance of using appropriate placeholder values that don't expose sensitive information, as these values might be visible in logs or error messages.
53-85
: LGTM: Comprehensive explanation of conditional queriesThis section effectively explains how to handle queries with conditional logic, providing a clear code example and demonstrating how to register multiple variants of a conditional query. The content addresses an important use case for complex queries.
Consider adding a brief note about the performance implications of registering multiple variants of a query, and whether there are any limits or best practices regarding the number of variants that should be registered.
🧰 Tools
🪛 LanguageTool
[style] ~76-~76: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: ...se types of queries correctly, you will need to register each variant of the query indi...(REP_NEED_TO_VB)
87-123
: LGTM: Comprehensive explanation of registered queries securityThis section provides a thorough explanation of how registered queries work, covering query identification, checking, and parameter substitution. The included code example effectively illustrates the concept of parameter substitution.
Consider adding a brief note about any potential security implications of parameter substitution, such as how SynthQL prevents SQL injection attacks when substituting parameter values.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~93-~93: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...rtant to understand how they work. The high level idea is simple: 1. Identifying querie...(EN_COMPOUND_ADJECTIVE_INTERNAL)
🪛 Markdownlint
93-93: Expected: 0 or 2; Actual: 1
Trailing spaces(MD009, no-trailing-spaces)
95-95: Expected: 2; Actual: 1
Spaces after list markers(MD030, list-marker-space)
96-96: Expected: 2; Actual: 1
Spaces after list markers(MD030, list-marker-space)
97-97: Expected: 2; Actual: 1
Spaces after list markers(MD030, list-marker-space)
130-149
: LGTM: Clear explanation of hash calculation with helpful examplesThis section effectively explains the hash calculation process, providing useful examples of queries with the same and different hashes. The link to the
hashQuery
function implementation is valuable for developers who want to explore further.Please address the following minor formatting issues:
- Add a hyphen to "high-level" on line 93 to form a compound adjective.
- Add "the" before "case" on line 124 for better readability.
- Add a comma after "So" on line 133.
- Consider rephrasing "very large" on line 132 to avoid the overused intensifier.
- Remove trailing spaces on lines 93, 126, and 148.
These small changes will improve the overall readability and consistency of the document.
🧰 Tools
🪛 LanguageTool
[style] ~132-~132: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...ngified query to avoid sending possibly very large JSON strings over the wire. Special car...(EN_WEAK_ADJECTIVE)
[uncategorized] ~133-~133: A comma might be missing here.
Context: ...rizable are not hardcoded in the hash. So for example, the following two queries ...(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)
🪛 Markdownlint
148-148: Expected: 0 or 2; Actual: 1
Trailing spaces(MD009, no-trailing-spaces)
132-132: Expected: 250; Actual: 296
Line length(MD013, line-length)
packages/backend/src/execution/executors/PgExecutor/queryBuilder/exp.ts (2)
355-358
: LGTM: Enhanced type safety forlimit
parameterThe added type check ensures that the
limit
parameter is a number, which improves type safety and prevents potential runtime errors. This is a good practice.Consider removing the
Number()
conversion in the SQL string since you've already ensuredlimit
is a number:- return this.add(`limit ${Number(limit)} `); + return this.add(`limit ${limit} `);This minor change would slightly improve performance while maintaining type safety.
407-410
: LGTM: Enhanced type safety foroffset
parameterThe added type check ensures that the
offset
parameter is a number, which improves type safety and prevents potential runtime errors. This change is consistent with the improvements made to thelimit
method and is a good practice.Consider removing the
Number()
conversion in the SQL string since you've already ensuredoffset
is a number:- return this.add(`offset ${Number(offset)} `); + return this.add(`offset ${offset} `);This minor change would slightly improve performance while maintaining type safety.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (6)
- packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts (1 hunks)
- packages/backend/src/execution/executors/PgExecutor/queryBuilder/exp.ts (3 hunks)
- packages/docs/docs/200-security/index.md (1 hunks)
- packages/docs/docs/200-security/query-middleware.md (1 hunks)
- packages/docs/docs/200-security/query-permissions.md (1 hunks)
- packages/docs/docs/200-security/registered-queries.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
packages/docs/docs/200-security/query-middleware.md
[uncategorized] ~43-~43: Possible missing comma found.
Context: ...can inject additional parameters to the query as it's now happening in a safe context...(AI_HYDRA_LEO_MISSING_COMMA)
packages/docs/docs/200-security/registered-queries.md
[style] ~76-~76: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: ...se types of queries correctly, you will need to register each variant of the query indi...(REP_NEED_TO_VB)
[uncategorized] ~93-~93: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...rtant to understand how they work. The high level idea is simple: 1. Identifying querie...(EN_COMPOUND_ADJECTIVE_INTERNAL)
[uncategorized] ~124-~124: You might be missing the article “the” here.
Context: ...UserById(0)) ``` ### What happens in case of a hash collision? If you try to reg...(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[style] ~128-~128: You have already used ‘trying to’ in nearby sentences. Consider using one of the replacements to let your writing stand out.
Context: ...ery B, it would be equivalent to simply trying to execute query B. ### How is the hash c...(REP_TRY)
[style] ~132-~132: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...ngified query to avoid sending possibly very large JSON strings over the wire. Special car...(EN_WEAK_ADJECTIVE)
[uncategorized] ~133-~133: A comma might be missing here.
Context: ...rizable are not hardcoded in the hash. So for example, the following two queries ...(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)
🪛 Markdownlint
packages/docs/docs/200-security/query-permissions.md
5-5: Expected: 250; Actual: 257
Line length(MD013, line-length)
69-69: null
Files should end with a single newline character(MD047, single-trailing-newline)
packages/docs/docs/200-security/registered-queries.md
93-93: Expected: 0 or 2; Actual: 1
Trailing spaces(MD009, no-trailing-spaces)
126-126: Expected: 0 or 2; Actual: 1
Trailing spaces(MD009, no-trailing-spaces)
148-148: Expected: 0 or 2; Actual: 1
Trailing spaces(MD009, no-trailing-spaces)
132-132: Expected: 250; Actual: 296
Line length(MD013, line-length)
95-95: Expected: 2; Actual: 1
Spaces after list markers(MD030, list-marker-space)
96-96: Expected: 2; Actual: 1
Spaces after list markers(MD030, list-marker-space)
97-97: Expected: 2; Actual: 1
Spaces after list markers(MD030, list-marker-space)
🔇 Additional comments (9)
packages/docs/docs/200-security/query-middleware.md (1)
1-5
: LGTM: Clear and concise introduction to query middlewaresThe introduction effectively explains the concept of query middlewares and their relevance to security. It provides a good foundation for the rest of the document.
packages/docs/docs/200-security/query-permissions.md (1)
1-69
: Excellent documentation on query permissionsThis documentation provides a comprehensive and well-structured overview of query permissions in SynthQL. The content effectively communicates key concepts, with a logical progression from basic to more advanced topics. The inclusion of relevant code examples enhances understanding.
The minor suggestions provided in the review comments will further improve clarity, completeness, and adherence to documentation best practices. Overall, this is a high-quality addition to the SynthQL documentation that will greatly assist users in implementing and understanding the query permission system.
🧰 Tools
🪛 Markdownlint
5-5: Expected: 250; Actual: 257
Line length(MD013, line-length)
69-69: null
Files should end with a single newline character(MD047, single-trailing-newline)
packages/docs/docs/200-security/index.md (1)
Line range hint
1-33
: Well-structured and comprehensive security documentation.The document provides a clear and thorough overview of SynthQL's security features. The logical structure, combined with relevant examples and explanations, makes it easy for users to understand and implement security measures in their projects.
Key strengths:
- Clear explanations of whitelisting queries, access restrictions, and row-level security.
- Practical code examples that demonstrate real-world usage.
- Logical flow from basic concepts to more advanced security implementations.
The document successfully achieves its goal of explaining SynthQL's security mechanisms and guiding users in implementing robust authorization logic.
packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts (1)
Line range hint
1-72
: Overall assessment of the test file.The test file for PgExecutor is well-structured and covers a good range of scenarios, including:
- Query compilation
- Query execution
- Different table queries (film, actor)
- Included columns and nested queries
- SQL injection prevention (newly added)
The addition of SQL injection tests enhances the security coverage of the test suite. Consider implementing the suggested improvements to make these tests even more robust and maintainable.
packages/docs/docs/200-security/registered-queries.md (3)
1-18
: LGTM: Clear introduction and illustrative exampleThe introduction effectively communicates the core security principle of SynthQL, and the code example provides a clear demonstration of how to register and execute a query. The use of TypeScript is consistent with the project's language.
20-25
: LGTM: Clear explanation of registered queries conceptThis section effectively explains the rationale behind registered queries and draws a helpful parallel with traditional REST APIs. The explanation is concise and easy to understand.
1-149
: Overall: Excellent documentation on registered queriesThis document provides a comprehensive and well-structured explanation of registered queries in SynthQL. It effectively covers the concept, implementation details, and security considerations. The use of code examples and clear explanations makes it accessible to developers of various skill levels.
The minor issues identified in the review (such as typos and formatting) do not detract significantly from the overall quality of the document. Once these are addressed, this will serve as an excellent resource for developers working with SynthQL.
Great job on creating this thorough and informative documentation!
🧰 Tools
🪛 LanguageTool
[style] ~76-~76: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: ...se types of queries correctly, you will need to register each variant of the query indi...(REP_NEED_TO_VB)
[uncategorized] ~93-~93: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...rtant to understand how they work. The high level idea is simple: 1. Identifying querie...(EN_COMPOUND_ADJECTIVE_INTERNAL)
[uncategorized] ~124-~124: You might be missing the article “the” here.
Context: ...UserById(0)) ``` ### What happens in case of a hash collision? If you try to reg...(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[style] ~128-~128: You have already used ‘trying to’ in nearby sentences. Consider using one of the replacements to let your writing stand out.
Context: ...ery B, it would be equivalent to simply trying to execute query B. ### How is the hash c...(REP_TRY)
[style] ~132-~132: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...ngified query to avoid sending possibly very large JSON strings over the wire. Special car...(EN_WEAK_ADJECTIVE)
[uncategorized] ~133-~133: A comma might be missing here.
Context: ...rizable are not hardcoded in the hash. So for example, the following two queries ...(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)
🪛 Markdownlint
93-93: Expected: 0 or 2; Actual: 1
Trailing spaces(MD009, no-trailing-spaces)
126-126: Expected: 0 or 2; Actual: 1
Trailing spaces(MD009, no-trailing-spaces)
148-148: Expected: 0 or 2; Actual: 1
Trailing spaces(MD009, no-trailing-spaces)
132-132: Expected: 250; Actual: 296
Line length(MD013, line-length)
95-95: Expected: 2; Actual: 1
Spaces after list markers(MD030, list-marker-space)
96-96: Expected: 2; Actual: 1
Spaces after list markers(MD030, list-marker-space)
97-97: Expected: 2; Actual: 1
Spaces after list markers(MD030, list-marker-space)
packages/backend/src/execution/executors/PgExecutor/queryBuilder/exp.ts (2)
35-35
: LGTM: Improved error message formattingThe change enhances the readability of the error message by using template literals for better string interpolation. This is a good practice for creating more informative error messages.
Line range hint
1-510
: Summary: Improved type safety in SqlBuilder classThe changes in this file focus on enhancing type safety for the
limit
andoffset
methods in theSqlBuilder
class. These improvements help prevent potential runtime errors by ensuring that the parameters are of the correct type. The changes are consistent and align with good programming practices, contributing to the overall robustness of the code.
# Query middlewares | ||
|
||
Query middlewares are functions that are executed before a query is executed. They can be used to add additional functionality to the query, such as logging, caching, or authentication. | ||
|
||
In the context of security, query middlewares can be used to add additional checks on every query, or add additional filters to the query to limit the result set. | ||
|
||
## Adding a middleware | ||
|
||
You can add a middleware to the query engine using the `.use()` method. | ||
|
||
```ts | ||
import { DB } from './db'; | ||
import { QueryEngine, mapQuery } from '@synthql/backend'; | ||
import { orders } from './queries'; | ||
|
||
const restrictOrdersByUser = middleware<DB>() | ||
.from('orders') | ||
.mapQuery((query, context) => { | ||
const userId = context.user.id; | ||
return { | ||
context, | ||
query: { | ||
...query, | ||
// transforms the `where` to ensure that only orders can be read from the | ||
// current user. | ||
where: { | ||
...query.where, | ||
user_id: userId, | ||
}, | ||
}, | ||
}; | ||
}); | ||
|
||
const queryEngine = new QueryEngine<DB>({ | ||
middlewares: [restrictOrdersByUser], | ||
}); | ||
``` | ||
|
||
## When are middlewares executed? | ||
|
||
When a query is executed, the ID check is performed first, and then the parameters are substituted. Then the middleware is executed. | ||
|
||
This ensures that the middleware can inject additional parameters to the query as it's now happening in a safe context. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Suggestion: Add a "Best Practices" section
The document provides an excellent introduction to query middlewares and their security implications. To further enhance its value, consider adding a "Best Practices" section at the end. This section could include:
- Guidelines for designing secure middlewares
- Common pitfalls to avoid
- Recommendations for testing middlewares
- Examples of how middlewares can be combined for comprehensive security measures
Would you like assistance in drafting this additional section?
🧰 Tools
🪛 LanguageTool
[uncategorized] ~43-~43: Possible missing comma found.
Context: ...can inject additional parameters to the query as it's now happening in a safe context...(AI_HYDRA_LEO_MISSING_COMMA)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
SynthQL pull request template
Why
Motivation an context for the change.
What changed
Brief summary of the changes.
Important
Mention important points that require special attention or that might surprise
reviewers.
Summary by CodeRabbit
New Features
Documentation