Skip to content

Comments

feat(topology): SNMP LLDP/CDP and NetFlow/IPFIX/sFlow v5 collectors with topology functions#21702

Draft
ktsaou wants to merge 36 commits intonetdata:masterfrom
ktsaou:topology-flows
Draft

feat(topology): SNMP LLDP/CDP and NetFlow/IPFIX/sFlow v5 collectors with topology functions#21702
ktsaou wants to merge 36 commits intonetdata:masterfrom
ktsaou:topology-flows

Conversation

@ktsaou
Copy link
Member

@ktsaou ktsaou commented Feb 4, 2026

Summary

  • Add Layer 2 topology discovery via SNMP LLDP-MIB and CISCO-CDP-MIB
  • Add Layer 3 flow collection via NetFlow v5/v9, IPFIX, and sFlow v5
  • Add topology functions (topology and flows) for dashboard integration
  • Add CLI tool for aggregating topology/flows from multiple agents (prototype for cloud service)
  • Comprehensive test coverage with real vendor data

Milestone 1: Data Collection ✅

This PR completes Milestone 1 — collecting topology and flow data at the agent level.

SNMP Topology (L2)

  • LLDP-MIB (IEEE 802.1AB) neighbor discovery with management addresses and capabilities
  • CISCO-CDP-MIB neighbor discovery with full cache fields
  • Topology cache tracking local device, ports, and remote neighbors
  • topology function returning JSON with devices and links

NetFlow Collector (L3)

  • NetFlow v5 and v9 decoding
  • IPFIX template-based decoding
  • sFlow v5 sample parsing
  • Flow aggregation by src/dst IP, port, protocol
  • flows function returning top talkers with bytes/packets/connections
  • Per-exporter and per-interface metrics

Aggregation Tool

  • CLI tool topology-flow-merge that aggregates topology/flows from multiple Netdata agents
  • Prototype for the cloud aggregation service
  • Will be adapted to the unified schema in Milestone 2

Testing

  • 116 snmprec fixtures from LibreNMS covering 50+ vendors (Cisco, Arista, Juniper, Fortinet, D-Link, etc.)
  • 36 pcap files from Akvorado covering NetFlow/IPFIX/sFlow edge cases
  • Unit tests validate ALL fixtures and pcaps
  • Integration tests with snmpsim and live UDP replay
  • CI workflow for simulator-based testing

Roadmap

Milestone Description Status
1. Data Collection SNMP topology + NetFlow/sFlow at agent level ✅ This PR
2. Unified Schema Single multi-layered topology schema (L2-L7) covering SNMP, NetFlow, network-viewer, streaming 🔜 Next
3. Cloud Aggregation Adapt topology-flow-merge tool into cloud service endpoint 📋 Planned
4. Visualization Multi-layered, overlayed topology visualization in dashboard 📋 Planned

Test plan

  • go test ./plugin/go.d/collector/snmp/... — all LLDP/CDP tests pass
  • go test ./plugin/go.d/collector/netflow/... — all flow decoder tests pass
  • Integration tests with snmpsim validate live SNMP queries
  • Integration tests replay pcaps to live NetFlow collector
  • Manual testing with real network devices
  • Cloud integration testing for topology visualization

Summary by cubic

Adds SNMP LLDP/CDP L2 and expanded OSPF/ISIS L3 topology via a new Go topology engine, live L7 topology from local sockets, and a Rust NetFlow/IPFIX/sFlow collector with journal-backed storage and fast multi-file queries. Updates CI, function API, and packaging to ship the netflow plugin and new journal tools.

  • New Features

    • SNMP topology: cached L2 with device/link charts, optional autoprobe, CI simulator tests, parity tooling; adds Enlinkd-parity bridge-domain model and L2 pipeline with root bridge/segment assembly; L3 pairing expanded with engine-based node/topology helpers and tests.
    • Network Viewer (L7): new topology:network-viewer function using schema v2.0.
    • NetFlow plugin (Rust): UDP decoders (v5/v7/v9, IPFIX, sFlow v5), tiered storage (raw/1m/5m/1h), query facets/projection, optional SRv6/VXLAN decap, dynamic routing enrichment (BioRIS/BMP), flows:netflow. Journal-session enables multi-file queries; safe timestamp overrides with monotonic floor and restart seeding; fail-fast ingest guard. Packaged as a separate component with netflow.yaml. Adds jctl CLI for journal inspection.
    • Function API/runtime: non-table response type, field projection, strict __job validation, key=value args, agent-wide method support, and topology alias registration.
  • Migration

    • NetFlow: enable plugin (ENABLE_PLUGIN_NETFLOW or installer flags), open UDP 2055, configure /etc/netdata/netflow.yaml; data under /var/cache/netdata/flows/{raw,1m,5m,1h}.
    • SNMP: topology.autoprobe defaults on; call topology:snmp for L2/L3 outputs.
    • Network Viewer: no config; call topology:network-viewer for live L7 topology.

