mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-05 20:40:16 -08:00
refactor(misconf): add ManifestFromYAML for unified manifest parsing (#9680)
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
@@ -10,13 +10,17 @@ import (
|
||||
)
|
||||
|
||||
type Manifest struct {
|
||||
Path string
|
||||
Content *ManifestNode
|
||||
FilePath string
|
||||
Content *ManifestNode
|
||||
}
|
||||
|
||||
func NewManifest(path string, root *ManifestNode) *Manifest {
|
||||
func NewManifest(path string, root *ManifestNode) (*Manifest, error) {
|
||||
if root.Type != TagMap {
|
||||
return &Manifest{FilePath: path}, nil
|
||||
}
|
||||
|
||||
root.Walk(func(n *ManifestNode) {
|
||||
n.Path = path
|
||||
n.FilePath = path
|
||||
switch v := n.Value.(type) {
|
||||
case []*ManifestNode:
|
||||
n.Value = lo.Filter(v, func(vv *ManifestNode, _ int) bool {
|
||||
@@ -29,38 +33,32 @@ func NewManifest(path string, root *ManifestNode) *Manifest {
|
||||
}
|
||||
})
|
||||
return &Manifest{
|
||||
Path: path,
|
||||
Content: root,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manifest) UnmarshalYAML(value *yaml.Node) error {
|
||||
|
||||
switch value.Tag {
|
||||
case string(TagMap):
|
||||
node := new(ManifestNode)
|
||||
node.Path = m.Path
|
||||
if err := value.Decode(node); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Content = node
|
||||
default:
|
||||
return fmt.Errorf("failed to handle tag: %s", value.Tag)
|
||||
}
|
||||
|
||||
return nil
|
||||
FilePath: path,
|
||||
Content: root,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Manifest) ToRego() any {
|
||||
if m.Content == nil {
|
||||
return nil
|
||||
}
|
||||
return m.Content.ToRego()
|
||||
}
|
||||
|
||||
func ManifestFromJSON(path string, data []byte) (*Manifest, error) {
|
||||
var root = &ManifestNode{}
|
||||
|
||||
if err := xjson.Unmarshal(data, root); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("unmarshal json: %w", err)
|
||||
}
|
||||
|
||||
return NewManifest(path, root), nil
|
||||
return NewManifest(path, root)
|
||||
}
|
||||
|
||||
func ManifestFromYAML(path string, data []byte) (*Manifest, error) {
|
||||
var root = &ManifestNode{}
|
||||
if err := yaml.Unmarshal(data, root); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal yaml: %w", err)
|
||||
}
|
||||
|
||||
return NewManifest(path, root)
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ const (
|
||||
|
||||
type ManifestNode struct {
|
||||
xjson.Location
|
||||
Offset int
|
||||
Value any
|
||||
Type TagType
|
||||
Path string
|
||||
Offset int
|
||||
Value any
|
||||
Type TagType
|
||||
FilePath string
|
||||
}
|
||||
|
||||
func (n *ManifestNode) ToRego() any {
|
||||
@@ -72,7 +72,7 @@ func (n *ManifestNode) metadata() map[string]any {
|
||||
return map[string]any{
|
||||
"startline": n.StartLine,
|
||||
"endline": n.EndLine,
|
||||
"filepath": n.Path,
|
||||
"filepath": n.FilePath,
|
||||
"offset": n.Offset,
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func (n *ManifestNode) UnmarshalYAML(node *yaml.Node) error {
|
||||
default:
|
||||
log.WithPrefix("k8s").Debug("Skipping unsupported node tag",
|
||||
log.String("tag", node.Tag),
|
||||
log.FilePath(n.Path),
|
||||
log.FilePath(n.FilePath),
|
||||
log.Int("line", node.Line),
|
||||
)
|
||||
}
|
||||
@@ -134,7 +134,7 @@ func (n *ManifestNode) handleSliceTag(node *yaml.Node) error {
|
||||
maxLine := node.Line
|
||||
for _, contentNode := range node.Content {
|
||||
newNode := new(ManifestNode)
|
||||
newNode.Path = n.Path
|
||||
newNode.FilePath = n.FilePath
|
||||
if err := contentNode.Decode(newNode); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -157,7 +157,7 @@ func (n *ManifestNode) handleMapTag(node *yaml.Node) error {
|
||||
key = contentNode.Value
|
||||
} else {
|
||||
newNode := new(ManifestNode)
|
||||
newNode.Path = n.Path
|
||||
newNode.FilePath = n.FilePath
|
||||
if err := contentNode.Decode(newNode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/iac/scanners/kubernetes/parser"
|
||||
)
|
||||
@@ -86,6 +85,7 @@ func TestJsonManifestToRego(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestManifestToRego(t *testing.T) {
|
||||
const filePath = "pod.json"
|
||||
tests := []struct {
|
||||
name string
|
||||
src string
|
||||
@@ -96,7 +96,7 @@ func TestManifestToRego(t *testing.T) {
|
||||
src: `field: !!timestamp 2024-04-01`,
|
||||
expected: map[string]any{
|
||||
"__defsec_metadata": map[string]any{
|
||||
"filepath": "",
|
||||
"filepath": filePath,
|
||||
"offset": 0,
|
||||
"startline": 1,
|
||||
"endline": 1,
|
||||
@@ -109,7 +109,7 @@ func TestManifestToRego(t *testing.T) {
|
||||
src: `field: !!binary dGVzdA==`,
|
||||
expected: map[string]any{
|
||||
"__defsec_metadata": map[string]any{
|
||||
"filepath": "",
|
||||
"filepath": filePath,
|
||||
"offset": 0,
|
||||
"startline": 1,
|
||||
"endline": 1,
|
||||
@@ -122,7 +122,7 @@ func TestManifestToRego(t *testing.T) {
|
||||
src: `field: 1.1`,
|
||||
expected: map[string]any{
|
||||
"__defsec_metadata": map[string]any{
|
||||
"filepath": "",
|
||||
"filepath": filePath,
|
||||
"offset": 0,
|
||||
"startline": 1,
|
||||
"endline": 1,
|
||||
@@ -134,8 +134,7 @@ func TestManifestToRego(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var manifest parser.Manifest
|
||||
err := yaml.Unmarshal([]byte(tt.src), &manifest)
|
||||
manifest, err := parser.ManifestFromYAML(filePath, []byte(tt.src))
|
||||
require.NoError(t, err)
|
||||
data := manifest.ToRego()
|
||||
assert.Equal(t, tt.expected, data)
|
||||
|
||||
@@ -3,12 +3,9 @@ package parser
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func Parse(_ context.Context, r io.Reader, path string) ([]any, error) {
|
||||
@@ -29,22 +26,23 @@ func Parse(_ context.Context, r io.Reader, path string) ([]any, error) {
|
||||
return []any{manifest.ToRego()}, nil
|
||||
}
|
||||
|
||||
var results []any
|
||||
var manifests []any
|
||||
|
||||
re := regexp.MustCompile(`(?m:^---\r?\n)`)
|
||||
pos := 0
|
||||
offset := 0
|
||||
for _, partial := range re.Split(string(contents), -1) {
|
||||
var result Manifest
|
||||
result.Path = path
|
||||
if err := yaml.Unmarshal([]byte(partial), &result); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal yaml: %w", err)
|
||||
manifest, err := ManifestFromYAML(path, []byte(partial))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Content != nil {
|
||||
result.Content.Offset = pos
|
||||
results = append(results, result.ToRego())
|
||||
|
||||
if manifest.Content != nil {
|
||||
manifest.Content.Offset = offset
|
||||
manifests = append(manifests, manifest.ToRego())
|
||||
}
|
||||
pos += len(strings.Split(partial, "\n"))
|
||||
|
||||
offset += len(strings.Split(partial, "\n"))
|
||||
}
|
||||
|
||||
return results, nil
|
||||
return manifests, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user