Cleanup/poller removal #2633

Merged
mfreeman451 merged 9 commits from refs/pull/2633/head into testing 2026-01-06 21:52:25 +00:00
mfreeman451 commented 2026-01-06 17:32:45 +00:00 (Migrated from github.com)
Owner

Imported from GitHub pull request.

Original GitHub pull request: #2226
Original author: @mfreeman451
Original URL: https://github.com/carverauto/serviceradar/pull/2226
Original created: 2026-01-06T17:32:45Z
Original updated: 2026-01-06T21:52:57Z
Original head: carverauto/serviceradar:cleanup/poller_removal
Original base: testing
Original merged: 2026-01-06T21:52:25Z 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

Enhancement, Bug fix, Tests


Description

  • Major architectural refactor: Transition from poller-based pull architecture to gateway-based push architecture with multi-tenant support

  • Protobuf schema updates: Renamed PollerId to GatewayId, replaced PollerService with AgentGatewayService, added new agent-gateway communication types (AgentHelloRequest, AgentHelloResponse, AgentConfigRequest, AgentConfigResponse)

  • Sync service refactoring: Removed KV client and gRPC pull-based dependencies; implemented gateway enrollment, config polling, and heartbeat loops for push-first communication with chunked streaming support

  • NATS multi-tenancy: Added NATS account management service with JWT/NKeys cryptographic operations, account signer implementation, and credentials file support

  • CLI enhancements: New NATS bootstrap and admin CLI functionality for operator/account credential generation and management

  • Agent push loop: New PushLoop implementation for managing periodic agent status pushes to gateway with config polling and service status collection

  • Test updates: Removed deprecated poller/KV-related tests, updated integration tests (Armis, NetBox) to remove KV dependencies, added new chunking logic tests

  • Bug fix: Added Sync component type to SPIRE configuration validation

  • Cleanup: Removed sync service command, related Docker/Kubernetes configurations, and deprecated pull-based gRPC methods


Diagram Walkthrough

flowchart LR
  A["Poller Architecture<br/>Pull-based"] -->|Refactor| B["Gateway Architecture<br/>Push-based"]
  B --> C["Agent Push Loop<br/>Status & Config"]
  B --> D["NATS Multi-tenancy<br/>JWT/NKeys"]
  B --> E["Chunked Streaming<br/>Results & Status"]
  C --> F["Gateway Client<br/>Enrollment & Polling"]
  D --> G["Account Manager<br/>Tenant Isolation"]
  E --> H["Configurable<br/>Chunk Sizes"]

File Walkthrough

Relevant files
Enhancement
7 files
monitoring.pb.go
Refactor protobuf definitions from poller to gateway architecture

proto/monitoring.pb.go

  • Renamed PollerId field to GatewayId across multiple message types
    (StatusRequest, ResultsRequest, StatusResponse, ResultsResponse)
  • Removed deprecated PollerStatusRequest, PollerStatusResponse, and
    ServiceStatus message types
  • Replaced PollerStatusChunk with new GatewayStatusRequest,
    GatewayStatusResponse, and GatewayStatusChunk types
  • Added new agent-gateway communication types: AgentHelloRequest,
    AgentHelloResponse, AgentConfigRequest, AgentConfigResponse, and
    AgentCheckConfig
  • Updated service definitions from PollerService to AgentGatewayService
    with new RPC methods
  • Added multi-tenant support fields (TenantId, TenantSlug) to
    gateway-related messages
+1039/-404
nats_bootstrap.go
Add NATS bootstrap and admin CLI functionality                     

pkg/cli/nats_bootstrap.go

  • New file implementing NATS bootstrap functionality for ServiceRadar
    CLI
  • Provides handlers for nats-bootstrap and admin nats subcommands with
    flag parsing
  • Implements bootstrap creation via Core API, local bootstrap, and
    verification modes
  • Generates NATS operator, system account, and platform account
    credentials and configuration files
  • Includes admin commands for generating bootstrap tokens, checking NATS
    status, and listing tenant accounts
  • Supports both text and JSON output formats for all operations
+961/-0 
service.go
Gateway push architecture with multi-tenant support           

pkg/sync/service.go

  • Removed KV client and gRPC client dependencies; replaced with
    gateway-based push architecture
  • Added multi-tenant support with per-tenant source configurations,
    integrations, and results tracking
  • Implemented gateway enrollment, config polling, and heartbeat loops
    for push-first communication
  • Refactored discovery and results handling to support chunked streaming
    with configurable chunk sizes
  • Deprecated pull-based GetResults and StreamResults gRPC methods in
    favor of gateway push
+1047/-309
account_manager.go
NATS account signer implementation                                             

pkg/nats/accounts/account_manager.go

  • New module providing stateless NATS account signing operations
  • Implements AccountSigner for creating tenant accounts and signing JWTs
  • Applies default subject mappings for tenant isolation (events, syslog,
    SNMP, netflow, etc.)
  • Supports custom account limits and user key revocations
+238/-0 
push_loop.go
New push loop implementation for agent status management 

pkg/agent/push_loop.go

  • New file implementing PushLoop struct that manages periodic pushing of
    agent status to gateway
  • Handles agent enrollment, config polling, and status collection from
    services and checkers
  • Includes thread-safe accessors for shared state (interval, config
    version, enrollment status)
  • Implements config fetching, applying, and conversion of proto checks
    to checker configs
+979/-0 
nats_account_service.go
New NATS account service for JWT-based multi-tenancy         

pkg/datasvc/nats_account_service.go

  • New file implementing NATSAccountServer for NATS JWT/NKeys
    cryptographic operations
  • Provides gRPC service methods for operator bootstrap, tenant account
    creation, and user credential generation
  • Handles mTLS authorization, resolver connection management, and JWT
    signing
  • Includes helper functions for proto conversion and NATS configuration
    file writing
+888/-0 
events.go
Add NATS credentials file support to event publisher         

pkg/core/events.go

  • Added support for NATS credentials file configuration in event
    publisher initialization
  • Appends nats.UserCredentials option when config.NATS.CredsFile is set
+4/-0     
Bug fix
1 files
spire.go
Add Sync component type to SPIRE configuration validation

pkg/edgeonboarding/spire.go

  • Added models.EdgeOnboardingComponentTypeSync to the unsupported
    component type check alongside EdgeOnboardingComponentTypeNone
+1/-1     
Dependencies
1 files
nats_account.pb.go
NATS account management protobuf definitions                         

proto/nats_account.pb.go

  • Generated protobuf code for NATS account management service
  • Defines message types for account creation, user credential
    generation, and JWT signing
  • Includes enums for user credential types (collector, service, admin)
  • Implements service methods for operator bootstrap and account JWT
    management
+1266/-0
Tests
3 files
netbox_test.go
Remove KV-related test code                                                           

pkg/sync/integrations/netbox/netbox_test.go

  • Removed KV data and gRPC imports from test file
  • Updated processDevices call to expect only device events return value
  • Simplified test assertions to validate only device IP extraction
+1/-116 
service_test.go
Refactor sync service tests to remove poller-related code

pkg/sync/service_test.go

  • Removed multiple test functions related to deprecated pull-based
    polling (TestSimpleSyncService_GetResults,
    TestSimpleSyncService_writeToKV*)
  • Simplified NewSimpleSyncService constructor calls by removing mock KV
    and gRPC client parameters
  • Added new tests for chunking logic (TestBuildResultsChunks,
    TestBuildGatewayStatusChunks, TestBuildResultsChunksSizeBudget)
  • Updated TestSimpleSyncService_StreamResults to verify unimplemented
    status and added TestGroupSourcesByTenantScope
+196/-467
armis_test.go
Remove poller/KV writer dependencies from Armis integration tests

pkg/sync/integrations/armis/armis_test.go

  • Removed KVWriter mock and related sweep config expectations from test
    setup
  • Simplified Fetch method signature to return only events instead of KV
    data and events
  • Removed tests for KV write operations and sweep config handling
  • Updated processDevices test to verify only device events without KV
    payloads or device targets
+18/-508
Configuration changes
1 files
prod.exs
Add Elixir production configuration                                           

elixir/serviceradar_agent_gateway/config/prod.exs

  • New production configuration file for Elixir service
  • Sets logger level to info for production environment
+4/-0     
Additional files
101 files
.bazelignore +4/-0     
.bazelrc +5/-0     
.env-sample +33/-0   
.env.example +38/-0   
main.yml +18/-0   
AGENTS.md +175/-11
MODULE.bazel +5/-0     
Makefile +47/-2   
README-Docker.md +16/-1   
BUILD.bazel +11/-0   
BUILD.bazel +12/-0   
mix_release.bzl +124/-49
BUILD.bazel +1/-0     
config.json +5/-6     
main.go +174/-74
build.rs +0/-1     
monitoring.proto +3/-26   
server.rs +2/-0     
monitoring.proto +2/-26   
server.rs +6/-6     
main.go +14/-0   
config.rs +26/-0   
grpc_server.rs +2/-0     
message_processor.rs +1/-0     
nats.rs +4/-0     
zen-consumer-with-otel.json +1/-0     
zen-consumer.json +1/-0     
BUILD.bazel +1/-0     
main.go +68/-0   
README.md +9/-12   
flowgger.toml +1/-0     
nats_output.rs +14/-0   
otel.toml +1/-0     
config.rs +13/-0   
nats_output.rs +7/-0     
setup.rs +1/-0     
BUILD.bazel +0/-25   
config.json +0/-77   
main.go +0/-123 
config.rs +21/-0   
main.rs +23/-1   
docker-compose.elx.yml +108/-0 
docker-compose.spiffe.yml +8/-157 
docker-compose.yml +298/-280
Dockerfile.agent-gateway +94/-0   
Dockerfile.core-elx +108/-0 
Dockerfile.sync +0/-95   
Dockerfile.web-ng +6/-0     
agent-minimal.docker.json +6/-6     
agent.docker.json +5/-20   
agent.mtls.json +7/-10   
.gitkeep +1/-0     
datasvc.docker.json +3/-2     
datasvc.mtls.json +14/-1   
db-event-writer.mtls.json +1/-0     
entrypoint-certs.sh +12/-8   
entrypoint-sync.sh +0/-96   
flowgger.docker.toml +2/-1     
generate-certs.sh +220/-12
nats.docker.conf +16/-160
netflow-consumer.mtls.json +1/-0     
otel.docker.toml +2/-0     
pg_hba.conf +9/-0     
pg_ident.conf +17/-0   
bootstrap-compose-spire.sh +0/-1     
ssl_dist.core.conf +17/-0   
ssl_dist.gateway.conf +17/-0   
ssl_dist.web.conf +17/-0   
sync.docker.json +0/-71   
sync.mtls.json +0/-75   
trapd.docker.json +2/-1     
zen.docker.json +2/-1     
BUILD.bazel +80/-42 
push_targets.bzl +2/-1     
SBOM.md +0/-1     
agents.md +8/-9     
architecture.md +100/-26
armis.md +7/-21   
ash-api.md +305/-0 
ash-authentication.md +244/-0 
ash-authorization.md +283/-0 
ash-domains.md +223/-0 
ash-migration-guide.md +339/-0 
auth-configuration.md +1/-1     
cluster.md +2/-2     
discovery.md +19/-20 
docker-setup.md +57/-14 
edge-agents.md +253/-0 
edge-onboarding.md +316/-273
identity_drift_monitoring.md +1/-1     
installation.md +13/-14 
intro.md +5/-5     
kv-configuration.md +3/-3     
netbox.md +4/-23   
netflow.md +1/-1     
onboarding-review-2025.md +0/-1     
rperf-monitoring.md +1/-1     
compose-mtls-sysmonosx.md +1/-1     
docker-compose-login-500.md +3/-3     
security-architecture.md +238/-0 
Additional files not shown

