Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package falcosecurity-container-plugin for
openSUSE:Factory checked in at 2026-09-24 22:58:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/falcosecurity-container-plugin (Old)
and /work/SRC/openSUSE:Factory/.falcosecurity-container-plugin.new.383539
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "falcosecurity-container-plugin"
Thu Sep 24 22:58:01 2026 rev:4 rq:1380077 version:0.7.5
Changes:
--------
---
/work/SRC/openSUSE:Factory/falcosecurity-container-plugin/falcosecurity-container-plugin.changes
2026-09-11 18:05:39.510686986 +0200
+++
/work/SRC/openSUSE:Factory/.falcosecurity-container-plugin.new.383539/falcosecurity-container-plugin.changes
2026-09-24 23:00:19.744428031 +0200
@@ -1,0 +2,11 @@
+Wed Sep 23 19:25:20 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to version 0.7.5:
+ * chore(plugins/container): bump version to 0.7.5
+ * fix(plugins/container): unblock listener shutdown
+ * build(deps): bump
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc
+ * build(deps): bump go.opentelemetry.io/otel/sdk
+- Export GOROOT for the go-worker build: the trimmed
+ distribution go binary cannot locate it alone
+
+-------------------------------------------------------------------
Old:
----
container-plugin-0.7.4.tar
New:
----
container-plugin-0.7.5.tar
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ falcosecurity-container-plugin.spec ++++++
--- /var/tmp/diff_new_pack.imQnhz/_old 2026-09-24 23:00:20.805472400 +0200
+++ /var/tmp/diff_new_pack.imQnhz/_new 2026-09-24 23:00:20.807472484 +0200
@@ -17,7 +17,7 @@
Name: falcosecurity-container-plugin
-Version: 0.7.4
+Version: 0.7.5
Release: 0
Summary: Falcosecurity plugin providing container metadata
# Legal-Review-Notice: MPL-2.0 from vendored Go modules statically
@@ -63,6 +63,8 @@
export GOPROXY=off
export GOTOOLCHAIN=local
export GOCACHE=%{_builddir}/.gocache
+# The distribution go binary is trimmed and cannot locate its GOROOT alone.
+export GOROOT=$(go env GOROOT)
%define __builder ninja
# ENABLE_TESTS pulls in a from-source libsinsp (sinsp_test_support); keep it
OFF
# so the plugin builds against the system stack only.
++++++ _service ++++++
--- /var/tmp/diff_new_pack.imQnhz/_old 2026-09-24 23:00:20.866474951 +0200
+++ /var/tmp/diff_new_pack.imQnhz/_new 2026-09-24 23:00:20.870475119 +0200
@@ -6,10 +6,10 @@
<service name="obs_scm" mode="manual">
<param name="url">https://github.com/falcosecurity/plugins.git</param>
<param name="scm">git</param>
- <param name="revision">refs/tags/plugins/container/v0.7.4</param>
+ <param name="revision">refs/tags/plugins/container/v0.7.5</param>
<param name="subdir">plugins/container</param>
<param name="filename">container-plugin</param>
- <param name="versionformat">0.7.4</param>
+ <param name="versionformat">0.7.5</param>
<param name="changesgenerate">enable</param>
</service>
<service name="tar" mode="manual"/>
++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.imQnhz/_old 2026-09-24 23:00:20.898476290 +0200
+++ /var/tmp/diff_new_pack.imQnhz/_new 2026-09-24 23:00:20.908476708 +0200
@@ -1,6 +1,6 @@
<servicedata>
<service name="tar_scm">
<param
name="url">https://github.com/falcosecurity/plugins.git</param>
- <param
name="changesrevision">efa4416dd148f0127499b23bb4ffa49bd417c385</param></service></servicedata>
+ <param
name="changesrevision">a246c88790db1180f8b15411a5fb20ce853f67a4</param></service></servicedata>
(No newline at EOF)
++++++ container-plugin-0.7.4.tar -> container-plugin-0.7.5.tar ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/container-plugin-0.7.4/CMakeLists.txt
new/container-plugin-0.7.5/CMakeLists.txt
--- old/container-plugin-0.7.4/CMakeLists.txt 2026-09-10 17:06:26.000000000
+0200
+++ new/container-plugin-0.7.5/CMakeLists.txt 2026-09-22 18:51:59.000000000
+0200
@@ -9,7 +9,7 @@
# project metadata
project(
container
- VERSION 0.7.4
+ VERSION 0.7.5
DESCRIPTION "Falco container metadata enrichment Plugin"
LANGUAGES CXX)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/container-plugin-0.7.4/go-worker/go.mod
new/container-plugin-0.7.5/go-worker/go.mod
--- old/container-plugin-0.7.4/go-worker/go.mod 2026-09-10 17:06:26.000000000
+0200
+++ new/container-plugin-0.7.5/go-worker/go.mod 2026-09-22 18:51:59.000000000
+0200
@@ -75,7 +75,7 @@
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
- github.com/go-logr/logr v1.4.3 // indirect
+ github.com/go-logr/logr v1.4.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/godbus/dbus/v5 v5.2.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 //
indirect
@@ -142,13 +142,13 @@
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0
// indirect
- go.opentelemetry.io/otel v1.44.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0
// indirect
- go.opentelemetry.io/otel/metric v1.44.0 // indirect
- go.opentelemetry.io/otel/sdk v1.44.0 // indirect
- go.opentelemetry.io/otel/trace v1.44.0 // indirect
- go.opentelemetry.io/proto/otlp v1.10.0 // indirect
+ go.opentelemetry.io/otel v1.45.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0
// indirect
+ go.opentelemetry.io/otel/metric v1.45.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.45.0 // indirect
+ go.opentelemetry.io/otel/trace v1.45.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.11.0 // indirect
go.podman.io/image/v5 v5.40.0 // indirect
go.podman.io/podman/v6 v6.0.2
go.podman.io/storage v1.63.0 // indirect
@@ -161,8 +161,8 @@
golang.org/x/term v0.45.0 // indirect
golang.org/x/text v0.41.0 // indirect
golang.org/x/time v0.15.0 // indirect
- google.golang.org/genproto/googleapis/api
v0.0.0-20260526163538-3dc84a4a5aaa // indirect
- google.golang.org/genproto/googleapis/rpc
v0.0.0-20260526163538-3dc84a4a5aaa // indirect
+ google.golang.org/genproto/googleapis/api
v0.0.0-20260803160001-6ac0973c030d // indirect
+ google.golang.org/genproto/googleapis/rpc
v0.0.0-20260803160001-6ac0973c030d // indirect
google.golang.org/grpc v1.83.2
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/container-plugin-0.7.4/go-worker/go.sum
new/container-plugin-0.7.5/go-worker/go.sum
--- old/container-plugin-0.7.4/go-worker/go.sum 2026-09-10 17:06:26.000000000
+0200
+++ new/container-plugin-0.7.5/go-worker/go.sum 2026-09-22 18:51:59.000000000
+0200
@@ -119,8 +119,8 @@
github.com/go-jose/go-jose/v4 v4.1.4
h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
github.com/go-jose/go-jose/v4 v4.1.4/go.mod
h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-logr/logr v1.2.2/go.mod
h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
-github.com/go-logr/logr v1.4.3/go.mod
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
+github.com/go-logr/logr v1.4.4/go.mod
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod
h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-task/slim-sprig/v3 v3.0.0
h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
@@ -352,24 +352,24 @@
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc
v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0
h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod
h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
-go.opentelemetry.io/otel v1.44.0
h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
-go.opentelemetry.io/otel v1.44.0/go.mod
h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0
h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod
h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0
h1:qazEJlUOQzhCpzQpFETGby7EdqjI1wsd0W+6Gg1SCTU=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0/go.mod
h1:fOD2Yefuxixkx3ahVNf0O/PERb6r4OlbxfATVnYvzCo=
+go.opentelemetry.io/otel v1.45.0
h1:pdrWmLHofpubmArBv1LgFSv1Z0Ie/ppdZzu+kUN5EeU=
+go.opentelemetry.io/otel v1.45.0/go.mod
h1:XZxIqPapzEYnhNSScF5DIqXhm/rYi0FzCe2XddAwZfQ=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0
h1:QRefszxJmfPdjXUUm3j6iDzY03mTPXMjqErFqQ67vUg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0/go.mod
h1:Tiz03lTBVBrm7eWZBOidzEaYaJa8tjwGUGv6d8mlTyk=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0
h1:fG5MCxGz8+2VtrN/WgqSpJFctVz24gpxj8CxkKmc8Ww=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0/go.mod
h1:BmAYTn+3ysbRe+IU2msxmf5Rx3g6DHvex+tWI3LdhYI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0
h1:lgh3PiVrRUWMLOVSkQicxzZll5NjF1r+AtsX1XRIHw0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0/go.mod
h1:5Cnhth3m/AgOeTgE3ex12pPmiu/gGtZit03kSzx9X7s=
-go.opentelemetry.io/otel/metric v1.44.0
h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
-go.opentelemetry.io/otel/metric v1.44.0/go.mod
h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
-go.opentelemetry.io/otel/sdk v1.44.0
h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
-go.opentelemetry.io/otel/sdk v1.44.0/go.mod
h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
-go.opentelemetry.io/otel/sdk/metric v1.44.0
h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
-go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod
h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
-go.opentelemetry.io/otel/trace v1.44.0
h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
-go.opentelemetry.io/otel/trace v1.44.0/go.mod
h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
-go.opentelemetry.io/proto/otlp v1.10.0
h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
-go.opentelemetry.io/proto/otlp v1.10.0/go.mod
h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
+go.opentelemetry.io/otel/metric v1.45.0
h1:7Eg1uH7CJ5cXv9is6tnBe1FI6rj1nwUdbFypRm3br/M=
+go.opentelemetry.io/otel/metric v1.45.0/go.mod
h1:HAPbm1nd3p1PmFH7v2dR+6BjXxw+Lq4a2+pndMAm08s=
+go.opentelemetry.io/otel/sdk v1.45.0
h1:4VVSMgQ83dUgW2aoX5f6JgLvHwIvzcuLnF9lUdCSpCw=
+go.opentelemetry.io/otel/sdk v1.45.0/go.mod
h1:Sr40LgXV7DsKMMJMKOhUWOgMWTfAaqvm2kF0g7ilwuA=
+go.opentelemetry.io/otel/sdk/metric v1.45.0
h1:oVFszMfyj1Am6s24Vtc7wBb8BKLcwepJjNEYILuiE3o=
+go.opentelemetry.io/otel/sdk/metric v1.45.0/go.mod
h1:vUWUxDZvu1WVRj8JA8S0AdhsPrZoDpA2DdZauIh4mDA=
+go.opentelemetry.io/otel/trace v1.45.0
h1:l/mP6Uv7oNO7/TblbhpbgMidxhq1uO/rPsikOyVhxag=
+go.opentelemetry.io/otel/trace v1.45.0/go.mod
h1:qoJJA2xNMnxRrdISU/kLtfUH2wNeQbiv+jhs/CxI8bc=
+go.opentelemetry.io/proto/otlp v1.11.0
h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
+go.opentelemetry.io/proto/otlp v1.11.0/go.mod
h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
go.podman.io/buildah v1.44.1 h1:WQhr/LK3do8ENLHYTls+wUIx6XWZPghZ4VH232WbL0U=
go.podman.io/buildah v1.44.1/go.mod
h1:hi+WSERjv19PU2CJ+AKbgwCO3IKuvtDXEUA8eXNkpqk=
go.podman.io/common v0.68.1 h1:y8NoHLidghpgHtWtwB9+pN7cHhIDe33g1sB4RFCRvKI=
@@ -501,10 +501,10 @@
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod
h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod
h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod
h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa
h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
-google.golang.org/genproto/googleapis/api
v0.0.0-20260526163538-3dc84a4a5aaa/go.mod
h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa
h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
-google.golang.org/genproto/googleapis/rpc
v0.0.0-20260526163538-3dc84a4a5aaa/go.mod
h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d
h1:FarXi840EJWSHYTN3ERkADbPWjl307+FGrA22KAVjjc=
+google.golang.org/genproto/googleapis/api
v0.0.0-20260803160001-6ac0973c030d/go.mod
h1:K/+WGbmBY7aNW1HDw1fJnKYo10i0DkAX6pows00dLig=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d
h1:IL4hdHzcUv2l/gcg98/Rj3FbtE6axwqslOW8SW0C+S0=
+google.golang.org/genproto/googleapis/rpc
v0.0.0-20260803160001-6ac0973c030d/go.mod
h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.19.0/go.mod
h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod
h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod
h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/container-plugin-0.7.4/go-worker/pkg/container/containerd.go
new/container-plugin-0.7.5/go-worker/pkg/container/containerd.go
--- old/container-plugin-0.7.4/go-worker/pkg/container/containerd.go
2026-09-10 17:06:26.000000000 +0200
+++ new/container-plugin-0.7.5/go-worker/pkg/container/containerd.go
2026-09-22 18:51:59.000000000 +0200
@@ -427,9 +427,13 @@
} else {
info, _ =
c.ctrToInfo(namespacedContext, container)
}
- outCh <- event.Event{
+ select {
+ case outCh <- event.Event{
Info: info,
IsCreate: isCreate,
+ }:
+ case <-ctx.Done():
+ return
}
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/container-plugin-0.7.4/go-worker/pkg/container/containerd_listener_test.go
new/container-plugin-0.7.5/go-worker/pkg/container/containerd_listener_test.go
---
old/container-plugin-0.7.4/go-worker/pkg/container/containerd_listener_test.go
1970-01-01 01:00:00.000000000 +0100
+++
new/container-plugin-0.7.5/go-worker/pkg/container/containerd_listener_test.go
2026-09-22 18:51:59.000000000 +0200
@@ -0,0 +1,109 @@
+package container
+
+import (
+ "context"
+ "log/slog"
+ "net"
+ "path/filepath"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ ctEvents "github.com/containerd/containerd/api/events"
+ containersapi
"github.com/containerd/containerd/api/services/containers/v1"
+ eventsapi "github.com/containerd/containerd/api/services/events/v1"
+ typesapi "github.com/containerd/containerd/api/types"
+ "github.com/containerd/typeurl/v2"
+ "github.com/stretchr/testify/require"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type shutdownEventService struct {
+ eventsapi.UnimplementedEventsServer
+}
+
+func (*shutdownEventService) Subscribe(_ *eventsapi.SubscribeRequest, stream
eventsapi.Events_SubscribeServer) error {
+ evt, err := typeurl.MarshalAnyToProto(&ctEvents.ContainerCreate{ID:
strings.Repeat("a", 64), Image: "alpine:latest"})
+ if err != nil {
+ return err
+ }
+ if err := stream.Send(&typesapi.Envelope{Namespace: "k8s.io", Topic:
"/containers/create", Event: evt}); err != nil {
+ return err
+ }
+ <-stream.Context().Done()
+ return stream.Context().Err()
+}
+
+type shutdownContainerService struct {
+ containersapi.UnimplementedContainersServer
+ inspecting chan struct{}
+ release chan struct{}
+}
+
+func (s *shutdownContainerService) Get(ctx context.Context, _
*containersapi.GetContainerRequest) (*containersapi.GetContainerResponse,
error) {
+ close(s.inspecting)
+ select {
+ case <-ctx.Done():
+ return nil, status.FromContextError(ctx.Err()).Err()
+ case <-s.release:
+ return nil, status.Error(codes.NotFound, "container already
removed")
+ }
+}
+
+func TestContainerdListenShutdown(t *testing.T) {
+ for _, receive := range []bool{true, false} {
+ name := "cancel_during_inspection"
+ if receive {
+ name = "delivered_fallback"
+ }
+ t.Run(name, func(t *testing.T) {
+ s := &shutdownContainerService{inspecting: make(chan
struct{}), release: make(chan struct{})}
+ socket := filepath.Join(t.TempDir(), "runtime.sock")
+ listener, err := net.Listen("unix", socket)
+ require.NoError(t, err)
+ server := grpc.NewServer()
+ containersapi.RegisterContainersServer(server, s)
+ eventsapi.RegisterEventsServer(server,
&shutdownEventService{})
+ go func() { _ = server.Serve(listener) }()
+ t.Cleanup(server.Stop)
+ engine, err :=
newContainerdEngine(context.Background(), slog.Default(), socket)
+ require.NoError(t, err)
+ t.Cleanup(func() { _ =
engine.(*containerdEngine).client.Close() })
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ var wg sync.WaitGroup
+ out, err := engine.Listen(ctx, &wg)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ cancel()
+ go func() {
+ for range out {
+ }
+ }()
+ })
+ select {
+ case <-s.inspecting:
+ case <-time.After(5 * time.Second):
+ t.Fatal("metadata request not started")
+ }
+ if receive {
+ close(s.release)
+ evt := waitOnChannelOrTimeout(t, out)
+ require.True(t, evt.IsCreate)
+ require.Equal(t, strings.Repeat("a", 64),
evt.FullID)
+ require.Equal(t, "alpine:latest", evt.Image)
+ }
+ cancel()
+ done := make(chan struct{})
+ go func() { wg.Wait(); close(done) }()
+ select {
+ case <-done:
+ case <-time.After(5 * time.Second):
+ t.Fatal("listener did not stop without an event
receiver")
+ }
+ })
+ }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/container-plugin-0.7.4/go-worker/pkg/container/cri.go
new/container-plugin-0.7.5/go-worker/pkg/container/cri.go
--- old/container-plugin-0.7.4/go-worker/pkg/container/cri.go 2026-09-10
17:06:26.000000000 +0200
+++ new/container-plugin-0.7.5/go-worker/pkg/container/cri.go 2026-09-22
18:51:59.000000000 +0200
@@ -489,7 +489,15 @@
// In case events have been disabled in the criEngine,
// an error will be captured and passed to the caller.
func (c *criEngine) Listen(ctx context.Context, wg *sync.WaitGroup) (<-chan
event.Event, error) {
+ ctx, cancel := context.WithCancel(ctx)
containerEventsCh := make(chan *v1.ContainerEventResponse)
+ // The CRI client can be blocked sending an event when its receiver
exits.
+ // Cancel the RPC, then receive until the producer closes its channel.
+ stop := func() {
+ cancel()
+ for range containerEventsCh {
+ }
+ }
// Buffered to prevent blocking; only the first subscription reports
through it.
containerEventsErrorCh := make(chan error, 1)
wg.Add(1)
@@ -532,6 +540,7 @@
select {
case err := <-containerEventsErrorCh:
if err != nil {
+ stop()
return nil, err
}
case <-time.After(containerEventsErrorTimeout):
@@ -543,6 +552,7 @@
go func() {
defer close(outCh)
defer wg.Done()
+ defer stop()
for {
select {
case <-ctx.Done():
@@ -611,8 +621,12 @@
}
info = c.ctrToInfo(ctx, ctr.GetStatus(), cPodSandbox,
ctr.GetInfo(), podSandboxStatus.GetInfo())
}
- outCh <- event.Event{
+ select {
+ case outCh <- event.Event{
Info: info,
IsCreate: evt.ContainerEventType !=
v1.ContainerEventType_CONTAINER_DELETED_EVENT,
+ }:
+ case <-ctx.Done():
+ return
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/container-plugin-0.7.4/go-worker/pkg/container/cri_test.go
new/container-plugin-0.7.5/go-worker/pkg/container/cri_test.go
--- old/container-plugin-0.7.4/go-worker/pkg/container/cri_test.go
2026-09-10 17:06:26.000000000 +0200
+++ new/container-plugin-0.7.5/go-worker/pkg/container/cri_test.go
2026-09-22 18:51:59.000000000 +0200
@@ -6,9 +6,11 @@
"errors"
"fmt"
"log/slog"
+ "strings"
"sync"
"sync/atomic"
"testing"
+ "testing/synctest"
"time"
"github.com/google/uuid"
@@ -656,6 +658,133 @@
}
}
+type shutdownRuntimeService struct {
+ internalapi.RuntimeService
+ inspecting chan struct{}
+ release chan struct{}
+ queued chan struct{}
+ finished chan struct{}
+ finishedOnce sync.Once
+ sourceError error
+ queueNext bool
+}
+
+func (s *shutdownRuntimeService) GetContainerEvents(ctx context.Context, out
chan *v1.ContainerEventResponse, _
func(v1.RuntimeService_GetContainerEventsClient)) error {
+ defer s.finishedOnce.Do(func() { close(s.finished) })
+ if s.sourceError != nil {
+ return s.sourceError
+ }
+ evt := &v1.ContainerEventResponse{ContainerId: strings.Repeat("b", 64),
ContainerEventType: v1.ContainerEventType_CONTAINER_CREATED_EVENT}
+ // Match cri-client: once Recv returns an event, its channel send does
not
+ // select on ctx.Done. Cancellation alone cannot release the producer.
+ out <- evt
+ if s.queueNext {
+ close(s.queued)
+ out <- evt
+ }
+ <-ctx.Done()
+ return ctx.Err()
+}
+
+func (s *shutdownRuntimeService) ContainerStatus(ctx context.Context, _
string, _ bool) (*v1.ContainerStatusResponse, error) {
+ select {
+ case <-s.inspecting:
+ default:
+ close(s.inspecting)
+ }
+ select {
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ case <-s.release:
+ return nil, errors.New("container already removed")
+ }
+}
+
+func TestCRIListenShutdown(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ receive, queueNext bool
+ }{
+ {name: "delivered_fallback", receive: true},
+ {name: "cancel_during_inspection"},
+ {name: "cancel_with_pending_source_send", queueNext: true},
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ config.Load(`{"hooks":7}`)
+ s := &shutdownRuntimeService{inspecting: make(chan
struct{}), release: make(chan struct{}), queued: make(chan struct{}), finished:
make(chan struct{}), queueNext: tc.queueNext}
+ engine := &criEngine{client: s, logger: slog.Default(),
runtime: typeCri.ToCTValue()}
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ var wg sync.WaitGroup
+ out, err := engine.Listen(ctx, &wg)
+ require.NoError(t, err)
+ // Rescue a broken implementation after the assertion,
so a failing
+ // regression does not leave a producer blocked for the
rest of the suite.
+ t.Cleanup(func() {
+ cancel()
+ go func() {
+ for range out {
+ }
+ }()
+ })
+ select {
+ case <-s.inspecting:
+ case <-time.After(5 * time.Second):
+ t.Fatal("metadata request not started")
+ }
+ if tc.queueNext {
+ select {
+ case <-s.queued:
+ case <-time.After(5 * time.Second):
+ t.Fatal("second source event not
queued")
+ }
+ }
+ if tc.receive {
+ close(s.release)
+ evt := waitOnChannelOrTimeout(t, out)
+ require.True(t, evt.IsCreate)
+ require.Equal(t, strings.Repeat("b", 64),
evt.FullID)
+ require.True(t, evt.IsPodSandbox)
+ }
+ cancel()
+ done := make(chan struct{})
+ go func() { wg.Wait(); close(done) }()
+ select {
+ case <-done:
+ case <-time.After(5 * time.Second):
+ t.Fatal("listener did not stop without an event
receiver")
+ }
+ select {
+ case <-s.finished:
+ default:
+ t.Fatal("upstream producer still running")
+ }
+ })
+ }
+}
+
+func TestCRIListenInitialErrorStopsProducer(t *testing.T) {
+ synctest.Test(t, func(t *testing.T) {
+ errUnavailable := errors.New("event stream unavailable")
+ s := &shutdownRuntimeService{sourceError: errUnavailable,
finished: make(chan struct{})}
+ engine := &criEngine{client: s, logger: slog.Default()}
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ var wg sync.WaitGroup
+ out, err := engine.Listen(ctx, &wg)
+ require.ErrorIs(t, err, errUnavailable)
+ require.Nil(t, out)
+ require.NoError(t, ctx.Err(), "failure cleanup must not cancel
the caller")
+ done := make(chan struct{})
+ go func() { wg.Wait(); close(done) }()
+ select {
+ case <-done:
+ case <-time.After(time.Second):
+ t.Fatal("failed listener left its producer retrying")
+ }
+ })
+}
+
// restartingRuntimeService serves one batch of events per call to
// GetContainerEvents, then ends the stream the way a runtime restart does.
type restartingRuntimeService struct {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/container-plugin-0.7.4/go-worker/pkg/container/docker.go
new/container-plugin-0.7.5/go-worker/pkg/container/docker.go
--- old/container-plugin-0.7.4/go-worker/pkg/container/docker.go
2026-09-10 17:06:26.000000000 +0200
+++ new/container-plugin-0.7.5/go-worker/pkg/container/docker.go
2026-09-22 18:51:59.000000000 +0200
@@ -336,9 +336,13 @@
dc.logger.LogAttrs(ctx,
config.LevelTrace, "container create or start event",
slog.String("container_id", msg.Actor.ID))
ctrJson, _, err =
dc.ContainerInspectWithRaw(ctx, msg.Actor.ID, config.GetWithSize())
if err == nil {
- outCh <- event.Event{
+ select {
+ case outCh <- event.Event{
Info:
dc.ctrToInfo(ctx, ctrJson),
IsCreate: true,
+ }:
+ case <-ctx.Done():
+ return
}
}
case events.ActionDestroy:
@@ -350,7 +354,8 @@
// AND as a fallback whenever
ContainerInspectWithRaw fails.
if err != nil {
// At least send an event with the
minimum set of data
- outCh <- event.Event{
+ select {
+ case outCh <- event.Event{
Info: event.Info{
Container:
event.Container{
Type:
typeDocker.ToCTValue(),
@@ -360,6 +365,9 @@
},
},
IsCreate: msg.Action !=
events.ActionDestroy,
+ }:
+ case <-ctx.Done():
+ return
}
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/container-plugin-0.7.4/go-worker/pkg/container/docker_listener_test.go
new/container-plugin-0.7.5/go-worker/pkg/container/docker_listener_test.go
--- old/container-plugin-0.7.4/go-worker/pkg/container/docker_listener_test.go
1970-01-01 01:00:00.000000000 +0100
+++ new/container-plugin-0.7.5/go-worker/pkg/container/docker_listener_test.go
2026-09-22 18:51:59.000000000 +0200
@@ -0,0 +1,185 @@
+package container
+
+import (
+ "context"
+ "encoding/json"
+ "io"
+ "log/slog"
+ "net"
+ "net/http"
+ "path/filepath"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/docker/docker/client"
+ "github.com/stretchr/testify/require"
+
+
"github.com/falcosecurity/plugins/plugins/container/go-worker/pkg/config"
+)
+
+// Docker and Podman expose the same event stream format. Keep the inspection
+// blocked until the test either allows a response or cancels the listener.
+func newListenerAPI(t *testing.T, missing bool) (string, <-chan struct{},
chan<- struct{}, <-chan struct{}) {
+ t.Helper()
+ socket := filepath.Join(t.TempDir(), "runtime.sock")
+ listener, err := net.Listen("unix", socket)
+ require.NoError(t, err)
+ inspecting, release, disconnected := make(chan struct{}), make(chan
struct{}), make(chan struct{})
+ var inspectOnce sync.Once
+ server := &http.Server{Handler: http.HandlerFunc(func(w
http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ switch {
+ case strings.HasSuffix(r.URL.Path, "/_ping"):
+ w.Header().Set("API-Version", "1.47")
+ w.Header().Set("Libpod-API-Version", "6.0.0")
+ w.Header().Set("OSType", "linux")
+ case strings.HasSuffix(r.URL.Path, "/events"):
+ // More than one event exercises a producer delivering
the next
+ // event while the listener is still inspecting the
first one.
+ for range 3 {
+ _ =
json.NewEncoder(w).Encode(map[string]any{"Type": "container", "Action":
"create", "Actor": map[string]any{"ID": fakeDockerID(1)}})
+ }
+ w.(http.Flusher).Flush()
+ <-r.Context().Done()
+ close(disconnected)
+ case strings.Contains(r.URL.Path, "/containers/") &&
strings.HasSuffix(r.URL.Path, "/json"):
+ inspectOnce.Do(func() { close(inspecting) })
+ select {
+ case <-r.Context().Done():
+ return
+ case <-release:
+ }
+ if missing {
+ w.WriteHeader(http.StatusNotFound)
+ _ =
json.NewEncoder(w).Encode(map[string]string{"message": "container already
removed"})
+ return
+ }
+ _ = json.NewEncoder(w).Encode(map[string]any{
+ "Id": fakeDockerID(1), "Name":
"/listener-test", "Created": "2026-09-09T00:00:00Z",
+ "Image": "sha256:" + strings.Repeat("a", 64),
"ImageName": "alpine:latest",
+ "Config": map[string]any{"Image":
"alpine:latest", "Labels": map[string]string{"app": "test"}},
+ })
+ default:
+ w.WriteHeader(http.StatusNotFound)
+ }
+ })}
+ go func() { _ = server.Serve(listener) }()
+ t.Cleanup(func() { _ = server.Close() })
+ return socket, inspecting, release, disconnected
+}
+
+func testHTTPListenerShutdown(t *testing.T, generate engineGenerator, observe
func(Engine, chan struct{})) {
+ t.Helper()
+ for _, tc := range []struct {
+ name string
+ receive, missing, cancelAfterInspect bool
+ }{
+ {name: "delivered_metadata", receive: true},
+ {name: "delivered_fallback", receive: true, missing: true},
+ {name: "cancel_during_inspection"},
+ {name: "cancel_after_successful_inspection",
cancelAfterInspect: true},
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ config.Load(`{"hooks":7}`)
+ socket, inspecting, release, disconnected :=
newListenerAPI(t, tc.missing)
+ // The engine context deliberately outlives the
listener: a listener
+ // must not depend on cancellation of the entire
connection.
+ engineCtx, stopEngine :=
context.WithCancel(context.Background())
+ defer stopEngine()
+ engine, err := generate(engineCtx, slog.Default(),
socket)
+ require.NoError(t, err)
+ inspected := make(chan struct{})
+ observe(engine, inspected)
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ var wg sync.WaitGroup
+ out, err := engine.Listen(ctx, &wg)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ cancel()
+ go func() {
+ for range out {
+ }
+ }()
+ })
+ select {
+ case <-inspecting:
+ case <-time.After(5 * time.Second):
+ t.Fatal("metadata request not started")
+ }
+ if tc.receive {
+ close(release)
+ for range 3 {
+ evt := waitOnChannelOrTimeout(t, out)
+ require.True(t, evt.IsCreate)
+ require.Equal(t, fakeDockerID(1),
evt.FullID)
+ if !tc.missing {
+ require.Equal(t,
"listener-test", evt.Name)
+ require.Equal(t, "test",
evt.Labels["app"])
+ }
+ }
+ }
+ if tc.cancelAfterInspect {
+ close(release)
+ select {
+ case <-inspected:
+ case <-time.After(5 * time.Second):
+ t.Fatal("successful inspection not
completed")
+ }
+ }
+ cancel()
+ done := make(chan struct{})
+ go func() { wg.Wait(); close(done) }()
+ select {
+ case <-done:
+ case <-time.After(5 * time.Second):
+ t.Fatal("listener did not stop without an event
receiver")
+ }
+ select {
+ case <-disconnected:
+ case <-time.After(5 * time.Second):
+ t.Fatal("event stream still connected after
listener stopped")
+ }
+ require.NoError(t, engineCtx.Err())
+ })
+ }
+}
+
+func TestDockerListenShutdown(t *testing.T) {
+ testHTTPListenerShutdown(t, newDockerEngine, func(engine Engine,
inspected chan struct{}) {
+ dc := engine.(*dockerEngine)
+ httpClient := dc.HTTPClient()
+ httpClient.Transport = &inspectionTransport{RoundTripper:
httpClient.Transport, inspected: inspected}
+ require.NoError(t, client.WithHTTPClient(httpClient)(dc.Client))
+ })
+}
+
+// The SDK closes an inspection response after parsing it, before returning
+// successfully. This lets a test cancel at the successful event-delivery path.
+type inspectionTransport struct {
+ http.RoundTripper
+ inspected chan struct{}
+ once sync.Once
+}
+
+func (tr *inspectionTransport) RoundTrip(req *http.Request) (*http.Response,
error) {
+ resp, err := tr.RoundTripper.RoundTrip(req)
+ if err == nil && strings.Contains(req.URL.Path, "/containers/") &&
strings.HasSuffix(req.URL.Path, "/json") {
+ tr.once.Do(func() { resp.Body =
&observedResponseBody{ReadCloser: resp.Body, closed: tr.inspected} })
+ }
+ return resp, err
+}
+
+type observedResponseBody struct {
+ io.ReadCloser
+ closed chan struct{}
+ once sync.Once
+}
+
+func (b *observedResponseBody) Close() error {
+ err := b.ReadCloser.Close()
+ b.once.Do(func() { close(b.closed) })
+ return err
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/container-plugin-0.7.4/go-worker/pkg/container/podman.go
new/container-plugin-0.7.5/go-worker/pkg/container/podman.go
--- old/container-plugin-0.7.4/go-worker/pkg/container/podman.go
2026-09-10 17:06:26.000000000 +0200
+++ new/container-plugin-0.7.5/go-worker/pkg/container/podman.go
2026-09-22 18:51:59.000000000 +0200
@@ -290,22 +290,26 @@
}
evChn := make(chan types.Event)
- cancelChan := make(chan bool)
- err := system.Events(pc.pCtx, evChn, cancelChan, &system.EventsOptions{
+ reqCtx, cancel := pc.requestCtx(ctx)
+ err := system.Events(reqCtx, evChn, nil, &system.EventsOptions{
Filters: filters,
Stream: &stream,
})
if err != nil {
+ cancel()
return nil, err
}
outCh := make(chan event.Event)
wg.Add(1)
go func() {
+ defer wg.Done()
+ defer close(outCh)
defer func() {
- wg.Done()
- close(cancelChan)
- close(outCh)
+ cancel()
+ // The bindings own evChn and can be blocked sending
the next event.
+ for range evChn {
+ }
}()
size := config.GetWithSize()
// Blocking: convert all events from podman to json strings
@@ -313,12 +317,11 @@
for {
select {
case <-ctx.Done():
- cancelChan <- true
return
case ev, ok := <-evChn:
if !ok {
// evChn has been closed - kill the
goroutine
- // NOTE this should never happen since
we are the ones closing the channel.
+ // The bindings close the channel when
the stream ends.
return
}
var (
@@ -327,11 +330,15 @@
)
switch ev.Action {
case events.ActionCreate, events.ActionStart:
- ctr, err = containers.Inspect(pc.pCtx,
ev.Actor.ID, &containers.InspectOptions{Size: &size})
+ ctr, err = containers.Inspect(reqCtx,
ev.Actor.ID, &containers.InspectOptions{Size: &size})
if err == nil {
- outCh <- event.Event{
+ select {
+ case outCh <- event.Event{
Info:
pc.ctrToInfo(ctr),
IsCreate: true,
+ }:
+ case <-ctx.Done():
+ return
}
}
case events.ActionRemove:
@@ -342,7 +349,8 @@
// AND as a fallback whenever Inspect fails.
if err != nil {
// At least send an event with the
minimal set of data
- outCh <- event.Event{
+ select {
+ case outCh <- event.Event{
Info: event.Info{
Container:
event.Container{
Type:
typePodman.ToCTValue(),
@@ -352,6 +360,9 @@
},
},
IsCreate: ev.Action !=
events.ActionRemove,
+ }:
+ case <-ctx.Done():
+ return
}
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/container-plugin-0.7.4/go-worker/pkg/container/podman_listener_test.go
new/container-plugin-0.7.5/go-worker/pkg/container/podman_listener_test.go
--- old/container-plugin-0.7.4/go-worker/pkg/container/podman_listener_test.go
1970-01-01 01:00:00.000000000 +0100
+++ new/container-plugin-0.7.5/go-worker/pkg/container/podman_listener_test.go
2026-09-22 18:51:59.000000000 +0200
@@ -0,0 +1,104 @@
+//go:build linux
+
+package container
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "log/slog"
+ "net/http"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "go.podman.io/podman/v6/pkg/bindings"
+
+
"github.com/falcosecurity/plugins/plugins/container/go-worker/pkg/config"
+)
+
+func TestPodmanListenShutdown(t *testing.T) {
+ testHTTPListenerShutdown(t, newPodmanEngine, func(engine Engine,
inspected chan struct{}) {
+ connection, err :=
bindings.GetClient(engine.(*podmanEngine).pCtx)
+ require.NoError(t, err)
+ connection.Client.Transport =
&inspectionTransport{RoundTripper: connection.Client.Transport, inspected:
inspected}
+ })
+}
+
+type eventTransport struct {
+ http.RoundTripper
+ body io.ReadCloser
+}
+
+func (tr eventTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+ if strings.HasSuffix(req.URL.Path, "/events") {
+ return &http.Response{StatusCode: http.StatusOK, Header:
make(http.Header), Body: tr.body, Request: req}, nil
+ }
+ return tr.RoundTripper.RoundTrip(req)
+}
+
+func TestPodmanListenDrainsPendingSourceEvent(t *testing.T) {
+ config.Load(`{"hooks":7}`)
+ socket, inspecting, _, _ := newListenerAPI(t, false)
+ engineCtx, stopEngine := context.WithCancel(context.Background())
+ defer stopEngine()
+ engine, err := newPodmanEngine(engineCtx, slog.Default(), socket)
+ require.NoError(t, err)
+ connection, err := bindings.GetClient(engine.(*podmanEngine).pCtx)
+ require.NoError(t, err)
+ reader, writer := io.Pipe()
+ t.Cleanup(func() { _ = reader.Close(); _ = writer.Close() })
+ body := &observedResponseBody{ReadCloser: reader, closed: make(chan
struct{})}
+ connection.Client.Transport = eventTransport{RoundTripper:
connection.Client.Transport, body: body}
+ secondRead := make(chan struct{})
+ go func() {
+ defer writer.Close()
+ for range 2 {
+ if _, err := fmt.Fprintf(writer,
`{"Type":"container","Action":"create","Actor":{"ID":%q}}`+"\n",
fakeDockerID(1)); err != nil {
+ return
+ }
+ }
+ // io.Pipe.Write returns only after the decoder read the bytes.
The
+ // SDK now has an event to send even if its context is
cancelled.
+ close(secondRead)
+ }()
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ var wg sync.WaitGroup
+ out, err := engine.Listen(ctx, &wg)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ cancel()
+ go func() {
+ for range out {
+ }
+ }()
+ })
+ select {
+ case <-inspecting:
+ case <-time.After(5 * time.Second):
+ t.Fatal("metadata request not started")
+ }
+ select {
+ case <-secondRead:
+ case <-time.After(5 * time.Second):
+ t.Fatal("second source event not read")
+ }
+ cancel()
+ done := make(chan struct{})
+ go func() { wg.Wait(); close(done) }()
+ select {
+ case <-done:
+ case <-time.After(5 * time.Second):
+ t.Fatal("listener did not stop")
+ }
+ // Only Events' deferred cleanup calls this Close. Merely cancelling an
+ // HTTP request would not prove its channel sender has returned.
+ select {
+ case <-body.closed:
+ case <-time.After(5 * time.Second):
+ t.Fatal("SDK producer stranded after listener stopped")
+ }
+}
++++++ container-plugin.obsinfo ++++++
--- /var/tmp/diff_new_pack.imQnhz/_old 2026-09-24 23:00:21.066483315 +0200
+++ /var/tmp/diff_new_pack.imQnhz/_new 2026-09-24 23:00:21.069483441 +0200
@@ -1,5 +1,5 @@
name: container-plugin
-version: 0.7.4
-mtime: 1789052786
-commit: efa4416dd148f0127499b23bb4ffa49bd417c385
+version: 0.7.5
+mtime: 1790095919
+commit: a246c88790db1180f8b15411a5fb20ce853f67a4
++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/falcosecurity-container-plugin/vendor.tar.gz
/work/SRC/openSUSE:Factory/.falcosecurity-container-plugin.new.383539/vendor.tar.gz
differ: char 5, line 1