From c4e0b338ba61546a5136f91e5f26234dabcff7bc Mon Sep 17 00:00:00 2001 From: Daniel McIlvaney Date: Fri, 29 May 2026 15:33:49 -0700 Subject: [PATCH 1/4] chore: enable dependabot cofig --- .github/dependabot.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..3c69c1a0cd6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,31 @@ +version: 2 + +updates: + # Python tooling dependencies — keep pip-installed scripts patched. + # `directories` (plural) supports globbing, so new requirements.txt files + # under these paths are picked up automatically without editing this file. + # `directory` (singular) does NOT support globbing. + - package-ecosystem: pip + directories: + - /.github/workflows/scripts/* + - /scripts/* + schedule: + interval: weekly + open-pull-requests-limit: 5 + labels: + - dependencies + - python + + # GitHub Actions used by PR-check workflows. + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 + labels: + - dependencies + - github-actions + groups: + actions: + patterns: + - "*" From 146d6f84aca6223df824ba012448df81eb9dcb43 Mon Sep 17 00:00:00 2001 From: Daniel McIlvaney Date: Fri, 29 May 2026 18:07:24 -0700 Subject: [PATCH 2/4] refactor(ci): move pipeline helper scripts to scripts/ci/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dependabot's pip updater cannot open PRs that modify any file under .github/ (only the github-actions ecosystem is granted that scope), so requirements.txt under .github/workflows/scripts/ could never be auto-updated. Relocate the helper-scripts subtree to top-level scripts/ci/ — linted (ruff/pyright scan scripts/) and writable by Dependabot. Pure rename; reference updates follow. --- {.github/workflows/scripts => scripts/ci}/components/README.md | 0 .../scripts => scripts/ci}/components/compute_change_set.sh | 0 .../scripts => scripts/ci}/components/compute_changed.sh | 0 .../scripts => scripts/ci}/components/compute_render_set.py | 0 {.github/workflows/scripts => scripts/ci}/control-tower/client.py | 0 .../scripts => scripts/ci}/control-tower/requirements.txt | 0 .../scripts => scripts/ci}/control-tower/run_package_build.py | 0 .../workflows/scripts => scripts/ci}/control-tower/run_prcheck.py | 0 .../scripts => scripts/ci}/control-tower/verify_locks.sh | 0 .../scripts => scripts/ci}/locks-check/post_locks_comment.py | 0 .../ci}/render-specs-check/check_rendered_specs.py | 0 .../ci}/render-specs-check/post_render_comment.py | 0 {.github/workflows/scripts => scripts/ci}/spec-review/README.md | 0 {.github/workflows/scripts => scripts/ci}/spec-review/_common.py | 0 .../ci}/spec-review/create_check_annotations.py | 0 .../scripts => scripts/ci}/spec-review/format_pr_comment.py | 0 .../workflows/scripts => scripts/ci}/spec-review/requirements.txt | 0 .../workflows/scripts => scripts/ci}/spec-review/spec_review.sh | 0 .../scripts => scripts/ci}/spec-review/spec_review_multi.sh | 0 .../scripts => scripts/ci}/spec-review/spec_review_schema.py | 0 20 files changed, 0 insertions(+), 0 deletions(-) rename {.github/workflows/scripts => scripts/ci}/components/README.md (100%) rename {.github/workflows/scripts => scripts/ci}/components/compute_change_set.sh (100%) rename {.github/workflows/scripts => scripts/ci}/components/compute_changed.sh (100%) rename {.github/workflows/scripts => scripts/ci}/components/compute_render_set.py (100%) rename {.github/workflows/scripts => scripts/ci}/control-tower/client.py (100%) rename {.github/workflows/scripts => scripts/ci}/control-tower/requirements.txt (100%) rename {.github/workflows/scripts => scripts/ci}/control-tower/run_package_build.py (100%) rename {.github/workflows/scripts => scripts/ci}/control-tower/run_prcheck.py (100%) rename {.github/workflows/scripts => scripts/ci}/control-tower/verify_locks.sh (100%) rename {.github/workflows/scripts => scripts/ci}/locks-check/post_locks_comment.py (100%) rename {.github/workflows/scripts => scripts/ci}/render-specs-check/check_rendered_specs.py (100%) rename {.github/workflows/scripts => scripts/ci}/render-specs-check/post_render_comment.py (100%) rename {.github/workflows/scripts => scripts/ci}/spec-review/README.md (100%) rename {.github/workflows/scripts => scripts/ci}/spec-review/_common.py (100%) rename {.github/workflows/scripts => scripts/ci}/spec-review/create_check_annotations.py (100%) rename {.github/workflows/scripts => scripts/ci}/spec-review/format_pr_comment.py (100%) rename {.github/workflows/scripts => scripts/ci}/spec-review/requirements.txt (100%) rename {.github/workflows/scripts => scripts/ci}/spec-review/spec_review.sh (100%) rename {.github/workflows/scripts => scripts/ci}/spec-review/spec_review_multi.sh (100%) rename {.github/workflows/scripts => scripts/ci}/spec-review/spec_review_schema.py (100%) diff --git a/.github/workflows/scripts/components/README.md b/scripts/ci/components/README.md similarity index 100% rename from .github/workflows/scripts/components/README.md rename to scripts/ci/components/README.md diff --git a/.github/workflows/scripts/components/compute_change_set.sh b/scripts/ci/components/compute_change_set.sh similarity index 100% rename from .github/workflows/scripts/components/compute_change_set.sh rename to scripts/ci/components/compute_change_set.sh diff --git a/.github/workflows/scripts/components/compute_changed.sh b/scripts/ci/components/compute_changed.sh similarity index 100% rename from .github/workflows/scripts/components/compute_changed.sh rename to scripts/ci/components/compute_changed.sh diff --git a/.github/workflows/scripts/components/compute_render_set.py b/scripts/ci/components/compute_render_set.py similarity index 100% rename from .github/workflows/scripts/components/compute_render_set.py rename to scripts/ci/components/compute_render_set.py diff --git a/.github/workflows/scripts/control-tower/client.py b/scripts/ci/control-tower/client.py similarity index 100% rename from .github/workflows/scripts/control-tower/client.py rename to scripts/ci/control-tower/client.py diff --git a/.github/workflows/scripts/control-tower/requirements.txt b/scripts/ci/control-tower/requirements.txt similarity index 100% rename from .github/workflows/scripts/control-tower/requirements.txt rename to scripts/ci/control-tower/requirements.txt diff --git a/.github/workflows/scripts/control-tower/run_package_build.py b/scripts/ci/control-tower/run_package_build.py similarity index 100% rename from .github/workflows/scripts/control-tower/run_package_build.py rename to scripts/ci/control-tower/run_package_build.py diff --git a/.github/workflows/scripts/control-tower/run_prcheck.py b/scripts/ci/control-tower/run_prcheck.py similarity index 100% rename from .github/workflows/scripts/control-tower/run_prcheck.py rename to scripts/ci/control-tower/run_prcheck.py diff --git a/.github/workflows/scripts/control-tower/verify_locks.sh b/scripts/ci/control-tower/verify_locks.sh similarity index 100% rename from .github/workflows/scripts/control-tower/verify_locks.sh rename to scripts/ci/control-tower/verify_locks.sh diff --git a/.github/workflows/scripts/locks-check/post_locks_comment.py b/scripts/ci/locks-check/post_locks_comment.py similarity index 100% rename from .github/workflows/scripts/locks-check/post_locks_comment.py rename to scripts/ci/locks-check/post_locks_comment.py diff --git a/.github/workflows/scripts/render-specs-check/check_rendered_specs.py b/scripts/ci/render-specs-check/check_rendered_specs.py similarity index 100% rename from .github/workflows/scripts/render-specs-check/check_rendered_specs.py rename to scripts/ci/render-specs-check/check_rendered_specs.py diff --git a/.github/workflows/scripts/render-specs-check/post_render_comment.py b/scripts/ci/render-specs-check/post_render_comment.py similarity index 100% rename from .github/workflows/scripts/render-specs-check/post_render_comment.py rename to scripts/ci/render-specs-check/post_render_comment.py diff --git a/.github/workflows/scripts/spec-review/README.md b/scripts/ci/spec-review/README.md similarity index 100% rename from .github/workflows/scripts/spec-review/README.md rename to scripts/ci/spec-review/README.md diff --git a/.github/workflows/scripts/spec-review/_common.py b/scripts/ci/spec-review/_common.py similarity index 100% rename from .github/workflows/scripts/spec-review/_common.py rename to scripts/ci/spec-review/_common.py diff --git a/.github/workflows/scripts/spec-review/create_check_annotations.py b/scripts/ci/spec-review/create_check_annotations.py similarity index 100% rename from .github/workflows/scripts/spec-review/create_check_annotations.py rename to scripts/ci/spec-review/create_check_annotations.py diff --git a/.github/workflows/scripts/spec-review/format_pr_comment.py b/scripts/ci/spec-review/format_pr_comment.py similarity index 100% rename from .github/workflows/scripts/spec-review/format_pr_comment.py rename to scripts/ci/spec-review/format_pr_comment.py diff --git a/.github/workflows/scripts/spec-review/requirements.txt b/scripts/ci/spec-review/requirements.txt similarity index 100% rename from .github/workflows/scripts/spec-review/requirements.txt rename to scripts/ci/spec-review/requirements.txt diff --git a/.github/workflows/scripts/spec-review/spec_review.sh b/scripts/ci/spec-review/spec_review.sh similarity index 100% rename from .github/workflows/scripts/spec-review/spec_review.sh rename to scripts/ci/spec-review/spec_review.sh diff --git a/.github/workflows/scripts/spec-review/spec_review_multi.sh b/scripts/ci/spec-review/spec_review_multi.sh similarity index 100% rename from .github/workflows/scripts/spec-review/spec_review_multi.sh rename to scripts/ci/spec-review/spec_review_multi.sh diff --git a/.github/workflows/scripts/spec-review/spec_review_schema.py b/scripts/ci/spec-review/spec_review_schema.py similarity index 100% rename from .github/workflows/scripts/spec-review/spec_review_schema.py rename to scripts/ci/spec-review/spec_review_schema.py From 60cc2486bbfcf4c4fe43cb22c133ebf48526ec6d Mon Sep 17 00:00:00 2001 From: Daniel McIlvaney Date: Fri, 29 May 2026 18:12:26 -0700 Subject: [PATCH 3/4] refactor(ci): point references at scripts/ci/ Update all callers, dependabot.yml, and instruction docs to the new scripts/ci/ location. dependabot pip ecosystem uses a single recursive /scripts/** glob covering scripts/ci/{control-tower,spec-review} and scripts/mcps. Add cooldown (delay new releases to catch bad ones) and group all python tooling bumps into one PR. --- .github/dependabot.yml | 16 +++++++++++-- .../instructions/ado-pipeline.instructions.md | 18 +++++++------- .../pr-check-workflows.instructions.md | 2 +- .github/workflows/ado/sources-upload.yml | 4 ++-- .../ado/templates/sources-upload-stages.yml | 10 ++++---- .github/workflows/check-rendered-specs.yml | 8 +++---- .github/workflows/spec-review.disabled | 20 ++++++++-------- scripts/ci/components/README.md | 2 +- scripts/ci/spec-review/README.md | 24 +++++++++---------- scripts/ci/spec-review/format_pr_comment.py | 2 +- scripts/ci/spec-review/spec_review.sh | 2 +- scripts/ci/spec-review/spec_review_multi.sh | 2 +- 12 files changed, 61 insertions(+), 49 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3c69c1a0cd6..b0e1cfa3aef 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,14 +7,23 @@ updates: # `directory` (singular) does NOT support globbing. - package-ecosystem: pip directories: - - /.github/workflows/scripts/* - - /scripts/* + - /scripts/** schedule: interval: weekly open-pull-requests-limit: 5 labels: - dependencies - python + # Wait until a release has been public for a few days before opening a PR, + # so yanked/broken releases get caught upstream first. Majors wait longer. + cooldown: + default-days: 7 + semver-major-days: 14 + # Bundle all python tooling bumps into a single PR per run. + groups: + python: + patterns: + - "*" # GitHub Actions used by PR-check workflows. - package-ecosystem: github-actions @@ -25,6 +34,9 @@ updates: labels: - dependencies - github-actions + # github-actions cooldown only supports a flat default-days (no semver granularity). + cooldown: + default-days: 7 groups: actions: patterns: diff --git a/.github/instructions/ado-pipeline.instructions.md b/.github/instructions/ado-pipeline.instructions.md index f72bbf479a9..2c07de5c78f 100644 --- a/.github/instructions/ado-pipeline.instructions.md +++ b/.github/instructions/ado-pipeline.instructions.md @@ -1,16 +1,16 @@ --- -applyTo: ".github/workflows/ado/*.yml,.github/workflows/ado/templates/*.yml,.github/workflows/scripts/**" -description: "Authoring and maintenance rules for Azure DevOps YAML pipelines under .github/workflows/ado/ (wrappers + raw stage templates under templates/) and their helper scripts under .github/workflows/scripts/ that run as GitHub PR checks or in the merge queue. Apply when creating or modifying any pipeline in that folder, or any script invoked by one — covers the wrapper/raw split, required OneBranch templates (Official vs NonOfficial), Workload Identity Federation service connections, Control Tower audience URIs, internal-only dependency sources (Go / Python / container images), Python-over-shell scripting, and security hardening." +applyTo: ".github/workflows/ado/*.yml,.github/workflows/ado/templates/*.yml,scripts/ci/**" +description: "Authoring and maintenance rules for Azure DevOps YAML pipelines under .github/workflows/ado/ (wrappers + raw stage templates under templates/) and their helper scripts under scripts/ci/ that run as GitHub PR checks or in the merge queue. Apply when creating or modifying any pipeline in that folder, or any script invoked by one — covers the wrapper/raw split, required OneBranch templates (Official vs NonOfficial), Workload Identity Federation service connections, Control Tower audience URIs, internal-only dependency sources (Go / Python / container images), Python-over-shell scripting, and security hardening." --- # Azure DevOps Pipelines (PR check & merge queue) -These instructions cover ADO YAML pipelines under `.github/workflows/ado/` that run as GitHub PR checks or in the merge queue, plus their helper scripts under `.github/workflows/scripts/`. Follow every MUST below — they encode internal Microsoft policy plus security hardening for this repo. +These instructions cover ADO YAML pipelines under `.github/workflows/ado/` that run as GitHub PR checks or in the merge queue, plus their helper scripts under `scripts/ci/`. Follow every MUST below — they encode internal Microsoft policy plus security hardening for this repo. -Helper scripts invoked from these pipelines MUST live under `.github/workflows/scripts//`. Two layouts are supported: +Helper scripts invoked from these pipelines MUST live under `scripts/ci//`. Two layouts are supported: 1. **Per-pipeline** — `/` is a logical area or pipeline name (e.g. `control-tower/`, `render-specs-check/`). The default. -2. **Cross-pipeline shared** — `/` = `components/`. Helpers here are deliberately consumed by multiple pipelines (GitHub Actions PR gates AND the ADO Control Tower pipeline). See [`.github/workflows/scripts/components/README.md`](../workflows/scripts/components/README.md) for the caller contract. A regression in this area breaks multiple gates at once, so changes need extra care. +2. **Cross-pipeline shared** — `/` = `components/`. Helpers here are deliberately consumed by multiple pipelines (GitHub Actions PR gates AND the ADO Control Tower pipeline). See [`scripts/ci/components/README.md`](../../scripts/ci/components/README.md) for the caller contract. A regression in this area breaks multiple gates at once, so changes need extra care. In either case, keep helpers self-contained and follow the same security hardening rules as the pipeline YAML itself. @@ -159,7 +159,7 @@ The authoritative list and rules live at https://eng.ms/docs/more/containers-sec ## Scripting -Avoid shell scripts beyond the smallest possible wiring (env exports, `##vso[...]` log commands, single-command tool invocations). For anything more complex — argument parsing, control flow, JSON/YAML handling, HTTP, branch-name/SHA parsing — write a **Python script** under `.github/workflows/scripts//` and invoke it from the pipeline: +Avoid shell scripts beyond the smallest possible wiring (env exports, `##vso[...]` log commands, single-command tool invocations). For anything more complex — argument parsing, control flow, JSON/YAML handling, HTTP, branch-name/SHA parsing — write a **Python script** under `scripts/ci//` and invoke it from the pipeline: ```yaml - task: AzureCLI@2 @@ -170,7 +170,7 @@ Avoid shell scripts beyond the smallest possible wiring (env exports, `##vso[... scriptLocation: inlineScript inlineScript: | set -euo pipefail - python3 .github/workflows/scripts//