Skip to content

Commit 9da60be

Browse files
committed
refactor(misconf): migrate from custom Azure JSON parser
Signed-off-by: nikpivkin <[email protected]>
1 parent 51aa022 commit 9da60be

File tree

4 files changed

+210
-39
lines changed

4 files changed

+210
-39
lines changed

pkg/iac/scanners/azure/arm/parser/parser.go

Lines changed: 108 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
package parser
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
67
"io"
78
"io/fs"
9+
"iter"
10+
"strconv"
11+
"strings"
812

13+
"github.com/go-json-experiment/json"
14+
"github.com/go-json-experiment/json/jsontext"
15+
16+
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
917
"github.com/aquasecurity/trivy/pkg/iac/scanners/azure"
10-
"github.com/aquasecurity/trivy/pkg/iac/scanners/azure/arm/parser/armjson"
1118
"github.com/aquasecurity/trivy/pkg/iac/scanners/azure/resolver"
1219
"github.com/aquasecurity/trivy/pkg/iac/types"
1320
"github.com/aquasecurity/trivy/pkg/log"
21+
xjson "github.com/aquasecurity/trivy/pkg/x/json"
1422
)
1523

1624
type Parser struct {
@@ -50,6 +58,7 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) ([]azure.Deployment, e
5058

5159
deployment, err := p.parseFile(f, path)
5260
if err != nil {
61+
println(err.Error())
5362
p.logger.Error("Failed to parse file", log.FilePath(path), log.Err(err))
5463
return nil
5564
}
@@ -64,22 +73,115 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) ([]azure.Deployment, e
6473
}
6574

