Skip to content

Commit e7fb877

Browse files
authored
Address all Bicep warnings (#2854)
1 parent a197445 commit e7fb877

13 files changed

+139
-1361
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
description: 'Infrastructure as Code with Bicep'
3+
applyTo: '**/*.bicep'
4+
---
5+
6+
# Bicep best-practices
7+
This list of best-practices builds on top of information available at https://learn.microsoft.com/azure/azure-resource-manager/bicep. It provides a more opinionated and up-to-date set of rules for generating high-quality Bicep code. You should aim to follow these rules whenever generating or modifying Bicep code.
8+
9+
## Rules
10+
### General
11+
1. Avoid setting the `name` field for `module` statements - it is no longer required.
12+
1. If you need to input or output a set of logically-grouped values, generate a single `param` or `output` statement with a User-defined type instead of emitting a `param` or `output` statement for each value.
13+
1. If generating parameters, default to generating Bicep parameters files (`*.bicepparam`), instead of ARM parameters files (`*.json`).
14+
15+
### Resources
16+
1. Do not add references from child resources to parent resources by using `/` characters in the child resource `name` property. Instead, use the `parent` property with a symbolic reference to the parent resource.
17+
1. If you are generating a child resource type, sometimes this may require you to add an `existing` resource for the parent if the parent is not already present in the file.
18+
1. If you see diagnostic codes `BCP036`, `BCP037` or `BCP081`, this may indicate you have hallucinated resource types or resource type properties. You may need to double-check against available resource type schema to tune your output.
19+
1. Avoid using multiple `resourceId()` functions and `reference()` function where possible. Instead use symbolic names to refer to ids or properties, creating `existing` resources if needed. For example, write `foo.id` or `foo.properties.id`, instead of `resourceId('...')` or `reference('...').id`.
20+
21+
### Types
22+
1. Avoid using open types such as `array` or `object` when referencing types where possible (e.g. in `output` or `param` statements). Instead, use User-defined types to define a more precise type.
23+
1. Use typed variables instead of untyped variables when exporting values with the `@export()` decorator. For example, use `var foo string = 'blah'` instead of `var foo = bar`.
24+
1. When using User-defined types, aim to avoid repetition, and comment properties with `@description()` where the context is unclear.
25+
1. If you are passing data directly to or from a resource body via a `param` or `output` statement, try to use existing Resource-derived types (`resourceInput<'type@version'>` and `resourceOutput<'type@version'>`) instead of writing User-defined types.
26+
27+
### Security
28+
1. When generating `param` or `output` statements, ALWAYS use the `@secure()` decorator if sensitive data is present.
29+
30+
### Syntax
31+
1. If you hit warnings or errors with null properties, prefer solving them with the safe-dereference (`.?`) operator, in conjunction with the coalesce (`??`) operator. For example, `a.?b ?? c` is better than `a!.b` which may cause runtime errors, or `a != null ? a.b : c` which is unnecessarily verbose.
32+
33+
## Glossary
34+
* Child resource: an Azure resource type with type name consisting of more than 1 `/` characters. For example, `Microsoft.Network/virtualNetworks/subnets` is a child resource. `Microsoft.Network/virtualNetworks` is not.

docs/deploy_existing.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ You should set these values before running `azd up`. Once you've set them, retur
88
* [OpenAI resource](#openai-resource)
99
* [Azure AI Search resource](#azure-ai-search-resource)
1010
* [Azure App Service Plan and App Service resources](#azure-app-service-plan-and-app-service-resources)
11-
* [Azure Application Insights and related resources](#azure-application-insights-and-related-resources)
1211
* [Azure AI Vision resources](#azure-ai-vision-resources)
1312
* [Azure Document Intelligence resource](#azure-document-intelligence-resource)
1413
* [Azure Speech resource](#azure-speech-resource)
@@ -72,12 +71,6 @@ You can also customize the search service (new or existing) for non-English sear
7271
1. Run `azd env set AZURE_APP_SERVICE {Name of existing Azure App Service}`.
7372
1. Run `azd env set AZURE_APP_SERVICE_SKU {SKU of Azure App Service, defaults to B1}`.
7473

75-
## Azure Application Insights and related resources
76-
77-
1. Run `azd env set AZURE_APPLICATION_INSIGHTS {Name of existing Azure App Insights}`.
78-
1. Run `azd env set AZURE_APPLICATION_INSIGHTS_DASHBOARD {Name of existing Azure App Insights Dashboard}`.
79-
1. Run `azd env set AZURE_LOG_ANALYTICS {Name of existing Azure Log Analytics Workspace Name}`.
80-
8174
## Azure AI Vision resources
8275

8376
1. Run `azd env set AZURE_VISION_SERVICE {Name of existing Azure AI Vision Service Name}`

infra/backend-dashboard.bicep

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ param applicationInsightsName string
44
param location string = resourceGroup().location
55
param tags object = {}
66

7-
// 2020-09-01-preview because that is the latest valid version
87
resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-preview' = {
98
name: name
109
location: location
@@ -21,7 +20,9 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
2120
colSpan: 2
2221
rowSpan: 1
2322
}
24-
metadata: {
23+
// The Bicep schema only defines MarkdownPart, so we use any() to bypass
24+
// type checking for other valid extension types (AppInsightsExtension, MonitorChartPart)
25+
metadata: any({
2526
inputs: [
2627
{
2728
name: 'id'
@@ -32,14 +33,13 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
3233
value: '1.0'
3334
}
3435
]
35-
#disable-next-line BCP036
3636
type: 'Extension/AppInsightsExtension/PartType/AspNetOverviewPinnedPart'
3737
asset: {
3838
idInputName: 'id'
3939
type: 'ApplicationInsights'
4040
}
4141
defaultMenuItemId: 'overview'
42-
}
42+
})
4343
}
4444
{
4545
position: {
@@ -48,7 +48,7 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
4848
colSpan: 1
4949
rowSpan: 1
5050
}
51-
metadata: {
51+
metadata: any({
5252
inputs: [
5353
{
5454
name: 'ComponentId'
@@ -63,14 +63,13 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
6363
value: '1.0'
6464
}
6565
]
66-
#disable-next-line BCP036
6766
type: 'Extension/AppInsightsExtension/PartType/ProactiveDetectionAsyncPart'
6867
asset: {
6968
idInputName: 'ComponentId'
7069
type: 'ApplicationInsights'
7170
}
7271
defaultMenuItemId: 'ProactiveDetection'
73-
}
72+
})
7473
}
7574
{
7675
position: {
@@ -79,7 +78,7 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
7978
colSpan: 1
8079
rowSpan: 1
8180
}
82-
metadata: {
81+
metadata: any({
8382
inputs: [
8483
{
8584
name: 'ComponentId'
@@ -105,13 +104,12 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
105104
value: '78ce933e-e864-4b05-a27b-71fd55a6afad'
106105
}
107106
]
108-
#disable-next-line BCP036
109107
type: 'Extension/AppInsightsExtension/PartType/AppMapButtonPart'
110108
asset: {
111109
idInputName: 'ComponentId'
112110
type: 'ApplicationInsights'
113111
}
114-
}
112+
})
115113
}
116114
{
117115
position: {
@@ -141,7 +139,7 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
141139
colSpan: 1
142140
rowSpan: 1
143141
}
144-
metadata: {
142+
metadata: any({
145143
inputs: [
146144
{
147145
name: 'ResourceId'
@@ -167,15 +165,14 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
167165
isOptional: true
168166
}
169167
]
170-
#disable-next-line BCP036
171168
type: 'Extension/AppInsightsExtension/PartType/CuratedBladeFailuresPinnedPart'
172169
isAdapter: true
173170
asset: {
174171
idInputName: 'ResourceId'
175172
type: 'ApplicationInsights'
176173
}
177174
defaultMenuItemId: 'failures'
178-
}
175+
})
179176
}
180177
{
181178
position: {
@@ -205,7 +202,7 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
205202
colSpan: 1
206203
rowSpan: 1
207204
}
208-
metadata: {
205+
metadata: any({
209206
inputs: [
210207
{
211208
name: 'ResourceId'
@@ -231,15 +228,14 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
231228
isOptional: true
232229
}
233230
]
234-
#disable-next-line BCP036
235231
type: 'Extension/AppInsightsExtension/PartType/CuratedBladePerformancePinnedPart'
236232
isAdapter: true
237233
asset: {
238234
idInputName: 'ResourceId'
239235
type: 'ApplicationInsights'
240236
}
241237
defaultMenuItemId: 'performance'
242-
}
238+
})
243239
}
244240
{
245241
position: {
@@ -248,7 +244,7 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
248244
colSpan: 4
249245
rowSpan: 3
250246
}
251-
metadata: {
247+
metadata: any({
252248
inputs: [
253249
{
254250
name: 'options'
@@ -306,10 +302,9 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
306302
isOptional: true
307303
}
308304
]
309-
#disable-next-line BCP036
310305
type: 'Extension/HubsExtension/PartType/MonitorChartPart'
311306
settings: {}
312-
}
307+
})
313308
}
314309
{
315310
position: {
@@ -318,7 +313,7 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
318313
colSpan: 4
319314
rowSpan: 3
320315
}
321-
metadata: {
316+
metadata: any({
322317
inputs: [
323318
{
324319
name: 'options'
@@ -376,10 +371,9 @@ resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-pr
376371
isOptional: true
377372
}
378373
]
379-
#disable-next-line BCP036
380374
type: 'Extension/HubsExtension/PartType/MonitorChartPart'
381375
settings: {}
382-
}
376+
})
383377
}
384378
]
385379
}

infra/core/ai/hub.bicep

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ resource hub 'Microsoft.MachineLearningServices/workspaces@2024-07-01-preview' =
6060
category: 'CognitiveSearch'
6161
authType: 'ApiKey'
6262
isSharedToAll: true
63-
target: 'https://${search.name}.search.windows.net/'
63+
target: 'https://${search!.name}.search.windows.net/'
6464
credentials: {
65-
key: !empty(aiSearchName) ? search.listAdminKeys().primaryKey : ''
65+
key: !empty(aiSearchName) ? search!.listAdminKeys().primaryKey : ''
6666
}
6767
}
6868
}

infra/core/host/appservice.bicep

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ resource appService 'Microsoft.Web/sites@2022-03-01' = {
9999
ENABLE_ORYX_BUILD: string(enableOryxBuild)
100100
},
101101
runtimeName == 'python' ? { PYTHON_ENABLE_GUNICORN_MULTIWORKERS: 'true' } : {},
102-
!empty(applicationInsightsName) ? { APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsights.properties.ConnectionString } : {},
103-
!empty(keyVaultName) ? { AZURE_KEY_VAULT_ENDPOINT: keyVault.properties.vaultUri } : {})
102+
!empty(applicationInsightsName) ? { APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsights!.properties.ConnectionString } : {},
103+
!empty(keyVaultName) ? { AZURE_KEY_VAULT_ENDPOINT: keyVault!.properties.vaultUri } : {})
104104
}
105105

