Cleanup/services page #2640

Merged
mfreeman451 merged 9 commits from refs/pull/2640/head into testing 2026-01-10 00:01:36 +00:00
mfreeman451 commented 2026-01-09 08:30:51 +00:00 (Migrated from github.com)
Owner

Imported from GitHub pull request.

Original GitHub pull request: #2235
Original author: @mfreeman451
Original URL: https://github.com/carverauto/serviceradar/pull/2235
Original created: 2026-01-09T08:30:51Z
Original updated: 2026-01-10T00:01:38Z
Original head: carverauto/serviceradar:cleanup/services_page
Original base: testing
Original merged: 2026-01-10T00:01:36Z 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, Documentation


Description

  • Major architectural refactoring from poller-based to gateway-based system: Comprehensive rename and restructuring of core components, services, and APIs to support a new gateway-centric architecture

  • Multi-tenant gateway push architecture: Refactored sync service to implement push-first integration with dynamic configuration management, replacing pull-based KV and gRPC clients with gateway client for result streaming

  • Gateway monitoring and status management: New comprehensive implementation for gateway health checks, offline/recovery detection, alert handling, and streaming status report processing with chunk reassembly

  • NATS infrastructure enhancements: Added NATS account management service with protobuf definitions and gRPC implementations for operator bootstrap, tenant account creation, and credential generation

  • CLI NATS bootstrap functionality: New comprehensive CLI implementation for NATS bootstrap operations including credential generation, token management, and status verification

  • Protobuf definitions update: Refactored protobuf messages from PollerService to AgentGatewayService with new message types for gateway-agent communication (AgentHelloRequest, AgentConfigRequest, etc.)

  • Edge onboarding service updates: Systematic terminology refactoring and support for new EdgeOnboardingComponentTypeSync component type

  • Removed legacy poller infrastructure: Deleted poller-specific packages, CLI commands, Docker configurations, and web UI components

  • API documentation updates: Updated Swagger documentation and gRPC service registration to reflect gateway terminology


Diagram Walkthrough

flowchart LR
  A["Legacy Poller<br/>Architecture"] -->|"Refactor"| B["Gateway-Based<br/>Architecture"]
  B -->|"Push-First"| C["Gateway Client<br/>Integration"]
  B -->|"Multi-Tenant"| D["Tenant-Scoped<br/>Configuration"]
  B -->|"Dynamic Config"| E["Config Polling &<br/>Heartbeat Loops"]
  F["NATS Account<br/>Service"] -->|"Supports"| B
  G["CLI Bootstrap<br/>Commands"] -->|"Manages"| F
  C -->|"Replaces"| H["Pull-Based<br/>KV/gRPC"]

File Walkthrough

Relevant files
Enhancement
6 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 GatewayServiceStatus message type with tenant-related fields
    (TenantId, TenantSlug)
  • Added new agent-gateway communication messages: AgentHelloRequest,
    AgentHelloResponse, AgentConfigRequest, AgentConfigResponse,
    AgentCheckConfig
  • Updated service definitions from PollerService to AgentGatewayService
    with new RPC methods
+1039/-404
nats_bootstrap.go
Add comprehensive NATS bootstrap CLI functionality             

pkg/cli/nats_bootstrap.go

  • New file implementing NATS bootstrap functionality for the 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
  • Supports token generation, status checking, and tenant listing via
    Core API endpoints
  • Includes helper functions for file I/O, credential generation, and
    output formatting (text/JSON)
+961/-0 
service.go
Multi-tenant gateway push architecture with dynamic config management

pkg/sync/service.go

  • Refactored sync service to support multi-tenant architecture with
    gateway push-first integration
  • Removed KV client and gRPC client dependencies; added gateway client
    for push-based results
  • Implemented per-source discovery scheduling with interval tracking and
    tenant-scoped configuration
  • Added gateway enrollment, config polling, and heartbeat loops for
    dynamic configuration management
  • Replaced streaming chunk generation with improved chunking logic and
    gateway status push support
  • Deprecated pull-based GetResults and StreamResults APIs in favor of
    push-based gateway integration
+1279/-316
gateways.go
Gateway monitoring and status management implementation   

pkg/core/gateways.go

  • New comprehensive gateway monitoring and status management
    implementation with 1547 lines of code
  • Implements gateway health checks, offline/recovery detection, and
    alert handling
  • Provides streaming status report processing with chunk reassembly for
    large datasets
  • Includes service registration, device inventory updates, and event
    publishing for gateway lifecycle events
+1547/-0
edge_onboarding.go
Poller to gateway terminology refactoring                               

pkg/core/edge_onboarding.go

  • Systematic rename of "poller" terminology to "gateway" throughout the
    edge onboarding service
  • Updates method names, variable names, type names, and configuration
    keys for consistency
  • Adds support for EdgeOnboardingComponentTypeSync component type
  • Updates gateway configuration management and KV store operations to
    use new naming
+208/-206
app.go
Update gRPC service registration to gateway service           

cmd/core/app/app.go

  • Updates gRPC service registration from RegisterPollerServiceServer to
    RegisterAgentGatewayServiceServer
  • Aligns service registration with new gateway-based architecture
+1/-1     
Documentation
1 files
main.go
Update API documentation terminology                                         

cmd/core/main.go

  • Updated API description from "service pollers" to "service gateways"
    in Swagger documentation
+1/-1     
Configuration changes
1 files
prod.exs
Add production configuration for Elixir agent gateway       

elixir/serviceradar_agent_gateway/config/prod.exs

  • New file with production-specific Elixir configuration
  • Sets logger level to info for production environment
+4/-0     
Dependencies
2 files
nats_account.pb.go
NATS account management protobuf definitions and service 

proto/nats_account.pb.go

  • Generated protobuf code for NATS account management service
  • Defines message types for account limits, subject mappings, and user
    credentials
  • Implements RPC service for operator bootstrap, tenant account
    creation, and user credential generation
  • Includes JWT signing and account management operations for NATS
    infrastructure
+1266/-0
nats_account_grpc.pb.go
NATS account gRPC service implementation                                 

proto/nats_account_grpc.pb.go

  • Auto-generated gRPC service code for NATS account management
    operations
  • Implements client and server interfaces for JWT signing and account
    operations
  • Provides methods for operator bootstrap, tenant account creation, and
    credential generation
  • Includes service registration and handler implementations for gRPC
    framework
+376/-0 
Miscellaneous
1 files
interfaces.go
Remove KVWriter from Armis integration mocks                         

pkg/sync/integrations/armis/interfaces.go

  • Removed KVWriter from mockgen directive for Armis integration
  • Simplifies mock generation to focus on core integration interfaces
+1/-6     
Additional files
101 files
.bazelignore +4/-0     
.bazelrc +5/-0     
.env-sample +33/-0   
.env.example +38/-0   
main.yml +18/-0   
AGENTS.md +177/-11
INSTALL.md +11/-11 
MODULE.bazel +5/-0     
Makefile +55/-14 
README-Docker.md +17/-2   
README.md +3/-3     
ROADMAP.md +1/-1     
BUILD.bazel +11/-6   
BUILD.bazel +12/-0   
mix_release.bzl +124/-49
BUILD.bazel +1/-0     
README.md +4/-4     
config.json +5/-6     
main.go +174/-74
build.rs +0/-1     
monitoring.proto +3/-26   
server.rs +2/-0     
main.go +1/-1     
README.md +2/-2     
monitoring.proto +2/-26   
server.rs +6/-6     
main.go +16/-2   
config.rs +26/-0   
grpc_server.rs +2/-2     
message_processor.rs +1/-0     
nats.rs +4/-0     
zen-consumer-with-otel.json +1/-0     
zen-consumer.json +1/-0     
config.json +4/-4     
config.json +4/-4     
BUILD.bazel +1/-0     
main.go +68/-0   
README.md +3/-3     
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/-111 
main.go +0/-138 
BUILD.bazel +0/-25   
config.json +0/-77   
main.go +0/-123 
main.go +1/-1     
config.rs +21/-0   
main.rs +23/-3   
docker-compose.elx.yml +109/-0 
docker-compose.spiffe.yml +8/-158 
docker-compose.yml +318/-269
Dockerfile.agent-gateway +94/-0   
Dockerfile.core-elx +108/-0 
Dockerfile.poller +0/-70   
Dockerfile.sync +0/-95   
Dockerfile.tools +1/-2     
Dockerfile.web-ng +6/-0     
agent-minimal.docker.json +6/-6     
agent.docker.json +5/-20   
agent.mtls.json +7/-10   
bootstrap-nested-spire.sh +0/-80   
.gitkeep +1/-0     
datasvc.docker.json +3/-2     
datasvc.mtls.json +14/-1   
db-event-writer.docker.json +2/-2     
db-event-writer.mtls.json +3/-2     
FRICTION_POINTS.md +0/-355 
README.md +0/-207 
SETUP_GUIDE.md +0/-307 
docker-compose.edge-e2e.yml +0/-27   
manage-packages.sh +0/-211 
setup-edge-e2e.sh +0/-198 
edge-poller-restart.sh +0/-178 
downstream-agent.conf +0/-32   
env +0/-4     
server.conf +0/-51   
upstream-agent.conf +0/-32   
entrypoint-certs.sh +13/-9   
entrypoint-poller.sh +0/-274 
entrypoint-sync.sh +0/-96   
fix-cert-permissions.sh +2/-2     
flowgger.docker.toml +2/-1     
generate-certs.sh +214/-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   
poller-stack.compose.yml +0/-121 
poller.docker.json +0/-128 
poller.mtls.json +0/-135 
poller.spiffe.json +0/-55   
refresh-upstream-credentials.sh +0/-248 
seed-poller-kv.sh +0/-83   
Additional files not shown

