1515package operators
1616
1717import (
18+ "context"
1819 "fmt"
1920 "log/slog"
2021 "math"
22+ "time"
2123
2224 "github.com/inspektor-gadget/inspektor-gadget/pkg/datasource"
2325 igoperators "github.com/inspektor-gadget/inspektor-gadget/pkg/operators"
@@ -27,6 +29,8 @@ import (
2729 ocihandler "github.com/inspektor-gadget/inspektor-gadget/pkg/operators/oci-handler"
2830 "github.com/inspektor-gadget/inspektor-gadget/pkg/operators/simple"
2931 "github.com/inspektor-gadget/inspektor-gadget/pkg/utils/host"
32+
33+ "github.com/micromize-dev/micromize/internal/sbom"
3034)
3135
3236// DataOperator is an alias for igoperators.DataOperator to avoid direct dependency in main
@@ -60,10 +64,12 @@ func NewCLIOperator() igoperators.DataOperator {
6064func NewImaOperator () igoperators.DataOperator {
6165 slog .Debug ("Creating IMA operator" )
6266 opPriority := math .MaxInt
67+ sbomFetcher := sbom .NewFetcher ()
6368
6469 operatorOptions := []simple.Option {
6570 simple .WithPriority (opPriority ),
6671 simple .OnInit (func (gadgetCtx igoperators.GadgetContext ) error {
72+ ctx := gadgetCtx .Context ()
6773 containersDatasource := gadgetCtx .GetDataSources ()["containers" ]
6874 if containersDatasource == nil {
6975 slog .Debug ("IMA Operator: containers datasource not available, skipping" )
@@ -75,14 +81,20 @@ func NewImaOperator() igoperators.DataOperator {
7581 return fmt .Errorf ("containers datasource missing event_type field" )
7682 }
7783
84+ containerConfigField := containersDatasource .GetField ("container_config" )
85+ if containerConfigField == nil {
86+ return fmt .Errorf ("containers datasource missing container_config field" )
87+ }
88+
89+ containerIDField := containersDatasource .GetField ("container_id" )
90+
7891 if err := containersDatasource .Subscribe (func (source datasource.DataSource , data datasource.Data ) error {
7992 eventType , err := eventTypeField .String (data )
8093 if err != nil {
8194 return fmt .Errorf ("getting event_type value: %w" , err )
8295 }
83-
8496 if eventType == "CREATED" {
85- slog . Info ( "IMA Operator: Container created event received" )
97+ handleContainerCreated ( ctx , sbomFetcher , containerConfigField , containerIDField , data )
8698 }
8799 return nil
88100 }, opPriority ); err != nil {
@@ -93,3 +105,47 @@ func NewImaOperator() igoperators.DataOperator {
93105 }
94106 return simple .New ("imaOperator" , operatorOptions ... )
95107}
108+
109+ func handleContainerCreated (ctx context.Context , fetcher * sbom.Fetcher , configField datasource.FieldAccessor , containerIDField datasource.FieldAccessor , data datasource.Data ) {
110+ ociConfig , err := configField .String (data )
111+ if err != nil {
112+ slog .Debug ("Failed to read container_config field" , "error" , err )
113+ return
114+ }
115+
116+ imageRef , err := sbom .ImageRefFromOCIConfig (ociConfig )
117+ if err != nil {
118+ slog .Debug ("Failed to parse OCI config" , "error" , err )
119+ return
120+ }
121+
122+ // Fallback: read image ref from Docker's config.v2.json when
123+ // OCI annotations don't contain the image name (plain Docker).
124+ if imageRef == "" && containerIDField != nil {
125+ containerID , _ := containerIDField .String (data )
126+ imageRef = sbom .ImageRefFromDockerConfig (containerID )
127+ }
128+
129+ imageRef = sbom .NormalizeImageRef (imageRef )
130+
131+ fetchCtx , cancel := context .WithTimeout (ctx , 30 * time .Second )
132+ defer cancel ()
133+
134+ sbomData , err := fetcher .FetchForImage (fetchCtx , imageRef )
135+ if err != nil {
136+ slog .Error ("Failed to fetch SBOM" , "error" , err )
137+ return
138+ }
139+ if sbomData != nil {
140+ slog .Info ("SBOM fetched for container image" , "image" , imageRef , "size" , len (sbomData ))
141+
142+ files , err := sbom .ParseFiles (sbomData )
143+ if err != nil {
144+ slog .Error ("Failed to parse SBOM files" , "error" , err )
145+ return
146+ }
147+ for _ , f := range files {
148+ slog .Info ("SBOM binary file" , "image" , imageRef , "file" , f .FileName , "sha256" , f .SHA256 )
149+ }
150+ }
151+ }
0 commit comments