2142 sql injection via unescaped device id in srql query construction #2581

Merged
mfreeman451 merged 4 commits from refs/pull/2581/head into staging 2025-12-16 18:01:21 +00:00
mfreeman451 commented 2025-12-16 17:02:01 +00:00 (Migrated from github.com)
Owner

Imported from GitHub pull request.

Original GitHub pull request: #2157
Original author: @mfreeman451
Original URL: https://github.com/carverauto/serviceradar/pull/2157
Original created: 2025-12-16T17:02:01Z
Original updated: 2025-12-16T18:01:27Z
Original head: carverauto/serviceradar:2142-sql-injection-via-unescaped-device_id-in-srql-query-construction
Original base: staging
Original merged: 2025-12-16T18:01:21Z by @mfreeman451

User description

IMPORTANT: Please sign the Developer Certificate of Origin

Thank you for your contribution to ServiceRadar. Please note, when contributing, the developer must include
a DCO sign-off statement indicating the DCO acceptance in one commit message. Here
is an example DCO Signed-off-by line in a commit message:

Signed-off-by: J. Doe <j.doe@domain.com>

Describe your changes

Code checklist before requesting a review

  • I have signed the DCO?
  • The build completes without errors?
  • All tests are passing when running make test?

PR Type

Bug fix, Enhancement, Tests


Description

SQL Injection Prevention via Parameterized Queries

  • Implemented comprehensive parameterized query support across Go and Rust codebase to prevent SQL injection vulnerabilities

  • Refactored SRQL query builders to use $N placeholders instead of string interpolation for user-supplied values

  • Added srqlBindBuilder utility for collecting and binding query parameters

  • Updated all MCP tools (devices, logs, events, sweeps, alerts) to use parameterized queries

Partition Scoping for Identity Engine

  • Enhanced identity resolution with partition-scoped cache keys (<partition>:<type>:<value>)

  • Added strongIdentifierCacheKey function for consistent cache key generation

  • Refactored batchLookupByStrongIdentifiers to group and process updates by partition

  • Updated database interface to include partition parameter in lookups

Rust SRQL Engine Enhancements

  • Implemented BindParam enum for parameterized query values (Text, TextArray, IntArray, Bool, Int, Float, Timestamptz)

  • Refactored all entity query builders to return SQL and bind parameters as tuples

  • Added visualization metadata generation via VizMeta types for query results

  • Implemented downsampling query support for time-series metrics with configurable aggregation

  • Added Apache AGE Cypher graph query execution with read-only validation

  • Exported public SRQL types and added EmbeddedSrql struct for embedded engine usage

  • Added Elixir NIF module for SRQL query translation from web-ng

OTEL Metrics Improvements

  • Added unit field to OTEL metric models (Go and Rust) for storing measurement units

  • Created continuous aggregation view otel_metrics_hourly_stats for pre-computed hourly statistics

  • Added hourly bucketing with 15-minute refresh policy for performance optimization

SNMP Service Deadlock Fix

  • Removed recursive RWMutex read locking in Check method to prevent deadlock

  • Added AST-based deadlock detection test to prevent regression

Web-ng Foundation

  • Added Phoenix LiveView application with JavaScript setup and custom hooks

  • Implemented SRQL query interface components with builder, results table, and auto-visualization

  • Added edge package onboarding token codec for secure token handling

  • Integrated Heroicons SVG icon library and daisyUI theme system with multiple color schemes

  • Added topbar progress bar library for UI feedback

Infrastructure & Configuration

  • Added PostgreSQL client certificate authentication support via PGSSLCERT and PGSSLKEY environment variables

  • Enhanced certificate generation with CNPG_CERT_EXTRA_IPS support and workstation client certificate

  • Updated Nginx entrypoint to route to web-ng service on port 4000

  • Added database schema migration for OTEL metrics unit column and aggregation view


Diagram Walkthrough

flowchart LR
  A["User Input"] -->|"Parameterized Queries"| B["Query Builder"]
  B -->|"Bind Parameters"| C["Database Driver"]
  C -->|"Safe Execution"| D["PostgreSQL"]
  
  E["Identity Engine"] -->|"Partition Scoping"| F["Cache Keys"]
  F -->|"Lookup"| G["Device Resolution"]
  
  H["SRQL Engine"] -->|"Visualization Metadata"| I["Query Results"]
  H -->|"Downsampling"| J["Time-Series Metrics"]
  H -->|"Graph Cypher"| K["AGE Database"]
  
  L["Web-ng UI"] -->|"SRQL NIF"| H
  L -->|"Components"| M["Query Interface"]

File Walkthrough

Relevant files
Enhancement
43 files
cnpg_observability.go
Refactor OTEL inserts to use parameterized queries             

pkg/db/cnpg_observability.go

  • Refactored OTEL insert operations to use parameterized queries with
    $1, $2, etc. placeholders instead of string formatting
  • Extracted SQL templates as module-level constants (otelLogsInsertSQL,
    otelMetricsInsertSQL, otelTracesInsertSQL)
  • Introduced otelRowInserter interface and concrete implementations to
    abstract row-specific logic
  • Consolidated duplicate insertion logic into shared insertOTELRows and
    insertOTEL helper functions
  • Added unit field to metrics insert query
+188/-131
identity_engine.go
Add partition scoping to identity engine cache keys           

pkg/registry/identity_engine.go

  • Updated cache key format to include partition: :: instead of :
  • Added strongIdentifierCacheKey function to normalize partition and
    build consistent cache keys
  • Refactored batchLookupByStrongIdentifiers to group updates by
    partition and process each partition separately
  • Extracted helper functions: groupUpdatesByPartition,
    collectStrongIdentifierSets, batchLookupIdentifierType
  • Updated batchLookupByStrongIdentifiersForPartition to accept partition
    parameter
+124/-54
builder.go
Update filter builders to use parameterized queries           

pkg/mcp/builder.go

  • Updated FilterHandlerFunc and FilterBuilder interface to accept
    srqlBindBuilder parameter
  • Modified GenericFilterBuilder.BuildFilters to use parameterized binds
    instead of string formatting
  • Added deterministic field processing by sorting JSON field keys before
    iteration
  • Replaced string interpolation with binds.Bind() calls for filter
    values
+20/-7   
server.go
Update MCP server to use parameterized queries                     

pkg/mcp/server.go

  • Updated executeGetDevice to use parameterized query with $1
    placeholder
  • Modified executeQueryEvents to build parameterized queries for time
    range filters
  • Added executeSRQLQueryWithParams method to dispatch to
    ParameterizedQueryExecutor
  • Refactored executeSRQLQuery to delegate to executeSRQLQueryWithParams
    with empty params
+24/-7   
tools_sweeps.go
Update sweep tools to use parameterized queries                   

pkg/mcp/tools_sweeps.go

  • Refactored registerGetRecentSweepsTool to use parameterized query for
    poller_id filter
  • Refactored registerGetSweepSummaryTool to use parameterized query for
    poller_id filter
  • Replaced string interpolation with $1 placeholder and queryParams
    array
+8/-4     
cnpg_identity_engine.go
Add partition filtering to identity lookups                           

pkg/db/cnpg_identity_engine.go

  • Updated batchGetDeviceIDsByIdentifierSQL to filter by partition column
    with $3 parameter
  • Modified BatchGetDeviceIDsByIdentifier to accept and pass partition
    parameter to query
  • Added default partition handling when partition is empty string
+8/-3     
tools_events.go
Update alerts tool to use parameterized queries                   

pkg/mcp/tools_events.go

  • Updated registerGetAlertsTool to use parameterized query for poller_id
    filter
  • Replaced string interpolation with $1 placeholder and queryParams
    array
+4/-2     
tools_devices.go
Update device tools to use parameterized queries                 

pkg/mcp/tools_devices.go

  • Updated registerDeviceTools to use parameterized query for device_id
    filter
  • Replaced string interpolation with $1 placeholder and queryParams
    array
+3/-3     
tools_logs.go
Update log tools to use parameterized queries                       

pkg/mcp/tools_logs.go

  • Updated registerLogTools to use parameterized query for poller_id
    filter
  • Replaced string interpolation with $1 placeholder and queryParams
    array
+4/-2     
interfaces.go
Update database interface for partition support                   

pkg/db/interfaces.go

  • Updated BatchGetDeviceIDsByIdentifier interface signature to include
    partition parameter
+1/-1     
binds.go
Add SRQL parameter binding builder utility                             

pkg/mcp/binds.go

  • New file introducing srqlBindBuilder struct for collecting query
    parameters
  • Provides Bind method to append values and generate $N placeholders
+12/-0   
otel.go
Add unit field to OTEL metric model                                           

pkg/models/otel.go

  • Added Unit field to OTELMetricRow struct for measurement units (e.g.,
    "ms", "bytes")
+1/-0     
mod.rs
Implement parameterized query support in Rust SRQL engine

rust/srql/src/query/mod.rs

  • Added BindParam enum to represent parameterized query values (Text,
    TextArray, IntArray, Bool, Int, Float, Timestamptz)
  • Refactored translate method to use new translate_request function
  • Added support for downsample and graph_cypher entities in query
    execution
  • Introduced helper functions: max_dollar_placeholder,
    reconcile_limit_offset_binds, diesel_sql, diesel_bind_count
  • Updated TranslateResponse to include params as Vec, pagination, and
    viz metadata
  • Added comprehensive tests for parameter arity matching, visualization
    metadata, and graph cypher validation
+523/-58
viz.rs
Add visualization metadata generation for queries               

rust/srql/src/query/viz.rs

  • New file providing visualization metadata generation for query results
  • Defines VizMeta, ColumnMeta, ColumnType, ColumnSemantic, and
    VizSuggestion types
  • Implements meta_for_plan function to generate column and suggestion
    metadata for all entity types
  • Supports timeseries and table visualization kinds with semantic hints
+605/-0 
devices.rs
Implement parameterized queries for devices entity             

rust/srql/src/query/devices.rs

  • Updated to_debug_sql to to_sql_and_params returning tuple of SQL and
    Vec
  • Added stats query support with parse_stats_spec and build_stats_query
    functions
  • Implemented collect_filter_params to extract bind parameters from
    device filters
  • Added parameter collection for time ranges, filters, and limit/offset
    clauses
  • Includes bind count validation in debug/test builds
+195/-7 
interfaces.rs
Implement parameterized queries for interfaces entity       

rust/srql/src/query/interfaces.rs

  • Updated to_debug_sql to to_sql_and_params returning tuple of SQL and
    Vec
  • Implemented collect_filter_params to extract bind parameters from
    interface filters
  • Added parameter collection for time ranges, filters, and limit/offset
    clauses
  • Includes bind count validation in debug/test builds
+112/-8 
lib.rs
Export SRQL types and add embedded engine support               

rust/srql/src/lib.rs

  • Exported public types: QueryDirection, QueryEngine, QueryRequest,
    QueryResponse, TranslateRequest, TranslateResponse
  • Added EmbeddedSrql struct for embedded SRQL engine usage
  • Implemented EmbeddedSrql::new constructor to initialize query engine
    with connection pool
+19/-0   
downsample.rs
Add downsampling query support for time-series metrics     

rust/srql/src/query/downsample.rs

  • New file implementing downsampling query support for time-series
    metrics with configurable bucket sizes and aggregation functions
  • Provides SQL generation and parameter binding for downsampled queries
    across multiple metric entity types
  • Implements series expression building and filter clause generation
    with proper parameter escaping
  • Includes placeholder rewriting to convert ? to PostgreSQL $N format
+521/-0 
services.rs
Refactor services query to return SQL and parameters         

rust/srql/src/query/services.rs

  • Refactored to_debug_sql to to_sql_and_params returning both SQL and
    bind parameters
  • Added stats query support with parse_stats_spec and build_stats_query
    functions
  • Implemented collect_filter_params to extract bind parameters from
    filters
  • Added bind count validation in debug/test builds
+172/-4 
parser.rs
Add downsampling and graph cypher query parsing support   

rust/srql/src/parser.rs

  • Added GraphCypher entity type for graph database queries
  • Introduced DownsampleSpec and DownsampleAgg types for downsampling
    configuration
  • Added parsing for bucket, agg, and series tokens for downsampling
    queries
  • Enhanced stats parsing to support as alias syntax with validation
+157/-2 
graph_cypher.rs
Add Apache AGE Cypher graph query support                               

rust/srql/src/query/graph_cypher.rs

  • New file implementing Apache AGE Cypher query execution against
    PostgreSQL graph database
  • Provides SQL generation with proper dollar-quoting for Cypher queries
  • Implements read-only validation to prevent write operations
  • Includes sophisticated placeholder rewriting that respects string
    literals and dollar-quoted strings
+208/-0 
traces.rs
Refactor traces query to return SQL and parameters             

rust/srql/src/query/traces.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params and collect_i32_list for parameter
    extraction
  • Implemented bind count validation in debug/test builds
+109/-4 
logs.rs
Refactor logs query to return SQL and parameters                 

rust/srql/src/query/logs.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params for parameter extraction from various
    filter types
  • Implemented stats query support with parameter binding
+103/-3 
cpu_metrics.rs
Refactor CPU metrics query to return SQL and parameters   

rust/srql/src/query/cpu_metrics.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params for extracting numeric and text filter
    parameters
  • Implemented bind count validation in debug/test builds
+85/-5   
pollers.rs
Refactor pollers query to return SQL and parameters           