Imported from GitHub pull request. Original GitHub pull request: #2235 Original author: @mfreeman451 Original URL: https://github.com/carverauto/serviceradar/pull/2235 Original created: 2026-01-09T08:30:51Z Original updated: 2026-01-10T00:01:38Z Original head: carverauto/serviceradar:cleanup/services_page Original base: testing Original merged: 2026-01-10T00:01:36Z 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, Documentation ___ ### **Description** - **Major architectural refactoring from poller-based to gateway-based system**: Comprehensive rename and restructuring of core components, services, and APIs to support a new gateway-centric architecture - **Multi-tenant gateway push architecture**: Refactored sync service to implement push-first integration with dynamic configuration management, replacing pull-based KV and gRPC clients with gateway client for result streaming - **Gateway monitoring and status management**: New comprehensive implementation for gateway health checks, offline/recovery detection, alert handling, and streaming status report processing with chunk reassembly - **NATS infrastructure enhancements**: Added NATS account management service with protobuf definitions and gRPC implementations for operator bootstrap, tenant account creation, and credential generation - **CLI NATS bootstrap functionality**: New comprehensive CLI implementation for NATS bootstrap operations including credential generation, token management, and status verification - **Protobuf definitions update**: Refactored protobuf messages from `PollerService` to `AgentGatewayService` with new message types for gateway-agent communication (`AgentHelloRequest`, `AgentConfigRequest`, etc.) - **Edge onboarding service updates**: Systematic terminology refactoring and support for new `EdgeOnboardingComponentTypeSync` component type - **Removed legacy poller infrastructure**: Deleted poller-specific packages, CLI commands, Docker configurations, and web UI components - **API documentation updates**: Updated Swagger documentation and gRPC service registration to reflect gateway terminology ___ ### Diagram Walkthrough ```mermaid flowchart LR A["Legacy Poller<br/>Architecture"] -->|"Refactor"| B["Gateway-Based<br/>Architecture"] B -->|"Push-First"| C["Gateway Client<br/>Integration"] B -->|"Multi-Tenant"| D["Tenant-Scoped<br/>Configuration"] B -->|"Dynamic Config"| E["Config Polling &<br/>Heartbeat Loops"] F["NATS Account<br/>Service"] -->|"Supports"| B G["CLI Bootstrap<br/>Commands"] -->|"Manages"| F C -->|"Replaces"| H["Pull-Based<br/>KV/gRPC"] ``` <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>6 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 <code>GatewayServiceStatus</code> message type with tenant-related fields <br>(<code>TenantId</code>, <code>TenantSlug</code>)<br> <li> Added new agent-gateway communication messages: <code>AgentHelloRequest</code>, <br><code>AgentHelloResponse</code>, <code>AgentConfigRequest</code>, <code>AgentConfigResponse</code>, <br><code>AgentCheckConfig</code><br> <li> Updated service definitions from <code>PollerService</code> to <code>AgentGatewayService</code> <br>with new RPC methods</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-4f7e955b42854cc9cf3fb063b95e58a04f36271e6a0c1cb42ea6d7953dd96cc4">+1039/-404</a></td> </tr> <tr> <td> <details> <summary><strong>nats_bootstrap.go</strong><dd><code>Add comprehensive NATS bootstrap CLI functionality</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/cli/nats_bootstrap.go <ul><li>New file implementing NATS bootstrap functionality for the 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> Supports token generation, status checking, and tenant listing via <br>Core API endpoints<br> <li> Includes helper functions for file I/O, credential generation, and <br>output formatting (text/JSON)</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-2176d03ba6ab4ccc1b0587a4727171546eecf6123e4df815ead583aaab062457">+961/-0</a>&nbsp; </td> </tr> <tr> <td> <details> <summary><strong>service.go</strong><dd><code>Multi-tenant gateway push architecture with dynamic config management</code></dd></summary> <hr> pkg/sync/service.go <ul><li>Refactored sync service to support multi-tenant architecture with <br>gateway push-first integration<br> <li> Removed KV client and gRPC client dependencies; added gateway client <br>for push-based results<br> <li> Implemented per-source discovery scheduling with interval tracking and <br>tenant-scoped configuration<br> <li> Added gateway enrollment, config polling, and heartbeat loops for <br>dynamic configuration management<br> <li> Replaced streaming chunk generation with improved chunking logic and <br>gateway status push support<br> <li> Deprecated pull-based <code>GetResults</code> and <code>StreamResults</code> APIs in favor of <br>push-based gateway integration</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7e">+1279/-316</a></td> </tr> <tr> <td> <details> <summary><strong>gateways.go</strong><dd><code>Gateway monitoring and status management implementation</code>&nbsp; &nbsp; </dd></summary> <hr> pkg/core/gateways.go <ul><li>New comprehensive gateway monitoring and status management <br>implementation with 1547 lines of code<br> <li> Implements gateway health checks, offline/recovery detection, and <br>alert handling<br> <li> Provides streaming status report processing with chunk reassembly for <br>large datasets<br> <li> Includes service registration, device inventory updates, and event <br>publishing for gateway lifecycle events</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-260332914ad2238e720f4637a71b0f9f01e899102bc6b37f7827782e56b0b5c0">+1547/-0</a></td> </tr> <tr> <td> <details> <summary><strong>edge_onboarding.go</strong><dd><code>Poller to gateway terminology refactoring</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/core/edge_onboarding.go <ul><li>Systematic rename of "poller" terminology to "gateway" throughout the <br>edge onboarding service<br> <li> Updates method names, variable names, type names, and configuration <br>keys for consistency<br> <li> Adds support for <code>EdgeOnboardingComponentTypeSync</code> component type<br> <li> Updates gateway configuration management and KV store operations to <br>use new naming</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-85874e3c4bdcc9110db09909f10648d44cdee554b26c987f910502321eb20b5c">+208/-206</a></td> </tr> <tr> <td> <details> <summary><strong>app.go</strong><dd><code>Update gRPC service registration to gateway service</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> cmd/core/app/app.go <ul><li>Updates gRPC service registration from <code>RegisterPollerServiceServer</code> to <br><code>RegisterAgentGatewayServiceServer</code><br> <li> Aligns service registration with new gateway-based architecture</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-4ad8a289575edf3b163088617b7a40ae1305c29ced0c7d59b3751c57d6938072">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1 files</summary><table> <tr> <td> <details> <summary><strong>main.go</strong><dd><code>Update API documentation terminology</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> cmd/core/main.go <ul><li>Updated API description from "service pollers" to "service gateways" <br>in Swagger documentation</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-4ab3fd1d4debc53dd2499d94a0f60c648fdae4235dd1e3678095a975f5bb434a">+1/-1</a>&nbsp; &nbsp; &nbsp; </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 production configuration for Elixir agent gateway</code>&nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> elixir/serviceradar_agent_gateway/config/prod.exs <ul><li>New file with production-specific Elixir configuration<br> <li> Sets logger level to <code>info</code> for production environment</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-5fdc859dfda96a02326392f61218325913f22f9f0c75a1276ee940d5db9fc62b">+4/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Dependencies</strong></td><td><details><summary>2 files</summary><table> <tr> <td> <details> <summary><strong>nats_account.pb.go</strong><dd><code>NATS account management protobuf definitions and service</code>&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 limits, subject mappings, and user <br>credentials<br> <li> Implements RPC service for operator bootstrap, tenant account <br>creation, and user credential generation<br> <li> Includes JWT signing and account management operations for NATS <br>infrastructure</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-49eb93c28e2d86d8dcf4ee78fd24bed498cf3fcfaa8e49849a36e70980420087">+1266/-0</a></td> </tr> <tr> <td> <details> <summary><strong>nats_account_grpc.pb.go</strong><dd><code>NATS account gRPC service implementation</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> proto/nats_account_grpc.pb.go <ul><li>Auto-generated gRPC service code for NATS account management <br>operations<br> <li> Implements client and server interfaces for JWT signing and account <br>operations<br> <li> Provides methods for operator bootstrap, tenant account creation, and <br>credential generation<br> <li> Includes service registration and handler implementations for gRPC <br>framework</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-af98ae5f073d25a2ea0a044c996542fc65d215f6a70f14a9fba0447d87b34e11">+376/-0</a>&nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Miscellaneous</strong></td><td><details><summary>1 files</summary><table> <tr> <td> <details> <summary><strong>interfaces.go</strong><dd><code>Remove KVWriter from Armis integration mocks</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary> <hr> pkg/sync/integrations/armis/interfaces.go <ul><li>Removed <code>KVWriter</code> from mockgen directive for Armis integration<br> <li> Simplifies mock generation to focus on core integration interfaces</ul> </details> </td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-d79328868812c0987fe9b3593dcad531ca90bb9aae2721a840c1ba1130659eec">+1/-6</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/2235/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/2235/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/2235/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/2235/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/2235/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/2235/files#diff-a54ff182c7e8acf56acfd6e4b9c3ff41e2c41a31c9b211b2deb9df75d9a478f9">+177/-11</a></td> </tr> <tr> <td><strong>INSTALL.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-09b140a43ebfdd8dbec31ce72cafffd15164d2860fd390692a030bcb932b54a0">+11/-11</a>&nbsp; </td> </tr> <tr> <td><strong>MODULE.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/files#diff-76ed074a9305c04054cdebb9e9aad2d818052b07091de1f20cad0bbac34ffb52">+55/-14</a>&nbsp; </td> </tr> <tr> <td><strong>README-Docker.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-9fd61d24482efe68c22d8d41e2a1dcc440f39195aa56e7a050f2abe598179efd">+17/-2</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>README.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5">+3/-3</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>ROADMAP.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-683343bdf93f55ed3cada86151abb8051282e1936e58d4e0a04beca95dff6e51">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-884fa9353a5226345e44fbabea3300efc7a87dfbcde0b6a42521ca51823f1b68">+11/-6</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/files#diff-86ec281f99363b6b6eb1f49e21d83b7eeca93a35b552b9f305fffc6855e38ccd">+124/-49</a></td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-143f8d1549d52f28906f19ce28e5568a5be474470ff103c2c1e63c3e6b08d670">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>README.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-bfd308915d0cf522e7fc76600dee687617dc69165ab22502a1d219850c0c0860">+4/-4</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>config.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/files#diff-61358711e980ccf505246fd3915f97cbd3a380e9b66f6fa5aad46749968c5ca3">+174/-74</a></td> </tr> <tr> <td><strong>build.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/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/2235/files#diff-bce0f4ca6548712f224b73816825d28e831acbbff7dbed3c98671ed50f65d028">+2/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>main.go</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-f25402eade63525184cb5e7437accff93c7b9338eebe81add6dc5f2a9eb12550">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>README.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-2e9751b437fa61442aac074c7a4a912d0ac50ac3ea156ac8aedd8478d21c6bdb">+2/-2</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>monitoring.proto</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/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/2235/files#diff-ed4d81d29a7267f93fd77e17993fd3491b9ef6ded18490b4514d10ed1d803bc2">+16/-2</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>config.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/files#diff-e4564a93f6cf84ff91cd3d8141fc9272ec9b4ec19defd107afa42be01fcfed5b">+2/-2</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>message_processor.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/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/2235/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/2235/files#diff-4d308af9802a93a0f656e8c02a3b5fcd8991407bb18360f087470db74e1f9524">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>config.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-2423ef78d36e905ae993b69ff59f5df6b2e1b9492fb0fa8c6d0aad7c76d2d229">+4/-4</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>config.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-ef778d85ac6f9652c25cb0d631f0fe8dfb3edac4dde5d719a4fc2926fb5c3216">+4/-4</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/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/2235/files#diff-0b0725713b87dca1de57200214a4fe04633f0d856c39aa8032280227bf8e8141">+3/-3</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>README.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/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/2235/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/2235/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/2235/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/2235/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/2235/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/2235/files#diff-e1f7c698e0e3a4e6afa971c1140e71cbf22593fbb19c81cb26b02c15c5dc46ec">+0/-25</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>config.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-9edc2486fff55fc399e0ac96dba5137948a7ea7285f5ef7846835355684b7ab5">+0/-111</a>&nbsp; </td> </tr> <tr> <td><strong>main.go</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-4b8ec845da50cd58d011e69f9d1c30530ee1968df26616b8768bb1fc03433bbe">+0/-138</a>&nbsp; </td> </tr> <tr> <td><strong>BUILD.bazel</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/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/2235/files#diff-78dc6bc53f1c760c66f43ff5f486bfe78a65bee8b2e0d4862293ec0892da2b29">+0/-123</a>&nbsp; </td> </tr> <tr> <td><strong>main.go</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-bc6eeb1b05bcb9179525e32fac1de9926b5823ec3504be546ab10c5c9740f544">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>config.rs</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/files#diff-33b655d8730ae3e9c844ee280787d11f1b0d5343119188273f89558805f814ba">+23/-3</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>docker-compose.elx.yml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-9562070d7ad4a3e9b2d06567008cf35de1d96448d914b3b45bf6c36d97cdd914">+109/-0</a>&nbsp; </td> </tr> <tr> <td><strong>docker-compose.spiffe.yml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-603fd9e7d40841d174f26b95d0cb0c9537430bf3f7a5da3ccbba4ea3d8ac66c9">+8/-158</a>&nbsp; </td> </tr> <tr> <td><strong>docker-compose.yml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-e45e45baeda1c1e73482975a664062aa56f20c03dd9d64a827aba57775bed0d3">+318/-269</a></td> </tr> <tr> <td><strong>Dockerfile.agent-gateway</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/files#diff-5ec7a971285669999af442a0c7f141c34f7fd9180257307f5c4ed12f789a2182">+108/-0</a>&nbsp; </td> </tr> <tr> <td><strong>Dockerfile.poller</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-d3ba129830fb366bfe23b00db4ef6218b10fc981d3c04842b1b3b3b367a8982f">+0/-70</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>Dockerfile.sync</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-0227933b9961fd553af1d229e89d71a0271fdc475081bbcef49b587941af1eda">+0/-95</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>Dockerfile.tools</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-0258db71e4070e342198965f1d046f3097640850b037df8a2287a7e239630add">+1/-2</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>Dockerfile.web-ng</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/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/2235/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/2235/files#diff-008f2216f159a9bd5db9cc90baaf6f1e64487df7af05b56ab3b9d6c4946aa95f">+7/-10</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>bootstrap-nested-spire.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-ab4746a08fb1e0b307a1e47660cd22182e283a087cba87dcbff0fdfe750f44f1">+0/-80</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>.gitkeep</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/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/2235/files#diff-3a45619e57f1e6e9a31486ec7fffb33ef246e271f82bac272ee0a946b88da70a">+14/-1</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>db-event-writer.docker.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-9fc51271f7ef5bb460160013e24e44e829b730656891d26fc49d5fe72fbb3147">+2/-2</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>db-event-writer.mtls.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-7a33f95f7545499abf0ed9fc91b58499ab209639e4885019579c959583fc7496">+3/-2</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>FRICTION_POINTS.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-b0653c58880f810ba832c0500733d63de309db98b43009fe73a1862494cf41bd">+0/-355</a>&nbsp; </td> </tr> <tr> <td><strong>README.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-31849f033cfc932acee35f549c069abb1f36101c352e553dd6bff8713b29f98c">+0/-207</a>&nbsp; </td> </tr> <tr> <td><strong>SETUP_GUIDE.md</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-b4914f8640a78038e45f51235a624535672680dc902de5f107fc051f4f281913">+0/-307</a>&nbsp; </td> </tr> <tr> <td><strong>docker-compose.edge-e2e.yml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-575d19ea771bdf8102cb9729db43a1bfd6afc2527160e54105beeac2e314f362">+0/-27</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>manage-packages.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-3c2ff6febbddb956c71557894adaf7d0a39a1f20dda120fe126364946bc47280">+0/-211</a>&nbsp; </td> </tr> <tr> <td><strong>setup-edge-e2e.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-2714e2c7e111f69ea9e9f5ddd7f6a70fa5ea96e3a53b851cb13b8b8b7cd12917">+0/-198</a>&nbsp; </td> </tr> <tr> <td><strong>edge-poller-restart.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-96a8fe52c38fd0d7c14895127df34a27be311cac89c53d28ee178661b629bd22">+0/-178</a>&nbsp; </td> </tr> <tr> <td><strong>downstream-agent.conf</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-747de0375ced42af978ca7dac239862bdabb7f6bd0bd634f134b485517a7b4ee">+0/-32</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>env</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-686f1a954c542f2ec9bf14c3170648b65190ad242c7f3a95a0f872ae41b8b1c6">+0/-4</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>server.conf</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-025f5b5ab79526cf549ca1fdb90dd659ba76b438f05a7f77d916d18728c4b572">+0/-51</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>upstream-agent.conf</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-e8a869ddf4affa31536a8d4e4e6f09c40072a7026da2c609d93c6ecf04138902">+0/-32</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>entrypoint-certs.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-83d6800b184a5233c66c69766286b0a60fece1bc64addb112d9f8dc019437f05">+13/-9</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>entrypoint-poller.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-e202d27e3331088745eb55cdd2b3e40ac3f5df109d9ff5c76c0faed60772807a">+0/-274</a>&nbsp; </td> </tr> <tr> <td><strong>entrypoint-sync.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-9d5620b8e6833309dbafb8ee6b6b75c3b942d163c3fe7f1a9827958b2d640265">+0/-96</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>fix-cert-permissions.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-17ea40a11edcaa7c85bb4215fda46b5a32505246fef0ab5f3ed47b28470c5ec8">+2/-2</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>flowgger.docker.toml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/files#diff-8298241543b4744a6ac7780c760ac5b5a0a87ba62de19c8612ebe1aba0996ebd">+214/-12</a></td> </tr> <tr> <td><strong>nats.docker.conf</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/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/2235/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/2235/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/2235/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/2235/files#diff-e7b8ce062e32c61fdc3bcc9e525c1f1df1c8008fbc02b11409e58c67baa17cc5">+17/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>poller-stack.compose.yml</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-f3b5c991c2c1f7646db0ca4ed9bcb5df0f313ce6a05d8f3c890f80c873f776f5">+0/-121</a>&nbsp; </td> </tr> <tr> <td><strong>poller.docker.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-d64ebb69ec31e831efd187c47a5bfff2573960306b177f6464e91cb44a3c709d">+0/-128</a>&nbsp; </td> </tr> <tr> <td><strong>poller.mtls.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-ef5d74bb3607431245c2bf06169d7fee89cae817e114035075b59a671229ab46">+0/-135</a>&nbsp; </td> </tr> <tr> <td><strong>poller.spiffe.json</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-4e04bd23a0216287d5c0bb3831e0f95e7922ed03e8386a10ae7f4873e4fdb538">+0/-55</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>refresh-upstream-credentials.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-d3b3a8fcdea1b49c9e1c0ecc12d61fb6d416313520e8ad52edbee9094dbdc271">+0/-248</a>&nbsp; </td> </tr> <tr> <td><strong>seed-poller-kv.sh</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-c12070f475dbe7dc83e747fa6ec9d2ebdbdd97921a54f372abc89a102b783ad7">+0/-83</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>Additional files not shown</strong></td> <td><a href="https://github.com/carverauto/serviceradar/pull/2235/files#diff-2f328e4cd8dbe3ad193e49d92bcf045f47a6b72b1e9487d366f6b8288589b4ca"></a></td> </tr> </table></details></td></tr></tbody></table> </details> ___
qodo-code-review[bot] commented 2026-01-09 08:32:30 +00:00 (Migrated from github.com)
Author
Owner

