go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/explorer/error_status.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package explorer
     5  
     6  import (
     7  	"go.mondoo.com/ranger-rpc/codes"
     8  	"go.mondoo.com/ranger-rpc/status"
     9  	"google.golang.org/genproto/googleapis/rpc/errdetails"
    10  	spb "google.golang.org/genproto/googleapis/rpc/status"
    11  )
    12  
    13  // cnquery codes start at 100 to avoid conflicts with GRPC and Ranger RPC codes
    14  // see https://github.com/mondoohq/ranger-rpc/blob/main/codes/codes.go
    15  type ErrorStatusCode uint32
    16  
    17  const (
    18  	Unknown ErrorStatusCode = iota + 100
    19  	// NotApplicable is returned when a query or asset is not applicable to the current scan
    20  	NotApplicable
    21  	// NoQueries is returned when no queries are found in the bundle for the asset
    22  	NoQueries
    23  )
    24  
    25  func NewErrorStatusCodeFromString(s string) ErrorStatusCode {
    26  	switch s {
    27  	case "NotApplicable":
    28  		return NotApplicable
    29  	case "NoQueries":
    30  		return NoQueries
    31  	}
    32  	return Unknown
    33  }
    34  
    35  func (e ErrorStatusCode) String() string {
    36  	switch e {
    37  	case NotApplicable:
    38  		return "NotApplicable"
    39  	case NoQueries:
    40  		return "NoQueries"
    41  	default:
    42  		return "Unknown"
    43  	}
    44  }
    45  
    46  // cnquery codes start at 100 to avoid conflicts with GRPC and Ranger RPC codes
    47  type ErrorCategory uint32
    48  
    49  const (
    50  	ErrorCategoryError ErrorCategory = iota
    51  	ErrorCategoryWarning
    52  	ErrorCategoryInformational
    53  )
    54  
    55  func (e ErrorCategory) String() string {
    56  	switch e {
    57  	case ErrorCategoryInformational:
    58  		return "info"
    59  	case ErrorCategoryWarning:
    60  		return "warning"
    61  	case ErrorCategoryError:
    62  		return "error"
    63  	default:
    64  		return "error"
    65  	}
    66  }
    67  
    68  func (e ErrorStatusCode) Category() ErrorCategory {
    69  	switch e {
    70  	case NotApplicable:
    71  		return ErrorCategoryInformational
    72  	case NoQueries:
    73  		return ErrorCategoryWarning
    74  	default:
    75  		return ErrorCategoryError
    76  	}
    77  }
    78  
    79  func NewErrorStatus(err error) *ErrorStatus {
    80  	s, ok := status.FromError(err)
    81  	if !ok {
    82  		// not status error - just add it as a generic error
    83  		return &ErrorStatus{
    84  			Code:    int32(codes.Unknown),
    85  			Message: err.Error(),
    86  		}
    87  	}
    88  
    89  	// if it's a status error, add it as a status error with details if possible
    90  	p := s.Proto()
    91  	if p != nil {
    92  		return &ErrorStatus{
    93  			Code:    p.GetCode(),
    94  			Message: p.GetMessage(),
    95  			Details: p.Details,
    96  		}
    97  	}
    98  	return &ErrorStatus{
    99  		Code:    int32(s.Code()),
   100  		Message: s.Message(),
   101  	}
   102  }
   103  
   104  func (e *ErrorStatus) StatusProto() *spb.Status {
   105  	return &spb.Status{
   106  		Code:    e.Code,
   107  		Message: e.Message,
   108  		Details: e.Details,
   109  	}
   110  }
   111  
   112  func (e *ErrorStatus) ErrorCode() ErrorStatusCode {
   113  	s := status.FromProto(e.StatusProto())
   114  	for _, detail := range s.Details() {
   115  		switch v := detail.(type) {
   116  		case *errdetails.ErrorInfo:
   117  			code, ok := v.Metadata["errorCode"]
   118  			if ok {
   119  				return NewErrorStatusCodeFromString(code)
   120  			}
   121  		}
   122  	}
   123  
   124  	return Unknown
   125  }