-
Notifications
You must be signed in to change notification settings - Fork 2.5k
feat(snowflake): snowflake integration #1993
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
base: staging
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Greptile OverviewGreptile SummaryThis PR adds a comprehensive Snowflake integration with OAuth authentication and multiple database operation tools. The implementation includes proper PKCE flow for OAuth security and covers common database operations (query, insert, update, delete, and various list operations). Key Changes:
Critical Issues:
Recommendations:
Confidence Score: 1/5
Important Files ChangedFile Analysis
Sequence DiagramsequenceDiagram
participant User
participant Frontend
participant AuthAPI as Auth Routes
participant Snowflake
participant Database
participant ToolAPI as Tool Execution
Note over User,Database: OAuth Flow
User->>Frontend: Initiate connection
Frontend->>AuthAPI: Start OAuth
AuthAPI->>AuthAPI: Generate PKCE
AuthAPI->>Snowflake: Authorization request
Snowflake->>User: Consent prompt
User->>Snowflake: Grant permission
Snowflake->>AuthAPI: Return authorization
AuthAPI->>Snowflake: Exchange for credentials
Snowflake->>AuthAPI: Provide credentials
AuthAPI->>Database: Store credentials
AuthAPI->>Frontend: Complete flow
Note over User,ToolAPI: Query Execution
User->>Frontend: Execute SQL operation
Frontend->>ToolAPI: Operation request
ToolAPI->>ToolAPI: Build SQL
ToolAPI->>Database: Get credentials
ToolAPI->>Snowflake: Execute query
Snowflake->>ToolAPI: Query results
ToolAPI->>Frontend: Return data
|
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.
27 files reviewed, 3 comments
| function buildDeleteSQL( | ||
| database: string, | ||
| schema: string, | ||
| table: string, | ||
| whereClause?: string | ||
| ): string { | ||
| const fullTableName = `${database}.${schema}.${table}` | ||
|
|
||
| let sql = `DELETE FROM ${fullTableName}` | ||
|
|
||
| // Add WHERE clause if provided | ||
| if (whereClause && whereClause.trim()) { | ||
| sql += ` WHERE ${whereClause}` | ||
| } | ||
|
|
||
| return sql |
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.
logic: SQL injection vulnerability: database, schema, table, and whereClause are concatenated directly into SQL without any validation or identifier quoting. Malicious input like table = "users; DROP TABLE users--" could execute arbitrary SQL.
| function buildDeleteSQL( | |
| database: string, | |
| schema: string, | |
| table: string, | |
| whereClause?: string | |
| ): string { | |
| const fullTableName = `${database}.${schema}.${table}` | |
| let sql = `DELETE FROM ${fullTableName}` | |
| // Add WHERE clause if provided | |
| if (whereClause && whereClause.trim()) { | |
| sql += ` WHERE ${whereClause}` | |
| } | |
| return sql | |
| function buildDeleteSQL( | |
| database: string, | |
| schema: string, | |
| table: string, | |
| whereClause?: string | |
| ): string { | |
| // Snowflake identifier quoting requires double quotes for SQL identifiers | |
| const quotedDatabase = `"${database.replace(/"/g, '""')}"` | |
| const quotedSchema = `"${schema.replace(/"/g, '""')}"` | |
| const quotedTable = `"${table.replace(/"/g, '""')}"` | |
| const fullTableName = `${quotedDatabase}.${quotedSchema}.${quotedTable}` | |
| let sql = `DELETE FROM ${fullTableName}` | |
| // Add WHERE clause if provided | |
| // Note: whereClause still needs proper parameterization - consider using Snowflake bind variables | |
| if (whereClause && whereClause.trim()) { | |
| sql += ` WHERE ${whereClause}` | |
| } | |
| return sql | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/sim/tools/snowflake/delete_rows.ts
Line: 14:29
Comment:
**logic:** SQL injection vulnerability: `database`, `schema`, `table`, and `whereClause` are concatenated directly into SQL without any validation or identifier quoting. Malicious input like `table = "users; DROP TABLE users--"` could execute arbitrary SQL.
```suggestion
function buildDeleteSQL(
database: string,
schema: string,
table: string,
whereClause?: string
): string {
// Snowflake identifier quoting requires double quotes for SQL identifiers
const quotedDatabase = `"${database.replace(/"/g, '""')}"`
const quotedSchema = `"${schema.replace(/"/g, '""')}"`
const quotedTable = `"${table.replace(/"/g, '""')}"`
const fullTableName = `${quotedDatabase}.${quotedSchema}.${quotedTable}`
let sql = `DELETE FROM ${fullTableName}`
// Add WHERE clause if provided
// Note: whereClause still needs proper parameterization - consider using Snowflake bind variables
if (whereClause && whereClause.trim()) {
sql += ` WHERE ${whereClause}`
}
return sql
}
```
How can I resolve this? If you propose a fix, please make it concise.| function buildInsertSQL( | ||
| database: string, | ||
| schema: string, | ||
| table: string, | ||
| columns: string[], | ||
| values: any[][] | ||
| ): string { | ||
| const fullTableName = `${database}.${schema}.${table}` | ||
| const columnList = columns.join(', ') | ||
|
|
||
| // Build values clause for multiple rows | ||
| const valuesClause = values | ||
| .map((rowValues) => { | ||
| const formattedValues = rowValues.map((val) => { | ||
| if (val === null || val === undefined) { | ||
| return 'NULL' | ||
| } | ||
| if (typeof val === 'string') { | ||
| // Escape single quotes by doubling them | ||
| return `'${val.replace(/'/g, "''")}'` | ||
| } | ||
| if (typeof val === 'boolean') { | ||
| return val ? 'TRUE' : 'FALSE' | ||
| } | ||
| return String(val) | ||
| }) | ||
| return `(${formattedValues.join(', ')})` | ||
| }) | ||
| .join(', ') | ||
|
|
||
| return `INSERT INTO ${fullTableName} (${columnList}) VALUES ${valuesClause}` | ||
| } |
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.
logic: SQL injection vulnerability: database, schema, table, and columns array are concatenated directly into SQL without identifier quoting. Malicious input in column names like "col1, (SELECT password FROM users)--" could expose data.
| function buildInsertSQL( | |
| database: string, | |
| schema: string, | |
| table: string, | |
| columns: string[], | |
| values: any[][] | |
| ): string { | |
| const fullTableName = `${database}.${schema}.${table}` | |
| const columnList = columns.join(', ') | |
| // Build values clause for multiple rows | |
| const valuesClause = values | |
| .map((rowValues) => { | |
| const formattedValues = rowValues.map((val) => { | |
| if (val === null || val === undefined) { | |
| return 'NULL' | |
| } | |
| if (typeof val === 'string') { | |
| // Escape single quotes by doubling them | |
| return `'${val.replace(/'/g, "''")}'` | |
| } | |
| if (typeof val === 'boolean') { | |
| return val ? 'TRUE' : 'FALSE' | |
| } | |
| return String(val) | |
| }) | |
| return `(${formattedValues.join(', ')})` | |
| }) | |
| .join(', ') | |
| return `INSERT INTO ${fullTableName} (${columnList}) VALUES ${valuesClause}` | |
| } | |
| function buildInsertSQL( | |
| database: string, | |
| schema: string, | |
| table: string, | |
| columns: string[], | |
| values: any[][] | |
| ): string { | |
| // Quote SQL identifiers to prevent injection | |
| const quotedDatabase = `"${database.replace(/"/g, '""')}"` | |
| const quotedSchema = `"${schema.replace(/"/g, '""')}"` | |
| const quotedTable = `"${table.replace(/"/g, '""')}"` | |
| const fullTableName = `${quotedDatabase}.${quotedSchema}.${quotedTable}` | |
| // Quote column names as SQL identifiers | |
| const columnList = columns.map(col => `"${col.replace(/"/g, '""')}"`).join(', ') | |
| // Build values clause for multiple rows | |
| const valuesClause = values | |
| .map((rowValues) => { | |
| const formattedValues = rowValues.map((val) => { | |
| if (val === null || val === undefined) { | |
| return 'NULL' | |
| } | |
| if (typeof val === 'string') { | |
| // Escape single quotes by doubling them | |
| return `'${val.replace(/'/g, "''")}'` | |
| } | |
| if (typeof val === 'boolean') { | |
| return val ? 'TRUE' : 'FALSE' | |
| } | |
| return String(val) | |
| }) | |
| return `(${formattedValues.join(', ')})` | |
| }) | |
| .join(', ') | |
| return `INSERT INTO ${fullTableName} (${columnList}) VALUES ${valuesClause}` | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/sim/tools/snowflake/insert_rows.ts
Line: 14:45
Comment:
**logic:** SQL injection vulnerability: `database`, `schema`, `table`, and `columns` array are concatenated directly into SQL without identifier quoting. Malicious input in column names like `"col1, (SELECT password FROM users)--"` could expose data.
```suggestion
function buildInsertSQL(
database: string,
schema: string,
table: string,
columns: string[],
values: any[][]
): string {
// Quote SQL identifiers to prevent injection
const quotedDatabase = `"${database.replace(/"/g, '""')}"`
const quotedSchema = `"${schema.replace(/"/g, '""')}"`
const quotedTable = `"${table.replace(/"/g, '""')}"`
const fullTableName = `${quotedDatabase}.${quotedSchema}.${quotedTable}`
// Quote column names as SQL identifiers
const columnList = columns.map(col => `"${col.replace(/"/g, '""')}"`).join(', ')
// Build values clause for multiple rows
const valuesClause = values
.map((rowValues) => {
const formattedValues = rowValues.map((val) => {
if (val === null || val === undefined) {
return 'NULL'
}
if (typeof val === 'string') {
// Escape single quotes by doubling them
return `'${val.replace(/'/g, "''")}'`
}
if (typeof val === 'boolean') {
return val ? 'TRUE' : 'FALSE'
}
return String(val)
})
return `(${formattedValues.join(', ')})`
})
.join(', ')
return `INSERT INTO ${fullTableName} (${columnList}) VALUES ${valuesClause}`
}
```
How can I resolve this? If you propose a fix, please make it concise.| function buildUpdateSQL( | ||
| database: string, | ||
| schema: string, | ||
| table: string, | ||
| updates: Record<string, any>, | ||
| whereClause?: string | ||
| ): string { | ||
| const fullTableName = `${database}.${schema}.${table}` | ||
|
|
||
| // Build SET clause | ||
| const setClause = Object.entries(updates) | ||
| .map(([column, value]) => { | ||
| let formattedValue: string | ||
|
|
||
| if (value === null || value === undefined) { | ||
| formattedValue = 'NULL' | ||
| } else if (typeof value === 'string') { | ||
| // Escape single quotes by doubling them | ||
| formattedValue = `'${value.replace(/'/g, "''")}'` | ||
| } else if (typeof value === 'boolean') { | ||
| formattedValue = value ? 'TRUE' : 'FALSE' | ||
| } else { | ||
| formattedValue = String(value) | ||
| } | ||
|
|
||
| return `${column} = ${formattedValue}` | ||
| }) | ||
| .join(', ') | ||
|
|
||
| let sql = `UPDATE ${fullTableName} SET ${setClause}` | ||
|
|
||
| // Add WHERE clause if provided | ||
| if (whereClause && whereClause.trim()) { | ||
| sql += ` WHERE ${whereClause}` | ||
| } | ||
|
|
||
| return sql | ||
| } |
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.
logic: SQL injection vulnerability: database, schema, table, and column names in updates object are concatenated directly into SQL without identifier quoting. Malicious column names could inject arbitrary SQL.
| function buildUpdateSQL( | |
| database: string, | |
| schema: string, | |
| table: string, | |
| updates: Record<string, any>, | |
| whereClause?: string | |
| ): string { | |
| const fullTableName = `${database}.${schema}.${table}` | |
| // Build SET clause | |
| const setClause = Object.entries(updates) | |
| .map(([column, value]) => { | |
| let formattedValue: string | |
| if (value === null || value === undefined) { | |
| formattedValue = 'NULL' | |
| } else if (typeof value === 'string') { | |
| // Escape single quotes by doubling them | |
| formattedValue = `'${value.replace(/'/g, "''")}'` | |
| } else if (typeof value === 'boolean') { | |
| formattedValue = value ? 'TRUE' : 'FALSE' | |
| } else { | |
| formattedValue = String(value) | |
| } | |
| return `${column} = ${formattedValue}` | |
| }) | |
| .join(', ') | |
| let sql = `UPDATE ${fullTableName} SET ${setClause}` | |
| // Add WHERE clause if provided | |
| if (whereClause && whereClause.trim()) { | |
| sql += ` WHERE ${whereClause}` | |
| } | |
| return sql | |
| } | |
| function buildUpdateSQL( | |
| database: string, | |
| schema: string, | |
| table: string, | |
| updates: Record<string, any>, | |
| whereClause?: string | |
| ): string { | |
| // Quote SQL identifiers to prevent injection | |
| const quotedDatabase = `"${database.replace(/"/g, '""')}"` | |
| const quotedSchema = `"${schema.replace(/"/g, '""')}"` | |
| const quotedTable = `"${table.replace(/"/g, '""')}"` | |
| const fullTableName = `${quotedDatabase}.${quotedSchema}.${quotedTable}` | |
| // Build SET clause with quoted column identifiers | |
| const setClause = Object.entries(updates) | |
| .map(([column, value]) => { | |
| // Quote column name as SQL identifier | |
| const quotedColumn = `"${column.replace(/"/g, '""')}"` | |
| let formattedValue: string | |
| if (value === null || value === undefined) { | |
| formattedValue = 'NULL' | |
| } else if (typeof value === 'string') { | |
| // Escape single quotes by doubling them | |
| formattedValue = `'${value.replace(/'/g, "''")}'` | |
| } else if (typeof value === 'boolean') { | |
| formattedValue = value ? 'TRUE' : 'FALSE' | |
| } else { | |
| formattedValue = String(value) | |
| } | |
| return `${quotedColumn} = ${formattedValue}` | |
| }) | |
| .join(', ') | |
| let sql = `UPDATE ${fullTableName} SET ${setClause}` | |
| // Add WHERE clause if provided | |
| // Note: whereClause still needs proper parameterization | |
| if (whereClause && whereClause.trim()) { | |
| sql += ` WHERE ${whereClause}` | |
| } | |
| return sql | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/sim/tools/snowflake/update_rows.ts
Line: 14:51
Comment:
**logic:** SQL injection vulnerability: `database`, `schema`, `table`, and column names in `updates` object are concatenated directly into SQL without identifier quoting. Malicious column names could inject arbitrary SQL.
```suggestion
function buildUpdateSQL(
database: string,
schema: string,
table: string,
updates: Record<string, any>,
whereClause?: string
): string {
// Quote SQL identifiers to prevent injection
const quotedDatabase = `"${database.replace(/"/g, '""')}"`
const quotedSchema = `"${schema.replace(/"/g, '""')}"`
const quotedTable = `"${table.replace(/"/g, '""')}"`
const fullTableName = `${quotedDatabase}.${quotedSchema}.${quotedTable}`
// Build SET clause with quoted column identifiers
const setClause = Object.entries(updates)
.map(([column, value]) => {
// Quote column name as SQL identifier
const quotedColumn = `"${column.replace(/"/g, '""')}"`
let formattedValue: string
if (value === null || value === undefined) {
formattedValue = 'NULL'
} else if (typeof value === 'string') {
// Escape single quotes by doubling them
formattedValue = `'${value.replace(/'/g, "''")}'`
} else if (typeof value === 'boolean') {
formattedValue = value ? 'TRUE' : 'FALSE'
} else {
formattedValue = String(value)
}
return `${quotedColumn} = ${formattedValue}`
})
.join(', ')
let sql = `UPDATE ${fullTableName} SET ${setClause}`
// Add WHERE clause if provided
// Note: whereClause still needs proper parameterization
if (whereClause && whereClause.trim()) {
sql += ` WHERE ${whereClause}`
}
return sql
}
```
How can I resolve this? If you propose a fix, please make it concise.a128838 to
c0d357d
Compare
| ) | ||
| } | ||
|
|
||
| const clientId = env.SNOWFLAKE_CLIENT_ID |
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.
isn't snowflake require clientId and client secret of the user account ?
1f8c88f to
ee04fdc
Compare
Summary
Snowflake integration. Still testing some auth stuff for creating and deleting tables.
Fixes #(issue)
Type of Change
Testing
Tested manually
Checklist