go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/detector/platform_resolver.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package detector
     5  
     6  import (
     7  	"github.com/rs/zerolog/log"
     8  	"go.mondoo.com/cnquery/providers-sdk/v1/inventory"
     9  	"go.mondoo.com/cnquery/providers/os/connection"
    10  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    11  )
    12  
    13  type detect func(r *PlatformResolver, pf *inventory.Platform, conn shared.Connection) (bool, error)
    14  
    15  type PlatformResolver struct {
    16  	Name     string
    17  	IsFamily bool
    18  	Children []*PlatformResolver
    19  	Detect   detect
    20  }
    21  
    22  func (r *PlatformResolver) Resolve(conn shared.Connection) (*inventory.Platform, bool) {
    23  	// prepare detect info object
    24  	di := &inventory.Platform{}
    25  	di.Family = make([]string, 0)
    26  
    27  	// start recursive platform resolution
    28  	pi, resolved := r.resolvePlatform(di, conn)
    29  
    30  	// if we have a container image use the architecture specified in the transport as it is resolved
    31  	// using the container image properties
    32  	tarConn, ok := conn.(*connection.TarConnection)
    33  	if resolved && ok {
    34  		pi.Arch = tarConn.PlatformArchitecture
    35  		di.Runtime = "docker-image"
    36  		di.Kind = "container-image"
    37  
    38  		// if the platform name is not set, we should fallback to the scratch operating system
    39  		if len(pi.Name) == 0 {
    40  			di.Name = "scratch"
    41  			di.Arch = tarConn.PlatformArchitecture
    42  			return di, true
    43  		}
    44  	}
    45  
    46  	containerConn, ok := conn.(*connection.DockerContainerConnection)
    47  	if resolved && ok {
    48  		pi.Arch = containerConn.PlatformArchitecture
    49  		di.Runtime = string(containerConn.Type())
    50  		di.Kind = "container"
    51  
    52  		// if the platform name is not set, we should fallback to the scratch operating system
    53  		if len(pi.Name) == 0 {
    54  			di.Name = "scratch"
    55  			di.Arch = pi.Arch
    56  			return di, true
    57  		}
    58  	}
    59  
    60  	log.Debug().Str("platform", pi.Name).Strs("family", pi.Family).Msg("platform> detected os")
    61  	return pi, resolved
    62  }
    63  
    64  // Resolve tries to find recursively all
    65  // platforms until a leaf (operating systems) detect
    66  // mechanism is returning true
    67  func (r *PlatformResolver) resolvePlatform(pf *inventory.Platform, conn shared.Connection) (*inventory.Platform, bool) {
    68  	detected, err := r.Detect(r, pf, conn)
    69  	if err != nil {
    70  		return pf, false
    71  	}
    72  
    73  	// if detection is true but we have a family
    74  	if detected == true && r.IsFamily == true {
    75  		// we are a family and we may have children to try
    76  		for _, c := range r.Children {
    77  			detected, resolved := c.resolvePlatform(pf, conn)
    78  			if resolved {
    79  				// add family hieracy
    80  				detected.Family = append(pf.Family, r.Name)
    81  				return detected, resolved
    82  			}
    83  		}
    84  
    85  		// we reached this point, we know it is the platfrom but we could not
    86  		// identify the system
    87  		// TODO: add generic platform instance
    88  		// TODO: should we return an error?
    89  	}
    90  
    91  	// return if the detect is true and we have a leaf
    92  	if detected && r.IsFamily == false {
    93  		return pf, true
    94  	}
    95  
    96  	// could not find it
    97  	return pf, false
    98  }