Imported GitHub PR comment.

Original author: @qodo-code-review[bot]
Original URL: https://github.com/carverauto/serviceradar/pull/2235#issuecomment-3727776562
Original created: 2026-01-09T08:32:30Z

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

Generic: Robust Error Handling and Edge Case Management

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

Status: Passed

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

Generic: Secure Error Handling

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

Status: Passed

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

Generic: Secure Logging Practices

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

Status: Passed

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

Generic: Comprehensive Audit Trails

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

Status:
Limited audit context: The new onboarding log event indicates onboarding started but does not include an actor
identifier or outcome details sufficient to reconstruct who/what initiated onboarding and
whether it succeeded.

Referred Code
log.Info().
	Str("component_type", string(componentType)).
	Bool("offline_package", packagePath != "").
	Bool("has_gateway_addr", gatewayEndpoint != "").
	Msg("Onboarding token detected - starting edge onboarding")

// Note: KVEndpoint is no longer required for SaaS mode.
// Agents connect to GatewayEndpoint and receive config via GetConfig.

// Create bootstrapper
b, err := NewBootstrapper(&Config{
	Token:           token,
	PackagePath:     packagePath,
	GatewayEndpoint: gatewayEndpoint,
	KVEndpoint:      kvEndpoint, // Optional for legacy/on-prem mode
	ServiceType:     componentType,
	PackageID:       packageID,
	CoreAPIURL:      coreAPIURL,
	Logger:          log,
	// StoragePath will use default

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

Generic: Security-First Input Validation and Data Handling

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

Status:
Endpoint not validated: Environment-provided GATEWAY_ADDR and KV_ENDPOINT values are only trimmed and
presence-checked, with no format/allowlist validation to prevent unsafe or unintended
endpoint injection/misconfiguration.

Referred Code
token := strings.TrimSpace(os.Getenv("ONBOARDING_TOKEN"))
gatewayEndpoint := strings.TrimSpace(os.Getenv("GATEWAY_ADDR"))
kvEndpoint := strings.TrimSpace(os.Getenv("KV_ENDPOINT"))
packageID := strings.TrimSpace(os.Getenv("EDGE_PACKAGE_ID"))
coreAPIURL := strings.TrimSpace(os.Getenv("CORE_API_URL"))
packagePath := firstNonEmpty(
	strings.TrimSpace(os.Getenv("ONBOARDING_PACKAGE")),
	strings.TrimSpace(os.Getenv("SR_ONBOARDING_PACKAGE")),
)

// If no onboarding token, use traditional config
if token == "" && packagePath == "" {
	return nil, nil
}

// Validate that required endpoints are present for online onboarding
if token != "" && packagePath == "" && gatewayEndpoint == "" && kvEndpoint == "" {
	return nil, ErrEndpointRequired
}

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/2235#issuecomment-3727776562 Original created: 2026-01-09T08:32:30Z --- ## PR Compliance Guide 🔍 <!-- https://github.com/carverauto/serviceradar/commit/4f0344cbdbd5f71f212d5a4b1ce783ac27cd39a8 --> 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=4>🟢</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> <details><summary><strong>Generic: Robust Error Handling and Edge Case Management</strong></summary><br> **Objective:** Ensure comprehensive error handling that provides meaningful context and graceful <br>degradation<br> **Status:** Passed<br> > Learn more about managing compliance <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#configuration-options'>generic rules</a> or creating your own <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#custom-compliance'>custom rules</a> </details></td></tr> <tr><td> <details><summary><strong>Generic: Secure Error Handling</strong></summary><br> **Objective:** To prevent the leakage of sensitive system information through error messages while <br>providing sufficient detail for internal debugging.<br> **Status:** Passed<br> > Learn more about managing compliance <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#configuration-options'>generic rules</a> or creating your own <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#custom-compliance'>custom rules</a> </details></td></tr> <tr><td> <details><summary><strong>Generic: Secure Logging Practices</strong></summary><br> **Objective:** To ensure logs are useful for debugging and auditing without exposing sensitive <br>information like PII, PHI, or cardholder data.<br> **Status:** 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=2>⚪</td> <td><details> <summary><strong>Generic: Comprehensive Audit Trails</strong></summary><br> **Objective:** To create a detailed and reliable record of critical system actions for security analysis <br>and compliance.<br> **Status:** <br><a href='https://github.com/carverauto/serviceradar/pull/2235/files#diff-e0086702d4c86140315e9347dc19ccae52a3eb64b66a15ccfafae8981c7945d8R94-R113'><strong>Limited audit context</strong></a>: The new onboarding log event indicates onboarding started but does not include an actor <br>identifier or outcome details sufficient to reconstruct who/what initiated onboarding and <br>whether it succeeded.<br> <details open><summary>Referred Code</summary> ```go log.Info(). Str("component_type", string(componentType)). Bool("offline_package", packagePath != ""). Bool("has_gateway_addr", gatewayEndpoint != ""). Msg("Onboarding token detected - starting edge onboarding") // Note: KVEndpoint is no longer required for SaaS mode. // Agents connect to GatewayEndpoint and receive config via GetConfig. // Create bootstrapper b, err := NewBootstrapper(&Config{ Token: token, PackagePath: packagePath, GatewayEndpoint: gatewayEndpoint, KVEndpoint: kvEndpoint, // Optional for legacy/on-prem mode ServiceType: componentType, PackageID: packageID, CoreAPIURL: coreAPIURL, Logger: log, // StoragePath will use default ``` </details> > Learn more about managing compliance <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#configuration-options'>generic rules</a> or creating your own <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#custom-compliance'>custom rules</a> </details></td></tr> <tr><td><details> <summary><strong>Generic: Security-First Input Validation and Data Handling</strong></summary><br> **Objective:** Ensure all data inputs are validated, sanitized, and handled securely to prevent <br>vulnerabilities<br> **Status:** <br><a href='https://github.com/carverauto/serviceradar/pull/2235/files#diff-e0086702d4c86140315e9347dc19ccae52a3eb64b66a15ccfafae8981c7945d8R70-R88'><strong>Endpoint not validated</strong></a>: Environment-provided <code>GATEWAY_ADDR</code> and <code>KV_ENDPOINT</code> values are only trimmed and <br>presence-checked, with no format/allowlist validation to prevent unsafe or unintended <br>endpoint injection/misconfiguration.<br> <details open><summary>Referred Code</summary> ```go token := strings.TrimSpace(os.Getenv("ONBOARDING_TOKEN")) gatewayEndpoint := strings.TrimSpace(os.Getenv("GATEWAY_ADDR")) kvEndpoint := strings.TrimSpace(os.Getenv("KV_ENDPOINT")) packageID := strings.TrimSpace(os.Getenv("EDGE_PACKAGE_ID")) coreAPIURL := strings.TrimSpace(os.Getenv("CORE_API_URL")) packagePath := firstNonEmpty( strings.TrimSpace(os.Getenv("ONBOARDING_PACKAGE")), strings.TrimSpace(os.Getenv("SR_ONBOARDING_PACKAGE")), ) // If no onboarding token, use traditional config if token == "" && packagePath == "" { return nil, nil } // Validate that required endpoints are present for online onboarding if token != "" && packagePath == "" && gatewayEndpoint == "" && kvEndpoint == "" { return nil, ErrEndpointRequired } ``` </details> > Learn more about managing compliance <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#configuration-options'>generic rules</a> or creating your own <a href='https://qodo-merge-docs.qodo.ai/tools/compliance/#custom-compliance'>custom rules</a> </details></td></tr> <tr><td align="center" colspan="2"> - [ ] Update <!-- /compliance --update_compliance=true --> </td></tr></tbody></table> <details><summary>Compliance status legend</summary> 🟢 - Fully Compliant<br> 🟡 - Partial Compliant<br> 🔴 - Not Compliant<br> ⚪ - Requires Further Human Verification<br> 🏷️ - Compliance label<br> </details>
qodo-code-review[bot] commented 2026-01-09 08:34:14 +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/2235#issuecomment-3727785629
Original created: 2026-01-09T08:34:14Z

PR Code Suggestions

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix malformed JSON in chunking

Fix a bug in buildResultsChunks that creates invalid JSON by resetting
deviceCount to 0 within the flush function, ensuring new chunks do not start
with a leading comma.

pkg/sync/service.go [1135-1202]

 func (s *SimpleSyncService) buildResultsChunks(
 	allDeviceUpdates []*models.DeviceUpdate,
 	sequence string,
 ) ([]*proto.ResultsChunk, error) {
 ...
+	flush := func() {
+		if deviceCount == 0 {
+			return
+		}
+		_ = buf.WriteByte(']')
+		payload := make([]byte, buf.Len())
+		copy(payload, buf.Bytes())
+		payloads = append(payloads, payload)
+		buf.Reset()
+		deviceCount = 0
+	}
+
 	for _, device := range allDeviceUpdates {
-		data, err := json.Marshal(device)
-		if err != nil {
-			return nil, fmt.Errorf("failed to marshal device update: %w", err)
-		}
+...
 
-		if buf.Len() == 0 {
-			_ = buf.WriteByte('[')
-		}
-
-		separatorLen := 0
-		if deviceCount > 0 {
-			separatorLen = 1
-		}
-
-		projectedLen := buf.Len() + separatorLen + len(data) + 1
-		if deviceCount > 0 && projectedLen > maxChunkSize {
-			flush()
-			_ = buf.WriteByte('[')
-			separatorLen = 0
-		}
-
-		if separatorLen == 1 {
-			_ = buf.WriteByte(',')
-		}
-
-		_, _ = buf.Write(data)
-		deviceCount++
-	}
-...
-}
-

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a critical bug that would produce malformed JSON, causing data processing to fail. The proposed fix is accurate and necessary for the feature's correctness.

High
Prevent data race on config
Suggestion Impact:The commit updates `createIntegration` to accept a `partition` argument and updates all call sites to read `Partition` under the config lock (or from `newCfg`) and pass it in, eliminating the need to access `s.config.Partition` inside `createIntegration` without synchronization. It also adds fallback logic to use "default" when the passed partition is empty.

code diff:

@@ -387,10 +387,11 @@
 	// Use fallback values from the new config being applied.
 	agentID := newCfg.AgentID
 	gatewayID := newCfg.GatewayID
+	partition := newCfg.Partition
 	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, agentID, gatewayID)
+			s.sources[name] = s.createIntegration(s.ctx, src, f, agentID, gatewayID, partition)
 		}
 	}
 	if intervalsChanged {
@@ -835,6 +836,7 @@
 	s.configMu.RLock()
 	agentID := s.config.AgentID
 	partition := s.config.Partition
+	gatewayID := s.config.GatewayID
 	s.configMu.RUnlock()
 
 	req := &proto.AgentHelloRequest{
@@ -1026,9 +1028,11 @@
 }
 
 func (s *SimpleSyncService) heartbeatLoop(ctx context.Context) error {
-	if err := s.pushHeartbeat(ctx); err != nil {
+	heartbeatCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
+	if err := s.pushHeartbeat(heartbeatCtx); err != nil && !errors.Is(err, context.Canceled) {
 		s.logger.Error().Err(err).Msg("Failed to push sync heartbeat")
 	}
+	cancel()
 
 	timer := time.NewTimer(s.getHeartbeatInterval())
 	defer timer.Stop()
@@ -1242,7 +1246,7 @@
 			ServiceType:  syncServiceType,
 			ResponseTime: 0,
 			AgentId:      agentID,
-			GatewayId:    "",
+			GatewayId:    gatewayID,
 			Partition:    partition,
 			Source:       syncResultsSource,
 			KvStoreId:    "",
@@ -1413,6 +1417,7 @@
 	// access config consistently for future-proofing.
 	agentID := s.config.AgentID
 	gatewayID := s.config.GatewayID
+	partition := s.config.Partition
 
 	for name, src := range s.config.Sources {
 		factory, ok := s.registry[src.Type]
@@ -1421,7 +1426,7 @@
 			continue
 		}
 
-		s.sources[name] = s.createIntegration(ctx, src, factory, agentID, gatewayID)
+		s.sources[name] = s.createIntegration(ctx, src, factory, agentID, gatewayID, partition)
 	}
 }
 
@@ -1438,6 +1443,7 @@
 	s.configMu.RLock()
 	agentID := s.config.AgentID
 	gatewayID := s.config.GatewayID
+	partition := s.config.Partition
 	s.configMu.RUnlock()
 
 	// Detect interval changes and reset timers for affected sources
@@ -1455,7 +1461,7 @@
 				continue
 			}
 
