Azure / Azure/bicep

Decompiler creates placeholder module parameter types if parameter types cannot be determined

Open
#3,913 1 comment 0 reactions 0 assignees View on GitHub
enhancement story: decompiler
Dominant language
Bicep
Stars
3.6k
Forks
830
Avg merge
1d 2h
Merged PRs (30d)
79

Description

**Bicep version**: `0.4.588`

**Describe the bug**
I attempting to decompile our IaCS automation account template and found that it seems to fail to properly reference elements in an array used by the module. While the loop for the module is correctly created, all parameters are missing their reference to the index. E.g. something should be formatted as `names[i]` but is instead only referenced as `names` which understandably causes subsequent issues.
Instead the ARM-originated `[copyIndex()]` is referenced inside the module where it is unknown (see below).

**To Reproduce**
The template looks something along the lines of

```Json
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"automationAccountName": {
"type": "string"
},
"runbooks": {
"type": "array",
"minLength": 0,
"defaultValue": [
]
}
},
"variables": {
"dummyRunbooks": {
"runbookName": "dummyRunbookValue"
},
"runbooks": "[if(greater(length(parameters('runbooks')),0),parameters('runbooks'), array(variables('dummyRunbooks')))]"

},
"resources": [
{
"condition": "[not(empty(array(parameters('runbooks'))))]",
"type": "Microsoft.Resources/deployments",
"name": "[concat('runbook-', if(empty(parameters('runbooks')), 'dummy', copyIndex('runbookCopy')))]",
"apiVersion": "2020-06-01",
"copy": {
"name": "runbookCopy",
"count": "[if(not(empty(variables('runbooks'))), length(variables('runbooks')), 1)]"
},
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Automation/automationAccounts/runbooks",
"name": "[concat(parameters('automationAccountName'), '/', variables('runbooks')[copyIndex()].runbookName)]",
"apiVersion": "2018-06-30",
"location": "[resourceGroup().location]",
"properties": {
"runbookType": "[if(empty(variables('runbooks')[copyIndex()].runbookType), json('null'), variables('runbooks')[copyIndex()].runbookType)]",
"publishContentLink": {
"uri": "someUri",
"version": "someVersion"
}
}
}
]
}
}
}
]
}
```

The bicep template in turn:
```bicep
param automationAccountName string
@minLength(0)
param runbooks array = []

var dummyRunbooks = {
runbookName: 'dummRunbookValue'
}
var runbooks_var = ((length(runbooks) > 0) ? runbooks : array(dummyRunbooks))

module runbook_runbooks_dummy_runbookCopy './nested_runbook_runbooks_dummy_runbookCopy.bicep' = [for i in range(0, ((!empty(runbooks_var)) ? length(runbooks_var) : 1)): {
name: 'runbook-${(empty(runbooks) ? 'dummy' : i)}'
params: {
variables_runbooks_copyIndex_runbookName: runbooks_var /* ### NOTE: This block is where the index references are missing */
variables_runbooks_copyIndex_runbookType: runbooks_var
variables_runbooks_copyIndex_runbookScriptUri: runbooks_var
variables_runbooks_copyIndex: runbooks_var
variables_runbooks_copyIndex_scriptStorageAccountId: runbooks_var
automationAccountName: automationAccountName
}
dependsOn: [
automationAccountName_resource
]
}]
```
with the inner file

```bicep
param variables_runbooks_copyIndex_runbookName ? /* TODO: fill in correct type */
param variables_runbooks_copyIndex_runbookType ? /* TODO: fill in correct type */
param variables_runbooks_copyIndex_runbookScriptUri ? /* TODO: fill in correct type */
param variables_runbooks_copyIndex ? /* TODO: fill in correct type */
param variables_runbooks_copyIndex_scriptStorageAccountId ? /* TODO: fill in correct type */

param automationAccountName string

resource automationAccountName_variables_runbooks_copyIndex_runbookName_runbookName 'Microsoft.Automation/automationAccounts/runbooks@2018-06-30' = {
name: '${automationAccountName}/${variables_runbooks_copyIndex_runbookName[copyIndex()].runbookName}' /* ### NOTE: The incorrect reference to the ARM copyIndex() function */
location: resourceGroup().location
properties: {
runbookType: (empty(variables_runbooks_copyIndex_runbookType[copyIndex()].runbookType) ? json('null') : variables_runbooks_copyIndex_runbookType[copyIndex()].runbookType)
publishContentLink: {
uri: "someUri"
version: "someVersion"
}
}
}
```

**Additional context**

While I do understand that the decompiler is unable to determine the type of parameter (in this case primarily strings) as the runbooks variable is an object; however, it should not care when handing the parameters over and just reference `runbooks_var[i]`.

I mean - it even says **'copyIndex'** in the parameter names.

Instead it seems to reference the index inside the module where `[copyIndex()]` is not something that exists. I guess it boils down to the decompiler failing to determine the parameter-types and then giving up/making the wrong assumptions.

Contributor guide

Open the contributing guide

Research direction

Start with the decompiler path that converts ARM copyIndex() expressions and inferred module parameter types; reproduce the behavior using the JSON template and generated Bicep files shown in the report. Done means the generated module arguments preserve the loop index and the nested file no longer relies on an unknown copyIndex().

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, json
Domain
compilers, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.