rust/srql/src/query/pollers.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params for parameter extraction with boolean
    support
  • Implemented bind count validation in debug/test builds
+81/-14 
otel_metrics.rs
Refactor OTEL metrics query to return SQL and parameters 

rust/srql/src/query/otel_metrics.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params for extracting text and boolean filter
    parameters
  • Implemented bind count validation in debug/test builds
+85/-5   
db.rs
Add PostgreSQL client certificate authentication support 

rust/srql/src/db.rs

  • Added support for client certificate and key configuration via
    PGSSLCERT and PGSSLKEY environment variables
  • Implemented build_client_config, load_client_certs, and
    load_client_key functions for mutual TLS
  • Updated PgConnectionManager::new to accept optional client certificate
    and key paths
+77/-10 
timeseries_metrics.rs
Refactor timeseries metrics query to return SQL and parameters

rust/srql/src/query/timeseries_metrics.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params for extracting numeric and text filter
    parameters
  • Implemented bind count validation in debug/test builds
+82/-4   
process_metrics.rs
Refactor process metrics query to return SQL and parameters

rust/srql/src/query/process_metrics.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params for extracting numeric and text filter
    parameters
  • Implemented bind count validation in debug/test builds
+77/-4   
disk_metrics.rs
Refactor disk metrics query to return SQL and parameters 

rust/srql/src/query/disk_metrics.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params for extracting numeric and text filter
    parameters
  • Implemented bind count validation in debug/test builds
+72/-4   
memory_metrics.rs
Refactor memory metrics query to return SQL and parameters

rust/srql/src/query/memory_metrics.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params for extracting numeric and text filter
    parameters
  • Implemented bind count validation in debug/test builds
+73/-4   
device_updates.rs
Refactor device updates query to return SQL and parameters

rust/srql/src/query/device_updates.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params with support for text and boolean filters
  • Implemented bind count validation in debug/test builds
+78/-4   
events.rs
Refactor events query to return SQL and parameters             

rust/srql/src/query/events.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added collect_filter_params for extracting text and integer filter
    parameters
  • Implemented bind count validation in debug/test builds
+71/-4   
config.rs
Add PostgreSQL client certificate configuration                   

rust/srql/src/config.rs

  • Added pg_ssl_cert and pg_ssl_key configuration fields for client
    certificate authentication
  • Added embedded constructor for creating test/embedded configurations
  • Updated configuration loading to read PGSSLCERT and PGSSLKEY
    environment variables
+23/-0   
trace_summaries.rs
Refactor trace summaries query to return SQL and parameters

rust/srql/src/query/trace_summaries.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added bind_param_from_query conversion function for parameter binding
+20/-3   
lib.rs
Add Elixir NIF for SRQL query translation                               

web-ng/native/srql_nif/src/lib.rs

  • New Elixir NIF module for translating SRQL queries using Rust
    implementation
  • Provides translate function callable from Elixir with query direction
    and mode support
  • Uses embedded database configuration for query translation without
    actual database connection
+49/-0   
device_graph.rs
Refactor device graph query to return SQL and parameters 

rust/srql/src/query/device_graph.rs

  • Refactored to_debug_sql to to_sql_and_params returning SQL and bind
    parameters
  • Added extract_params function to collect device graph query parameters
+11/-3   
models.rs
Add unit field to OTEL metric row model                                   

rust/srql/src/models.rs

  • Added unit field to OtelMetricRow struct for storing metric unit
    information
  • Updated into_json method to include the unit field in JSON output
+2/-0     
app.js
Add Phoenix LiveView application JavaScript setup               

web-ng/assets/js/app.js

  • New Phoenix LiveView application JavaScript entry point with socket
    and live view configuration
  • Implemented custom TimeseriesChart hook for interactive chart tooltips
    and hover effects
  • Configured topbar progress indicator and development features
    including live reload
+142/-0 
heroicons.js
Add Heroicons Tailwind CSS plugin                                               

web-ng/assets/vendor/heroicons.js

  • New Tailwind CSS plugin for integrating Heroicons SVG icon library
  • Supports multiple icon variants (outline, solid, mini, micro) with
    automatic sizing
  • Generates CSS custom properties for icon usage via mask-image
    technique
+43/-0   
onboarding_token.ex
Add edge package onboarding token codec                                   

web-ng/lib/serviceradar_web_ng/edge/onboarding_token.ex

  • New Elixir module for encoding and decoding edge package onboarding
    tokens
  • Implements Base64 URL-safe encoding with JSON payload containing
    package ID, download token, and optional API URL
  • Provides comprehensive validation and error handling for token format
    and content
+82/-0   
srql_components.ex
Add SRQL query interface components and builder                   

web-ng/lib/serviceradar_web_ng_web/components/srql_components.ex

  • Added comprehensive SRQL (ServiceRadar Query Language) component
    module with 818 lines
  • Implemented query bar component with text input, builder toggle, and
    submit button
  • Created results table component with dynamic column detection and cell
    formatting
  • Added auto-visualization component supporting timeseries and
    category-based charts with sparkline rendering
  • Implemented query builder component with entity selection, time
    filters, downsampling options, filter management, sorting, and limit
    controls
  • Included helper functions for cell formatting (time, links, severity
    badges, booleans, JSON), URL parsing, ISO8601 date parsing, and
    category label formatting
+818/-0 
00000000000002_otel_metrics_unit_and_agg.up.sql
Add unit column and hourly metrics aggregation for performance

pkg/db/cnpg/migrations/00000000000002_otel_metrics_unit_and_agg.up.sql

  • Added unit column to otel_metrics table to store metric units (e.g.,
    "ms", "bytes", "1")
  • Created index on unit column for efficient filtering
  • Implemented continuous aggregation view otel_metrics_hourly_stats with
    hourly bucketing for pre-computed statistics
  • Added refresh policy to update aggregation every 15 minutes with
    3-hour start offset and 1-hour end offset
  • Created indexes on aggregation view for efficient time-range and
    service-based queries
  • Granted SELECT permissions to spire role and added documentation
    comment
+63/-0   
Bug fix
2 files
query_utils.go
Implement parameterized SRQL queries to prevent SQL injection

pkg/mcp/query_utils.go

  • Introduced ParameterizedQueryExecutor interface for parameterized SRQL
    query support
  • Added srqlBindBuilder helper to collect bind parameters and generate
    $N placeholders
  • Refactored query builders (buildLogQuery, buildRecentLogsQuery,
    buildDevicesQuery) to return tuples of (query, params)
  • Replaced string interpolation with parameterized binds for
    user-supplied values (timestamps, IDs, filters)
  • Added executeSRQL dispatcher to route queries to parameterized or
    plain executor based on parameter count
+40/-20 
service.go
Fix potential deadlock in SNMP service Check method           

pkg/checker/snmp/service.go

  • Removed s.mu.RLock() and defer s.mu.RUnlock() from Check method
  • Added comment explaining why recursive RWMutex read locking must be
    avoided
  • Allows GetStatus to acquire its own locks without deadlock risk
+3/-4     
Tests
6 files
parameterized_queries_test.go
Add tests for parameterized SRQL query binding                     

pkg/mcp/parameterized_queries_test.go

  • New test file validating parameterized query execution
  • Tests verify that user-supplied values are bound as parameters, not
    concatenated into SQL
  • Includes tests for devices, logs, and events tools with SQL injection
    payloads
  • Validates that structured tools require ParameterizedQueryExecutor
    support
+123/-0 
service_deadlock_test.go
Add deadlock detection test for SNMP service                         

pkg/checker/snmp/service_deadlock_test.go

  • New test file using AST analysis to detect potential deadlock patterns
  • Verifies that Check method does not hold s.mu.RLock() while calling
    GetStatus()
  • Prevents recursive RWMutex read locking which can cause deadlock with
    write-preferring semantics
+101/-0 
registry_test.go
Update registry tests for partition parameter                       

pkg/registry/registry_test.go

  • Updated all BatchGetDeviceIDsByIdentifier mock expectations to include
    partition parameter
  • Affects multiple test cases: allowCanonicalizationQueries,
    TestProcessBatchDeviceUpdates_MergesSweepIntoCanonicalDevice, and
    others
+5/-5     
identity_engine_partition_test.go
Add partition scoping tests for identity engine                   

pkg/registry/identity_engine_partition_test.go

  • New test file validating partition-scoped identity resolution
  • Tests that same MAC address in different partitions resolves to
    different device IDs
  • Verifies batchLookupByStrongIdentifiers correctly groups and processes
    updates by partition
+51/-0   
canon_simulation_test.go
Update DIRE simulation test for partition support               

pkg/registry/canon_simulation_test.go

  • Updated setupDIREMockDB to pass partition parameter to
    BatchGetDeviceIDsByIdentifier
  • Updated cache key construction to use strongIdentifierCacheKey
    function
  • Updated UpsertDeviceIdentifiers mock to use strongIdentifierCacheKey
    for consistency
+4/-4     
harness.rs
Update test harness for SSL configuration                               

rust/srql/tests/support/harness.rs

  • Updated test configuration to include new pg_ssl_cert and pg_ssl_key
    fields set to None
+2/-0     
Miscellaneous
1 files
mock_db.go
Update mock to include partition parameter                             

pkg/db/mock_db.go

  • Updated BatchGetDeviceIDsByIdentifier mock signature to include
    partition parameter
  • Regenerated mock recorder to match updated interface
  • Added blank line formatting fix
+6/-5     
Formatting
1 files
server_test.go
Fix test file formatting                                                                 

pkg/mcp/server_test.go

  • Fixed indentation formatting (spaces to tabs) in test file
+5/-5     
Configuration changes
4 files
schema.rs
Add unit field to OTEL metrics schema                                       

rust/srql/src/schema.rs

  • Added unit field to otel_metrics table schema with Nullable type
+1/-0     
generate-certs.sh
Enhance certificate generation with extra IPs and workstation cert

docker/compose/generate-certs.sh

  • Added support for CNPG_CERT_EXTRA_IPS environment variable to include
    additional IPs in CNPG certificate SANs
  • Implemented certificate regeneration logic when required SANs are
    missing
  • Added generation of workstation client certificate for external
    developer connections
+28/-6   
entrypoint-nginx.sh
Update Nginx entrypoint for web-ng service                             

docker/compose/entrypoint-nginx.sh

  • Updated service health checks to wait for web-ng on port 4000 instead
    of web on port 3000
  • Removed health check for core service on port 8090
+4/-12   
app.css
Add main application CSS with Tailwind and daisyUI configuration

web-ng/assets/css/app.css

  • Added main application CSS file with Tailwind CSS configuration
    imports
  • Configured daisyUI plugin with themes disabled and custom theme
    plugins
  • Defined two custom daisyUI themes: "dark" (Dracula-inspired) and
    "light" (Phoenix-inspired) with complete color palettes and design
    tokens
  • Added custom Tailwind variants for LiveView classes
    (phx-click-loading, phx-submit-loading, phx-change-loading) and dark
    mode support
  • Added CSS rule for transparent display of LiveView wrapper divs
+105/-0 
Dependencies
2 files
daisyui-theme.js
Add daisyUI theme plugin bundle with multiple color schemes

web-ng/assets/vendor/daisyui-theme.js

  • Added new daisyUI theme plugin bundle (124 lines) with MIT license
  • Includes theme configuration system with withOptions plugin function
  • Contains pre-built theme definitions for multiple color schemes
    (cyberpunk, acid, black, dark, light, luxury, dracula, retro, lofi,
    valentine, nord, lemonade, garden, aqua, corporate, pastel, bumblebee,
    coffee, silk, sunset, synthwave, dim, abyss, forest, night,
    caramellatte, autumn, emerald, cupcake, cmyk, business, winter,
    halloween, fantasy, wireframe)
  • Exports theme configuration as CommonJS module
+124/-0 
topbar.js
Add topbar progress bar library for UI feedback                   

web-ng/assets/vendor/topbar.js

  • Added topbar 3.0.0 JavaScript library (138 lines) with MIT license
  • Implements progress bar visualization with canvas rendering
  • Provides configuration options for bar thickness, colors, shadow
    effects, and auto-run behavior
  • Exports topbar object with methods: config(), show(), progress(), and
    hide()
