github.com/google/osv-scalibr@v0.4.1/extractor/standalone/containers/docker/docker.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package docker extracts container inventory from docker API.
    16  package docker
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  
    22  	"github.com/docker/docker/api/types/container"
    23  	"github.com/docker/docker/client"
    24  	"github.com/google/osv-scalibr/extractor"
    25  	"github.com/google/osv-scalibr/extractor/standalone"
    26  	"github.com/google/osv-scalibr/inventory"
    27  	"github.com/google/osv-scalibr/plugin"
    28  )
    29  
    30  const (
    31  	// Name is the unique name of this extractor.
    32  	Name = "containers/docker"
    33  )
    34  
    35  // Extractor implements the docker extractor.
    36  type Extractor struct {
    37  	client Client
    38  }
    39  
    40  // New returns an extractor
    41  func New() standalone.Extractor {
    42  	return &Extractor{}
    43  }
    44  
    45  // NewWithClient returns an extractor which uses a specified docker client.
    46  func NewWithClient(c Client) standalone.Extractor {
    47  	return &Extractor{client: c}
    48  }
    49  
    50  // Name of the extractor.
    51  func (e Extractor) Name() string { return Name }
    52  
    53  // Version of the extractor.
    54  func (e Extractor) Version() int { return 0 }
    55  
    56  // Requirements of the extractor.
    57  func (e Extractor) Requirements() *plugin.Capabilities {
    58  	return &plugin.Capabilities{RunningSystem: true}
    59  }
    60  
    61  // Extract extracts containers from the docker API.
    62  func (e *Extractor) Extract(ctx context.Context, input *standalone.ScanInput) (inventory.Inventory, error) {
    63  	if e.client == nil {
    64  		var err error
    65  		e.client, err = client.NewClientWithOpts(client.WithAPIVersionNegotiation())
    66  		if err != nil {
    67  			return inventory.Inventory{}, fmt.Errorf("cannot connect with docker %w", err)
    68  		}
    69  	}
    70  
    71  	// extract running containers
    72  	containers, err := e.client.ContainerList(ctx, container.ListOptions{})
    73  	if err != nil {
    74  		return inventory.Inventory{}, fmt.Errorf("error fetching containers: %w", err)
    75  	}
    76  
    77  	pkgs := make([]*extractor.Package, 0, len(containers))
    78  	for _, ctr := range containers {
    79  		pkgs = append(pkgs, &extractor.Package{
    80  			Name:    ctr.Image,
    81  			Version: ctr.ImageID,
    82  			Metadata: &Metadata{
    83  				ImageName:   ctr.Image,
    84  				ImageDigest: ctr.ImageID,
    85  				ID:          ctr.ID,
    86  				Ports:       ctr.Ports,
    87  			},
    88  		})
    89  	}
    90  	return inventory.Inventory{Packages: pkgs}, nil
    91  }