diff --git a/pkg/fanal/analyzer/config/azurearm/azurearm.go b/pkg/fanal/analyzer/config/azurearm/azurearm.go index ecd7826173a0..455894a715b6 100644 --- a/pkg/fanal/analyzer/config/azurearm/azurearm.go +++ b/pkg/fanal/analyzer/config/azurearm/azurearm.go @@ -3,6 +3,7 @@ package azurearm import ( "os" "path/filepath" + "strings" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" @@ -34,5 +35,8 @@ func newAzureARMConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnal // Required overrides config.Analyzer.Required() and check if the given file is JSON. func (a *azureARMConfigAnalyzer) Required(filePath string, _ os.FileInfo) bool { - return filepath.Ext(filePath) == ".json" + return filepath.Ext(filePath) == ".json" && + // skip CreateUiDefinition + // https://learn.microsoft.com/en-us/azure/azure-resource-manager/managed-applications/create-uidefinition-overview + strings.ToLower(filepath.Base(filePath)) != "createuidefinition.json" } diff --git a/pkg/fanal/analyzer/config/azurearm/azurearm_test.go b/pkg/fanal/analyzer/config/azurearm/azurearm_test.go index 5546f492504e..ed1fc105021a 100644 --- a/pkg/fanal/analyzer/config/azurearm/azurearm_test.go +++ b/pkg/fanal/analyzer/config/azurearm/azurearm_test.go @@ -25,6 +25,16 @@ func Test_azureARMConfigAnalyzer_Required(t *testing.T) { filePath: "test.yaml", want: false, }, + { + name: "CreateUiDefinition", + filePath: "CreateUiDefinition.json", + want: false, + }, + { + name: "CreateUiDefinition lowercase", + filePath: "createuidefinition.json", + want: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/iac/detection/detect.go b/pkg/iac/detection/detect.go index fcaad6a36179..42204c901b5c 100644 --- a/pkg/iac/detection/detect.go +++ b/pkg/iac/detection/detect.go @@ -142,6 +142,7 @@ func init() { sniff := struct { Schema string `json:"$schema"` + Handler string `json:"handler"` Parameters map[string]any `json:"parameters"` Resources []any `json:"resources"` }{} @@ -155,6 +156,12 @@ func init() { return false } + // skip CreateUiDefinition + // https://learn.microsoft.com/en-us/azure/azure-resource-manager/managed-applications/create-uidefinition-overview + if sniff.Handler != "" { + return false + } + return len(sniff.Parameters) > 0 || len(sniff.Resources) > 0 } diff --git a/pkg/iac/detection/detect_test.go b/pkg/iac/detection/detect_test.go index f082220f2f00..1ebd7ca67337 100644 --- a/pkg/iac/detection/detect_test.go +++ b/pkg/iac/detection/detect_test.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "os" + "slices" "strings" "testing" @@ -420,6 +421,28 @@ rules: FileTypeJSON, }, }, + { + name: "CreateUiDefinition", + path: "CreateUiDefinition.json", + r: strings.NewReader(`{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "isWizard": false, + "basics": {} + }, + "basics": [], + "steps": [], + "outputs": {}, + "resourceTypes": [] + } +}`), + expected: []FileType{ + FileTypeJSON, + }, + }, } for _, test := range tests { @@ -429,13 +452,7 @@ rules: assert.Equal(t, len(test.expected), len(actualDetections)) for _, expected := range test.expected { resetReader(test.r) - var found bool - for _, actual := range actualDetections { - if actual == expected { - found = true - break - } - } + found := slices.Contains(actualDetections, expected) assert.True(t, found, "%s should be detected", expected) } }) diff --git a/pkg/iac/scanners/azure/arm/parser/parser.go b/pkg/iac/scanners/azure/arm/parser/parser.go index 53f9eb21431b..405443e1cff9 100644 --- a/pkg/iac/scanners/azure/arm/parser/parser.go +++ b/pkg/iac/scanners/azure/arm/parser/parser.go @@ -50,8 +50,10 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) ([]azure.Deployment, e deployment, err := p.parseFile(f, path) if err != nil { - return err + p.logger.Error("Failed to parse file", log.FilePath(path), log.Err(err)) + return nil } + deployments = append(deployments, *deployment) return nil }); err != nil { diff --git a/pkg/iac/scanners/azure/arm/parser/template.go b/pkg/iac/scanners/azure/arm/parser/template.go index ed7b3fa30238..f7aa3253336b 100644 --- a/pkg/iac/scanners/azure/arm/parser/template.go +++ b/pkg/iac/scanners/azure/arm/parser/template.go @@ -1,29 +1,29 @@ package parser import ( - types2 "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" + "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" "github.com/aquasecurity/trivy/pkg/iac/scanners/azure/arm/parser/armjson" "github.com/aquasecurity/trivy/pkg/iac/types" ) type Template struct { - Metadata types.Metadata `json:"-"` - Schema types2.Value `json:"$schema"` - ContentVersion types2.Value `json:"contentVersion"` - APIProfile types2.Value `json:"apiProfile"` - Parameters map[string]Parameter `json:"parameters"` - Variables map[string]types2.Value `json:"variables"` - Functions []Function `json:"functions"` - Resources []Resource `json:"resources"` - Outputs map[string]types2.Value `json:"outputs"` + Metadata types.Metadata `json:"-"` + Schema azure.Value `json:"$schema"` + ContentVersion azure.Value `json:"contentVersion"` + APIProfile azure.Value `json:"apiProfile"` + Parameters map[string]Parameter `json:"parameters"` + Variables map[string]azure.Value `json:"variables"` + Functions []Function `json:"functions"` + Resources []Resource `json:"resources"` + Outputs map[string]azure.Value `json:"outputs"` } type Parameter struct { Metadata types.Metadata - Type types2.Value `json:"type"` - DefaultValue types2.Value `json:"defaultValue"` - MaxLength types2.Value `json:"maxLength"` - MinLength types2.Value `json:"minLength"` + Type azure.Value `json:"type"` + DefaultValue azure.Value `json:"defaultValue"` + MaxLength azure.Value `json:"maxLength"` + MinLength azure.Value `json:"minLength"` } type Function struct{} @@ -46,15 +46,15 @@ func (p *Parameter) SetMetadata(m *types.Metadata) { } type innerResource struct { - APIVersion types2.Value `json:"apiVersion"` - Type types2.Value `json:"type"` - Kind types2.Value `json:"kind"` - Name types2.Value `json:"name"` - Location types2.Value `json:"location"` - Tags types2.Value `json:"tags"` - Sku types2.Value `json:"sku"` - Properties types2.Value `json:"properties"` - Resources []Resource `json:"resources"` + APIVersion azure.Value `json:"apiVersion"` + Type azure.Value `json:"type"` + Kind azure.Value `json:"kind"` + Name azure.Value `json:"name"` + Location azure.Value `json:"location"` + Tags azure.Value `json:"tags"` + Sku azure.Value `json:"sku"` + Properties azure.Value `json:"properties"` + Resources []Resource `json:"resources"` } func (v *Resource) UnmarshalJSONWithMetadata(node armjson.Node) error { diff --git a/pkg/iac/scanners/azure/arm/parser/template_test.go b/pkg/iac/scanners/azure/arm/parser/template_test.go index 493cee263582..0f48a7992088 100644 --- a/pkg/iac/scanners/azure/arm/parser/template_test.go +++ b/pkg/iac/scanners/azure/arm/parser/template_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - types2 "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" + "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" "github.com/aquasecurity/trivy/pkg/iac/scanners/azure/arm/parser/armjson" "github.com/aquasecurity/trivy/pkg/iac/types" ) @@ -40,22 +40,22 @@ func Test_JSONUnmarshal(t *testing.T) { "minLength": 3 */ assert.Equal(t, "string", prefix.Type.Raw()) - assert.Equal(t, types2.KindString, prefix.Type.Kind) + assert.Equal(t, azure.KindString, prefix.Type.Kind) assert.Equal(t, 8, prefix.Type.Metadata.Range().GetStartLine()) assert.Equal(t, 8, prefix.Type.Metadata.Range().GetEndLine()) assert.Equal(t, "x", prefix.DefaultValue.Raw()) - assert.Equal(t, types2.KindString, prefix.DefaultValue.Kind) + assert.Equal(t, azure.KindString, prefix.DefaultValue.Kind) assert.Equal(t, 9, prefix.DefaultValue.Metadata.Range().GetStartLine()) assert.Equal(t, 9, prefix.DefaultValue.Metadata.Range().GetEndLine()) assert.Equal(t, int64(11), prefix.MaxLength.Raw()) - assert.Equal(t, types2.KindNumber, prefix.MaxLength.Kind) + assert.Equal(t, azure.KindNumber, prefix.MaxLength.Kind) assert.Equal(t, 10, prefix.MaxLength.Metadata.Range().GetStartLine()) assert.Equal(t, 10, prefix.MaxLength.Metadata.Range().GetEndLine()) assert.Equal(t, int64(3), prefix.MinLength.Raw()) - assert.Equal(t, types2.KindNumber, prefix.MinLength.Kind) + assert.Equal(t, azure.KindNumber, prefix.MinLength.Kind) assert.Equal(t, 11, prefix.MinLength.Metadata.Range().GetStartLine()) assert.Equal(t, 11, prefix.MinLength.Metadata.Range().GetEndLine()) }