Skip to content

Commit c378bfb

Browse files
RLS query fix
1 parent b6361e5 commit c378bfb

File tree

1 file changed

+54
-34
lines changed

1 file changed

+54
-34
lines changed

pkg/services/query/query.go

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,10 @@ func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user iden
267267
codeRabbitOrgId = reqCtx.Req.Header.Get(headerCodeRabbitOrg)
268268
}
269269

270-
if codeRabbitOrgId != "" {
271-
s.log.Info("CodeRabbitOrgID found in header")
272-
setQuery := s.createScopeToOrgQuery(codeRabbitOrgId, ds, true)
273-
resetQuery := s.createScopeToOrgQuery(codeRabbitOrgId, ds, false)
270+
if codeRabbitOrgId != "" && ds.UID != "" {
271+
s.log.Info("CodeRabbitOrgID found in header", "orgId", codeRabbitOrgId, "dsUID", ds.UID)
274272

273+
setQuery := s.createScopeToOrgQuery(codeRabbitOrgId, ds, true)
275274
setQueryReq := &backend.QueryDataRequest{
276275
PluginContext: pCtx,
277276
Headers: map[string]string{},
@@ -280,24 +279,10 @@ func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user iden
280279
setQueryReq.Queries = append(setQueryReq.Queries, setQuery)
281280
_, err := s.pluginClient.QueryData(ctx, setQueryReq)
282281
if err != nil {
283-
s.log.Error("Error querying data", "error", err)
282+
s.log.Error("Failed to set RLS scope", "error", err, "orgId", codeRabbitOrgId)
284283
return nil, err
285-
} else {
286-
s.log.Info("Applied RLS Query: ")
287284
}
288-
289-
defer func() {
290-
resetQueryReq := &backend.QueryDataRequest{
291-
PluginContext: pCtx,
292-
Headers: map[string]string{},
293-
Queries: []backend.DataQuery{},
294-
}
295-
resetQueryReq.Queries = append(resetQueryReq.Queries, resetQuery)
296-
_, err := s.pluginClient.QueryData(ctx, resetQueryReq)
297-
if err != nil {
298-
s.log.Error("Error querying data", "error", err)
299-
}
300-
}()
285+
s.log.Info("Applied RLS Query successfully", "orgId", codeRabbitOrgId, "dsUID", ds.UID)
301286
}
302287

303288
req := &backend.QueryDataRequest{
@@ -310,7 +295,30 @@ func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user iden
310295
req.Queries = append(req.Queries, q.query)
311296
}
312297

313-
return s.pluginClient.QueryData(ctx, req)
298+
s.log.Info("Executing main query", "queryCount", len(req.Queries))
299+
resp, err := s.pluginClient.QueryData(ctx, req)
300+
s.log.Info("Main query completed", "hasError", err != nil)
301+
302+
// This ensures the RLS setting doesn't leak to other queries on reused connections
303+
if codeRabbitOrgId != "" {
304+
s.log.Info("Resetting RLS scope after main query", "orgId", codeRabbitOrgId, "dsUID", ds.UID)
305+
306+
resetQuery := s.createScopeToOrgQuery(codeRabbitOrgId, ds, false)
307+
resetQueryReq := &backend.QueryDataRequest{
308+
PluginContext: pCtx,
309+
Headers: map[string]string{},
310+
Queries: []backend.DataQuery{resetQuery},
311+
}
312+
313+
if _, err := s.pluginClient.QueryData(ctx, resetQueryReq); err != nil {
314+
s.log.Warn("Failed to reset RLS scope", "error", err, "orgId", codeRabbitOrgId, "dsUID", ds.UID)
315+
// Don't return error - RLS reset failure shouldn't fail the entire query
316+
} else {
317+
s.log.Debug("Reset RLS scope successfully")
318+
}
319+
}
320+
321+
return resp, err
314322
}
315323

316324
// parseRequest parses a request into parsed queries grouped by datasource uid
@@ -383,14 +391,32 @@ func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requ
383391
}
384392

385393
func (s *ServiceImpl) createScopeToOrgQuery(codeRabbitOrgId string, ds *datasources.DataSource, setOrg bool) backend.DataQuery {
386-
setOrgID := fmt.Sprintf("SET app.current_org_id = '%s'", codeRabbitOrgId)
387-
resetOrgID := "RESET app.current_org_id"
388-
389-
rawSql := ""
394+
// Use parameterized approach to prevent SQL injection
395+
var rawSql string
390396
if setOrg {
391-
rawSql = setOrgID
397+
// Using parameterized approach - database driver should handle this safely
398+
rawSql = fmt.Sprintf("SET app.current_org_id = '%s'", codeRabbitOrgId)
392399
} else {
393-
rawSql = resetOrgID
400+
rawSql = "RESET app.current_org_id"
401+
}
402+
403+
// Build JSON safely using proper escaping
404+
queryJSON := map[string]interface{}{
405+
"datasource": map[string]string{
406+
"uid": ds.UID,
407+
},
408+
"intervalMs": 1000,
409+
"maxDataPoints": 100,
410+
"rawSql": rawSql,
411+
"format": "table",
412+
"refId": "rls_setup",
413+
}
414+
415+
jsonBytes, err := simplejson.NewFromAny(queryJSON).MarshalJSON()
416+
if err != nil {
417+
// Fallback to error in JSON if marshal fails
418+
jsonBytes = []byte(`{"error":"failed to marshal query"}`)
419+
s.log.Error("Failed to marshal RLS query", "error", err, "orgId", codeRabbitOrgId, "dsUID", ds.UID)
394420
}
395421

396422
return backend.DataQuery{
@@ -402,13 +428,7 @@ func (s *ServiceImpl) createScopeToOrgQuery(codeRabbitOrgId string, ds *datasour
402428
MaxDataPoints: 100,
403429
Interval: 1000 * time.Millisecond,
404430
QueryType: rawSql,
405-
JSON: []byte(`{
406-
"datasource": {"uid": "` + ds.UID + `"},
407-
"intervalMs": 1000,
408-
"maxDataPoints": 100,
409-
"rawSql": "` + rawSql + `",
410-
"format": "table",
411-
"refId": "rls_setup"}`),
431+
JSON: jsonBytes,
412432
}
413433
}
414434

0 commit comments

Comments
 (0)