-			integrations[name] = s.createIntegration(s.ctx, src, factory, agentID, gatewayID)
+			integrations[name] = s.createIntegration(s.ctx, src, factory, agentID, gatewayID, partition)
 		}
 
 		if len(integrations) == 0 {
@@ -1772,13 +1778,13 @@
 }
 
 // createIntegration creates a single integration instance.
-// agentID and gatewayID are fallback values if not set in src.
+// agentID, gatewayID, and partition are fallback values if not set in src.
 // Callers must ensure these values are obtained under proper synchronization.
 func (s *SimpleSyncService) createIntegration(
 	ctx context.Context,
 	src *models.SourceConfig,
 	factory IntegrationFactory,
-	agentID, gatewayID string,
+	agentID, gatewayID, partition string,
 ) Integration {
 	cfgCopy := *src
 	if cfgCopy.AgentID == "" {
@@ -1790,7 +1796,11 @@
 	}
 
 	if cfgCopy.Partition == "" {
-		cfgCopy.Partition = "default"
+		if partition != "" {
+			cfgCopy.Partition = partition
+		} else {
+			cfgCopy.Partition = "default"
+		}
 	}

To prevent a data race, pass the partition value as an argument to the
createIntegration function instead of accessing the shared s.config.Partition
field directly without a lock.

pkg/sync/service.go [1774-1797]

 // createIntegration creates a single integration instance.
-// agentID and gatewayID are fallback values if not set in src.
+// agentID, gatewayID, and partition are fallback values if not set in src.
 // Callers must ensure these values are obtained under proper synchronization.
 func (s *SimpleSyncService) createIntegration(
 	ctx context.Context,
 	src *models.SourceConfig,
 	factory IntegrationFactory,
-	agentID, gatewayID string,
+	agentID, gatewayID, partition string,
 ) Integration {
 	cfgCopy := *src
 	if cfgCopy.AgentID == "" {
 		cfgCopy.AgentID = agentID
 	}
 
 	if cfgCopy.GatewayID == "" {
 		cfgCopy.GatewayID = gatewayID
 	}
 
 	if cfgCopy.Partition == "" {
-		cfgCopy.Partition = s.config.Partition
+		cfgCopy.Partition = partition
 	}
 
 	return factory(ctx, &cfgCopy, s.metrics, s.logger)
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a potential data race when accessing s.config.Partition without a lock. Fixing this is crucial for concurrent safety and preventing unpredictable behavior or crashes.

Medium
Prevent goroutine leak on shutdown
Suggestion Impact:The select in flushGatewayStatusUpdates was updated to include a case for <-s.ShutdownChan (and an explicit return on ctx.Done), ensuring the goroutine terminates cleanly during shutdown.

code diff:

@@ -166,6 +166,8 @@
 	for {
 		select {
 		case <-ctx.Done():
+			return
+		case <-s.ShutdownChan:
 			return

Add a case for s.ShutdownChan in the select statement within
flushGatewayStatusUpdates to prevent a goroutine leak on server shutdown.

pkg/core/gateways.go [161-204]

 func (s *Server) flushGatewayStatusUpdates(ctx context.Context) {
 	interval := s.gatewayStatusIntervalOrDefault()
 	ticker := time.NewTicker(interval)
 	defer ticker.Stop()
 
 	for {
 		select {
 		case <-ctx.Done():
+			return
+		case <-s.ShutdownChan:
 			return
 		case <-ticker.C:
 			s.gatewayStatusUpdateMutex.Lock()
 			updates := s.gatewayStatusUpdates
 
 			s.gatewayStatusUpdates = make(map[string]*models.GatewayStatus)
 			s.gatewayStatusUpdateMutex.Unlock()
 
 			if len(updates) == 0 {
 				continue
 			}
 ...
 		}
 	}
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: This suggestion correctly identifies a goroutine leak in flushGatewayStatusUpdates due to a missing shutdown channel case. Adding a case for s.ShutdownChan is critical for ensuring graceful server shutdown and preventing resource leaks, which is a significant correctness and reliability issue.

Medium
Prevent goroutine leak in heartbeat
Suggestion Impact:The initial heartbeat call in heartbeatLoop was modified to use a 15s timeout context, reducing the risk of hanging indefinitely on startup. However, it was not moved into a separate goroutine, so the loop can still block until the initial heartbeat returns (up to the timeout).

code diff:

 func (s *SimpleSyncService) heartbeatLoop(ctx context.Context) error {
-	if err := s.pushHeartbeat(ctx); err != nil {
+	heartbeatCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
+	if err := s.pushHeartbeat(heartbeatCtx); err != nil && !errors.Is(err, context.Canceled) {
 		s.logger.Error().Err(err).Msg("Failed to push sync heartbeat")
 	}
+	cancel()
 

To prevent the heartbeatLoop from blocking on startup, run the initial heartbeat
call in a non-blocking goroutine with a separate, short-lived context.

pkg/sync/service.go [1028-1047]

 func (s *SimpleSyncService) heartbeatLoop(ctx context.Context) error {
-	if err := s.pushHeartbeat(ctx); err != nil {
-		s.logger.Error().Err(err).Msg("Failed to push sync heartbeat")
-	}
+	go func() {
+		// Run initial heartbeat in a goroutine to avoid blocking the loop start.
+		// Use a short timeout to prevent it from hanging indefinitely.
+		hCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
+		defer cancel()
+		if err := s.pushHeartbeat(hCtx); err != nil {
+			s.logger.Error().Err(err).Msg("Failed to push initial sync heartbeat")
+		}
+	}()
 
 	timer := time.NewTimer(s.getHeartbeatInterval())
 	defer timer.Stop()
 
 	for {
 		select {
 		case <-ctx.Done():
 			return ctx.Err()
 		case <-timer.C:
 			if err := s.pushHeartbeat(ctx); err != nil {
 				s.logger.Error().Err(err).Msg("Failed to push sync heartbeat")
 			}
 			timer.Reset(s.getHeartbeatInterval())
 		}
 	}
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that a blocking initial heartbeat can prevent the main loop from starting, improving the service's robustness against network issues during startup.

Medium
Return errors from Armis updates

Modify runArmisUpdates to return the collected updateErrors instead of nil, so
that failures are propagated to the caller.

pkg/sync/service.go [687-701]

 func (s *SimpleSyncService) runArmisUpdates(ctx context.Context) error {
     s.logger.Info().Msg("Starting Armis update cycle")
+    var updateErrors []error
 
     tenantIntegrations := s.snapshotTenantIntegrations()
     if len(tenantIntegrations) == 0 {
         sourcesSnapshot := s.snapshotLegacySources()
         updateErrors = append(updateErrors, s.runArmisUpdatesForIntegrations(ctx, "", sourcesSnapshot)...)
     } else {
         for tenantID, integrations := range tenantIntegrations {
             updateErrors = append(updateErrors, s.runArmisUpdatesForIntegrations(ctx, tenantID, integrations)...)
         }
     }
 
+    if len(updateErrors) > 0 {
+        return fmt.Errorf("armis update completed with %d errors: %w", len(updateErrors), errors.Join(updateErrors...))
+    }
     return nil
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that runArmisUpdates swallows errors, preventing callers from knowing if the operation failed. Returning the aggregated errors is crucial for proper error handling and observability.

Medium
General
Include GatewayId in status
Suggestion Impact:The commit now reads gatewayID from s.config and sets GatewayServiceStatus.GatewayId to that value (replacing the previous empty string), ensuring status messages include the configured gateway ID.

code diff:

 	s.configMu.RLock()
 	agentID := s.config.AgentID
 	partition := s.config.Partition
+	gatewayID := s.config.GatewayID
 	s.configMu.RUnlock()
 
 	req := &proto.AgentHelloRequest{
@@ -1026,9 +1028,11 @@
 }
 
 func (s *SimpleSyncService) heartbeatLoop(ctx context.Context) error {
-	if err := s.pushHeartbeat(ctx); err != nil {
+	heartbeatCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
+	if err := s.pushHeartbeat(heartbeatCtx); err != nil && !errors.Is(err, context.Canceled) {
 		s.logger.Error().Err(err).Msg("Failed to push sync heartbeat")
 	}
+	cancel()
 
 	timer := time.NewTimer(s.getHeartbeatInterval())
 	defer timer.Stop()
@@ -1242,7 +1246,7 @@
 			ServiceType:  syncServiceType,
 			ResponseTime: 0,
 			AgentId:      agentID,
-			GatewayId:    "",
+			GatewayId:    gatewayID,
 			Partition:    partition,

Populate the GatewayId field in the GatewayServiceStatus struct using the
GatewayID from the service configuration instead of leaving it as an empty
string.

pkg/sync/service.go [1238-1251]

+s.configMu.RLock()
+gatewayID := s.config.GatewayID
+s.configMu.RUnlock()
 status := &proto.GatewayServiceStatus{
     ServiceName:  syncServiceName,
     Available:    true,
     Message:      chunk.Data,
     ServiceType:  syncServiceType,
     ResponseTime: 0,
     AgentId:      agentID,
-    GatewayId:    "",
+    GatewayId:    gatewayID,
     Partition:    partition,
     Source:       syncResultsSource,
     KvStoreId:    "",
     TenantId:     tenantID,
     TenantSlug:   tenantSlug,
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies that GatewayId is being left empty. Populating it from the configuration improves the completeness of status messages, which can be important for routing or debugging on the server side.

Low
  • Update
Imported GitHub PR comment. Original author: @qodo-code-review[bot] Original URL: https://github.com/carverauto/serviceradar/pull/2235#issuecomment-3727785629 Original created: 2026-01-09T08:34:14Z --- ## PR Code Suggestions ✨ <!-- 4f0344c --> Explore these optional code suggestions: <table><thead><tr><td><strong>Category</strong></td><td align=left><strong>Suggestion&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </strong></td><td align=center><strong>Impact</strong></td></tr><tbody><tr><td rowspan=5>Possible issue</td> <td> <details><summary>Fix malformed JSON in chunking</summary> ___ **Fix a bug in <code>buildResultsChunks</code> that creates invalid JSON by resetting <br><code>deviceCount</code> to 0 within the <code>flush</code> function, ensuring new chunks do not start <br>with a leading comma.** [pkg/sync/service.go [1135-1202]](https://github.com/carverauto/serviceradar/pull/2235/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7eR1135-R1202) ```diff func (s *SimpleSyncService) buildResultsChunks( allDeviceUpdates []*models.DeviceUpdate, sequence string, ) ([]*proto.ResultsChunk, error) { ... + flush := func() { + if deviceCount == 0 { + return + } + _ = buf.WriteByte(']') + payload := make([]byte, buf.Len()) + copy(payload, buf.Bytes()) + payloads = append(payloads, payload) + buf.Reset() + deviceCount = 0 + } + for _, device := range allDeviceUpdates { - data, err := json.Marshal(device) - if err != nil { - return nil, fmt.Errorf("failed to marshal device update: %w", err) - } +... - if buf.Len() == 0 { - _ = buf.WriteByte('[') - } - - separatorLen := 0 - if deviceCount > 0 { - separatorLen = 1 - } - - projectedLen := buf.Len() + separatorLen + len(data) + 1 - if deviceCount > 0 && projectedLen > maxChunkSize { - flush() - _ = buf.WriteByte('[') - separatorLen = 0 - } - - if separatorLen == 1 { - _ = buf.WriteByte(',') - } - - _, _ = buf.Write(data) - deviceCount++ - } -... -} - ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 9</summary> __ Why: This suggestion correctly identifies a critical bug that would produce malformed JSON, causing data processing to fail. The proposed fix is accurate and necessary for the feature's correctness. </details></details></td><td align=center>High </td></tr><tr><td> <details><summary>✅ <s>Prevent data race on config</s></summary> ___ <details><summary><b>Suggestion Impact:</b></summary>The commit updates `createIntegration` to accept a `partition` argument and updates all call sites to read `Partition` under the config lock (or from `newCfg`) and pass it in, eliminating the need to access `s.config.Partition` inside `createIntegration` without synchronization. It also adds fallback logic to use "default" when the passed partition is empty. code diff: ```diff @@ -387,10 +387,11 @@ // Use fallback values from the new config being applied. agentID := newCfg.AgentID gatewayID := newCfg.GatewayID + partition := newCfg.Partition 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, agentID, gatewayID) + s.sources[name] = s.createIntegration(s.ctx, src, f, agentID, gatewayID, partition) } } if intervalsChanged { @@ -835,6 +836,7 @@ s.configMu.RLock() agentID := s.config.AgentID partition := s.config.Partition + gatewayID := s.config.GatewayID s.configMu.RUnlock() req := &proto.AgentHelloRequest{ @@ -1026,9 +1028,11 @@ } func (s *SimpleSyncService) heartbeatLoop(ctx context.Context) error { - if err := s.pushHeartbeat(ctx); err != nil { + heartbeatCtx, cancel := context.WithTimeout(ctx, 15*time.Second) + if err := s.pushHeartbeat(heartbeatCtx); err != nil && !errors.Is(err, context.Canceled) { s.logger.Error().Err(err).Msg("Failed to push sync heartbeat") } + cancel() timer := time.NewTimer(s.getHeartbeatInterval()) defer timer.Stop() @@ -1242,7 +1246,7 @@ ServiceType: syncServiceType, ResponseTime: 0, AgentId: agentID, - GatewayId: "", + GatewayId: gatewayID, Partition: partition, Source: syncResultsSource, KvStoreId: "", @@ -1413,6 +1417,7 @@ // access config consistently for future-proofing. agentID := s.config.AgentID gatewayID := s.config.GatewayID + partition := s.config.Partition for name, src := range s.config.Sources { factory, ok := s.registry[src.Type] @@ -1421,7 +1426,7 @@ continue } - s.sources[name] = s.createIntegration(ctx, src, factory, agentID, gatewayID) + s.sources[name] = s.createIntegration(ctx, src, factory, agentID, gatewayID, partition) } } @@ -1438,6 +1443,7 @@ s.configMu.RLock() agentID := s.config.AgentID gatewayID := s.config.GatewayID + partition := s.config.Partition s.configMu.RUnlock() // Detect interval changes and reset timers for affected sources @@ -1455,7 +1461,7 @@ continue } - integrations[name] = s.createIntegration(s.ctx, src, factory, agentID, gatewayID) + integrations[name] = s.createIntegration(s.ctx, src, factory, agentID, gatewayID, partition) } if len(integrations) == 0 { @@ -1772,13 +1778,13 @@ } // createIntegration creates a single integration instance. -// agentID and gatewayID are fallback values if not set in src. +// agentID, gatewayID, and partition are fallback values if not set in src. // Callers must ensure these values are obtained under proper synchronization. func (s *SimpleSyncService) createIntegration( ctx context.Context, src *models.SourceConfig, factory IntegrationFactory, - agentID, gatewayID string, + agentID, gatewayID, partition string, ) Integration { cfgCopy := *src if cfgCopy.AgentID == "" { @@ -1790,7 +1796,11 @@ } if cfgCopy.Partition == "" { - cfgCopy.Partition = "default" + if partition != "" { + cfgCopy.Partition = partition + } else { + cfgCopy.Partition = "default" + } } ``` </details> ___ **To prevent a data race, pass the <code>partition</code> value as an argument to the <br><code>createIntegration</code> function instead of accessing the shared <code>s.config.Partition</code> <br>field directly without a lock.** [pkg/sync/service.go [1774-1797]](https://github.com/carverauto/serviceradar/pull/2235/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7eR1774-R1797) ```diff // createIntegration creates a single integration instance. -// agentID and gatewayID are fallback values if not set in src. +// agentID, gatewayID, and partition are fallback values if not set in src. // Callers must ensure these values are obtained under proper synchronization. func (s *SimpleSyncService) createIntegration( ctx context.Context, src *models.SourceConfig, factory IntegrationFactory, - agentID, gatewayID string, + agentID, gatewayID, partition string, ) Integration { cfgCopy := *src if cfgCopy.AgentID == "" { cfgCopy.AgentID = agentID } if cfgCopy.GatewayID == "" { cfgCopy.GatewayID = gatewayID } if cfgCopy.Partition == "" { - cfgCopy.Partition = s.config.Partition + cfgCopy.Partition = partition } return factory(ctx, &cfgCopy, s.metrics, s.logger) } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 8</summary> __ Why: The suggestion correctly identifies a potential data race when accessing `s.config.Partition` without a lock. Fixing this is crucial for concurrent safety and preventing unpredictable behavior or crashes. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>✅ <s>Prevent goroutine leak on shutdown</s></summary> ___ <details><summary><b>Suggestion Impact:</b></summary>The select in flushGatewayStatusUpdates was updated to include a case for <-s.ShutdownChan (and an explicit return on ctx.Done), ensuring the goroutine terminates cleanly during shutdown. code diff: ```diff @@ -166,6 +166,8 @@ for { select { case <-ctx.Done(): + return + case <-s.ShutdownChan: return ``` </details> ___ **Add a case for <code>s.ShutdownChan</code> in the <code>select</code> statement within <br><code>flushGatewayStatusUpdates</code> to prevent a goroutine leak on server shutdown.** [pkg/core/gateways.go [161-204]](https://github.com/carverauto/serviceradar/pull/2235/files#diff-260332914ad2238e720f4637a71b0f9f01e899102bc6b37f7827782e56b0b5c0R161-R204) ```diff func (s *Server) flushGatewayStatusUpdates(ctx context.Context) { interval := s.gatewayStatusIntervalOrDefault() ticker := time.NewTicker(interval) defer ticker.Stop() for { select { case <-ctx.Done(): + return + case <-s.ShutdownChan: return case <-ticker.C: s.gatewayStatusUpdateMutex.Lock() updates := s.gatewayStatusUpdates s.gatewayStatusUpdates = make(map[string]*models.GatewayStatus) s.gatewayStatusUpdateMutex.Unlock() if len(updates) == 0 { continue } ... } } } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 8</summary> __ Why: This suggestion correctly identifies a goroutine leak in `flushGatewayStatusUpdates` due to a missing shutdown channel case. Adding a case for `s.ShutdownChan` is critical for ensuring graceful server shutdown and preventing resource leaks, which is a significant correctness and reliability issue. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>✅ <s>Prevent goroutine leak in heartbeat</s></summary> ___ <details><summary><b>Suggestion Impact:</b></summary>The initial heartbeat call in heartbeatLoop was modified to use a 15s timeout context, reducing the risk of hanging indefinitely on startup. However, it was not moved into a separate goroutine, so the loop can still block until the initial heartbeat returns (up to the timeout). code diff: ```diff func (s *SimpleSyncService) heartbeatLoop(ctx context.Context) error { - if err := s.pushHeartbeat(ctx); err != nil { + heartbeatCtx, cancel := context.WithTimeout(ctx, 15*time.Second) + if err := s.pushHeartbeat(heartbeatCtx); err != nil && !errors.Is(err, context.Canceled) { s.logger.Error().Err(err).Msg("Failed to push sync heartbeat") } + cancel() ``` </details> ___ **To prevent the <code>heartbeatLoop</code> from blocking on startup, run the initial heartbeat <br>call in a non-blocking goroutine with a separate, short-lived context.** [pkg/sync/service.go [1028-1047]](https://github.com/carverauto/serviceradar/pull/2235/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7eR1028-R1047) ```diff func (s *SimpleSyncService) heartbeatLoop(ctx context.Context) error { - if err := s.pushHeartbeat(ctx); err != nil { - s.logger.Error().Err(err).Msg("Failed to push sync heartbeat") - } + go func() { + // Run initial heartbeat in a goroutine to avoid blocking the loop start. + // Use a short timeout to prevent it from hanging indefinitely. + hCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + if err := s.pushHeartbeat(hCtx); err != nil { + s.logger.Error().Err(err).Msg("Failed to push initial sync heartbeat") + } + }() timer := time.NewTimer(s.getHeartbeatInterval()) defer timer.Stop() for { select { case <-ctx.Done(): return ctx.Err() case <-timer.C: if err := s.pushHeartbeat(ctx); err != nil { s.logger.Error().Err(err).Msg("Failed to push sync heartbeat") } timer.Reset(s.getHeartbeatInterval()) } } } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly identifies that a blocking initial heartbeat can prevent the main loop from starting, improving the service's robustness against network issues during startup. </details></details></td><td align=center>Medium </td></tr><tr><td> <details><summary>Return errors from Armis updates</summary> ___ **Modify <code>runArmisUpdates</code> to return the collected <code>updateErrors</code> instead of <code>nil</code>, so <br>that failures are propagated to the caller.** [pkg/sync/service.go [687-701]](https://github.com/carverauto/serviceradar/pull/2235/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7eR687-R701) ```diff func (s *SimpleSyncService) runArmisUpdates(ctx context.Context) error { s.logger.Info().Msg("Starting Armis update cycle") + var updateErrors []error tenantIntegrations := s.snapshotTenantIntegrations() if len(tenantIntegrations) == 0 { sourcesSnapshot := s.snapshotLegacySources() updateErrors = append(updateErrors, s.runArmisUpdatesForIntegrations(ctx, "", sourcesSnapshot)...) } else { for tenantID, integrations := range tenantIntegrations { updateErrors = append(updateErrors, s.runArmisUpdatesForIntegrations(ctx, tenantID, integrations)...) } } + if len(updateErrors) > 0 { + return fmt.Errorf("armis update completed with %d errors: %w", len(updateErrors), errors.Join(updateErrors...)) + } return nil } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 7</summary> __ Why: The suggestion correctly points out that `runArmisUpdates` swallows errors, preventing callers from knowing if the operation failed. Returning the aggregated errors is crucial for proper error handling and observability. </details></details></td><td align=center>Medium </td></tr><tr><td rowspan=1>General</td> <td> <details><summary>✅ <s>Include GatewayId in status</s></summary> ___ <details><summary><b>Suggestion Impact:</b></summary>The commit now reads gatewayID from s.config and sets GatewayServiceStatus.GatewayId to that value (replacing the previous empty string), ensuring status messages include the configured gateway ID. code diff: ```diff s.configMu.RLock() agentID := s.config.AgentID partition := s.config.Partition + gatewayID := s.config.GatewayID s.configMu.RUnlock() req := &proto.AgentHelloRequest{ @@ -1026,9 +1028,11 @@ } func (s *SimpleSyncService) heartbeatLoop(ctx context.Context) error { - if err := s.pushHeartbeat(ctx); err != nil { + heartbeatCtx, cancel := context.WithTimeout(ctx, 15*time.Second) + if err := s.pushHeartbeat(heartbeatCtx); err != nil && !errors.Is(err, context.Canceled) { s.logger.Error().Err(err).Msg("Failed to push sync heartbeat") } + cancel() timer := time.NewTimer(s.getHeartbeatInterval()) defer timer.Stop() @@ -1242,7 +1246,7 @@ ServiceType: syncServiceType, ResponseTime: 0, AgentId: agentID, - GatewayId: "", + GatewayId: gatewayID, Partition: partition, ``` </details> ___ **Populate the <code>GatewayId</code> field in the <code>GatewayServiceStatus</code> struct using the <br><code>GatewayID</code> from the service configuration instead of leaving it as an empty <br>string.** [pkg/sync/service.go [1238-1251]](https://github.com/carverauto/serviceradar/pull/2235/files#diff-b4ea5a5b3d811fa94c6a84c71c0ddb920ce177a376d13cb776f05dd6017c4c7eR1238-R1251) ```diff +s.configMu.RLock() +gatewayID := s.config.GatewayID +s.configMu.RUnlock() status := &proto.GatewayServiceStatus{ ServiceName: syncServiceName, Available: true, Message: chunk.Data, ServiceType: syncServiceType, ResponseTime: 0, AgentId: agentID, - GatewayId: "", + GatewayId: gatewayID, Partition: partition, Source: syncResultsSource, KvStoreId: "", TenantId: tenantID, TenantSlug: tenantSlug, } ``` `[To ensure code accuracy, apply this suggestion manually]` <details><summary>Suggestion importance[1-10]: 5</summary> __ Why: The suggestion correctly identifies that `GatewayId` is being left empty. Populating it from the configuration improves the completeness of status messages, which can be important for routing or debugging on the server side. </details></details></td><td align=center>Low </td></tr> <tr><td align="center" colspan="2"> - [ ] Update <!-- /improve_multi --more_suggestions=true --> </td><td></td></tr></tbody></table>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
carverauto/serviceradar!2640
No description provided.