microsoft/openvmm

Public

mirrored fromhttps://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2d321ee34e4dd620a030b11b532fa4d8a6f3ed73

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

Guide/src/dev_guide/dev_tools/flowey/steps.md

155lines · modecode

1# Steps
2
3**Steps** are units of work that will be executed at runtime. Different
4step types exist for different purposes.
5
6## Types of Steps
7
8### Rust Steps
9
10Rust steps execute Rust code at runtime and are the most common step type in flowey.
11
12**`emit_rust_step`**: The primary method for emitting steps that run Rust code. Steps can claim variables, read inputs, perform work, and write outputs. Returns an optional `ReadVar<SideEffect>` that other steps can use as a dependency.
13
14**`emit_minor_rust_step`**: Similar to `emit_rust_step` but for steps that cannot fail (no `Result` return) and don't need visibility in CI logs. Used for simple transformations and glue logic. Using minor steps also improve performance, since there is a slight cost to starting and ending a 'step' in GitHub and ADO. During the build stage, minor steps that are adjacent to each other will get merged into one giant CI step.
15
16**`emit_rust_stepv`**: Convenience method that combines creating a new variable and emitting a step in one call. The step's return value is automatically written to the new variable.
17
18For detailed examples of Rust steps, see the [`NodeCtx` emit methods documentation](https://openvmm.dev/rustdoc/linux/flowey/node/prelude/struct.NodeCtx.html).
19
20### ADO Steps
21
22**`emit_ado_step`**: Emits a step that generates Azure DevOps Pipeline YAML. Takes a closure that returns a YAML string snippet which is interpolated into the generated pipeline.
23
24For ADO step examples, see the [`NodeCtx::emit_ado_step` documentation](https://openvmm.dev/rustdoc/linux/flowey_core/node/struct.NodeCtx.html#method.emit_ado_step).
25
26### GitHub Steps
27
28**`emit_gh_step`**: Creates a GitHub Actions step using the fluent `GhStepBuilder` API. Supports specifying the action, parameters, outputs, dependencies, and permissions. Returns a builder that must be finalized with `.finish(ctx)`.
29
30For GitHub step examples, see the [`GhStepBuilder` documentation](https://openvmm.dev/rustdoc/linux/flowey_core/node/steps/github/struct.GhStepBuilder.html).
31
32### Side Effect Steps
33
34**`emit_side_effect_step`**: Creates a dependency relationship without executing code. Useful for aggregating multiple side effect dependencies into a single side effect. More efficient than emitting an empty Rust step.
35
36For side effect step examples, see the [`NodeCtx::emit_side_effect_step` documentation](https://openvmm.dev/rustdoc/linux/flowey_core/node/struct.NodeCtx.html#method.emit_side_effect_step).
37
38### Isolated Working Directories and Path Immutability
39
40```admonish warning title="Critical Constraint"
41**Each step gets its own fresh local working directory.** This avoids the "single global working directory dumping ground" common in bash + YAML systems.
42
43However, while flowey variables enforce sharing XOR mutability at the type-system level, **developers must manually enforce this at the filesystem level**:
44
45**Steps must NEVER modify the contents of paths referenced by `ReadVar<PathBuf>`.**
46```
47
48When you write a path to `WriteVar<PathBuf>`, you're creating an immutable contract. Other steps reading that path must treat it as read-only. If you need to modify files from a `ReadVar<PathBuf>`, copy them to your step's working directory.
49
50## Runtime Services
51
52Runtime services provide the API available during step execution (inside the
53closures passed to `emit_rust_step`, etc.).
54
55### RustRuntimeServices
56
57[`RustRuntimeServices`](https://openvmm.dev/rustdoc/linux/flowey_core/node/steps/rust/struct.RustRuntimeServices.html) is the primary runtime service available in Rust steps. It provides:
58
59#### Variable Operations
60
61- Reading and writing flowey variables
62- Secret handling (automatic secret propagation for safety)
63- Support for reading values of any type that implements [`ReadVarValue`](https://openvmm.dev/rustdoc/linux/flowey_core/node/trait.ReadVarValue.html)
64
65#### Environment Queries
66
67- Backend identification (Local, ADO, or GitHub)
68- Platform detection (Windows, Linux, macOS)
69- Architecture information (x86_64, Aarch64)
70
71### AdoStepServices
72
73[`AdoStepServices`](https://openvmm.dev/rustdoc/linux/flowey_core/node/steps/ado/struct.AdoStepServices.html) provides integration with Azure DevOps-specific features when emitting ADO YAML steps:
74
75**ADO Variable Bridge:**
76
77- Convert ADO runtime variables (like `BUILD.SOURCEBRANCH`) into flowey vars
78- Convert flowey vars back into ADO variables for use in YAML
79- Handle secret variables appropriately
80
81**Repository Resources:**
82
83- Resolve repository IDs declared as pipeline resources
84- Access repository information in ADO-specific steps
85
86### GhStepBuilder
87
88[`GhStepBuilder`](https://openvmm.dev/rustdoc/linux/flowey_core/node/steps/github/struct.GhStepBuilder.html) is a fluent builder for constructing GitHub Actions steps with:
89
90**Step Configuration:**
91
92- Specifying the action to use (e.g., `actions/checkout@v4`)
93- Adding input parameters via `.with()`
94- Capturing step outputs into flowey variables
95- Setting conditional execution based on variables
96
97**Dependency Management:**
98
99- Declaring side-effect dependencies via `.run_after()`
100- Ensuring steps run in the correct order
101
102**Permissions:**
103
104- Declaring required GITHUB_TOKEN permissions
105- Automatic permission aggregation at the job level
106
107## Secret Variables and CI Backend Integration
108
109Flowey provides built-in support for handling sensitive data like API keys, tokens, and credentials through **secret variables**. Secret variables are treated specially to prevent accidental exposure in logs and CI outputs.
110
111### How Secret Handling Works
112
113When a variable is marked as secret, flowey ensures:
114
115- The value is not logged or printed in step output
116- CI backends (ADO, GitHub Actions) are instructed to mask the value in their logs
117- Secret status is automatically propagated to prevent leaks
118
119### Automatic Secret Propagation
120
121To prevent accidental leaks, flowey uses conservative automatic secret propagation:
122
123```admonish warning
124If a step reads a secret value, **all subsequent writes from that step are automatically marked as secret** by default. This prevents accidentally leaking secrets through derived values.
125```
126
127For example:
128
129```rust,ignore
130ctx.emit_rust_step("process token", |ctx| {
131 let secret_token = secret_token.claim(ctx);
132 let output_var = output_var.claim(ctx);
133 |rt| {
134 let token = rt.read(secret_token); // Reading a secret
135
136 // This write is AUTOMATICALLY marked as secret
137 // (even though we're just writing "done")
138 rt.write(output_var, &"done".to_string());
139
140 Ok(())
141 }
142});
143```
144
145If you need to write non-secret data after reading a secret, use `write_not_secret()`:
146
147```rust,ignore
148rt.write_not_secret(output_var, &"done".to_string());
149```
150
151### Best Practices for Secrets
152
1531. **Never use `ReadVar::from_static()` for secrets** - static values are encoded in plain text in the generated YAML
1542. **Always use `write_secret()`** when writing sensitive data like tokens, passwords, or keys
1553. **Minimize secret lifetime** - read secrets as late as possible and don't pass them through more variables than necessary
156