[BUG] Expansion fails with "Hash must be finalized before the hash value is retrieved" when using an object output from a cross-scope module
Maintainers usually reply within 4 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 62/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- azure, powershell
- Domain
- cloud, devops, infrastructure
Research direction
Start by locating DeploymentVisitor.GetDeploymentScope and ExpressionHelpers.GetUnique, then reproduce the failure with the provided main.bicep, child.bicep, and assignments.bicep files with symbolicNameCodegen enabled. Done means the explicit cross-scope deployment resolves its object output correctly and guid() expands without the hash-finalization error or duplicate resource names.
Written by the indexing model from the issue text.
Description
Existing rule
N/A
Description of the issue
When a Bicep module is deployed to a different scope using the scope property (for example a nested management group), the resource ID recorded for the nested deployment does not account for the explicit scope.
DeploymentVisitor.GetDeploymentScope resolves the subscriptionId, resourceGroup and managementGroup properties of a deployment resource, but ignores the scope property. As a result the nested deployment is registered under its real scope, while the symbol resolves to the parent context scope. These do not match, so TemplateContext.TryGetResource fails to find the deployment.
reference() then falls back to a synthetic mock, and a chain such as reference('customRoles').outputs.policyReader.value.id resolves to an empty value instead of the expected string. When that empty value is passed to guid() as the last argument, expansion fails with:
Hash must be finalized before the hash value is retrieved
There are two defects here:
- The explicit
scopeproperty of a deployment resource is not used when calculating the resource ID, so cross-scope module outputs do not resolve. ExpressionHelpers.GetUniqueonly callsTransformFinalBlockwhen the final argument can be converted to a string. If it cannot, the hash is never finalized and readingHashAlgorithm.Hashthrows. An argument that cannot be converted in any other position is silently skipped instead, which would produce a duplicate name rather than an error.
Error messages
Hash must be finalized before the hash value is retrieved
Inner stack trace:
at System.Security.Cryptography.HashAlgorithm.get_Hash()
at PSRule.Rules.Azure.Arm.Expressions.ExpressionHelpers.GetUnique(Object[] args)
at PSRule.Rules.Azure.Arm.Expressions.Functions.Guid(ITemplateContext context, Object[] args)
Reproduction
The module deployed with scope set to a child management group is required to reproduce the issue. Without scope the same template expands correctly.
main.bicep:
targetScope = 'managementGroup'
resource intermediateRoot 'Microsoft.Management/managementGroups@2023-04-01' = {
scope: tenant()
name: 'mg-intermediate-root'
properties: {
displayName: 'Intermediate Root'
}
}
module customRoles './child.bicep' = {
name: 'customRoles'
scope: intermediateRoot
}
module roleAssignments './assignments.bicep' = {
name: 'roleAssignments'
scope: intermediateRoot
params: {
roleAssignments: [
{
principalId: '00000000-0000-0000-0000-000000000001'
roleDefinitionId: customRoles.outputs.policyReader.id
}
{
principalId: '00000000-0000-0000-0000-000000000002'
roleDefinitionId: customRoles.outputs.policyReader.id
}
]
}
}
child.bicep:
targetScope = 'managementGroup'
resource roleDefinition 'Microsoft.Authorization/roleDefinitions@2022-04-01' = {
name: guid('policyReader', managementGroup().id)
properties: {
roleName: 'Policy Reader'
description: 'Read only access to policy.'
type: 'CustomRole'
permissions: [
{
actions: [
'Microsoft.Authorization/policyAssignments/read'
]
}
]
assignableScopes: [
managementGroup().id
]
}
}
output policyReader object = {
id: roleDefinition.id
name: roleDefinition.name
}
assignments.bicep:
targetScope = 'managementGroup'
type roleAssignmentInput = {
principalId: string
roleDefinitionId: string
}
param roleAssignments roleAssignmentInput[]
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [
for assignment in roleAssignments: {
name: guid(managementGroup().id, assignment.principalId, assignment.roleDefinitionId)
properties: {
principalId: assignment.principalId
principalType: 'ServicePrincipal'
roleDefinitionId: assignment.roleDefinitionId
}
}
]
Expansion of main.bicep fails. Reducing the name to guid(assignment.roleDefinitionId) also fails, which isolates the failure to that argument. Removing scope: intermediateRoot from the modules allows expansion to succeed.
The template requires symbolicNameCodegen to be enabled in bicepconfig.json to produce the reference('customRoles') form.
Version of PSRule
2.9.0
Version of PSRule for Azure
1.48.0
Additional context
Note that fixing only the hash finalization is not sufficient, and would be worse than the current behaviour. The unresolved argument would be silently skipped, so every role assignment sharing a principal would collapse to the same guid() value and expansion would emit duplicate resource names instead of an error. The scope resolution needs to be fixed so the value resolves correctly.
- Dominant language
- PowerShell
- Stars
- 449
- Forks
- 111
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 11
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Azure/PSRule.Rules.Azure
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Azure/PSRule.Rules.Azure#3929 · 1 comment ·
Maintainers usually reply within 4 days
-
Export-AzRuleData fails with HTTP 400 for DefenderForStorageSettings due to deprecated API versionOpenbug feature: in-flight-export
Difficulty 1/5 Under an hour Newbie friendliness 90/100
Azure/PSRule.Rules.Azure#3865 · 1 comment · 1 reaction ·
Maintainers usually reply within 4 days
-
Difficulty 3/5 1-2 days Newbie friendliness 75/100
Azure/PSRule.Rules.Azure#3920 ·
Maintainers usually reply within 4 days
-
bug feature: bicep-language feature: pre-flight-expansion
Difficulty 4/5 3-5 days Newbie friendliness 55/100
Azure/PSRule.Rules.Azure#3907 ·
Maintainers usually reply within 4 days
-
bug feature: bicep-language feature: pre-flight-expansion
Difficulty 4/5 3-5 days Newbie friendliness 48/100
Azure/PSRule.Rules.Azure#3884 ·
Maintainers usually reply within 4 days
All issues in Azure/PSRule.Rules.Azure
Similar issues
-
area:web bug P3
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 6 days
-
Difficulty 1/5 Under an hour Newbie friendliness 92/100
GoogleCloudPlatform/k8s-config-connector#13462 ·
Maintainers usually reply within 1 day
-
Needs: triage :mag:
Difficulty 1/5 Under an hour Newbie friendliness 92/100
microsoft/azure-container-apps#1842 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
neondatabase/neon#12950 · 1 comment ·