Written for commit 28c7a6e. Summary will update on new commits.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 218 files

Confidence score: 3/5

  • The maxBuckets cap in src/go/plugin/go.d/collector/netflow/flow_aggregator.go can be bypassed for older buckets, risking unbounded map growth and memory pressure.
  • src/go/plugin/go.d/collector/netflow/collector.go ignores caller contexts in Init/Cleanup, so framework cancellation/timeout may not propagate, impacting shutdown reliability.
  • Score reflects concrete behavioral risks (resource growth and shutdown propagation), though fixes are localized.
  • Pay close attention to src/go/plugin/go.d/collector/netflow/flow_aggregator.go, src/go/plugin/go.d/collector/netflow/collector.go - bucket limit enforcement and context propagation.

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/go/plugin/go.d/collector/netflow/collector.go">

<violation number="1" location="src/go/plugin/go.d/collector/netflow/collector.go:117">
P2: Init discards the caller context and always uses context.Background(), so module cancellation from the framework won't propagate to the collector goroutines.</violation>

<violation number="2" location="src/go/plugin/go.d/collector/netflow/collector.go:158">
P2: Cleanup ignores the caller’s context and uses context.Background(), which can block shutdowns when the framework expects cancellation/timeout to be honored.</violation>
</file>

<file name="src/go/plugin/go.d/collector/netflow/flow_aggregator.go">

<violation number="1" location="src/go/plugin/go.d/collector/netflow/flow_aggregator.go:255">
P2: maxBuckets enforcement can fail when the incoming bucket is older than all existing buckets, allowing the map to exceed the configured limit.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@github-actions github-actions bot added area/packaging Packaging and operating systems support area/build Build system (autotools and cmake). collectors/systemd-journal labels Feb 8, 2026
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 128 files (changes from recent commits).

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/crates/netdata-netflow/netflow-plugin/src/network_sources.rs">

<violation number="1" location="src/crates/netdata-netflow/netflow-plugin/src/network_sources.rs:178">
P2: Silent failure on lock poisoning: if `state.by_source.write()` fails due to lock poisoning, records are silently dropped without logging. Consider at minimum logging a warning when the lock cannot be acquired.</violation>
</file>

<file name="src/crates/netdata-netflow/netflow-plugin/src/plugin_config.rs">

<violation number="1" location="src/crates/netdata-netflow/netflow-plugin/src/plugin_config.rs:984">
P2: The gRPC address validation only checks for any ':' when no scheme is provided, so IPv6 literals without a port pass validation even though the error message requires host:port. This lets invalid configs through and will fail later at connection time.</violation>
</file>

<file name="src/go/plugin/go.d/collector/snmp/topology_cache_test.go">

<violation number="1" location="src/go/plugin/go.d/collector/snmp/topology_cache_test.go:203">
P3: The helper treats any non-nil attribute type as a valid non-empty list, so the test can pass even when the attribute is the wrong type or empty. To keep the test meaningful, only return true for non-empty list types and treat unknown types as missing.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@vkalintiris
Copy link
Contributor

@ktsaou you have to rebase the branch. This will bring in #21723 which changed the way plugins can register/call functions.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/web/api/functions/function-streaming.c">

<violation number="1" location="src/web/api/functions/function-streaming.c:18">
P1: Avoid unbounded variable-length stack allocations from the user-controlled `function` string; a large request can exhaust the stack and crash the agent. Use a bounded buffer with a length check or heap allocation with proper cleanup.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Add optional entry timestamp overrides while preserving strict monotonic ordering (last + 1us floor) for realtime and monotonic values.