106106
resource configLogs 'config' = {

infra/core/host/container-app-upsert.bicep

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ module app 'container-app.bicep' = {
116116
allowedOrigins: allowedOrigins
117117
external: external
118118
env: concat(envAsArray, envSecrets)
119-
imageName: !empty(imageName) ? imageName : exists ? existingApp.properties.template.containers[0].image : ''
119+
imageName: !empty(imageName) ? imageName : exists ? existingApp!.properties.template.containers[0].image : ''
120120
targetPort: targetPort
121121
serviceBinds: serviceBinds
122122
}

infra/core/host/container-app.bicep

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ module containerRegistryAccess '../security/registry-access.bicep' = if (usePriv
104104
name: '${deployment().name}-registry-access'
105105
params: {
106106
containerRegistryName: containerRegistryName
107-
principalId: usePrivateRegistry ? userIdentity.properties.principalId : ''
107+
principalId: usePrivateRegistry ? userIdentity!.properties.principalId : ''
108108
}
109109
}
110110

@@ -174,7 +174,7 @@ resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-05-01'
174174
}
175175

176176
output defaultDomain string = containerAppsEnvironment.properties.defaultDomain
177-
output identityPrincipalId string = normalizedIdentityType == 'None' ? '' : (empty(identityName) ? app.identity.principalId : userIdentity.properties.principalId)
177+
output identityPrincipalId string = normalizedIdentityType == 'None' ? '' : (empty(identityName) ? app.identity.principalId : userIdentity!.properties.principalId)
178178
output identityResourceId string = normalizedIdentityType == 'UserAssigned' ? resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', userIdentity.name) : ''
179179
output imageName string = imageName
180180
output name string = app.name

infra/core/host/container-apps-environment.bicep

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2025-02-02-
2828
appLogsConfiguration: {
2929
destination: 'log-analytics'
3030
logAnalyticsConfiguration: {
31-
customerId: logAnalyticsWorkspace.properties.customerId
32-
sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey
31+
customerId: logAnalyticsWorkspace!.properties.customerId
32+
sharedKey: logAnalyticsWorkspace!.listKeys().primarySharedKey
3333
}
3434
}
35-
daprAIInstrumentationKey: daprEnabled && !empty(applicationInsightsName) ? applicationInsights.properties.InstrumentationKey : ''
35+
daprAIInstrumentationKey: daprEnabled && !empty(applicationInsightsName) ? applicationInsights!.properties.InstrumentationKey : ''
3636
publicNetworkAccess: usePrivateIngress ? 'Disabled' : 'Enabled'
3737
vnetConfiguration: usePrivateIngress ? {
3838
infrastructureSubnetId: subnetResourceId

0 commit comments

Comments
 (0)