Proposal - 'Strict mode' for WhatIf / Preflight validation
- Dominant language
- Bicep
- Stars
- 3.6k
- Forks
- 830
- Avg merge
- 1d 21m
- Merged PRs (30d)
- 79
Description
# Proposal - 'Strict mode' for WhatIf / Preflight validation
## Problem statement
Without any diagnostics, it is difficult to understand which scenarios might cause a template to be partially validated by preflight or what-if. Some example problematic authoring patterns:
* Passing 'runtime' values to nested module parameters, and then using them to format resource names.
* Using `newGuid` / `utcNow` to format resource names.
Other patterns which may decrease WhatIf accuracy or reduce Preflight validation capabilities include:
* Combining 'runtime' & 'deploy time' values to format large body properties.
I'd like to see a 'Strict mode' which can be enabled in the Bicep config, so that full validation is the default behavior, with a way of opting out in situations where runtime behavior is unavoidable.
The opt-out of Strict mode could behave a bit like Rust's [`unsafe` keyword](https://doc.rust-lang.org/std/keyword.unsafe.html) - where all the 'non-strict' code is clearly marked and easier to scrutinize - using for example a `#disable-next-line strict-mode-validation`.
## Syntax
Just some very rough mockups to give an idea of what I'm thinking. With the below, Bicep should give the user the guarantee that **everything** will be evaluated during preflight/what-if, apart from the things that the user has explicitly opted out of with `#disable-next-line strict-mode-validation`.
### bicepconfig.json
```json
{
"strict-mode": {
"enabled": true
}
}
```
### Bicep samples
#### module.bicep
```bicep
// params must be constants by default - requiring a @runtime decorator to opt-out
@runtime()
param myRuntimeValue string
// by default, parameters are considered to be deploy-time constants
param myConstant string
// Blocked with an error message. Runtime value is being used as a default value for a constant param
param myConstantGuid string = newGuid()
// Blocked with an error message. Runtime value is being used as a default value for a constant param
param myConstantDefaultValue string = toLower(myRuntimeValue)
resource blah '...' = {
// Permitted
name: toLower(myConstant)
...
}
resource blah2 '...' = {
// Blocked with an error message. Runtime param value is being used to format a resource name
name: toLower(myRuntimeValue )
...
}
resource blah3 '...' = {
name: 'blah3'
// Warning - preflight/whatif validation will not be precise as we're using a runtime value to format a resource body
properties: myRuntimeValue
}
resource blah4 '...' = {
name: 'blah4'
// Permitted - user has opted out of warning
#disable-next-line strict-mode-validation
properties: myRuntimeValue
}
// Permitted - outputting a Runtime value, but marking as such
@runtime()
output myRuntimeOutput string = blah.properties.runtimeValue
// Permitted - id is a constant
output constantResId string = blah.id
// Permitted - name is a constant
output constantResName string = blah.name
// Blocked - the output has not been marked with @runtime, but is outputting a runtime value
output myConstantOutput string = blah.properties.runtimeValue
```
#### main.bicep
```bicep
resource foo '...' existing = {
name: 'foo'
}
module myMod './module.bicep' = {
name: 'myMod'
params: {
// Permitted - using a runtime value for a param marked with @runtime
myRuntimeValue: foo.properties.somethingUnsafe
// Blocked
myConstant: foo.properties.somethingUnsafe
// Permitted - id, name, type & apiVersion are constants
myConstantGuid : foo.id
}
}
module otherMod './otherMod.bicep' = {
// Permitted - we know that constantResName is a constant
name: myMod.outputs.constantResName
params: {
// Permitted - passing a runtime output to a runtime param
runtimeParam: myMod.outputs.myRuntimeOutput
// Permitted - passing a constant output to a constant param
constantParam: myMod.outputs.constantResId
}
}
```
## Implementation
TBD. I wanted to create this issue to gauge interest first.
Contributor guide
Research direction
Review the proposal's bicepconfig.json, module.bicep, and main.bicep examples to identify the requested strict-mode rules, runtime opt-outs, and diagnostics. Implementation is marked TBD; work would be complete when the behavior, configuration, syntax, and validation scope are defined and agreed for the shown scenarios.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure
- Domain
- cloud, compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100