Seed monotonic baseline from journal tail on startup (same boot only) so override writes remain monotonic across process restarts.

Keep existing write_entry() behavior unchanged and cover new behavior with integration tests.
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 2 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/go/plugin/go.d/collector/snmp/integrations/snmp_devices.md">

<violation number="1" location="src/go/plugin/go.d/collector/snmp/integrations/snmp_devices.md:208">
P2: The security description for `Snmp:topology` incorrectly claims it only exposes interface names and traffic counters, but this function returns LLDP/CDP topology data (devices, links, management addresses). This is misleading for users reading the documentation.</violation>

<violation number="2" location="src/go/plugin/go.d/collector/snmp/integrations/snmp_devices.md:209">
P2: The availability description references interface data caching instead of LLDP/CDP topology data, which doesn’t match this function’s purpose. It should reference topology cache readiness.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 10 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/crates/journalctl/src/main.rs">

<violation number="1" location="src/crates/journalctl/src/main.rs:152">
P2: Guard against relative times that underflow the UNIX epoch; the current subtraction can go negative and wrap when cast to u64.</violation>
</file>

<file name="src/crates/journal-session/src/cursor.rs">

<violation number="1" location="src/crates/journal-session/src/cursor.rs:103">
P2: Broken rustdoc intra-doc link: `Cursor::fields` does not exist. The method is `payloads()`, so the link target should be `Cursor::payloads`.</violation>

<violation number="2" location="src/crates/journal-session/src/cursor.rs:475">
P2: This `expect()` panics in library code, which violates the project convention ("Avoid panics in library paths; return typed errors instead"). Additionally, the panic message references `fields()` but the method is named `payloads()`. Return a typed `SessionError` variant instead.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

};

let now = chrono::Utc::now().timestamp_micros();
return Ok((now - offset_usec) as u64);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Guard against relative times that underflow the UNIX epoch; the current subtraction can go negative and wrap when cast to u64.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/crates/journalctl/src/main.rs, line 152:

<comment>Guard against relative times that underflow the UNIX epoch; the current subtraction can go negative and wrap when cast to u64.</comment>

<file context>
@@ -0,0 +1,432 @@
+        };
+
+        let now = chrono::Utc::now().timestamp_micros();
+        return Ok((now - offset_usec) as u64);
+    }
+
</file context>
Fix with Cubic

///
/// Must be called after [`step()`](Cursor::step) returns `true`.
pub fn payloads(&mut self) -> Result<Payloads<'_>, SessionError> {
let entry_offset = self.entry_offset.expect("fields() called without step()");
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This expect() panics in library code, which violates the project convention ("Avoid panics in library paths; return typed errors instead"). Additionally, the panic message references fields() but the method is named payloads(). Return a typed SessionError variant instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/crates/journal-session/src/cursor.rs, line 475:

<comment>This `expect()` panics in library code, which violates the project convention ("Avoid panics in library paths; return typed errors instead"). Additionally, the panic message references `fields()` but the method is named `payloads()`. Return a typed `SessionError` variant instead.</comment>

<file context>
@@ -0,0 +1,517 @@
+    ///
+    /// Must be called after [`step()`](Cursor::step) returns `true`.
+    pub fn payloads(&mut self) -> Result<Payloads<'_>, SessionError> {
+        let entry_offset = self.entry_offset.expect("fields() called without step()");
+        let jf = self.journal_file.as_ref().unwrap();
+        let iter = jf.entry_data_objects(entry_offset)?;
</file context>
Fix with Cubic

journal-session provides a cursor-based API for iterating journal entries
across multiple files. Files are discovered, sorted, and traversed
sequentially with transparent cross-file transitions. The two-phase
iteration API (step() + payloads()) returns raw data object payloads as
byte slices, letting callers pay only for the fields they need.

Key features:
- CursorBuilder with match filters, time bounds (since/until), direction
- Binary search on archived file timestamps to skip irrelevant files
- Error recovery: bad files are skipped, caller can retry
- Lending iterator (Payloads) with internal decompression buffer reuse

