Bundled Azure CLI extensions are not version-pinned
- Dominant language
- TypeScript
- Stars
- 102
- Forks
- 25
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 22
Description
## Problem
The bundled Azure CLI extensions are the only external tools we ship that are **not** version-pinned.
`package.json` pins everything else with a checksum:
```json
"azureCli": { "version": "2.89.0", "win32": { "checksum": "fb55449e…" } },
"python": { "linux": { "url": "…cpython-3.10.18…", "checksum": "b712e37f…" } },
"aksMcp": { "version": "v0.0.20", "win32": { "amd64": { "checksum": "0aa99734…" } } }
```
but extensions are listed by bare name:
```json
"extensions": ["resource-graph", "alertsmanagement", "connectedk8s"]
```
`build/download-az-cli.ts` installs those with `az extension add -n `, which resolves whatever the Azure CLI extension index currently advertises as newest-compatible. Two builds of the same commit can therefore bundle different extension versions.
This is observable, not theoretical. In build `245401` the CLI chose `connectedk8s-1.11.3`, while the public extension index served `1.11.1` as newest a few hours earlier the same day:
```
DEBUG: cli.azure.cli.core.extension._resolve: Chosen {'filename': 'connectedk8s-1.11.3-py2.py3-none-any.whl', …}
```
Each extension version also drags in its own transitive dependency set from PyPI (`connectedk8s` pins `kubernetes==24.2.0`, `pycryptodome==3.20.0`, `oras==0.2.25`, `azure-mgmt-hybridcompute==7.0.0`), so the shipped payload moves with it.
## Why it matters
- **Reproducibility** — rebuilding a released tag does not reproduce the released bytes, and the `.az-cli-staged.json` marker records only names, so the incremental-build check cannot tell that a staged bundle holds a different version than a fresh install would.
- **Supply chain** — an extension and its whole dependency tree enter the shipped app with no pinned version and no checksum, unlike every other bundled tool. The signed installer contains binaries (`cryptography`, `pycryptodome`, `rpds-py`) whose versions were decided at build time by a remote index.
- **Debuggability** — when a build breaks, "which extension version" is not answerable from the repo, only from build logs. `alertsmanagement` resolves to a preview version today (`WARNING: No stable version of 'alertsmanagement' to install. Preview versions allowed.`), which can change without notice.
## Suggested direction
Allow an optional version per extension, keeping the current bare-name form working:
```json
"extensions": [
{ "name": "connectedk8s", "version": "1.11.3" },
"resource-graph"
]
```
Touch points:
- `expectedAzCliExtensions()` in `build/az-cli-config.ts` — already the single source both install paths and the staged marker go through
- `sameExtensionSet()` / `StagedAzCli` in the same file — the marker should record resolved versions so the incremental check compares like with like
- both install loops in `build/download-az-cli.ts` — pass `-n ==` (or the pinned wheel URL) when a version is given
- `build/verify-bundled-tools.ts` — assert the bundled version matches the pin, as it already does for the Azure CLI itself
Open questions worth settling in the issue rather than guessing:
- Pin only `connectedk8s` (the one with real dependencies and the one that has broken a build), or all three?
- Do we want checksums as well, or is a version pin enough given the wheels come from `azcliprod.blob.core.windows.net` over HTTPS with the CLI verifying its own checksum from the index?
- What is the update cadence — Dependabot cannot see these, so pins need an owner or they rot.
## Context
Found while diagnosing the Windows signing pipeline failure in build `245357`, where bundling `connectedk8s` failed because pypi.org is unreachable from the Windows 1ES pool. That specific failure is fixed separately by routing pip through the Microsoft package feed proxy; the unpinned versions are an independent issue that surfaced in the same logs.
Contributor guide
Research direction
Start with expectedAzCliExtensions(), sameExtensionSet(), and StagedAzCli in build/az-cli-config.ts, then trace both installation loops in build/download-az-cli.ts. Review build/verify-bundled-tools.ts and settle the pinning and checksum scope; done means configured extension versions are installed, recorded in the staged marker, compared during incremental builds, and verified against the bundle.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, kubernetes, typescript
- Domain
- build-system, devops, tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100