Skip to content

Commit 072dc95

Browse files
authored
Improve expansion internals documentation with high-level flow diagram and code references (#3716)
1 parent 49313ba commit 072dc95

7 files changed

Lines changed: 96 additions & 3 deletions

File tree

docs/assets/stylesheets/extra.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
--md-admonition-icon--learn: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M12.292 2.06v-.001l11.25 4.75a.749.749 0 0 1 0 1.382L19 10.108V15a.75.75 0 0 1-.11.391h-.001a2.84 2.84 0 0 1-.392.482c-.249.256-.625.58-1.163.896-1.08.638-2.776 1.23-5.334 1.23-.673 0-1.286-.041-1.846-.113a.75.75 0 0 1 .192-1.487c.492.063 1.042.1 1.654.1 2.317 0 3.746-.533 4.572-1.021.31-.178.596-.397.849-.65l.079-.085V10.74l-5.208 2.2a.75.75 0 0 1-.584 0L5.75 10.424v3.17c.502.129.96.391 1.327.758.579.578.923 1.41.923 2.428v4.5a.761.761 0 0 1-.345.634 2.157 2.157 0 0 1-.21.117 3.923 3.923 0 0 1-.52.213A6.121 6.121 0 0 1 5 22.532a6.092 6.092 0 0 1-1.925-.288 4.065 4.065 0 0 1-.52-.213 1.816 1.816 0 0 1-.22-.124.757.757 0 0 1-.335-.624v-4.5c0-1.02.344-1.85.923-2.43a2.904 2.904 0 0 1 1.327-.757V9.793L.458 8.19a.75.75 0 0 1 0-1.38l11.25-4.75a.75.75 0 0 1 .584 0ZM12 11.436 21.322 7.5 12 3.564 2.678 7.5ZM5 15c-.377 0-.745.141-1.017.413-.265.265-.483.7-.483 1.368v4.022c.299.105.797.228 1.5.228s1.201-.123 1.5-.228V16.78c0-.669-.218-1.103-.483-1.368A1.433 1.433 0 0 0 5 15Z"></path></svg>');
3333
--md-admonition-icon--message: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 4.75C0 3.784.784 3 1.75 3h20.5c.966 0 1.75.784 1.75 1.75v14.5A1.75 1.75 0 0 1 22.25 21H1.75A1.75 1.75 0 0 1 0 19.25Zm1.75-.25a.25.25 0 0 0-.25.25v14.5c0 .138.112.25.25.25h20.5a.25.25 0 0 0 .25-.25V4.75a.25.25 0 0 0-.25-.25Z"/><path d="M5 8.75A.75.75 0 0 1 5.75 8h11.5a.75.75 0 0 1 0 1.5H5.75A.75.75 0 0 1 5 8.75Zm0 4a.75.75 0 0 1 .75-.75h5.5a.75.75 0 0 1 0 1.5h-5.5a.75.75 0 0 1-.75-.75Z"/></svg>');
3434
--md-admonition-icon--security: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 15.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0m-.25-8.25a.75.75 0 0 0-1.5 0v4.5a.75.75 0 0 0 1.5 0z"/><path d="M11.46.637a1.75 1.75 0 0 1 1.08 0l8.25 2.675A1.75 1.75 0 0 1 22 4.976V10c0 6.19-3.77 10.705-9.401 12.83a1.7 1.7 0 0 1-1.198 0C5.771 20.704 2 16.19 2 10V4.976c0-.76.49-1.43 1.21-1.664Zm.617 1.426a.25.25 0 0 0-.154 0L3.673 4.74a.25.25 0 0 0-.173.237V10c0 5.461 3.28 9.483 8.43 11.426a.2.2 0 0 0 .14 0C17.22 19.483 20.5 15.46 20.5 10V4.976a.25.25 0 0 0-.173-.237Z"/></svg>');
35+
--md-admonition-icon--diamond: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M1.527 13.237a1.75 1.75 0 0 1 0-2.474l9.272-9.273a1.75 1.75 0 0 1 2.475 0l9.272 9.273a1.75 1.75 0 0 1 0 2.474l-9.272 9.272a1.75 1.75 0 0 1-2.475 0Zm1.06-1.414a.25.25 0 0 0 0 .354l9.273 9.272a.25.25 0 0 0 .353 0l9.272-9.272a.25.25 0 0 0 0-.354l-9.272-9.272a.25.25 0 0 0-.353 0Z"/></svg>');
3536
}
3637

3738
/* experimental */
@@ -110,6 +111,25 @@
110111
mask-image: var(--md-admonition-icon--security);
111112
}
112113

