From 44cab92a30eeb5e87ed69065d8c07c53b46b0e4c Mon Sep 17 00:00:00 2001 From: "Stanislav Andras (from Dev Box)" Date: Fri, 4 Sep 2026 10:30:10 +0200 Subject: [PATCH 1/3] fix(cargo-anvil): remove Bash from ADO steps (#160) Use PowerShell for generated setup, impact, and group steps so Windows ADO agents do not require Git Bash. Preserve impact selection through the step environment and add a regression guard over emitted ADO artifacts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ad83c731-5326-43e7-84fe-3aef46ef031f --- crates/cargo-anvil/docs/design/ado.md | 19 ++- crates/cargo-anvil/src/anvil/artifacts/ado.rs | 23 ++- .../cargo-anvil/templates/ado/steps/group.yml | 14 +- .../templates/ado/steps/impact.yml | 4 +- .../cargo-anvil/templates/ado/steps/setup.yml | 6 +- .../snapshots/snapshots__ado_backend.snap | 138 ++++++++---------- 6 files changed, 99 insertions(+), 105 deletions(-) diff --git a/crates/cargo-anvil/docs/design/ado.md b/crates/cargo-anvil/docs/design/ado.md index 6f6cf56d9..c31d6c32f 100644 --- a/crates/cargo-anvil/docs/design/ado.md +++ b/crates/cargo-anvil/docs/design/ado.md @@ -609,13 +609,13 @@ threading pre-formatted strings the local run never produces. The chain: by a 1ESPT `job.yml`). 3. **The group step template** runs `just anvil-` with an impact mode fixed **by group class at emit time** (never probed from a file). PR groups — which always download the - artifact — export `ANVIL_IMPACT=consume`. In consume mode `anvil-impact` is a pure + artifact — set `ANVIL_IMPACT=consume` in the step environment. In consume mode `anvil-impact` is a pure no-op — it trusts the downloaded cache verbatim and **neither snapshots nor recomputes**, so it needs neither cargo-delta nor a fetched base ref. Each scoped check reads its category's scope from the cache file via `_anvil-impact-include` (into a local `$include` variable). 4. **Scheduled stages download nothing** and always validate the full workspace, so the - group step exports `ANVIL_IMPACT=off`. Like the PR `consume`, this is fixed by group + group step sets `ANVIL_IMPACT=off` in the step environment. Like the PR `consume`, this is fixed by group class at emit time and is **not** derived from `target/anvil/impact/impact.state`: the mode is a property of the group class, not something probed at runtime. (`setup.yml` no longer caches `target/` at all, so the durable `impact.state` never travels through the @@ -681,15 +681,16 @@ steps: catch { Write-Error "Could not resolve PR title for PR $prId"; exit 1 } env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) -- script: just anvil-pr-fast +- pwsh: just anvil-pr-fast displayName: anvil pr-fast env: PR_TITLE: $(PR_TITLE) # Scope comes from the downloaded target/anvil/impact cache: a PR group - # always downloads the artifact, so it exports ANVIL_IMPACT=consume (trust + # always downloads the artifact, so it sets ANVIL_IMPACT=consume (trust # the cache; no snapshot/cargo-delta/base ref), whereas a scheduled group - # exports ANVIL_IMPACT=off. The mode is fixed by group class at emit time -- never + # sets ANVIL_IMPACT=off. The mode is fixed by group class at emit time -- never # probed from the cacheable impact.state marker. See §4.3. + ANVIL_IMPACT: "consume" ``` The generated per-group step templates take no parameters. Only `pr-fast.yml` @@ -734,8 +735,10 @@ takes a single `group` parameter that controls which recipes run: `pr-fast` matrix leg never installs cargo-mutants. The template expects the caller to provide the Rust/rustup bootstrap and -`cargo` on PATH (see §6). ADO uses the default `install` backend (source -builds) so adopters do not need to approve a binary-installation service. +`cargo` on PATH (see §6). Command steps use `pwsh`, which is already required +by the template's toolchain fingerprinting step, so Windows agents do not need +Bash. ADO uses the default `install` backend (source builds) so adopters do not +need to approve a binary-installation service. `impact.yml` invokes `setup.yml` with `group: none`, then installs `cargo-delta` via `anvil-tool-cargo-delta-install` and runs the shared **`just anvil-impact`** @@ -900,7 +903,7 @@ files into upserts/deletions of a sticky PR comment via the Azure DevOps REST AP path is the supported way). The wiring lives in the `pr_fast` stage of `pr-stages.yml`, as a pwsh step that runs -on the canonical Linux leg after the `pr-fast` group's `bash: just anvil-pr-fast` +on the canonical Linux leg after the `pr-fast` group's `pwsh: just anvil-pr-fast` step: ```yaml diff --git a/crates/cargo-anvil/src/anvil/artifacts/ado.rs b/crates/cargo-anvil/src/anvil/artifacts/ado.rs index f1d16684e..cecd433c2 100644 --- a/crates/cargo-anvil/src/anvil/artifacts/ado.rs +++ b/crates/cargo-anvil/src/anvil/artifacts/ado.rs @@ -257,13 +257,13 @@ mod tests { #[test] fn setup_step_quotes_inline_command_values_containing_colons() { - // An inline `- bash: echo "x: y"` is a YAML *plain scalar*; the inner + // An inline `- pwsh: Write-Host "x: y"` is a YAML *plain scalar*; the inner // `: ` is parsed as a mapping separator ("Mapping values are not // allowed in this context"), which ADO rejects at compile time. Such // values must be wrapped in quotes. Guard every inline command scalar // in the setup step (and catch the specific group=none echo). assert!( - SETUP_STEP.contains(r#"- bash: 'echo "anvil-setup: group=none, skipping tool install"'"#), + SETUP_STEP.contains(r#"- pwsh: 'Write-Host "anvil-setup: group=none, skipping tool install"'"#), "the group=none echo must be single-quoted so its colon stays literal", ); for line in SETUP_STEP.lines() { @@ -289,6 +289,17 @@ mod tests { } } + #[test] + fn ado_artifacts_do_not_require_bash() { + for artifact in all() { + let has_bash_step = artifact.body().lines().any(|line| { + let line = line.trim_start(); + line.starts_with("- bash:") || line.starts_with("- task: Bash@") + }); + assert!(!has_bash_step, "ADO artifact contains a Bash step:\n{}", artifact.body()); + } + } + #[test] fn group_step_passes_group_to_setup() { let body = render_group_step("pr-fast"); @@ -385,9 +396,9 @@ mod tests { ); // A PR group always downloads the artifact, so it consumes it. The mode // is fixed by tier -- not probed at runtime from a marker file. - assert!(body.contains("export ANVIL_IMPACT=consume")); + assert!(body.contains(r#"ANVIL_IMPACT: "consume""#)); assert!( - !body.contains("ANVIL_IMPACT=off"), + !body.contains(r#"ANVIL_IMPACT: "off""#), "a PR group must not fall back to off (it always has the artifact)" ); assert!( @@ -417,9 +428,9 @@ mod tests { // target/anvil/impact/impact.state, so no leftover state on the agent // can wrongly enable scoping and skip the full-workspace backstop. let body = render_group_step("scheduled-test"); - assert!(body.contains("export ANVIL_IMPACT=off")); + assert!(body.contains(r#"ANVIL_IMPACT: "off""#)); assert!( - !body.contains("ANVIL_IMPACT=consume"), + !body.contains(r#"ANVIL_IMPACT: "consume""#), "scheduled group must never consume the impact cache" ); assert!( diff --git a/crates/cargo-anvil/templates/ado/steps/group.yml b/crates/cargo-anvil/templates/ado/steps/group.yml index 335afcfc6..bec5d4cb3 100644 --- a/crates/cargo-anvil/templates/ado/steps/group.yml +++ b/crates/cargo-anvil/templates/ado/steps/group.yml @@ -11,24 +11,22 @@ # target/anvil/impact/ (via job.yml's inputArtifacts) and the scoped checks # read that cache via their `anvil-impact` dependency -- the same code path as # a local run. Scheduled group jobs download nothing and run full-workspace -# (see the bash step). +# (see the group step). steps: - template: setup.yml parameters: group: __GROUP__ __PR_TITLE_STEP__ - - bash: | - set -euo pipefail + - pwsh: just anvil-__GROUP__ + displayName: anvil-__GROUP__ + env: +__PR_TITLE_ENV__ # The impact mode is fixed by group class at emit time -- never probed from a # marker file. PR group jobs downloaded the target/anvil/impact artifact # and trust it verbatim (consume: anvil-impact no-ops -- no snapshot, # cargo-delta, or base ref); scheduled group jobs force off so every # tier runs full-workspace. - export ANVIL_IMPACT=__IMPACT_MODE__ - just anvil-__GROUP__ - displayName: anvil-__GROUP__ - env: -__PR_TITLE_ENV__ + ANVIL_IMPACT: "__IMPACT_MODE__" # Disable cargo incremental compilation in CI: the incremental dir is # not part of the anvil-setup cache (see setup.yml), so generating it is # pure cost with no cross-run benefit. Mirrors the GitHub impl workflows' diff --git a/crates/cargo-anvil/templates/ado/steps/impact.yml b/crates/cargo-anvil/templates/ado/steps/impact.yml index 87083afc0..4e970ebae 100644 --- a/crates/cargo-anvil/templates/ado/steps/impact.yml +++ b/crates/cargo-anvil/templates/ado/steps/impact.yml @@ -17,9 +17,9 @@ steps: - template: setup.yml parameters: group: none - - bash: just anvil-tool-cargo-delta-install install + - pwsh: just anvil-tool-cargo-delta-install install displayName: anvil impact (install cargo-delta) - - bash: just anvil-impact + - pwsh: just anvil-impact # Run the shared anvil-impact recipe -- the same impact building block # adopters run locally. It resolves the base ref (_anvil-base-ref), # snapshots the base ref in a throwaway worktree and the working diff --git a/crates/cargo-anvil/templates/ado/steps/setup.yml b/crates/cargo-anvil/templates/ado/steps/setup.yml index 76c09809b..a01466714 100644 --- a/crates/cargo-anvil/templates/ado/steps/setup.yml +++ b/crates/cargo-anvil/templates/ado/steps/setup.yml @@ -79,11 +79,11 @@ steps: # group="none" -> skip; caller installs what it needs # group= -> only that group's prerequisites - ${{ if eq(parameters.group, 'none') }}: - - bash: 'echo "anvil-setup: group=none, skipping tool install"' + - pwsh: 'Write-Host "anvil-setup: group=none, skipping tool install"' displayName: anvil setup (group=none -- skip tool install) - ${{ elseif eq(parameters.group, '') }}: - - bash: just anvil-setup + - pwsh: just anvil-setup displayName: anvil setup (install full catalog) - ${{ else }}: - - bash: just anvil-${{ parameters.group }}-setup + - pwsh: just anvil-${{ parameters.group }}-setup displayName: anvil setup (install ${{ parameters.group }} prerequisites) diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap index 3b45a1055..0bd9087e2 100644 --- a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap +++ b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap @@ -995,9 +995,9 @@ steps: - template: setup.yml parameters: group: none - - bash: just anvil-tool-cargo-delta-install install + - pwsh: just anvil-tool-cargo-delta-install install displayName: anvil impact (install cargo-delta) - - bash: just anvil-impact + - pwsh: just anvil-impact # Run the shared anvil-impact recipe -- the same impact building block # adopters run locally. It resolves the base ref (_anvil-base-ref), # snapshots the base ref in a throwaway worktree and the working @@ -1127,7 +1127,7 @@ jobs: # target/anvil/impact/ (via job.yml's inputArtifacts) and the scoped checks # read that cache via their `anvil-impact` dependency -- the same code path as # a local run. Scheduled group jobs download nothing and run full-workspace -# (see the bash step). +# (see the group step). steps: - template: setup.yml parameters: @@ -1156,19 +1156,17 @@ steps: displayName: anvil-pr-fast (resolve PR title) env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) - - bash: | - set -euo pipefail + - pwsh: just anvil-pr-fast + displayName: anvil-pr-fast + env: + # Resolved by the preceding pr-fast step; empty only outside PR builds. + PR_TITLE: $(PR_TITLE) # The impact mode is fixed by group class at emit time -- never probed from a # marker file. PR group jobs downloaded the target/anvil/impact artifact # and trust it verbatim (consume: anvil-impact no-ops -- no snapshot, # cargo-delta, or base ref); scheduled group jobs force off so every # tier runs full-workspace. - export ANVIL_IMPACT=consume - just anvil-pr-fast - displayName: anvil-pr-fast - env: - # Resolved by the preceding pr-fast step; empty only outside PR builds. - PR_TITLE: $(PR_TITLE) + ANVIL_IMPACT: "consume" # Disable cargo incremental compilation in CI: the incremental dir is # not part of the anvil-setup cache (see setup.yml), so generating it is # pure cost with no cross-run benefit. Mirrors the GitHub impl workflows' @@ -1189,24 +1187,22 @@ steps: # target/anvil/impact/ (via job.yml's inputArtifacts) and the scoped checks # read that cache via their `anvil-impact` dependency -- the same code path as # a local run. Scheduled group jobs download nothing and run full-workspace -# (see the bash step). +# (see the group step). steps: - template: setup.yml parameters: group: pr-msrv - - bash: | - set -euo pipefail + - pwsh: just anvil-pr-msrv + displayName: anvil-pr-msrv + env: + # The impact mode is fixed by group class at emit time -- never probed from a # marker file. PR group jobs downloaded the target/anvil/impact artifact # and trust it verbatim (consume: anvil-impact no-ops -- no snapshot, # cargo-delta, or base ref); scheduled group jobs force off so every # tier runs full-workspace. - export ANVIL_IMPACT=consume - just anvil-pr-msrv - displayName: anvil-pr-msrv - env: - + ANVIL_IMPACT: "consume" # Disable cargo incremental compilation in CI: the incremental dir is # not part of the anvil-setup cache (see setup.yml), so generating it is # pure cost with no cross-run benefit. Mirrors the GitHub impl workflows' @@ -1227,24 +1223,22 @@ steps: # target/anvil/impact/ (via job.yml's inputArtifacts) and the scoped checks # read that cache via their `anvil-impact` dependency -- the same code path as # a local run. Scheduled group jobs download nothing and run full-workspace -# (see the bash step). +# (see the group step). steps: - template: setup.yml parameters: group: pr-mutants - - bash: | - set -euo pipefail + - pwsh: just anvil-pr-mutants + displayName: anvil-pr-mutants + env: + # The impact mode is fixed by group class at emit time -- never probed from a # marker file. PR group jobs downloaded the target/anvil/impact artifact # and trust it verbatim (consume: anvil-impact no-ops -- no snapshot, # cargo-delta, or base ref); scheduled group jobs force off so every # tier runs full-workspace. - export ANVIL_IMPACT=consume - just anvil-pr-mutants - displayName: anvil-pr-mutants - env: - + ANVIL_IMPACT: "consume" # Disable cargo incremental compilation in CI: the incremental dir is # not part of the anvil-setup cache (see setup.yml), so generating it is # pure cost with no cross-run benefit. Mirrors the GitHub impl workflows' @@ -1265,24 +1259,22 @@ steps: # target/anvil/impact/ (via job.yml's inputArtifacts) and the scoped checks # read that cache via their `anvil-impact` dependency -- the same code path as # a local run. Scheduled group jobs download nothing and run full-workspace -# (see the bash step). +# (see the group step). steps: - template: setup.yml parameters: group: pr-runtime-analysis - - bash: | - set -euo pipefail + - pwsh: just anvil-pr-runtime-analysis + displayName: anvil-pr-runtime-analysis + env: + # The impact mode is fixed by group class at emit time -- never probed from a # marker file. PR group jobs downloaded the target/anvil/impact artifact # and trust it verbatim (consume: anvil-impact no-ops -- no snapshot, # cargo-delta, or base ref); scheduled group jobs force off so every # tier runs full-workspace. - export ANVIL_IMPACT=consume - just anvil-pr-runtime-analysis - displayName: anvil-pr-runtime-analysis - env: - + ANVIL_IMPACT: "consume" # Disable cargo incremental compilation in CI: the incremental dir is # not part of the anvil-setup cache (see setup.yml), so generating it is # pure cost with no cross-run benefit. Mirrors the GitHub impl workflows' @@ -1303,24 +1295,22 @@ steps: # target/anvil/impact/ (via job.yml's inputArtifacts) and the scoped checks # read that cache via their `anvil-impact` dependency -- the same code path as # a local run. Scheduled group jobs download nothing and run full-workspace -# (see the bash step). +# (see the group step). steps: - template: setup.yml parameters: group: pr-test - - bash: | - set -euo pipefail + - pwsh: just anvil-pr-test + displayName: anvil-pr-test + env: + # The impact mode is fixed by group class at emit time -- never probed from a # marker file. PR group jobs downloaded the target/anvil/impact artifact # and trust it verbatim (consume: anvil-impact no-ops -- no snapshot, # cargo-delta, or base ref); scheduled group jobs force off so every # tier runs full-workspace. - export ANVIL_IMPACT=consume - just anvil-pr-test - displayName: anvil-pr-test - env: - + ANVIL_IMPACT: "consume" # Disable cargo incremental compilation in CI: the incremental dir is # not part of the anvil-setup cache (see setup.yml), so generating it is # pure cost with no cross-run benefit. Mirrors the GitHub impl workflows' @@ -1341,24 +1331,22 @@ steps: # target/anvil/impact/ (via job.yml's inputArtifacts) and the scoped checks # read that cache via their `anvil-impact` dependency -- the same code path as # a local run. Scheduled group jobs download nothing and run full-workspace -# (see the bash step). +# (see the group step). steps: - template: setup.yml parameters: group: scheduled-advisories - - bash: | - set -euo pipefail + - pwsh: just anvil-scheduled-advisories + displayName: anvil-scheduled-advisories + env: + # The impact mode is fixed by group class at emit time -- never probed from a # marker file. PR group jobs downloaded the target/anvil/impact artifact # and trust it verbatim (consume: anvil-impact no-ops -- no snapshot, # cargo-delta, or base ref); scheduled group jobs force off so every # tier runs full-workspace. - export ANVIL_IMPACT=off - just anvil-scheduled-advisories - displayName: anvil-scheduled-advisories - env: - + ANVIL_IMPACT: "off" # Disable cargo incremental compilation in CI: the incremental dir is # not part of the anvil-setup cache (see setup.yml), so generating it is # pure cost with no cross-run benefit. Mirrors the GitHub impl workflows' @@ -1379,24 +1367,22 @@ steps: # target/anvil/impact/ (via job.yml's inputArtifacts) and the scoped checks # read that cache via their `anvil-impact` dependency -- the same code path as # a local run. Scheduled group jobs download nothing and run full-workspace -# (see the bash step). +# (see the group step). steps: - template: setup.yml parameters: group: scheduled-exhaustive - - bash: | - set -euo pipefail + - pwsh: just anvil-scheduled-exhaustive + displayName: anvil-scheduled-exhaustive + env: + # The impact mode is fixed by group class at emit time -- never probed from a # marker file. PR group jobs downloaded the target/anvil/impact artifact # and trust it verbatim (consume: anvil-impact no-ops -- no snapshot, # cargo-delta, or base ref); scheduled group jobs force off so every # tier runs full-workspace. - export ANVIL_IMPACT=off - just anvil-scheduled-exhaustive - displayName: anvil-scheduled-exhaustive - env: - + ANVIL_IMPACT: "off" # Disable cargo incremental compilation in CI: the incremental dir is # not part of the anvil-setup cache (see setup.yml), so generating it is # pure cost with no cross-run benefit. Mirrors the GitHub impl workflows' @@ -1417,24 +1403,22 @@ steps: # target/anvil/impact/ (via job.yml's inputArtifacts) and the scoped checks # read that cache via their `anvil-impact` dependency -- the same code path as # a local run. Scheduled group jobs download nothing and run full-workspace -# (see the bash step). +# (see the group step). steps: - template: setup.yml parameters: group: scheduled-runtime-analysis - - bash: | - set -euo pipefail + - pwsh: just anvil-scheduled-runtime-analysis + displayName: anvil-scheduled-runtime-analysis + env: + # The impact mode is fixed by group class at emit time -- never probed from a # marker file. PR group jobs downloaded the target/anvil/impact artifact # and trust it verbatim (consume: anvil-impact no-ops -- no snapshot, # cargo-delta, or base ref); scheduled group jobs force off so every # tier runs full-workspace. - export ANVIL_IMPACT=off - just anvil-scheduled-runtime-analysis - displayName: anvil-scheduled-runtime-analysis - env: - + ANVIL_IMPACT: "off" # Disable cargo incremental compilation in CI: the incremental dir is # not part of the anvil-setup cache (see setup.yml), so generating it is # pure cost with no cross-run benefit. Mirrors the GitHub impl workflows' @@ -1455,24 +1439,22 @@ steps: # target/anvil/impact/ (via job.yml's inputArtifacts) and the scoped checks # read that cache via their `anvil-impact` dependency -- the same code path as # a local run. Scheduled group jobs download nothing and run full-workspace -# (see the bash step). +# (see the group step). steps: - template: setup.yml parameters: group: scheduled-test - - bash: | - set -euo pipefail + - pwsh: just anvil-scheduled-test + displayName: anvil-scheduled-test + env: + # The impact mode is fixed by group class at emit time -- never probed from a # marker file. PR group jobs downloaded the target/anvil/impact artifact # and trust it verbatim (consume: anvil-impact no-ops -- no snapshot, # cargo-delta, or base ref); scheduled group jobs force off so every # tier runs full-workspace. - export ANVIL_IMPACT=off - just anvil-scheduled-test - displayName: anvil-scheduled-test - env: - + ANVIL_IMPACT: "off" # Disable cargo incremental compilation in CI: the incremental dir is # not part of the anvil-setup cache (see setup.yml), so generating it is # pure cost with no cross-run benefit. Mirrors the GitHub impl workflows' @@ -1561,13 +1543,13 @@ steps: # group="none" -> skip; caller installs what it needs # group= -> only that group's prerequisites - ${{ if eq(parameters.group, 'none') }}: - - bash: 'echo "anvil-setup: group=none, skipping tool install"' + - pwsh: 'Write-Host "anvil-setup: group=none, skipping tool install"' displayName: anvil setup (group=none -- skip tool install) - ${{ elseif eq(parameters.group, '') }}: - - bash: just anvil-setup + - pwsh: just anvil-setup displayName: anvil setup (install full catalog) - ${{ else }}: - - bash: just anvil-${{ parameters.group }}-setup + - pwsh: just anvil-${{ parameters.group }}-setup displayName: anvil setup (install ${{ parameters.group }} prerequisites) === .pipelines/anvil-pr.yml === From 5892319a17f10f13055eb2d71f91e8fcd4b0f95d Mon Sep 17 00:00:00 2001 From: "Stanislav Andras (from Dev Box)" Date: Fri, 4 Sep 2026 16:20:01 +0200 Subject: [PATCH 2/3] docs(anvil): clarify impact environment wording Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ad83c731-5326-43e7-84fe-3aef46ef031f --- crates/cargo-anvil/docs/design/ado.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/cargo-anvil/docs/design/ado.md b/crates/cargo-anvil/docs/design/ado.md index c31d6c32f..f4c4f65a2 100644 --- a/crates/cargo-anvil/docs/design/ado.md +++ b/crates/cargo-anvil/docs/design/ado.md @@ -686,9 +686,9 @@ steps: env: PR_TITLE: $(PR_TITLE) # Scope comes from the downloaded target/anvil/impact cache: a PR group - # always downloads the artifact, so it sets ANVIL_IMPACT=consume (trust + # always downloads the artifact, so it sets ANVIL_IMPACT to consume (trust # the cache; no snapshot/cargo-delta/base ref), whereas a scheduled group - # sets ANVIL_IMPACT=off. The mode is fixed by group class at emit time -- never + # sets ANVIL_IMPACT to off. The mode is fixed by group class at emit time -- never # probed from the cacheable impact.state marker. See §4.3. ANVIL_IMPACT: "consume" ``` From 2e4841f7f3448e35de8049195a5bbd8ba07d8236 Mon Sep 17 00:00:00 2001 From: "Stanislav Andras (from Dev Box)" Date: Fri, 4 Sep 2026 19:19:18 +0200 Subject: [PATCH 3/3] chore(anvil): refresh catalog checksum Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ad83c731-5326-43e7-84fe-3aef46ef031f --- .anvil.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.anvil.lock b/.anvil.lock index c6b3d4200..9aefb5312 100644 --- a/.anvil.lock +++ b/.anvil.lock @@ -1,7 +1,7 @@ version = 1 tool = "anvil" tool_version = "0.8.0" -catalog_checksum = "sha256:340049d773da5264378aca52285405950b2a317fdf2ca2302e8650b591354e8c" +catalog_checksum = "sha256:c62ab972b9e416813d2f56764e4b7a2fa72850dc9653fbd53feeb6f6970644f4" [[file]] path = ".anvil/container/Dockerfile.dockerignore"