jctl is a journalctl-like CLI built on journal-session:
- Scans /var/log/journal by default, or use --directory/-D, --file
- Supports --since/--until with absolute, relative ("1 day ago"), and
  symbolic (today, yesterday, now) timestamps
- Match filters (FIELD=VALUE), --grep, --priority
- Output formats: short, verbose, json, cat
- Single-file introspection: --header, --fields, -F

journal-core changes:
- Re-export EntryDataIterator for external field iteration
- Add JournalReader::build_filter() to extract FilterExpr for use
  with JournalCursor directly
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 9 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/go/plugin/go.d/agent/jobmgr/manager.go">

<violation number="1" location="src/go/plugin/go.d/agent/jobmgr/manager.go:174">
P2: The new topology alias registration isn't mirrored in cleanup; `topology:*` aliases remain registered after shutdown, leaving stale handlers if the manager is re-initialized. Add corresponding unregistration for the alias names.</violation>
</file>

<file name="src/go/plugin/go.d/collector/snmp/ddsnmp/ddsnmpcollector/collector_table.go">

<violation number="1" location="src/go/plugin/go.d/collector/snmp/ddsnmp/ddsnmpcollector/collector_table.go:330">
P1: Caching auxiliary tables (tables with no symbols, used only for cross-table tags) prevents them from being re-walked. However, dependent tables that *do* need walking (e.g., due to cache expiry or first run) rely on `walkedData` to resolve cross-table tags. Since `walkedData` only contains the results of the *current* walk, skipping the auxiliary table means its data is missing from `walkedData`, causing tag resolution to fail for the dependent table.

The fix is to ensure auxiliary tables are always present in `walkedData` when needed. The safest way with the current architecture is to NOT cache them (remove the `cacheData` call), forcing them to be walked every cycle. Alternatively, the cross-table resolution logic would need to be updated to fallback to reading from the cache.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