+138/-0 
Additional files
101 files
.env.example +18/-1   
.tool-versions +2/-0     
AGENTS.md +46/-0   
docker-compose.yml +27/-119
Dockerfile.web-ng +71/-0   
nginx.conf.template +6/-138 
AGENTS.md +72/-0   
design.md +0/-29   
proposal.md +0/-25   
spec.md +0/-148 
tasks.md +0/-68   
proposal.md +0/-26   
spec.md +0/-34   
tasks.md +0/-13   
proposal.md +0/-68   
proposal.md +0/-42   
tasks.md +0/-20   
design.md +0/-26   
proposal.md +0/-16   
spec.md +0/-85   
tasks.md +0/-25   
design.md +114/-0 
proposal.md +48/-0   
spec.md +24/-0   
spec.md +22/-0   
tasks.md +83/-0   
design.md +0/-29   
proposal.md +0/-21   
spec.md +0/-23   
tasks.md +0/-19   
design.md +62/-0   
proposal.md +25/-0   
spec.md +20/-0   
tasks.md +28/-0   
proposal.md +0/-14   
spec.md +0/-28   
spec.md +0/-35   
tasks.md +0/-20   
design.md +208/-0 
proposal.md +54/-0   
tasks.md +220/-0 
proposal.md +0/-18   
spec.md +0/-61   
tasks.md +0/-13   
proposal.md +0/-45   
spec.md +0/-60   
tasks.md +0/-28   
proposal.md +0/-83   
spec.md +0/-112 
tasks.md +0/-84   
proposal.md +0/-44   
spec.md +0/-32   
tasks.md +0/-45   
proposal.md +0/-26   
spec.md +0/-46   
tasks.md +0/-24   
proposal.md +0/-19   
spec.md +0/-18   
tasks.md +0/-19   
design.md +32/-0   
proposal.md +22/-0   
spec.md +13/-0   
tasks.md +17/-0   
design.md +30/-0   
proposal.md +15/-0   
spec.md +40/-0   
tasks.md +18/-0   
proposal.md +0/-144 
spec.md +0/-81   
tasks.md +0/-43   
proposal.md +0/-14   
spec.md +0/-14   
tasks.md +0/-17   
proposal.md +16/-0   
spec.md +10/-0   
tasks.md +12/-0   
proposal.md +0/-39   
spec.md +0/-70   
tasks.md +0/-33   
proposal.md +0/-102 
spec.md +0/-46   
tasks.md +0/-53   
proposal.md +0/-125 
proposal.md +0/-129 
spec.md +0/-22   
tasks.md +0/-15   
design.md +0/-126 
proposal.md +0/-45   
spec.md +0/-65   
tasks.md +0/-60   
proposal.md +0/-30   
schema-mapping.md +0/-90   
spec.md +0/-54   
tasks.md +0/-31   
proposal.md +0/-17   
spec.md +0/-13   
tasks.md +0/-9     
proposal.md +0/-155 
tasks.md +0/-92   
proposal.md +0/-14   
Additional files not shown