Imported from GitHub pull request. Original GitHub pull request: #2226 Original author: @mfreeman451 Original URL: https://github.com/carverauto/serviceradar/pull/2226 Original created: 2026-01-06T17:32:45Z Original updated: 2026-01-06T21:52:57Z Original head: carverauto/serviceradar:cleanup/poller_removal Original base: testing Original merged: 2026-01-06T21:52:25Z 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** Enhancement, Bug fix, Tests ___ ### **Description** - **Major architectural refactor**: Transition from poller-based pull architecture to gateway-based push architecture with multi-tenant support - **Protobuf schema updates**: Renamed `PollerId` to `GatewayId`, replaced `PollerService` with `AgentGatewayService`, added new agent-gateway communication types (`AgentHelloRequest`, `AgentHelloResponse`, `AgentConfigRequest`, `AgentConfigResponse`) - **Sync service refactoring**: Removed KV client and gRPC pull-based dependencies; implemented gateway enrollment, config polling, and heartbeat loops for push-first communication with chunked streaming support - **NATS multi-tenancy**: Added NATS account management service with JWT/NKeys cryptographic operations, account signer implementation, and credentials file support - **CLI enhancements**: New NATS bootstrap and admin CLI functionality for operator/account credential generation and management - **Agent push loop**: New `PushLoop` implementation for managing periodic agent status pushes to gateway with config polling and service status collection - **Test updates**: Removed deprecated poller/KV-related tests, updated integration tests (Armis, NetBox) to remove KV dependencies, added new chunking logic tests - **Bug fix**: Added `Sync` component type to SPIRE configuration validation - **Cleanup**: Removed sync service command, related Docker/Kubernetes configurations, and deprecated pull-based gRPC methods ___ ### Diagram Walkthrough ```mermaid flowchart LR A["Poller Architecture<br/>Pull-based"] -->|Refactor| B["Gateway Architecture<br/>Push-based"] B --> C["Agent Push Loop<br/>Status & Config"] B --> D["NATS Multi-tenancy<br/>JWT/NKeys"] B --> E["Chunked Streaming<br/>Results & Status"] C --> F["Gateway Client<br/>Enrollment & Polling"] D --> G["Account Manager<br/>Tenant Isolation"] E --> H["Configurable<br/>Chunk Sizes"] ``` <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>7 files</summary><table> <tr> <td> <details> <summary><strong>monitoring.pb.go</strong><dd><code>Refactor protobuf definitions from poller to gateway architecture</code></dd></summary> <hr> proto/monitoring.pb.go <ul><li>Renamed <code>PollerId</code> field to <code>GatewayId</code> across multiple message types <br>(<code>StatusRequest</code>, <code>ResultsRequest</code>, <code>StatusResponse</code>, <code>ResultsResponse</code>)<br> <li> Removed deprecated <code>PollerStatusRequest</code>, <code>PollerStatusResponse</code>, and <br><code>ServiceStatus</code> message types<br> <li> Replaced <code>PollerStatusChunk</code> with new <code>GatewayStatusRequest</code>, <br><code>GatewayStatusResponse</code>, and <code>GatewayStatusChunk</code> types<br> <li> Added new agent-gateway communication types: <code>AgentHelloRequest</code>, <br><code>AgentHelloResponse</code>, <code>AgentConfigRequest</code>, <code>AgentConfigResponse</code>, and <br><code>AgentCheckConfig</code><br> <li> Updated service definitions from <code>PollerService</code> to <code>AgentGatewayService</code> <br>with new RPC methods<br> <li> Added multi-tenant support fields (<code>TenantId</code>, <code>TenantSlug</code>) to <br>gateway-related messages</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-4f7e955b42854cc9cf3fb063b95e58a04f36271e6a0c1cb42ea6d7953dd96cc4">+1039/-404</a></td> </tr> <tr> <td> <details> <summary><strong>nats_bootstrap.go</strong><dd><code>Add NATS bootstrap and admin CLI functionality</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/cli/nats_bootstrap.go <ul><li>New file implementing NATS bootstrap functionality for ServiceRadar <br>CLI<br> <li> Provides handlers for <code>nats-bootstrap</code> and <code>admin nats</code> subcommands with <br>flag parsing<br> <li> Implements bootstrap creation via Core API, local bootstrap, and <br>verification modes<br> <li> Generates NATS operator, system account, and platform account <br>credentials and configuration files<br> <li> Includes admin commands for generating bootstrap tokens, checking NATS <br>status, and listing tenant accounts<br> <li> Supports both text and JSON output formats for all operations</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-2176d03ba6ab4ccc1b0587a4727171546eecf6123e4df815ead583aaab062457">+961/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>service.go</strong><dd><code>Gateway push architecture with multi-tenant support</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/sync/service.go <ul><li>Removed KV client and gRPC client dependencies; replaced with <br>gateway-based push architecture<br> <li> Added multi-tenant support with per-tenant source configurations, <br>integrations, and results tracking<br> <li> Implemented gateway enrollment, config polling, and heartbeat loops <br>for push-first communication<br> <li> Refactored discovery and results handling to support chunked streaming <br>with configurable chunk sizes<br> <li> Deprecated pull-based <code>GetResults</code> and <code>StreamResults</code> gRPC methods in <br>favor of gateway push</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7e">+1047/-309</a></td> </tr> <tr> <td> <details> <summary><strong>account_manager.go</strong><dd><code>NATS account signer implementation</code>&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/nats/accounts/account_manager.go <ul><li>New module providing stateless NATS account signing operations<br> <li> Implements <code>AccountSigner</code> for creating tenant accounts and signing JWTs<br> <li> Applies default subject mappings for tenant isolation (events, syslog, <br>SNMP, netflow, etc.)<br> <li> Supports custom account limits and user key revocations</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-6d99437619fe01afb4470e118528ff6f0154b1169948cce1fccfadd742c41178">+238/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>push_loop.go</strong><dd><code>New push loop implementation for agent status management</code>&nbsp; </dd></summary> <hr> pkg/agent/push_loop.go <ul><li>New file implementing <code>PushLoop</code> struct that manages periodic pushing of <br>agent status to gateway<br> <li> Handles agent enrollment, config polling, and status collection from <br>services and checkers<br> <li> Includes thread-safe accessors for shared state (interval, config <br>version, enrollment status)<br> <li> Implements config fetching, applying, and conversion of proto checks <br>to checker configs</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-5f0d59be34ef26b449d7f5fd2b198a29b277936b9708a699f7487415ed6c2785">+979/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>nats_account_service.go</strong><dd><code>New NATS account service for JWT-based multi-tenancy</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/datasvc/nats_account_service.go <ul><li>New file implementing <code>NATSAccountServer</code> for NATS JWT/NKeys <br>cryptographic operations<br> <li> Provides gRPC service methods for operator bootstrap, tenant account <br>creation, and user credential generation<br> <li> Handles mTLS authorization, resolver connection management, and JWT <br>signing<br> <li> Includes helper functions for proto conversion and NATS configuration <br>file writing</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-3e814328b5d5bddca9cd4b0ca021a975cf416afdc059e454452580a4ce751320">+888/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>events.go</strong><dd><code>Add NATS credentials file support to event publisher</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/core/events.go <ul><li>Added support for NATS credentials file configuration in event <br>publisher initialization<br> <li> Appends <code>nats.UserCredentials</code> option when <code>config.NATS.CredsFile</code> is set</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-7d499ed41701e367e51735c9a0a78bcce977dea3872771eb7b22c47dc39e0241">+4/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Bug fix</strong></td><td><details><summary>1 files</summary><table> <tr> <td> <details> <summary><strong>spire.go</strong><dd><code>Add Sync component type to SPIRE configuration validation</code></dd></summary> <hr> pkg/edgeonboarding/spire.go <ul><li>Added <code>models.EdgeOnboardingComponentTypeSync</code> to the unsupported <br>component type check alongside <code>EdgeOnboardingComponentTypeNone</code></ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-5d784c136f3db0128ea90d628cbefdff9e2ba18eba9a1775f54fc630bde8ee1d">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Dependencies</strong></td><td><details><summary>1 files</summary><table> <tr> <td> <details> <summary><strong>nats_account.pb.go</strong><dd><code>NATS account management protobuf definitions</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> proto/nats_account.pb.go <ul><li>Generated protobuf code for NATS account management service<br> <li> Defines message types for account creation, user credential <br>generation, and JWT signing<br> <li> Includes enums for user credential types (collector, service, admin)<br> <li> Implements service methods for operator bootstrap and account JWT <br>management</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-49eb93c28e2d86d8dcf4ee78fd24bed498cf3fcfaa8e49849a36e70980420087">+1266/-0</a></td> </tr> </table></details></td></tr><tr><td><strong>Tests</strong></td><td><details><summary>3 files</summary><table> <tr> <td> <details> <summary><strong>netbox_test.go</strong><dd><code>Remove KV-related test code</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; </dd></summary> <hr> pkg/sync/integrations/netbox/netbox_test.go <ul><li>Removed KV data and gRPC imports from test file<br> <li> Updated <code>processDevices</code> call to expect only device events return value<br> <li> Simplified test assertions to validate only device IP extraction</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-66de83a0ffb0ccc0a546fa548a6ec04ea5351f63cc6b4959214b4a490301ca2a">+1/-116</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>service_test.go</strong><dd><code>Refactor sync service tests to remove poller-related code</code></dd></summary> <hr> pkg/sync/service_test.go <ul><li>Removed multiple test functions related to deprecated pull-based <br>polling (<code>TestSimpleSyncService_GetResults</code>, <br><code>TestSimpleSyncService_writeToKV*</code>)<br> <li> Simplified <code>NewSimpleSyncService</code> constructor calls by removing mock KV <br>and gRPC client parameters<br> <li> Added new tests for chunking logic (<code>TestBuildResultsChunks</code>, <br><code>TestBuildGatewayStatusChunks</code>, <code>TestBuildResultsChunksSizeBudget</code>)<br> <li> Updated <code>TestSimpleSyncService_StreamResults</code> to verify unimplemented <br>status and added <code>TestGroupSourcesByTenantScope</code></ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-1775a061aca7003b65ee5bac4510511d264530cadb4939909327db56f6163092">+196/-467</a></td> </tr> <tr> <td> <details> <summary><strong>armis_test.go</strong><dd><code>Remove poller/KV writer dependencies from Armis integration tests</code></dd></summary> <hr> pkg/sync/integrations/armis/armis_test.go <ul><li>Removed <code>KVWriter</code> mock and related sweep config expectations from test <br>setup<br> <li> Simplified <code>Fetch</code> method signature to return only events instead of KV <br>data and events<br> <li> Removed tests for KV write operations and sweep config handling<br> <li> Updated <code>processDevices</code> test to verify only device events without KV <br>payloads or device targets</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-69a98265fabfd3234d96f407cd3ce5e716245079318a624db61f55c1c9b17571">+18/-508</a></td> </tr> </table></details></td></tr><tr><td><strong>Configuration changes</strong></td><td><details><summary>1 files</summary><table> <tr> <td> <details> <summary><strong>prod.exs</strong><dd><code>Add Elixir production configuration</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> elixir/serviceradar_agent_gateway/config/prod.exs <ul><li>New production configuration file for Elixir service<br> <li> Sets logger level to info for production environment</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-5fdc859dfda96a02326392f61218325913f22f9f0c75a1276ee940d5db9fc62b">+4/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Additional files</strong></td><td><details><summary>101 files</summary><table> <tr> <td><strong>.bazelignore</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-a5641cd37d6ad98b32cdfce1980836cc68312277bc6a7052f55da02ada5bc6cf">+4/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>.bazelrc</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-544556920c45b42cbfe40159b082ce8af6bd929e492d076769226265f215832f">+5/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>.env-sample</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-c4368a972a7fa60d9c4e333cebf68cdb9a67acb810451125c02e3b7eb2594e3d">+33/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>.env.example</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-a3046da0d15a27e89f2afe639b25748a7ad4d9290af3e7b1b6c1a5533c8f0a8c">+38/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>main.yml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-7829468e86c1cc5d5133195b5cb48e1ff6c75e3e9203777f6b2e379d9e4882b3">+18/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>AGENTS.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-a54ff182c7e8acf56acfd6e4b9c3ff41e2c41a31c9b211b2deb9df75d9a478f9">+175/-11</a></td> </tr> <tr> <td><strong>MODULE.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-6136fc12446089c3db7360e923203dd114b6a1466252e71667c6791c20fe6bdc">+5/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>Makefile</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-76ed074a9305c04054cdebb9e9aad2d818052b07091de1f20cad0bbac34ffb52">+47/-2</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>README-Docker.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-9fd61d24482efe68c22d8d41e2a1dcc440f39195aa56e7a050f2abe598179efd">+16/-1</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-884fa9353a5226345e44fbabea3300efc7a87dfbcde0b6a42521ca51823f1b68">+11/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-0e80ea46aeb61a873324685edb96eae864c7a2004fbb7ee404b4ec951190ba10">+12/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>mix_release.bzl</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-86ec281f99363b6b6eb1f49e21d83b7eeca93a35b552b9f305fffc6855e38ccd">+124/-49</a></td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-143f8d1549d52f28906f19ce28e5568a5be474470ff103c2c1e63c3e6b08d670">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>config.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-5b1bc8fe77422534739bdd3a38dc20d2634a86c171265c34e1b5d0c5a61b6bab">+5/-6</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>main.go</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-61358711e980ccf505246fd3915f97cbd3a380e9b66f6fa5aad46749968c5ca3">+174/-74</a></td> </tr> <tr> <td><strong>build.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-251e7a923f45f8f903e510d10f183366bda06d281c8ecc3669e1858256e2186d">+0/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>monitoring.proto</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-b56f709f4a0a3db694f2124353908318631f23e20b7846bc4b8ee869e2e0632a">+3/-26</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>server.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-bce0f4ca6548712f224b73816825d28e831acbbff7dbed3c98671ed50f65d028">+2/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>monitoring.proto</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-9faf6025eb0d3d38383f5b7ad2b733abeb38454d5e4de3e83994e94b12d87a50">+2/-26</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>server.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-2c4395fee16396339c3eea518ad9bec739174c67c9cedf62e6848c17136dd33e">+6/-6</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>main.go</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-ed4d81d29a7267f93fd77e17993fd3491b9ef6ded18490b4514d10ed1d803bc2">+14/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>config.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-05038f3867985e757de9027609950e682bad6d1992dac6acd7c28962a3c65dc4">+26/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>grpc_server.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-e4564a93f6cf84ff91cd3d8141fc9272ec9b4ec19defd107afa42be01fcfed5b">+2/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>message_processor.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-9fcbc5358a9009e60a8cd22d21e5a9ea652787c727732d0b869e0865495114c3">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>nats.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-97f7335def0ad5d644b594a1076ae2d7080b11259cbb8de22c7946cc8e4b39f8">+4/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>zen-consumer-with-otel.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-68375f1f7847e1fbdf75664f6be65b1ad94ae6ce86ed73fc5964d65054668acb">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>zen-consumer.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-4d308af9802a93a0f656e8c02a3b5fcd8991407bb18360f087470db74e1f9524">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-c62c0139ebdb337369f4067567cd2c52b8e7decb3ddfabc77f9f67b2f6e5789c">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>main.go</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-5e7731adfb877918cd65d9d5531621312496450fd550fea2682efca4ca8fe816">+68/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>README.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-f425b4378f84e0ba0c6f532facff17ff5d55b4dc6033d8bf35130a159cd2ba32">+9/-12</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>flowgger.toml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-af9f49f931e282dca53d1f0521b036d222fe671f77e61a876a84cf4c6d7cca4d">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>nats_output.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-a82e2e4d413539bf0b414b5629665b19648447523994cba639c4d1238aa5a0c1">+14/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>otel.toml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-c64b9ace832b8ea57a2be62f84166e03bb1904882635d444ec76a880cdf14cc0">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>config.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-abbaec651da3d6af96b482e0f77bb909b65dbe0cabd78b5803769cc9dab0a1b0">+13/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>nats_output.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-6b585ea3564a481174e04da1270e2e13edd4e2b980d02a2652d6d21e6d82a498">+7/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>setup.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-3891f667deb20fd26e296d3e2742c57378d3764fe1743118e612465ae360391f">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-4f5d2ea4260d490a0d6f28adde0b35eca8af77d22f3ee366a783946c53687619">+0/-25</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>config.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-bcac20d6b3cb81f0059e766839ba1ee59a885009249501b0ba1182ebb1daea25">+0/-77</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>main.go</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-78dc6bc53f1c760c66f43ff5f486bfe78a65bee8b2e0d4862293ec0892da2b29">+0/-123</a>&nbsp; </td> </tr> <tr> <td><strong>config.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-c89b88ba4d2bf0a054d0ba69a672a92c30140b8d19503d67b980a218ffe3106d">+21/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>main.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-33b655d8730ae3e9c844ee280787d11f1b0d5343119188273f89558805f814ba">+23/-1</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>docker-compose.elx.yml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-9562070d7ad4a3e9b2d06567008cf35de1d96448d914b3b45bf6c36d97cdd914">+108/-0</a>&nbsp; </td> </tr> <tr> <td><strong>docker-compose.spiffe.yml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-603fd9e7d40841d174f26b95d0cb0c9537430bf3f7a5da3ccbba4ea3d8ac66c9">+8/-157</a>&nbsp; </td> </tr> <tr> <td><strong>docker-compose.yml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-e45e45baeda1c1e73482975a664062aa56f20c03dd9d64a827aba57775bed0d3">+298/-280</a></td> </tr> <tr> <td><strong>Dockerfile.agent-gateway</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-332bc81a932ae08efa711a71b60fe0954d99bf17ebdab00a3baaa177a44de8b0">+94/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>Dockerfile.core-elx</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-5ec7a971285669999af442a0c7f141c34f7fd9180257307f5c4ed12f789a2182">+108/-0</a>&nbsp; </td> </tr> <tr> <td><strong>Dockerfile.sync</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-0227933b9961fd553af1d229e89d71a0271fdc475081bbcef49b587941af1eda">+0/-95</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>Dockerfile.web-ng</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-92d43af1965575d56c3380ecc8a81024aac2ff36f039ec2d3839e9fc7852bc10">+6/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>agent-minimal.docker.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-1f09fad94636c90373af8e270f6ba0332ae4f4d1df50a4909729280a3a9691e6">+6/-6</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>agent.docker.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-5d33fe703515d03076d31261ecf946e9c6fc668cf5bf65099d49b670739e455e">+5/-20</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>agent.mtls.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-008f2216f159a9bd5db9cc90baaf6f1e64487df7af05b56ab3b9d6c4946aa95f">+7/-10</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>.gitkeep</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-d72c41aab2d6f2c230a4340dfefe7917cdd12bed942c825aa0d4c9875a637bac">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>datasvc.docker.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-3f2719d3dbfe042e8383739e3c78e74e5f851a44e5e46bea8e79c4b79fdcc34f">+3/-2</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>datasvc.mtls.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-3a45619e57f1e6e9a31486ec7fffb33ef246e271f82bac272ee0a946b88da70a">+14/-1</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>db-event-writer.mtls.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-7a33f95f7545499abf0ed9fc91b58499ab209639e4885019579c959583fc7496">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>entrypoint-certs.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-83d6800b184a5233c66c69766286b0a60fece1bc64addb112d9f8dc019437f05">+12/-8</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>entrypoint-sync.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-9d5620b8e6833309dbafb8ee6b6b75c3b942d163c3fe7f1a9827958b2d640265">+0/-96</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>flowgger.docker.toml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-824f8797b418d4b9f5ea41e4a3741a0ed64b881f343072464489a76b7ea01008">+2/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>generate-certs.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-8298241543b4744a6ac7780c760ac5b5a0a87ba62de19c8612ebe1aba0996ebd">+220/-12</a></td> </tr> <tr> <td><strong>nats.docker.conf</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-06f2012494f428fe1bfb304972061c2094e0d99da88ba9af6914f7776872e6eb">+16/-160</a></td> </tr> <tr> <td><strong>netflow-consumer.mtls.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-f15920e8498a24f71ce3eec4f48fe8fefbb1765a90362998af779a660fcef9e1">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>otel.docker.toml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-d4af38790e3657b7589cd37a7539d5308b032f11caba7aa740ddc86bf99f4415">+2/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>pg_hba.conf</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-7bd5f7292054916c7e5997f4c84ac9ec07d4c945621a48936c2aed0575fb96eb">+9/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>pg_ident.conf</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-e7b8ce062e32c61fdc3bcc9e525c1f1df1c8008fbc02b11409e58c67baa17cc5">+17/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>bootstrap-compose-spire.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-ca219a124d4c95ee7995764d7e0c322b4bfe59e357b7bcb42bc5d7c8b9b0af0d">+0/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>ssl_dist.core.conf</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-08d49d8621b581d1a9aa5c456f61e8c5774e021083c982cbb514019f915a1701">+17/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>ssl_dist.gateway.conf</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-4a43a8290d45ac68592000e7ef51afe78b4213090155bd42aafb46e66130f7ae">+17/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>ssl_dist.web.conf</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-cef5be462ddb059fdfdeb9fd7c5cd70e656c4cd8b6ae1fe3fe312557b3da80ac">+17/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>sync.docker.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-4237fcee4f33a230abf28e12e8d4823499d163759cd1ff124fec1c62faa8b8b4">+0/-71</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>sync.mtls.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-c652c07f7127be5b2932d92e6ef4c7448c544d1f3095cb96a03294fa58fd3c4c">+0/-75</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>trapd.docker.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-1ab1a0e03e63bc02e0ef31992a7187a377927272ed2060150b40d44cc0ea3357">+2/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>zen.docker.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-e060a3164cdc2746e0d9ad000fcf43c4bcdb05f4a41c586d7220e2ff2a7df01d">+2/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-0e4db31c224a8f72ae8e870a849e38a59d74a2c7f7b04347b0b3eb07e20c5a80">+80/-42</a>&nbsp; </td> </tr> <tr> <td><strong>push_targets.bzl</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-4af33fe62caba04b6d479589c16cfb85babc39bae5c92595d4d4e31660738513">+2/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>SBOM.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-1747f3c15088e6b4a3ff7fb1fdec9c2ef15ac865ee991b26ace892deba984eae">+0/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>agents.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-af8d04277f2353629065b0cc5fad3e44bd3e7c20339bd125e0812104bdbeff28">+8/-9</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>architecture.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-90abd06467420fd89391fd1a4d75ceb1f6a9381de4d13a95fffe606abff38d37">+100/-26</a></td> </tr> <tr> <td><strong>armis.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-3e5c728550851ae1cfb8754eb8a1566d8084ebc58646c73f7c29ac6f7d60adbf">+7/-21</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>ash-api.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-1cb48a12148688dc640f42675d0b3c2458ecc40175f4ae7eef4b07bdc2ede3a3">+305/-0</a>&nbsp; </td> </tr> <tr> <td><strong>ash-authentication.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-e3d22dc8d6917661b980dd9c7e08bdc07fad4d225b10c60885b091a9cdd20425">+244/-0</a>&nbsp; </td> </tr> <tr> <td><strong>ash-authorization.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-72abeea2439e2281b6f998db2d11a73fe3ab393898125c466f0b16e7a49d3088">+283/-0</a>&nbsp; </td> </tr> <tr> <td><strong>ash-domains.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-bc78325c5ea4c6839212536a43336a231175450738af14f4173be663acf2fe49">+223/-0</a>&nbsp; </td> </tr> <tr> <td><strong>ash-migration-guide.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-e730373f07f6656d00327de02b4aa64e13809aadb3bf5478a4c60041ee431ad8">+339/-0</a>&nbsp; </td> </tr> <tr> <td><strong>auth-configuration.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-92b481e02c4edb9a178f51f2a8cb94108c7bcb1514a4629d8c67d8f20a70e852">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>cluster.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-0d2e32a530d31d08b311213cd036c14e611d2f9a31e9cbcaa97f02b53edeeb44">+2/-2</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>discovery.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-a7f02a003a0e9aaf09d6aa072689ca8ad8b7b298ee014c6ffb878d2a5ecbab28">+19/-20</a>&nbsp; </td> </tr> <tr> <td><strong>docker-setup.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-8604269dffb3ce4133e48cab374ca8e97745d0efbdef67cad792aeb5945fe5ec">+57/-14</a>&nbsp; </td> </tr> <tr> <td><strong>edge-agents.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-df8f4b6b6cd8fb926f9204b2bab85ec4f393286d1b25d8a62d2debd357dd651d">+253/-0</a>&nbsp; </td> </tr> <tr> <td><strong>edge-onboarding.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-f32fbefcc4dd23b0f2146015630a411099012e8bf56ea7b9d52ae8b2a83ac3e3">+316/-273</a></td> </tr> <tr> <td><strong>identity_drift_monitoring.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-963ddfdc868c8777f9004744f5d2c5ec3ce585b81d1c0de2269b9d7a73942a9f">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>installation.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-19fd876fb56da88a1becb80817b52db1a40e8491641d547913b93bb7ecda3d22">+13/-14</a>&nbsp; </td> </tr> <tr> <td><strong>intro.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-5ddf6bcf52fe8ef8dfc865f5f2295616d5c073d899766372e5929cc0fd479ffd">+5/-5</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>kv-configuration.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-24c06e4806fa0ec5508ae5aeab9fbe82be7122af9933e6b7970032576cf5f6f8">+3/-3</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>netbox.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-ee0f0a76b85416a7c6e086eca04b7991c176075816b51f442ddb94ea6506dc68">+4/-23</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>netflow.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-a64260e87bce20ed3bd93c7b64dac6ff175cdc7c67071276601aa9f6d370d634">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>onboarding-review-2025.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-1728c73ae8e684d13b7b166b90cbfc5363c0794dcd63f7fa3733e1c624940e98">+0/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>rperf-monitoring.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-70d068dec062c5ed771e7294401c52d55e85e279e9eee4f1084ca06c23b2fde8">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>compose-mtls-sysmonosx.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-6faf517c376b3509d0b14235f1b674a825f0399cd8a20791d8caf3b6ef16525b">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>docker-compose-login-500.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-d3ec1ba25f119cff4efcb5767a1afe923b92fd5727453c6276030bc8e9923f05">+3/-3</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>security-architecture.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-49e33c2fc609030af8a64af34016a22e9e86c0f3781acec5a9e6d0f7ccf5dc09">+238/-0</a>&nbsp; </td> </tr> <tr> <td><strong>Additional files not shown</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-2f328e4cd8dbe3ad193e49d92bcf045f47a6b72b1e9487d366f6b8288589b4ca"></a></td> </tr> </table></details></td></tr></tbody></table> </details> ___
qodo-code-review[bot] commented 2026-01-06 17:34:01 +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/2226#issuecomment-3715636152
Original created: 2026-01-06T17:34:01Z

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
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
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

  • 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/2226#issuecomment-3715636152 Original created: 2026-01-06T17:34:01Z --- ## PR Compliance Guide 🔍 <!-- https://github.com/carverauto/serviceradar/commit/870ef5cf868f42b40026ec2285c43a604b08ce67 --> 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>🎫 <strong>No ticket provided </strong></summary> - [ ] Create ticket/issue <!-- /create_ticket --create_ticket=true --> </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=1>🟢</td><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 rowspan=5>⚪</td> <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 2026-01-06 17:35:33 +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/2226#issuecomment-3715640843
