Skip to content

Commit 0f0202c

Browse files
committed
Fix NetIPC scanner and Go toolchain issues
1 parent c83b182 commit 0f0202c

17 files changed

Lines changed: 311 additions & 34 deletions
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
# SOW-0024 - Netdata PR Scanner And CI Cleanup
2+
3+
## Status
4+
5+
Status: completed
6+
7+
Sub-state: source SDK scanner and Go toolchain fixes implemented, validated, and ready to vendor into Netdata PR 22729.
8+
9+
## Requirements
10+
11+
### Purpose
12+
13+
Keep the NetIPC SDK source authoritative while unblocking the downstream Netdata vendor-update PR from real scanner findings and Go toolchain normalization failures.
14+
15+
### User Request
16+
17+
The user asked to check PR comments and CI failures, then approved:
18+
19+
1. Fix the source plugin-ipc SDK first, push it, then re-vendor into Netdata.
20+
2. Leave the Sonar duplication gate as-is for this iteration.
21+
3. Treat the observed Windows CI failure as unrelated runner/toolchain failure unless later evidence proves a NetIPC-specific failure.
22+
23+
### Assistant Understanding
24+
25+
Facts:
26+
27+
- Netdata PR 22729 had no open GitHub review threads.
28+
- Codacy reported two unused variables in the vendored Windows named-pipe handshake.
29+
- SonarCloud reported two C reliability findings in the vendored apps lookup client and minor Go code-smell findings.
30+
- Netdata Go CI failed because the workflow runs `go fix ./...` and the vendored Go code was not normalized for Netdata's current Go toolchain.
31+
- The observed Windows CI failure happened after NetIPC built and failed because the runner did not have `link.exe` / Visual Studio available.
32+
33+
Inferences:
34+
35+
- Fixing the source SDK avoids a Netdata-only vendored patch that would be overwritten by the next vendor sync.
36+
- The C lookup reliability finding is best addressed by making existing positive-count pointer invariants explicit, not by changing lookup semantics.
37+
- The unused Windows batch variables are stale local computations; the protocol deliberately keeps response batch size symmetric with request batch size.
38+
39+
Unknowns:
40+
41+
- Whether Sonar duplication will still block the downstream PR after these fixes; the user explicitly selected leaving duplication unchanged for this iteration.
42+
43+
### Acceptance Criteria
44+
45+
- Source SDK removes the Codacy unused-variable pattern without changing handshake negotiation semantics.
46+
- Source SDK makes the C lookup client positive-count pointer invariants explicit for apps and cgroups lookup.
47+
- Source SDK Go code is normalized by `go fix ./...`.
48+
- Same-failure scans find no remaining exact patterns from the addressed scanner findings.
49+
- Focused C, Rust, and Go validation passes before committing.
50+
51+
## Analysis
52+
53+
Sources checked:
54+
55+
- `docs/level1-wire-envelope.md`
56+
- `src/libnetdata/netipc/src/transport/windows/netipc_named_pipe.c`
57+
- `src/libnetdata/netipc/src/transport/posix/netipc_uds_handshake.c`
58+
- `src/libnetdata/netipc/src/service/netipc_service_apps_lookup.c`
59+
- `src/libnetdata/netipc/src/service/netipc_service_cgroups_lookup.c`
60+
- `src/go/pkg/netipc/service/raw/apps_lookup.go`
61+
- `src/go/pkg/netipc/service/raw/cgroups_lookup.go`
62+
- `src/go/pkg/netipc/protocol/lookup_guard_test.go`
63+
- `src/go/pkg/netipc/service/raw/lookup_common_test.go`
64+
65+
Current state:
66+
67+
- `docs/level1-wire-envelope.md` specifies request/response batch-item symmetry for the current handshake.
68+
- POSIX C, Rust, and Go handshakes already derive the agreed response batch item count from the client request batch item count.
69+
- C apps and cgroups lookup clients already allocate arrays only for positive logical request counts, but the invariant was implicit inside the batching loop.
70+
- The Go source needed normal Go toolchain rewrites such as integer-range loops, `min`, and `fmt.Appendf`.
71+
72+
Risks:
73+
74+
- Changing handshake negotiation would be a cross-language protocol behavior change. This SOW avoids that.
75+
- Adding an early zero-item shortcut in C could skip endpoint interaction. This SOW avoids that and preserves the existing call flow.
76+
- Go toolchain rewrites are mechanical but touch shared SDK code, so full Go package tests are required.
77+
78+
## Pre-Implementation Gate
79+
80+
Status: ready
81+
82+
Problem / root-cause model:
83+
84+
- The downstream PR exposed three independent cleanup classes:
85+
- stale unused Windows handshake locals;
86+
- implicit C lookup invariants that confused static analysis;
87+
- source not normalized for the downstream Go toolchain's `go fix` step.
88+
89+
Evidence reviewed:
90+
91+
- `docs/level1-wire-envelope.md` records the handshake response-batch symmetry rule.
92+
- POSIX C, Rust, and Go transport code implement the same batch symmetry.
93+
- C lookup code rejects positive counts with null request arrays and allocates item buffers for positive counts before the batching loop.
94+
- Netdata CI log showed `go fix ./...` produced diffs in vendored Go files.
95+
96+
Affected contracts and surfaces:
97+
98+
- Windows C named-pipe server handshake implementation.
99+
- C apps and cgroups lookup client implementations.
100+
- Go protocol/service/transport source formatting and toolchain normalization.
101+
- Downstream Netdata vendored copy after re-vendor.
102+
103+
Existing patterns to reuse:
104+
105+
- Keep handshake response batch size symmetric with request batch size.
106+
- Keep apps and cgroups lookup client logic symmetrical where their flow is equivalent.
107+
- Use `go fix ./...` exactly as downstream CI does.
108+
109+
Risk and blast radius:
110+
111+
- Runtime risk is low because the C handshake edit removes unused locals only.
112+
- Runtime risk is low for lookup invariants because normal positive-count paths already satisfy the new checks.
113+
- Go diffs are mechanical toolchain rewrites; the blast radius is all touched Go SDK packages.
114+
115+
Sensitive data handling plan:
116+
117+
- Do not read `.env` or token files.
118+
- Do not copy secrets, credentials, customer data, private endpoints, personal data, or proprietary operational details into durable artifacts.
119+
- Scanner and CI evidence is summarized by file/rule class only.
120+
121+
Implementation plan:
122+
123+
1. Remove unused Windows handshake batch-default variables while preserving request/response batch symmetry.
124+
2. Add explicit positive-count pointer invariants to C apps and cgroups lookup clients.
125+
3. Run `go fix ./...` and manually remove the exact remaining unnecessary-variable patterns Sonar identified.
126+
4. Validate C, Rust, and Go SDK paths.
127+
128+
Validation plan:
129+
130+
- `go test ./pkg/netipc/...`
131+
- `go fix ./... && git diff --exit-code -- src/go/pkg/netipc`
132+
- `cmake --build build`
133+
- `/usr/bin/ctest --test-dir build --output-on-failure`
134+
- `cargo test`
135+
- Same-failure `rg` scan for the exact fixed patterns.
136+
137+
Artifact impact plan:
138+
139+
- AGENTS.md: no workflow or guardrail change expected.
140+
- Runtime project skills: no reusable workflow change expected.
141+
- Specs: no protocol or public API behavior change expected.
142+
- End-user/operator docs: no operator behavior change expected.
143+
- End-user/operator skills: no output/reference skill change expected.
144+
- SOW lifecycle: complete this narrow SOW in the same commit as the source fixes.
145+
146+
Open-source reference evidence:
147+
148+
- No external open-source references were needed; the authoritative evidence was the local SDK source, docs, and downstream PR feedback.
149+
150+
Open decisions:
151+
152+
- Resolved by the user: fix source first and re-vendor; leave duplication unchanged; treat current Windows failure as unrelated infrastructure.
153+
154+
## Implications And Decisions
155+
156+
1. Source-first fix
157+
158+
- Decision: fix plugin-ipc and re-vendor to Netdata.
159+
- Benefit: keeps the SDK authoritative.
160+
- Risk: requires two commits/pushes, one in the SDK and one downstream.
161+
162+
2. Duplication gate
163+
164+
- Decision: do not change duplication scope or refactor duplicated tests in this iteration.
165+
- Benefit: avoids mixing scanner policy/test refactors into a CI cleanup.
166+
- Risk: downstream Sonar quality gate may still report duplication after these code fixes.
167+
168+
3. Windows CI
169+
170+
- Decision: do not change code or workflow for the observed Windows runner failure.
171+
- Benefit: avoids unrelated infrastructure churn.
172+
- Risk: the downstream PR remains blocked if the runner/toolchain problem persists.
173+
174+
## Plan
175+
176+
1. Patch C scanner findings and Go toolchain normalization in the SDK.
177+
2. Validate source SDK.
178+
3. Commit and push the SDK.
179+
4. Re-vendor the new SDK commit into Netdata PR 22729.
180+
181+
## Execution Log
182+
183+
### 2026-06-15
184+
185+
- Removed unused Windows named-pipe server handshake batch-default variables.
186+
- Added explicit positive-count pointer invariants to C apps and cgroups lookup clients.
187+
- Ran `go fix ./...` in the Go module and kept the generated source rewrites.
188+
- Removed exact remaining unnecessary temporary variables in Go files identified by Sonar.
189+
- Preserved the pre-existing dirty generated benchmark binary as uncommitted local state.
190+
191+
## Validation
192+
193+
Acceptance criteria evidence:
194+
195+
- The Windows handshake now has no `s_req_bat` or `s_resp_bat` locals.
196+
- C lookup positive-count loops now explicitly require non-null request and result storage pointers.
197+
- `go fix ./... && git diff --exit-code -- src/go/pkg/netipc` passed.
198+
199+
Tests or equivalent validation:
200+
201+
- `go test ./pkg/netipc/...` passed.
202+
- `cmake --build build` passed.
203+
- `/usr/bin/ctest --test-dir build --output-on-failure` passed: 48/48 tests.
204+
- `cargo test` in `src/crates/netipc` passed: 375 Rust tests plus binary/doc-test targets.
205+
206+
Real-use evidence:
207+
208+
- Downstream re-vendor and PR CI recheck are handled after this SDK commit; no separate runtime service was started for this source-only cleanup.
209+
210+
Reviewer findings:
211+
212+
- No external reviewer was requested for this narrow scanner/CI cleanup.
213+
214+
Same-failure scan:
215+
216+
- `rg` found no remaining exact occurrences of `s_req_bat`, `s_resp_bat`, the specific `payloadExceededSuffixFits` temporary-variable pattern, or the specific `ensureLookupRequestCapacity` temporary-variable pattern under the touched SDK paths.
217+
218+
Sensitive data gate:
219+
220+
- No `.env`, token files, credentials, customer data, private endpoints, personal data, or proprietary operational details were read or copied into durable artifacts.
221+
222+
Artifact maintenance gate:
223+
224+
- AGENTS.md: no update needed; no workflow or guardrail changed.
225+
- Runtime project skills: no update needed; no reusable workflow changed.
226+
- Specs: no update needed; handshake semantics and lookup API behavior were preserved.
227+
- End-user/operator docs: no update needed; no operator-visible behavior changed.
228+
- End-user/operator skills: no update needed; no output/reference skill changed.
229+
- SOW lifecycle: this SOW is completed and placed under `.agents/sow/done/` in the same commit as the source fixes.
230+
231+
Specs update:
232+
233+
- Not needed; no protocol, wire-format, public API, default, or documented behavior changed.
234+
235+
Project skills update:
236+
237+
- Not needed; no reusable project workflow changed.
238+
239+
End-user/operator docs update:
240+
241+
- Not needed; source cleanup only.
242+
243+
End-user/operator skills update:
244+
245+
- Not needed; no exported/operator skill changed.
246+
247+
Lessons:
248+
249+
- When downstream CI enforces a newer Go toolchain's `go fix`, the source SDK must be normalized before vendoring to avoid recurring downstream-only diffs.
250+
251+
Follow-up mapping:
252+
253+
- Downstream Netdata re-vendor is tracked in Netdata PR 22729 and the Netdata active vendor-update SOW.
254+
255+
## Outcome
256+
257+
Completed.
258+
259+
## Lessons Extracted
260+
261+
- Keep source SDK Go code normalized to the downstream Go toolchain before vendoring into Netdata.
262+
263+
## Followup
264+
265+
None.
266+
267+
## Regression Log
268+
269+
None yet.

