Skip to main content

acn-go-version-bump

Go version upgrade procedure for Azure Container Networking. Use when upgrading Go minor/patch versions, bumping MS Go toolchain, fixing FIPS/systemcrypto configuration, updating Dockerfile templates, or responding to Go CVE patches. Covers the 3-tier automation (digest refresh, patch bump, minor upgrade) and the manual steps for each tier.

Source facts

Repository
Azure/azure-container-networking
Last source activity
October 1, 2026 at 18:26
Detected SKILL.md language
English
Stars
435
Forks
279

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
acn-go-version-bump
description
Go version upgrade procedure for Azure Container Networking. Use when upgrading Go minor/patch versions, bumping MS Go toolchain, fixing FIPS/systemcrypto configuration, updating Dockerfile templates, or responding to Go CVE patches. Covers the 3-tier automation (digest refresh, patch bump, minor upgrade) and the manual steps for each tier.
user-invocable
true
license
MIT
compatibility
Designed for GitHub Copilot Coding Agent and Claude Code.
metadata
{"author":"behzad-mir","version":"4.6.0"}
allowed-tools
Read Edit Write Glob Grep Bash(go:*) Bash(make:*) Bash(skopeo:*) Bash(git:*) Bash(gh:*) Agent
**Persona:** You are a Go platform engineer maintaining the Azure Container Networking build toolchain. You understand MS Go's FIPS requirements, MCR image tagging, and the multi-file version propagation needed for Go upgrades in this repo. **Modes:** - **Upgrade mode** — performing a Go version upgrade (minor or patch). Analyze MS Go docs, assess repo impact, then execute changes. - **FIPS audit mode** — verifying crypto configuration is correct for the current Go version and CGO settings. - **Workflow debug mode** — troubleshooting the `go-version-check.yaml` automation workflow. --- # Go Version Upgrade Procedure ## Step 0: Analyze MS Go Documentation (MANDATORY) **CRITICAL: Before making ANY code changes, you MUST fetch and analyze ALL relevant MS Go documentation for the target version. Do not rely on hardcoded rules — requirements change between versions.** ### Documents to Fetch **These docs may be pre-cached in `.github/ms-go-docs/` by `copilot-setup-steps.yml` (which runs before the agent firewall activates).** Try reading the cached files first. If they don't exist (e.g., running locally or cache wasn't populated), fall back to `gh api`. ```bash # 1. FIPS README — the AUTHORITATIVE source for crypto configuration # PREFERRED: read pre-cached file (firewall blocks cross-repo gh api calls) cat .github/ms-go-docs/README.md 2>/dev/null || \ gh api "repos/microsoft/go/contents/eng/doc/fips/README.md?ref=microsoft/main" --jq '.content' | base64 -d # 2. NocgoOpenSSL — detailed nocgo backend docs cat .github/ms-go-docs/NocgoOpenSSL.md 2>/dev/null || \ gh api "repos/microsoft/go/contents/eng/doc/NocgoOpenSSL.md?ref=microsoft/main" --jq '.content' | base64 -d # 3. Installation guide cat .github/ms-go-docs/Installation.md 2>/dev/null || \ gh api "repos/microsoft/go/contents/eng/doc/Installation.md?ref=microsoft/main" --jq '.content' | base64 -d # 4. Migration Guide — toolchain behavior, breaking changes cat .github/ms-go-docs/MigrationGuide.md 2>/dev/null || \ gh api "repos/microsoft/go/contents/eng/doc/MigrationGuide.md?ref=microsoft/main" --jq '.content' | base64 -d # 5. FIPS User Guide — runtime requirements, crypto API behavior cat .github/ms-go-docs/UserGuide.md 2>/dev/null || \ gh api "repos/microsoft/go/contents/eng/doc/fips/UserGuide.md?ref=microsoft/main" --jq '.content' | base64 -d # 6. Additional Features — all MS-specific patches cat .github/ms-go-docs/AdditionalFeatures.md 2>/dev/null || \ gh api "repos/microsoft/go/contents/eng/doc/AdditionalFeatures.md?ref=microsoft/main" --jq '.content' | base64 -d # 7. Upstream Go release notes (fetch from go.dev — may be blocked) # curl -sL https://go.dev/doc/go1.<MINOR> || echo "Blocked by firewall — skip" ``` **Image digests are also pre-resolved** into `.github/image-digests/`: ```bash cat .github/image-digests/go-image.txt # Go builder SHA cat .github/image-digests/mariner-core.txt # Azure Linux base/core SHA cat .github/image-digests/mariner-distroless.txt # Azure Linux distroless SHA cat .github/image-digests/windows-hpc.txt # Windows HPC base image SHA ``` Use these cached values for Dockerfile updates when `skopeo` is blocked by the firewall. ### Analysis Procedure — GOEXPERIMENT Determination **This is the step the agent failed on previously. Follow it precisely.** After fetching the docs, you MUST determine the correct `GOEXPERIMENT` value for EVERY build in this repo. The answer depends on THREE things: 1. The target Go version number 2. Whether the build uses `CGO_ENABLED=0` or `CGO_ENABLED=1` 3. The platform (Linux vs Windows) **How to find the answer in the docs:** 1. Open `eng/doc/fips/README.md` and find the section titled **"Usage: Common configurations"** 2. This section contains a table mapping (OS, CGO setting, Go version) → required GOEXPERIMENT 3. Extract the GOEXPERIMENT value for: - Linux + CGO_ENABLED=1 → typically `systemcrypto` (uses OpenSSL via dlopen) - Linux + CGO_ENABLED=0 → may need a special experiment (e.g., `ms_nocgo_opensslcrypto`) - Windows → typically no GOEXPERIMENT needed (CNG backend works without CGO) **CRITICAL UNDERSTANDING:** In MS Go, the crypto backend is NOT optional — it's mandatory for FIPS compliance. If a build requires `CGO_ENABLED=0` (static binary) on Linux, and the default crypto backend requires CGO, then you MUST set a GOEXPERIMENT that provides a nocgo-compatible backend. Without it, **the build will fail** with linker errors or crypto initialization panics. **DO NOT** assume that "no GOEXPERIMENT" is safe for CGO=0 builds. Read the docs and determine what backend is used by default and whether it requires CGO. ### Cross-Reference with Repo After determining the correct GOEXPERIMENT per (CGO, OS) pair, audit EVERY build path: ```bash # Find all CGO settings in build scripts grep -rn "CGO_ENABLED" .pipelines/build/scripts/ --include="*.sh" # Find all CGO settings in Dockerfiles and templates grep -rn "CGO_ENABLED" . --include="*.Dockerfile" --include="*.Dockerfile.tmpl" --include="Dockerfile.tmpl" # Find CGO settings in Makefiles grep -rn "CGO_ENABLED" Makefile */Makefile # ALSO find implicit CGO=1 via -buildmode=c-shared (doesn't explicitly set CGO_ENABLED) grep -rn "buildmode=c-shared" Makefile */Makefile .pipelines/build/scripts/ ``` For EACH file that sets `CGO_ENABLED` OR uses `-buildmode=c-shared`, you MUST ensure the correct `GOEXPERIMENT` is set in the same scope. ### Full Analysis Checklist #### A. Build Environment Requirements - [ ] Required `GOEXPERIMENT` values per (CGO, OS) combination — **from fips/README.md table** - [ ] Required build flags (`-buildmode`, `-ldflags`, etc.) - [ ] `GOTOOLCHAIN` behavior changes - [ ] Any new env vars introduced or deprecated - [ ] `go mod tidy` behavior changes (stricter validation, new directives) #### B. Runtime Dependencies - [ ] Required system libraries (libc, libdl, libpthread, libcrypto) - [ ] Base image requirements (what libraries must be present) - [ ] Architecture-specific limitations Cross-reference: - Check `MARINER_DISTROLESS_IMG` in `build/images.mk` - Verify runtime base images have required crypto libraries #### C. Crypto/FIPS Changes (CRITICAL) - [ ] Which crypto backend is selected BY DEFAULT (no GOEXPERIMENT set)? - [ ] Does the default backend require CGO? If yes → CGO=0 builds WILL FAIL without intervention - [ ] What GOEXPERIMENT enables a nocgo-compatible backend? - [ ] Is `MS_GO_NOSYSTEMCRYPTO` deprecated? - [ ] Any crypto API behavior changes (non-FIPS curves, key sizes)? #### D. Compatibility & Breaking Changes - [ ] Deprecated stdlib APIs - [ ] Module system changes - [ ] Key dependency support (controller-runtime, client-go, cilium) ### Output: Change Plan Before making any code changes, produce a change plan: ```markdown ## MS Go <VERSION> Upgrade — Requirements Analysis ### Source Documents Reviewed - [ ] eng/doc/fips/README.md: <GOEXPERIMENT table findings> - [ ] eng/doc/NocgoOpenSSL.md: <nocgo backend details> - [ ] docs/go1.XX.md: <version-specific changes> - [ ] eng/doc/MigrationGuide.md: <relevant migration steps> - [ ] eng/doc/fips/UserGuide.md: <runtime requirements> ### GOEXPERIMENT Determination (from fips/README.md) | Build Configuration | GOEXPERIMENT Required | Reason | |---|---|---| | Linux + CGO_ENABLED=1 | <value from docs> | <why> | | Linux + CGO_ENABLED=0 | <value from docs> | <why — if blank, explain why safe> | | Windows (any CGO) | <value from docs> | <why> | ### Files Requiring GOEXPERIMENT Changes List EVERY file that needs modification: | File | CGO Setting | Current GOEXPERIMENT | Required GOEXPERIMENT | Action | |---|---|---|---|---| | .pipelines/build/scripts/cni.sh | 0 | (none) | <value> | Add export | | .pipelines/build/scripts/cns.sh | 0 | (none) | <value> | Add export | | ... | ... | ... | ... | ... | | Makefile (all CGO=0 targets) | 0 | (none) | <value> | Add inline | ### Risk Assessment - Breaking changes affecting this codebase: ... - FIPS compliance impact: ... ``` **Only proceed with code changes after the analysis is complete and EVERY build path is accounted for.** --- ## Step 1: Execute Version Bump ### Go Version Strategy ACN uses **floating minor version tags** for the Go build image (`build/images.mk`): - `GO_IMG` uses a 2-part minor version tag (e.g., `golang:1.26-azurelinux3.0`) - The floating tag resolves to the latest patch via SHA digest at `make dockerfiles` time **Separate compatibility from the preferred toolchain:** - The `go` directive is the module's minimum language/toolchain and dependency compatibility floor. Keep it at the lowest version supported by the source and every required dependency. - The `toolchain` directive selects the exact preferred patch used for development and CI. Patch bumps update this directive in every independently tested module without raising the `go` floor. - Use a full release version for the floor when dependencies require it. For example, `go 1.25` sorts before `go 1.25.0` and cannot satisfy dependencies that declare `go 1.25.0`. **Example:** If the compatibility floor is Go 1.25 and the supported build toolchain is Go 1.26.7, use this in every module: ```go go 1.25.0 toolchain go1.26.7 ``` ### Version Sources (ALL must be updated — do NOT skip any) **⚠️ IMPORTANT: The ROOT `go.mod` is the FIRST file to update. Do NOT only update sub-modules.** ``` build/images.mk (GO_IMG=golang:1.XX-azurelinux3.0) ← primary image tag │ ├── ROOT MODULE: │ └── → go.mod (go floor + exact toolchain) │ ├── BUILD ENVIRONMENT: │ ├── → tools-go/go.mod (same floor + toolchain) │ ├── → .devcontainer/Dockerfile (VARIANT="1.XX") ← dev container version │ ├── → .pipelines/build/scripts/install-go.sh (DEFAULT_IMAGE SHA) │ ├── → bpf-prog/ipv6-hp-bpf/linux.Dockerfile (Go image SHA) │ ├── → npm/linux.Dockerfile (tag 1.XX.Y) │ ├── → npm/windows.Dockerfile (tag 1.XX.Y) │ └── → All .tmpl Dockerfiles (via `make dockerfiles`) │ └── INDEPENDENT MODULES (update toolchain in EACH; raise go floor only when required): ├── → azure-ipam/go.mod ├── → azure-ip-masq-merger/go.mod ├── → azure-iptables-monitor/go.mod ├── → bpf-prog/ipv6-hp-bpf/go.mod ├── → cilium-log-collector/go.mod ├── → cni/go.mod ├── → crd/go.mod ├── → dropgz/go.mod ├── → npm/go.mod ├── → pkgerrlint/go.mod ├── → tools/azure-npm-to-cilium-validator/go.mod └── → zapai/go.mod ``` ### Files to Update (in order) 1. **`go.mod` (ROOT)** — Update the exact `toolchain` directive. - Preserve the `go` compatibility floor unless source or dependencies require a newer language version. 2. **`build/images.mk`** — Update `GO_IMG` tag - ALWAYS use 2-part floating tag: `1.27-azurelinux3.0`, never `1.27.0-azurelinux3.0` 3. **`tools-go/go.mod`** — Update `toolchain` to match root 4. **All sub-module `go.mod` files** — Update `toolchain` to match (see full list above) 5. **Do NOT run `go mod tidy`** — it times out in the agent environment - Existing `go.sum` files remain valid for pure version bumps (deps don't change) - `tools-go/go.sum` is handled by the migration step (copy from `tools.go.sum`) - CI or a follow-up commit will reconcile any checksum drift if needed 6. **`.devcontainer/Dockerfile`** — Update `VARIANT` arg to `"1.XX"` 7. **`.pipelines/build/scripts/install-go.sh`** — Update `DEFAULT_IMAGE` to new Go image digest: ```bash # Read the pre-cached Go image digest (resolved during copilot-setup-steps) NEW_GO_DIGEST=$(cat .github/image-digests/go-image.txt 2>/dev/null) # If cache exists, use it to update install-go.sh: if [ -n "$NEW_GO_DIGEST" ]; then sed -i "s|DEFAULT_IMAGE=\".*\"|DEFAULT_IMAGE=\"${NEW_GO_DIGEST}\"|" .pipelines/build/scripts/install-go.sh fi ``` Also update the `skopeo inspect` comment above it to reference the new tag. 8. **`bpf-prog/ipv6-hp-bpf/linux.Dockerfile`** — Update Go image tag and SHA - ⚠️ This Dockerfile uses a **plain Debian-based Go image** (e.g., `golang:1.26.4`), NOT the `-azurelinux3.0` variant used elsewhere - It needs `apt-get` for BPF tooling (llvm, clang, libbpf-dev), which is only available on Debian - **Do NOT use the same digest as `install-go.sh` or `build/images.mk`** — those use the Azure Linux image - Resolve the correct digest separately: ```bash skopeo inspect "docker://mcr.microsoft.com/oss/go/microsoft/golang:1.XX.Y" --format "{{.Digest}}" ``` (using the plain patch tag, e.g., `1.26.6`, without `-azurelinux3.0`) 9. **`npm/linux.Dockerfile`** and **`npm/windows.Dockerfile`** — Update Go tag - ⚠️ npm Dockerfiles use **plain patch tag** (e.g., `golang:1.26.4`), NOT the `-azurelinux3.0` suffixed tag - The npm builder uses Ubuntu as runtime base, not Azure Linux - `npm/windows.Dockerfile` builds on a **Linux builder** (`--platform=linux/amd64`) cross-compiling with `GOOS=windows` — it still needs `GOEXPERIMENT` for CGO_ENABLED=0 on the Linux build stage - Replace `MS_GO_NOSYSTEMCRYPTO=1` with appropriate `GOEXPERIMENT=<value>` in BOTH files 10. **Run `make dockerfiles`** — Regenerate all template-based Dockerfiles ### Step 1b: Apply GOEXPERIMENT to ALL Build Paths (CRITICAL) **This step is where the previous agent failed. Do NOT skip any file.** Based on your GOEXPERIMENT determination from Step 0, you must update EVERY build path. Here is the COMPLETE list of locations that need GOEXPERIMENT: #### Pipeline Build Scripts (`.pipelines/build/scripts/*.sh`) Each script that sets `CGO_ENABLED` MUST also export the correct `GOEXPERIMENT`: ```bash # For CGO_ENABLED=0 scripts (Linux-only guard if script is multi-platform): if [[ "$GOOS" == "linux" ]] || [[ -z "$GOOS" ]]; then export GOEXPERIMENT=<value_for_cgo0> fi export CGO_ENABLED=0 # For CGO_ENABLED=1 scripts: export GOEXPERIMENT=<value_for_cgo1> export CGO_ENABLED=1 ``` Scripts to update: - `.pipelines/build/scripts/cni.sh`
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub