microsoft/skill-fedora-mirror-injections
[Skill] Diagnose Azure Linux Stage 1 (bootstrap-mirror) BuildRequires resolution failures and backfill missing RPMs into the prod Fedora updates mirror via the azl-infra injections file. Use when triaging stage-1 / azl4-bootstrap-mirror build failures, finding dependency gaps in the Fedora mirror, deciding whether a failure is a real mirror gap vs a transient timeout or a spec bug, adding entries to azl4-stage1-injections.yaml, or opening a PR with mirror injections. Triggers: bootstrap-mirror, stage 1 build failure, fedora mirror gap, missing BuildRequires, nothing provides crate, no match for argument, injections file, azl4-stage1-injections, mirror injection.
npx skills add https://github.com/microsoft/azurelinux --skill skill-fedora-mirror-injections
Diagnose BuildRequires resolution failures in AzL4 Stage 1
(*-bootstrap-mirror) builds, decide which are real prod-mirror gaps, and
backfill the missing RPMs via azl4-stage1-injections.yaml in azl-infra.
Validated on the mirror_bootstrap0623 round (draft PR #27888; 34-package
retest all passed).
azl-infra — holds the injections file and mirror tooling. Clone from:https://dev.azure.com/mariner-org/polar/_git/azl-infra
(Azure DevOps org mariner-org, project polar). The relevant tree is
scripts/fedora_mirror/.
azurelinux — the package specs (for spec-fix cases). Clone from:https://github.com/microsoft/azurelinux.git (branch 4.0).
Use when the user asks to:
azl4-bootstrap build failure or triage summary.Stage 1 (azl4-bootstrap-mirror) builds resolve all BuildRequires
from the prod Fedora mirror alone (kojifedoramirror.blob.core.windows.net).
Koji-built RPMs from the same build set are not used as build deps, so
build ordering is irrelevant — a resolution failure means the mirror
lacks that exact NVR/crate version, even if the provider built fine in the
same run. Do not dismiss these as build-order races.
Repo split: fedora-43-everything (base release) is frozen and consumed
live from upstream; fedora-43-updates drifts and is what gets
mirrored into blob snapshots — so it is what needs injections.
X from fedora-43-updates.Y; X demoted from updates repodata.X never entered the frozen releases/43/Everything.X is still recoverable from kojipkgs (Fedora's build archive).The spec's BuildRequires upper bound (>= X < next~) can't accept Y →
inject X back from kojipkgs.
import json, re
d = json.load(open('triage-summary-*.json'))
pat = re.compile(r'nothing provides|No match for argument|Could NOT find|missing:', re.I)
for b in d['buckets']:
for t in b['tasks']:
if pat.search(t['shortSummary']):
print(b['name'], t['taskID'], t['package'])
Check all buckets — gaps hide outside the obvious one.
curl -sk "https://<koji-host>/koji/getfile?taskID=<childID>&name=root.log&offset=0" \
| grep -iE "nothing provides|No match for argument|conflicting requests"
crate(icu_collections) >= 2.1.1 < 2.2.0~ proves the mirror has the name at
2.2.0 but not the needed version (the eviction signature).
| Signature | Class | Action |
|---|---|---|
| nothing provides ... < X~ / No match for argument: crate = X | Real mirror gap | Inject X from kojipkgs |
| Curl error (28): Timeout from the blob mirror | Transient infra | Retest, don't inject |
| Could NOT find <LIB> at %build, lib IS in mirror | Spec bug | Fix the azurelinux spec (BuildRequires) |
| Needs version requiring a whole-stack realignment | Version skew | Upstream owner fix |
0623 exclusions: grpc (libpfm-devel current, just add
BuildRequires: libpfm-devel), qt6-qthttpserver (`qt6-qtbase-private-devel
= 6.10.2` vs mirror qtbase 6.9.2 → qt6 stack realignment).
Rust: SRPM is rust-<crate>; binaries are rust-<crate>-devel,
rust-<crate>+<feature>-devel — all noarch, one shared NVR. Inject
every subpackage of the NVR.
# versions
curl -s "https://kojipkgs.fedoraproject.org/packages/<name>/" | grep -oE '>[0-9][^<]*/<' | sed -E 's/>//;s/\/<//' | sort -V
# releases for a version
curl -s "https://kojipkgs.fedoraproject.org/packages/<name>/<ver>/" | grep -oE '>[0-9][^<]*\.fc[0-9]+/<' | sed -E 's/>//;s/\/<//'
# noarch subpackages for the NVR
curl -s "https://kojipkgs.fedoraproject.org/packages/<name>/<ver>/<rel>/noarch/" | grep -oE 'href="[^"]+\.noarch\.rpm"' | sed -E 's/href="//;s/"//' | sort
rpm -qp --requires <rpm> | grep -E 'crate\(' | grep '<' # upper-bounded deps
rpm -qp --provides <rpm> | grep -E '^crate\('
Confirm each < X~ dep is satisfied by the injected set or current mirror
(e.g. siblings bounded < 3.0.0~ are fine against a 2.2.0 mirror; only
< 2.2.0~ pins need injecting). Iterate to a fixpoint. For masked gaps
(downstream packages that never reached builddep), run a full-set offline
depsolve against mirror + injections before rerunning. Note Rust
%generate_buildrequires produces BRs at build time — a static depsolve
misses them.
File: azl-infra/scripts/fedora_mirror/injections/azl4-stage1-injections.yaml
- {source: rust-icu_collections, name: rust-icu_collections-devel, version: 2.1.1, release: 5.fc43, arch: noarch}
source = SRPM, name = binary RPM (set source whenever they differ —always for rust crates; binaries live under the SRPM dir on kojipkgs).
noarch fans out to x86_64 + aarch64; arch-specific binaries get one entry per arch.(source, name, arch), +feature-devel before bare-devel. Insert in place; do not append. Keep entries comment-free
(rationale goes in the PR/commit).
No standalone --dry-run; reuse the script's own functions:
import yaml, inject_packages as ip, logging
logging.disable(logging.CRITICAL)
inj = yaml.safe_load(open('injections/azl4-stage1-injections.yaml'))
repos = yaml.safe_load(open('repos.yaml'))
new = [p for p in ip.expand_packages(inj, repos) if p['source_name'] in {'rust-...'}]
print('HEAD failures:', sum(0 if ip.head_check(p['url'])[0] else 1 for p in new)) # want 0
inject_packages.py is add-only + idempotent (dedup by dest path,
SKIPs existing). No delete path. Storage: account kojifedoramirrorsa,
container fedora-mirror; blob path
snapshots/<snap>/<repo>/<arch>/Packages/<first-letter>/<file>.rpm.
Snapshot caveat: the injection only helps if it lands in the snapshot the
target consumes — confirm the file's snapshot: matches before running.
Commit the injection entries on a branch off azl-infra main and open the
PR — this is the deliverable.
<user>/<task>-<date> off latest origin/main.azl4-stage1-injections.yaml (no existing linestouched), entries comment-free and in the correct alphabetical slot.
which failing package(s) each entry unblocks, closure notes, the target
snapshot:, and any packages deliberately excluded (spec bugs / version
skew) with why.
> After merge (optional): once the injection lands in the prod snapshot,
> retest the affected packages (include the transient-timeout ones; exclude
> spec/version-skew) with a body like:
> `json
> {
> "repoUri": "https://github.com/microsoft/azurelinux.git",
> "branch": "4.0",
> "commitSha": "",
> "packageTarget": "azl4-bootstrap-mirror",
> "packages": ["rust-icu_normalizer", "rust-rkyv", "..."],
> "isScratchBuild": true
> }
> `
A burst of Curl error (28): Timeout is usually a time-windowed blob outage,
not a bad package. Confirm: (1) same RPM failing across many packages →
systemic; (2) failures pack into a short window (0623: 29 in ~78 min) →
transient; (3) most other builds in that window succeeded (0623: 97%) →
mirror was up. If all three hold, retest — do not inject.
When old + new both exist (old in frozen base, new in updates/mirror), dnf
picks the highest and an old-API spec fails (e.g. rust-uucore 0.0.27 vs
0.7.0). Deleting from the mirror is the wrong lever (sync re-adds it, no
delete tooling, diverges from upstream). Fix: pin the spec's
crate(uucore) = 0.0.27 (+ lockstep siblings uucore_procs,
uuhelp_parser). Since 0.0.27 lives in the frozen live base repo, the pin
needs zero mirror changes.
azl-infra: https://dev.azure.com/mariner-org/polar/_git/azl-infraazl-infra/scripts/fedora_mirror/injections/azl4-stage1-injections.yaml.../injections/example.yaml.../fedora_mirror/{inject_packages,snapshot_repos}.py, repos.yaml, _common.pyhttps://kojipkgs.fedoraproject.org/packages/https://kojifedoramirrorsa.blob.core.windows.net/fedora-mirror/azl-infraTake microsoft/skill-fedora-mirror-injections from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.