Imported from GitHub pull request. Original GitHub pull request: #2157 Original author: @mfreeman451 Original URL: https://github.com/carverauto/serviceradar/pull/2157 Original created: 2025-12-16T17:02:01Z Original updated: 2025-12-16T18:01:27Z Original head: carverauto/serviceradar:2142-sql-injection-via-unescaped-device_id-in-srql-query-construction Original base: staging Original merged: 2025-12-16T18:01:21Z by @mfreeman451 --- ### **User description** ## IMPORTANT: Please sign the Developer Certificate of Origin Thank you for your contribution to ServiceRadar. Please note, when contributing, the developer must include a [DCO sign-off statement]( https://developercertificate.org/) indicating the DCO acceptance in one commit message. Here is an example DCO Signed-off-by line in a commit message: ``` Signed-off-by: J. Doe <j.doe@domain.com> ``` ## Describe your changes ## Issue ticket number and link ## Code checklist before requesting a review - [ ] I have signed the DCO? - [ ] The build completes without errors? - [ ] All tests are passing when running make test? ___ ### **PR Type** Bug fix, Enhancement, Tests ___ ### **Description** **SQL Injection Prevention via Parameterized Queries** - Implemented comprehensive parameterized query support across Go and Rust codebase to prevent SQL injection vulnerabilities - Refactored SRQL query builders to use `$N` placeholders instead of string interpolation for user-supplied values - Added `srqlBindBuilder` utility for collecting and binding query parameters - Updated all MCP tools (devices, logs, events, sweeps, alerts) to use parameterized queries **Partition Scoping for Identity Engine** - Enhanced identity resolution with partition-scoped cache keys (`<partition>:<type>:<value>`) - Added `strongIdentifierCacheKey` function for consistent cache key generation - Refactored `batchLookupByStrongIdentifiers` to group and process updates by partition - Updated database interface to include partition parameter in lookups **Rust SRQL Engine Enhancements** - Implemented `BindParam` enum for parameterized query values (Text, TextArray, IntArray, Bool, Int, Float, Timestamptz) - Refactored all entity query builders to return SQL and bind parameters as tuples - Added visualization metadata generation via `VizMeta` types for query results - Implemented downsampling query support for time-series metrics with configurable aggregation - Added Apache AGE Cypher graph query execution with read-only validation - Exported public SRQL types and added `EmbeddedSrql` struct for embedded engine usage - Added Elixir NIF module for SRQL query translation from web-ng **OTEL Metrics Improvements** - Added `unit` field to OTEL metric models (Go and Rust) for storing measurement units - Created continuous aggregation view `otel_metrics_hourly_stats` for pre-computed hourly statistics - Added hourly bucketing with 15-minute refresh policy for performance optimization **SNMP Service Deadlock Fix** - Removed recursive RWMutex read locking in `Check` method to prevent deadlock - Added AST-based deadlock detection test to prevent regression **Web-ng Foundation** - Added Phoenix LiveView application with JavaScript setup and custom hooks - Implemented SRQL query interface components with builder, results table, and auto-visualization - Added edge package onboarding token codec for secure token handling - Integrated Heroicons SVG icon library and daisyUI theme system with multiple color schemes - Added topbar progress bar library for UI feedback **Infrastructure & Configuration** - Added PostgreSQL client certificate authentication support via `PGSSLCERT` and `PGSSLKEY` environment variables - Enhanced certificate generation with `CNPG_CERT_EXTRA_IPS` support and workstation client certificate - Updated Nginx entrypoint to route to web-ng service on port 4000 - Added database schema migration for OTEL metrics unit column and aggregation view ___ ### Diagram Walkthrough ```mermaid flowchart LR A["User Input"] -->|"Parameterized Queries"| B["Query Builder"] B -->|"Bind Parameters"| C["Database Driver"] C -->|"Safe Execution"| D["PostgreSQL"] E["Identity Engine"] -->|"Partition Scoping"| F["Cache Keys"] F -->|"Lookup"| G["Device Resolution"] H["SRQL Engine"] -->|"Visualization Metadata"| I["Query Results"] H -->|"Downsampling"| J["Time-Series Metrics"] H -->|"Graph Cypher"| K["AGE Database"] L["Web-ng UI"] -->|"SRQL NIF"| H L -->|"Components"| M["Query Interface"] ``` <details><summary><h3>File Walkthrough</h3></summary> <table><thead><tr><th></th><th align="left">Relevant files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>43 files</summary><table> <tr> <td> <details> <summary><strong>cnpg_observability.go</strong><dd><code>Refactor OTEL inserts to use parameterized queries</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/db/cnpg_observability.go <ul><li>Refactored OTEL insert operations to use parameterized queries with <br><code>$1</code>, <code>$2</code>, etc. placeholders instead of string formatting<br> <li> Extracted SQL templates as module-level constants (<code>otelLogsInsertSQL</code>, <br><code>otelMetricsInsertSQL</code>, <code>otelTracesInsertSQL</code>)<br> <li> Introduced <code>otelRowInserter</code> interface and concrete implementations to <br>abstract row-specific logic<br> <li> Consolidated duplicate insertion logic into shared <code>insertOTELRows</code> and <br><code>insertOTEL</code> helper functions<br> <li> Added <code>unit</code> field to metrics insert query</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-abaae95adb6fa6d0241553f6d1b39ecff3dd6159db72babbe39dfb3cd231cd3d">+188/-131</a></td> </tr> <tr> <td> <details> <summary><strong>identity_engine.go</strong><dd><code>Add partition scoping to identity engine cache keys</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/registry/identity_engine.go <ul><li>Updated cache key format to include partition: <code><partition>:<type>:<value></code> instead of <code><type>:<value></code><br> <li> Added <code>strongIdentifierCacheKey</code> function to normalize partition and <br>build consistent cache keys<br> <li> Refactored <code>batchLookupByStrongIdentifiers</code> to group updates by <br>partition and process each partition separately<br> <li> Extracted helper functions: <code>groupUpdatesByPartition</code>, <br><code>collectStrongIdentifierSets</code>, <code>batchLookupIdentifierType</code><br> <li> Updated <code>batchLookupByStrongIdentifiersForPartition</code> to accept partition <br>parameter</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-496f24b3784656e1d6bb97cafe5c528bbecea5a0b74b4be578d3b83e858038c7">+124/-54</a></td> </tr> <tr> <td> <details> <summary><strong>builder.go</strong><dd><code>Update filter builders to use parameterized queries</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/mcp/builder.go <ul><li>Updated <code>FilterHandlerFunc</code> and <code>FilterBuilder</code> interface to accept <br><code>srqlBindBuilder</code> parameter<br> <li> Modified <code>GenericFilterBuilder.BuildFilters</code> to use parameterized binds <br>instead of string formatting<br> <li> Added deterministic field processing by sorting JSON field keys before <br>iteration<br> <li> Replaced string interpolation with <code>binds.Bind()</code> calls for filter <br>values</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-ee3c16d7d8882a3a65d28bfedf7f0a5e59698b00ae482bc5565b3314503d5db2">+20/-7</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>server.go</strong><dd><code>Update MCP server to use parameterized queries</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/mcp/server.go <ul><li>Updated <code>executeGetDevice</code> to use parameterized query with <code>$1</code> <br>placeholder<br> <li> Modified <code>executeQueryEvents</code> to build parameterized queries for time <br>range filters<br> <li> Added <code>executeSRQLQueryWithParams</code> method to dispatch to <br><code>ParameterizedQueryExecutor</code><br> <li> Refactored <code>executeSRQLQuery</code> to delegate to <code>executeSRQLQueryWithParams</code> <br>with empty params</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-bbb88ac338d81b0a37cd59fc53d68171d2de4780653253a2fd257f18fbf81bd0">+24/-7</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>tools_sweeps.go</strong><dd><code>Update sweep tools to use parameterized queries</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/mcp/tools_sweeps.go <ul><li>Refactored <code>registerGetRecentSweepsTool</code> to use parameterized query for <br><code>poller_id</code> filter<br> <li> Refactored <code>registerGetSweepSummaryTool</code> to use parameterized query for <br><code>poller_id</code> filter<br> <li> Replaced string interpolation with <code>$1</code> placeholder and <code>queryParams</code> <br>array</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-c2ddcfeb6736358e171e60164cac1cb48b8af464bebe8445fd17fe580caaaa2f">+8/-4</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>cnpg_identity_engine.go</strong><dd><code>Add partition filtering to identity lookups</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/db/cnpg_identity_engine.go <ul><li>Updated <code>batchGetDeviceIDsByIdentifierSQL</code> to filter by <code>partition</code> column <br>with <code>$3</code> parameter<br> <li> Modified <code>BatchGetDeviceIDsByIdentifier</code> to accept and pass <code>partition</code> <br>parameter to query<br> <li> Added default partition handling when partition is empty string</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-756702fbe82153fa86ae9b6bd6e5b109901d5fb8ee27cb9bc19f51277d3632f0">+8/-3</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>tools_events.go</strong><dd><code>Update alerts tool to use parameterized queries</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/mcp/tools_events.go <ul><li>Updated <code>registerGetAlertsTool</code> to use parameterized query for <code>poller_id</code> <br>filter<br> <li> Replaced string interpolation with <code>$1</code> placeholder and <code>queryParams</code> <br>array</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-3adaae4a85720d41db6c831160f8fd28273584047ac4a4540f2f9bcc5c6bcd90">+4/-2</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>tools_devices.go</strong><dd><code>Update device tools to use parameterized queries</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/mcp/tools_devices.go <ul><li>Updated <code>registerDeviceTools</code> to use parameterized query for <code>device_id</code> <br>filter<br> <li> Replaced string interpolation with <code>$1</code> placeholder and <code>queryParams</code> <br>array</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-9305d32d7f3683b79015dd7448623cf5393bf7f0631548313d810a3ed08d65dd">+3/-3</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>tools_logs.go</strong><dd><code>Update log tools to use parameterized queries</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/mcp/tools_logs.go <ul><li>Updated <code>registerLogTools</code> to use parameterized query for <code>poller_id</code> <br>filter<br> <li> Replaced string interpolation with <code>$1</code> placeholder and <code>queryParams</code> <br>array</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-8f85b80d8ce508452e002b324e459f01c581bbd97ad961c7e30a054505d8f29a">+4/-2</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>interfaces.go</strong><dd><code>Update database interface for partition support</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/db/interfaces.go <ul><li>Updated <code>BatchGetDeviceIDsByIdentifier</code> interface signature to include <br><code>partition</code> parameter</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-c230fe0c315251837357bfde4ae7f7b34080398d8e48af6bf78badb2124271f3">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>binds.go</strong><dd><code>Add SRQL parameter binding builder utility</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/mcp/binds.go <ul><li>New file introducing <code>srqlBindBuilder</code> struct for collecting query <br>parameters<br> <li> Provides <code>Bind</code> method to append values and generate <code>$N</code> placeholders</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-d974916543440aa2780504c53b6aa34621e95f117e6ed9725c9723543abbc063">+12/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>otel.go</strong><dd><code>Add unit field to OTEL metric model</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/models/otel.go <ul><li>Added <code>Unit</code> field to <code>OTELMetricRow</code> struct for measurement units (e.g., <br>"ms", "bytes")</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-1e3b11419ec190436bdb0f61dc96c17cb51ffad29964e6d16f4621b74f2c36cc">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>mod.rs</strong><dd><code>Implement parameterized query support in Rust SRQL engine</code></dd></summary> <hr> rust/srql/src/query/mod.rs <ul><li>Added <code>BindParam</code> enum to represent parameterized query values (Text, <br>TextArray, IntArray, Bool, Int, Float, Timestamptz)<br> <li> Refactored <code>translate</code> method to use new <code>translate_request</code> function<br> <li> Added support for downsample and graph_cypher entities in query <br>execution<br> <li> Introduced helper functions: <code>max_dollar_placeholder</code>, <br><code>reconcile_limit_offset_binds</code>, <code>diesel_sql</code>, <code>diesel_bind_count</code><br> <li> Updated <code>TranslateResponse</code> to include <code>params</code> as <code>Vec<BindParam></code>, <code>pagination</code>, and <br><code>viz</code> metadata<br> <li> Added comprehensive tests for parameter arity matching, visualization <br>metadata, and graph cypher validation</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-393e3fa3d0e41741834cd7cd398a06111ab7b141ae6caca7a5dcc0e036172491">+523/-58</a></td> </tr> <tr> <td> <details> <summary><strong>viz.rs</strong><dd><code>Add visualization metadata generation for queries</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/viz.rs <ul><li>New file providing visualization metadata generation for query results<br> <li> Defines <code>VizMeta</code>, <code>ColumnMeta</code>, <code>ColumnType</code>, <code>ColumnSemantic</code>, and <br><code>VizSuggestion</code> types<br> <li> Implements <code>meta_for_plan</code> function to generate column and suggestion <br>metadata for all entity types<br> <li> Supports timeseries and table visualization kinds with semantic hints</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-70c860470ae125afe6d7e4a2f9cf9eb36f8967ae773c3a47804329bbf56a2d8b">+605/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>devices.rs</strong><dd><code>Implement parameterized queries for devices entity</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/devices.rs <ul><li>Updated <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning tuple of SQL and <br><code>Vec<BindParam></code><br> <li> Added stats query support with <code>parse_stats_spec</code> and <code>build_stats_query</code> <br>functions<br> <li> Implemented <code>collect_filter_params</code> to extract bind parameters from <br>device filters<br> <li> Added parameter collection for time ranges, filters, and limit/offset <br>clauses<br> <li> Includes bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-3202f22fff6863ed7848a129c49e2323322462b379d896d3fca2e59aa6f7b4c5">+195/-7</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>interfaces.rs</strong><dd><code>Implement parameterized queries for interfaces entity</code>&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/interfaces.rs <ul><li>Updated <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning tuple of SQL and <br><code>Vec<BindParam></code><br> <li> Implemented <code>collect_filter_params</code> to extract bind parameters from <br>interface filters<br> <li> Added parameter collection for time ranges, filters, and limit/offset <br>clauses<br> <li> Includes bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-1ec833d4525fb2806523888b8c57b76ca8dd2ab70539368ccecc4d262769c8c5">+112/-8</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>lib.rs</strong><dd><code>Export SRQL types and add embedded engine support</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/lib.rs <ul><li>Exported public types: <code>QueryDirection</code>, <code>QueryEngine</code>, <code>QueryRequest</code>, <br><code>QueryResponse</code>, <code>TranslateRequest</code>, <code>TranslateResponse</code><br> <li> Added <code>EmbeddedSrql</code> struct for embedded SRQL engine usage<br> <li> Implemented <code>EmbeddedSrql::new</code> constructor to initialize query engine <br>with connection pool</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-8c0401c0d0bb9761ed66ff5328703755132a87d625f77878f53037e2329644b8">+19/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>downsample.rs</strong><dd><code>Add downsampling query support for time-series metrics</code>&nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/downsample.rs <ul><li>New file implementing downsampling query support for time-series <br>metrics with configurable bucket sizes and aggregation functions<br> <li> Provides SQL generation and parameter binding for downsampled queries <br>across multiple metric entity types<br> <li> Implements series expression building and filter clause generation <br>with proper parameter escaping<br> <li> Includes placeholder rewriting to convert <code>?</code> to PostgreSQL <code>$N</code> format</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-94f68b4684578afa112ab05ff903667b6cd902ad276e17c12af350078b300a6a">+521/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>services.rs</strong><dd><code>Refactor services query to return SQL and parameters</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/services.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning both SQL and <br>bind parameters<br> <li> Added stats query support with <code>parse_stats_spec</code> and <code>build_stats_query</code> <br>functions<br> <li> Implemented <code>collect_filter_params</code> to extract bind parameters from <br>filters<br> <li> Added bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-ad5e7e1a352406ed473a765de4856625f1bede590e7e2c724163bcd1e7b313e9">+172/-4</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>parser.rs</strong><dd><code>Add downsampling and graph cypher query parsing support</code>&nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/parser.rs <ul><li>Added <code>GraphCypher</code> entity type for graph database queries<br> <li> Introduced <code>DownsampleSpec</code> and <code>DownsampleAgg</code> types for downsampling <br>configuration<br> <li> Added parsing for <code>bucket</code>, <code>agg</code>, and <code>series</code> tokens for downsampling <br>queries<br> <li> Enhanced stats parsing to support <code>as alias</code> syntax with validation</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-b2edf55d1721185349ecddb2f4eacc42e0dfcae19b6c2bc638602f187da67e66">+157/-2</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>graph_cypher.rs</strong><dd><code>Add Apache AGE Cypher graph query support</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/graph_cypher.rs <ul><li>New file implementing Apache AGE Cypher query execution against <br>PostgreSQL graph database<br> <li> Provides SQL generation with proper dollar-quoting for Cypher queries<br> <li> Implements read-only validation to prevent write operations<br> <li> Includes sophisticated placeholder rewriting that respects string <br>literals and dollar-quoted strings</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-378b0ec80e1b1221c347160a0dac36c82d082fa06766d47d18cf069220166309">+208/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>traces.rs</strong><dd><code>Refactor traces query to return SQL and parameters</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/traces.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> and <code>collect_i32_list</code> for parameter <br>extraction<br> <li> Implemented bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-f390b0aef82baa9c3438719276dca70be826318d7446074a83b4527558528e19">+109/-4</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>logs.rs</strong><dd><code>Refactor logs query to return SQL and parameters</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/logs.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> for parameter extraction from various <br>filter types<br> <li> Implemented stats query support with parameter binding</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-f4d3b33667f2e79a6ebe4cfff931f93c728d9a81c305ac13586e623850a504db">+103/-3</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>cpu_metrics.rs</strong><dd><code>Refactor CPU metrics query to return SQL and parameters</code>&nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/cpu_metrics.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> for extracting numeric and text filter <br>parameters<br> <li> Implemented bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-400c860c805cd3e1a5e7f7c42cece63cce3e62c1f3fd8b49a5803e26b40fe31e">+85/-5</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>pollers.rs</strong><dd><code>Refactor pollers query to return SQL and parameters</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/pollers.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> for parameter extraction with boolean <br>support<br> <li> Implemented bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-e2192a3ba3041ed995e0abf9973489b7dff550949ff75da41d31bf514e765cc4">+81/-14</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>otel_metrics.rs</strong><dd><code>Refactor OTEL metrics query to return SQL and parameters</code>&nbsp; </dd></summary> <hr> rust/srql/src/query/otel_metrics.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> for extracting text and boolean filter <br>parameters<br> <li> Implemented bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-8106bfa2099b8a6d945b338532f8b1108467e2f0592ddbd64d546fcbce3e3613">+85/-5</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>db.rs</strong><dd><code>Add PostgreSQL client certificate authentication support</code>&nbsp; </dd></summary> <hr> rust/srql/src/db.rs <ul><li>Added support for client certificate and key configuration via <br><code>PGSSLCERT</code> and <code>PGSSLKEY</code> environment variables<br> <li> Implemented <code>build_client_config</code>, <code>load_client_certs</code>, and <br><code>load_client_key</code> functions for mutual TLS<br> <li> Updated <code>PgConnectionManager::new</code> to accept optional client certificate <br>and key paths</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-8d5a0c48024aa12a3e06de065ca71e940d2b5007fbc34ef87471b90d7937891c">+77/-10</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>timeseries_metrics.rs</strong><dd><code>Refactor timeseries metrics query to return SQL and parameters</code></dd></summary> <hr> rust/srql/src/query/timeseries_metrics.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> for extracting numeric and text filter <br>parameters<br> <li> Implemented bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-8450bff3aef4c1271bbf9b96809b4a5ac7b218e3f98c8b60387e35dbf4845bb0">+82/-4</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>process_metrics.rs</strong><dd><code>Refactor process metrics query to return SQL and parameters</code></dd></summary> <hr> rust/srql/src/query/process_metrics.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> for extracting numeric and text filter <br>parameters<br> <li> Implemented bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-c70bb600f5fba7199d80930fdc735cfc38371ef2d4ff3c821af55100e4cb0bac">+77/-4</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>disk_metrics.rs</strong><dd><code>Refactor disk metrics query to return SQL and parameters</code>&nbsp; </dd></summary> <hr> rust/srql/src/query/disk_metrics.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> for extracting numeric and text filter <br>parameters<br> <li> Implemented bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-b5a536baa37176f971e96c789991202b483314e2a85d4556489b4568a5675162">+72/-4</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>memory_metrics.rs</strong><dd><code>Refactor memory metrics query to return SQL and parameters</code></dd></summary> <hr> rust/srql/src/query/memory_metrics.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> for extracting numeric and text filter <br>parameters<br> <li> Implemented bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-a12a227c4b5c224359799853f5fd7bbf626ec14b1e7eae40e4c65b1db6699417">+73/-4</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>device_updates.rs</strong><dd><code>Refactor device updates query to return SQL and parameters</code></dd></summary> <hr> rust/srql/src/query/device_updates.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> with support for text and boolean filters<br> <li> Implemented bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-77b99f0ef409a6a3e4ecc65800ae841231a82b27a64e8dc1d4667db6698a539d">+78/-4</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>events.rs</strong><dd><code>Refactor events query to return SQL and parameters</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/query/events.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>collect_filter_params</code> for extracting text and integer filter <br>parameters<br> <li> Implemented bind count validation in debug/test builds</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-ad603163a35223c63c68279e53a1a4c9219b9096042a168d8a87443abaa29a58">+71/-4</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>config.rs</strong><dd><code>Add PostgreSQL client certificate configuration</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/config.rs <ul><li>Added <code>pg_ssl_cert</code> and <code>pg_ssl_key</code> configuration fields for client <br>certificate authentication<br> <li> Added <code>embedded</code> constructor for creating test/embedded configurations<br> <li> Updated configuration loading to read <code>PGSSLCERT</code> and <code>PGSSLKEY</code> <br>environment variables</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-8a094b8b89c66adf329551634fa2c9c0e2ad9a1043f42012ad11cd3bf3f8ab6a">+23/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>trace_summaries.rs</strong><dd><code>Refactor trace summaries query to return SQL and parameters</code></dd></summary> <hr> rust/srql/src/query/trace_summaries.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>bind_param_from_query</code> conversion function for parameter binding</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-ff98619eb5dc4d75205d1797477e9e2880f42081e8d0c61d6fd1d6e5926b72fa">+20/-3</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>lib.rs</strong><dd><code>Add Elixir NIF for SRQL query translation</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> web-ng/native/srql_nif/src/lib.rs <ul><li>New Elixir NIF module for translating SRQL queries using Rust <br>implementation<br> <li> Provides <code>translate</code> function callable from Elixir with query direction <br>and mode support<br> <li> Uses embedded database configuration for query translation without <br>actual database connection</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-74a225cdf31e64db49fb42c0419c524068150b07528e8d722a75e3ec8034c297">+49/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>device_graph.rs</strong><dd><code>Refactor device graph query to return SQL and parameters</code>&nbsp; </dd></summary> <hr> rust/srql/src/query/device_graph.rs <ul><li>Refactored <code>to_debug_sql</code> to <code>to_sql_and_params</code> returning SQL and bind <br>parameters<br> <li> Added <code>extract_params</code> function to collect device graph query parameters</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-a6e5019c94fdef4f11f3c834e5e6ecac78efd5ce40f34b93bb64fe8076db9011">+11/-3</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>models.rs</strong><dd><code>Add unit field to OTEL metric row model</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/models.rs <ul><li>Added <code>unit</code> field to <code>OtelMetricRow</code> struct for storing metric unit <br>information<br> <li> Updated <code>into_json</code> method to include the <code>unit</code> field in JSON output</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-57c82b01f92e9bd40063d0b0178c12d452771ac133f2121fb0ac008b167da367">+2/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>app.js</strong><dd><code>Add Phoenix LiveView application JavaScript setup</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> web-ng/assets/js/app.js <ul><li>New Phoenix LiveView application JavaScript entry point with socket <br>and live view configuration<br> <li> Implemented custom <code>TimeseriesChart</code> hook for interactive chart tooltips <br>and hover effects<br> <li> Configured topbar progress indicator and development features <br>including live reload</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-16bc6f19f34cfdd66ac36b4ef2dd66d34e3470c4eb324ebc3e4bb8e58a91360c">+142/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>heroicons.js</strong><dd><code>Add Heroicons Tailwind CSS plugin</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> web-ng/assets/vendor/heroicons.js <ul><li>New Tailwind CSS plugin for integrating Heroicons SVG icon library<br> <li> Supports multiple icon variants (outline, solid, mini, micro) with <br>automatic sizing<br> <li> Generates CSS custom properties for icon usage via mask-image <br>technique</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-435329705234b4577a06b84302017b73aaf264e7af376e6bfd5abbf71611d9bd">+43/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>onboarding_token.ex</strong><dd><code>Add edge package onboarding token codec</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> web-ng/lib/serviceradar_web_ng/edge/onboarding_token.ex <ul><li>New Elixir module for encoding and decoding edge package onboarding <br>tokens<br> <li> Implements Base64 URL-safe encoding with JSON payload containing <br>package ID, download token, and optional API URL<br> <li> Provides comprehensive validation and error handling for token format <br>and content</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-e2e1ed43a06834d4af7dfb07b38dd2f67d4c801ec8c7a1eea40759b59de83010">+82/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>srql_components.ex</strong><dd><code>Add SRQL query interface components and builder</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> web-ng/lib/serviceradar_web_ng_web/components/srql_components.ex <ul><li>Added comprehensive SRQL (ServiceRadar Query Language) component <br>module with 818 lines<br> <li> Implemented query bar component with text input, builder toggle, and <br>submit button<br> <li> Created results table component with dynamic column detection and cell <br>formatting<br> <li> Added auto-visualization component supporting timeseries and <br>category-based charts with sparkline rendering<br> <li> Implemented query builder component with entity selection, time <br>filters, downsampling options, filter management, sorting, and limit <br>controls<br> <li> Included helper functions for cell formatting (time, links, severity <br>badges, booleans, JSON), URL parsing, ISO8601 date parsing, and <br>category label formatting</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-aeeb844af4bc736fac30dab33b73c6d9023ffa5c75b79dacfbc287b61524ec59">+818/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>00000000000002_otel_metrics_unit_and_agg.up.sql</strong><dd><code>Add unit column and hourly metrics aggregation for performance</code></dd></summary> <hr> pkg/db/cnpg/migrations/00000000000002_otel_metrics_unit_and_agg.up.sql <ul><li>Added <code>unit</code> column to <code>otel_metrics</code> table to store metric units (e.g., <br>"ms", "bytes", "1")<br> <li> Created index on <code>unit</code> column for efficient filtering<br> <li> Implemented continuous aggregation view <code>otel_metrics_hourly_stats</code> with <br>hourly bucketing for pre-computed statistics<br> <li> Added refresh policy to update aggregation every 15 minutes with <br>3-hour start offset and 1-hour end offset<br> <li> Created indexes on aggregation view for efficient time-range and <br>service-based queries<br> <li> Granted SELECT permissions to <code>spire</code> role and added documentation <br>comment</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-b72421ae372e6c3faecf402cf1e945f9c5b092cf19c73c2c3fd86a45acd00547">+63/-0</a>&nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Bug fix</strong></td><td><details><summary>2 files</summary><table> <tr> <td> <details> <summary><strong>query_utils.go</strong><dd><code>Implement parameterized SRQL queries to prevent SQL injection</code></dd></summary> <hr> pkg/mcp/query_utils.go <ul><li>Introduced <code>ParameterizedQueryExecutor</code> interface for parameterized SRQL <br>query support<br> <li> Added <code>srqlBindBuilder</code> helper to collect bind parameters and generate <br><code>$N</code> placeholders<br> <li> Refactored query builders (<code>buildLogQuery</code>, <code>buildRecentLogsQuery</code>, <br><code>buildDevicesQuery</code>) to return tuples of <code>(query, params)</code><br> <li> Replaced string interpolation with parameterized binds for <br>user-supplied values (timestamps, IDs, filters)<br> <li> Added <code>executeSRQL</code> dispatcher to route queries to parameterized or <br>plain executor based on parameter count</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-6a33491056954507b65b8252854786d3d9c65534c7c88700fcc2592f808b192b">+40/-20</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>service.go</strong><dd><code>Fix potential deadlock in SNMP service Check method</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/checker/snmp/service.go <ul><li>Removed <code>s.mu.RLock()</code> and <code>defer s.mu.RUnlock()</code> from <code>Check</code> method<br> <li> Added comment explaining why recursive RWMutex read locking must be <br>avoided<br> <li> Allows <code>GetStatus</code> to acquire its own locks without deadlock risk</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-c592649b582c62a85d1dd416ac7fb609e55531cb43c8199a15f4432ce8ae05d8">+3/-4</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Tests</strong></td><td><details><summary>6 files</summary><table> <tr> <td> <details> <summary><strong>parameterized_queries_test.go</strong><dd><code>Add tests for parameterized SRQL query binding</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/mcp/parameterized_queries_test.go <ul><li>New test file validating parameterized query execution<br> <li> Tests verify that user-supplied values are bound as parameters, not <br>concatenated into SQL<br> <li> Includes tests for devices, logs, and events tools with SQL injection <br>payloads<br> <li> Validates that structured tools require <code>ParameterizedQueryExecutor</code> <br>support</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-330a1eb194c06c458ba999e3ce7346c4dc33dea154e15a8132dc6fc13bf3c296">+123/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>service_deadlock_test.go</strong><dd><code>Add deadlock detection test for SNMP service</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/checker/snmp/service_deadlock_test.go <ul><li>New test file using AST analysis to detect potential deadlock patterns<br> <li> Verifies that <code>Check</code> method does not hold <code>s.mu.RLock()</code> while calling <br><code>GetStatus()</code><br> <li> Prevents recursive RWMutex read locking which can cause deadlock with <br>write-preferring semantics</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-6a31b13924de8ba2b712fc5deb881056c50f7448bb61eb84efe82850eb08325e">+101/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>registry_test.go</strong><dd><code>Update registry tests for partition parameter</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/registry/registry_test.go <ul><li>Updated all <code>BatchGetDeviceIDsByIdentifier</code> mock expectations to include <br><code>partition</code> parameter<br> <li> Affects multiple test cases: <code>allowCanonicalizationQueries</code>, <br><code>TestProcessBatchDeviceUpdates_MergesSweepIntoCanonicalDevice</code>, and <br>others</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-f010972d104404be52d2a8e6e784cb56e31194f90795a69571a12696bcbdc075">+5/-5</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>identity_engine_partition_test.go</strong><dd><code>Add partition scoping tests for identity engine</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/registry/identity_engine_partition_test.go <ul><li>New test file validating partition-scoped identity resolution<br> <li> Tests that same MAC address in different partitions resolves to <br>different device IDs<br> <li> Verifies <code>batchLookupByStrongIdentifiers</code> correctly groups and processes <br>updates by partition</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-77aee244beb622dec723a0a62d2d11785b5b76a9fe5df912ba559227d3f4ba70">+51/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>canon_simulation_test.go</strong><dd><code>Update DIRE simulation test for partition support</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/registry/canon_simulation_test.go <ul><li>Updated <code>setupDIREMockDB</code> to pass <code>partition</code> parameter to <br><code>BatchGetDeviceIDsByIdentifier</code><br> <li> Updated cache key construction to use <code>strongIdentifierCacheKey</code> <br>function<br> <li> Updated <code>UpsertDeviceIdentifiers</code> mock to use <code>strongIdentifierCacheKey</code> <br>for consistency</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-73b73409b3941af4ac860561c87772763feca734fd8ab597f36e5e4047c6bf3c">+4/-4</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>harness.rs</strong><dd><code>Update test harness for SSL configuration</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/tests/support/harness.rs <ul><li>Updated test configuration to include new <code>pg_ssl_cert</code> and <code>pg_ssl_key</code> <br>fields set to <code>None</code></ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-f15ba86798901e9218b7310fbeae763be61ab6ccf3fe592a79d63eda02eea8b4">+2/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Miscellaneous</strong></td><td><details><summary>1 files</summary><table> <tr> <td> <details> <summary><strong>mock_db.go</strong><dd><code>Update mock to include partition parameter</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/db/mock_db.go <ul><li>Updated <code>BatchGetDeviceIDsByIdentifier</code> mock signature to include <br><code>partition</code> parameter<br> <li> Regenerated mock recorder to match updated interface<br> <li> Added blank line formatting fix</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-30e38f888d4849fc40d7ebb1559c2a84c43aa8cd13b3b89fd7ec6cf873b243c7">+6/-5</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Formatting</strong></td><td><details><summary>1 files</summary><table> <tr> <td> <details> <summary><strong>server_test.go</strong><dd><code>Fix test file formatting</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/mcp/server_test.go - Fixed indentation formatting (spaces to tabs) in test file </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-0b91a426e8631fe9cc9109206e3e6d922ff1de7dfdee7b4c6518fbdd94e86c7a">+5/-5</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Configuration changes</strong></td><td><details><summary>4 files</summary><table> <tr> <td> <details> <summary><strong>schema.rs</strong><dd><code>Add unit field to OTEL metrics schema</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> rust/srql/src/schema.rs <ul><li>Added <code>unit</code> field to <code>otel_metrics</code> table schema with <code>Nullable<Text></code> type</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-2fe4906f42b52f96b7bc2d3431885b996b6701cfb88416905ae130b472d536ea">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>generate-certs.sh</strong><dd><code>Enhance certificate generation with extra IPs and workstation cert</code></dd></summary> <hr> docker/compose/generate-certs.sh <ul><li>Added support for <code>CNPG_CERT_EXTRA_IPS</code> environment variable to include <br>additional IPs in CNPG certificate SANs<br> <li> Implemented certificate regeneration logic when required SANs are <br>missing<br> <li> Added generation of <code>workstation</code> client certificate for external <br>developer connections</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-8298241543b4744a6ac7780c760ac5b5a0a87ba62de19c8612ebe1aba0996ebd">+28/-6</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>entrypoint-nginx.sh</strong><dd><code>Update Nginx entrypoint for web-ng service</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> docker/compose/entrypoint-nginx.sh <ul><li>Updated service health checks to wait for <code>web-ng</code> on port 4000 instead <br>of <code>web</code> on port 3000<br> <li> Removed health check for <code>core</code> service on port 8090</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-0372d61e48b7bdb23bed91a7f72fc774fe36afca5ecafc97b170ed35be4e2e59">+4/-12</a>&nbsp; &nbsp; </td> </tr> <tr> <td> <details> <summary><strong>app.css</strong><dd><code>Add main application CSS with Tailwind and daisyUI configuration</code></dd></summary> <hr> web-ng/assets/css/app.css <ul><li>Added main application CSS file with Tailwind CSS configuration <br>imports<br> <li> Configured daisyUI plugin with themes disabled and custom theme <br>plugins<br> <li> Defined two custom daisyUI themes: "dark" (Dracula-inspired) and <br>"light" (Phoenix-inspired) with complete color palettes and design <br>tokens<br> <li> Added custom Tailwind variants for LiveView classes <br>(<code>phx-click-loading</code>, <code>phx-submit-loading</code>, <code>phx-change-loading</code>) and dark <br>mode support<br> <li> Added CSS rule for transparent display of LiveView wrapper divs</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-e2f1698b818ca68e34f2f330886b5dc3621fb6033b4414869c7e3d677aa4c4d3">+105/-0</a>&nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Dependencies</strong></td><td><details><summary>2 files</summary><table> <tr> <td> <details> <summary><strong>daisyui-theme.js</strong><dd><code>Add daisyUI theme plugin bundle with multiple color schemes</code></dd></summary> <hr> web-ng/assets/vendor/daisyui-theme.js <ul><li>Added new daisyUI theme plugin bundle (124 lines) with MIT license<br> <li> Includes theme configuration system with <code>withOptions</code> plugin function<br> <li> Contains pre-built theme definitions for multiple color schemes <br>(cyberpunk, acid, black, dark, light, luxury, dracula, retro, lofi, <br>valentine, nord, lemonade, garden, aqua, corporate, pastel, bumblebee, <br>coffee, silk, sunset, synthwave, dim, abyss, forest, night, <br>caramellatte, autumn, emerald, cupcake, cmyk, business, winter, <br>halloween, fantasy, wireframe)<br> <li> Exports theme configuration as CommonJS module</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-1f651678246fddd353d5b865da740f0fd7f0a16d5e252a378d791ae43136c803">+124/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>topbar.js</strong><dd><code>Add topbar progress bar library for UI feedback</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> web-ng/assets/vendor/topbar.js <ul><li>Added topbar 3.0.0 JavaScript library (138 lines) with MIT license<br> <li> Implements progress bar visualization with canvas rendering<br> <li> Provides configuration options for bar thickness, colors, shadow <br>effects, and auto-run behavior<br> <li> Exports topbar object with methods: <code>config()</code>, <code>show()</code>, <code>progress()</code>, and <br><code>hide()</code></ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-b33ec2270b5ebb791a0c96c3ff024f82d66d346be6d542374e5885273f7bc004">+138/-0</a>&nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Additional files</strong></td><td><details><summary>101 files</summary><table> <tr> <td><strong>.env.example</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-a3046da0d15a27e89f2afe639b25748a7ad4d9290af3e7b1b6c1a5533c8f0a8c">+18/-1</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>.tool-versions</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-751af1a340658c7b8176fe32d7db9fadbe15d1d075daba1919a91df04155bc70">+2/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>AGENTS.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-a54ff182c7e8acf56acfd6e4b9c3ff41e2c41a31c9b211b2deb9df75d9a478f9">+46/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>docker-compose.yml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-e45e45baeda1c1e73482975a664062aa56f20c03dd9d64a827aba57775bed0d3">+27/-119</a></td> </tr> <tr> <td><strong>Dockerfile.web-ng</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-92d43af1965575d56c3380ecc8a81024aac2ff36f039ec2d3839e9fc7852bc10">+71/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>nginx.conf.template</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-62ef305390094ce81632d493253e470ca46e7daa76da1079c131e41502975d07">+6/-138</a>&nbsp; </td> </tr> <tr> <td><strong>AGENTS.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-593e5b1ccdb5f528a4b0f5d7dd56b10c4422aeb11cf7292bf4c21a93a7756340">+72/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>design.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-5e5a5da59cb9f0b4f7a8fc3c492f1be70a9292fc0533fe4fc103a85f27f3c105">+0/-29</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-3fa8ff1eb6c2b79b5937f3b7e97d0eaa429475802e0e136d70e61f3ce8b996e1">+0/-25</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-68425fc01e3047a9fd103cfcb917fa84bdc3f2781539b29a5f0f983753d57627">+0/-148</a>&nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-8bd336677c2048834707d9f86bcb964404304815695a2ebd7273203c57cb7c92">+0/-68</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-6f0c5aff0b965fcdd9db0c5694e0687fa72e170a89c33bda18ec8f82f426ad33">+0/-26</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-2860cadf010e37686782686da542b1669a8e860231acf8b00bbadbbde3f54719">+0/-34</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-bc5b4da0f06380ea7f2f89c15b94cdbfc7c6637d3db0b6703950e2609f7933ff">+0/-13</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-bf83f1fb2e0bb30309a84bc3343bc28a06fef20726e1c8583b406a93697dfc87">+0/-68</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-ad29ce951260d3acc52d2ff591319fda8dbf485bb420f3968f8a9dfd1e91c856">+0/-42</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-557ef0882398cb52535288f1dc8edd81197b0a34dc62ca68b69ecf1754d3c479">+0/-20</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>design.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-888d2efd1371a95f95ba77bf4506d180c1fd65434603a56cf2e8a3ad495386ce">+0/-26</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-f3c3c8d9463a1c6eb3934bb6c516985accb7f58b402a0d5e414ff65c1c732bc3">+0/-16</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-6e956f86e942a3106c94ea3f1a1bd46210c035e9240be297a488b639449d3e90">+0/-85</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-7d7c4d6b4718fd5255ec47aa62dee71b5da2c83ff2160164603454379b618181">+0/-25</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>design.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-799ac314609701ea23f8321cd5e4464c24b9c4634ee8b863d104dc2955aa6eda">+114/-0</a>&nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-bfc316cf42c3c49e04d2363e9ee566c1d78cd3d8830932590ddc8abe2e777a24">+48/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-b3d0f1681371e322ccc253767df5d32e59d23aaddfb979da0746932ef1f97139">+24/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-5482ba561260689cb4331860e556a69f4e0c312d8b6a0636c4e354e80bfff88a">+22/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-08fc870484787c82a4ca64544593d4fbeb34b7d2d09c0bd6f1ae1f1354ae1368">+83/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>design.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-4aa7fc4af23187c7e80727f72cd233de9676cb832a0850271ea8c180dd50c140">+0/-29</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-cea28b6af37c67606e313f2233bd1ae7187f9a4e1289bef0823678c8346e6b7c">+0/-21</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-dbf6e0bdd671feb4089a7d8897979220c1a3f7442d99cd6badf2c02cd80b4d03">+0/-23</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-16748c17e91c4e6e2e591bec79735cf7c956cfd005e0aa7787d0893c04cf08d0">+0/-19</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>design.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-fcc4aa820ee62670cf4965e87b2e0206086d7bb9f83d4146f68a3d763ed66fd6">+62/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-5a6bb224d3c0031de4edb02183b529c4e54b7d0c4f2972babcc848411436718f">+25/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-1e72eebd22cd4f5b5250f5b168b102c3b6fcc5d1ef2418d71acba7a0e3efd340">+20/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-eeff025d43ddd0d8d735cd97a9aa573b0d831f44190263c5cdcddce34d1a9b01">+28/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-81a990985d497493238589e703ea366222940cc604a571ce21bfeca5bfc442e5">+0/-14</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-f5daa5f8f49623f6cec383c2b7197ae8431b51bb217c391dd3f674a380bba00d">+0/-28</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-21ba4baae6c7dbf1e091af2f2cfde05086826dcd839802d6e26eaa407eab584c">+0/-35</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-c00044e9668389895df2d518bf418b693b3a12ad3488e2926abbdd71b98644ba">+0/-20</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>design.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-cb59e5a2e863f7206ac3be889b3cc23b7eef933fbc33909b0d4f19235eeacbd6">+208/-0</a>&nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-381b711be98b0c138b5513beec105376f4b63e46d82bfd75e7d22e4b0eb3e6ff">+54/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-52b58e4010c2df75f7534dc76212ed1c275e462f5f4be90fa0b947a5bfd407ce">+220/-0</a>&nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-8478335a646a61fa4a74ea2f9c784cd441632ec92dba1b3f8d5b5fed52c9db3d">+0/-18</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-e14559d7bc9392db00b7d08e31b875dd4fbe0eb15538a04ec4e9dbd8b342ad8c">+0/-61</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-da75158b3b75bf8129cbec0f47cd86dcee1b97f8cccb1b1864c628e11fb83beb">+0/-13</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-7af7b9e5ec186b60f6082c416f1cf7fa777e26c7b67aa7a2fe5f582f3c558813">+0/-45</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-860d8d8d95eb220b8d6e5590df8982fec404e52dea8565587343d431998e54bb">+0/-60</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-9031f16c5cff8b7150870d905750fef62ad51f9ec20faec52aa62a74efcb79a9">+0/-28</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-ed59ef5f7b9f94cea669c81eccf7ae83d579c5ea60b4f139da3eb68a02e368ff">+0/-83</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-796f2e05e4b1942bcfd740f51f5f5a63cace288520ceee7a439936da6196521e">+0/-112</a>&nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-7306d84aa629841d30563d0ddbcc2178e690cdd564451cbf009ebdbfdcbf3e95">+0/-84</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-804cde784a8519f9f453950e7f5faf7eebe67a771a7c29a501f53acdd5ffac61">+0/-44</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-74ae971093987c8e2e0fae413c88feb5b5e95218869956d88808827005df0029">+0/-32</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-9ef6c02134c8900f69fbd4326e8f1facbf6ac0cced8f09714c0776270840f24f">+0/-45</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-81ac6baf30e8d593daac5904fe8ee44954ea59b60cfebb932d6167039401ec70">+0/-26</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-b476498724d1ccfae69ca3db18d65fc2a18e629803fe277531948545ca36b944">+0/-46</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-e7a2e1f30c6f53270296c7e92cf5828c71a4a21dc4ea2a6c1b4d74da304e87ac">+0/-24</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-ca1b0821c2554f35858d70b8a41cd51bac6611ac04e7e16dfad75f38ed2ce930">+0/-19</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-69f23ca388bf44599fe256a2dedafc0e8af9fb346bb917efe6f2c95b84e971d7">+0/-18</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-0d3a5a254abeadabd0c30d04b56b43c8f4b43dcdb6c8f300d1f953fa602247d7">+0/-19</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>design.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-7120eaa6a5f458aa2e1649559057f77ecd7355c3eb9079a3cbe53fdfac97b93b">+32/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-cd52b3fd553ef7792c277ff50c4e9a9e1f3499b62def55e845f1311f5da7eb0d">+22/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-a212262a53d3ee2d68753329b05835cd20f2aa7671ffa686b4a6083f1d330256">+13/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-0b26ad240d4dcd68f67721a1352e54bcf78ee404d2ee167feca6675008466f61">+17/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>design.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-241d7df520e53d9bafd95027f32a00ffe31495c6bfaec479494a5904c4215d63">+30/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-9b1ddcbf90157cb6d07c63b0c435a434272e3279594c5510f2a3d297223fd672">+15/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-2d6fc29f0ddfb9b6213d83339d0d93ef5196a7ec7fc0e6b07c587c5908894c95">+40/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-9024bbd8abac8c96b2d4e0437250ee344cf5f12560785561285afe82e21d4457">+18/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-bc74372977e86a0e3f64c1af49c0610fe4d80798113604c17298cba508433003">+0/-144</a>&nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-57a85c7ff6659407d8665b61c6d9d7b09c71a213d1aca1e5fd993c027c14cfc0">+0/-81</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-1ba2529c7b515076581e20414759e23c0d25c327e312d456620c98c2c0700f6a">+0/-43</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-4bcd11bed34206ce4102519db0e148b7b197fab33423d03712aa23475df761bc">+0/-14</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-9f15500fd74ac3845aec9f5a6a2b2024a019b2f9438ce92f47fe18a6d945ab09">+0/-14</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-bd097cdff5fea1b8137a6f3fffb2dda7686b999f1e6e3889b4372481c1c37a66">+0/-17</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-0534d758c6b8e27938b14175fe5a6ff9bf0ee3a352da208c3f651cab9a460736">+16/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-5845d29d43f16fd852471b164a176e879de47eb15be4d4bcc32e27130a6095ec">+10/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-f7b9a49b7e16fb0ce430f87e5fe38160d9a072efe92259ca776fe6ee0449a7c9">+12/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-a913209a981d4c6b3e8339293fcb062e02065c6485c215304d34a66dfca38997">+0/-39</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-8ea36913f5d5236389f519283c919ffd1c3d1124de5684b954873958051c8dbb">+0/-70</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-138a6873eaaab55e8974878fd16911bae1de7b8c708e006b996744428c2ecd5b">+0/-33</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-c47d90ba805c8ea005726fc211e6179821ffa7e92b78054a338f6d5f6b81ab31">+0/-102</a>&nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-4a5a9adb68cec10a1c6b76d4788fe9b774c2f0034d1aa780814fb144fc458ad0">+0/-46</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-f34fa0a85f29520c314cde60d360176dff077bc0aae86fa99d96764c523ccac3">+0/-53</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-23212a3c01b653c3006efbbf6ca9782f767e74ce7aa85d7b71805dbb36d562ae">+0/-125</a>&nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-ad3bf3baec592ea2000de51abcd43628efd97c1524956d0580562e54b56515ad">+0/-129</a>&nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-239ceb7ed8d7185674ebc80a40aab82ea6955a159999df3ec7736870a416fac3">+0/-22</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-355450ac691dae6d2c3167233558588ea0e0ab969b5266044d4226b00e61ddab">+0/-15</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>design.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-5274bb4e518de9acae67adc9f953dff53e206dd3c1c74b1f7d31aa6a180a3657">+0/-126</a>&nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-5eec4c44ee16c05009a335e42f8d1f2f51f2141a67b8ecaf4e10bb89750aaf01">+0/-45</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-13e8b130ad04fa345823dca1c00eaab10c696e215a5f103e81bb9be68a3a9c0d">+0/-65</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-da976ef6be4f59ef694d7366995b6cc21249f4250cde4d376cd22217a0d8efae">+0/-60</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-0fdd4aa24e76cffe64401b5f3ed8bd0df236aa967851dec02939944647077c5f">+0/-30</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>schema-mapping.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-7d2d02aac4b8c93911ff89f3f2baad6c06cda6200b50a208912c138f83a470ba">+0/-90</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-12a4fb79e11a97004a73b86bea21ab75d6e9e3aea1bc42829de521088b795e7c">+0/-54</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-41f4a077d59d3369f485b1680f01ebee506f69f5297e197af9a8aed377df707d">+0/-31</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-9ffe47187efe19b5084ed1a469b3968036d7e8ceaef769941d036d654b875bae">+0/-17</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>spec.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-d16036359c50038867c508ffd03d819586d7940f78c71e9e964608944b5fd7b4">+0/-13</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-a95a4231cd1c5a744e1cb535f65f8b5567c1a20090792590c4a573962521c4a3">+0/-9</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-329567f3e1a4d68bfef837958cae30e81bdcd5dd00c85cf718be8d52f19d9ae5">+0/-155</a>&nbsp; </td> </tr> <tr> <td><strong>tasks.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-f80014269b48ec6c3c2ae45129db9a020f43ac2ddd8374c29ea2e83c7ac4bb9a">+0/-92</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>proposal.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-65a7bc84effa38ac6a43b4f47021e04aad4d7e0d8fc26d99260fe143cd5cbf91">+0/-14</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>Additional files not shown</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2157/files#diff-2f328e4cd8dbe3ad193e49d92bcf045f47a6b72b1e9487d366f6b8288589b4ca"></a></td> </tr> </table></details></td></tr></tbody></table> </details> ___
qodo-code-review[bot] commented 2025-12-16 17:03:30 +00:00 (Migrated from github.com)
Author
Owner

