## 1. Project Overview & Quickstart (microsoft/azurelinux)

<h1>
   Azure Linux 4
</h1>

**An open-source Linux distribution built and optimized for [Azure](https://azure.microsoft.com/), with sources derived from [Fedora Linux](https://fedoraproject.org/).** Azure Linux provides a secured, reliable operating system for virtual machines, containers, and bare-metal platforms.

Azure Linux is built on a robust open-source foundation from the Fedora ecosystem and enhanced with Azure-specific innovations. This provides the familiarity of the RPM package ecosystem, while adding Azure-native security, compliance, and operational capabilities.

Key features of Azure Linux include: hardened security posture, an Azure-optimized kernel, supply chain security, native Azure integration, and a predictable lifecycle.

> **This branch holds the in-development sources for Azure Linux 4.** For Azure Linux 3, see the [`3.0` branch](https://github.com/microsoft/azurelinux/tree/3.0).

## Getting started

The links below will help you get started with Azure Linux:

| | |
|---|---|
| **Product documentation** | <https://aka.ms/azurelinux> |
| **Release information** | [GitHub Releases](https://github.com/microsoft/azurelinux/releases) |
| **File a bug / feedback** | [GitHub Issues](https://github.com/microsoft/azurelinux/issues) |
| **Ask a question / get help** | [SUPPORT.md](SUPPORT.md) |
| **Get started as a distro developer** | [DEVELOPING.md](DEVELOPING.md) |
| **Contribution guidelines** | [CONTRIBUTING.md](CONTRIBUTING.md) |
| **Report a security issue** | [SECURITY.md](SECURITY.md) |

## Using Azure Linux

*Note: Azure Linux 4 is still in development*


**🖥️ Azure VM**

To try Azure Linux in an Azure VM, please visit [our Azure Linux 4.0 page](https://aka.ms/azure-linux-4-marketplace) on the Microsoft Marketplace.




**📦 Container**

To try Azure Linux base container, please use the following image reference: `mcr.microsoft.com/azurelinux-beta/base/core:4.0`




**💿 ISO Installer**

To try Azure Linux in a local VM, please download the ISO Installer: [x86_64](https://aka.ms/azurelinux-4.0-x86_64.iso) / [ARM64](https://aka.ms/azurelinux-4.0-aarch64.iso)

Before using a downloaded ISO, [verify the checksum and signature of the ISO](./docs/verify-iso-signature-and-checksum.md).

After downloading and verifying the ISO, follow the [ISO installer instructions](./docs/iso-installer-in-local-vm.md) to install and use Azure Linux in a local VM (Hyper-V on Windows or QEMU/KVM on Linux). The ISO runs the [Anaconda](https://anaconda-installer.readthedocs.io/) installer.

_Note: Support for the ISO is community based. Before filing a new bug or feature request, please search the list of Github Issues. If you are unable to find a matching issue, please report new bugs by clicking [here](https://github.com/microsoft/azurelinux/issues). For additional information, refer to the [SUPPORT.md](./SUPPORT.md) file._




**🐧 Windows Subsystem for Linux (WSL)**

To try Azure Linux on the Windows Subsystem for Linux, please download the `.wsl` distribution package for your architecture:

- [x86_64](https://aka.ms/azurelinux-4.0-x86_64.wsl)
- [ARM64](https://aka.ms/azurelinux-4.0-aarch64.wsl)

Before installing a downloaded package, [verify the checksum and signature of the `.wsl` package](./docs/verify-wsl-signature-and-checksum.md).

Install the distribution using `wsl`:

```powershell
wsl --install --from-file "C:\Path\To\AzureLinux-4.0-ARCH.wsl"
```

To list all the installed distributions:

```powershell
wsl --list
```

To use the distro:

```powershell
wsl -d AzureLinux-4
```



## What's in this branch?

Azure Linux 4 is an RPM-based distribution optimized for Azure and modern cloud workloads. It is defined by a set of TOML configuration files and targeted *overlays* applied to [Fedora Linux](https://fedoraproject.org/), its upstream base.

Deviations from upstream are declaratively defined and scoped to avoid unnecessary divergence or forking. This repository contains a mechanically rendered set of RPM package spec files derived from applying this layer to Fedora's upstream packaging sources.

## How Azure Linux is defined

The distro is described almost entirely in TOML-based configuration files. Our open-source development tool, [`azldev`](https://github.com/microsoft/azure-linux-dev-tools), is used to apply this configuration to upstream Fedora spec files and packaging sources.

```text
azldev.toml        # Top-level entry point
├── distro/        # Distro-wide configs (e.g., sources, mock configs)
└── base/          # The "base" project: components, images, tests
    └── comps/     # Component definitions (one per source package)
    └── images/    # Base image definitions
```

### Concepts/terms

- **Components** (also known as source packages) are the unit of packaging.
  Most are imported in source form from Fedora's upstream dist-git repositories; each component produces one or more RPMs. Azure Linux builds all components from sources to produce a full set of installable RPM packages.
- **Overlays** are declarative modifications to upstream specs and sources
  (e.g., patches, additions/removals, build parameters). They live alongside the component definition and always carry a `description` explaining *why* the change is needed. Overlays let us avoid forking upstream specs and are more flexible than plain textual patches.
- **Rendered specs** are the final `.spec` files produced by applying overlays to upstream sources. They are mechanically generated by `azldev`, checked in for visibility and auditability, and live under [`specs/`](specs/). Treat them as derived output and not sources for editing. We use them as the input to standard RPM building services/tools (`mock` + `rpmbuild`, `koji`).

For a deeper tour of the tooling, the overlay system, and how to get started developing within this distro, please see
[DEVELOPING.md](DEVELOPING.md).

## Repository layout

| Path | What's there |
|---|---|
| [`azldev.toml`](azldev.toml) | Top-level config — includes `distro/` and `base/`. |
| [`distro/`](distro/) | Distro definitions (Azure Linux + upstream Fedora), shared `mock` configs. |
| [`base/`](base/) | The `base` project: components, images, tests. |
| [`base/comps/`](base/comps/) | **Component definitions** — the heart of the distro. |
| [`base/images/`](base/images/) | Image definitions (VM, container, etc.) built from the component set using [`KIWI NG`](https://osinside.github.io/kiwi/). |
| [`specs/`](specs/) | **Rendered specs** — generated `.spec` files after overlays are applied. Checked in for visibility; do not hand-edit. |
| [`locks/`](locks/) | Per-component lock files pinning upstream commits + input fingerprints; do not hand-edit. |
| [`external/schemas/`](external/schemas/) | Cached copy of the JSON Schema for TOML config files; mirrored from `azldev`. |
| [`.github/`](.github/) | CI workflows, plus Copilot prompts, skills, and agent instructions used by AI-assisted development. |

## Getting started as a distro developer

If you want to build or develop within the distro, start with **[DEVELOPING.md](DEVELOPING.md)**. Don't worry about this if you're primarily looking to *use* the distro.

## Engagement & support

- **Bugs and feature requests:** file a
  [GitHub issue](https://github.com/microsoft/azurelinux/issues). Please search existing issues first to avoid duplicates. Share as much as you can with us regarding what you tried and what you're seeing.
- **Support:** see [SUPPORT.md](SUPPORT.md) for the full set of channels.
- **Security vulnerabilities:** do **not** open a public issue. Follow the process in [SECURITY.md](SECURITY.md) to report privately to the Microsoft Security Response Center.
- **Pull requests:** see [CONTRIBUTING.md](CONTRIBUTING.md) for the patch-series workflow, commit-message conventions, and review expectations.
- **Community calls:** Azure Linux hosts community calls where users can connect with our product and support teams, discuss new features, share feedback, and learn how others are using Azure Linux.
  Each session also includes a featured demo. Upcoming community calls (08:00–09:00 PT):
  - 2026-07-23 — [Click to join][community-call-join]
  - 2026-09-24 — [Click to join][community-call-join]
  - 2026-11-19 — [Click to join][community-call-join]
  - 2027-01-28 — [Click to join][community-call-join]
  - 2027-03-25 — [Click to join][community-call-join]
  - 2027-05-27 — [Click to join][community-call-join]

[community-call-join]: https://teams.microsoft.com/l/meetup-join/19%3ameeting_ZDcyZjRkYWMtOWQxYS00OTk3LWFhNmMtMTMwY2VhMTA4OTZi%40thread.v2/0?context=%7b%22Tid%22%3a%2272f988bf-86f1-41af-91ab-2d7cd011db47%22%2c%22Oid%22%3a%2271a6ce92-58a5-4ea0-96f4-bd4a0401370a%22%7d
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions
or comments.

## Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos is subject to those third parties' policies.

## Acknowledgments

Any Linux distribution, including Azure Linux, benefits from contributions by the open-source software community. We gratefully acknowledge all contributions made from the broader community.

We specifically want to thank [the Fedora Project](https://start.fedoraproject.org/) for providing us with a strong foundation across components, spec files, tools, services, and community. We are proud to participate and contribute to this community.

The Azure Linux penguin icon is inspired by the Linux mascot ("Tux"), created by Larry Ewing.

## License

Unless otherwise specified, the content of the Azure Linux distribution and this repository are distributed under an [MIT license](LICENSE).

Individual packages within the distribution are distributed under licenses specified in their package spec files and sources.

This repository contains files derived from Fedora Linux. For details on the licensing terms for the Fedora Project, please consult [fedoraproject.org](https://docs.fedoraproject.org/en-US/legal/fedora-linux-license/).

## 2. Official Technical Reference & Guides (microsoft/azure-linux-dev-tools)

## File: README.md

# Azure Linux Dev Tools

[](https://pkg.go.dev/github.com/microsoft/azure-linux-dev-tools)
[](./LICENSE)

Azure Linux Dev Tools is a collection of utilities useful for development
of the Azure Linux distro.

## `azldev`

`azldev` is a developer tool for working on the
[Azure Linux](https://github.com/microsoft/azurelinux) distro.

It supports:

* Parsing, resolving, and querying TOML-based metadata defining the Azure Linux distro.
* Preparing the sources for a source component for building with `mock`, `koji`, or similar standard build tool/service.
* Fetching source archives from lookaside caches.
* Developer convenience utilities for locally building individual packages and images.

### Quick start

1. Install `golang` and other prerequisites via your system's package manager, e.g.:

   ```console
   dnf install -y golang mock dnf-utils mock-rpmautospec kiwi
   ```

   Note: `mock-rpmautospec` plugin hooks `rpmautospec` into mock's build lifecycle. It pulls `rpmautospec` as a dependency which processes `%autorelease` and `%autochangelog` macros in spec files.

1. Install `azldev`:

    ```console
    go install github.com/microsoft/azure-linux-dev-tools/cmd/azldev@latest
    ```

   To pin a specific release instead of tracking the latest, replace `@latest`
   with a version tag, e.g. `@v0.1.0`.

1. To ensure you can build using `mock` you must be a member of the `mock` group, e.g.:

   ```console
   usermod -aG mock $USER
   ```

   Note that this may require re-login or `newgrp` to ensure your environment registers
   the group update.

### Completion

You can install completion extensions for `azldev` with your shell by running:

```console
eval "$(azldev completion bash)"
```

Similar support exists for `fish` and `zsh`.

### User documentation

To learn more about the TOML-based metadata that `azldev` supports, `azldev`'s
command-line usage, or other usage information, please consult
this repo's [User Guide](./docs/user).

### Developing and contributing

Please see our [Contribution Guidelines](./CONTRIBUTING.md) for our project.

For development setup and workflow, please consult our [Developer Guide](./docs/developer).

## Changelog

Notable changes for each release are recorded in the [changelog](./CHANGELOG.md).

When preparing a release:

* Match the wording and formatting of existing entries, including inline code
  for commands and identifiers.
* End each new entry with links to its pull requests, such as
  [#123](https://github.com/microsoft/azure-linux-dev-tools/pull/123).
* Leave entries for earlier releases unchanged.

## Getting Help

Have questions, found a bug, or need a new feature? Open an issue in our [GitHub repository](https://github.com/microsoft/azure-linux-dev-tools/issues/new/choose). For guidance on how to file an issue, see [how to report issues](https://aka.ms/azurelinux-reportissues).

For security issues, please see the [security policy](./SECURITY.md).

## License

This project is licensed under the MIT License. See the [LICENSE](./LICENSE)
file for details.

## Trademarks

This project may contain trademarks or logos for projects, products, or
services. Authorized use of Microsoft trademarks or logos is subject to and must
follow [Microsoft's Trademark & Brand
Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
Use of Microsoft trademarks or logos in modified versions of this project must
not cause confusion or imply Microsoft sponsorship. Any use of third-party
trademarks or logos are subject to those third-party's policies.

---

## File: docs/developer/ideas/future-ideas.md

# Ideas for future consideration

## Package building

### Parameterized components

A single component can be defined to be built with a matrix of parameters, where each set of parameters results in a different "flavour" of the component being built.

Sample use cases:

- Building different configurations of the kernel.
- Building a bootstrap and full version of a component to resolve circular dependencies.

### One project can define and build different versions of the kernel

### OOT module components can build with all or selected versions of the kernels

Components providing OOT kernel modules must have a way to build against all supported kernel versions or a specific subset of them.

**IMPORTANT:** it must be possible to define OOT components in such way, that packages built for a newer kernel version are **NOT** considered as updates of the ones built for the older kernel versions. This is required, so that updating the OOT components does not inadvertently update the kernel as well due to the package's dependency on a specific kernel version.

Example:

- Project defines `kernel-older` version 1.0.0 and `kernel-newer` version 1.1.0.
- Project builds `OOT-comp` for both kernels.
- Having the package manager update `OOT-comp` on `kernel-older` does not automatically update to `kernel-newer`.

Effectively this means that the `OOT-comp` packages defined for both kernels are not considered the same package by the package manager/RPM.

## Supported origins for component sources

### Fedora SRPM repos

### Blob stores with anonymous access

### Azure blob stores requiring authentication

For such blob stores, the tool should at minimum be able to use the credentials set by logging into Azure with `az login`.

---

## File: docs/developer/how-to/add-go-tool.md

# How to: add a go tool to this project

Please consult the documentation for our [build tool go modules](../../../tools/README.md).

---

## File: docs/developer/how-to/dev-workflow.md

# Ideal Development Workflow

## Before Making Changes

1. **Understand the codebase**: Review existing code patterns and architecture
2. **Run the full test suite**: Execute `mage all` to ensure clean state
3. **Create an issue**: For non-trivial changes, discuss the approach first

## Making Changes

1. **Create a feature branch**: Use descriptive names (e.g., `user/feature/add-config-validation`)
2. **Write tests first**: Consider adding tests for new functionality before implementing
3. **Follow coding standards**: See standards section below
4. **Make incremental commits**: Use clear, descriptive commit messages following conventional commit format. Conventional commit naming will be enforced by the CI pipeline for the final PR title.

## Validating Changes

Before submitting, ensure your changes pass all checks:

```bash
mage all  # Default Go validation (also invokes slow scenario tests)
```

For faster iteration during development:

```bash
mage build     # Rebuild the tool
mage unit      # Fast unit tests
mage check all # All quality checks, including optional Python checks
mage fix all   # Auto-fix issues
```

To audit how thoroughly your tests actually catch bugs (beyond line coverage) — for example after
adding a new package or non-trivial logic — run mutation testing; see
[Mutation Testing](./testing.md#mutation-testing). `mage mutationDiff main` audits just your
branch's changes.

For scenario tests, use:

```bash
mage scenario  # Run all scenario tests (may take time)
```

To see all available Mage targets, run:

```bash
mage -l
```

---

## File: docs/developer/how-to/get-started.md

# Getting Started

## Prerequisites

- **go 1.25+** - Required for building and running the application
- **git** - For version control and submitting changes
- **mage** - Our build automation tool

  ```bash
  # Mage is not technically required, the build tools may also be invoked
  # directly via `go run magefile.go` or `./magefile.go`
  go install github.com/magefile/mage@latest
  ```

- **Python and pip** *(only if you touch Python code)* - The repository pins
   the `ruff` linter/formatter and `pyright` type checker in
   [`requirements-lint.txt`](../../../requirements-lint.txt). They are used by `mage check python`
   and `mage fix python`. Create and activate a virtual environment before installing the tools:

  ```bash
  # On Azure Linux
   tdnf install -y python3-pip

   python3 -m venv .venv
   source .venv/bin/activate
   pip install -r requirements-lint.txt
  ```

   Activate `.venv` in each shell before running `mage check python`, `mage fix python`,
   or `mage check all`. The dev container installs the pinned tools for you.

## Initial Setup

1. Fork the repository (strongly recommended for all contributors)
2. Clone your fork locally
3. Install dependencies, e.g.:

   ```bash
   dnf install -y golang
   ```

4. Verify the build works:

   ```bash
   mage build
   ```

5. Install the built tools to your `$GOPATH/bin` directory:

   ```bash
   mage install
   ```

   After running `mage install`, the tools will be available in your `$GOPATH/bin` directory.
   Not all systems will have this directory in their `$PATH` by default, so you may need to add it.

### Azure Linux 3.0 as a development host

```bash
# These instructions work for Azure Linux (https://github.com/microsoft/azurelinux)
# While the tools should build and run on any system with golang installed, some of the runtime dependencies
# may not be available on all systems (e.g., `mock`).
tdnf install -y golang ca-certificates glibc-devel

# Install runtime requirements for the azldev tool
tdnf install -y mock dnf-utils mock-rpmautospec

git clone 
cd <REPO>

# You may want to permanently add $GOPATH/bin to your $PATH via
#     echo 'export GOPATH=$(go env GOPATH)' >> $HOME/.bashrc
#     echo 'export PATH=$PATH:${GOPATH}/bin' >> $HOME/.bashrc
export GOPATH=$(go env GOPATH)
export PATH=$PATH:${GOPATH}/bin
go install github.com/magefile/mage@latest
mage build
mage install
```

## Development

Please review these follow-up documents:

- [Suggested development workflow](./dev-workflow.md).
- [Coding standards](../reference/coding-standards.md).
- [Submitting pull requests](./pull-requests.md)

## Testing

Testing can be run with `mage`, or directly using `go test`. The `mage` build system is preferred as it can also automatically run the scenario tests and update the test expectations.

```bash
# Run the unit tests
mage unit

# Run the coverage tests, producing an .html report
mage coverage

# Run scenario tests
mage scenario
```

See the [testing documentation](./testing.md) for detailed guidelines on writing and running tests.

## Troubleshooting

### Common Issues

- **Build failures**: Ensure Go version is 1.25+ and all dependencies are installed. Try running `mage build -v`. Ensure `GOPATH` is configured.
- **Test failures**: Run `mage generate` to ensure generated code is up to date
- **Lint errors**: Address specific linting issues or discuss exceptions with maintainers
- **Command not found**: Run `mage install`, ensure `GOPATH` is in your `$PATH`.

## Questions and Support

If you have any questions about contributing, please open an issue in the repository.

Thank you for contributing!

---

## File: docs/developer/how-to/testing.md

# Testing guidelines

This document provides guidelines for writing and maintaining tests within the AZL Dev Preview project, with a special focus on using interface mocks via GoMock.

## Table of Contents

- [Unit Tests](#unit-tests)
- [Scenario Tests](#scenario-tests)
- [Mutation Testing](#mutation-testing)
- [Test Utilities](#test-utilities)
- [Mocking dependencies](#mocking-dependencies)
  - [Generating Mocks](#generating-mocks)
  - [Using Mocks in Tests](#using-mocks-in-tests)
    - [Best Practices](#best-practices)
    - [Basic Usage](#basic-usage)
    - [Setting Expectations](#setting-expectations)
    - [Setting up mock return values](#setting-up-mock-return-values)
    - [Testing Error Conditions](#testing-error-conditions)
    - [Mocks side effects](#mocks-side-effects)

## Unit Tests

- **CRITICAL**: Unit tests must NOT write to the real filesystem or spawn real external processes
- Use the test context facilities (`internal/global/testctx`) for in-memory filesystem access
- Tests should not assume any files in the real host filesystem are present
- Use table-driven tests where appropriate
- Test both success and failure cases
- Use meaningful test names that describe the scenario
- Leverage `testify` for assertions

## Scenario Tests

- Use the scenario testing framework in `scenario/`
- Test realistic user workflows
- Include both positive and negative test cases
- Use `mage scenarioUpdate` when test expectations change and snapshots need updating
- Use existing test helpers in `scenario/internal/cmdtest`

## Mutation Testing

Mutation testing measures how good the tests actually are (as opposed to mere line coverage) by
introducing small changes ("mutants") into the source and checking whether the test suite catches
them. A mutant that tests fail on is *killed*; one that passes is a *lived* mutant and points to a
real gap in test assertions. The project uses [gremlins](https://github.com/go-gremlins/gremlins),
pinned in `tools/gremlins`.

Mutation testing recompiles and reruns the tests for every mutant, so it's slower than unit tests;
running the whole repo (`./`) takes a few minutes. Scope it for quicker feedback:

```bash
# Scope to a single package.
mage mutation ./internal/rpm

# Scope to only the lines changed relative to a git ref (fastest; ideal on a branch).
mage mutationDiff main
```

Interpreting the output:

- **Test efficacy** is the percentage of `KILLED` mutants over `KILLED + LIVED`. Higher is better.
- **LIVED** mutants are the actionable signal: a change the tests did not detect.
- **NOT COVERED** mutants are in code with no test coverage at all.
- Some `LIVED` mutants are *equivalent* (e.g. `len(x) > 0` vs `>= 0` when the loop body no-ops on an
  empty slice) and cannot be killed. Inspect before "fixing".

The console output is filtered to just the actionable mutants (`LIVED` and `NOT COVERED`) plus the
summary totals; a full JSON report covering every mutant (including `KILLED`) is written to
`out/mutation-report.json` for tooling or detailed review.

Mutation testing only exercises **unit tests**. Scenario tests are gated behind the `scenario` build
tag and are not run by gremlins, so they never slow down a mutation run. The targets also exclude the
`scenario/` and `magefiles/` trees and generated mocks from the mutant set to avoid `NOT COVERED`
noise.

> **Note**: Timeout tuning is configured in `.gremlins.yaml` (`unleash.timeout-coefficient`, currently 100).
> On this repo's fast suites, gremlins' default is often too tight once recompilation is included, so mutants can be
> mis-reported as `TIMED OUT` (which gremlins counts as killed, inflating efficacy).
> If you run `gremlins` without the repo config, pass a higher `--timeout-coefficient` (e.g. 100) for accurate results.

## Test Utilities

- Create reusable test fixtures when appropriate
- Mock external dependencies appropriately. See [Mocking dependencies](#mocking-dependencies) for details
- The in-memory filesystem is available via `internal/global/testctx` for testing purposes

## Mocking dependencies

The AZL Dev Preview project uses [GoMock](https://github.com/golang/mock) to generate mock implementations of interfaces for testing purposes. These mocks allow for controlled testing of components that depend on interfaces without relying on concrete implementations.

Mock generation is handled through Go's built-in [`go:generate` functionality](https://pkg.go.dev/cmd/go#hdr-Generate_Go_files_by_processing_source). The project uses a pinned version of `mockgen` stored in the `tools/mockgen` directory to ensure consistent behavior across all environments.

### Generating Mocks

To generate new mocks for an interface, add a `go:generate` directive at the top of the file containing the interface. Example from `internal/global/opctx/interfaces.go`:

```go
//go:generate go tool -modfile=../../../tools/mockgen/go.mod mockgen -source=interfaces.go -destination=opctx_test/opctx_mocks.go -package=opctx_test --copyright_file=../../../LICENSE
```

The directive should:

1. Reference the mockgen tool using the relative path to the tool's go.mod file
2. Specify the source file containing the interfaces
3. Define the destination path for the generated mocks. Place the file inside a folder with the `_test` suffix to ensure it is ignored during test coverage reports
4. Set the package name for the generated mocks
5. Include a copyright file reference

Mocks are automatically generated as part of the build process when running any of the below commands:

```shell
mage generate
mage build
mage unit
go generate ./...
```

NOTE: `go test` will **NOT** run the `go:generate` directives.

### Using Mocks in Tests

#### Best Practices

1. **Don't overuse mocks**: Only mock interfaces that are external to the component under test
2. **Keep tests focused**: Test one unit of functionality at a time
3. **Use helper functions**: Create helper functions to set up common mock configurations
4. **Use table-driven tests**: When testing similar functionality with different inputs
5. **Follow existing patterns**: See examples in the codebase such as `internal/utils/externalcmd/externalcmd_test.go`

#### Basic Usage

Full documentation and examples for using GoMock can be found in the [GoMock documentation](https://github.com/golang/mock?tab=readme-ov-file#building-mocks). Below is a short set of usage examples from this project.

To use the generated mocks in your tests:

1. Import the mock package:

   ```go
   import (
       "go.uber.org/mock/gomock"
       "github.com/microsoft/azure-linux-dev-tools/internal/global/opctx/opctx_test"
   )
   ```

2. Create a controller and mock instances:

   ```go
   func TestMyFunction(t *testing.T) {
       // Create a new controller
       ctrl := gomock.NewController(t)

       // Create mock instances using the controller
       mockFileSystem := opctx_test.NewMockFileSystemFactory(ctrl)
       mockOSEnv := opctx_test.NewMockOSEnvFactory(ctrl)

       // Use the mocks in your test
       app := azldev.NewApp(mockFileSystem, mockOSEnv)

       // Set expectations, run test code, verify
   }
   ```

#### Setting Expectations

GoMock allows you to define expectations for method calls on your mock objects:

```go
// Expect DryRun() to be called any number of times and return false
mockDryRunnable.EXPECT().DryRun().AnyTimes().Return(false)

// Expect GetEventListener() to be called exactly once with any arguments
// and return a specific mock object
mockContext.EXPECT().GetEventListener().Times(1).Return(mockEventListener)
```

These expectations are automatically verified at the end of the test. If the expectations are not met, the test will fail. Similarly, if an unexpected method call is made on the mock, the test will also fail.

#### Setting up mock return values

You can configure a mock to return a specific value. This includes returning another pre-configured mock:

```go
// Must always create a controller for the mocks.
ctrl := gomock.NewController(t)

// Create a mock of the command factory interface.
mockCmdFactory := opctx_test.NewMockCommandFactory(ctrl)

// Create a mock of the command returned by the command factory.
mockCmd := opctx_test.NewMockCommand(ctrl)

// Set up the mock command's behaviour for its Run() method. Here it returns a nil error.
// The 'gomock.Any()' is an argument matcher making sure we won't fail the test regardless of the input.
mockCmd.EXPECT().Run(gomock.Any()).Return(nil)

// Set up the command factory to return the mock command when Command() is called.
mockCmdFactory.EXPECT().Command(gomock.Any()).Return(mockCmd, nil)

(...)

// Some test code using the mock command factory:
cmd, err := mockCmdFactory.Command("arbitrary input")
require.NoError(t, err)
require.Equal(t, mockCmd, cmd)

err = cmd.Run(ctx.Background())
require.NoError(t, err)

// GoMock will automatically verify that the expected calls were made on the mock.
```

#### Testing Error Conditions

Use mocks to simulate error conditions:

```go
mockCmd.EXPECT().Run(gomock.Any()).Return(errors.New("command error"))
```

#### Mocks side effects

You can define a function to be executed when a mock method is called, allowing you to simulate side effects:

```go
const testDir = "/test/dir"

// Must always create a controller for the mocks.
ctrl := gomock.NewController(t)

// Create a mock of a command we expect to run.
// The 'gomock.Any()' is an argument matcher making sure we won't fail the test regardless of the input.
testFS := afero.NewMemMapFs()
mockCmd := opctx_test.NewMockCommand(ctrl)
mockCmd.EXPECT().Run(gomock.Any()).DoAndReturn(func(_ context.Context) error {
    // Simulate some side effect. Creating a directory in this case.
    err := fileutils.MkdirAll(testFS, testDir)
    require.NoError(t, err)

    return nil
})

...
```

---

## File: docs/developer/reference/build.md

# Build Reference

All code in this repo is written in `golang`. The `golang` package is required to build and run the tools.

The build system uses mage, which can be installed with `go install github.com/magefile/mage@latest`. Alternatively, a zero-install approach is available through `go run magefile.go` or `./magefile.go`, which automatically downloads the required dependencies without manual installation. Go build tools are managed automatically by go.


All core tooling dependencies are handled by `go tool`, which will automatically get the required tools when using `mage`. See [the tools section](../../../tools/README.md) for more information.

Optional Python lint tools are pinned in [`requirements-lint.txt`](../../../requirements-lint.txt). Before using a Mage target that runs Python checks, follow the virtual environment setup in [Getting Started](../how-to/get-started.md#prerequisites) so that `ruff` and `pyright` are on your `PATH`.

This repo contains configs for the `golangci-lint` linter. It is installed as part of the [VSCode go extension](https://marketplace.visualstudio.com/items?itemName=golang.go). It's also optionally available as a [binary release](https://golangci-lint.run/docs/welcome/install/local/#binaries).

## Mage Commands

| Command | Description | When to Use |
|---------|-------------|-------------|
| `mage -l` | List all available targets | To see all options |
| `mage all` | Build, test, default checks, and scenario pipeline | Before submitting PR |
| `mage build` | Build Go binaries | After code changes |
| `mage install` | Build Go binaries and install | Outer-loop testing |
| `mage unit` | Run unit tests | After writing tests |
| `mage scenario` | Run scenario tests (SLOW) | For major changes |
| `mage scenarioUpdate` | Update test snapshots | When test expectations change |
| `mage mutation ` | Run mutation testing on a package; writes `out/mutation-report.json` | To assess test quality of a package |
| `mage mutationDiff <ref>` | Run mutation testing on lines changed vs a git ref | To check test quality of a branch's changes |
| `mage check default` | Run default Go checks (lint, static analysis, license) | Before committing |
| `mage check all` | Run all quality checks, including Python | Before committing or after Python changes |
| `mage fix all` | Auto-fix code issues | When linting fails |
| `mage generate` | Run `go generate ./...` (mockgen, stringer, etc.) | Seldom needed directly; runs automatically with build/test |
| `mage docs` | Build binary + regenerate CLI docs and JSON schema | After changing config structs or CLI commands |

**Note**: Dependencies run automatically in correct order
(i.e. `mage build` and `mage unit` automatically run code generation as needed).

## Code Generation

The project uses automatic code generation including:

- `go:generate` directives
- Stringer for enums
- Schema generation
- Mocks generated by `mockgen`

There are two generation stages:

1. **`mage generate`** — runs `go generate ./...` for all packages (mockgen, stringer, etc.). This is a prerequisite for building and runs automatically with `mage build` and `mage unit`.
2. **`mage docs`** — builds the binary, then regenerates CLI docs (`docs/user/reference/cli/`) and JSON schema (`schemas/azldev.schema.json`). Run this after changing config structs (schema) or Cobra command descriptions (CLI docs).

You typically don't need to run `mage generate` manually; `mage build` runs it automatically. Run `mage docs` explicitly when you want to update the schema or CLI docs without running the full scenario test suite.

See [tools documentation](../../../tools/README.md#invoking-the-tool-as-part-of-gogenerate) for more details on how to use tools with `go tool` in `go:generate` directives.

---

## File: docs/developer/reference/coding-standards.md

# Coding Standards

## Go Code Style

- **Follow Go conventions**: Use `mage fix lint` for formatting (fallback: `gofmt`), and standard Go idioms
- **Naming**: Use clear, descriptive names for variables, functions, and types
- **Error handling**: Always handle errors appropriately with context. Use the following pattern:

  ```go
  // ErrOperationFailed is a global error for operation failures
  var ErrOperationFailed = errors.New("operation failed")

  // someOperation returns an error
  func someOperation() error {
      return fmt.Errorf("failed to connect to service: %w", ErrOperationFailed)
  }

  // Example usage in a function
  func performOperation() error {
      err := someOperation()
      // Wrap the error with context
      if err != nil {
          return fmt.Errorf("performing operation: %w", err)
      }
      return nil
  }
  ```

- **Comments**: Document exported functions, types, and complex logic
- **Package organization**: Follow the existing package structure
- **String formatting**: Prefer `%#q` format specifier for strings

## Code Quality Requirements

- **Linting**: All code must pass `golangci-lint` checks (use `mage check lint` and `mage fix lint` to fix some issues automatically)
  - Avoid using `//nolint` comments unless absolutely necessary. If you must use it, specify the linter (e.g., `//nolint:golint`).
- **Testing**: New functionality requires unit tests
- **Coverage**: Maintain reasonable test coverage for critical paths
- **Documentation**: Update relevant documentation for user-facing changes

## File Organization

- **Business logic**: Place in `internal/` packages
- **Command handlers**: Keep minimal logic in `cmd/` packages
- **Unit Tests**: Co-locate with source files using `_test.go` suffix
- **Scenario Tests**: Use `scenario/` for scenario tests
- **Configuration**: Use TOML format, provide defaults in `defaultconfigs/`

## Command Structure

- See [azldev command guidelines](../reference/command-guidelines.md) for details on command structure and naming conventions.

## Python Code Style

Some functionality is implemented in Python scripts (e.g. scripts embedded in the
Go binary).

- **Linting & formatting**: All Python must pass `ruff` (config: [`ruff.toml`](../../../ruff.toml)).
  Run `mage check python` to lint and `mage fix python` to auto-format and apply fixes.
- **Type checking**: All Python must pass `pyright` (config: [`pyrightconfig.json`](../../../pyrightconfig.json)).
  This is also run by `mage check python`.
- **Tool installation**: Install the pinned versions from [`requirements-lint.txt`](../../../requirements-lint.txt)
  in the virtual environment described in [Getting Started](../how-to/get-started.md#prerequisites).
- Both checks are part of `mage check all`.

## Logging Guidelines

- Use structured logging with the `slog` package
- Include relevant context in log messages
- Use appropriate log levels (Debug, Info, Warn, Error)