‎src/go/pkg/netipc/protocol/apps_lookup.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ func DecodeAppsLookupRequest(buf []byte) (*AppsLookupRequestView, error) {
189189
if err := validateLookupDir(buf, AppsLookupReqHdr, itemCount, len(buf)-dirEnd, 0, AppsLookupKeySize); err != nil {
190190
return nil, err
191191
}
192-
for i := uint32(0); i < itemCount; i++ {
192+
for i := range itemCount {
193193
base := AppsLookupReqHdr + int(i)*LookupDirEntrySize
194194
off, _, err := lookupDirEntry(buf, base)
195195
if err != nil {
@@ -251,7 +251,7 @@ func DecodeAppsLookupResponse(buf []byte) (*AppsLookupResponseView, error) {
251251
if err := validateLookupDir(buf, AppsLookupRespHdr, itemCount, len(buf)-dirEnd, AppsLookupItemHdr, -1); err != nil {
252252
return nil, err
253253
}
254-
for i := uint32(0); i < itemCount; i++ {
254+
for i := range itemCount {
255255
base := AppsLookupRespHdr + int(i)*LookupDirEntrySize
256256
off, length, err := lookupDirEntry(buf, base)
257257
if err != nil {

‎src/go/pkg/netipc/protocol/cgroups_lookup.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func DecodeCgroupsLookupRequest(buf []byte) (*CgroupsLookupRequestView, error) {
144144
return nil, err
145145
}
146146
view := &CgroupsLookupRequestView{ItemCount: itemCount, packedStart: dirEnd, payload: buf}
147-
for i := uint32(0); i < itemCount; i++ {
147+
for i := range itemCount {
148148
keyWithNul, key, err := view.itemBytes(i)
149149
if err != nil {
150150
return nil, err
@@ -248,7 +248,7 @@ func DecodeCgroupsLookupResponse(buf []byte) (*CgroupsLookupResponseView, error)
248248
if err := validateLookupDir(buf, CgroupsLookupRespHdr, itemCount, len(buf)-dirEnd, CgroupsLookupItemHdr, -1); err != nil {
249249
return nil, err
250250
}
251-
for i := uint32(0); i < itemCount; i++ {
251+
for i := range itemCount {
252252
base := CgroupsLookupRespHdr + int(i)*LookupDirEntrySize
253253
off, length, err := lookupDirEntry(buf, base)
254254
if err != nil {

‎src/go/pkg/netipc/protocol/frame.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ func BatchDirDecode(buf []byte, itemCount uint32, packedAreaLen uint32) ([]Batch
281281
}
282282

283283
out := make([]BatchEntry, count)
284-
for i := 0; i < count; i++ {
284+
for i := range count {
285285
base := i * 8
286286
off := ne.Uint32(buf[base : base+4])
287287
length := ne.Uint32(buf[base+4 : base+8])
@@ -309,7 +309,7 @@ func BatchDirValidate(buf []byte, itemCount uint32, packedAreaLen uint32) error
309309
return ErrTruncated
310310
}
311311
count := int(itemCount)
312-
for i := 0; i < count; i++ {
312+
for i := range count {
313313
base := i * 8
314314
off := ne.Uint32(buf[base : base+4])
315315
length := ne.Uint32(buf[base+4 : base+8])

‎src/go/pkg/netipc/protocol/lookup_common.go‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ func validateLookupDir(buf []byte, dirStart int, itemCount uint32, packedAreaLen
298298

299299
prevEnd := uint64(0)
300300
count := int(itemCount)
301-
for i := 0; i < count; i++ {
301+
for i := range count {
302302
base := dirStart + i*LookupDirEntrySize
303303
off := ne.Uint32(buf[base : base+4])
304304
length := ne.Uint32(buf[base+4 : base+8])
@@ -414,7 +414,7 @@ func validateLabels(item []byte, hdrSize int, labelCount uint16, fixedEnd int) (
414414
return 0, ErrOutOfBounds
415415
}
416416

417-
for i := uint16(0); i < labelCount; i++ {
417+
for i := range labelCount {
418418
entryRel, ok := checkedInt(uint64(i) * uint64(LookupLabelEntrySize))
419419
if !ok {
420420
return 0, ErrOutOfBounds
@@ -650,7 +650,7 @@ func finishLookupResponse(buf []byte, hdrSize int, itemCount uint32, dataOffset
650650
if finalPackedStart < firstItemAbs {
651651
copy(buf[finalPackedStart:], buf[firstItemAbs:firstItemAbs+packedDataLen])
652652
}
653-
for i := 0; i < count; i++ {
653+
for i := range count {
654654
entry := hdrSize + i*LookupDirEntrySize
655655
abs, ok := checkedInt(uint64(ne.Uint32(buf[entry : entry+4])))
656656
if !ok || abs < firstItemAbs {

‎src/go/pkg/netipc/protocol/lookup_guard_test.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,10 +1951,10 @@ func TestLookupThirtyTwoBitGuardCoverage(t *testing.T) {
19511951
t.Fatalf("cgroups itemBytes over-int offset = %v, want ErrOutOfBounds", err)
19521952
}
19531953

1954-
if got := payloadExceededSuffixFits(0, 0, nil, 0, hugeLookupItems); !got {
1954+
if !payloadExceededSuffixFits(0, 0, nil, 0, hugeLookupItems) {
19551955
t.Fatal("payloadExceededSuffixFits should ignore unrepresentable maxItems")
19561956
}
1957-
if got := payloadExceededSuffixFits(0, 0, make([]uint32, 2), overMaxInt, 1); got {
1957+
if payloadExceededSuffixFits(0, 0, make([]uint32, 2), overMaxInt, 1) {
19581958
t.Fatal("payloadExceededSuffixFits should reject unrepresentable first index")
19591959
}
19601960
if _, ok := makePayloadExceededSuffixBytes(overMaxInt); ok {

‎src/go/pkg/netipc/service/raw/apps_lookup.go‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,7 @@ func appsLookupNextRequest(pids []uint32, maxPayload uint32) (int, int, error) {
4545
if maxCount <= 0 {
4646
return 0, 0, protocol.ErrOverflow
4747
}
48-
count := len(pids)
49-
if count > maxCount {
50-
count = maxCount
51-
}
48+
count := min(len(pids), maxCount)
5249
size, err := appsLookupRequestSize(pids[:count])
5350
if err != nil {
5451
return 0, 0, err
@@ -88,7 +85,7 @@ func (c *Client) CallAppsLookupWithTimeout(pids []uint32, timeoutMs uint32) (*pr
8885
if err != nil {
8986
oneItemSize, serr := appsLookupRequestSize([]uint32{0})
9087
if errors.Is(err, protocol.ErrOverflow) && start < len(pids) && serr == nil {
91-
if cerr := c.ensureLookupRequestCapacity(oneItemSize); cerr == nil {
88+
if c.ensureLookupRequestCapacity(oneItemSize) == nil {
9289
continue
9390
}
9491
}

0 commit comments

Comments
 (0)