Imported GitHub PR comment.

Original author: @qodo-code-review[bot]
Original URL: https://github.com/carverauto/serviceradar/pull/2157#issuecomment-3661535194
Original created: 2025-12-16T17:03:30Z

You are nearing your monthly Qodo Merge usage quota. For more information, please visit here.

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🟢
🎫 #2142
🟢 Prevent SQL injection in MCP devices.getDevice by stopping direct interpolation of
user-supplied device_id into SRQL/SQL and using parameterized queries or proper escaping.
Prevent SQL injection in MCP server executeGetDevice path by stopping direct interpolation
of user-supplied DeviceID into the SRQL query and using parameterized queries or proper
escaping.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Swallowed DB error: The new batchLookupIdentifierType path drops database lookup errors and silently returns
empty matches, removing actionable context for diagnosing identity resolution failures.

Referred Code
results, err := e.db.BatchGetDeviceIDsByIdentifier(ctx, identifierType, values, partition)
if err != nil {
	return matches
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Logs user query: The added code logs full SRQL query strings (which may embed user-supplied filters) and
therefore may leak sensitive user input into logs depending on deployment and log
retention.

Referred Code
m.logger.Debug().Str("query", query).Msgf("Executing %s query", entity)

// Execute SRQL query via API
results, err := m.executeSRQLQueryWithParams(ctx, query, binds.params, commonParams.Limit)
if err != nil {
	return nil, fmt.Errorf("failed to execute %s query: %w", entity, err)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Raw filter injection: The query builders still append params.Filter directly into the SRQL WHERE clause without
binding or validation, which may preserve an injection vector depending on the intended
trust model for Filter.

Referred Code
if params.Filter != "" {
	conditions = append(conditions, params.Filter)
}

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
- Requires Further Human Verification
🏷️ - Compliance label
Imported GitHub PR comment. Original author: @qodo-code-review[bot] Original URL: https://github.com/carverauto/serviceradar/pull/2157#issuecomment-3661535194 Original created: 2025-12-16T17:03:30Z --- _You are nearing your monthly Qodo Merge usage quota. For more information, please visit [here](https://qodo-merge-docs.qodo.ai/installation/qodo_merge/#cloud-users)._ ## PR Compliance Guide 🔍 <!-- https://github.com/carverauto/serviceradar/commit/b1f9b471ccb3b25c065625a22f5204837a45c77f --> Below is a summary of compliance checks for this PR:<br> <table><tbody><tr><td colspan='2'><strong>Security Compliance</strong></td></tr> <tr><td>🟢</td><td><details><summary><strong>No security concerns identified</strong></summary> No security vulnerabilities detected by AI analysis. Human verification advised for critical code. </details></td></tr> <tr><td colspan='2'><strong>Ticket Compliance</strong></td></tr> <tr><td>🟢</td> <td> <details> <summary>🎫 <a href=https://github.com/carverauto/serviceradar/issues/2142>#2142</a></summary> <table width='100%'><tbody> <tr><td rowspan=2>🟢</td> <td>Prevent SQL injection in MCP <code>devices.getDevice</code> by stopping direct interpolation of <br>user-supplied <code>device_id</code> into SRQL/SQL and using parameterized queries or proper escaping.<br></td></tr> <tr><td>Prevent SQL injection in MCP server <code>executeGetDevice</code> path by stopping direct interpolation <br>of user-supplied <code>DeviceID</code> into the SRQL query and using parameterized queries or proper <br>escaping.<br></td></tr> </tbody></table> </details> </td></tr> <tr><td colspan='2'><strong>Codebase Duplication Compliance</strong></td></tr> <tr><td>⚪</td><td><details><summary><strong>Codebase context is not defined </strong></summary> Follow the <a href='https://qodo-merge-docs.qodo.ai/core-abilities/rag_context_enrichment/'>guide</a> to enable codebase context checks. </details></td></tr> <tr><td colspan='2'><strong>Custom Compliance</strong></td></tr> <tr><td rowspan=3>🟢</td><td> <details><summary><strong>Generic: Comprehensive Audit Trails</strong></summary><br> **Objective:** To create a detailed and reliable record of critical system actions for security analysis <br>and compliance.<br> **Status:** Passed<br> > Learn more about managing compliance <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#configuration-options'>generic rules</a> or creating your own <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#custom-compliance'>custom rules</a> </details></td></tr> <tr><td> <details><summary><strong>Generic: Meaningful Naming and Self-Documenting Code</strong></summary><br> **Objective:** Ensure all identifiers clearly express their purpose and intent, making code <br>self-documenting<br> **Status:** Passed<br> > Learn more about managing compliance <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#configuration-options'>generic rules</a> or creating your own <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#custom-compliance'>custom rules</a> </details></td></tr> <tr><td> <details><summary><strong>Generic: Secure Error Handling</strong></summary><br> **Objective:** To prevent the leakage of sensitive system information through error messages while <br>providing sufficient detail for internal debugging.<br> **Status:** Passed<br> > Learn more about managing compliance <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#configuration-options'>generic rules</a> or creating your own <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#custom-compliance'>custom rules</a> </details></td></tr> <tr><td rowspan=1>🔴</td> <td><details> <summary><strong>Generic: Robust Error Handling and Edge Case Management</strong></summary><br> **Objective:** Ensure comprehensive error handling that provides meaningful context and graceful <br>degradation<br> **Status:** <br><a href='https://github.com/carverauto/serviceradar/pull/2157/files#diff-496f24b3784656e1d6bb97cafe5c528bbecea5a0b74b4be578d3b83e858038c7R630-R633'><strong>Swallowed DB error</strong></a>: The new <code>batchLookupIdentifierType</code> path drops database lookup errors and silently returns <br>empty matches, removing actionable context for diagnosing identity resolution failures.<br> <details open><summary>Referred Code</summary> ```go results, err := e.db.BatchGetDeviceIDsByIdentifier(ctx, identifierType, values, partition) if err != nil { return matches } ``` </details> > Learn more about managing compliance <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#configuration-options'>generic rules</a> or creating your own <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#custom-compliance'>custom rules</a> </details></td></tr> <tr><td rowspan=2>⚪</td> <td><details> <summary><strong>Generic: Secure Logging Practices</strong></summary><br> **Objective:** To ensure logs are useful for debugging and auditing without exposing sensitive <br>information like PII, PHI, or cardholder data.<br> **Status:** <br><a href='https://github.com/carverauto/serviceradar/pull/2157/files#diff-ee3c16d7d8882a3a65d28bfedf7f0a5e59698b00ae482bc5565b3314503d5db2R218-R223'><strong>Logs user query</strong></a>: The added code logs full SRQL query strings (which may embed user-supplied filters) and <br>therefore may leak sensitive user input into logs depending on deployment and log <br>retention.<br> <details open><summary>Referred Code</summary> ```go m.logger.Debug().Str("query", query).Msgf("Executing %s query", entity) // Execute SRQL query via API results, err := m.executeSRQLQueryWithParams(ctx, query, binds.params, commonParams.Limit) if err != nil { return nil, fmt.Errorf("failed to execute %s query: %w", entity, err) ``` </details> > Learn more about managing compliance <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#configuration-options'>generic rules</a> or creating your own <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#custom-compliance'>custom rules</a> </details></td></tr> <tr><td><details> <summary><strong>Generic: Security-First Input Validation and Data Handling</strong></summary><br> **Objective:** Ensure all data inputs are validated, sanitized, and handled securely to prevent <br>vulnerabilities<br> **Status:** <br><a href='https://github.com/carverauto/serviceradar/pull/2157/files#diff-6a33491056954507b65b8252854786d3d9c65534c7c88700fcc2592f808b192bR85-R87'><strong>Raw filter injection</strong></a>: The query builders still append <code>params.Filter</code> directly into the SRQL <code>WHERE</code> clause without <br>binding or validation, which may preserve an injection vector depending on the intended <br>trust model for <code>Filter</code>.<br> <details open><summary>Referred Code</summary> ```go if params.Filter != "" { conditions = append(conditions, params.Filter) } ``` </details> > Learn more about managing compliance <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#configuration-options'>generic rules</a> or creating your own <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#custom-compliance'>custom rules</a> </details></td></tr> <tr><td align="center" colspan="2"> - [ ] Update <!-- /compliance --update_compliance=true --> </td></tr></tbody></table> <details><summary>Compliance status legend</summary> 🟢 - Fully Compliant<br> 🟡 - Partial Compliant<br> 🔴 - Not Compliant<br> ⚪ - Requires Further Human Verification<br> 🏷️ - Compliance label<br> </details>
qodo-code-review[bot] commented 2025-12-16 17:05:16 +00:00 (Migrated from github.com)
Author
Owner

Imported GitHub PR comment.

Original author: @qodo-code-review[bot]
Original URL: https://github.com/carverauto/serviceradar/pull/2157#issuecomment-3661542321
Original created: 2025-12-16T17:05:16Z

You are nearing your monthly Qodo Merge usage quota. For more information, please visit here.

PR Code Suggestions

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix SQL injection in status filter

Fix an SQL injection vulnerability in buildDevicesQuery by parameterizing the
is_available status filter instead of using string formatting.

pkg/mcp/query_utils.go [162-208]

 func buildDevicesQuery(params ListDevicesParams) (string, []any) {
 	query := showDevicesQuery
 
 	binds := &srqlBindBuilder{}
 	var conditions []string
 
 	if params.Type != "" {
 		conditions = append(conditions, fmt.Sprintf("device_type = %s", binds.Bind(params.Type)))
 	}
 
 	if params.Status != "" {
 		var condition string
 		statusLower := strings.ToLower(params.Status)
 		if statusLower == "available" || statusLower == "unavailable" {
 			// is_available is a boolean field, not a string
 			if statusLower == "available" {
-				condition = "is_available = true"
+				condition = fmt.Sprintf("is_available = %s", binds.Bind(true))
 			} else {
-				condition = "is_available = false"
+				condition = fmt.Sprintf("is_available = %s", binds.Bind(false))
 			}
 		} else {
 			// is_available is a boolean field, not a string
 			if statusLower == "true" || statusLower == "false" {
-				condition = fmt.Sprintf("is_available = %s", params.Status)
+				isAvailable, _ := strconv.ParseBool(statusLower)
+				condition = fmt.Sprintf("is_available = %s", binds.Bind(isAvailable))
 			} else {
 				// Fallback: assume it's a custom status field
 				condition = fmt.Sprintf("status = %s", binds.Bind(params.Status))
 			}
 		}
 
 		if condition != "" {
 			conditions = append(conditions, condition)
 		}
 	}
 
 	if len(conditions) > 0 {
 		query += " WHERE " + strings.Join(conditions, " AND ")
 	}
 
 	if params.Limit <= 0 {
 		params.Limit = defaultLimit
 	}
 
 	query += fmt.Sprintf(" LIMIT %d", params.Limit)
 
 	return query, binds.params
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a significant SQL injection vulnerability where a boolean-like string is interpolated directly into the query, which the PR's main goal was to prevent.

High
Rewrite query placeholders consistently

Apply the rewrite_placeholders function to the DEVICE_GRAPH_QUERY string for
consistency with other query handling in the codebase.

rust/srql/src/query/device_graph.rs [30-37]

+let sql = rewrite_placeholders(DEVICE_GRAPH_QUERY.trim());
 Ok((
-    DEVICE_GRAPH_QUERY.trim().to_string(),
+    sql,
     vec![
         BindParam::Text(params.device_id),
         BindParam::Bool(params.collector_owned_only),
         BindParam::Bool(params.include_topology),
     ],
 ))

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out an inconsistency by not using rewrite_placeholders, which is used elsewhere for similar queries, improving consistency and preventing potential future issues.

Medium
Security
Safely parse comma-separated environment variable

To prevent potential command injection, parse the comma-separated
CNPG_CERT_EXTRA_IPS environment variable into a shell array instead of using
echo and tr.

docker/compose/generate-certs.sh [165-167]

-for ip in $(echo "$CNPG_CERT_EXTRA_IPS" | tr ',' ' '); do
-    CNPG_SAN="${CNPG_SAN},IP:${ip}"
+IFS=',' read -r -a extra_ips <<< "$CNPG_CERT_EXTRA_IPS"
+for ip in "${extra_ips[@]}"; do
+    # Trim whitespace, in case of "1.1.1.1, 2.2.2.2"
+    ip_trimmed=$(echo "$ip" | xargs)
+    if [ -n "$ip_trimmed" ]; then
+        CNPG_SAN="${CNPG_SAN},IP:${ip_trimmed}"
+    fi
 done
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a potential command injection vulnerability from unsafe parsing of an environment variable and provides a robust, safer alternative.

Medium
Use query parameters for LIMIT

Parameterize the LIMIT clause in buildRecentLogsQuery to prevent potential
performance issues and maintain consistency with other query parameterization
changes.

pkg/mcp/query_utils.go [115-130]

 func buildRecentLogsQuery(params RecentLogsParams) (string, []any) {
 	query := showLogsQuery
 
 	binds := &srqlBindBuilder{}
 	if params.PollerID != "" {
 		query += fmt.Sprintf(" WHERE poller_id = %s", binds.Bind(params.PollerID))
 	}
 
 	if params.Limit <= 0 {
 		params.Limit = defaultLimit
 	}
 
-	query += fmt.Sprintf(" ORDER BY _tp_time DESC LIMIT %d", params.Limit)
+	query += fmt.Sprintf(" ORDER BY _tp_time DESC LIMIT %s", binds.Bind(params.Limit))
 
 	return query, binds.params
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that the LIMIT clause is not parameterized, which is inconsistent with the PR's goal of preventing SQL injection and could lead to performance issues.

Medium
Parameterize LIMIT clause

Parameterize the LIMIT clause in buildLogQuery to prevent potential SQL
injection and performance issues by binding the limit value instead of using
string formatting.

pkg/mcp/query_utils.go [80-113]

 func buildLogQuery(params LogQueryParams) (string, []any) {
     query := showLogsQuery
     conditions := []string{}
     binds := &srqlBindBuilder{}
     // ...
     if len(conditions) > 0 {
         query += " WHERE " + strings.Join(conditions, " AND ")
     }
-    query += fmt.Sprintf(" LIMIT %d", params.Limit)
+    // Parameterize the limit
+    limitPlaceholder := binds.Bind(params.Limit)
+    query += fmt.Sprintf(" LIMIT %s", limitPlaceholder)
     return query, binds.params
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that the LIMIT clause is not parameterized, which is inconsistent with the PR's goal and could lead to performance issues if a large value is passed.

Medium
Parameterize bucket duration

In build_sql, use a SQL placeholder for bucket_secs and bind it as a parameter
instead of using string formatting to prevent potential SQL injection.

rust/srql/src/query/downsample.rs [88-90]

 let mut sql = format!(
-    "SELECT time_bucket(make_interval(secs => {bucket_secs}), {ts_col}) AS timestamp, {series_expr} AS series, {agg_expr} AS value\nFROM {table}\nWHERE ",
+    "SELECT time_bucket(make_interval(secs => ?), {ts_col}) AS timestamp, {series_expr} AS series, {agg_expr} AS value\nFROM {table}\nWHERE ",
 );
+// later, in build_bind_values before pushing start/end:
+binds.insert(0, SqlBindValue::BigInt(downsample.bucket_seconds));

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that bucket_secs is interpolated into the SQL string and proposes using a bind parameter, which is a security best practice, even though the value is already validated.

Medium
General
Limit dollar quote attempts

Add a maximum attempt count to the dollar_quote function to prevent a potential
infinite loop and return an error if it is exceeded.

rust/srql/src/query/graph_cypher.rs [59-76]

-fn dollar_quote(input: &str) -> String {
+fn dollar_quote(input: &str) -> Result<String> {
+    const MAX_ATTEMPTS: usize = 10;
     let mut attempt = 0usize;
 
-    loop {
+    while attempt < MAX_ATTEMPTS {
         let tag = if attempt == 0 {
             "srql".to_string()
         } else {
             format!("srql_{attempt}")
         };
         let delimiter = format!("${tag}$");
         if !input.contains(&delimiter) {
-            return format!("{delimiter}{input}{delimiter}");
+            return Ok(format!("{delimiter}{input}{delimiter}"));
         }
         attempt += 1;
     }
+    Err(ServiceError::Internal("unable to dollar-quote input safely".into()))
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a theoretical risk of an infinite loop and proposes a robust solution by adding a maximum attempt limit, improving the function's resilience.

Low
Improve TLS error context

Improve the error context message in build_client_config to reference the client
certificate and key paths instead of the root certificate path for better
debugging.

rust/srql/src/db.rs [138-140]

 builder
     .with_client_auth_cert(certs, key)
-    .with_context(|| format!("failed to build client TLS config for {root_cert}"))
+    .with_context(|| format!("failed to build client TLS config with client_cert={cert}, client_key={key}"))

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 4

__

Why: The suggestion improves an error message to be more specific, which aids in debugging, although it is a minor improvement.

Low
  • Update
Imported GitHub PR comment. Original author: @qodo-code-review[bot] Original URL: https://github.com/carverauto/serviceradar/pull/2157#issuecomment-3661542321 Original created: 2025-12-16T17:05:16Z --- _You are nearing your monthly Qodo Merge usage quota. For more information, please visit [here](https://qodo-merge-docs.qodo.ai/installation/qodo_merge/#cloud-users)._ ## PR Code Suggestions ✨ <!-- b1f9b47 --> Explore these optional code suggestions: <table><thead><tr><td><strong>Category</strong></td><td align=left><strong>Suggestion&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </strong></td><td align=center><strong>Impact</strong></td></tr><tbody><tr><td rowspan=2>Possible issue</td> <td> <details><summary>Fix SQL injection in status filter</summary> ___ **Fix an SQL injection vulnerability in <code>buildDevicesQuery</code> by parameterizing the <br><code>is_available</code> status filter instead of using string formatting.** [pkg/mcp/query_utils.go [162-208]](https://github.com/carverauto/serviceradar/pull/2157/files#diff-6a33491056954507b65b8252854786d3d9c65534c7c88700fcc2592f808b192bR162-R208) ```diff func buildDevicesQuery(params ListDevicesParams) (string, []any) { query := showDevicesQuery binds := &srqlBindBuilder{} var conditions []string if params.Type != "" { conditions = append(conditions, fmt.Sprintf("device_type = %s", binds.Bind(params.Type))) } if params.Status != "" { var condition string statusLower := strings.ToLower(params.Status) if statusLower == "available" || statusLower == "unavailable" { // is_available is a boolean field, not a string if statusLower == "available" { - condition = "is_available = true" + condition = fmt.Sprintf("is_available = %s", binds.Bind(true)) } else { - condition = "is_available = false" + condition = fmt.Sprintf("is_available = %s", binds.Bind(false)) } } else { // is_available is a boolean field, not a string if statusLower == "true" || statusLower == "false" { - condition = fmt.Sprintf("is_available = %s", params.Status) + isAvailable, _ := strconv.ParseBool(statusLower) + condition = fmt.Sprintf("is_available = %s", binds.Bind(isAvailable)) } else { // Fallback: assume it's a custom status field condition = fmt.Sprintf("status = %s", binds.Bind(params.Status)) } } if condition != "" { conditions = append(conditions, condition) } } if len(conditions) > 0 { query += " WHERE " + strings.Join(conditions, " AND ") } if params.Limit <= 0 { params.Limit = defaultLimit } query += fmt.Sprintf(" LIMIT %d", params.Limit) return query, binds.params } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 9</summary> __ Why: The suggestion correctly identifies a significant SQL injection vulnerability where a boolean-like string is interpolated directly into the query, which the PR's main goal was to prevent. </details></details></td><td align=center>High </td></tr><tr><td> <details><summary>Rewrite query placeholders consistently</summary> ___ **Apply the <code>rewrite_placeholders</code> function to the <code>DEVICE_GRAPH_QUERY</code> string for <br>consistency with other query handling in the codebase.** [rust/srql/src/query/device_graph.rs [30-37]](https://github.com/carverauto/serviceradar/pull/2157/files#diff-a6e5019c94fdef4f11f3c834e5e6ecac78efd5ce40f34b93bb64fe8076db9011R30-R37) ```diff +let sql = rewrite_placeholders(DEVICE_GRAPH_QUERY.trim()); Ok(( - DEVICE_GRAPH_QUERY.trim().to_string(), + sql, vec![ BindParam::Text(params.device_id), BindParam::Bool(params.collector_owned_only), BindParam::Bool(params.include_topology), ], )) ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly points out an inconsistency by not using `rewrite_placeholders`, which is used elsewhere for similar queries, improving consistency and preventing potential future issues. </details></details></td><td align=center>Medium </td></tr><tr><td rowspan=4>Security</td> <td> <details><summary>Safely parse comma-separated environment variable</summary> ___ **To prevent potential command injection, parse the comma-separated <br><code>CNPG_CERT_EXTRA_IPS</code> environment variable into a shell array instead of using <br><code>echo</code> and <code>tr</code>.** [docker/compose/generate-certs.sh [165-167]](https://github.com/carverauto/serviceradar/pull/2157/files#diff-8298241543b4744a6ac7780c760ac5b5a0a87ba62de19c8612ebe1aba0996ebdR165-R167) ```diff -for ip in $(echo "$CNPG_CERT_EXTRA_IPS" | tr ',' ' '); do - CNPG_SAN="${CNPG_SAN},IP:${ip}" +IFS=',' read -r -a extra_ips <<< "$CNPG_CERT_EXTRA_IPS" +for ip in "${extra_ips[@]}"; do + # Trim whitespace, in case of "1.1.1.1, 2.2.2.2" + ip_trimmed=$(echo "$ip" | xargs) + if [ -n "$ip_trimmed" ]; then + CNPG_SAN="${CNPG_SAN},IP:${ip_trimmed}" + fi done ``` - [ ] **Apply / Chat** <!-- /improve --apply_suggestion=2 --> <details><summary>Suggestion importance[1-10]: 8</summary> __ Why: The suggestion correctly identifies a potential command injection vulnerability from unsafe parsing of an environment variable and provides a robust, safer alternative. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Use query parameters for LIMIT</summary> ___ **Parameterize the <code>LIMIT</code> clause in <code>buildRecentLogsQuery</code> to prevent potential <br>performance issues and maintain consistency with other query parameterization <br>changes.** [pkg/mcp/query_utils.go [115-130]](https://github.com/carverauto/serviceradar/pull/2157/files#diff-6a33491056954507b65b8252854786d3d9c65534c7c88700fcc2592f808b192bR115-R130) ```diff func buildRecentLogsQuery(params RecentLogsParams) (string, []any) { query := showLogsQuery binds := &srqlBindBuilder{} if params.PollerID != "" { query += fmt.Sprintf(" WHERE poller_id = %s", binds.Bind(params.PollerID)) } if params.Limit <= 0 { params.Limit = defaultLimit } - query += fmt.Sprintf(" ORDER BY _tp_time DESC LIMIT %d", params.Limit) + query += fmt.Sprintf(" ORDER BY _tp_time DESC LIMIT %s", binds.Bind(params.Limit)) return query, binds.params } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly identifies that the `LIMIT` clause is not parameterized, which is inconsistent with the PR's goal of preventing SQL injection and could lead to performance issues. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Parameterize LIMIT clause</summary> ___ **Parameterize the <code>LIMIT</code> clause in <code>buildLogQuery</code> to prevent potential SQL <br>injection and performance issues by binding the limit value instead of using <br>string formatting.** [pkg/mcp/query_utils.go [80-113]](https://github.com/carverauto/serviceradar/pull/2157/files#diff-6a33491056954507b65b8252854786d3d9c65534c7c88700fcc2592f808b192bR80-R113) ```diff func buildLogQuery(params LogQueryParams) (string, []any) { query := showLogsQuery conditions := []string{} binds := &srqlBindBuilder{} // ... if len(conditions) > 0 { query += " WHERE " + strings.Join(conditions, " AND ") } - query += fmt.Sprintf(" LIMIT %d", params.Limit) + // Parameterize the limit + limitPlaceholder := binds.Bind(params.Limit) + query += fmt.Sprintf(" LIMIT %s", limitPlaceholder) return query, binds.params } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly points out that the `LIMIT` clause is not parameterized, which is inconsistent with the PR's goal and could lead to performance issues if a large value is passed. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Parameterize bucket duration</summary> ___ **In <code>build_sql</code>, use a SQL placeholder for <code>bucket_secs</code> and bind it as a parameter <br>instead of using string formatting to prevent potential SQL injection.** [rust/srql/src/query/downsample.rs [88-90]](https://github.com/carverauto/serviceradar/pull/2157/files#diff-94f68b4684578afa112ab05ff903667b6cd902ad276e17c12af350078b300a6aR88-R90) ```diff let mut sql = format!( - "SELECT time_bucket(make_interval(secs => {bucket_secs}), {ts_col}) AS timestamp, {series_expr} AS series, {agg_expr} AS value\nFROM {table}\nWHERE ", + "SELECT time_bucket(make_interval(secs => ?), {ts_col}) AS timestamp, {series_expr} AS series, {agg_expr} AS value\nFROM {table}\nWHERE ", ); +// later, in build_bind_values before pushing start/end: +binds.insert(0, SqlBindValue::BigInt(downsample.bucket_seconds)); ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly identifies that `bucket_secs` is interpolated into the SQL string and proposes using a bind parameter, which is a security best practice, even though the value is already validated. </details></details></td><td align=center>Medium </td></tr><tr><td rowspan=2>General</td> <td> <details><summary>Limit dollar quote attempts</summary> ___ **Add a maximum attempt count to the <code>dollar_quote</code> function to prevent a potential <br>infinite loop and return an error if it is exceeded.** [rust/srql/src/query/graph_cypher.rs [59-76]](https://github.com/carverauto/serviceradar/pull/2157/files#diff-378b0ec80e1b1221c347160a0dac36c82d082fa06766d47d18cf069220166309R59-R76) ```diff -fn dollar_quote(input: &str) -> String { +fn dollar_quote(input: &str) -> Result<String> { + const MAX_ATTEMPTS: usize = 10; let mut attempt = 0usize; - loop { + while attempt < MAX_ATTEMPTS { let tag = if attempt == 0 { "srql".to_string() } else { format!("srql_{attempt}") }; let delimiter = format!("${tag}$"); if !input.contains(&delimiter) { - return format!("{delimiter}{input}{delimiter}"); + return Ok(format!("{delimiter}{input}{delimiter}")); } attempt += 1; } + Err(ServiceError::Internal("unable to dollar-quote input safely".into())) } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 6</summary> __ Why: The suggestion correctly identifies a theoretical risk of an infinite loop and proposes a robust solution by adding a maximum attempt limit, improving the function's resilience. </details></details></td><td align=center>Low </td></tr><tr><td> <details><summary>Improve TLS error context</summary> ___ **Improve the error context message in <code>build_client_config</code> to reference the client <br>certificate and key paths instead of the root certificate path for better <br>debugging.** [rust/srql/src/db.rs [138-140]](https://github.com/carverauto/serviceradar/pull/2157/files#diff-8d5a0c48024aa12a3e06de065ca71e940d2b5007fbc34ef87471b90d7937891cR138-R140) ```diff builder .with_client_auth_cert(certs, key) - .with_context(|| format!("failed to build client TLS config for {root_cert}")) + .with_context(|| format!("failed to build client TLS config with client_cert={cert}, client_key={key}")) ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 4</summary> __ Why: The suggestion improves an error message to be more specific, which aids in debugging, although it is a minor improvement. </details></details></td><td align=center>Low </td></tr> <tr><td align="center" colspan="2"> - [ ] Update <!-- /improve_multi --more_suggestions=true --> </td><td></td></tr></tbody></table>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
carverauto/serviceradar!2581
No description provided.