114+
/* implementation reference */
115+
.md-typeset .admonition.implementation,
116+
.md-typeset details.implementation {
117+
border-color: rgb(124, 77, 255)
118+
}
119+
120+
.md-typeset .implementation>.admonition-title,
121+
.md-typeset .implementation>summary {
122+
background-color: rgba(124, 77, 255, .1);
123+
border-color: rgb(124, 77, 255);
124+
}
125+
126+
.md-typeset .implementation>.admonition-title::before,
127+
.md-typeset .implementation>summary::before {
128+
background-color: rgb(124, 77, 255);
129+
-webkit-mask-image: var(--md-admonition-icon--diamond);
130+
mask-image: var(--md-admonition-icon--diamond);
131+
}
132+
113133
/* badges */
114134

115135
.badge {

docs/changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ What's changed since v1.47.0:
4848
- Azure Kubernetes Service:
4949
- Updated `Azure.AKS.Version` to use `1.33.7` as the minimum version by @BernieWhite.
5050
[#3708](https://github.com/Azure/PSRule.Rules.Azure/issues/3708)
51+
- Improved documentation for expansion internals with a high-level flow diagram and code references by @Copilot.
52+
[#3715](https://github.com/Azure/PSRule.Rules.Azure/issues/3715)
5153

5254
## v1.47.0
5355

docs/en/rules/module.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ Name | Synopsis | Severity | Level
641641
---- | -------- | -------- | -----
642642
[Azure.VNET.FirewallSubnet](Azure.VNET.FirewallSubnet.md) | Use Azure Firewall to filter network traffic to and from Azure resources. | Important | Error
643643

644-
### SE:01 Security baseline
644+
### SE:01 Security Baseline
645645

646646
Name | Synopsis | Severity | Level
647647
---- | -------- | -------- | -----

docs/es/rules/module.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ Name | Synopsis | Severity | Level
641641
---- | -------- | -------- | -----
642642
[Azure.VNET.FirewallSubnet](Azure.VNET.FirewallSubnet.md) | Use Azure Firewall to filter network traffic to and from Azure resources. | Important | Error
643643

644-
### SE:01 Security baseline
644+
### SE:01 Security Baseline
645645

646646
Name | Synopsis | Severity | Level
647647
---- | -------- | -------- | -----

docs/license-contributing/expansion-internals.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,46 @@ The main components of the expansion process are:
4444
- **Materialized properties** &mdash; Some resources types have properties that are affected by multiple deployments or
4545
child resources. These must be calculated to determine the final state value of the property.
4646

47+
### High-level flow
48+
49+
The following diagram shows the high-level flow of the expansion process from source file to expanded resources.
50+
51+
```mermaid
52+
flowchart TD
53+
A["Input file (.bicep / .bicepparam / .json)"] --> B{Is Bicep source?}
54+
B -->|Yes| C["Build with Bicep CLI\n(bicep build / bicep build-params)"]
55+
B -->|No| D[Read ARM template JSON]
56+
C --> D
57+
D --> E["Load parameters\n(parameter file + AZURE_PARAMETER_DEFAULTS)"]
58+
E --> F["Visit deployment\n(DeploymentVisitor)"]
59+
F --> G["Process definitions\n(parameters, variables, functions, types)"]
60+
G --> H["Build dependency graph\n(ResourceDependencyGraph)"]
61+
H --> I[Visit each resource in dependency order]
62+
I --> J{Is nested deployment?}
63+
J -->|Yes| K["Visit nested deployment recursively\n(inner / outer scope)"]
64+
J -->|No| L["Evaluate condition\nExpand copy loops"]
65+
L --> M["Resolve property expressions\n(ExpressionBuilder)"]
66+
M --> N[Emit resource to context]
67+
K --> N
68+
N --> O{More resources?}
69+
O -->|Yes| I
70+
O -->|No| P["Post-process\n(MaterializedDeploymentVisitor)\nNest children, materialize properties"]
71+
P --> Q[Output expanded resources]
72+
```
73+
74+
### Key components
75+
76+
The key source code components involved in the expansion process are:
77+
78+
Component | Source file | Description
79+
---------- | ----------- | -----------
80+
`BicepHelper` | `src/PSRule.Rules.Azure/Data/Bicep/BicepHelper.cs` | Invokes the Bicep CLI and coordinates expansion of Bicep and ARM files.
81+
`DeploymentVisitor` | `src/PSRule.Rules.Azure/Arm/Deployments/DeploymentVisitor.cs` | The core visitor that walks the ARM deployment structure.
82+
`MaterializedDeploymentVisitor` | `src/PSRule.Rules.Azure/Arm/Deployments/MaterializedDeploymentVisitor.cs` | Extends `DeploymentVisitor` to handle post-processing of emitted resources.
83+
`ResourceDependencyGraph` | `src/PSRule.Rules.Azure/Arm/Deployments/ResourceDependencyGraph.cs` | Builds and resolves the dependency graph for resources in a deployment.
84+
`ExpressionBuilder` | `src/PSRule.Rules.Azure/Arm/Expressions/ExpressionBuilder.cs` | Parses and evaluates ARM template expressions.
85+
`Functions` | `src/PSRule.Rules.Azure/Arm/Expressions/Functions.cs` | Implementations of ARM template built-in functions used during expression evaluation.
86+
4787
## Building Bicep
4888

4989
Azure Bicep code syntax is a domain specific language provides a higher level of abstraction over ARM deployments.
@@ -55,6 +95,14 @@ As a result, the Bicep CLI must be installed and available prior to running the
5595

5696
To build a Bicep file, the Bicep CLI is invoked with `bicep build` or `bicep build-params` command.
5797

98+
!!! Implementation
99+
The `BicepHelper` class (`src/PSRule.Rules.Azure/Data/Bicep/BicepHelper.cs`) is responsible for:
100+
101+
- Discovering the Bicep CLI.
102+
- Spawning the Bicep CLI process.
103+
- Calling `ProcessFile` for a `.bicep` file or `ProcessParamFile` for a `.bicepparam` file.
104+
- Passing the resulting ARM template JSON to the deployment visitor for expansion.
105+
58106
### CLI discovery
59107

60108
To find an instance of the Bicep CLI, PSRule for Azure probes several paths, and uses the first instance found.
@@ -94,6 +142,10 @@ Secrets are a good example of this, as they should not be specified in the param
94142
Definitions are the building blocks of the ARM deployment and may be reference by resources or other definitions.
95143
For most cases, definitions are lazy loaded into the context of the deployment during expansion.
96144

145+
!!! Implementation
146+
The `LazyParameter`, `LazyVariable`, and `LazyOutput` classes (in `src/PSRule.Rules.Azure/Arm/Deployments/`) implement this lazy loading pattern,
147+
deferring evaluation of each definition until it is first referenced.
148+
97149
Exceptions to this are when copy loops are used to define variables and parameters.
98150
Otherwise the definitions are not resolved until they are referenced by a resource.
99151

@@ -107,6 +159,10 @@ Similarly, a deployment may return outputs that are used in the parent deploymen
107159
As a result, each resource must be visited based on a dependency graph so that dependencies are resolved
108160
before dependant resources.
109161

162+
!!! Implementation
163+
The `ResourceDependencyGraph` class (`src/PSRule.Rules.Azure/Arm/Deployments/ResourceDependencyGraph.cs`) builds this graph
164+
from the `dependsOn` properties declared in the template, and performs a topological sort to produce the correct visit order.
165+
110166
## Visiting each resource
111167

112168
When a resource is visited:
@@ -146,6 +202,16 @@ For each function to be understood by the expansion process, it must be implemen
146202

147203
When an expression is called, context about the deployment is passed into the root function of the expression.
148204

205+
!!! Implementation
206+
The key classes for expression evaluation are:
207+
208+
- `ExpressionParser` (`src/PSRule.Rules.Azure/Arm/Expressions/ExpressionParser.cs`) &mdash;
209+
Tokenizes and parses ARM expression strings into an `ExpressionStream`.
210+
- `ExpressionBuilder` (`src/PSRule.Rules.Azure/Arm/Expressions/ExpressionBuilder.cs`) &mdash;
211+
Builds a callable expression tree from the parsed tokens.
212+
- `Functions` (`src/PSRule.Rules.Azure/Arm/Expressions/Functions.cs`) &mdash;
213+
Contains implementations of all supported ARM template built-in functions.
214+
149215
### Context properties
150216

151217
During deployment to Azure, ARM maintains several context objects that are used to evaluate expressions.

docs/license-contributing/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Please read our [contributing guidelines][2] and [code of conduct][3] to learn h
2727
- [Writing documentation](writing-documentation.md) &mdash; Guidelines for writing and improving documentation.
2828
- [Getting started with documentation](getting-started-with-documentation.md) &mdash; How to get started contributing to documentation.
2929
- [Get started contributing](get-started-contributing.md) &mdash; How to get started contributing to the project.
30+
- [Expansion internals](expansion-internals.md) &mdash; Internals of the expansion process for developers and contributors.
3031

3132
[1]: https://github.com/Azure/PSRule.Rules.Azure/blob/main/LICENSE
3233
[2]: https://github.com/Azure/PSRule.Rules.Azure/blob/main/CONTRIBUTING.md

mkdocs.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ markdown_extensions:
137137
anchor_linenums: true
138138
line_spans: __span
139139
pygments_lang_class: true
140-
- pymdownx.superfences
140+
- pymdownx.superfences:
141+
custom_fences:
142+
- name: mermaid
143+
class: mermaid
144+
format: !!python/name:pymdownx.superfences.fence_code_format
141145
- pymdownx.pathconverter
142146
- pymdownx.tabbed:
143147
alternate_style: true

0 commit comments

Comments
 (0)