Repository navigation
feat: the node knows whose code it profiles (ADR 0059) - #94
Merged
Merged
Conversation
Closes for the eBPF capture path the defect ADR 0058 named as open. The symbol filter classifies a frame by module path, so a service under github.com/acme/web was redacted as third-party unless someone had named it — the configured list was not an addition to what the filter knew, it was the only thing standing between the customer's service layer and the placeholder. The information was already on the node and in the same process. cmd/agent/ node.go runs the scanner, which reads each container's main module and every replace-redirected dependency every pass; cmd/agent/pipeline.go ran the profiler beside it and built one filter for the whole node from configuration alone. The two goroutines never spoke. - The scanner publishes a container→own-modules index, replaced wholesale per pass so a departed container leaves with it (the targeting.Publisher shape). - processWindow builds a filter per container: configured prefixes plus that build's own modules. A container the scanner has not reported yet falls back to the old behaviour, which Validate already covers. - An allow-list entry that cannot be a module path is refused, on both paths: a build declaring a bare "github.com" would otherwise admit every module on it. This also rejects the same typo from an operator, which is a behaviour change and is stated in the ADR. - The chart's refusal to install ebpf with an empty allow-list goes: it required a value that no longer changes anything. Why nobody saw it: the capture e2e configured the sample's own module path. It now installs with nothing configured, so a surviving sample frame can only mean the node read the module off the binary. go test ./... and golangci-lint run ./... (host and GOOS=linux) — pass, 0 issues. e2e not run locally. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011YRKuL97KRndaopfpixrhp
This was referenced Aug 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes, for the eBPF capture path, the defect #93's ADR named as open.
The defect
The symbol filter classifies a frame by module path: no domain → stdlib or unpublished code, keep; allow-listed prefix → keep; anything else → third-party, redact. A customer's service lives under
github.com/acme/web, which has a domain.So the configured list was never an addition to what the filter knew — it was the only thing standing between the customer's service layer and
[filtered]. Name one prefix, run five services, redact four.The information was already there, in the same process
cmd/agent/node.goruns the scanner, which reads every kept binary's main module and everyreplace-redirected dependency, per container, every pass.cmd/agent/pipeline.go:60ran the profiler beside it and built one filter for the whole node, from configuration alone. Two goroutines in one process that never spoke.container → own modulesindex, replaced wholesale per pass so a container no live process belongs to leaves with it. Same shapeinternal/targetinguses on the controller, and for the same reason.processWindow— which already grouped by container — builds the filter per group: configured prefixes plus that build's own modules.Validatealready refuses a profile of nothing but the runtime. No new drop rule for a case the existing one covers.Two things worth a look
An allow-list entry that cannot be a module path is now refused. Part of the list comes from binaries, so a build declaring its main module as a bare
github.comwould otherwise admit every module hosted there. The same check applies to a prefix an operator wrote, where the same typo was previously accepted — that is a behaviour change for a misconfigured install and it is named in the ADR rather than left to be found.This is not a defence against a hostile workload: a binary that lies exposes its own dependency frames to the party the customer already trusts with its profiles. It bounds a plausible typo.
The chart stops requiring
allowedModulePrefixesforebpf. That refusal existed because an empty list produced nothing, forever, silently. That stopped being true. A required value that changes nothing is the inert knob ADR 0025 abolished — soebpfnow installs and produces useful profiles with no profiling configuration at all, which is whatinventory+ pull has done since #93.Why nobody saw it
test/e2e/capture_test.gosetallowedModulePrefixes: [sampleModulePath]— the e2e was configured around the bug. It now installs with the allow-list absent, so a surviving frame of the sample can only mean the node read the module off the binary. That is the load-bearing change in this PR's test surface.Also
OwnModulesmoves intonodescan, so the derivation that both paths depend on exists once instead of once per consumer.Evidence
TestOwnCodeSurvivesWithNothingConfiguredships a profile throughprocessWindowwith an empty configured list and asserts the workload's frame survives and the dependency's does not;TestWithoutTheIndexTheSameWindowShipsNothingpins the old behaviour beside it.TestOnlyAPlausibleModulePathIsAnAllowListEntryandTestTheFilterDropsAnImplausibleEntrycover the guard.go test ./...andgolangci-lint run ./...pass on host andGOOS=linux, 0 issues.Still open, and stated in the ADR
The eBPF capture path contributes nothing to
collection_coverage. The prober and puller each report what they attempted and why it failed (#92, #93); the profiler's refusals live only in the node's log. So "this workload has no eBPF profile" is still indistinguishable from a broken agent — exactly what ADR 0054 exists to prevent. Separate slice.🤖 Generated with Claude Code
https://claude.ai/code/session_011YRKuL97KRndaopfpixrhp