Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Expose ValidationLevel so what-if can run under a least-privilege identity

Open
#954 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
78/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
azure, powershell
Domain
cloud, devops, security

Research direction

Start in src/internal/functions/New-AzOpsDeployment.ps1 and trace how $parameters is assembled before the what-if command call. Add the documented Core.WhatIfValidationLevel setting while preserving the Provider default, then verify that what-if receives the setting and that ProviderNoRbac supports least-privilege validation without changing existing behavior.

Written by the indexing model from the issue text.

Description

Summary

New-AzOpsDeployment never passes -ValidationLevel to the what-if cmdlets, so ARM always applies the default Provider. Provider runs preflight as a real deployment and checks write permission on every resource in the template. The practical result is that Invoke-AzOpsPush -WhatIf cannot run under a least-privilege identity — the Validate pipeline must use the same principal as Push.

ARM already supports the fix. ValidationLevel: ProviderNoRbac performs full template and provider validation but checks only read permission per resource. AzOps just has no way to ask for it.

Current behaviour

In src/internal/functions/New-AzOpsDeployment.ps1 the what-if call is:

$results = & $whatIfCommand @parameters -ErrorAction Continue -ErrorVariable resultsError

$parameters is built up through the function and never contains a ValidationLevel entry. There is no PSFConfig setting for it either — the only what-if related key is Core.WhatifExcludedChangeTypes.

Repro
  1. Give the Validate pipeline identity a role with */read, Microsoft.Resources/deployments/whatIf/action and Microsoft.Resources/deployments/validate/action, and no write on any resource type.
  2. Open a pull request that adds a resource — in our case Microsoft.AlertsManagement/actionRules and microsoft.insights/actionGroups.
  3. Validate fails:
Get-AzResourceGroupDeploymentWhatIfResult: InvalidTemplateDeployment - Long running operation
failed with status 'Failed'. Additional Info:'The template deployment failed with error:
'Authorization failed for template resource '<name>' of type
'Microsoft.AlertsManagement/actionRules'. The client '***' with object id '<redacted>' does not
have permission to perform action 'Microsoft.AlertsManagement/actionRules/write' at scope
'/subscriptions/<redacted>/resourceGroups/<redacted>/providers/Microsoft.AlertsManagement/actionRules/<name>'.'.'

Granting Microsoft.Resources/deployments/whatIf/action alone is not enough — that clears the first error, and then preflight fails on the per-resource write check.

Why this matters

The usual CI pattern is a low-privilege identity for PR preview and a separate writer for deploy, so that a pull request from anyone cannot run under a principal able to change production. With AzOps, Validate has to hold deploy rights, because what-if demands them.

AzOps-Accelerator ships a single credentials variable group shared by pull.yml, validate.yml and push.yml, so this is consistent with the reference design today — but it means the split isn't available to anyone who wants it.

Proposal

Expose the ARM parameter as a setting, defaulting to Provider so existing behaviour is unchanged:

"Core.WhatIfValidationLevel": "Provider"

and add it to the splat in New-AzOpsDeployment when a what-if is being performed, e.g.

$validationLevel = Get-PSFConfigValue -FullName 'AzOps.Core.WhatIfValidationLevel'
if ($validationLevel) {
    $parameters.ValidationLevel = $validationLevel
}

Operators who want a read-only preview identity could then set ProviderNoRbac and pair it with a custom role of */read plus the two preview actions. AzOps-Accelerator could subsequently offer a separate validate identity, which is not possible while the module cannot pass the parameter.

Workaround considered and rejected

Injecting the parameter from the pipeline:

$global:PSDefaultParameterValues['Get-AzResourceGroupDeploymentWhatIfResult:ValidationLevel'] = 'ProviderNoRbac'

This is unsupported, relies on the global scope reaching into module scope, does not reach the ForEach-Object -Parallel runspaces used when AllowMultipleTemplateParameterFiles and ParallelDeployMultipleTemplateParameterFiles are enabled, and fails silently by reverting to Provider rather than reporting that the setting was ignored.

Versions
  • AzOps 2.8.5, and confirmed unchanged on main at time of writing
  • Azure DevOps pipelines from AzOps-Accelerator
  • ValidationLevel requires Az PowerShell 13.4.0+ / Azure CLI 2.76.0+
References
Dominant language
PowerShell
Stars
420
Forks
174
Avg merge
16d 18h
Merged PRs (30d)
1

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Azure/AzOps

All issues in Azure/AzOps

Similar issues

More Cloud issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.