Skip to content

Commit feb11ae

Browse files
tas50claude
andcommitted
🐛 Fix nil pointer dereferences in Azure provider
Add nil checks for Azure SDK pointer-typed Properties fields across multiple resources to prevent panics when API responses contain nil values. Files fixed: - advisor.go: guard r.Properties before accessing recommendations - aks.go: guard entry.Properties.PowerState, use convert.ToValue for entry.ID - cloud_defender.go: guard setting.Properties and containersPricing.Properties - compute.go: guard networkInterface.Properties, config.Properties, ip.ID - iam.go: guard roleDef.Properties and roleDef.ID - monitor.go: guard entry.Properties.Actions and .Condition - network.go: guard flowLog.Properties, vng.Properties.BgpSettings, vng.Properties.SKU, ipc.Properties, fw.Properties, ipConfig.Properties - sql.go: guard entry.Properties, entry.SKU, vaSettings.Properties, vaSettings.Properties.RecurringScans Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8384ca1 commit feb11ae

File tree

8 files changed

+302
-235
lines changed

8 files changed

+302
-235
lines changed

providers/azure/resources/advisor.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,22 @@ func (a *mqlAzureSubscriptionAdvisorService) recommendations() ([]any, error) {
6464
return nil, err
6565
}
6666
args := map[string]*llx.RawData{
67-
"id": llx.StringDataPtr(r.ID),
68-
"name": llx.StringDataPtr(r.Name),
69-
"type": llx.StringDataPtr(r.Type),
70-
"category": llx.StringDataPtr((*string)(r.Properties.Category)),
71-
"impact": llx.StringDataPtr((*string)(r.Properties.Impact)),
72-
"risk": llx.StringDataPtr((*string)(r.Properties.Risk)),
73-
"properties": llx.DictData(props),
74-
"impactedResourceType": llx.StringDataPtr(r.Properties.ImpactedField),
75-
"impactedResource": llx.StringDataPtr(r.Properties.ImpactedValue),
67+
"id": llx.StringDataPtr(r.ID),
68+
"name": llx.StringDataPtr(r.Name),
69+
"type": llx.StringDataPtr(r.Type),
70+
"properties": llx.DictData(props),
7671
}
77-
if r.Properties.ShortDescription != nil {
78-
// the 'Description' field in the API response is always empty, use the short description instead
79-
args["description"] = llx.StringDataPtr(r.Properties.ShortDescription.Problem)
80-
args["remediation"] = llx.StringDataPtr(r.Properties.ShortDescription.Solution)
72+
if r.Properties != nil {
73+
args["category"] = llx.StringDataPtr((*string)(r.Properties.Category))
74+
args["impact"] = llx.StringDataPtr((*string)(r.Properties.Impact))
75+
args["risk"] = llx.StringDataPtr((*string)(r.Properties.Risk))
76+
args["impactedResourceType"] = llx.StringDataPtr(r.Properties.ImpactedField)
77+
args["impactedResource"] = llx.StringDataPtr(r.Properties.ImpactedValue)
78+
if r.Properties.ShortDescription != nil {
79+
// the 'Description' field in the API response is always empty, use the short description instead
80+
args["description"] = llx.StringDataPtr(r.Properties.ShortDescription.Problem)
81+
args["remediation"] = llx.StringDataPtr(r.Properties.ShortDescription.Solution)
82+
}
8183
}
8284
mqlRecomm, err := CreateResource(a.MqlRuntime, "azure.subscription.advisorService.recommendation", args)
8385
if err != nil {

providers/azure/resources/aks.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ func (a *mqlAzureSubscriptionAksServiceClusterAutoUpgradeProfile) id() (string,
9090
return a.Id.Data, nil
9191
}
9292

93+
func aksPowerState(entry *clusters.ManagedCluster) *llx.RawData {
94+
if entry.Properties != nil && entry.Properties.PowerState != nil {
95+
return llx.StringDataPtr((*string)(entry.Properties.PowerState.Code))
96+
}
97+
return llx.NilData
98+
}
99+
93100
func (a *mqlAzureSubscriptionAksService) clusters() ([]any, error) {
94101
conn := a.MqlRuntime.Connection.(*connection.AzureConnection)
95102
ctx := context.Background()
@@ -211,7 +218,7 @@ func (a *mqlAzureSubscriptionAksService) clusters() ([]any, error) {
211218
}
212219
aadRes, err := CreateResource(a.MqlRuntime, "azure.subscription.aksService.cluster.aadProfile",
213220
map[string]*llx.RawData{
214-
"id": llx.StringData(*entry.ID + "/aadProfile"),
221+
"id": llx.StringData(convert.ToValue(entry.ID) + "/aadProfile"),
215222
"managed": llx.BoolDataPtr(aadP.Managed),
216223
"enableAzureRBAC": llx.BoolDataPtr(aadP.EnableAzureRBAC),
217224
"adminGroupObjectIDs": llx.ArrayData(adminGroupObjectIDs, types.String),
@@ -228,7 +235,7 @@ func (a *mqlAzureSubscriptionAksService) clusters() ([]any, error) {
228235
aup := entry.Properties.AutoUpgradeProfile
229236
autoUpgradeRes, err := CreateResource(a.MqlRuntime, "azure.subscription.aksService.cluster.autoUpgradeProfile",
230237
map[string]*llx.RawData{
231-
"id": llx.StringData(*entry.ID + "/autoUpgradeProfile"),
238+
"id": llx.StringData(convert.ToValue(entry.ID) + "/autoUpgradeProfile"),
232239
"upgradeChannel": llx.StringDataPtr((*string)(aup.UpgradeChannel)),
233240
"nodeOSUpgradeChannel": llx.StringDataPtr((*string)(aup.NodeOSUpgradeChannel)),
234241
})
@@ -247,7 +254,7 @@ func (a *mqlAzureSubscriptionAksService) clusters() ([]any, error) {
247254
"provisioningState": llx.StringDataPtr(entry.Properties.ProvisioningState),
248255
"createdAt": llx.TimeDataPtr(createdAt),
249256
"nodeResourceGroup": llx.StringDataPtr(entry.Properties.NodeResourceGroup),
250-
"powerState": llx.StringDataPtr((*string)(entry.Properties.PowerState.Code)),
257+
"powerState": aksPowerState(entry),
251258
"tags": llx.MapData(convert.PtrMapStrToInterface(entry.Tags), types.String),
252259
"rbacEnabled": llx.BoolDataPtr(entry.Properties.EnableRBAC),
253260
"dnsPrefix": llx.StringDataPtr(entry.Properties.DNSPrefix),

providers/azure/resources/cloud_defender.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -456,8 +456,10 @@ func (a *mqlAzureSubscriptionCloudDefenderService) monitoringAgentAutoProvision(
456456
if err != nil {
457457
return false, err
458458
}
459-
autoProvision := *setting.Properties.AutoProvision
460-
return autoProvision == security.AutoProvisionOn, nil
459+
if setting.Properties == nil || setting.Properties.AutoProvision == nil {
460+
return false, nil
461+
}
462+
return *setting.Properties.AutoProvision == security.AutoProvisionOn, nil
461463
}
462464

463465
func (a *mqlAzureSubscriptionCloudDefenderService) defenderForContainers() (any, error) {
@@ -522,19 +524,21 @@ func (a *mqlAzureSubscriptionCloudDefenderService) defenderForContainers() (any,
522524
}
523525

524526
enabled := false
525-
if containersPricing.Properties.PricingTier != nil {
527+
if containersPricing.Properties != nil && containersPricing.Properties.PricingTier != nil {
526528
enabled = *containersPricing.Properties.PricingTier == security.PricingTierStandard
527529
}
528530
extensions := []extension{}
529-
for _, ext := range containersPricing.Properties.Extensions {
530-
if ext.IsEnabled == nil || ext.Name == nil {
531-
continue
532-
}
533-
e := false
534-
if *ext.IsEnabled == security.IsEnabledTrue {
535-
e = true
531+
if containersPricing.Properties != nil {
532+
for _, ext := range containersPricing.Properties.Extensions {
533+
if ext.IsEnabled == nil || ext.Name == nil {
534+
continue
535+
}
536+
e := false
537+
if *ext.IsEnabled == security.IsEnabledTrue {
538+
e = true
539+
}
540+
extensions = append(extensions, extension{Name: *ext.Name, IsEnabled: e})
536541
}
537-
extensions = append(extensions, extension{Name: *ext.Name, IsEnabled: e})
538542
}
539543

540544
def := defenderForContainers{

providers/azure/resources/compute.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,9 +526,15 @@ func (a *mqlAzureSubscriptionComputeServiceVm) publicIpAddresses() ([]any, error
526526
return nil, err
527527
}
528528

529+
if networkInterface.Interface.Properties == nil {
530+
continue
531+
}
529532
for _, config := range networkInterface.Interface.Properties.IPConfigurations {
533+
if config.Properties == nil {
534+
continue
535+
}
530536
ip := config.Properties.PublicIPAddress
531-
if ip != nil {
537+
if ip != nil && ip.ID != nil {
532538
publicIPID := *ip.ID
533539
publicIpResource, err := ParseResourceID(publicIPID)
534540
if err != nil {

providers/azure/resources/iam.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,28 +71,34 @@ func (a *mqlAzureSubscriptionAuthorizationService) roles() ([]any, error) {
7171
return nil, err
7272
}
7373
for _, roleDef := range page.Value {
74-
roleType := convert.ToValue(roleDef.Properties.RoleType)
74+
var roleType string
7575
scopes := []any{}
76-
for _, s := range roleDef.Properties.AssignableScopes {
77-
if s != nil {
78-
scopes = append(scopes, *s)
79-
}
80-
}
8176
permissions := []any{}
82-
for idx, p := range roleDef.Properties.Permissions {
83-
id := fmt.Sprintf("%s/azure.subscription.authorizationService.roleDefinition.permission/%d", *roleDef.ID, idx)
84-
permission, err := newMqlRolePermission(a.MqlRuntime, id, p)
85-
if err != nil {
86-
return nil, err
77+
var roleName, description *string
78+
if roleDef.Properties != nil {
79+
roleType = convert.ToValue(roleDef.Properties.RoleType)
80+
roleName = roleDef.Properties.RoleName
81+
description = roleDef.Properties.Description
82+
for _, s := range roleDef.Properties.AssignableScopes {
83+
if s != nil {
84+
scopes = append(scopes, *s)
85+
}
86+
}
87+
for idx, p := range roleDef.Properties.Permissions {
88+
id := fmt.Sprintf("%s/azure.subscription.authorizationService.roleDefinition.permission/%d", convert.ToValue(roleDef.ID), idx)
89+
permission, err := newMqlRolePermission(a.MqlRuntime, id, p)
90+
if err != nil {
91+
return nil, err
92+
}
93+
permissions = append(permissions, permission)
8794
}
88-
permissions = append(permissions, permission)
8995
}
9096
mqlRoleDefinition, err := CreateResource(a.MqlRuntime, "azure.subscription.authorizationService.roleDefinition",
9197
map[string]*llx.RawData{
9298
"__id": llx.StringDataPtr(roleDef.ID),
9399
"id": llx.StringDataPtr(roleDef.ID),
94-
"name": llx.StringDataPtr(roleDef.Properties.RoleName),
95-
"description": llx.StringDataPtr(roleDef.Properties.Description),
100+
"name": llx.StringDataPtr(roleName),
101+
"description": llx.StringDataPtr(description),
96102
"type": llx.StringData(roleType),
97103
"scopes": llx.ArrayData(scopes, types.String),
98104
"permissions": llx.ArrayData(permissions, types.ResourceLike),

providers/azure/resources/monitor.go

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -242,30 +242,34 @@ func (a *mqlAzureSubscriptionMonitorServiceActivityLog) alerts() ([]any, error)
242242
actions := []mqlAlertAction{}
243243
conditions := []mqlAlertCondition{}
244244

245-
for _, act := range entry.Properties.Actions.ActionGroups {
246-
mqlAction := mqlAlertAction{
247-
ActionGroupId: convert.ToValue(act.ActionGroupID),
248-
WebhookProperties: convert.PtrMapStrToStr(act.WebhookProperties),
245+
if entry.Properties != nil && entry.Properties.Actions != nil {
246+
for _, act := range entry.Properties.Actions.ActionGroups {
247+
mqlAction := mqlAlertAction{
248+
ActionGroupId: convert.ToValue(act.ActionGroupID),
249+
WebhookProperties: convert.PtrMapStrToStr(act.WebhookProperties),
250+
}
251+
actions = append(actions, mqlAction)
249252
}
250-
actions = append(actions, mqlAction)
251253
}
252-
for _, cond := range entry.Properties.Condition.AllOf {
253-
anyOf := []mqlAlertLeafCondition{}
254-
for _, leaf := range cond.AnyOf {
255-
mqlAnyOfLeaf := mqlAlertLeafCondition{
256-
FieldName: convert.ToValue(leaf.Field),
257-
Equals: convert.ToValue(leaf.Equals),
258-
ContainsAny: convert.SliceStrPtrToStr(leaf.ContainsAny),
254+
if entry.Properties != nil && entry.Properties.Condition != nil {
255+
for _, cond := range entry.Properties.Condition.AllOf {
256+
anyOf := []mqlAlertLeafCondition{}
257+
for _, leaf := range cond.AnyOf {
258+
mqlAnyOfLeaf := mqlAlertLeafCondition{
259+
FieldName: convert.ToValue(leaf.Field),
260+
Equals: convert.ToValue(leaf.Equals),
261+
ContainsAny: convert.SliceStrPtrToStr(leaf.ContainsAny),
262+
}
263+
anyOf = append(anyOf, mqlAnyOfLeaf)
259264
}
260-
anyOf = append(anyOf, mqlAnyOfLeaf)
261-
}
262-
mqlCondition := mqlAlertCondition{
263-
FieldName: convert.ToValue(cond.Field),
264-
Equals: convert.ToValue(cond.Equals),
265-
ContainsAny: convert.SliceStrPtrToStr(cond.ContainsAny),
266-
AnyOf: anyOf,
265+
mqlCondition := mqlAlertCondition{
266+
FieldName: convert.ToValue(cond.Field),
267+
Equals: convert.ToValue(cond.Equals),
268+
ContainsAny: convert.SliceStrPtrToStr(cond.ContainsAny),
269+
AnyOf: anyOf,
270+
}
271+
conditions = append(conditions, mqlCondition)
267272
}
268-
conditions = append(conditions, mqlCondition)
269273
}
270274

271275
actionsDict := []any{}

0 commit comments

Comments
 (0)