github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/rego/result.go (about)

     1  package rego
     2  
     3  import (
     4  	"fmt"
     5  	"io/fs"
     6  	"strconv"
     7  
     8  	defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types"
     9  
    10  	"github.com/khulnasoft-lab/defsec/pkg/scan"
    11  
    12  	"github.com/open-policy-agent/opa/rego"
    13  )
    14  
    15  type regoResult struct {
    16  	Filepath     string
    17  	Resource     string
    18  	StartLine    int
    19  	EndLine      int
    20  	SourcePrefix string
    21  	Message      string
    22  	Explicit     bool
    23  	Managed      bool
    24  	FSKey        string
    25  	FS           fs.FS
    26  	Parent       *regoResult
    27  }
    28  
    29  func (r regoResult) GetMetadata() defsecTypes.Metadata {
    30  	var m defsecTypes.Metadata
    31  	if !r.Managed {
    32  		m = defsecTypes.NewUnmanagedMetadata()
    33  	} else {
    34  		rng := defsecTypes.NewRangeWithFSKey(r.Filepath, r.StartLine, r.EndLine, r.SourcePrefix, r.FSKey, r.FS)
    35  		if r.Explicit {
    36  			m = defsecTypes.NewExplicitMetadata(rng, r.Resource)
    37  		} else {
    38  			m = defsecTypes.NewMetadata(rng, r.Resource)
    39  		}
    40  	}
    41  	if r.Parent != nil {
    42  		return m.WithParent(r.Parent.GetMetadata())
    43  	}
    44  	return m
    45  }
    46  
    47  func (r regoResult) GetRawValue() interface{} {
    48  	return nil
    49  }
    50  
    51  func parseResult(raw interface{}) *regoResult {
    52  	var result regoResult
    53  	result.Managed = true
    54  	switch val := raw.(type) {
    55  	case []interface{}:
    56  		var msg string
    57  		for _, item := range val {
    58  			switch raw := item.(type) {
    59  			case map[string]interface{}:
    60  				result = parseCause(raw)
    61  			case string:
    62  				msg = raw
    63  			}
    64  		}
    65  		result.Message = msg
    66  	case string:
    67  		result.Message = val
    68  	case map[string]interface{}:
    69  		result = parseCause(val)
    70  	default:
    71  		result.Message = "Rego policy resulted in DENY"
    72  	}
    73  	return &result
    74  }
    75  
    76  func parseCause(cause map[string]interface{}) regoResult {
    77  	var result regoResult
    78  	result.Managed = true
    79  	if msg, ok := cause["msg"]; ok {
    80  		result.Message = fmt.Sprintf("%s", msg)
    81  	}
    82  	if filepath, ok := cause["filepath"]; ok {
    83  		result.Filepath = fmt.Sprintf("%s", filepath)
    84  	}
    85  	if msg, ok := cause["fskey"]; ok {
    86  		result.FSKey = fmt.Sprintf("%s", msg)
    87  	}
    88  	if msg, ok := cause["resource"]; ok {
    89  		result.Resource = fmt.Sprintf("%s", msg)
    90  	}
    91  	if start, ok := cause["startline"]; ok {
    92  		result.StartLine = parseLineNumber(start)
    93  	}
    94  	if end, ok := cause["endline"]; ok {
    95  		result.EndLine = parseLineNumber(end)
    96  	}
    97  	if prefix, ok := cause["sourceprefix"]; ok {
    98  		result.SourcePrefix = fmt.Sprintf("%s", prefix)
    99  	}
   100  	if explicit, ok := cause["explicit"]; ok {
   101  		if set, ok := explicit.(bool); ok {
   102  			result.Explicit = set
   103  		}
   104  	}
   105  	if managed, ok := cause["managed"]; ok {
   106  		if set, ok := managed.(bool); ok {
   107  			result.Managed = set
   108  		}
   109  	}
   110  	if parent, ok := cause["parent"]; ok {
   111  		if m, ok := parent.(map[string]interface{}); ok {
   112  			parentResult := parseCause(m)
   113  			result.Parent = &parentResult
   114  		}
   115  	}
   116  	return result
   117  }
   118  
   119  func parseLineNumber(raw interface{}) int {
   120  	str := fmt.Sprintf("%s", raw)
   121  	n, _ := strconv.Atoi(str)
   122  	return n
   123  }
   124  
   125  func (s *Scanner) convertResults(set rego.ResultSet, input Input, namespace string, rule string, traces []string) scan.Results {
   126  	var results scan.Results
   127  
   128  	offset := 0
   129  	if input.Contents != nil {
   130  		if xx, ok := input.Contents.(map[string]interface{}); ok {
   131  			if md, ok := xx["__defsec_metadata"]; ok {
   132  				if md2, ok := md.(map[string]interface{}); ok {
   133  					if sl, ok := md2["offset"]; ok {
   134  						offset, _ = sl.(int)
   135  					}
   136  				}
   137  			}
   138  		}
   139  	}
   140  	for _, result := range set {
   141  		for _, expression := range result.Expressions {
   142  			values, ok := expression.Value.([]interface{})
   143  			if !ok {
   144  				values = []interface{}{expression.Value}
   145  			}
   146  
   147  			for _, value := range values {
   148  				regoResult := parseResult(value)
   149  				regoResult.FS = input.FS
   150  				if regoResult.Filepath == "" && input.Path != "" {
   151  					regoResult.Filepath = input.Path
   152  				}
   153  				if regoResult.Message == "" {
   154  					regoResult.Message = fmt.Sprintf("Rego policy rule: %s.%s", namespace, rule)
   155  				}
   156  				regoResult.StartLine += offset
   157  				regoResult.EndLine += offset
   158  				results.AddRego(regoResult.Message, namespace, rule, traces, regoResult)
   159  			}
   160  		}
   161  	}
   162  	return results
   163  }
   164  
   165  func (s *Scanner) embellishResultsWithRuleMetadata(results scan.Results, metadata StaticMetadata) scan.Results {
   166  	results.SetRule(metadata.ToRule())
   167  	return results
   168  }