Skip to content

Commit

Permalink
refactor: migrate REGO functions to Go
Browse files Browse the repository at this point in the history
  • Loading branch information
nikpivkin committed Jan 22, 2024
1 parent c2d65f4 commit 3a22d37
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 198 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,5 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)

replace github.com/aquasecurity/trivy-policies => github.com/nikpivkin/trivy-policies v0.0.0-20240122112512-4cefa920d85c
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
github.com/aquasecurity/trivy-policies v0.8.0 h1:LvmIdw/DfTF72Lc8L+CKLYzfb5BFYzLBGFFR95PKC74=
github.com/aquasecurity/trivy-policies v0.8.0/go.mod h1:qF/t59pgK/0JTV6tXaeA3Iw3opzoMgzGCDcTDBmqb30=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
Expand Down Expand Up @@ -122,6 +120,8 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/nikpivkin/trivy-policies v0.0.0-20240122112512-4cefa920d85c h1:haHvIlIYDbyg3FcFrsPWcaEwBGBAkuPwPQ6GegoWXUE=
github.com/nikpivkin/trivy-policies v0.0.0-20240122112512-4cefa920d85c/go.mod h1:I8cjIJ/PzMkhIY+2DVT2Vco0USiOqXjw04HzSEZXp9c=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/open-policy-agent/opa v0.60.0 h1:ZPoPt4yeNs5UXCpd/P/btpSyR8CR0wfhVoh9BOwgJNs=
github.com/open-policy-agent/opa v0.60.0/go.mod h1:aD5IK6AiLNYBjNXn7E02++yC8l4Z+bRDvgM6Ss0bBzA=
Expand Down
109 changes: 0 additions & 109 deletions pkg/rego/custom.go

This file was deleted.

198 changes: 123 additions & 75 deletions pkg/rego/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"github.com/open-policy-agent/opa/rego"
)

const denyMessage = "Rego policy resulted in DENY"