Original created: 2026-01-06T17:35:33Z

PR Code Suggestions

Latest suggestions up to 9464350

CategorySuggestion                                                                                                                                    Impact
Possible issue
Preserve protobuf field numbers

Avoid reusing the protobuf field number from the removed poller_id for
gateway_id to prevent breaking backward compatibility and causing potential data
corruption. Instead, reserve the old field number or use a new, unused one for
gateway_id.

proto/monitoring.pb.go [139-148]

 type StatusRequest struct {
 	state         protoimpl.MessageState `protogen:"open.v1"`
 	ServiceName   string                 `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` // Type of service to check (process, port, dusk)
 	ServiceType   string                 `protobuf:"bytes,2,opt,name=service_type,json=serviceType,proto3" json:"service_type,omitempty"` // Type of service (process, port, grpc, etc)
 	AgentId       string                 `protobuf:"bytes,3,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`             // Agent ID for traceability
-	GatewayId     string                 `protobuf:"bytes,4,opt,name=gateway_id,json=gatewayId,proto3" json:"gateway_id,omitempty"`       // Gateway ID for traceability
+	PollerId      string                 `protobuf:"bytes,4,opt,name=poller_id,json=pollerId,proto3" json:"poller_id,omitempty"`          // Poller ID for traceability (legacy)
 	Details       string                 `protobuf:"bytes,5,opt,name=details,proto3" json:"details,omitempty"`                            // Additional details (e.g., process name)
 	Port          int32                  `protobuf:"varint,6,opt,name=port,proto3" json:"port,omitempty"`                                 // Port number for port checks
+	GatewayId     string                 `protobuf:"bytes,7,opt,name=gateway_id,json=gatewayId,proto3" json:"gateway_id,omitempty"`       // Gateway ID for traceability
 	unknownFields protoimpl.UnknownFields
 	sizeCache     protoimpl.SizeCache
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 10

__

Why: The suggestion correctly identifies a critical backward-compatibility issue in the protobuf definition, where reusing a field number for a different field can lead to data corruption with older clients.

High
Prevent overwriting stored host IP

Preserve the HostIP field when updating gateway status to prevent it from being
overwritten with an empty value.

pkg/core/gateways.go [581-634]

 gatewayStatus := &models.GatewayStatus{
 	GatewayID: req.GatewayId,
 	IsHealthy: true,
 	LastSeen:  now,
 }
 normSourceIP := normalizeHostIP(resolvedSourceIP)
+if normSourceIP != "" {
+	gatewayStatus.HostIP = normSourceIP
+}
 
 existingStatus, err := s.DB.GetGatewayStatus(ctx, req.GatewayId)
 if err == nil {
 	gatewayStatus.FirstSeen = existingStatus.FirstSeen
+	if gatewayStatus.HostIP == "" {
+		gatewayStatus.HostIP = normalizeHostIP(existingStatus.HostIP)
+	}
 	currentState := existingStatus.IsHealthy
 
 	if err := s.DB.UpdateGatewayStatus(ctx, gatewayStatus); err != nil {
 		s.logger.Error().
 			Err(err).
 			Str("gateway_id", req.GatewayId).
 			Msg("Failed to store gateway status")
 
 		return nil, fmt.Errorf("failed to store gateway status: %w", err)
 	}
 ...
 gatewayStatus.FirstSeen = now
 
 if err := s.DB.UpdateGatewayStatus(ctx, gatewayStatus); err != nil {
 	s.logger.Error().
 		Err(err).
 		Str("gateway_id", req.GatewayId).
 		Msg("Failed to create new gateway status")
 
 	return nil, fmt.Errorf("failed to create gateway status: %w", err)
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that the HostIP field could be unintentionally cleared during a status update, which could lead to loss of important data.

Medium
Fail fast on missing input

In processICMPMetrics, return an error instead of nil when the svc parameter is
nil. This "fail-fast" approach improves error handling and helps identify
upstream bugs.

pkg/core/metrics.go [579-585]

 func (s *Server) processICMPMetrics(
 	ctx context.Context,
 	gatewayID string, partition string, sourceIP string, agentID string,
 	svc *proto.GatewayServiceStatus,
 	details json.RawMessage,
 	now time.Time) error {
 	if svc == nil {
-		return nil
+		return fmt.Errorf("icmp metrics payload missing service status")
 	}

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that returning nil on a nil input svc can hide upstream issues. Failing fast by returning an error provides better error handling and makes debugging easier by preventing silent failures.

Medium
Normalize identifiers written to KV

Use the normalized checker kind when creating a newCheck to prevent duplicate
entries in the gateway configuration.

pkg/core/edge_onboarding.go [2818-2823]

 normalizedKind := strings.ToLower(strings.TrimSpace(pkg.CheckerKind))
 // For gRPC-based checkers, the agent expects service_type="grpc" and service_name=<kind>.
 newCheck := gatewayCheckConfig{
 	Type: "grpc",
-	Name: pkg.CheckerKind,
+	Name: strings.TrimSpace(pkg.CheckerKind),
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly points out an inconsistency where duplicate check detection uses a normalized name, but the new check is created with the raw name, potentially leading to duplicate entries.

Low
Prevent nil map buffer panics

Prevent a potential panic in bufferRperfMetrics by ensuring s.metricBuffers is
initialized before use. This can be done by adding a nil check under the lock.

pkg/core/metrics.go [467-471]

 func (s *Server) bufferRperfMetrics(gatewayID string, metrics []*models.TimeseriesMetric) {
+	if len(metrics) == 0 {
+		return
+	}
+
 	s.metricBufferMu.Lock()
+	defer s.metricBufferMu.Unlock()
+
+	if s.metricBuffers == nil {
+		s.metricBuffers = make(map[string][]*models.TimeseriesMetric)
+	}
+
 	s.metricBuffers[gatewayID] = append(s.metricBuffers[gatewayID], metrics...)
-	s.metricBufferMu.Unlock()
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential nil pointer dereference that would cause a panic if s.metricBuffers is not initialized. This improves the robustness of the code, especially in test environments where Server might be partially constructed.

Low
Incremental [*]
Avoid caching with empty keys

Add a check to ensure pkg.GatewayID is not empty before using it as a key for
activationCacheStore. This prevents potential cache collisions for packages with
an empty gateway ID.

pkg/core/edge_onboarding.go [340-343]

 s.activationCacheStore(pkg.ComponentType, pkg.ComponentID, pkg, true)
-if pkg.ComponentType == models.EdgeOnboardingComponentTypeGateway {
+if pkg.ComponentType == models.EdgeOnboardingComponentTypeGateway && strings.TrimSpace(pkg.GatewayID) != "" {
 	s.activationCacheStore(models.EdgeOnboardingComponentTypeGateway, pkg.GatewayID, pkg, true)
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: This is a good defensive check to prevent caching packages with an empty GatewayID, which could lead to cache collisions and incorrect data being served.

Medium
Guard deletion on empty IDs

Add a check to ensure pkg.GatewayID is not empty before deleting it from the
s.allowed map. This prevents unintended deletion of an entry with an empty
string key.

pkg/core/edge_onboarding.go [1363-1368]

 if pkg.ComponentType == models.EdgeOnboardingComponentTypeGateway || pkg.ComponentType == models.EdgeOnboardingComponentTypeNone {
-	s.mu.Lock()
-	delete(s.allowed, pkg.GatewayID)
-	s.mu.Unlock()
-	s.broadcastAllowedSnapshot()
+	if strings.TrimSpace(pkg.GatewayID) != "" {
+		s.mu.Lock()
+		delete(s.allowed, pkg.GatewayID)
+		s.mu.Unlock()
+		s.broadcastAllowedSnapshot()
+	}
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: This is a valid defensive programming suggestion that prevents accidentally deleting an entry with an empty key from the s.allowed map, which could have unintended side effects.

Medium
Prevent null array serialization

Add the omitempty tag to the Checks field in the gatewayAgentConfig struct. This
prevents a nil slice from being marshaled as null in the JSON output.

pkg/core/edge_onboarding.go [2738-2743]

 type gatewayAgentConfig struct {
-	Address  string              `json:"address"`
-	Checks   []gatewayCheckConfig `json:"checks"`
-	Security json.RawMessage     `json:"security,omitempty"`
+	Address  string               `json:"address"`
+	Checks   []gatewayCheckConfig `json:"checks,omitempty"`
+	Security json.RawMessage      `json:"security,omitempty"`
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential JSON marshaling issue where a nil slice becomes null, which might be undesirable for consumers. Adding omitempty is a standard and effective way to handle this.

Medium
General
Add descriptor alias for compatibility

Add a backward-compatibility alias for the renamed File_proto_monitoring_proto
variable to File_monitoring_proto to avoid breaking changes for consumers of
this generated code.

proto/monitoring.pb.go [1740]

 var File_monitoring_proto protoreflect.FileDescriptor
 
+// Backwards-compatibility alias (deprecated): older code may still reference this symbol.
+//nolint:revive
+var File_proto_monitoring_proto protoreflect.FileDescriptor
+

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out a breaking change for an exported variable and proposes a valid solution to maintain backward compatibility, which is important for generated code that might be used externally.

Medium
  • More

Previous suggestions

Suggestions up to commit 870ef5c
CategorySuggestion                                                                                                                                    Impact
Possible issue
Prevent deadlock from blocking channel write
Suggestion Impact:UpdateConfig was changed to use a non-blocking select when sending to s.reloadChan, preventing a blocking send while the config mutex is held. The commit also adjusts the log message when the channel is full (Debug instead of Warn) and includes mutex locking around UpdateConfig.

code diff:

@@ -368,6 +368,10 @@
 	if newCfg == nil {
 		return
 	}
+
+	s.configMu.Lock()
+	defer s.configMu.Unlock()
+
 	// Check interval changes
 	newDisc := time.Duration(newCfg.DiscoveryInterval)
 	newUpd := time.Duration(newCfg.UpdateInterval)
@@ -385,6 +389,7 @@
 		select {
 		case s.reloadChan <- struct{}{}:
 		default:
+			s.logger.Debug().Msg("Reload channel full; skipping reload trigger")
 		}
 	}

In UpdateConfig, use a non-blocking select statement to send to s.reloadChan to
prevent a potential deadlock if the channel is full while a mutex is held.

pkg/sync/service.go [367-391]

 func (s *SimpleSyncService) UpdateConfig(newCfg *Config) {
 	if newCfg == nil {
 		return
 	}
 	s.configMu.Lock()
 	defer s.configMu.Unlock()
 
 	newDisc := time.Duration(newCfg.DiscoveryInterval)
 	newUpd := time.Duration(newCfg.UpdateInterval)
 
 	intervalsChanged := (newDisc != s.discoveryInterval) || (newUpd != s.armisUpdateInterval)
 	s.discoveryInterval = newDisc
 	s.armisUpdateInterval = newUpd
 	// Rebuild integrations even when sources are cleared.
 	s.sources = make(map[string]Integration)
 	for name, src := range newCfg.Sources {
 		if f, ok := s.registry[src.Type]; ok {
 			s.sources[name] = s.createIntegration(s.ctx, src, f)
 		}
 	}
 	if intervalsChanged {
 		s.logger.Info().Msg("Sync intervals changed, triggering reload")
-		s.reloadChan <- struct{}{}
+		select {
+		case s.reloadChan <- struct{}{}:
+		default:
+			s.logger.Warn().Msg("Reload channel is full; skipping reload trigger")
+		}
 	}
 
 	s.config = *newCfg
 }
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a potential deadlock caused by a blocking send on s.reloadChan while holding s.configMu. The proposed fix using a non-blocking select is the standard and correct way to prevent this type of deadlock.

High
Remove extra newline literal

Remove the extra newline literal "\n" from the file_monitoring_proto_rawDesc
constant to prevent potential protobuf descriptor parsing errors.

proto/monitoring.pb.go [1751-1753]

-// in the generated raw descriptor for StatusRequest (and similarly in other messages)
+// corrected raw descriptor snippet
 "...\\bagent_id\\x18\\x03 \\x01(\\tR\\aagentId\\x12\\x1d\\n" +
-"\\n" +
 "gateway_id\\x18\\x04 \\x01(\\tR\\tgatewayId\\x12\\x18\\n" +
 "..."
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a stray newline literal "\n" in the file_monitoring_proto_rawDesc constant, which could cause protobuf descriptor parsing to fail at runtime. This is a critical fix for the generated code's integrity.

Medium
Fix race condition on config
Suggestion Impact:The commit adds s.configMu.RLock()/RUnlock() around the read of s.config.Sources[sourceName] in applySourceBlacklist, addressing the identified race condition. It also adds a write lock in the config update path, further reducing concurrent access issues.

code diff:

+	s.configMu.Lock()
+	defer s.configMu.Unlock()
+
 	// Check interval changes
 	newDisc := time.Duration(newCfg.DiscoveryInterval)
 	newUpd := time.Duration(newCfg.UpdateInterval)
@@ -385,6 +389,7 @@
 		select {
 		case s.reloadChan <- struct{}{}:
 		default:
+			s.logger.Debug().Msg("Reload channel full; skipping reload trigger")
 		}
 	}
 	s.config = *newCfg
@@ -1491,7 +1496,10 @@
 	sourceName string,
 	devices []*models.DeviceUpdate,
 ) (filteredDevices []*models.DeviceUpdate) {
+	s.configMu.RLock()
 	sourceConfig := s.config.Sources[sourceName]
+	s.configMu.RUnlock()
+
 	if sourceConfig == nil || len(sourceConfig.NetworkBlacklist) == 0 {
 		return devices
 	}

Add a read lock in applySourceBlacklist when accessing s.config.Sources to
prevent a potential race condition with concurrent configuration updates.

pkg/sync/service.go [1490-1516]

 func (s *SimpleSyncService) applySourceBlacklist(
 	sourceName string,
 	devices []*models.DeviceUpdate,
--	kvData map[string][]byte) (filteredDevices []*models.DeviceUpdate, filteredKVData map[string][]byte) {
-+) (filteredDevices []*models.DeviceUpdate) {
+) (filteredDevices []*models.DeviceUpdate) {
+	s.configMu.RLock()
 	sourceConfig := s.config.Sources[sourceName]
+	s.configMu.RUnlock()
 	if sourceConfig == nil || len(sourceConfig.NetworkBlacklist) == 0 {
--		return devices, kvData
-+		return devices
+		return devices
 	}
 
 	networkBlacklist, err := NewNetworkBlacklist(sourceConfig.NetworkBlacklist, s.logger)
 	if err != nil {
 		s.logger.Error().Err(err).Str("source", sourceName).Msg("Failed to create network blacklist for source")
--		return devices, kvData
-+		return devices
+		return devices
 	}
 
 	originalCount := len(devices)
 	filteredDevices = networkBlacklist.FilterDevices(devices)
 
 	if filteredCount := originalCount - len(filteredDevices); filteredCount > 0 {
 		s.logger.Info().
 			Str("source", sourceName).
 			Int("filtered_count", filteredCount).
 			Int("remaining_count", len(filteredDevices)).
 			Msg("Applied source-specific network blacklist filtering to devices")
 	}
--
--	// Also filter KV data to remove blacklisted entries
--	originalKVCount := len(kvData)
--	filteredKVData = networkBlacklist.FilterKVData(kvData, filteredDevices)
--
--	if kvFilteredCount := originalKVCount - len(filteredKVData); kvFilteredCount > 0 {
--		s.logger.Info().
--			Str("source", sourceName).
--			Int("filtered_count", kvFilteredCount).
--			Int("remaining_count", len(filteredKVData)).
--			Msg("Applied source-specific network blacklist filtering to KV data")
--	}
--
--	return filteredDevices, filteredKVData
-+	return filteredDevices
+	return filteredDevices
 }
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a race condition where s.config.Sources is read without a lock, while it can be modified concurrently by UpdateConfig. The proposed fix of using s.configMu.RLock() is accurate and prevents this potential data race.

Medium
Prevent race condition during configuration update
Suggestion Impact:The commit updated applyConfigPayload to take a read lock on s.config, clone it, then release the lock before mutating the cloned config—matching the suggested approach to avoid data races during concurrent config access.

code diff:

@@ -835,7 +852,11 @@
 		sources = map[string]*models.SourceConfig{}
 	}
 
-	updatedCfg := s.config
+	// Clone config under read lock to prevent race with concurrent updates
+	s.configMu.RLock()
+	updatedCfg := s.config.Clone()
+	s.configMu.RUnlock()
+
 	if payload.AgentID != "" {
 		updatedCfg.AgentID = payload.AgentID
 	}

In applyConfigPayload, create a deep copy of s.config under a lock before
modifying it to prevent race conditions with other goroutines.

pkg/sync/service.go [828-858]

 func (s *SimpleSyncService) applyConfigPayload(payload *gatewaySyncPayload, configVersion string) {
 	if payload == nil {
 		return
 	}
 
 	sources := payload.Sources
 	if sources == nil {
 		sources = map[string]*models.SourceConfig{}
 	}
 
-	updatedCfg := s.config
+	s.configMu.RLock()
+	updatedCfg := s.config.Clone()
+	s.configMu.RUnlock()
+
 	if payload.AgentID != "" {
 		updatedCfg.AgentID = payload.AgentID
 	}
 	if payload.TenantID != "" {
 		updatedCfg.TenantID = payload.TenantID
 	}
 	updatedCfg.Sources = sources
 
 	scope := payload.Scope
 	if scope == "" {
 		scope = "tenant"
 	}
 
 	s.UpdateConfig(&updatedCfg)
 	s.setTenantSources(sources, scope)
 
 	if configVersion != "" {
 		s.setConfigVersion(configVersion)
 	}
 }
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a race condition where s.config is read and modified without a lock. The proposed solution to create a copy of the config under a read lock before modification is a correct and safe way to handle concurrent access.

Medium
Safely handle API response types

Add checks for type assertions when parsing the API response for tenants to
handle unexpected data types gracefully by displaying 'N/A' for invalid fields.

pkg/cli/nats_bootstrap.go [951-957]

 		for _, t := range tenants {
-			tenantID, _ := t["id"].(string)
-			slug, _ := t["slug"].(string)
-			status, _ := t["nats_account_status"].(string)
-			accountKey, _ := t["nats_account_public_key"].(string)
+			tenantID, ok := t["id"].(string)
+			if !ok {
+				tenantID = "N/A"
+			}
+			slug, ok := t["slug"].(string)
+			if !ok {
+				slug = "N/A"
+			}
+			status, ok := t["nats_account_status"].(string)
+			if !ok {
+				status = "N/A"
+			}
+			accountKey, ok := t["nats_account_public_key"].(string)
+			if !ok {
+				accountKey = "N/A"
+			}
 			fmt.Printf("%-36s  %-20s  %-15s  %s\n", tenantID, slug, status, accountKey)
 		}
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies that unchecked type assertions on API response data can lead to confusing output if the data types are unexpected, and the proposed change makes the output more robust and user-friendly.

Low
High-level
Use the official NATS nsc tool

Instead of building a custom service and CLI for NATS account management, use
the official NATS nsc tool. This would simplify the architecture and reduce
maintenance.

Examples:

proto/nats_account.pb.go [1-1266]
pkg/cli/nats_bootstrap.go [1-961]

Solution Walkthrough:

Before:

// pkg/cli/nats_bootstrap.go
func RunNatsBootstrap(cfg *CmdConfig) error {
  // ... logic to call a custom gRPC service ...
}

// proto/nats_account.pb.go
service NATSAccountService {
  rpc BootstrapOperator(...) returns (...);
  rpc CreateTenantAccount(...) returns (...);
  rpc GenerateUserCredentials(...) returns (...);
  // ... other RPCs for JWT management
}

// pkg/nats/accounts/service.go (inferred)
// Implements the NATSAccountService gRPC service,
// using NATS Go libraries to create keys,
// sign JWTs, and manage accounts.

After:

// Control Plane Service (e.g., for tenant onboarding)

func createNatsAccountForTenant(tenantSlug string) error {
  // Execute the official 'nsc' command-line tool
  // to create and manage NATS accounts and users.
  // This replaces the custom gRPC service.

  // 1. Add account
  cmd := exec.Command("nsc", "add", "account", "--name", tenantSlug)
  if err := cmd.Run(); err != nil {
    return err
  }

  // 2. Add user
  cmd = exec.Command("nsc", "add", "user", "--name", "user1", "--account", tenantSlug)
  if err := cmd.Run(); err != nil {
    return err
  }

  // 3. Generate user credentials
  // ... and so on for other management tasks.
}

Suggestion importance[1-10]: 7

__

Why: The suggestion raises a valid, high-impact architectural point about reinventing NATS account management instead of using the official nsc tool, which could simplify the codebase and reduce maintenance.

Medium
General
Fix context cancellation handling
Suggestion Impact:The commit removed the `case <-s.ctx.Done(): return s.ctx.Err()` branch from `configPollLoop`, so the loop now only exits on the passed-in `ctx.Done()`. The same redundant `s.ctx.Done()` cancellation branch was also removed from another similar poll loop (heartbeat), extending the same idea beyond the original suggestion.

code diff:

@@ -956,8 +981,6 @@
 		select {
 		case <-ctx.Done():
 			return ctx.Err()
-		case <-s.ctx.Done():
-			return s.ctx.Err()
 		case <-timer.C:
 			if err := s.fetchAndApplyConfig(ctx); err != nil {
 				if errors.Is(err, errGatewayNotEnrolled) {
@@ -983,8 +1006,6 @@
 		select {
 		case <-ctx.Done():
 			return ctx.Err()
-		case <-s.ctx.Done():
-			return s.ctx.Err()
 		case <-timer.C:

In configPollLoop, remove the check for s.ctx.Done() and only listen for
cancellation on the ctx argument passed to the function.

pkg/sync/service.go [951-972]

 func (s *SimpleSyncService) configPollLoop(ctx context.Context) error {
     timer := time.NewTimer(s.getConfigPollInterval())
     defer timer.Stop()
 
     for {
         select {
         case <-ctx.Done():
             return ctx.Err()
-        case <-s.ctx.Done():
-            return s.ctx.Err()
         case <-timer.C:
             …
         }
     }
 }
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that listening to both the local ctx and the service-wide s.ctx is redundant and potentially confusing. The function should only respect the context passed to it, making the cancellation behavior clearer and more conventional.

Medium
Validate output format flag

Add validation to ensure the --output flag is either 'text' or 'json', returning
an error for invalid values.

pkg/cli/nats_bootstrap.go [106]

 cfg.NATSOutputFormat = strings.ToLower(strings.TrimSpace(*output))
+if cfg.NATSOutputFormat != "text" && cfg.NATSOutputFormat != "json" {
+    return fmt.Errorf("invalid output format %q, must be 'text' or 'json'", cfg.NATSOutputFormat)
+}
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that the --output flag value is not validated, which could lead to silent failures. Adding explicit validation improves the command's robustness and provides clear feedback to the user for invalid input.

Medium
Prevent conflicting mode flags

Add a check to prevent the mutually exclusive flags --verify and --local from
being used together.

pkg/cli/nats_bootstrap.go [79-81]

 if err := fs.Parse(args); err != nil {
     return fmt.Errorf("parsing nats-bootstrap flags: %w", err)
 }
+if *verify && *local {
+    return fmt.Errorf("cannot specify both --verify and --local")
+}
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that --verify and --local represent mutually exclusive modes of operation. Adding a check to prevent their simultaneous use improves the CLI's robustness and provides clearer error messaging to the user.

Medium
Remove stale checks on update
Suggestion Impact:The previously commented-out stale-check removal loop in applyChecks was enabled and updated with new comments asserting the gateway config as source of truth, so stale checks are now deleted when not seen in the gateway config.

code diff:

-	// Optionally: remove checks that are no longer in the config
-	// (commented out for now - may want to keep local file-based checks)
-	// for name := range p.server.checkerConfs {
-	// 	if !seenChecks[name] {
-	// 		delete(p.server.checkerConfs, name)
-	// 		p.logger.Info().Str("name", name).Msg("Removed stale check")
-	// 	}
-	// }
+	// Remove checks that are no longer in the gateway config.
+	// Gateway config is the source of truth for all checker configurations.
+	for name := range p.server.checkerConfs {
+		if !seenChecks[name] {
+			delete(p.server.checkerConfs, name)
+			p.logger.Info().Str("name", name).Msg("Removed stale check")
+		}
+	}

Enable the removal of stale checker configurations by uncommenting the relevant
code block in applyChecks.

pkg/agent/push_loop.go [765-772]

-// Optionally: remove checks that are no longer in the config
-// (commented out for now - may want to keep local file-based checks)
-// for name := range p.server.checkerConfs {
-// 	if !seenChecks[name] {
-// 		delete(p.server.checkerConfs, name)
-// 		p.logger.Info().Str("name", name).Msg("Removed stale check")
-// 	}
-// }
+for name := range p.server.checkerConfs {
+    if !seenChecks[name] {
+        delete(p.server.checkerConfs, name)
+        p.logger.Info().Str("name", name).Msg("Removed stale check")
+    }
+}
Suggestion importance[1-10]: 5

__

Why: The suggestion proposes enabling a commented-out feature to remove stale checks. While this is a reasonable feature enhancement for configuration management, the original code intentionally left it disabled to preserve local checks, so this change alters intended behavior.

Low
Imported GitHub PR comment. Original author: @qodo-code-review[bot] Original URL: https://github.com/carverauto/serviceradar/pull/2226#issuecomment-3715640843 Original created: 2026-01-06T17:35:33Z --- ## PR Code Suggestions ✨ <!-- 9464350 --> Latest suggestions up to 9464350 <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=5>Possible issue</td> <td> <details><summary>Preserve protobuf field numbers</summary> ___ **Avoid reusing the protobuf field number from the removed <code>poller_id</code> for <br><code>gateway_id</code> to prevent breaking backward compatibility and causing potential data <br>corruption. Instead, reserve the old field number or use a new, unused one for <br><code>gateway_id</code>.** [proto/monitoring.pb.go [139-148]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-4f7e955b42854cc9cf3fb063b95e58a04f36271e6a0c1cb42ea6d7953dd96cc4R139-R148) ```diff type StatusRequest struct { state protoimpl.MessageState `protogen:"open.v1"` ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` // Type of service to check (process, port, dusk) ServiceType string `protobuf:"bytes,2,opt,name=service_type,json=serviceType,proto3" json:"service_type,omitempty"` // Type of service (process, port, grpc, etc) AgentId string `protobuf:"bytes,3,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` // Agent ID for traceability - GatewayId string `protobuf:"bytes,4,opt,name=gateway_id,json=gatewayId,proto3" json:"gateway_id,omitempty"` // Gateway ID for traceability + PollerId string `protobuf:"bytes,4,opt,name=poller_id,json=pollerId,proto3" json:"poller_id,omitempty"` // Poller ID for traceability (legacy) Details string `protobuf:"bytes,5,opt,name=details,proto3" json:"details,omitempty"` // Additional details (e.g., process name) Port int32 `protobuf:"varint,6,opt,name=port,proto3" json:"port,omitempty"` // Port number for port checks + GatewayId string `protobuf:"bytes,7,opt,name=gateway_id,json=gatewayId,proto3" json:"gateway_id,omitempty"` // Gateway ID for traceability unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 10</summary> __ Why: The suggestion correctly identifies a critical backward-compatibility issue in the protobuf definition, where reusing a field number for a different field can lead to data corruption with older clients. </details></details></td><td align=center>High </td></tr><tr><td> <details><summary>Prevent overwriting stored host IP</summary> ___ **Preserve the <code>HostIP</code> field when updating gateway status to prevent it from being <br>overwritten with an empty value.** [pkg/core/gateways.go [581-634]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-260332914ad2238e720f4637a71b0f9f01e899102bc6b37f7827782e56b0b5c0R581-R634) ```diff gatewayStatus := &models.GatewayStatus{ GatewayID: req.GatewayId, IsHealthy: true, LastSeen: now, } normSourceIP := normalizeHostIP(resolvedSourceIP) +if normSourceIP != "" { + gatewayStatus.HostIP = normSourceIP +} existingStatus, err := s.DB.GetGatewayStatus(ctx, req.GatewayId) if err == nil { gatewayStatus.FirstSeen = existingStatus.FirstSeen + if gatewayStatus.HostIP == "" { + gatewayStatus.HostIP = normalizeHostIP(existingStatus.HostIP) + } currentState := existingStatus.IsHealthy if err := s.DB.UpdateGatewayStatus(ctx, gatewayStatus); err != nil { s.logger.Error(). Err(err). Str("gateway_id", req.GatewayId). Msg("Failed to store gateway status") return nil, fmt.Errorf("failed to store gateway status: %w", err) } ... gatewayStatus.FirstSeen = now if err := s.DB.UpdateGatewayStatus(ctx, gatewayStatus); err != nil { s.logger.Error(). Err(err). Str("gateway_id", req.GatewayId). Msg("Failed to create new gateway status") return nil, fmt.Errorf("failed to create gateway status: %w", err) } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly identifies that the `HostIP` field could be unintentionally cleared during a status update, which could lead to loss of important data. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Fail fast on missing input</summary> ___ **In <code>processICMPMetrics</code>, return an error instead of <code>nil</code> when the <code>svc</code> parameter is <br><code>nil</code>. This "fail-fast" approach improves error handling and helps identify <br>upstream bugs.** [pkg/core/metrics.go [579-585]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-6d98e853ce17576c088e77956ae4ecfa8078019e0bff107a79d8d1d6ed2443adR579-R585) ```diff func (s *Server) processICMPMetrics( ctx context.Context, gatewayID string, partition string, sourceIP string, agentID string, svc *proto.GatewayServiceStatus, details json.RawMessage, now time.Time) error { if svc == nil { - return nil + return fmt.Errorf("icmp metrics payload missing service status") } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly points out that returning `nil` on a `nil` input `svc` can hide upstream issues. Failing fast by returning an error provides better error handling and makes debugging easier by preventing silent failures. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Normalize identifiers written to KV</summary> ___ **Use the normalized checker kind when creating a <code>newCheck</code> to prevent duplicate <br>entries in the gateway configuration.** [pkg/core/edge_onboarding.go [2818-2823]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-85874e3c4bdcc9110db09909f10648d44cdee554b26c987f910502321eb20b5cR2818-R2823) ```diff normalizedKind := strings.ToLower(strings.TrimSpace(pkg.CheckerKind)) // For gRPC-based checkers, the agent expects service_type="grpc" and service_name=<kind>. newCheck := gatewayCheckConfig{ Type: "grpc", - Name: pkg.CheckerKind, + Name: strings.TrimSpace(pkg.CheckerKind), } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 6</summary> __ Why: The suggestion correctly points out an inconsistency where duplicate check detection uses a normalized name, but the new check is created with the raw name, potentially leading to duplicate entries. </details></details></td><td align=center>Low </td></tr><tr><td> <details><summary>Prevent nil map buffer panics</summary> ___ **Prevent a potential panic in <code>bufferRperfMetrics</code> by ensuring <code>s.metricBuffers</code> is <br>initialized before use. This can be done by adding a nil check under the lock.** [pkg/core/metrics.go [467-471]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-6d98e853ce17576c088e77956ae4ecfa8078019e0bff107a79d8d1d6ed2443adR467-R471) ```diff func (s *Server) bufferRperfMetrics(gatewayID string, metrics []*models.TimeseriesMetric) { + if len(metrics) == 0 { + return + } + s.metricBufferMu.Lock() + defer s.metricBufferMu.Unlock() + + if s.metricBuffers == nil { + s.metricBuffers = make(map[string][]*models.TimeseriesMetric) + } + s.metricBuffers[gatewayID] = append(s.metricBuffers[gatewayID], metrics...) - s.metricBufferMu.Unlock() } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 6</summary> __ Why: The suggestion correctly identifies a potential nil pointer dereference that would cause a panic if `s.metricBuffers` is not initialized. This improves the robustness of the code, especially in test environments where `Server` might be partially constructed. </details></details></td><td align=center>Low </td></tr><tr><td rowspan=3>Incremental <sup><a href='https://qodo-merge-docs.qodo.ai/core-abilities/incremental_update/'>[*]</a></sup></td> <td> <details><summary>Avoid caching with empty keys</summary> ___ **Add a check to ensure <code>pkg.GatewayID</code> is not empty before using it as a key for <br><code>activationCacheStore</code>. This prevents potential cache collisions for packages with <br>an empty gateway ID.** [pkg/core/edge_onboarding.go [340-343]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-85874e3c4bdcc9110db09909f10648d44cdee554b26c987f910502321eb20b5cR340-R343) ```diff s.activationCacheStore(pkg.ComponentType, pkg.ComponentID, pkg, true) -if pkg.ComponentType == models.EdgeOnboardingComponentTypeGateway { +if pkg.ComponentType == models.EdgeOnboardingComponentTypeGateway && strings.TrimSpace(pkg.GatewayID) != "" { s.activationCacheStore(models.EdgeOnboardingComponentTypeGateway, pkg.GatewayID, pkg, true) } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: This is a good defensive check to prevent caching packages with an empty `GatewayID`, which could lead to cache collisions and incorrect data being served. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Guard deletion on empty IDs</summary> ___ **Add a check to ensure <code>pkg.GatewayID</code> is not empty before deleting it from the <br><code>s.allowed</code> map. This prevents unintended deletion of an entry with an empty <br>string key.** [pkg/core/edge_onboarding.go [1363-1368]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-85874e3c4bdcc9110db09909f10648d44cdee554b26c987f910502321eb20b5cR1363-R1368) ```diff if pkg.ComponentType == models.EdgeOnboardingComponentTypeGateway || pkg.ComponentType == models.EdgeOnboardingComponentTypeNone { - s.mu.Lock() - delete(s.allowed, pkg.GatewayID) - s.mu.Unlock() - s.broadcastAllowedSnapshot() + if strings.TrimSpace(pkg.GatewayID) != "" { + s.mu.Lock() + delete(s.allowed, pkg.GatewayID) + s.mu.Unlock() + s.broadcastAllowedSnapshot() + } } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: This is a valid defensive programming suggestion that prevents accidentally deleting an entry with an empty key from the `s.allowed` map, which could have unintended side effects. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Prevent null array serialization</summary> ___ **Add the <code>omitempty</code> tag to the <code>Checks</code> field in the <code>gatewayAgentConfig</code> struct. This <br>prevents a <code>nil</code> slice from being marshaled as <code>null</code> in the JSON output.** [pkg/core/edge_onboarding.go [2738-2743]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-85874e3c4bdcc9110db09909f10648d44cdee554b26c987f910502321eb20b5cR2738-R2743) ```diff type gatewayAgentConfig struct { - Address string `json:"address"` - Checks []gatewayCheckConfig `json:"checks"` - Security json.RawMessage `json:"security,omitempty"` + Address string `json:"address"` + Checks []gatewayCheckConfig `json:"checks,omitempty"` + Security json.RawMessage `json:"security,omitempty"` } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly identifies a potential JSON marshaling issue where a `nil` slice becomes `null`, which might be undesirable for consumers. Adding `omitempty` is a standard and effective way to handle this. </details></details></td><td align=center>Medium </td></tr><tr><td rowspan=1>General</td> <td> <details><summary>Add descriptor alias for compatibility</summary> ___ **Add a backward-compatibility alias for the renamed <code>File_proto_monitoring_proto</code> <br>variable to <code>File_monitoring_proto</code> to avoid breaking changes for consumers of <br>this generated code.** [proto/monitoring.pb.go [1740]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-4f7e955b42854cc9cf3fb063b95e58a04f36271e6a0c1cb42ea6d7953dd96cc4R1740-R1740) ```diff var File_monitoring_proto protoreflect.FileDescriptor +// Backwards-compatibility alias (deprecated): older code may still reference this symbol. +//nolint:revive +var File_proto_monitoring_proto protoreflect.FileDescriptor + ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly points out a breaking change for an exported variable and proposes a valid solution to maintain backward compatibility, which is important for generated code that might be used externally. </details></details></td><td align=center>Medium </td></tr> <tr><td align="center" colspan="2"> - [ ] More <!-- /improve --more_suggestions=true --> </td><td></td></tr></tbody></table> ___ #### Previous suggestions <details><summary>✅ Suggestions up to commit 870ef5c</summary> <br><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=5>Possible issue</td> <td> <details><summary>✅ <s>Prevent deadlock from blocking channel write</s></summary> ___ <details><summary><b>Suggestion Impact:</b></summary>UpdateConfig was changed to use a non-blocking select when sending to s.reloadChan, preventing a blocking send while the config mutex is held. The commit also adjusts the log message when the channel is full (Debug instead of Warn) and includes mutex locking around UpdateConfig. code diff: ```diff @@ -368,6 +368,10 @@ if newCfg == nil { return } + + s.configMu.Lock() + defer s.configMu.Unlock() + // Check interval changes newDisc := time.Duration(newCfg.DiscoveryInterval) newUpd := time.Duration(newCfg.UpdateInterval) @@ -385,6 +389,7 @@ select { case s.reloadChan <- struct{}{}: default: + s.logger.Debug().Msg("Reload channel full; skipping reload trigger") } } ``` </details> ___ **In <code>UpdateConfig</code>, use a non-blocking <code>select</code> statement to send to <code>s.reloadChan</code> to <br>prevent a potential deadlock if the channel is full while a mutex is held.** [pkg/sync/service.go [367-391]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7eR367-R391) ```diff func (s *SimpleSyncService) UpdateConfig(newCfg *Config) { if newCfg == nil { return } s.configMu.Lock() defer s.configMu.Unlock() newDisc := time.Duration(newCfg.DiscoveryInterval) newUpd := time.Duration(newCfg.UpdateInterval) intervalsChanged := (newDisc != s.discoveryInterval) || (newUpd != s.armisUpdateInterval) s.discoveryInterval = newDisc s.armisUpdateInterval = newUpd // Rebuild integrations even when sources are cleared. s.sources = make(map[string]Integration) for name, src := range newCfg.Sources { if f, ok := s.registry[src.Type]; ok { s.sources[name] = s.createIntegration(s.ctx, src, f) } } if intervalsChanged { s.logger.Info().Msg("Sync intervals changed, triggering reload") - s.reloadChan <- struct{}{} + select { + case s.reloadChan <- struct{}{}: + default: + s.logger.Warn().Msg("Reload channel is full; skipping reload trigger") + } } s.config = *newCfg } ``` <details><summary>Suggestion importance[1-10]: 9</summary> __ Why: The suggestion correctly identifies a potential deadlock caused by a blocking send on `s.reloadChan` while holding `s.configMu`. The proposed fix using a non-blocking `select` is the standard and correct way to prevent this type of deadlock. </details></details></td><td align=center>High </td></tr><tr><td> <details><summary>Remove extra newline literal</summary> ___ **Remove the extra newline literal <code>"\n"</code> from the <code>file_monitoring_proto_rawDesc</code> <br>constant to prevent potential protobuf descriptor parsing errors.** [proto/monitoring.pb.go [1751-1753]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-4f7e955b42854cc9cf3fb063b95e58a04f36271e6a0c1cb42ea6d7953dd96cc4R1751-R1753) ```diff -// in the generated raw descriptor for StatusRequest (and similarly in other messages) +// corrected raw descriptor snippet "...\\bagent_id\\x18\\x03 \\x01(\\tR\\aagentId\\x12\\x1d\\n" + -"\\n" + "gateway_id\\x18\\x04 \\x01(\\tR\\tgatewayId\\x12\\x18\\n" + "..." ``` <details><summary>Suggestion importance[1-10]: 8</summary> __ Why: The suggestion correctly identifies a stray newline literal `"\n"` in the `file_monitoring_proto_rawDesc` constant, which could cause protobuf descriptor parsing to fail at runtime. This is a critical fix for the generated code's integrity. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>✅ <s>Fix race condition on config</s></summary> ___ <details><summary><b>Suggestion Impact:</b></summary>The commit adds s.configMu.RLock()/RUnlock() around the read of s.config.Sources[sourceName] in applySourceBlacklist, addressing the identified race condition. It also adds a write lock in the config update path, further reducing concurrent access issues. code diff: ```diff + s.configMu.Lock() + defer s.configMu.Unlock() + // Check interval changes newDisc := time.Duration(newCfg.DiscoveryInterval) newUpd := time.Duration(newCfg.UpdateInterval) @@ -385,6 +389,7 @@ select { case s.reloadChan <- struct{}{}: default: + s.logger.Debug().Msg("Reload channel full; skipping reload trigger") } } s.config = *newCfg @@ -1491,7 +1496,10 @@ sourceName string, devices []*models.DeviceUpdate, ) (filteredDevices []*models.DeviceUpdate) { + s.configMu.RLock() sourceConfig := s.config.Sources[sourceName] + s.configMu.RUnlock() + if sourceConfig == nil || len(sourceConfig.NetworkBlacklist) == 0 { return devices } ``` </details> ___ **Add a read lock in <code>applySourceBlacklist</code> when accessing <code>s.config.Sources</code> to <br>prevent a potential race condition with concurrent configuration updates.** [pkg/sync/service.go [1490-1516]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7eR1490-R1516) ```diff func (s *SimpleSyncService) applySourceBlacklist( sourceName string, devices []*models.DeviceUpdate, -- kvData map[string][]byte) (filteredDevices []*models.DeviceUpdate, filteredKVData map[string][]byte) { -+) (filteredDevices []*models.DeviceUpdate) { +) (filteredDevices []*models.DeviceUpdate) { + s.configMu.RLock() sourceConfig := s.config.Sources[sourceName] + s.configMu.RUnlock() if sourceConfig == nil || len(sourceConfig.NetworkBlacklist) == 0 { -- return devices, kvData -+ return devices + return devices } networkBlacklist, err := NewNetworkBlacklist(sourceConfig.NetworkBlacklist, s.logger) if err != nil { s.logger.Error().Err(err).Str("source", sourceName).Msg("Failed to create network blacklist for source") -- return devices, kvData -+ return devices + return devices } originalCount := len(devices) filteredDevices = networkBlacklist.FilterDevices(devices) if filteredCount := originalCount - len(filteredDevices); filteredCount > 0 { s.logger.Info(). Str("source", sourceName). Int("filtered_count", filteredCount). Int("remaining_count", len(filteredDevices)). Msg("Applied source-specific network blacklist filtering to devices") } -- -- // Also filter KV data to remove blacklisted entries -- originalKVCount := len(kvData) -- filteredKVData = networkBlacklist.FilterKVData(kvData, filteredDevices) -- -- if kvFilteredCount := originalKVCount - len(filteredKVData); kvFilteredCount > 0 { -- s.logger.Info(). -- Str("source", sourceName). -- Int("filtered_count", kvFilteredCount). -- Int("remaining_count", len(filteredKVData)). -- Msg("Applied source-specific network blacklist filtering to KV data") -- } -- -- return filteredDevices, filteredKVData -+ return filteredDevices + return filteredDevices } ``` <details><summary>Suggestion importance[1-10]: 8</summary> __ Why: The suggestion correctly identifies a race condition where `s.config.Sources` is read without a lock, while it can be modified concurrently by `UpdateConfig`. The proposed fix of using `s.configMu.RLock()` is accurate and prevents this potential data race. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>✅ <s>Prevent race condition during configuration update</s></summary> ___ <details><summary><b>Suggestion Impact:</b></summary>The commit updated applyConfigPayload to take a read lock on s.config, clone it, then release the lock before mutating the cloned config—matching the suggested approach to avoid data races during concurrent config access. code diff: ```diff @@ -835,7 +852,11 @@ sources = map[string]*models.SourceConfig{} } - updatedCfg := s.config + // Clone config under read lock to prevent race with concurrent updates + s.configMu.RLock() + updatedCfg := s.config.Clone() + s.configMu.RUnlock() + if payload.AgentID != "" { updatedCfg.AgentID = payload.AgentID } ``` </details> ___ **In <code>applyConfigPayload</code>, create a deep copy of <code>s.config</code> under a lock before <br>modifying it to prevent race conditions with other goroutines.** [pkg/sync/service.go [828-858]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7eR828-R858) ```diff func (s *SimpleSyncService) applyConfigPayload(payload *gatewaySyncPayload, configVersion string) { if payload == nil { return } sources := payload.Sources if sources == nil { sources = map[string]*models.SourceConfig{} } - updatedCfg := s.config + s.configMu.RLock() + updatedCfg := s.config.Clone() + s.configMu.RUnlock() + if payload.AgentID != "" { updatedCfg.AgentID = payload.AgentID } if payload.TenantID != "" { updatedCfg.TenantID = payload.TenantID } updatedCfg.Sources = sources scope := payload.Scope if scope == "" { scope = "tenant" } s.UpdateConfig(&updatedCfg) s.setTenantSources(sources, scope) if configVersion != "" { s.setConfigVersion(configVersion) } } ``` <details><summary>Suggestion importance[1-10]: 8</summary> __ Why: The suggestion correctly identifies a race condition where `s.config` is read and modified without a lock. The proposed solution to create a copy of the config under a read lock before modification is a correct and safe way to handle concurrent access. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Safely handle API response types</summary> ___ **Add checks for type assertions when parsing the API response for tenants to <br>handle unexpected data types gracefully by displaying 'N/A' for invalid fields.** [pkg/cli/nats_bootstrap.go [951-957]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-2176d03ba6ab4ccc1b0587a4727171546eecf6123e4df815ead583aaab062457R951-R957) ```diff for _, t := range tenants { - tenantID, _ := t["id"].(string) - slug, _ := t["slug"].(string) - status, _ := t["nats_account_status"].(string) - accountKey, _ := t["nats_account_public_key"].(string) + tenantID, ok := t["id"].(string) + if !ok { + tenantID = "N/A" + } + slug, ok := t["slug"].(string) + if !ok { + slug = "N/A" + } + status, ok := t["nats_account_status"].(string) + if !ok { + status = "N/A" + } + accountKey, ok := t["nats_account_public_key"].(string) + if !ok { + accountKey = "N/A" + } fmt.Printf("%-36s %-20s %-15s %s\n", tenantID, slug, status, accountKey) } ``` <details><summary>Suggestion importance[1-10]: 6</summary> __ Why: The suggestion correctly identifies that unchecked type assertions on API response data can lead to confusing output if the data types are unexpected, and the proposed change makes the output more robust and user-friendly. </details></details></td><td align=center>Low </td></tr><tr><td rowspan=1>High-level</td> <td> <details><summary>Use the official NATS <code>nsc</code> tool</summary> ___ **Instead of building a custom service and CLI for NATS account management, use <br>the official NATS <code>nsc</code> tool. This would simplify the architecture and reduce <br>maintenance.** ### Examples: <details> <summary> <a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-49eb93c28e2d86d8dcf4ee78fd24bed498cf3fcfaa8e49849a36e70980420087R1-R1266">proto/nats_account.pb.go [1-1266]</a> </summary></details> <details> <summary> <a href="https://github.com/carverauto/serviceradar/pull/2226/files#diff-2176d03ba6ab4ccc1b0587a4727171546eecf6123e4df815ead583aaab062457R1-R961">pkg/cli/nats_bootstrap.go [1-961]</a> </summary></details> ### Solution Walkthrough: #### Before: ```go // pkg/cli/nats_bootstrap.go func RunNatsBootstrap(cfg *CmdConfig) error { // ... logic to call a custom gRPC service ... } // proto/nats_account.pb.go service NATSAccountService { rpc BootstrapOperator(...) returns (...); rpc CreateTenantAccount(...) returns (...); rpc GenerateUserCredentials(...) returns (...); // ... other RPCs for JWT management } // pkg/nats/accounts/service.go (inferred) // Implements the NATSAccountService gRPC service, // using NATS Go libraries to create keys, // sign JWTs, and manage accounts. ``` #### After: ```go // Control Plane Service (e.g., for tenant onboarding) func createNatsAccountForTenant(tenantSlug string) error { // Execute the official 'nsc' command-line tool // to create and manage NATS accounts and users. // This replaces the custom gRPC service. // 1. Add account cmd := exec.Command("nsc", "add", "account", "--name", tenantSlug) if err := cmd.Run(); err != nil { return err } // 2. Add user cmd = exec.Command("nsc", "add", "user", "--name", "user1", "--account", tenantSlug) if err := cmd.Run(); err != nil { return err } // 3. Generate user credentials // ... and so on for other management tasks. } ``` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion raises a valid, high-impact architectural point about reinventing NATS account management instead of using the official `nsc` tool, which could simplify the codebase and reduce maintenance. </details></details></td><td align=center>Medium </td></tr><tr><td rowspan=4>General</td> <td> <details><summary>✅ <s>Fix context cancellation handling<!-- not_implemented --></s></summary> ___ <details><summary><b>Suggestion Impact:</b></summary>The commit removed the `case <-s.ctx.Done(): return s.ctx.Err()` branch from `configPollLoop`, so the loop now only exits on the passed-in `ctx.Done()`. The same redundant `s.ctx.Done()` cancellation branch was also removed from another similar poll loop (heartbeat), extending the same idea beyond the original suggestion. code diff: ```diff @@ -956,8 +981,6 @@ select { case <-ctx.Done(): return ctx.Err() - case <-s.ctx.Done(): - return s.ctx.Err() case <-timer.C: if err := s.fetchAndApplyConfig(ctx); err != nil { if errors.Is(err, errGatewayNotEnrolled) { @@ -983,8 +1006,6 @@ select { case <-ctx.Done(): return ctx.Err() - case <-s.ctx.Done(): - return s.ctx.Err() case <-timer.C: ``` </details> ___ **In <code>configPollLoop</code>, remove the check for <code>s.ctx.Done()</code> and only listen for <br>cancellation on the <code>ctx</code> argument passed to the function.** [pkg/sync/service.go [951-972]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7eR951-R972) ```diff func (s *SimpleSyncService) configPollLoop(ctx context.Context) error { timer := time.NewTimer(s.getConfigPollInterval()) defer timer.Stop() for { select { case <-ctx.Done(): return ctx.Err() - case <-s.ctx.Done(): - return s.ctx.Err() case <-timer.C: … } } } ``` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly points out that listening to both the local `ctx` and the service-wide `s.ctx` is redundant and potentially confusing. The function should only respect the context passed to it, making the cancellation behavior clearer and more conventional. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Validate output format flag</summary> ___ **Add validation to ensure the <code>--output</code> flag is either 'text' or 'json', returning <br>an error for invalid values.** [pkg/cli/nats_bootstrap.go [106]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-2176d03ba6ab4ccc1b0587a4727171546eecf6123e4df815ead583aaab062457R106-R106) ```diff cfg.NATSOutputFormat = strings.ToLower(strings.TrimSpace(*output)) +if cfg.NATSOutputFormat != "text" && cfg.NATSOutputFormat != "json" { + return fmt.Errorf("invalid output format %q, must be 'text' or 'json'", cfg.NATSOutputFormat) +} ``` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly points out that the `--output` flag value is not validated, which could lead to silent failures. Adding explicit validation improves the command's robustness and provides clear feedback to the user for invalid input. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Prevent conflicting mode flags</summary> ___ **Add a check to prevent the mutually exclusive flags <code>--verify</code> and <code>--local</code> from <br>being used together.** [pkg/cli/nats_bootstrap.go [79-81]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-2176d03ba6ab4ccc1b0587a4727171546eecf6123e4df815ead583aaab062457R79-R81) ```diff if err := fs.Parse(args); err != nil { return fmt.Errorf("parsing nats-bootstrap flags: %w", err) } +if *verify && *local { + return fmt.Errorf("cannot specify both --verify and --local") +} ``` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly identifies that `--verify` and `--local` represent mutually exclusive modes of operation. Adding a check to prevent their simultaneous use improves the CLI's robustness and provides clearer error messaging to the user. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>✅ <s>Remove stale checks on update</s></summary> ___ <details><summary><b>Suggestion Impact:</b></summary>The previously commented-out stale-check removal loop in applyChecks was enabled and updated with new comments asserting the gateway config as source of truth, so stale checks are now deleted when not seen in the gateway config. code diff: ```diff - // Optionally: remove checks that are no longer in the config - // (commented out for now - may want to keep local file-based checks) - // for name := range p.server.checkerConfs { - // if !seenChecks[name] { - // delete(p.server.checkerConfs, name) - // p.logger.Info().Str("name", name).Msg("Removed stale check") - // } - // } + // Remove checks that are no longer in the gateway config. + // Gateway config is the source of truth for all checker configurations. + for name := range p.server.checkerConfs { + if !seenChecks[name] { + delete(p.server.checkerConfs, name) + p.logger.Info().Str("name", name).Msg("Removed stale check") + } + } ``` </details> ___ **Enable the removal of stale checker configurations by uncommenting the relevant <br>code block in <code>applyChecks</code>.** [pkg/agent/push_loop.go [765-772]](https://github.com/carverauto/serviceradar/pull/2226/files#diff-5f0d59be34ef26b449d7f5fd2b198a29b277936b9708a699f7487415ed6c2785R765-R772) ```diff -// Optionally: remove checks that are no longer in the config -// (commented out for now - may want to keep local file-based checks) -// for name := range p.server.checkerConfs { -// if !seenChecks[name] { -// delete(p.server.checkerConfs, name) -// p.logger.Info().Str("name", name).Msg("Removed stale check") -// } -// } +for name := range p.server.checkerConfs { + if !seenChecks[name] { + delete(p.server.checkerConfs, name) + p.logger.Info().Str("name", name).Msg("Removed stale check") + } +} ``` <details><summary>Suggestion importance[1-10]: 5</summary> __ Why: The suggestion proposes enabling a commented-out feature to remove stale checks. While this is a reasonable feature enhancement for configuration management, the original code intentionally left it disabled to preserve local checks, so this change alters intended behavior. </details></details></td><td align=center>Low </td></tr> <tr><td align="center" colspan="2"> <!-- /improve_multi --more_suggestions=true --> </td><td></td></tr></tbody></table> </details>
qodo-code-review[bot] commented 2026-01-06 21:50:29 +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/2226#issuecomment-3716494125
Original created: 2026-01-06T21:50:29Z

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: test-rust (rust/srql)

Failed stage: Run Tests []

Failed test name: srql_api_queries

Failure summary:

  • The GitHub Action failed because the Rust integration test srql_api_queries failed (exit code 101
    from cargo test --test api).
  • The test panicked in rust/srql/tests/support/harness.rs:74:10 while trying to acquire a remote
    fixture lock, due to a database connection error.
  • Postgres rejected the connection with: FATAL: pg_hba.conf rejects connection for host
    "10.42.221.65", user "srql_hydra", database "postgres", no encryption, indicating the CI runner
    host/IP or TLS/SSL mode is not allowed by the server’s pg_hba.conf rules (connection attempted with
    no encryption).
Relevant error logs:
1:  Runner name: 'arc-runner-set-2tp2m-runner-m2f4n'
2:  Runner group name: 'Default'
...

126:  ^[[36;1mif command -v apt-get >/dev/null 2>&1; then^[[0m
127:  ^[[36;1m  sudo apt-get update^[[0m
128:  ^[[36;1m  sudo apt-get install -y build-essential pkg-config libssl-dev protobuf-compiler cmake flex bison^[[0m
129:  ^[[36;1melif command -v dnf >/dev/null 2>&1; then^[[0m
130:  ^[[36;1m  sudo dnf install -y gcc gcc-c++ make openssl-devel protobuf-compiler cmake flex bison^[[0m
131:  ^[[36;1melif command -v yum >/dev/null 2>&1; then^[[0m
132:  ^[[36;1m  sudo yum install -y gcc gcc-c++ make openssl-devel protobuf-compiler cmake flex bison^[[0m
133:  ^[[36;1melif command -v microdnf >/dev/null 2>&1; then^[[0m
134:  ^[[36;1m  sudo microdnf install -y gcc gcc-c++ make openssl-devel protobuf-compiler cmake flex bison^[[0m
135:  ^[[36;1melse^[[0m
136:  ^[[36;1m  echo "Unsupported package manager; please install gcc, g++ (or clang), make, OpenSSL headers, pkg-config, and protoc manually." >&2^[[0m
137:  ^[[36;1m  exit 1^[[0m
138:  ^[[36;1mfi^[[0m
139:  ^[[36;1m^[[0m
140:  ^[[36;1mensure_pkg_config^[[0m
141:  ^[[36;1mprotoc --version || (echo "protoc installation failed" && exit 1)^[[0m
142:  shell: /usr/bin/bash -e {0}
...

181:  libprotoc 3.12.4
182:  ##[group]Run bazelbuild/setup-bazelisk@v3
183:  with:
184:  bazelisk-version: 1.x
185:  token: ***
186:  env:
187:  BUILDBUDDY_ORG_API_KEY: ***
188:  SRQL_TEST_DATABASE_URL: ***
189:  SRQL_TEST_ADMIN_URL: ***
190:  ##[endgroup]
191:  Attempting to download 1.x...
192:  Acquiring v1.27.0 from https://github.com/bazelbuild/bazelisk/releases/download/v1.27.0/bazelisk-linux-amd64
193:  Adding to the cache ...
194:  Successfully cached bazelisk to /home/runner/_work/_tool/bazelisk/1.27.0/x64
195:  Added bazelisk to the path
196:  ##[warning]Failed to restore: Cache service responded with 400
197:  Restored bazelisk cache dir @ /home/runner/.cache/bazelisk
...

253:  targets: 
254:  components: clippy
255:  ##[endgroup]
256:  ##[group]Run : set $CARGO_HOME
257:  ^[[36;1m: set $CARGO_HOME^[[0m
258:  ^[[36;1mecho CARGO_HOME=${CARGO_HOME:-"$HOME/.cargo"} >> $GITHUB_ENV^[[0m
259:  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
260:  env:
261:  BUILDBUDDY_ORG_API_KEY: ***
262:  SRQL_TEST_DATABASE_URL: ***
263:  SRQL_TEST_ADMIN_URL: ***
264:  ##[endgroup]
265:  ##[group]Run : install rustup if needed
266:  ^[[36;1m: install rustup if needed^[[0m
267:  ^[[36;1mif ! command -v rustup &>/dev/null; then^[[0m
268:  ^[[36;1m  curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused --location --silent --show-error --fail https://sh.rustup.rs | sh -s -- --default-toolchain none -y^[[0m
269:  ^[[36;1m  echo "$CARGO_HOME/bin" >> $GITHUB_PATH^[[0m
...

369:  ^[[36;1m    echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse >> $GITHUB_ENV^[[0m
370:  ^[[36;1m  elif rustc +stable --version --verbose | grep -q '^release: 1\.6[67]\.'; then^[[0m
371:  ^[[36;1m    touch "/home/runner/_work/_temp"/.implicit_cargo_registries_crates_io_protocol || true^[[0m
372:  ^[[36;1m    echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=git >> $GITHUB_ENV^[[0m
373:  ^[[36;1m  fi^[[0m
374:  ^[[36;1mfi^[[0m
375:  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
376:  env:
377:  BUILDBUDDY_ORG_API_KEY: ***
378:  SRQL_TEST_DATABASE_URL: ***
379:  SRQL_TEST_ADMIN_URL: ***
380:  CARGO_HOME: /home/runner/.cargo
381:  CARGO_INCREMENTAL: 0
382:  CARGO_TERM_COLOR: always
383:  ##[endgroup]
384:  ##[group]Run : work around spurious network errors in curl 8.0
385:  ^[[36;1m: work around spurious network errors in curl 8.0^[[0m
386:  ^[[36;1m# https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/timeout.20investigation^[[0m
...

532:  ^[[1m^[[92m  Downloaded^[[0m tower v0.4.13
533:  ^[[1m^[[92m  Downloaded^[[0m serde_json v1.0.145
534:  ^[[1m^[[92m  Downloaded^[[0m rustls-webpki v0.101.7
535:  ^[[1m^[[92m  Downloaded^[[0m chrono v0.4.42
536:  ^[[1m^[[92m  Downloaded^[[0m typenum v1.19.0
537:  ^[[1m^[[92m  Downloaded^[[0m toml_edit v0.22.27
538:  ^[[1m^[[92m  Downloaded^[[0m tokio-postgres v0.7.15
539:  ^[[1m^[[92m  Downloaded^[[0m socket2 v0.5.10
540:  ^[[1m^[[92m  Downloaded^[[0m regex v1.12.2
541:  ^[[1m^[[92m  Downloaded^[[0m tokio v1.48.0
542:  ^[[1m^[[92m  Downloaded^[[0m uuid v0.8.2
543:  ^[[1m^[[92m  Downloaded^[[0m unicode-properties v0.1.4
544:  ^[[1m^[[92m  Downloaded^[[0m unicode-bidi v0.3.18
545:  ^[[1m^[[92m  Downloaded^[[0m tracing-log v0.2.0
546:  ^[[1m^[[92m  Downloaded^[[0m tracing-attributes v0.1.30
547:  ^[[1m^[[92m  Downloaded^[[0m thiserror-impl v1.0.69
548:  ^[[1m^[[92m  Downloaded^[[0m spiffe v0.6.7
549:  ^[[1m^[[92m  Downloaded^[[0m socket2 v0.6.1
550:  ^[[1m^[[92m  Downloaded^[[0m smallvec v1.15.1
551:  ^[[1m^[[92m  Downloaded^[[0m sharded-slab v0.1.7
552:  ^[[1m^[[92m  Downloaded^[[0m pulldown-cmark v0.13.0
553:  ^[[1m^[[92m  Downloaded^[[0m unicase v2.8.1
554:  ^[[1m^[[92m  Downloaded^[[0m toml v0.8.23
555:  ^[[1m^[[92m  Downloaded^[[0m tokio-stream v0.1.17
556:  ^[[1m^[[92m  Downloaded^[[0m tinyvec v1.10.0
557:  ^[[1m^[[92m  Downloaded^[[0m time-macros v0.2.24
558:  ^[[1m^[[92m  Downloaded^[[0m thread_local v1.1.9
559:  ^[[1m^[[92m  Downloaded^[[0m thiserror-impl v2.0.17
560:  ^[[1m^[[92m  Downloaded^[[0m thiserror v2.0.17
561:  ^[[1m^[[92m  Downloaded^[[0m thiserror v1.0.69
562:  ^[[1m^[[92m  Downloaded^[[0m tempfile v3.23.0
...

573:  ^[[1m^[[92m  Downloaded^[[0m rustls-webpki v0.103.8
574:  ^[[1m^[[92m  Downloaded^[[0m ring v0.17.14
575:  ^[[1m^[[92m  Downloaded^[[0m zeroize_derive v1.4.2
576:  ^[[1m^[[92m  Downloaded^[[0m logos v0.15.1
577:  ^[[1m^[[92m  Downloaded^[[0m zeroize v1.8.2
578:  ^[[1m^[[92m  Downloaded^[[0m yoke-derive v0.8.1
579:  ^[[1m^[[92m  Downloaded^[[0m yoke v0.8.1
580:  ^[[1m^[[92m  Downloaded^[[0m whoami v1.6.1
581:  ^[[1m^[[92m  Downloaded^[[0m want v0.3.1
582:  ^[[1m^[[92m  Downloaded^[[0m time-core v0.1.6
583:  ^[[1m^[[92m  Downloaded^[[0m sync_wrapper v1.0.2
584:  ^[[1m^[[92m  Downloaded^[[0m subtle v2.6.1
585:  ^[[1m^[[92m  Downloaded^[[0m strsim v0.11.1
586:  ^[[1m^[[92m  Downloaded^[[0m stable_deref_trait v1.2.1
587:  ^[[1m^[[92m  Downloaded^[[0m slab v0.4.11
588:  ^[[1m^[[92m  Downloaded^[[0m serde_path_to_error v0.1.20
589:  ^[[1m^[[92m  Downloaded^[[0m schemars v0.9.0
...

771:  ^[[1m^[[92m   Compiling^[[0m parking_lot_core v0.9.12
772:  ^[[1m^[[92m    Checking^[[0m scopeguard v1.2.0
773:  ^[[1m^[[92m    Checking^[[0m log v0.4.28
774:  ^[[1m^[[92m    Checking^[[0m once_cell v1.21.3
775:  ^[[1m^[[92m    Checking^[[0m futures-sink v0.3.31
776:  ^[[1m^[[92m    Checking^[[0m memchr v2.7.6
777:  ^[[1m^[[92m   Compiling^[[0m autocfg v1.5.0
778:  ^[[1m^[[92m    Checking^[[0m pin-utils v0.1.0
779:  ^[[1m^[[92m   Compiling^[[0m fnv v1.0.7
780:  ^[[1m^[[92m    Checking^[[0m futures-task v0.3.31
781:  ^[[1m^[[92m   Compiling^[[0m serde v1.0.228
782:  ^[[1m^[[92m   Compiling^[[0m regex-syntax v0.8.8
783:  ^[[1m^[[92m    Checking^[[0m equivalent v1.0.2
784:  ^[[1m^[[92m    Checking^[[0m stable_deref_trait v1.2.1
785:  ^[[1m^[[92m    Checking^[[0m hashbrown v0.16.0
786:  ^[[1m^[[92m   Compiling^[[0m thiserror v2.0.17
787:  ^[[1m^[[92m   Compiling^[[0m zerocopy v0.8.27
...

858:  ^[[1m^[[92m   Compiling^[[0m rustls v0.23.35
859:  ^[[1m^[[92m    Checking^[[0m cpufeatures v0.2.17
860:  ^[[1m^[[92m   Compiling^[[0m ring v0.17.14
861:  ^[[1m^[[92m    Checking^[[0m nom v7.1.3
862:  ^[[1m^[[92m   Compiling^[[0m pq-src v0.3.10+libpq-18.0
863:  ^[[1m^[[92m   Compiling^[[0m indexmap v1.9.3
864:  ^[[1m^[[92m    Checking^[[0m matchit v0.8.4
865:  ^[[1m^[[92m    Checking^[[0m siphasher v1.0.1
866:  ^[[1m^[[92m    Checking^[[0m fallible-iterator v0.2.0
867:  ^[[1m^[[92m   Compiling^[[0m oid-registry v0.8.1
868:  ^[[1m^[[92m   Compiling^[[0m pq-sys v0.7.5
869:  ^[[1m^[[92m   Compiling^[[0m diesel_derives v2.3.4
870:  ^[[1m^[[92m    Checking^[[0m utf8_iter v1.0.4
871:  ^[[1m^[[92m    Checking^[[0m hashbrown v0.12.3
872:  ^[[1m^[[92m    Checking^[[0m http-body v1.0.1
873:  ^[[1m^[[92m    Checking^[[0m serde_path_to_error v0.1.20
874:  ^[[1m^[[92m    Checking^[[0m pem v3.0.6
875:  ^[[1m^[[92m    Checking^[[0m whoami v1.6.1
876:  ^[[1m^[[92m    Checking^[[0m unicode-normalization v0.1.25
877:  ^[[1m^[[92m    Checking^[[0m http-body-util v0.1.3
878:  ^[[1m^[[92m    Checking^[[0m phf_shared v0.13.1
879:  ^[[1m^[[92m   Compiling^[[0m rustls v0.21.12
880:  ^[[1m^[[92m    Checking^[[0m winnow v0.7.13
881:  ^[[1m^[[92m   Compiling^[[0m thiserror v1.0.69
882:  ^[[1m^[[92m    Checking^[[0m toml_write v0.1.2
...

921:  ^[[1m^[[92m    Checking^[[0m rand v0.8.5
922:  ^[[1m^[[92m    Checking^[[0m postgres-protocol v0.6.9
923:  ^[[1m^[[92m   Compiling^[[0m pulldown-cmark-to-cmark v21.0.0
924:  ^[[1m^[[92m    Checking^[[0m matchers v0.2.0
925:  ^[[1m^[[92m    Checking^[[0m postgres-types v0.2.11
926:  ^[[1m^[[92m    Checking^[[0m sct v0.7.1
927:  ^[[1m^[[92m    Checking^[[0m rustls-webpki v0.101.7
928:  ^[[1m^[[92m   Compiling^[[0m synstructure v0.13.2
929:  ^[[1m^[[92m   Compiling^[[0m darling_core v0.21.3
930:  ^[[1m^[[92m   Compiling^[[0m diesel_table_macro_syntax v0.3.0
931:  ^[[1m^[[92m   Compiling^[[0m tokio-macros v2.6.0
932:  ^[[1m^[[92m   Compiling^[[0m serde_derive v1.0.228
933:  ^[[1m^[[92m   Compiling^[[0m tracing-attributes v0.1.30
934:  ^[[1m^[[92m   Compiling^[[0m displaydoc v0.2.5
935:  ^[[1m^[[92m   Compiling^[[0m prost-derive v0.14.1
936:  ^[[1m^[[92m   Compiling^[[0m thiserror-impl v2.0.17
937:  ^[[1m^[[92m   Compiling^[[0m zerovec-derive v0.11.2
938:  ^[[1m^[[92m   Compiling^[[0m async-trait v0.1.89
939:  ^[[1m^[[92m   Compiling^[[0m zeroize_derive v1.4.2
940:  ^[[1m^[[92m   Compiling^[[0m prost-derive v0.13.5
941:  ^[[1m^[[92m   Compiling^[[0m miette-derive v7.6.0
942:  ^[[1m^[[92m   Compiling^[[0m pin-project-internal v1.1.10
943:  ^[[1m^[[92m   Compiling^[[0m der_derive v0.7.3
944:  ^[[1m^[[92m   Compiling^[[0m asn1-rs-impl v0.2.0
945:  ^[[1m^[[92m   Compiling^[[0m axum-macros v0.4.2
946:  ^[[1m^[[92m   Compiling^[[0m async-stream-impl v0.3.6
947:  ^[[1m^[[92m   Compiling^[[0m thiserror-impl v1.0.69
948:  ^[[1m^[[92m   Compiling^[[0m tonic-build v0.14.2
...

1075:  ^[[1m^[[92m   Compiling^[[0m futures-task v0.3.31
1076:  ^[[1m^[[92m   Compiling^[[0m futures-io v0.3.31
1077:  ^[[1m^[[92m   Compiling^[[0m stable_deref_trait v1.2.1
1078:  ^[[1m^[[92m   Compiling^[[0m libc v0.2.177
1079:  ^[[1m^[[92m   Compiling^[[0m serde_core v1.0.228
1080:  ^[[1m^[[92m   Compiling^[[0m anyhow v1.0.100
1081:  ^[[1m^[[92m   Compiling^[[0m tower-service v0.3.3
1082:  ^[[1m^[[92m   Compiling^[[0m zerocopy v0.8.27
1083:  ^[[1m^[[92m   Compiling^[[0m lazy_static v1.5.0
1084:  ^[[1m^[[92m   Compiling^[[0m lock_api v0.4.14
1085:  ^[[1m^[[92m   Compiling^[[0m num-traits v0.2.19
1086:  ^[[1m^[[92m   Compiling^[[0m percent-encoding v2.3.2
1087:  ^[[1m^[[92m   Compiling^[[0m subtle v2.6.1
1088:  ^[[1m^[[92m   Compiling^[[0m typenum v1.19.0
1089:  ^[[1m^[[92m   Compiling^[[0m futures-channel v0.3.31
1090:  ^[[1m^[[92m   Compiling^[[0m thiserror v2.0.17
1091:  ^[[1m^[[92m   Compiling^[[0m tower-layer v0.3.3
...

1154:  ^[[1m^[[92m   Compiling^[[0m data-encoding v2.9.0
1155:  ^[[1m^[[92m   Compiling^[[0m iana-time-zone v0.1.64
1156:  ^[[1m^[[92m   Compiling^[[0m phf v0.13.1
1157:  ^[[1m^[[92m   Compiling^[[0m matchit v0.7.3
1158:  ^[[1m^[[92m   Compiling^[[0m toml_write v0.1.2
1159:  ^[[1m^[[92m   Compiling^[[0m bitflags v2.10.0
1160:  ^[[1m^[[92m   Compiling^[[0m winnow v0.7.13
1161:  ^[[1m^[[92m   Compiling^[[0m tinystr v0.8.2
1162:  ^[[1m^[[92m   Compiling^[[0m potential_utf v0.1.4
1163:  ^[[1m^[[92m   Compiling^[[0m indexmap v1.9.3
1164:  ^[[1m^[[92m   Compiling^[[0m async-stream v0.3.6
1165:  ^[[1m^[[92m   Compiling^[[0m rustls-pemfile v2.2.0
1166:  ^[[1m^[[92m   Compiling^[[0m icu_collections v2.1.1
1167:  ^[[1m^[[92m   Compiling^[[0m num-bigint v0.4.6
1168:  ^[[1m^[[92m   Compiling^[[0m downcast-rs v2.0.2
1169:  ^[[1m^[[92m   Compiling^[[0m thiserror v1.0.69
1170:  ^[[1m^[[92m   Compiling^[[0m tracing-log v0.2.0
...

1216:  ^[[1m^[[92m   Compiling^[[0m rusticata-macros v4.1.0
1217:  ^[[1m^[[92m   Compiling^[[0m rand_chacha v0.9.0
1218:  ^[[1m^[[92m   Compiling^[[0m rand_chacha v0.3.1
1219:  ^[[1m^[[92m   Compiling^[[0m icu_normalizer v2.1.1
1220:  ^[[1m^[[92m   Compiling^[[0m icu_properties v2.1.1
1221:  ^[[1m^[[92m   Compiling^[[0m spki v0.7.3
1222:  ^[[1m^[[92m   Compiling^[[0m pkcs8 v0.10.2
1223:  ^[[1m^[[92m   Compiling^[[0m x509-cert v0.2.5
1224:  ^[[1m^[[92m   Compiling^[[0m prost-types v0.14.1
1225:  ^[[1m^[[92m   Compiling^[[0m prost-types v0.13.5
1226:  ^[[1m^[[92m   Compiling^[[0m darling_macro v0.21.3
1227:  ^[[1m^[[92m   Compiling^[[0m rand v0.9.2
1228:  ^[[1m^[[92m   Compiling^[[0m rand v0.8.5
1229:  ^[[1m^[[92m   Compiling^[[0m serde v1.0.228
1230:  ^[[1m^[[92m   Compiling^[[0m serde_json v1.0.145
1231:  ^[[1m^[[92m   Compiling^[[0m serde_path_to_error v0.1.20
1232:  ^[[1m^[[92m   Compiling^[[0m darling v0.21.3
...

1305:  test parser::tests::parses_lists ... ok
1306:  test parser::tests::parses_list_values ... ok
1307:  test parser::tests::parses_interfaces_entity ... ok
1308:  test parser::tests::parses_basic_query ... ok
1309:  test parser::tests::parses_rollup_stats_keyword ... ok
1310:  test parser::tests::parses_rollup_stats_with_filters ... ok
1311:  test parser::tests::parses_stats_expression ... ok
1312:  test parser::tests::parses_time ... ok
1313:  test parser::tests::parses_unquoted_stats_alias ... ok
1314:  test parser::tests::rejects_empty_rollup_stats ... ok
1315:  test parser::tests::parses_unquoted_stats_alias_with_following_tokens ... ok
1316:  test parser::tests::rejects_stats_alias_missing_identifier ... ok
1317:  test parser::tests::rejects_overly_long_stats_expression ... ok
1318:  test query::agents::tests::builds_query_with_gateway_filter ... ok
1319:  test query::agents::tests::builds_query_with_type_id_filter ... ok
1320:  test query::agents::tests::unknown_filter_field_returns_error ... ok
1321:  test query::cpu_metrics::tests::unknown_filter_field_returns_error ... ok
1322:  test parser::tests::rejects_list_filters_over_limit ... ok
1323:  test query::cpu_metrics::tests::stats_query_matches_cpu_language_reference ... ok
1324:  test query::gateways::tests::unknown_filter_field_returns_error ... ok
1325:  test query::logs::tests::rollup_stats_severity_builds_cagg_query ... ok
1326:  test query::logs::tests::rollup_stats_severity_with_service_filter ... ok
1327:  test query::interfaces::tests::stats_count_interfaces_emits_count_query ... ok
1328:  test query::disk_metrics::tests::unknown_filter_field_returns_error ... ok
1329:  test query::logs::tests::rollup_stats_unknown_type_returns_error ... ok
1330:  test query::logs::tests::stats_query_counts_logs_for_service ... ok
1331:  test query::logs::tests::unknown_stats_filter_field_returns_error ... ok
1332:  test query::logs::tests::unknown_filter_field_returns_error ... ok
1333:  test query::otel_metrics::tests::unknown_filter_field_returns_error ... ok
1334:  test query::memory_metrics::tests::unknown_filter_field_returns_error ... ok
1335:  test query::process_metrics::tests::unknown_filter_field_returns_error ... ok
1336:  test query::services::tests::unknown_filter_field_returns_error ... ok
1337:  ^[[1m^[[92m     Running^[[0m unittests src/main.rs (/home/runner/_work/serviceradar/serviceradar/target/debug/deps/srql-ef0fb1a8aa7439b4)
1338:  test query::tests::devices_docs_example_available_true ... ok
1339:  test query::tests::translate_graph_cypher_rejects_mutations ... ok
1340:  test query::tests::translate_downsample_emits_time_bucket_query ... ok
1341:  test query::tests::gateways_docs_example_health_and_status ... ok
1342:  test query::timeseries_metrics::tests::unknown_filter_field_returns_error ... ok
1343:  test query::tests::devices_docs_example_available_false ... ok
1344:  test time::tests::parses_absolute_range ... ok
1345:  test query::traces::tests::unknown_filter_field_returns_error ... ok
1346:  test time::tests::parses_open_end_absolute_range ... ok
1347:  test time::tests::parses_relative_days ... ok
1348:  test time::tests::parses_open_start_absolute_range ... ok
1349:  test time::tests::rejects_absolute_range_exceeding_limit ... ok
1350:  test time::tests::rejects_open_end_range_exceeding_limit ... ok
1351:  test query::tests::services_docs_example_service_type_timeframe ... ok
1352:  test query::tests::devices_docs_example_discovery_sources_contains_all ... ok
1353:  test query::tests::translate_graph_cypher_wraps_rows_as_topology_payload ... ok
1354:  test query::tests::translate_includes_visualization_metadata ... ok
1355:  test query::tests::translate_param_arity_matches_sql_placeholders ... ok
1356:  test query::tests::interfaces_docs_example_ip_addresses_contains_any ... ok
1357:  test result: ok. 54 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
1358:  ^[[1m^[[92m     Running^[[0m tests/api.rs (/home/runner/_work/serviceradar/serviceradar/target/debug/deps/api-b0a82ccb463a2c0a)
1359:  running 0 tests
1360:  test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
1361:  running 1 test
1362:  test srql_api_queries ... FAILED
1363:  failures:
1364:  ---- srql_api_queries stdout ----
1365:  [srql-test] SRQL_TEST_DATABASE_URL: user=srql db=srql_fixture hosts=["srql-fixture.serviceradar.cloud"] port=5432
1366:  [srql-test] SRQL_TEST_ADMIN_URL: user=srql_hydra db=postgres hosts=["srql-fixture.serviceradar.cloud"] port=5432
1367:  thread 'srql_api_queries' (9175) panicked at rust/srql/tests/support/harness.rs:74:10:
1368:  failed to acquire remote fixture lock: db error
1369:  Caused by:
1370:  FATAL: pg_hba.conf rejects connection for host "10.42.221.65", user "srql_hydra", database "postgres", no encryption
1371:  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
1372:  failures:
1373:  srql_api_queries
1374:  test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.13s
1375:  ^[[1m^[[91merror^[[0m: test failed, to rerun pass `--test api`
1376:  ##[error]Process completed with exit code 101.
1377:  Post job cleanup.

Imported GitHub PR comment. Original author: @qodo-code-review[bot] Original URL: https://github.com/carverauto/serviceradar/pull/2226#issuecomment-3716494125 Original created: 2026-01-06T21:50:29Z --- ## CI Feedback 🧐 A test triggered by this PR failed. Here is an AI-generated analysis of the failure: <table><tr><td> **Action:** test-rust (rust/srql)</td></tr> <tr><td> **Failed stage:** [Run Tests](https://github.com/carverauto/serviceradar/actions/runs/20763078324/job/59622724225) [❌] </td></tr> <tr><td> **Failed test name:** srql_api_queries </td></tr> <tr><td> **Failure summary:** <ul><li>The GitHub Action failed because the Rust integration test <code>srql_api_queries</code> failed (exit code 101 <br>from <code>cargo test --test api</code>).<br> <li> The test panicked in <code>rust/srql/tests/support/harness.rs:74:10</code> while trying to acquire a remote <br>fixture lock, due to a database connection error.<br> <li> Postgres rejected the connection with: <code>FATAL: pg_hba.conf rejects connection for host </code><br><code>"10.42.221.65", user "srql_hydra", database "postgres", no encryption</code>, indicating the CI runner <br>host/IP or TLS/SSL mode is not allowed by the server’s <code>pg_hba.conf</code> rules (connection attempted with <br><code>no encryption</code>).<br></ul> </td></tr> <tr><td> <details><summary>Relevant error logs:</summary> ```yaml 1: Runner name: 'arc-runner-set-2tp2m-runner-m2f4n' 2: Runner group name: 'Default' ... 126: ^[[36;1mif command -v apt-get >/dev/null 2>&1; then^[[0m 127: ^[[36;1m sudo apt-get update^[[0m 128: ^[[36;1m sudo apt-get install -y build-essential pkg-config libssl-dev protobuf-compiler cmake flex bison^[[0m 129: ^[[36;1melif command -v dnf >/dev/null 2>&1; then^[[0m 130: ^[[36;1m sudo dnf install -y gcc gcc-c++ make openssl-devel protobuf-compiler cmake flex bison^[[0m 131: ^[[36;1melif command -v yum >/dev/null 2>&1; then^[[0m 132: ^[[36;1m sudo yum install -y gcc gcc-c++ make openssl-devel protobuf-compiler cmake flex bison^[[0m 133: ^[[36;1melif command -v microdnf >/dev/null 2>&1; then^[[0m 134: ^[[36;1m sudo microdnf install -y gcc gcc-c++ make openssl-devel protobuf-compiler cmake flex bison^[[0m 135: ^[[36;1melse^[[0m 136: ^[[36;1m echo "Unsupported package manager; please install gcc, g++ (or clang), make, OpenSSL headers, pkg-config, and protoc manually." >&2^[[0m 137: ^[[36;1m exit 1^[[0m 138: ^[[36;1mfi^[[0m 139: ^[[36;1m^[[0m 140: ^[[36;1mensure_pkg_config^[[0m 141: ^[[36;1mprotoc --version || (echo "protoc installation failed" && exit 1)^[[0m 142: shell: /usr/bin/bash -e {0} ... 181: libprotoc 3.12.4 182: ##[group]Run bazelbuild/setup-bazelisk@v3 183: with: 184: bazelisk-version: 1.x 185: token: *** 186: env: 187: BUILDBUDDY_ORG_API_KEY: *** 188: SRQL_TEST_DATABASE_URL: *** 189: SRQL_TEST_ADMIN_URL: *** 190: ##[endgroup] 191: Attempting to download 1.x... 192: Acquiring v1.27.0 from https://github.com/bazelbuild/bazelisk/releases/download/v1.27.0/bazelisk-linux-amd64 193: Adding to the cache ... 194: Successfully cached bazelisk to /home/runner/_work/_tool/bazelisk/1.27.0/x64 195: Added bazelisk to the path 196: ##[warning]Failed to restore: Cache service responded with 400 197: Restored bazelisk cache dir @ /home/runner/.cache/bazelisk ... 253: targets: 254: components: clippy 255: ##[endgroup] 256: ##[group]Run : set $CARGO_HOME 257: ^[[36;1m: set $CARGO_HOME^[[0m 258: ^[[36;1mecho CARGO_HOME=${CARGO_HOME:-"$HOME/.cargo"} >> $GITHUB_ENV^[[0m 259: shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0} 260: env: 261: BUILDBUDDY_ORG_API_KEY: *** 262: SRQL_TEST_DATABASE_URL: *** 263: SRQL_TEST_ADMIN_URL: *** 264: ##[endgroup] 265: ##[group]Run : install rustup if needed 266: ^[[36;1m: install rustup if needed^[[0m 267: ^[[36;1mif ! command -v rustup &>/dev/null; then^[[0m 268: ^[[36;1m curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused --location --silent --show-error --fail https://sh.rustup.rs | sh -s -- --default-toolchain none -y^[[0m 269: ^[[36;1m echo "$CARGO_HOME/bin" >> $GITHUB_PATH^[[0m ... 369: ^[[36;1m echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse >> $GITHUB_ENV^[[0m 370: ^[[36;1m elif rustc +stable --version --verbose | grep -q '^release: 1\.6[67]\.'; then^[[0m 371: ^[[36;1m touch "/home/runner/_work/_temp"/.implicit_cargo_registries_crates_io_protocol || true^[[0m 372: ^[[36;1m echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=git >> $GITHUB_ENV^[[0m 373: ^[[36;1m fi^[[0m 374: ^[[36;1mfi^[[0m 375: shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0} 376: env: 377: BUILDBUDDY_ORG_API_KEY: *** 378: SRQL_TEST_DATABASE_URL: *** 379: SRQL_TEST_ADMIN_URL: *** 380: CARGO_HOME: /home/runner/.cargo 381: CARGO_INCREMENTAL: 0 382: CARGO_TERM_COLOR: always 383: ##[endgroup] 384: ##[group]Run : work around spurious network errors in curl 8.0 385: ^[[36;1m: work around spurious network errors in curl 8.0^[[0m 386: ^[[36;1m# https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/timeout.20investigation^[[0m ... 532: ^[[1m^[[92m Downloaded^[[0m tower v0.4.13 533: ^[[1m^[[92m Downloaded^[[0m serde_json v1.0.145 534: ^[[1m^[[92m Downloaded^[[0m rustls-webpki v0.101.7 535: ^[[1m^[[92m Downloaded^[[0m chrono v0.4.42 536: ^[[1m^[[92m Downloaded^[[0m typenum v1.19.0 537: ^[[1m^[[92m Downloaded^[[0m toml_edit v0.22.27 538: ^[[1m^[[92m Downloaded^[[0m tokio-postgres v0.7.15 539: ^[[1m^[[92m Downloaded^[[0m socket2 v0.5.10 540: ^[[1m^[[92m Downloaded^[[0m regex v1.12.2 541: ^[[1m^[[92m Downloaded^[[0m tokio v1.48.0 542: ^[[1m^[[92m Downloaded^[[0m uuid v0.8.2 543: ^[[1m^[[92m Downloaded^[[0m unicode-properties v0.1.4 544: ^[[1m^[[92m Downloaded^[[0m unicode-bidi v0.3.18 545: ^[[1m^[[92m Downloaded^[[0m tracing-log v0.2.0 546: ^[[1m^[[92m Downloaded^[[0m tracing-attributes v0.1.30 547: ^[[1m^[[92m Downloaded^[[0m thiserror-impl v1.0.69 548: ^[[1m^[[92m Downloaded^[[0m spiffe v0.6.7 549: ^[[1m^[[92m Downloaded^[[0m socket2 v0.6.1 550: ^[[1m^[[92m Downloaded^[[0m smallvec v1.15.1 551: ^[[1m^[[92m Downloaded^[[0m sharded-slab v0.1.7 552: ^[[1m^[[92m Downloaded^[[0m pulldown-cmark v0.13.0 553: ^[[1m^[[92m Downloaded^[[0m unicase v2.8.1 554: ^[[1m^[[92m Downloaded^[[0m toml v0.8.23 555: ^[[1m^[[92m Downloaded^[[0m tokio-stream v0.1.17 556: ^[[1m^[[92m Downloaded^[[0m tinyvec v1.10.0 557: ^[[1m^[[92m Downloaded^[[0m time-macros v0.2.24 558: ^[[1m^[[92m Downloaded^[[0m thread_local v1.1.9 559: ^[[1m^[[92m Downloaded^[[0m thiserror-impl v2.0.17 560: ^[[1m^[[92m Downloaded^[[0m thiserror v2.0.17 561: ^[[1m^[[92m Downloaded^[[0m thiserror v1.0.69 562: ^[[1m^[[92m Downloaded^[[0m tempfile v3.23.0 ... 573: ^[[1m^[[92m Downloaded^[[0m rustls-webpki v0.103.8 574: ^[[1m^[[92m Downloaded^[[0m ring v0.17.14 575: ^[[1m^[[92m Downloaded^[[0m zeroize_derive v1.4.2 576: ^[[1m^[[92m Downloaded^[[0m logos v0.15.1 577: ^[[1m^[[92m Downloaded^[[0m zeroize v1.8.2 578: ^[[1m^[[92m Downloaded^[[0m yoke-derive v0.8.1 579: ^[[1m^[[92m Downloaded^[[0m yoke v0.8.1 580: ^[[1m^[[92m Downloaded^[[0m whoami v1.6.1 581: ^[[1m^[[92m Downloaded^[[0m want v0.3.1 582: ^[[1m^[[92m Downloaded^[[0m time-core v0.1.6 583: ^[[1m^[[92m Downloaded^[[0m sync_wrapper v1.0.2 584: ^[[1m^[[92m Downloaded^[[0m subtle v2.6.1 585: ^[[1m^[[92m Downloaded^[[0m strsim v0.11.1 586: ^[[1m^[[92m Downloaded^[[0m stable_deref_trait v1.2.1 587: ^[[1m^[[92m Downloaded^[[0m slab v0.4.11 588: ^[[1m^[[92m Downloaded^[[0m serde_path_to_error v0.1.20 589: ^[[1m^[[92m Downloaded^[[0m schemars v0.9.0 ... 771: ^[[1m^[[92m Compiling^[[0m parking_lot_core v0.9.12 772: ^[[1m^[[92m Checking^[[0m scopeguard v1.2.0 773: ^[[1m^[[92m Checking^[[0m log v0.4.28 774: ^[[1m^[[92m Checking^[[0m once_cell v1.21.3 775: ^[[1m^[[92m Checking^[[0m futures-sink v0.3.31 776: ^[[1m^[[92m Checking^[[0m memchr v2.7.6 777: ^[[1m^[[92m Compiling^[[0m autocfg v1.5.0 778: ^[[1m^[[92m Checking^[[0m pin-utils v0.1.0 779: ^[[1m^[[92m Compiling^[[0m fnv v1.0.7 780: ^[[1m^[[92m Checking^[[0m futures-task v0.3.31 781: ^[[1m^[[92m Compiling^[[0m serde v1.0.228 782: ^[[1m^[[92m Compiling^[[0m regex-syntax v0.8.8 783: ^[[1m^[[92m Checking^[[0m equivalent v1.0.2 784: ^[[1m^[[92m Checking^[[0m stable_deref_trait v1.2.1 785: ^[[1m^[[92m Checking^[[0m hashbrown v0.16.0 786: ^[[1m^[[92m Compiling^[[0m thiserror v2.0.17 787: ^[[1m^[[92m Compiling^[[0m zerocopy v0.8.27 ... 858: ^[[1m^[[92m Compiling^[[0m rustls v0.23.35 859: ^[[1m^[[92m Checking^[[0m cpufeatures v0.2.17 860: ^[[1m^[[92m Compiling^[[0m ring v0.17.14 861: ^[[1m^[[92m Checking^[[0m nom v7.1.3 862: ^[[1m^[[92m Compiling^[[0m pq-src v0.3.10+libpq-18.0 863: ^[[1m^[[92m Compiling^[[0m indexmap v1.9.3 864: ^[[1m^[[92m Checking^[[0m matchit v0.8.4 865: ^[[1m^[[92m Checking^[[0m siphasher v1.0.1 866: ^[[1m^[[92m Checking^[[0m fallible-iterator v0.2.0 867: ^[[1m^[[92m Compiling^[[0m oid-registry v0.8.1 868: ^[[1m^[[92m Compiling^[[0m pq-sys v0.7.5 869: ^[[1m^[[92m Compiling^[[0m diesel_derives v2.3.4 870: ^[[1m^[[92m Checking^[[0m utf8_iter v1.0.4 871: ^[[1m^[[92m Checking^[[0m hashbrown v0.12.3 872: ^[[1m^[[92m Checking^[[0m http-body v1.0.1 873: ^[[1m^[[92m Checking^[[0m serde_path_to_error v0.1.20 874: ^[[1m^[[92m Checking^[[0m pem v3.0.6 875: ^[[1m^[[92m Checking^[[0m whoami v1.6.1 876: ^[[1m^[[92m Checking^[[0m unicode-normalization v0.1.25 877: ^[[1m^[[92m Checking^[[0m http-body-util v0.1.3 878: ^[[1m^[[92m Checking^[[0m phf_shared v0.13.1 879: ^[[1m^[[92m Compiling^[[0m rustls v0.21.12 880: ^[[1m^[[92m Checking^[[0m winnow v0.7.13 881: ^[[1m^[[92m Compiling^[[0m thiserror v1.0.69 882: ^[[1m^[[92m Checking^[[0m toml_write v0.1.2 ... 921: ^[[1m^[[92m Checking^[[0m rand v0.8.5 922: ^[[1m^[[92m Checking^[[0m postgres-protocol v0.6.9 923: ^[[1m^[[92m Compiling^[[0m pulldown-cmark-to-cmark v21.0.0 924: ^[[1m^[[92m Checking^[[0m matchers v0.2.0 925: ^[[1m^[[92m Checking^[[0m postgres-types v0.2.11 926: ^[[1m^[[92m Checking^[[0m sct v0.7.1 927: ^[[1m^[[92m Checking^[[0m rustls-webpki v0.101.7 928: ^[[1m^[[92m Compiling^[[0m synstructure v0.13.2 929: ^[[1m^[[92m Compiling^[[0m darling_core v0.21.3 930: ^[[1m^[[92m Compiling^[[0m diesel_table_macro_syntax v0.3.0 931: ^[[1m^[[92m Compiling^[[0m tokio-macros v2.6.0 932: ^[[1m^[[92m Compiling^[[0m serde_derive v1.0.228 933: ^[[1m^[[92m Compiling^[[0m tracing-attributes v0.1.30 934: ^[[1m^[[92m Compiling^[[0m displaydoc v0.2.5 935: ^[[1m^[[92m Compiling^[[0m prost-derive v0.14.1 936: ^[[1m^[[92m Compiling^[[0m thiserror-impl v2.0.17 937: ^[[1m^[[92m Compiling^[[0m zerovec-derive v0.11.2 938: ^[[1m^[[92m Compiling^[[0m async-trait v0.1.89 939: ^[[1m^[[92m Compiling^[[0m zeroize_derive v1.4.2 940: ^[[1m^[[92m Compiling^[[0m prost-derive v0.13.5 941: ^[[1m^[[92m Compiling^[[0m miette-derive v7.6.0 942: ^[[1m^[[92m Compiling^[[0m pin-project-internal v1.1.10 943: ^[[1m^[[92m Compiling^[[0m der_derive v0.7.3 944: ^[[1m^[[92m Compiling^[[0m asn1-rs-impl v0.2.0 945: ^[[1m^[[92m Compiling^[[0m axum-macros v0.4.2 946: ^[[1m^[[92m Compiling^[[0m async-stream-impl v0.3.6 947: ^[[1m^[[92m Compiling^[[0m thiserror-impl v1.0.69 948: ^[[1m^[[92m Compiling^[[0m tonic-build v0.14.2 ... 1075: ^[[1m^[[92m Compiling^[[0m futures-task v0.3.31 1076: ^[[1m^[[92m Compiling^[[0m futures-io v0.3.31 1077: ^[[1m^[[92m Compiling^[[0m stable_deref_trait v1.2.1 1078: ^[[1m^[[92m Compiling^[[0m libc v0.2.177 1079: ^[[1m^[[92m Compiling^[[0m serde_core v1.0.228 1080: ^[[1m^[[92m Compiling^[[0m anyhow v1.0.100 1081: ^[[1m^[[92m Compiling^[[0m tower-service v0.3.3 1082: ^[[1m^[[92m Compiling^[[0m zerocopy v0.8.27 1083: ^[[1m^[[92m Compiling^[[0m lazy_static v1.5.0 1084: ^[[1m^[[92m Compiling^[[0m lock_api v0.4.14 1085: ^[[1m^[[92m Compiling^[[0m num-traits v0.2.19 1086: ^[[1m^[[92m Compiling^[[0m percent-encoding v2.3.2 1087: ^[[1m^[[92m Compiling^[[0m subtle v2.6.1 1088: ^[[1m^[[92m Compiling^[[0m typenum v1.19.0 1089: ^[[1m^[[92m Compiling^[[0m futures-channel v0.3.31 1090: ^[[1m^[[92m Compiling^[[0m thiserror v2.0.17 1091: ^[[1m^[[92m Compiling^[[0m tower-layer v0.3.3 ... 1154: ^[[1m^[[92m Compiling^[[0m data-encoding v2.9.0 1155: ^[[1m^[[92m Compiling^[[0m iana-time-zone v0.1.64 1156: ^[[1m^[[92m Compiling^[[0m phf v0.13.1 1157: ^[[1m^[[92m Compiling^[[0m matchit v0.7.3 1158: ^[[1m^[[92m Compiling^[[0m toml_write v0.1.2 1159: ^[[1m^[[92m Compiling^[[0m bitflags v2.10.0 1160: ^[[1m^[[92m Compiling^[[0m winnow v0.7.13 1161: ^[[1m^[[92m Compiling^[[0m tinystr v0.8.2 1162: ^[[1m^[[92m Compiling^[[0m potential_utf v0.1.4 1163: ^[[1m^[[92m Compiling^[[0m indexmap v1.9.3 1164: ^[[1m^[[92m Compiling^[[0m async-stream v0.3.6 1165: ^[[1m^[[92m Compiling^[[0m rustls-pemfile v2.2.0 1166: ^[[1m^[[92m Compiling^[[0m icu_collections v2.1.1 1167: ^[[1m^[[92m Compiling^[[0m num-bigint v0.4.6 1168: ^[[1m^[[92m Compiling^[[0m downcast-rs v2.0.2 1169: ^[[1m^[[92m Compiling^[[0m thiserror v1.0.69 1170: ^[[1m^[[92m Compiling^[[0m tracing-log v0.2.0 ... 1216: ^[[1m^[[92m Compiling^[[0m rusticata-macros v4.1.0 1217: ^[[1m^[[92m Compiling^[[0m rand_chacha v0.9.0 1218: ^[[1m^[[92m Compiling^[[0m rand_chacha v0.3.1 1219: ^[[1m^[[92m Compiling^[[0m icu_normalizer v2.1.1 1220: ^[[1m^[[92m Compiling^[[0m icu_properties v2.1.1 1221: ^[[1m^[[92m Compiling^[[0m spki v0.7.3 1222: ^[[1m^[[92m Compiling^[[0m pkcs8 v0.10.2 1223: ^[[1m^[[92m Compiling^[[0m x509-cert v0.2.5 1224: ^[[1m^[[92m Compiling^[[0m prost-types v0.14.1 1225: ^[[1m^[[92m Compiling^[[0m prost-types v0.13.5 1226: ^[[1m^[[92m Compiling^[[0m darling_macro v0.21.3 1227: ^[[1m^[[92m Compiling^[[0m rand v0.9.2 1228: ^[[1m^[[92m Compiling^[[0m rand v0.8.5 1229: ^[[1m^[[92m Compiling^[[0m serde v1.0.228 1230: ^[[1m^[[92m Compiling^[[0m serde_json v1.0.145 1231: ^[[1m^[[92m Compiling^[[0m serde_path_to_error v0.1.20 1232: ^[[1m^[[92m Compiling^[[0m darling v0.21.3 ... 1305: test parser::tests::parses_lists ... ok 1306: test parser::tests::parses_list_values ... ok 1307: test parser::tests::parses_interfaces_entity ... ok 1308: test parser::tests::parses_basic_query ... ok 1309: test parser::tests::parses_rollup_stats_keyword ... ok 1310: test parser::tests::parses_rollup_stats_with_filters ... ok 1311: test parser::tests::parses_stats_expression ... ok 1312: test parser::tests::parses_time ... ok 1313: test parser::tests::parses_unquoted_stats_alias ... ok 1314: test parser::tests::rejects_empty_rollup_stats ... ok 1315: test parser::tests::parses_unquoted_stats_alias_with_following_tokens ... ok 1316: test parser::tests::rejects_stats_alias_missing_identifier ... ok 1317: test parser::tests::rejects_overly_long_stats_expression ... ok 1318: test query::agents::tests::builds_query_with_gateway_filter ... ok 1319: test query::agents::tests::builds_query_with_type_id_filter ... ok 1320: test query::agents::tests::unknown_filter_field_returns_error ... ok 1321: test query::cpu_metrics::tests::unknown_filter_field_returns_error ... ok 1322: test parser::tests::rejects_list_filters_over_limit ... ok 1323: test query::cpu_metrics::tests::stats_query_matches_cpu_language_reference ... ok 1324: test query::gateways::tests::unknown_filter_field_returns_error ... ok 1325: test query::logs::tests::rollup_stats_severity_builds_cagg_query ... ok 1326: test query::logs::tests::rollup_stats_severity_with_service_filter ... ok 1327: test query::interfaces::tests::stats_count_interfaces_emits_count_query ... ok 1328: test query::disk_metrics::tests::unknown_filter_field_returns_error ... ok 1329: test query::logs::tests::rollup_stats_unknown_type_returns_error ... ok 1330: test query::logs::tests::stats_query_counts_logs_for_service ... ok 1331: test query::logs::tests::unknown_stats_filter_field_returns_error ... ok 1332: test query::logs::tests::unknown_filter_field_returns_error ... ok 1333: test query::otel_metrics::tests::unknown_filter_field_returns_error ... ok 1334: test query::memory_metrics::tests::unknown_filter_field_returns_error ... ok 1335: test query::process_metrics::tests::unknown_filter_field_returns_error ... ok 1336: test query::services::tests::unknown_filter_field_returns_error ... ok 1337: ^[[1m^[[92m Running^[[0m unittests src/main.rs (/home/runner/_work/serviceradar/serviceradar/target/debug/deps/srql-ef0fb1a8aa7439b4) 1338: test query::tests::devices_docs_example_available_true ... ok 1339: test query::tests::translate_graph_cypher_rejects_mutations ... ok 1340: test query::tests::translate_downsample_emits_time_bucket_query ... ok 1341: test query::tests::gateways_docs_example_health_and_status ... ok 1342: test query::timeseries_metrics::tests::unknown_filter_field_returns_error ... ok 1343: test query::tests::devices_docs_example_available_false ... ok 1344: test time::tests::parses_absolute_range ... ok 1345: test query::traces::tests::unknown_filter_field_returns_error ... ok 1346: test time::tests::parses_open_end_absolute_range ... ok 1347: test time::tests::parses_relative_days ... ok 1348: test time::tests::parses_open_start_absolute_range ... ok 1349: test time::tests::rejects_absolute_range_exceeding_limit ... ok 1350: test time::tests::rejects_open_end_range_exceeding_limit ... ok 1351: test query::tests::services_docs_example_service_type_timeframe ... ok 1352: test query::tests::devices_docs_example_discovery_sources_contains_all ... ok 1353: test query::tests::translate_graph_cypher_wraps_rows_as_topology_payload ... ok 1354: test query::tests::translate_includes_visualization_metadata ... ok 1355: test query::tests::translate_param_arity_matches_sql_placeholders ... ok 1356: test query::tests::interfaces_docs_example_ip_addresses_contains_any ... ok 1357: test result: ok. 54 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 1358: ^[[1m^[[92m Running^[[0m tests/api.rs (/home/runner/_work/serviceradar/serviceradar/target/debug/deps/api-b0a82ccb463a2c0a) 1359: running 0 tests 1360: test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 1361: running 1 test 1362: test srql_api_queries ... FAILED 1363: failures: 1364: ---- srql_api_queries stdout ---- 1365: [srql-test] SRQL_TEST_DATABASE_URL: user=srql db=srql_fixture hosts=["srql-fixture.serviceradar.cloud"] port=5432 1366: [srql-test] SRQL_TEST_ADMIN_URL: user=srql_hydra db=postgres hosts=["srql-fixture.serviceradar.cloud"] port=5432 1367: thread 'srql_api_queries' (9175) panicked at rust/srql/tests/support/harness.rs:74:10: 1368: failed to acquire remote fixture lock: db error 1369: Caused by: 1370: FATAL: pg_hba.conf rejects connection for host "10.42.221.65", user "srql_hydra", database "postgres", no encryption 1371: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace 1372: failures: 1373: srql_api_queries 1374: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.13s 1375: ^[[1m^[[91merror^[[0m: test failed, to rerun pass `--test api` 1376: ##[error]Process completed with exit code 101. 1377: Post job cleanup. ``` </details></td></tr></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!2633
No description provided.