6675
func (p *Parser) parseFile(r io.Reader, filename string) (*azure.Deployment, error) {
67-
var template Template
76+
6877
data, err := io.ReadAll(r)
6978
if err != nil {
7079
return nil, err
7180
}
72-
root := types.NewMetadata(
81+
82+
data = xjson.ToRFC8259(data)
83+
84+
lr := xjson.NewLineReader(bytes.NewReader(data))
85+
86+
var template Template
87+
88+
rootMetadata := types.NewMetadata(
7389
types.NewRange(filename, 0, 0, "", p.targetFS),
7490
"",
7591
).WithInternal(resolver.NewResolver())
7692

77-
if err := armjson.Unmarshal(data, &template, &root); err != nil {
78-
return nil, fmt.Errorf("failed to parse template: %w", err)
93+
if err := json.UnmarshalRead(lr, &template, json.WithUnmarshalers(
94+
json.JoinUnmarshalers(
95+
xjson.UnmarshalerWithObjectLocation(lr, func() xjson.DecodeHook {
96+
stack := map[jsontext.Pointer]*types.Metadata{
97+
"": {},
98+
}
99+
return xjson.DecodeHook{
100+
Before: func(dec *jsontext.Decoder, obj any) {
101+
pointer := dec.StackPointer()
102+
if pointer != "" {
103+
// Do not overwrite metadata if we have already set it below
104+
if _, exists := stack[pointer]; !exists {
105+
if _, ok := obj.(MetadataReceiver); ok {
106+
stack[pointer] = &types.Metadata{}
107+
}
108+
109+
}
110+
}
111+
112+
// The array node is visited after all its elements,
113+
// so the parent metadata must already be created.
114+
// parent := pointer.Parent()
115+
// if _, err := strconv.Atoi(pointer.Parent().LastToken()); err == nil {
116+
// stack[parent] = &types.Metadata{}
117+
// }
118+
},
119+
After: func(dec *jsontext.Decoder, obj any, loc ftypes.Location) {
120+
pointer := dec.StackPointer()
121+
ref := buildNodeRef(pointer.Tokens())
122+
rng := types.NewRange(filename, loc.StartLine, loc.EndLine, "", p.targetFS)
123+
metadata := types.NewMetadata(rng, ref)
124+
125+
if pointer == "" {
126+
metadata.SetParentPtr(&rootMetadata)
127+
} else {
128+
parentPtr := pointer.Parent()
129+
for parentPtr != "" {
130+
if parent, ok := stack[parentPtr]; ok {
131+
metadata.SetParentPtr(parent)
132+
break
133+
}
134+
parentPtr = parentPtr.Parent()
135+
}
136+
137+
if parentPtr == "" {
138+
metadata.SetParentPtr(&template.Metadata)
139+
}
140+
}
141+
142+
existingMeta, ok := stack[pointer]
143+
if ok {
144+
*existingMeta = metadata
145+
} else {
146+
stack[pointer.Parent()] = &metadata
147+
existingMeta = &metadata
148+
}
149+
150+
if mr, ok := obj.(MetadataReceiver); ok {
151+
mr.SetMetadata(*existingMeta)
152+
}
153+
},
154+
}
155+
}()),
156+
),
157+
)); err != nil {
158+
return nil, fmt.Errorf("unmarshal template: %w", err)
79159
}
80160
return p.convertTemplate(template), nil
81161
}
82162

163+
func buildNodeRef(seq iter.Seq[string]) string {
164+
var sb strings.Builder
165+
for el := range seq {
166+
if _, err := strconv.Atoi(el); err == nil {
167+
sb.WriteString("[")
168+
sb.WriteString(el)
169+
sb.WriteString("]")
170+
} else {
171+
if sb.Len() > 0 {
172+
sb.WriteString(".")
173+
}
174+
sb.WriteString(el)
175+
}
176+
177+
}
178+
return sb.String()
179+
}
180+
181+
type MetadataReceiver interface {
182+
SetMetadata(types.Metadata)
183+
}
184+
83185
func (p *Parser) convertTemplate(template Template) *azure.Deployment {
84186

85187
deployment := azure.Deployment{
@@ -142,7 +244,7 @@ func (p *Parser) convertResource(input Resource) azure.Resource {
142244
Type: input.Type,
143245
Kind: input.Kind,
144246
Name: input.Name,
145-
Location: input.Location,
247+
Location: input.Loc,
146248
Properties: input.Properties,
147249
Resources: children,
148250
}

pkg/iac/scanners/azure/arm/parser/template.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import (
44
"github.com/aquasecurity/trivy/pkg/iac/scanners/azure"
55
"github.com/aquasecurity/trivy/pkg/iac/scanners/azure/arm/parser/armjson"
66
"github.com/aquasecurity/trivy/pkg/iac/types"
7+
xjson "github.com/aquasecurity/trivy/pkg/x/json"
78
)
89

910
type Template struct {
11+
xjson.Location
1012
Metadata types.Metadata `json:"-"`
1113
Schema azure.Value `json:"$schema"`
1214
ContentVersion azure.Value `json:"contentVersion"`
@@ -19,6 +21,7 @@ type Template struct {
1921
}
2022

2123
type Parameter struct {
24+
xjson.Location
2225
Metadata types.Metadata
2326
Type azure.Value `json:"type"`
2427
DefaultValue azure.Value `json:"defaultValue"`
@@ -33,24 +36,25 @@ type Resource struct {
3336
innerResource
3437
}
3538

36-
func (t *Template) SetMetadata(m *types.Metadata) {
37-
t.Metadata = *m
39+
func (t *Template) SetMetadata(m types.Metadata) {
40+
t.Metadata = m
3841
}
3942

40-
func (r *Resource) SetMetadata(m *types.Metadata) {
41-
r.Metadata = *m
43+
func (r *Resource) SetMetadata(m types.Metadata) {
44+
r.Metadata = m
4245
}
4346

44-
func (p *Parameter) SetMetadata(m *types.Metadata) {
45-
p.Metadata = *m
47+
func (p *Parameter) SetMetadata(m types.Metadata) {
48+
p.Metadata = m
4649
}
4750

4851
type innerResource struct {
52+
xjson.Location
4953
APIVersion azure.Value `json:"apiVersion"`
5054
Type azure.Value `json:"type"`
5155
Kind azure.Value `json:"kind"`
5256
Name azure.Value `json:"name"`
53-
Location azure.Value `json:"location"`
57+
Loc azure.Value `json:"location"`
5458
Tags azure.Value `json:"tags"`
5559
Sku azure.Value `json:"sku"`
5660
Properties azure.Value `json:"properties"`

pkg/iac/scanners/azure/value.go

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package azure
22

33
import (
4+
"fmt"
45
"slices"
56
"strings"
67
"time"
78

8-
armjson2 "github.com/aquasecurity/trivy/pkg/iac/scanners/azure/arm/parser/armjson"
9+
"github.com/aquasecurity/trivy/pkg/iac/scanners/azure/arm/parser/armjson"
910
"github.com/aquasecurity/trivy/pkg/iac/types"
11+
xjson "github.com/aquasecurity/trivy/pkg/x/json"
12+
"github.com/go-json-experiment/json"
13+
"github.com/go-json-experiment/json/jsontext"
1014
)
1115

1216
type EvalContext struct{}
@@ -25,6 +29,7 @@ const (
2529
)
2630

2731
type Value struct {
32+
xjson.Location
2833
types.Metadata
2934
rLit any
3035
rMap map[string]Value
@@ -97,24 +102,66 @@ func (v *Value) GetMetadata() types.Metadata {
97102
return v.Metadata
98103
}
99104

100-
func (v *Value) UnmarshalJSONWithMetadata(node armjson2.Node) error {
105+
func (v *Value) SetMetadata(m types.Metadata) {
106+
v.Metadata = m
107+
}
108+
109+
func (n *Value) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
110+
switch k := dec.PeekKind(); k {
111+
case 't', 'f':
112+
n.Kind = KindBoolean
113+
if err := json.UnmarshalDecode(dec, &n.rLit); err != nil {
114+
return err
115+
}
116+
case '"':
117+
n.Kind = KindString
118+
if err := json.UnmarshalDecode(dec, &n.rLit); err != nil {
119+
return err
120+
}
121+
case '0':
122+
n.Kind = KindNumber
123+
if err := json.UnmarshalDecode(dec, &n.rLit); err != nil {
124+
return err
125+
}
126+
case '[':
127+
n.Kind = KindArray
128+
if err := json.UnmarshalDecode(dec, &n.rArr); err != nil {
129+
return err
130+
}
131+
case '{':
132+
n.Kind = KindObject
133+
if err := json.UnmarshalDecode(dec, &n.rMap); err != nil {
134+
return err
135+
}
136+
case 'n':
137+
// TODO: UnmarshalJSONFrom is called only for the root null
138+
return dec.SkipValue()
139+
case 0:
140+
return dec.SkipValue()
141+
default:
142+
return fmt.Errorf("unexpected token kind %q at %d", k.String(), dec.InputOffset())
143+
}
144+
return nil
145+
}
146+
147+
func (v *Value) UnmarshalJSONWithMetadata(node armjson.Node) error {
101148

102149
v.updateValueKind(node)
103150

104151
v.Metadata = node.Metadata()
105152

106153
switch node.Kind() {
107-
case armjson2.KindArray:
154+
case armjson.KindArray:
108155
err := v.unmarshallArray(node)
109156
if err != nil {
110157
return err
111158
}
112-
case armjson2.KindObject:
159+
case armjson.KindObject:
113160
err := v.unmarshalObject(node)
114161
if err != nil {
115162
return err
116163
}
117-
case armjson2.KindString:
164+
case armjson.KindString:
118165
err := v.unmarshalString(node)
119166
if err != nil {
120167
return err
@@ -138,7 +185,7 @@ func (v *Value) UnmarshalJSONWithMetadata(node armjson2.Node) error {
138185
return nil
139186
}
140187

141-
func (v *Value) unmarshalString(node armjson2.Node) error {
188+
func (v *Value) unmarshalString(node armjson.Node) error {
142189
var str string
143190
if err := node.Decode(&str); err != nil {
144191
return err
@@ -153,7 +200,7 @@ func (v *Value) unmarshalString(node armjson2.Node) error {
153200
return nil
154201
}
155202

156-
func (v *Value) unmarshalObject(node armjson2.Node) error {
203+
func (v *Value) unmarshalObject(node armjson.Node) error {
157204
obj := make(map[string]Value)
158205
for i := 0; i < len(node.Content()); i += 2 {
159206
var key string
@@ -170,7 +217,7 @@ func (v *Value) unmarshalObject(node armjson2.Node) error {
170217
return nil
171218
}
172219

173-
func (v *Value) unmarshallArray(node armjson2.Node) error {
220+
func (v *Value) unmarshallArray(node armjson.Node) error {
174221
var arr []Value
175222
for _, child := range node.Content() {
176223
var val Value
@@ -183,19 +230,19 @@ func (v *Value) unmarshallArray(node armjson2.Node) error {
183230
return nil
184231
}
185232

186-
func (v *Value) updateValueKind(node armjson2.Node) {
233+
func (v *Value) updateValueKind(node armjson.Node) {
187234
switch node.Kind() {
188-
case armjson2.KindString:
235+
case armjson.KindString:
189236
v.Kind = KindString
190-
case armjson2.KindNumber:
237+
case armjson.KindNumber:
191238
v.Kind = KindNumber
192-
case armjson2.KindBoolean:
239+
case armjson.KindBoolean:
193240
v.Kind = KindBoolean
194-
case armjson2.KindObject:
241+
case armjson.KindObject:
195242
v.Kind = KindObject
196-
case armjson2.KindNull:
243+
case armjson.KindNull:
197244
v.Kind = KindNull
198-
case armjson2.KindArray:
245+
case armjson.KindArray:
199246
v.Kind = KindArray
200247
default:
201248
panic(node.Kind())

0 commit comments

Comments
 (0)