From c6d95d7cd271c3d29ce147f1ad5983cafc1caf48 Mon Sep 17 00:00:00 2001 From: yagreut <123973998+yagreut@users.noreply.github.com> Date: Wed, 19 Nov 2025 09:21:09 +0200 Subject: [PATCH] feat(misconf): Update AppService schema (#9792) Signed-off-by: nikpivkin Co-authored-by: Nikita Pivkin --- pkg/iac/adapters/arm/appservice/adapt.go | 36 +++++---- pkg/iac/adapters/arm/appservice/adapt_test.go | 27 ++++--- .../terraform/azure/appservice/adapt.go | 77 ++++++------------- .../terraform/azure/appservice/adapt_test.go | 42 +++------- .../providers/azure/appservice/appservice.go | 33 +++++--- pkg/iac/rego/schemas/cloud.json | 20 ++++- pkg/iac/scanners/azure/value.go | 2 +- pkg/iac/terraform/block.go | 3 + 8 files changed, 120 insertions(+), 120 deletions(-) diff --git a/pkg/iac/adapters/arm/appservice/adapt.go b/pkg/iac/adapters/arm/appservice/adapt.go index d5512cc5d3..9df3f8dff0 100644 --- a/pkg/iac/adapters/arm/appservice/adapt.go +++ b/pkg/iac/adapters/arm/appservice/adapt.go @@ -3,7 +3,6 @@ package appservice import ( "github.com/aquasecurity/trivy/pkg/iac/providers/azure/appservice" "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" - iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" ) func Adapt(deployment azure.Deployment) appservice.AppService { @@ -32,27 +31,36 @@ func adaptServices(deployment azure.Deployment) []appservice.Service { func adaptFunctionApp(resource azure.Resource) appservice.FunctionApp { return appservice.FunctionApp{ - Metadata: resource.Metadata, - HTTPSOnly: resource.Properties.GetMapValue("httpsOnly").AsBoolValue(false, resource.Properties.GetMetadata()), + Metadata: resource.Metadata, + HTTPSOnly: resource.Properties.GetMapValue("httpsOnly"). + AsBoolValue(false, resource.Properties.GetMetadata()), } } func adaptService(resource azure.Resource) appservice.Service { + props := resource.Properties + identity := props.GetMapValue("identity") + siteAuthSettings := props.GetMapValue("siteAuthSettings") + siteConfig := props.GetMapValue("siteConfig") return appservice.Service{ Metadata: resource.Metadata, - EnableClientCert: resource.Properties.GetMapValue("clientCertEnabled").AsBoolValue(false, resource.Properties.GetMetadata()), - Identity: struct{ Type iacTypes.StringValue }{ - Type: resource.Properties.GetMapValue("identity").GetMapValue("type").AsStringValue("", resource.Properties.GetMetadata()), + EnableClientCert: props.GetMapValue("clientCertEnabled").AsBoolValue(false, props.GetMetadata()), + HTTPSOnly: props.GetMapValue("httpsOnly").AsBoolValue(false, props.GetMetadata()), + Identity: appservice.Identity{ + Metadata: identity.GetMetadata(), + Type: identity.GetMapValue("type"). + AsStringValue("", props.GetMetadata()), }, - Authentication: struct{ Enabled iacTypes.BoolValue }{ - Enabled: resource.Properties.GetMapValue("siteAuthSettings").GetMapValue("enabled").AsBoolValue(false, resource.Properties.GetMetadata()), + Authentication: appservice.Authentication{ + Metadata: siteAuthSettings.GetMetadata(), + Enabled: siteAuthSettings.GetMapValue("enabled").AsBoolValue(false, props.GetMetadata()), }, - Site: struct { - EnableHTTP2 iacTypes.BoolValue - MinimumTLSVersion iacTypes.StringValue - }{ - EnableHTTP2: resource.Properties.GetMapValue("httpsOnly").AsBoolValue(false, resource.Properties.GetMetadata()), - MinimumTLSVersion: resource.Properties.GetMapValue("minTlsVersion").AsStringValue("", resource.Properties.GetMetadata()), + Site: appservice.Site{ + EnableHTTP2: siteConfig.GetMapValue("http20Enabled").AsBoolValue(false, siteConfig.GetMetadata()), + MinimumTLSVersion: siteConfig.GetMapValue("minTlsVersion").AsStringValue("", siteConfig.GetMetadata()), + PHPVersion: siteConfig.GetMapValue("phpVersion").AsStringValue("", siteConfig.GetMetadata()), + PythonVersion: siteConfig.GetMapValue("pythonVersion").AsStringValue("", siteConfig.GetMetadata()), + FTPSState: siteConfig.GetMapValue("ftpsState").AsStringValue("", siteConfig.GetMetadata()), }, } } diff --git a/pkg/iac/adapters/arm/appservice/adapt_test.go b/pkg/iac/adapters/arm/appservice/adapt_test.go index 4c72d5ae40..42e24fd52a 100644 --- a/pkg/iac/adapters/arm/appservice/adapt_test.go +++ b/pkg/iac/adapters/arm/appservice/adapt_test.go @@ -25,8 +25,8 @@ func TestAdapt(t *testing.T) { ] }`, expected: appservice.AppService{ - FunctionApps: []appservice.FunctionApp{{}}, Services: []appservice.Service{{}}, + FunctionApps: []appservice.FunctionApp{{}}, }, }, { @@ -44,7 +44,14 @@ func TestAdapt(t *testing.T) { "siteAuthSettings": { "enabled": true }, - "minTlsVersion": "1.3" + "minTlsVersion": "1.3", + "siteConfig": { + "http20Enabled": true, + "minTlsVersion": "1.2", + "phpVersion": "8.1", + "pythonVersion": "3.11", + "ftpsState": "FtpsOnly" + } } } ] @@ -52,18 +59,19 @@ func TestAdapt(t *testing.T) { expected: appservice.AppService{ Services: []appservice.Service{{ EnableClientCert: types.BoolTest(true), - Identity: struct{ Type types.StringValue }{ + HTTPSOnly: types.BoolTest(true), + Identity: appservice.Identity{ Type: types.StringTest("SystemAssigned"), }, - Authentication: struct{ Enabled types.BoolValue }{ + Authentication: appservice.Authentication{ Enabled: types.BoolTest(true), }, - Site: struct { - EnableHTTP2 types.BoolValue - MinimumTLSVersion types.StringValue - }{ + Site: appservice.Site{ EnableHTTP2: types.BoolTest(true), - MinimumTLSVersion: types.StringTest("1.3"), + MinimumTLSVersion: types.StringTest("1.2"), + PHPVersion: types.StringTest("8.1"), + PythonVersion: types.StringTest("3.11"), + FTPSState: types.StringTest("FtpsOnly"), }, }}, FunctionApps: []appservice.FunctionApp{{ @@ -78,5 +86,4 @@ func TestAdapt(t *testing.T) { adaptertest.AdaptAndCompare(t, tt.source, tt.expected, Adapt) }) } - } diff --git a/pkg/iac/adapters/terraform/azure/appservice/adapt.go b/pkg/iac/adapters/terraform/azure/appservice/adapt.go index 3ff7223cb2..80aa13e8d1 100644 --- a/pkg/iac/adapters/terraform/azure/appservice/adapt.go +++ b/pkg/iac/adapters/terraform/azure/appservice/adapt.go @@ -1,9 +1,10 @@ package appservice import ( + "github.com/samber/lo" + "github.com/aquasecurity/trivy/pkg/iac/providers/azure/appservice" "github.com/aquasecurity/trivy/pkg/iac/terraform" - iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" ) func Adapt(modules terraform.Modules) appservice.AppService { @@ -15,80 +16,50 @@ func Adapt(modules terraform.Modules) appservice.AppService { func adaptServices(modules terraform.Modules) []appservice.Service { var services []appservice.Service - - for _, module := range modules { - for _, resource := range module.GetResourcesByType("azurerm_app_service") { - services = append(services, adaptService(resource)) - } + for _, resource := range modules.GetResourcesByType("azurerm_app_service") { + services = append(services, adaptService(resource)) } return services } func adaptFunctionApps(modules terraform.Modules) []appservice.FunctionApp { var functionApps []appservice.FunctionApp - - for _, module := range modules { - for _, resource := range module.GetResourcesByType("azurerm_function_app") { - functionApps = append(functionApps, adaptFunctionApp(resource)) - } + for _, resource := range modules.GetResourcesByType("azurerm_function_app") { + functionApps = append(functionApps, adaptFunctionApp(resource)) } return functionApps } func adaptService(resource *terraform.Block) appservice.Service { - enableClientCertAttr := resource.GetAttribute("client_cert_enabled") - enableClientCertVal := enableClientCertAttr.AsBoolValueOrDefault(false, resource) - - identityBlock := resource.GetBlock("identity") - typeVal := iacTypes.String("", resource.GetMetadata()) - if identityBlock.IsNotNil() { - typeAttr := identityBlock.GetAttribute("type") - typeVal = typeAttr.AsStringValueOrDefault("", identityBlock) - } - - authBlock := resource.GetBlock("auth_settings") - enabledVal := iacTypes.Bool(false, resource.GetMetadata()) - if authBlock.IsNotNil() { - enabledAttr := authBlock.GetAttribute("enabled") - enabledVal = enabledAttr.AsBoolValueOrDefault(false, authBlock) - } - siteBlock := resource.GetBlock("site_config") - enableHTTP2Val := iacTypes.Bool(false, resource.GetMetadata()) - minTLSVersionVal := iacTypes.String("1.2", resource.GetMetadata()) - if siteBlock.IsNotNil() { - enableHTTP2Attr := siteBlock.GetAttribute("http2_enabled") - enableHTTP2Val = enableHTTP2Attr.AsBoolValueOrDefault(false, siteBlock) - - minTLSVersionAttr := siteBlock.GetAttribute("min_tls_version") - minTLSVersionVal = minTLSVersionAttr.AsStringValueOrDefault("1.2", siteBlock) - } - + identityBlock := resource.GetBlock("identity") + authBlock := resource.GetBlock("auth_settings") return appservice.Service{ Metadata: resource.GetMetadata(), - EnableClientCert: enableClientCertVal, - Identity: struct{ Type iacTypes.StringValue }{ - Type: typeVal, + EnableClientCert: resource.GetAttribute("client_cert_enabled").AsBoolValueOrDefault(false, resource), + HTTPSOnly: resource.GetAttribute("https_only").AsBoolValueOrDefault(false, resource), + Identity: appservice.Identity{ + Metadata: lo.TernaryF(identityBlock.IsNil(), resource.GetMetadata, identityBlock.GetMetadata), + Type: identityBlock.GetAttribute("type").AsStringValueOrDefault("", identityBlock), }, - Authentication: struct{ Enabled iacTypes.BoolValue }{ - Enabled: enabledVal, + Authentication: appservice.Authentication{ + Metadata: lo.TernaryF(identityBlock.IsNil(), resource.GetMetadata, authBlock.GetMetadata), + Enabled: authBlock.GetAttribute("enabled").AsBoolValueOrDefault(false, authBlock), }, - Site: struct { - EnableHTTP2 iacTypes.BoolValue - MinimumTLSVersion iacTypes.StringValue - }{ - EnableHTTP2: enableHTTP2Val, - MinimumTLSVersion: minTLSVersionVal, + Site: appservice.Site{ + Metadata: lo.TernaryF(identityBlock.IsNil(), resource.GetMetadata, siteBlock.GetMetadata), + EnableHTTP2: siteBlock.GetAttribute("http2_enabled").AsBoolValueOrDefault(false, siteBlock), + MinimumTLSVersion: siteBlock.GetAttribute("min_tls_version").AsStringValueOrDefault("1.2", siteBlock), + PHPVersion: siteBlock.GetAttribute("php_version").AsStringValueOrDefault("", siteBlock), + PythonVersion: siteBlock.GetAttribute("python_version").AsStringValueOrDefault("", siteBlock), + FTPSState: siteBlock.GetAttribute("ftps_state").AsStringValueOrDefault("", siteBlock), }, } } func adaptFunctionApp(resource *terraform.Block) appservice.FunctionApp { - HTTPSOnlyAttr := resource.GetAttribute("https_only") - HTTPSOnlyVal := HTTPSOnlyAttr.AsBoolValueOrDefault(false, resource) - return appservice.FunctionApp{ Metadata: resource.GetMetadata(), - HTTPSOnly: HTTPSOnlyVal, + HTTPSOnly: resource.GetAttribute("https_only").AsBoolValueOrDefault(false, resource), } } diff --git a/pkg/iac/adapters/terraform/azure/appservice/adapt_test.go b/pkg/iac/adapters/terraform/azure/appservice/adapt_test.go index 28b468a3ba..1049f5c96e 100644 --- a/pkg/iac/adapters/terraform/azure/appservice/adapt_test.go +++ b/pkg/iac/adapters/terraform/azure/appservice/adapt_test.go @@ -40,20 +40,16 @@ func Test_adaptService(t *testing.T) { } `, expected: appservice.Service{ - Metadata: iacTypes.NewTestMetadata(), - EnableClientCert: iacTypes.Bool(true, iacTypes.NewTestMetadata()), - Identity: struct{ Type iacTypes.StringValue }{ - Type: iacTypes.String("UserAssigned", iacTypes.NewTestMetadata()), + EnableClientCert: iacTypes.BoolTest(true), + Identity: appservice.Identity{ + Type: iacTypes.StringTest("UserAssigned"), }, - Authentication: struct{ Enabled iacTypes.BoolValue }{ - Enabled: iacTypes.Bool(true, iacTypes.NewTestMetadata()), + Authentication: appservice.Authentication{ + Enabled: iacTypes.BoolTest(true), }, - Site: struct { - EnableHTTP2 iacTypes.BoolValue - MinimumTLSVersion iacTypes.StringValue - }{ - EnableHTTP2: iacTypes.Bool(true, iacTypes.NewTestMetadata()), - MinimumTLSVersion: iacTypes.String("1.0", iacTypes.NewTestMetadata()), + Site: appservice.Site{ + EnableHTTP2: iacTypes.BoolTest(true), + MinimumTLSVersion: iacTypes.StringTest("1.0"), }, }, }, @@ -64,20 +60,8 @@ func Test_adaptService(t *testing.T) { } `, expected: appservice.Service{ - Metadata: iacTypes.NewTestMetadata(), - EnableClientCert: iacTypes.Bool(false, iacTypes.NewTestMetadata()), - Identity: struct{ Type iacTypes.StringValue }{ - Type: iacTypes.String("", iacTypes.NewTestMetadata()), - }, - Authentication: struct{ Enabled iacTypes.BoolValue }{ - Enabled: iacTypes.Bool(false, iacTypes.NewTestMetadata()), - }, - Site: struct { - EnableHTTP2 iacTypes.BoolValue - MinimumTLSVersion iacTypes.StringValue - }{ - EnableHTTP2: iacTypes.Bool(false, iacTypes.NewTestMetadata()), - MinimumTLSVersion: iacTypes.String("1.2", iacTypes.NewTestMetadata()), + Site: appservice.Site{ + MinimumTLSVersion: iacTypes.StringTest("1.2"), }, }, }, @@ -107,8 +91,7 @@ func Test_adaptFunctionApp(t *testing.T) { } `, expected: appservice.FunctionApp{ - Metadata: iacTypes.NewTestMetadata(), - HTTPSOnly: iacTypes.Bool(true, iacTypes.NewTestMetadata()), + HTTPSOnly: iacTypes.BoolTest(true), }, }, { @@ -118,8 +101,7 @@ func Test_adaptFunctionApp(t *testing.T) { } `, expected: appservice.FunctionApp{ - Metadata: iacTypes.NewTestMetadata(), - HTTPSOnly: iacTypes.Bool(false, iacTypes.NewTestMetadata()), + HTTPSOnly: iacTypes.BoolTest(false), }, }, } diff --git a/pkg/iac/providers/azure/appservice/appservice.go b/pkg/iac/providers/azure/appservice/appservice.go index 990adf9818..9e9efbed3a 100755 --- a/pkg/iac/providers/azure/appservice/appservice.go +++ b/pkg/iac/providers/azure/appservice/appservice.go @@ -9,19 +9,32 @@ type AppService struct { FunctionApps []FunctionApp } +type Identity struct { + Metadata iacTypes.Metadata + Type iacTypes.StringValue +} + +type Authentication struct { + Metadata iacTypes.Metadata + Enabled iacTypes.BoolValue +} + type Service struct { Metadata iacTypes.Metadata EnableClientCert iacTypes.BoolValue - Identity struct { - Type iacTypes.StringValue - } - Authentication struct { - Enabled iacTypes.BoolValue - } - Site struct { - EnableHTTP2 iacTypes.BoolValue - MinimumTLSVersion iacTypes.StringValue - } + HTTPSOnly iacTypes.BoolValue + Identity Identity + Authentication Authentication + Site Site +} + +type Site struct { + Metadata iacTypes.Metadata + EnableHTTP2 iacTypes.BoolValue + MinimumTLSVersion iacTypes.StringValue + PHPVersion iacTypes.StringValue + PythonVersion iacTypes.StringValue + FTPSState iacTypes.StringValue } type FunctionApp struct { diff --git a/pkg/iac/rego/schemas/cloud.json b/pkg/iac/rego/schemas/cloud.json index 7930d74fd7..6d9c36ebda 100644 --- a/pkg/iac/rego/schemas/cloud.json +++ b/pkg/iac/rego/schemas/cloud.json @@ -4528,13 +4528,17 @@ "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.BoolValue" }, + "httpsonly": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.BoolValue" + }, "identity": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.appservice.Service.Identity" }, "site": { "type": "object", - "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.appservice.Service.Site" + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.appservice.Site" } } }, @@ -4556,16 +4560,28 @@ } } }, - "github.com.aquasecurity.trivy.pkg.iac.providers.azure.appservice.Service.Site": { + "github.com.aquasecurity.trivy.pkg.iac.providers.azure.appservice.Site": { "type": "object", "properties": { "enablehttp2": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.BoolValue" }, + "ftpsstate": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + }, "minimumtlsversion": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + }, + "phpversion": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + }, + "pythonversion": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" } } }, diff --git a/pkg/iac/scanners/azure/value.go b/pkg/iac/scanners/azure/value.go index 27bac4932b..898bc00d1a 100644 --- a/pkg/iac/scanners/azure/value.go +++ b/pkg/iac/scanners/azure/value.go @@ -106,7 +106,7 @@ func NewExprValue(value string, metadata types.Metadata) Value { } } -func (v *Value) GetMetadata() types.Metadata { +func (v Value) GetMetadata() types.Metadata { return lo.FromPtr(v.metadata) } diff --git a/pkg/iac/terraform/block.go b/pkg/iac/terraform/block.go index 33dfd391a5..b7a749f40e 100644 --- a/pkg/iac/terraform/block.go +++ b/pkg/iac/terraform/block.go @@ -138,6 +138,9 @@ func (b *Block) Reference() Reference { } func (b *Block) GetMetadata() iacTypes.Metadata { + if b.IsNil() { + return iacTypes.NewUnmanagedMetadata() + } return b.metadata }