// We still cache their presence so they are not re-walked on every cycle.
if len(result.config.Symbols) == 0 {
if result.pdus != nil {
tc.tableCache.cacheData(result.config, nil, nil, nil)
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Caching auxiliary tables (tables with no symbols, used only for cross-table tags) prevents them from being re-walked. However, dependent tables that do need walking (e.g., due to cache expiry or first run) rely on walkedData to resolve cross-table tags. Since walkedData only contains the results of the current walk, skipping the auxiliary table means its data is missing from walkedData, causing tag resolution to fail for the dependent table.

The fix is to ensure auxiliary tables are always present in walkedData when needed. The safest way with the current architecture is to NOT cache them (remove the cacheData call), forcing them to be walked every cycle. Alternatively, the cross-table resolution logic would need to be updated to fallback to reading from the cache.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/go/plugin/go.d/collector/snmp/ddsnmp/ddsnmpcollector/collector_table.go, line 330:

<comment>Caching auxiliary tables (tables with no symbols, used only for cross-table tags) prevents them from being re-walked. However, dependent tables that *do* need walking (e.g., due to cache expiry or first run) rely on `walkedData` to resolve cross-table tags. Since `walkedData` only contains the results of the *current* walk, skipping the auxiliary table means its data is missing from `walkedData`, causing tag resolution to fail for the dependent table.

The fix is to ensure auxiliary tables are always present in `walkedData` when needed. The safest way with the current architecture is to NOT cache them (remove the `cacheData` call), forcing them to be walked every cycle. Alternatively, the cross-table resolution logic would need to be updated to fallback to reading from the cache.</comment>

<file context>
@@ -322,12 +322,43 @@ func (tc *tableCollector) buildTableNameMap(walkResults []tableWalkResult) map[s
+	// We still cache their presence so they are not re-walked on every cycle.
+	if len(result.config.Symbols) == 0 {
+		if result.pdus != nil {
+			tc.tableCache.cacheData(result.config, nil, nil, nil)
+		} else if tc.tableCache.isConfigCached(result.config) {
+			stats.SNMP.TablesCached++
</file context>
Fix with Cubic

// Register default module-scoped function name.
funcNames := []string{fmt.Sprintf("%s:%s", name, method.ID)}
// Topology methods may also be exposed with topology:* aliases for UI grouping.
if method.ResponseType == "topology" && strings.HasPrefix(method.ID, "topology:") {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new topology alias registration isn't mirrored in cleanup; topology:* aliases remain registered after shutdown, leaving stale handlers if the manager is re-initialized. Add corresponding unregistration for the alias names.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/go/plugin/go.d/agent/jobmgr/manager.go, line 174:

<comment>The new topology alias registration isn't mirrored in cleanup; `topology:*` aliases remain registered after shutdown, leaving stale handlers if the manager is re-initialized. Add corresponding unregistration for the alias names.</comment>

<file context>
@@ -168,10 +168,13 @@ func (m *Manager) Run(ctx context.Context, in chan []*confgroup.Group) {
+				// Register default module-scoped function name.
+				funcNames := []string{fmt.Sprintf("%s:%s", name, method.ID)}
+				// Topology methods may also be exposed with topology:* aliases for UI grouping.
+				if method.ResponseType == "topology" && strings.HasPrefix(method.ID, "topology:") {
+					funcNames = append(funcNames, method.ID)
+				}
</file context>
Fix with Cubic

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/go/tools/topology-parity-evidence/main.go">

<violation number="1">
P2: Assertion detection uses `rawLine`, so `assert*` tokens in comments or string literals are counted as real assertions, which can inflate the inventory and create false parity gaps. Scan `cleanLine` (the comment/string-stripped version) instead.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@@ -0,0 +1,2806 @@
// SPDX-License-Identifier: GPL-3.0-or-later
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Assertion detection uses rawLine, so assert* tokens in comments or string literals are counted as real assertions, which can inflate the inventory and create false parity gaps. Scan cleanLine (the comment/string-stripped version) instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/go/tools/topology-parity-evidence/main.go, line 2286:

<comment>Assertion detection uses `rawLine`, so `assert*` tokens in comments or string literals are counted as real assertions, which can inflate the inventory and create false parity gaps. Scan `cleanLine` (the comment/string-stripped version) instead.</comment>

<file context>
@@ -0,0 +1,2806 @@
+		inBlockComment = nextInBlockComment
+		trimmed := strings.TrimSpace(cleanLine)
+
+		if matches := assertionCallRE.FindAllStringSubmatchIndex(rawLine, -1); len(matches) > 0 {
+			for _, m := range matches {
+				if len(m) < 4 {
</file context>
Fix with Cubic

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 25 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/go/pkg/topology/engine/parity/evidence/office-live-reliability-report.md">

<violation number="1" location="src/go/pkg/topology/engine/parity/evidence/office-live-reliability-report.md:6">
P2: Avoid committing real SNMP community strings in documentation; replace with a redacted placeholder to prevent leaking credentials.</violation>
</file>

<file name="src/go/plugin/go.d/collector/snmp/topology_registry.go">

<violation number="1" location="src/go/plugin/go.d/collector/snmp/topology_registry.go:177">
P2: L3 topology responses skip augmentLocalActorFromCache, so local device attributes (management addresses, capabilities, sys_descr, etc.) are missing compared with L2. Consider augmenting the L3 data before returning.</violation>

<violation number="2" location="src/go/plugin/go.d/collector/snmp/topology_registry.go:182">
P2: Merged topology responses skip augmentLocalActorFromCache, so local device attributes are dropped in the combined L2/L3 output. Consider augmenting the merged data before returning.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

## Scope
- Gate: `T4.5` + `T4.6`
- Office seed: `10.20.4.0/24`
- Community: `atadteN`
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Avoid committing real SNMP community strings in documentation; replace with a redacted placeholder to prevent leaking credentials.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/go/pkg/topology/engine/parity/evidence/office-live-reliability-report.md, line 6:

<comment>Avoid committing real SNMP community strings in documentation; replace with a redacted placeholder to prevent leaking credentials.</comment>

<file context>
@@ -0,0 +1,60 @@
+## Scope
+- Gate: `T4.5` + `T4.6`
+- Office seed: `10.20.4.0/24`
+- Community: `atadteN`
+- Function under validation: `topology:snmp` (`topology_view:l2|l3|merged`)
+
</file context>
Fix with Cubic

Comment on lines +182 to +187
case topologyViewMerged:
data, ok := mergeSNMPTopologyData(l2Data, l2OK, l3Data, l3OK, agentID, collectedAt)
if !ok {
return topologyData{}, false
}
return data, true
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Merged topology responses skip augmentLocalActorFromCache, so local device attributes are dropped in the combined L2/L3 output. Consider augmenting the merged data before returning.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/go/plugin/go.d/collector/snmp/topology_registry.go, line 182:

<comment>Merged topology responses skip augmentLocalActorFromCache, so local device attributes are dropped in the combined L2/L3 output. Consider augmenting the merged data before returning.</comment>

<file context>
@@ -157,6 +166,42 @@ func (r *topologyRegistry) snapshot() (topologyData, bool) {
+			return topologyData{}, false
+		}
+		return l3Data, true
+	case topologyViewMerged:
+		data, ok := mergeSNMPTopologyData(l2Data, l2OK, l3Data, l3OK, agentID, collectedAt)
+		if !ok {
</file context>
Suggested change
case topologyViewMerged:
data, ok := mergeSNMPTopologyData(l2Data, l2OK, l3Data, l3OK, agentID, collectedAt)
if !ok {
return topologyData{}, false
}
return data, true
case topologyViewMerged:
data, ok := mergeSNMPTopologyData(l2Data, l2OK, l3Data, l3OK, agentID, collectedAt)
if !ok {
return topologyData{}, false
}
for _, snapshot := range snapshots {
augmentLocalActorFromCache(&data, snapshot.localDevice)
}
return data, true
Fix with Cubic

Comment on lines +177 to +181
case topologyViewL3:
if !l3OK {
return topologyData{}, false
}
return l3Data, true
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: L3 topology responses skip augmentLocalActorFromCache, so local device attributes (management addresses, capabilities, sys_descr, etc.) are missing compared with L2. Consider augmenting the L3 data before returning.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/go/plugin/go.d/collector/snmp/topology_registry.go, line 177:

<comment>L3 topology responses skip augmentLocalActorFromCache, so local device attributes (management addresses, capabilities, sys_descr, etc.) are missing compared with L2. Consider augmenting the L3 data before returning.</comment>

<file context>
@@ -157,6 +166,42 @@ func (r *topologyRegistry) snapshot() (topologyData, bool) {
+		selectedView = topologyViewL2
+	}
+	switch selectedView {
+	case topologyViewL3:
+		if !l3OK {
+			return topologyData{}, false
</file context>
Suggested change
case topologyViewL3:
if !l3OK {
return topologyData{}, false
}
return l3Data, true
case topologyViewL3:
if !l3OK {
return topologyData{}, false
}
data := l3Data
for _, snapshot := range snapshots {
augmentLocalActorFromCache(&data, snapshot.localDevice)
}
return data, true
Fix with Cubic

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 7 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/go/pkg/topology/engine/topology_adapter.go">

<violation number="1">
P1: Segment actors are always appended to the output regardless of identity-key deduplication. Unlike device and endpoint actors which `continue` (skip) when keys are empty or already present in `actorIndex`, this code only gates `addTopologyIdentityKeys` but not the `append`. This will produce duplicate actors when identity keys overlap.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 12 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="TODO-topology-library-phase2-direct-port.md">

<violation number="1">
P1: Do not commit real SNMP community strings in documentation. Replace `atadteN` with a redacted placeholder (e.g., `<community>`) everywhere it appears to avoid leaking credentials.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@@ -0,0 +1,2276 @@
# TODO-topology-library-phase2-direct-port
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Do not commit real SNMP community strings in documentation. Replace atadteN with a redacted placeholder (e.g., <community>) everywhere it appears to avoid leaking credentials.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At TODO-topology-library-phase2-direct-port.md:

<comment>Do not commit real SNMP community strings in documentation. Replace `atadteN` with a redacted placeholder (e.g., `<community>`) everywhere it appears to avoid leaking credentials.</comment>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/build Build system (autotools and cmake). area/ci area/collectors Everything related to data collection area/docs area/go area/metadata Integrations metadata area/packaging Packaging and operating systems support area/plugins.d area/web collectors/go.d

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants