PSRule.Rules.Azure icon indicating copy to clipboard operation
PSRule.Rules.Azure copied to clipboard

The arguments for 'Filter' are not in the expected format or type

Open Dylan-Prins opened this issue 1 year ago • 19 comments

Using PSRule v2.8.1 Using PSRule.Rules.Azure v1.26.0 Github runner: Ubuntu-latest

Deployment error

Error: Unable to expand resources because the source file '/home/runner/work/Solution.ManagedOxygen/Solution.ManagedOxygen/OxygenManagementZone.bicep' was not valid. An error occurred evaluating expression '[filter(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('virtualNetworkMZ-{0}', parameters('nameSuffix'))), '2022-09-01').outputs.subnets.value, lambda('s', equals(lambdaVariables('s').name, 'OxygenManagementZone')))[0].id]' line 1092. The arguments for 'Filter' are not in the expected format or type.

Bicep

filter(virtualNetwork.outputs.subnets, s => s.name == environment)[0].id

JSON

"[filter(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('virtualNetworkLZ-{0}', parameters('nameSuffix'))), '2022-09-01').outputs.subnets.value, lambda('s', equals(lambdaVariables('s').name, parameters('environment'))))[0].id]"

Dylan-Prins avatar Apr 19 '23 09:04 Dylan-Prins

@Dylan-Prins Thanks for reporting the issue.

BernieWhite avatar Apr 19 '23 10:04 BernieWhite

@Dylan-Prins Follow up questions:

  • Does the virtualNetwork.outputs.subnets equal the names of subnets?
  • If so, how do you populate the array output?
  • Are you populating the array from deployments using the Microsoft.Network/virtualNetworks/subnets sub-resource?

BernieWhite avatar Apr 19 '23 15:04 BernieWhite

we use the following output in a network module:

output subnets array = vNet.properties.subnets

The deployment is tested locally and works fine by the way.

Dylan-Prins avatar Apr 20 '23 07:04 Dylan-Prins

Hi @BernieWhite I work together with Dylan, while your fix worked in one of the pre-releases, it broke in the official release 1.27.0

Error: Unable to expand resources because the source file '/home/runner/work/Solution.ManagedOxygen/Solution.ManagedOxygen/OxygenManagementZone.bicep' was not valid. An error occurred evaluating expression '[filter(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('virtualNetworkMZ-{0}', parameters('nameSuffix'))), '2022-09-01').outputs.subnets.value, lambda('s', equals(lambdaVariables('s').name, 'OxygenManagementZone')))[0].id]' line 2811. The arguments for 'Filter' are not in the expected format or type.

donheerschap avatar May 31 '23 09:05 donheerschap

@donheerschap hmm OK thanks for letting us know. Let me have a look and get back to you.

BernieWhite avatar May 31 '23 10:05 BernieWhite

@donheerschap what was the last pre-release version that worked for you? 1.27.0-B0003 or did you try a different version?

BernieWhite avatar May 31 '23 10:05 BernieWhite

@BernieWhite v1.27.0-B0015 was the last version which worked for me.

donheerschap avatar May 31 '23 12:05 donheerschap

@donheerschap If you are able to provide an example that reproduces the issue that would be very helpful.

My repro does not generate the same issue:

var resourceGroupName = 'rg-test'

module vnet 'Tests.Bicep.13.child.bicep' = {
  scope: resourceGroup(resourceGroupName)
  name: 'vnet${resourceGroupName}'
}

output vnetId string = filter(vnet.outputs.subnets, s => s.name == 'subnet1')[0].id
var subnets = [
  {
    name: 'subnet1'
    addressPrefix: '10.0.0.0/24'
  }
  {
    name: 'subnet2'
    addressPrefix: '10.0.1.0/24'
  }
  {
    name: 'subnet3'
    addressPrefix: '10.0.2.0/24'
  }
]

resource vnet 'Microsoft.Network/virtualNetworks@2022-09-01' = {
  name: 'vnet1'
  properties: {
    subnets: [for item in subnets: {
      name: item.name
      properties: {
        addressPrefix: item.addressPrefix
      }
    }]
  }
}

output subnets array = vnet.properties.subnets

BernieWhite avatar Jun 01 '23 14:06 BernieWhite

Hi @BernieWhite

The most outstanding difference between your repro and our is that the equal values of the filter argument is a variable and not a hardcoded string:

param environment string = 'production'

module virtualNetwork 'br/BicepFeatures:virtualnetwork:v2.2.0' = {
  name: 'virtualNetworkLZ-${nameSuffix}'
  scope: resourceGroup(resourceGroupName)
  dependsOn: [resourceGroupLZ]
  params: {
    customName: vNetName
    applicationName: ''
    environmentName: ''
    index: 1
    regionName: ''
    vNetPrefix: ['10.11.0.0/16']
    subnets: subnets
    workloadName: ''
    tags: tags
  }
}

module keyVault '../../services/keyvault.bicep' = {
  scope: resourceGroup(resourceGroupName)
  dependsOn: [resourceGroupLZ, virtualNetwork]
  name: 'keyVaultLZ-${nameSuffix}'
  params: {
    name: keyVaultName
    environmentName: environmentName
    logAnalyticsWorkspaceID: logAnalyticsWorkspace.id
    managed: managed
    tags: tags
    subnetId: filter(virtualNetwork.outputs.subnets, s => s.name == environment)[0].id
  }
}
resource vNet 'Microsoft.Network/virtualNetworks@2021-08-01' = {
  name: empty(customName) ? toLower('vnet-${workloadName}-${applicationName}-${environmentName}-${regionName}-${padLeft(index, 2, '0')}') : customName
  location: location
  tags: tags
  properties: {
    addressSpace: {
      addressPrefixes: vNetPrefix
    }
    dhcpOptions: {
      dnsServers: vNetDnsServers
    }
    subnets: subnets
  }
}

@description('The name of the Azure resource')
output resourceName string = vNet.name
@description('The resource-id of the Azure resource')
output resourceID string = vNet.id
@description('Array of subnets created in the vNet module.')
output subnets array = vNet.properties.subnets

donheerschap avatar Jun 02 '23 07:06 donheerschap

@donheerschap Thanks for the additional information. This may be fixed by #2255 (v1.27.1) which is related to dependency ordering that could cause this issue.

If you give it a go, let me know if this fixes your issue.

BernieWhite avatar Jun 03 '23 05:06 BernieWhite

@BernieWhite I'm not getting it anymore on the variable argument, but I do on the hardcoded arguments:

Using PSRule v2.8.1
Using PSRule.Rules.Azure v1.28.0-B0010

----------------------------
Explore documentation: https://aka.ms/ps-rule
Contribute and find source: https://github.com/microsoft/PSRule
Report issues: https://github.com/microsoft/PSRule/issues
PSRule.Rules.Azure: https://aka.ms/ps-rule-azure
----------------------------

From repository: https://github.com/WeAreInSpark/Solution.ManagedOxygen
  on : refs/pull/23/merge
  at : 47fd08620428df05[52](https://github.com/WeAreInSpark/Solution.ManagedOxygen/actions/runs/5176359771/jobs/9325080304?pr=23#step:4:54)7c0f15d45b89dca66b05d7

Error: Unable to expand resources because the source file '/home/runner/work/Solution.ManagedOxygen/Solution.ManagedOxygen/OxygenManagementZone.bicep' was not valid. An error occurred evaluating expression '[filter(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('virtualNetworkMZ-{0}', parameters('nameSuffix'))), '2022-09-01').outputs.subnets.value, lambda('s', equals(lambdaVariables('s').name, 'OxygenManagementZone')))[0].id]' line 2835. The arguments for 'Filter' are not in the expected format or type.

donheerschap avatar Jun 05 '23 11:06 donheerschap

Hi, any update on this issue. We are facing similar issue with our code:

Using PSRule v2.9.0
Using PSRule.Rules.Azure v1.28.0-B0010

...

An error occurred evaluating expression '[filter(parameters('subnetList'), lambda('item', equals(lambdaVariables('item').name, 'AzureBastionSubnet')))]' line 586. Invalid cast from 'System.String' to 'Newtonsoft.Json.Linq.JArray'."

Our template:

param subnetList array

var subnetAzureBastion = filter(subnetList, item => item.name == 'AzureBastionSubnet' )
var subnetAzureBastionSubnetaddressPrefix = !empty(subnetAzureBastion) ? subnetAzureBastion[0].properties.addressPrefix : ''

output rules array = !empty(subnetAzureBastion) ? [
  { 
    name: 'allow-inbound-ssh-from-bastion'
    properties: {
      description: 'Allow SSH from bastion traffic'
      direction: 'Inbound'
      priority: 100
      access: 'Allow'
      protocol: 'Tcp'
      sourcePortRange: '*'
      destinationPortRange: '22'
      sourceAddressPrefix: subnetAzureBastionSubnetaddressPrefix
      destinationAddressPrefix: '*'
    }
  }
  {
    name: 'allow-inbound-rdp-from-bastion'
    properties: {
      description: 'Allow RDP from bastion traffic'
      direction: 'Inbound'
      priority: 110
      access: 'Allow'
      protocol: 'Tcp'
      sourcePortRange: '*'
      destinationPortRange: '3389'
      sourceAddressPrefix: subnetAzureBastionSubnetaddressPrefix
      destinationAddressPrefix: '*'
    }
  }
] : []

This is triggered from a template that creates NSG rules like this (not the entire template is included, as it is a large one...):

// Existing resources for reference
resource vnet 'Microsoft.Network/virtualNetworks@2020-08-01' existing = {
  name: vnetName
}

// Generate Bastion Rules if AzureBastionSubnet is detected
module bastionRules 'submodules/bastion.bicep' = {
  name: '${deployment().name}-bastionRules'
  params: {
    subnetList: vnet.properties.subnets
  }
}

This deploy just fine to azure and works as expected there, but PSRule errors and stop inspect.

Same is observed as mentioned in this thread. If i hardcode the "subnetList" parameter with a parameter file and then run PSRule works, but when dynamically generated by fetching information form an exisiting resource causes the error.

haavardg avatar Jun 26 '23 10:06 haavardg

Hi @Dylan-Prins @donheerschap @haavardg, we've released a pre-release 1.28.0-B0079 which we hope addressed the above issues in your environment.

If you are able to try and provide feedback we'd appreciated it.

BernieWhite avatar Jul 04 '23 06:07 BernieWhite

Hi bernie,

Sorry for the delay but the issue is still not fixed

____  _____ ____        __
   / __ \/ ___// __ \__  __/ /__
  / /_/ /\__ \/ /_/ / / / / / _ \
 / ____/___/ / _, _/ /_/ / /  __/
/_/    /____/_/ |_|\__,_/_/\___/

Using PSRule v2.9.0
Using PSRule.Rules.Azure v1.29.0-B0062

----------------------------
Explore documentation: https://aka.ms/ps-rule
Contribute and find source: https://github.com/microsoft/PSRule
Report issues: https://github.com/microsoft/PSRule/issues
PSRule.Rules.Azure: https://aka.ms/ps-rule-azure
----------------------------

From repository: https://github.com/*******
  on : refs/pull/[47](https://github.com/WeAreInSpark/Solution.ManagedOxygen/actions/runs/5809977598/job/15749906778?pr=49#step:4:49)/merge
  at : 4c44a858eaa8509f3f37330029fe3e58b88fdeef

Warning: The option 'Execution.NotProcessedWarning' is deprecated and will be removed with PSRule v3. See http://aka.ms/ps-rule/deprecations for more detail.
Error: Unable to expand resources because the source file '/home/runner/work/Solution.ManagedOxygen/Solution.ManagedOxygen/OxygenManagementZone.bicep' was not valid. An error occurred evaluating expression '[parameters('devOpsAgentVMPassword')]' line 423. The parameter named 'devOpsAgentVMPassword' was not set or a defaultValue was defined.

 -> tests/OxygenManagementZone_cia.production.parameters.json : .json [5/5]

    [PASS] Azure.Template.ParameterFile (AZR-000229)
    [PASS] Azure.Template.ParameterScheme (AZR-000230)
    [PASS] Azure.Template.MetadataLink (AZR-000231)
    [PASS] Azure.Template.ParameterValue (AZR-000232)
    [PASS] Azure.Template.ValidSecretRef (AZR-000233)

Error: Unable to expand resources because the source file '/home/runner/work/Solution.ManagedOxygen/Solution.ManagedOxygen/OxygenLandingZone.bicep' was not valid. An error occurred evaluating expression '[filter(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, variables('resourceGroupName')), 'Microsoft.Resources/deployments', 'networkmodule'), '2022-09-01').outputs.subnets.value, lambda('s', equals(lambdaVariables('s').name, parameters('environment'))))[0].id]' line 29[49](https://github.com/WeAreInSpark/Solution.ManagedOxygen/actions/runs/5809977598/job/15749906778?pr=49#step:4:51). The arguments for 'Filter' are not in the expected format or type.

Dylan-Prins avatar Aug 16 '23 12:08 Dylan-Prins

@BernieWhite sorry, did not mention you.

Dylan-Prins avatar Sep 06 '23 06:09 Dylan-Prins

Thanks for the update @Dylan-Prins

BernieWhite avatar Sep 09 '23 04:09 BernieWhite

@BernieWhite any update on this one? We're having exactly the same problem on a line like this one:

...
resource vnet 'Microsoft.Network/virtualNetworks@2023-02-01' existing = {
  scope: resourceGroup(vnetRgName)
  name: vnetName
}

resource functionApp 'Microsoft.Web/sites@2022-09-01' = {
  ...
  properties: {
    serverFarmId: modServicePlan.outputs.servicePlanId
    virtualNetworkSubnetId: filter(vnet.properties.subnets, s => s.name == subnetName)[0].id // <===== line with problem
  ...

@Dylan-Prins did you find a work-around for this?

JaccoDieleman avatar May 30 '24 10:05 JaccoDieleman

@JaccoDieleman Thanks for the reproduction.

There is no easy fix for your case, because you're using existing PSRule don't know how many subnets your existing VNET in Azure has, or what they are called.

We could just return [] an empty array, but then your [0].id would be null and fail elsewhere.

An alternatively approach would be to use:

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-02-01' existing = {
  scope: resourceGroup(vnetRgName)
  name: '${vnetName}/${subnetName}'
}

resource functionApp 'Microsoft.Web/sites@2022-09-01' = {
  ...
  properties: {
    serverFarmId: modServicePlan.outputs.servicePlanId
    virtualNetworkSubnetId: subnet.id
  ...

OR

resource vnet 'Microsoft.Network/virtualNetworks@2023-02-01' existing = {
  scope: resourceGroup(vnetRgName)
  name: vnetName
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-02-01' existing = {
  parent: vnet
  name: subnetName
}

resource functionApp 'Microsoft.Web/sites@2022-09-01' = {
  ...
  properties: {
    serverFarmId: modServicePlan.outputs.servicePlanId
    virtualNetworkSubnetId: subnet.id
  ...

BernieWhite avatar May 30 '24 14:05 BernieWhite

@BernieWhite Thanks a lot for your prompt reply! This solved the problem! 🥳 Besides, my bicep code is a bit more readable.

JaccoDieleman avatar May 31 '24 06:05 JaccoDieleman