Releases: kubescape/node-agent
Release list
Release v0.3.238
What
Two commits:
-
Schema dedup — replaces node-agent's duplicate
profileDataRequiredschema with type aliases to the canonical armoapi-go types (ProfileDataRequired/ProfileDataField/ProfileDataPattern). Defining the matcher once in armoapi-go — imported by node-agent (query side), storage (generation side / rule-aware collapse), and the backend (rules in MongoDB) — guarantees it can't drift between the side that records a profile and the side that queries it. Shape change: a profile-data surface is now a pointer (Opens *ProfileDataField); a nil pointer means "not declared" (the role the oldFieldRequirement.Declaredbool played).mergeFieldupdated to pointer + nil-check; the schema's own test moves to armoapi-go. -
Dependency fix — resolves the transitive conflicts from the
kubescape/storage v0.0.282bump using additive replace directives only, leaving the three frozen replaces (syft, inspektor-gadget, cilium/ebpf) and the storage pin untouched.
Deps
armoapi-go→v0.0.719(profileDataRequired schema +UnionOpenProtection).kubescape/storage→v0.0.282.
Dependency resolution (was the blocker — now fixed)
The storage v0.0.282 bump pulled a newer transitive stack that broke the build against the frozen forks:
opencontainers/runtime-specwas forced tov1.3.0, which changedLinuxPids.Limitfromint64to*int64;containerd v1.7.32'soci/spec_opts.goassigns anint64and stopped compiling.anchore/stereoscopewas forced tov0.1.22, whose docker/podman clients need a docker API (client.New,client.PingOptions) newer than the pinneddocker v28.5.2; the frozenkubescape/syftfork expectsstereoscope v0.1.9.
Resolved with two additive replaces pinning these transitives back to the versions the frozen set already uses:
replace github.com/opencontainers/runtime-spec => github.com/opencontainers/runtime-spec v1.2.1
replace github.com/anchore/stereoscope => github.com/anchore/stereoscope v0.1.9-0.20250826202322-ef061ea78385
(runtime-spec v1.2.1 is what origin/main used; the stereoscope pseudo-version is the one the kubescape/syft v1.32.0-ks.2 fork requires.) The three frozen replaces and storage v0.0.282 are unchanged.
Verified
go build ./...— clean.go test ./... -run='^$'— all test binaries compile.- Unit tests pass for the affected packages:
pkg/objectcache/containerprofilecache(projection /mergeField) andpkg/rulemanager/cel/libraries/applicationprofile(was_path_opened).
Related
- armosec/armoapi-go#656 (
UnionOpenProtection, released in v0.0.719) - kubescape/storage#335 (generation-side rule-aware collapse)
🤖 Generated with Claude Code
Summary by CodeRabbit
-
Bug Fixes
- Improved validation of profile data requirements, including clearer errors for unknown fields, invalid values, and malformed patterns.
- Prevented invalid profile data from being accepted during rule conversion.
- Updated profile requirement handling to correctly recognize undeclared fields.
-
Tests
- Added coverage for valid profile data conversion and validation failures.
-
Chores
- Updated the Go toolchain and project dependencies.
Release v0.3.231
Overview
Upgrades the Go version to 1.27 across the project and applies automated idiom refactoring.
- Updated
go.modto Go 1.27 and tidied dependencies. - Applied
go fix ./...andgolang.org/x/tools/go/analysis/passes/modernize/cmd/modernize -fix ./.... - Refactored manual slice and map loops to use standard library utilities (
slices.Contains,maps.Copy). - Modernized struct initialization syntax and formatted code using
go fmt ./.... - Updated builder image tags in
build/Dockerfileandbuild/Dockerfile.debugtogolang:1.27-trixie. - Updated Go version in GitHub Actions workflows (
pr-created.yaml,pr-merged.yaml,bypass.yaml,component-tests.yaml,benchmark.yaml) and documentation.
How to Test
- Run
go build ./... - Run
go test ./...
Release v0.3.226
Overview
Lands the client half of "conditional container-profile fetch" (step 4a of 5 in
armosec/shared-designs-and-docs#201,
status: proposed). The container-profile cache reconciler can now present the
content checksum of the profile it already holds, and treat a server's
"unchanged" reply as "keep the cached entry, skip the rebuild" — instead of
today's behavior, which fetches the full body every tick and only decides
after the object is on the wire whether a rebuild is needed.
This PR is DORMANT. No in-tree ProfileClient implementer returns the new
sentinel, so no conditional fetch has been or can be observed here. Green
tests prove the contract compiles and existing behavior is byte-for-byte
unchanged — nothing more. The companion kubescape/backend PR (kubescape/backend#62)
adds the server-side contract; a private downstream adapter (not part of this
org, not this PR) is what will eventually make node-agent actually send the
checksum in production.
Design constraint
storage.ProfileClient.GetContainerProfile(ctx, namespace, name) has a second
implementer in this repo (pkg/storage/v1, the in-cluster CRD/aggregated-API
backend), which has no concept of a remote checksum. This PR does not
change that interface's signature — pkg/storage/v1/, storage_mock.go, and
the interface definition are byte-for-byte untouched (git diff --stat is
empty). The checksum crosses the boundary out-of-band instead: a context.Context
key on the request side, a sentinel error plus an ObjectMeta annotation on
the response side.
Changes
pkg/storage/checksum.go(new):WithKnownChecksum/KnownChecksumFromContext
over an unexported context key;ErrProfileUnchanged; the exported
ContainerProfileChecksumAnnotationKey(backend.kubescape.io/container-profile-checksum,
matching kubescape/backend#62's key exactly — pinned by a dedicated
cross-repo equality test in the downstream adapter).CachedContainerProfilegains aChecksumfield, populated at both
places a cache entry is constructed (rebuildEntryFromSourcesand
buildEntry/tryPopulateEntry— missing the second site would have made
the optimization silently inert for every profile that never changes, i.e.
exactly the population it targets).refreshOneEntry's guard for attaching a checksum to the learned-CP fetch
requires: no authored-CP override in play, the projection spec hash
unchanged, a known checksum available, and the entry's learned status is
already terminal (Completed+Full) — that last conjunct exists because a
lifecycle-only change (e.g. completion status flipping) doesn't change the
content checksum, and this cache'sStatefeeds real alerting logic
downstream, so a conditional fetch is only requested once nothing about the
entry can still move.- The user-authored-CP fetch (a separate call in the same function) never
receives a checksum and is completely unaffected. docs/features/container-profile-conditional-fetch-contract.md(new):
documents this repo's half of the cross-repo contract for future
maintainers and upstream reviewers.
Testing
- 17 new tests in
pkg/objectcache/containerprofilecache/reconciler_checksum_test.go,
covering: both construction sites (including that the adopted entry stores
the learned CP's checksum, not the authored CP's), every guard conjunct
individually, per-call-site isolation (the authored-CP fetch never sees a
checksum even in the same tick), the sentinel keeping the cache entry
pointer-identical with no rebuild, and the terminal-state guard walking all
three phases (declined while partial → completion flip reaches the cache →
shortcut engages once terminal). go test ./pkg/objectcache/containerprofilecache/... -racegreen.go test ./pkg/objectcache/... -run Goldengreen — no projection-golden
churn from the new annotation.- Every pre-existing test in this package passes unmodified — no assertion
edits, no new skips. go build ./...— confirms the in-clusterStorageimplementer still
satisfiesProfileClientwith zero changes on this PR's part.
Related
Step 4a of 5 in the conditional container-profile fetch plan.
Companion PR: kubescape/backend#62 (step 2, proto contract).
🤖 Generated with Claude Code
https://claude.ai/code/session_01HnqMRD3r2kGYUBTxMHM5vi
AI-skills: oh-my-claudecode:plan,oh-my-claudecode:team | cmds: /oh-my-claudecode:deep-interview
Summary by CodeRabbit
-
New Features
- Added conditional fetching for unchanged container profiles, reducing unnecessary data transfers with compatible sources.
- Container profile checksums are stored and reused during eligible refreshes.
- Cached profiles are retained when a source confirms that content is unchanged.
- Added refresh safeguards to periodically revalidate profiles and prevent overlapping refresh operations.
- Added metrics for conditional-fetch requests and responses.
-
Documentation
- Documented the conditional-fetch contract, checksum behavior, and refresh conditions.
Release v0.3.219
Description
This PR updates dependencies that have available security patches to address open Dependabot alerts on kubescape/node-agent.
Updated Dependencies & Addressed Advisories
github.com/cilium/cilium: updated fromv1.17.15tov1.17.16- Resolves Alert #108 (GHSA-q6h5-q3q6-f87x / CVE-2026-53935)
github.com/containerd/containerd: updated fromv1.7.30tov1.7.33- Resolves Alert #100 (GHSA-xhf5-7wjv-pqxp / CVE-2026-53488)
- Resolves Alert #99 (GHSA-jpcc-p29g-p8mq / CVE-2026-47262)
- Resolves Alert #97 (GHSA-fqw6-gf59-qr4w / CVE-2026-46680)
github.com/go-git/go-billy/v5: updated fromv5.8.0tov5.9.0- Resolves Alert #88 (GHSA-qw64-3x98-g7q2 / CVE-2026-44973)
- Resolves Alert #87 (GHSA-m3xc-h892-ggx6 / CVE-2026-44740)
github.com/go-git/go-git/v5: updated fromv5.18.0tov5.19.2- Resolves Alert #112 (GHSA-8g3w-hx67-27v6)
- Resolves Alert #111 (GHSA-v472-7476-q58q)
- Resolves Alert #101 (GHSA-w5pp-99ch-qj29)
- Resolves Alert #96 (GHSA-crhj-59gh-8x96 / CVE-2026-45571)
- Resolves Alert #95 (GHSA-m7cr-m3pv-hgrp / CVE-2026-45570)
- Resolves Alert #86 (GHSA-389r-gv7p-r3rp / CVE-2026-45022)
github.com/google/cel-go: updated fromv0.26.1tov0.29.0- Resolves Alert #110 (GHSA-w374-2whf-pp64)
- Adapted
cel.NewStaticOptimizercall site to handle error return value in pkg/rulemanager/cel/cel.go
github.com/in-toto/in-toto-golang: updated fromv0.9.0tov0.11.0- Resolves Alert #85 (GHSA-pmwq-pjrm-6p5r)
go.mongodb.org/mongo-driver: updated fromv1.17.6tov1.17.7- Resolves Alert #98 (GHSA-cp6g-7hqx-qxhp / CVE-2026-2303)
golang.org/x/image: updated fromv0.38.0tov0.41.0- Resolves Alert #107 (GHSA-q675-qj96-32m9 / CVE-2026-46599)
oras.land/oras-go/v2: updated fromv2.6.0tov2.6.2- Resolves Alert #106 (GHSA-vh4v-2xq2-g5cg)
- Resolves Alert #105 (GHSA-fxhp-mv3v-67qp / CVE-2026-50163)
- Resolves Alert #104 (GHSA-8xwf-rjm4-xvhv / CVE-2026-50162)
- Resolves Alert #103 (GHSA-jxpm-75mh-9fp7 / CVE-2026-50151)
- Resolves Alert #102 (GHSA-xf85-363p-868w / CVE-2026-48978)
How to test
- Run
go build ./...and verify compilation succeeds. - Run
go test ./...to run unit test suites.
Summary by CodeRabbit
-
Bug Fixes
- Improved reliability when initializing expression evaluation. Configuration errors are now detected early and reported clearly instead of allowing setup to continue unsuccessfully.
-
Chores
- Updated several underlying components and security-related libraries to newer versions.
- Added support for newer attestation functionality and removed an outdated utility dependency.
Release v0.3.218
Overview
Resolves cross-container DNS attribution and Anycast/CDN IP collision poisoning in NetworkNeighborhood egress profiles (root fix for SUB-8289).
Problem
Previously, DNSManager.ReportEvent (pkg/dnsmanager/dns_manager.go) stored all resolved IP-to-domain mappings in a single, node-global LRU cache (addressToDomainMap). When building a container's NetworkNeighbor in createNetworkNeighbor (pkg/containerprofilemanager/v1/container_data.go), raw-IP egress connections were resolved by querying that global cache without container identity.
If Workload A resolved an IP belonging to a multi-tenant CDN/Anycast edge (such as OpenAI/Anthropic hosted behind Cloudflare or AWS edge blocks), that IP-to-domain mapping was stored globally. Subsequent egress traffic from Workload B (or node-level infra pods touching node egress) to that same shared IP would inherit Workload A's domain name, baking incorrect domain labels directly into Workload B's NetworkNeighborhood CR.
Solution
- Per-Container LRU Cache: Replaced the global
addressToDomainMapinDNSManagerwith acontainerToAddressToDomainmap of per-container LRU caches. - Container-Scoped Lookup: Updated
DNSResolver.ResolveIPAddress(containerID string, ipAddr string)to query the container's own resolution cache. - Caller Context Propagation:
createNetworkNeighborincontainerprofilemanagerpasses itscontainerIDtoResolveIPAddress.buildNetworkEventinnetworkstreampassesevent.GetContainerID()toResolveIPAddress.
- Lifecycle Cleanup: On container removal (
EventTypeRemoveContainer), the container's resolution cache is evicted alongside its cloud services cache to prevent memory leaks. - Testing: Added unit tests for cross-container DNS isolation (
TestContainerDNSIsolation) and container removal cache cleanup (TestContainerDNSLifecycleCleanup).
Summary by CodeRabbit
- Bug Fixes
- Improved DNS-based domain resolution by isolating cached mappings per container.
- Prevented DNS mappings from one container from affecting another.
- Added cleanup of DNS mappings when containers are removed, with a brief grace period for in-flight activity.
- Improved resolution for network events involving external destinations and host processes.
- Restored a safe default DNS cache capacity when an invalid or non-positive size is configured.
- Prevented empty container identifiers from incorrectly resolving as host traffic.
Release v0.3.216
Summary of Changes
This PR implements additional hot-path performance improvements, correctness fixes, and dead code removal:
-
O(1) Exact Map & Trailing-Slash Lookup for Path/Endpoint Rules (
pkg/rulemanager/cel/libraries/containerprofile/path_match.goet al.):- Extracted
matchLiteralPathhelper shared acrossopen.go,http.go, andexec.go. - Replaced linear
CompareDynamicloops on literal paths with an$O(1)$ map lookup with single trailing-slash equivalence (/etc/passwd/↔/etc/passwd). - Guarded against false matches on empty paths (
""), multiple trailing slashes (//), and root (/), verified by a 100% agreement differential test againstdynamicpathdetector.CompareDynamic. - Dramatically reduces CPU overhead on event evaluation for large container profiles.
- Extracted
-
Eliminate
pprof.DoLabels on Rule Evaluation Hot-Path (pkg/rulemanager/rule_manager.go&event_handler_factory.go):- Removed
pprof.Do(..., pprof.Labels("rule", rule.ID))and event handler labels. - Eliminates per-rule
runtime/pprof.WithLabelsand context allocations on every single event (-139 MB allocations under load, -7% CPU).
- Removed
-
Gated OTEL Metrics Initialization (
cmd/main.go&pkg/config/config.go):- Uses
metricsmanager.NewMetricsNoop()and skipsgoruntime.Startwhen no Prometheus scrape or OTEL endpoint is configured, avoiding background metrics collection overhead when metrics are disabled.
- Uses
-
SBOM Layer Order & Digest↔Size Pairing Bug Fix (
pkg/sbommanager/v1/syftutil/source.go):- Clones
imageInfo.ImageSpec.RootFS.DiffIDsbeforeslices.Reverse(which is used for top-first overlay resolution). -
Fixes pre-existing bug: Prevents in-place mutation that previously caused
toLayersto pair layer digests with the file size of the opposite layer (top layer digest paired with base layer size, and vice versa). - Preserves OCI base-first order in
ImageMetadata.LayersandRawConfig.rootfs.diff_ids. - Pinned with regression test
Test_NewSource_LayerOrderingAndDigestSizePairing.
- Clones
-
Test Mock Fidelity (
pkg/objectcache/v1/mock.go):- Updated
RuleObjectCacheMockto split dynamic paths with⋯or*intoPatterns(mirroring productionApply).
- Updated
-
Pruned Dead Legacy Prometheus Code:
- Removed unused 764-line
pkg/metricsmanager/prometheus/package (node-agent fully standardized on OTEL).
- Removed unused 764-line
Verification
- Differential test
TestMatchLiteralPath_DifferentialAgainstCompareDynamicproves 100% equivalence withCompareDynamicon literal paths. - SBOM regression test
Test_NewSource_LayerOrderingAndDigestSizePairingconfirms digest↔size pairing and layer ordering. - Benchmark passed on CI with -17.5% memory and -7.0% Peak CPU p95.
Summary by CodeRabbit
-
New Features
- Metrics collection now activates when configured through the metrics exporter or supported OpenTelemetry settings.
- Metrics safely remain disabled when no metrics configuration is present.
-
Bug Fixes
- Improved endpoint, file, and executable path matching, including consistent trailing-slash handling and empty-path protection.
- Prevented image metadata from being modified while preparing SBOM sources.
- Improved consistency between cached container profiles and runtime matching behavior.
-
Chores
- Removed the legacy Prometheus metrics implementation and related benchmarks.
Release v0.3.215
Summary of Changes
This PR implements high-impact memory and CPU optimizations identified from the pprof profiles captured during the benchmark CI runs:
-
Pool
bufio.Readerin HTTP Parsing (pkg/containerwatcher/v2/tracers/httpparse.go):- Replaces per-event
bufio.NewReaderallocations with async.Poolof*bufio.Reader. - In benchmark pprof data,
bufio.NewReaderSizeaccounted for 1.24 GB (14.03%) of total memory allocated under load.
- Replaces per-event
-
Eliminate Redundant Process Node Copy in
GetContainerProcessTree(pkg/processtree/process_tree_manager.go):GetContainerProcessTreepreviously calledptm.creator.GetProcessNode(int(pid))solely to verifyprocessNode != nil.GetProcessNodeperformed a fullshallowCopyProcesscreating maps and slices that were immediately discarded becauseGetPidBranchdoes its own lookup directly on the process map.- Removing this redundant call eliminates 214 MB (2.43%) of heap allocations under load.
-
Zero-Allocation Struct Keys for LRU Caches:
- HTTP Tracer: Keyed
eventsMapbytype httpEventKey struct { inode uint64; sockFd uint32 }instead of allocating concatenated string keys (strconv.FormatUint(...)). - Process Tree Manager: Keyed
containerProcessTreeCachebytype treeCacheKey struct { containerID string; pid uint32 }instead of string formatting on every single event lookup.
- HTTP Tracer: Keyed
-
Empty Container Guard in
GetContainerProcessTree(pkg/processtree/process_tree_manager.go):- Early-returns
armotypes.Process{}, nilfor host events (containerID == ""), avoiding map lookups, mutex acquisitions, and missing-container error formatting.
- Early-returns
-
Typed Slice Min-Heap with Zero Interface Boxing for
OrderedEventQueue(pkg/containerwatcher/v2/ordered_event_queue.go) & Batch Extraction (pkg/containerwatcher/v2/container_watcher.go):- Replaces
lane.PriorityQueuewith a typed slice min-heap ([]EventEntry), eliminating heap wrapper allocations on push/pop. - Added
PopBatchand reusable bufferbatchBufinContainerWatcher.processQueueBatch, popping full batches under a single lock and eliminating per-event mutex lock acquisitions.
- Replaces
Verification
- All unit tests across
pkg/containerwatcher/v2/...andpkg/processtree/...pass. - Benchmark quality gate passed in CI with ~15% Memory reduction and ~5% Peak CPU reduction.
Release v0.3.212
Summary
ClamAV is the only in-tree implementation of the MalwareScanner interface, and it is obsolete.
Its alerts never reach the hash-signature matcher — that path handles rule R6000 only — and the
dashboard's "Malware Name" field reads a signature name that only the hash path fills, so a
ClamAV alert renders it empty today. This removes the scanner, the sidecar image and the claims
about it, and keeps the interface.
BREAKING CHANGE: the node-agent no longer ships a malware scanner. malwareDetectionEnabled
still starts the malware manager, but with no scanner registered it cannot produce an alert, so
it logs a warning saying exactly that.
Ticket
None — this repository has no ticket link. Tracked internally as part of the file-hash detection
GA work.
Changes
- Delete
pkg/malwaremanager/v1/clamav— the scanner. - Delete
clamav/— the sidecar image: Dockerfile, Makefile, the init script and the
database-filter script. - Drop the
CLAMAV_SOCKETwiring inCreateMalwareManager, and warn when the manager starts
with no scanner registered. - Drop the ClamAV surface of the CI test chart under
tests/chart. - Drop the ClamAV claims in
README.md,docs/CONFIGURATION.mdand the demo walkthrough, and
the demo screenshot the removed section used. go mod tidydropsgithub.com/dutchcoders/go-clamd.
Kept on purpose: MalwareScanner, MalwareResult, MalwareManagerClient and
pkg/malwaremanager/v1/types. They are the extension point for an out-of-tree scanner, and
downstream exporters build on MalwareResult.
The matching chart change removes the sidecar from kubescape/helm-charts. The two are
independent and can merge in either order: this agent ignores an absent CLAMAV_SOCKET, and a
running sidecar with no client is inert.
Testing
go build ./... and go vet ./... for GOOS=linux → pass. The test suite does not run on
macOS — the dependency tree is Linux-only — so CI is the gate for the tests. helm template on
tests/chart with capabilities.malwareDetection=enable → renders, no ClamAV.
AI-skills: armosec-shared-rules:agent-dispatch-policy
Release v0.3.206
Overview
Repoints node-agent's inspektor-gadget dependency from the personal fork
(matthyx/inspektor-gadget) to the org-owned fork (kubescape/inspektor-gadget),
so the dependency isn't tied to one contributor's personal GitHub account.
kubescape/inspektor-gadget:mainwas force-pushed to match
matthyx/inspektor-gadget:main(commit06b0d12b), which included one extra
refactor commit beyond whatgo.modwas previously pinned to (same feature,
no behavior change — seepkg/operators/ebpf/manualfetch.go).go.mod'sreplacedirective now points atkubescape/inspektor-gadgetwith
a pseudo-version pinned to that commit;go.sumupdated viago mod tidy.- Added
docs/features/inspektor-gadget-fork.mddocumenting which fork is used
and how to update the pin going forward.
How to Test
go build ./...andgo mod tidyrun clean against the new replace target.
🤖 Generated with Claude Code
AI-skills: none | cmds: /clear
Summary by CodeRabbit
-
Documentation
- Added guidance for the Inspektor Gadget dependency, including its source, version pinning, migration details, and update validation steps.
-
Maintenance
- Updated the Inspektor Gadget dependency to a newer version from the maintained project fork.
Release v0.3.200
The fork (matthyx/inspektor-gadget) was reset onto upstream v0.48.1 with its fork-specific commits reapplied and cleaned up; this picks up the corrected datasource pooling implementation (matching upstream PR inspektor-gadget/inspektor-gadget#5295) and the uprobetracer/TLS reattach fixes.
Docs-exempt: pure dependency version bump (go.mod/go.sum only), no behavioral change to this repo's own code
Overview
Summary by CodeRabbit
- Chores
- Updated an underlying component to a newer version, bringing in the latest available improvements and fixes.