type regoResult struct {
Filepath string
Resource string
Expand All @@ -24,6 +26,13 @@ type regoResult struct {
Parent *regoResult
}

func messageResult(msg string) *regoResult {
return &regoResult{
Managed: true,
Message: msg,
}
}

func (r regoResult) GetMetadata() defsecTypes.Metadata {
var m defsecTypes.Metadata
if !r.Managed {
Expand All @@ -46,102 +55,147 @@ func (r regoResult) GetRawValue() interface{} {
return nil
}

func parseResult(raw interface{}) *regoResult {
var result regoResult
result.Managed = true
switch val := raw.(type) {
case []interface{}:
var msg string
for _, item := range val {
switch raw := item.(type) {
case map[string]interface{}:
result = parseCause(raw)
case string:
msg = raw
}
func (r *regoResult) applyOffset(offset int) {
r.StartLine += offset
r.EndLine += offset
}

func (r *regoResult) updateMeta(raw map[string]any) {
for k, v := range raw {
switch k {
case "startline", "StartLine":
r.StartLine = parseLineNumber(v)
case "endline", "EndLine":
r.EndLine = parseLineNumber(v)
case "filepath", "Path":
r.Filepath = getString(v)
case "sourceprefix":
r.SourcePrefix = getString(v)
case "explicit":
r.Explicit = getBool(v)
case "managed":
r.Managed = getBool(v)
case "fskey":
r.FSKey = getString(v)
case "resource":
r.Resource = getString(v)
}
result.Message = msg
case string:
result.Message = val
case map[string]interface{}:
result = parseCause(val)
default:
result.Message = "Rego policy resulted in DENY"
}
return &result
}

func parseCause(cause map[string]interface{}) regoResult {
var result regoResult
result.Managed = true
if msg, ok := cause["msg"]; ok {
result.Message = fmt.Sprintf("%s", msg)
func getString(raw any) string {
if str, ok := raw.(string); ok {
return str
}
if filepath, ok := cause["filepath"]; ok {
result.Filepath = fmt.Sprintf("%s", filepath)
return ""
}

func getBool(raw any) bool {
if b, ok := raw.(bool); ok {
return b
}
if msg, ok := cause["fskey"]; ok {
result.FSKey = fmt.Sprintf("%s", msg)
return false
}

func newRegoResult(rawInput any) *regoResult {
result := &regoResult{
Managed: true,
}
if msg, ok := cause["resource"]; ok {
result.Resource = fmt.Sprintf("%s", msg)

input, ok := rawInput.(map[string]any)
if !ok {
return result
}
if start, ok := cause["startline"]; ok {
result.StartLine = parseLineNumber(start)

if rawMsg, exists := input["msg"]; exists {
if msg, ok := rawMsg.(string); ok {
result.Message = msg
}
}
if end, ok := cause["endline"]; ok {
result.EndLine = parseLineNumber(end)

meta := parseMetadata(input)
result.updateMeta(meta)

if parent, ok := meta["parent"]; ok {
result.Parent = newRegoResult(map[string]any{"metadata": parent})
}
if prefix, ok := cause["sourceprefix"]; ok {
result.SourcePrefix = fmt.Sprintf("%s", prefix)

return result
}

func parseMetadata(input map[string]any) map[string]any {
res := make(map[string]any)
rawMetadata, exists := input["metadata"]
if !exists {
// for backward compatibility
rawMetadata = input
}
if explicit, ok := cause["explicit"]; ok {
if set, ok := explicit.(bool); ok {
result.Explicit = set
}

cause, ok := rawMetadata.(map[string]any)
if !ok {
return res
}
if managed, ok := cause["managed"]; ok {
if set, ok := managed.(bool); ok {
result.Managed = set

rawDefsecMeta, exists := cause["__defsec_metadata"]
if !exists {
res = cause
} else {
defsecMeta, ok := rawDefsecMeta.(map[string]any)
if !ok {
return res
}
res = defsecMeta
}
if parent, ok := cause["parent"]; ok {
if m, ok := parent.(map[string]interface{}); ok {
parentResult := parseCause(m)
result.Parent = &parentResult

return res
}

func parseResult(raw any) *regoResult {

switch val := raw.(type) {
case []any:
var msg string
var result *regoResult
for _, item := range val {
switch raw := item.(type) {
case map[string]any:
if res := newRegoResult(raw); res != nil {
result = res
}
case string:
msg = raw
}
}
if result != nil {
result.Message = msg
return result
}
return messageResult(msg)
case string:
return messageResult(val)
case map[string]any:
return newRegoResult(val)
default:
return messageResult(denyMessage)
}
return result
}

func parseLineNumber(raw interface{}) int {
str := fmt.Sprintf("%s", raw)
n, _ := strconv.Atoi(str)
func parseLineNumber(raw any) int {
n, _ := strconv.Atoi(fmt.Sprintf("%s", raw))
return n
}

func (s *Scanner) convertResults(set rego.ResultSet, input Input, namespace string, rule string, traces []string) scan.Results {
var results scan.Results

offset := 0
if input.Contents != nil {
if xx, ok := input.Contents.(map[string]interface{}); ok {
if md, ok := xx["__defsec_metadata"]; ok {
if md2, ok := md.(map[string]interface{}); ok {
if sl, ok := md2["offset"]; ok {
offset, _ = sl.(int)
}
}
}
}
}
offset := input.GetOffset()

for _, result := range set {
for _, expression := range result.Expressions {
values, ok := expression.Value.([]interface{})
values, ok := expression.Value.([]any)
if !ok {
values = []interface{}{expression.Value}
values = []any{expression.Value}
}

for _, value := range values {
regoResult := parseResult(value)
regoResult.FS = input.FS
Expand All @@ -151,16 +205,10 @@ func (s *Scanner) convertResults(set rego.ResultSet, input Input, namespace stri
if regoResult.Message == "" {
regoResult.Message = fmt.Sprintf("Rego policy rule: %s.%s", namespace, rule)
}
regoResult.StartLine += offset
regoResult.EndLine += offset
regoResult.applyOffset(offset)
results.AddRego(regoResult.Message, namespace, rule, traces, regoResult)
}
}
}
return results
}

func (s *Scanner) embellishResultsWithRuleMetadata(results scan.Results, metadata StaticMetadata) scan.Results {
results.SetRule(metadata.ToRule())
return results
}
Loading

0 comments on commit 3a22d37

Please sign in to comment.