Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions .github/workflows/check-kernel-configs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

# This action checks that required kernel configs have not been removed or
# modified to an undesirable value.
name: Kernel Required Configs Check

on:
push:
branches: [ 4.0 ]
paths:
- 'base/comps/kernel*/*config*'
pull_request:
branches: [ 4.0 ]
paths:
- 'base/comps/kernel*/*config*'

# Cancel in-progress runs of this workflow if a new run is triggered.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

permissions: {}

jobs:
check:
name: Kernel configs check
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Workflow trigger checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
# Need history so git diff-tree can resolve the base/before commit.
fetch-depth: 0

- name: Get base commit for PRs
if: ${{ github.event_name == 'pull_request' }}
env:
BASE_REF: ${{ github.base_ref }}
HEAD_SHA: ${{ github.sha }}
run: |
set -euo pipefail
git fetch origin "$BASE_REF"
base_sha=$(git rev-parse "origin/$BASE_REF")
echo "base_sha=$base_sha" >> "$GITHUB_ENV"
echo "Merging $HEAD_SHA into $BASE_REF"

- name: Get base commit for Pushes
if: ${{ github.event_name == 'push' }}
env:
BEFORE_SHA: ${{ github.event.before }}
HEAD_SHA: ${{ github.sha }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: |
set -euo pipefail
# `github.event.before` is 0000...0000 on the first push of a new
# branch, and may point at a commit no longer reachable after a
# force-push. In either case, fall back to merge-base against the
# repo default branch so we still get a sensible diff window.
zero_sha="0000000000000000000000000000000000000000"
base_sha=""
if [ -n "$BEFORE_SHA" ] && [ "$BEFORE_SHA" != "$zero_sha" ]; then
if git fetch --quiet origin "$BEFORE_SHA" 2>/dev/null \
&& git rev-parse --quiet --verify "$BEFORE_SHA^{commit}" >/dev/null; then
base_sha="$BEFORE_SHA"
else
echo "before-sha $BEFORE_SHA is not reachable (likely force-push); falling back to default branch"
fi
else
echo "no before-sha (first push of branch); falling back to default branch"
fi
if [ -z "$base_sha" ]; then
git fetch --quiet origin "$DEFAULT_BRANCH"
base_sha=$(git merge-base "origin/$DEFAULT_BRANCH" "$HEAD_SHA")
fi
echo "base_sha=$base_sha" >> "$GITHUB_ENV"
echo "Merging $HEAD_SHA into $base_sha"

# For consistency, we use the same major/minor version of Python that Azure Linux ships.
- name: Setup Python 3.14
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.14'

- name: Get Python dependencies
run: python3 -m pip install -r scripts/ci/kernel/kernel-config-checker/requirements.txt

- name: Run kernel config pytest validations
env:
BASE_SHA: ${{ env.base_sha }}
HEAD_SHA: ${{ github.sha }}
run: |
set -euo pipefail
cd scripts/ci/kernel/kernel-config-checker
python3 -m pytest -q tests/test_kernel_config_validation.py \
--base-sha "$BASE_SHA" \
--head-sha "$HEAD_SHA"
216 changes: 216 additions & 0 deletions scripts/ci/kernel/kernel-config-checker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Kernel Config Checker

A robust kernel configuration validation system using Pydantic v2 schemas. Supports default configurations and per-kernel overrides with architecture-specific settings.

## Features

- **Schema-based validation** - Uses Pydantic v2 for robust config validation
- **Multi-architecture support** - Handles x86_64 and arm64 architectures
- **Flexible overrides** - Default configs with per-kernel overrides
- **Interactive config management** - Add new configs with guided prompts
- **Config querying** - Check config values across all kernels/architectures

## Installation

From the repo root, install the Python dependencies:

```bash
pip install -r scripts/ci/kernel/kernel-config-checker/requirements.txt
```

All commands below should be run from `scripts/ci/kernel/kernel-config-checker/`:

```bash
cd scripts/ci/kernel/kernel-config-checker
```

## Usage

### Check Kernel Config

Validate a `.config` file against intentional configurations:

```bash
python -m kernel_config_checker.check_config /path/to/.config kernel_config_checker/kernel_configs_json/azl4-os-required-kernel-configs.json kernel-name architecture
```

Example:

```bash
python -m kernel_config_checker.check_config kernel.config kernel_config_checker/kernel_configs_json/azl4-os-required-kernel-configs.json kernel x86_64
```

### Add New Config

Interactively add a new kernel configuration:

```bash
python -m kernel_config_checker.check_config --add-config kernel_config_checker/kernel_configs_json/azl4-os-required-kernel-configs.json
```

Features:

- Add to default or override sections
- Support for single or multiple architectures
- Leave architectures blank to omit them from JSON
- Create new override sections or use existing ones

### Query Config Values

Check a config value across all architectures and kernels:

```bash
python -m kernel_config_checker.check_config --check-all kernel_config_checker/kernel_configs_json/azl4-os-required-kernel-configs.json CONFIG_NAME
```

Example:

```bash
python -m kernel_config_checker.check_config --check-all kernel_config_checker/kernel_configs_json/azl4-os-required-kernel-configs.json CONFIG_DRM
```

### Run the CI validation locally

The `Kernel Required Configs Check` GitHub Actions workflow validates changed kernel configs by running the pytest harness in `tests/`. To reproduce a run locally, invoke pytest with the same base/head SHAs the workflow would use:

```bash
python -m pytest tests/ \
--base-sha "$(git merge-base HEAD origin/4.0)" \
--head-sha HEAD
```

Omit the flags to default to `HEAD^..HEAD`. The harness walks the diff, filters to `base/comps/kernel*/*config*` paths whose kernel appears in the policy JSON's `overrides`, and runs the same `check_kernel_config` logic used by the CLI. Deletions of tracked kernel config files fail a dedicated test.

To add a new check (e.g. a lint over the policy JSON, or a per-arch invariant), drop another `test_*.py` into `tests/` — no workflow changes required.

## Configuration Schema

The system uses a structured JSON schema with default and override sections:

```json
{
"default": {
"name": "default",
"kernel_configs": [
{
"name": "CONFIG_EXAMPLE",
"values": [
{
"architecture": "x86_64",
"value": "y"
},
{
"architecture": "arm64",
"value": "m"
}
],
"justification": "Explanation for this config"
}
]
},
"overrides": [
{
"name": "kernel-hwe",
"kernel_configs": [
{
"name": "CONFIG_DRM",
"values": [
{
"architecture": "arm64",
"value": "y"
}
],
"justification": "amdgpu - https://github.com/microsoft/azurelinux/pull/10612"
}
]
}
]
}
```

### Architecture Support

- Configs can specify values for `x86_64`, `arm64`, or both
- When adding configs, leaving an architecture blank omits it from the JSON
- At least one architecture must be specified

### Value Types

- `y` - Built into kernel
- `m` - Built as module
- `n` - Disabled ("is not set" or missing)
- Custom values supported for specific configs

## Project Structure

```text
scripts/ci/kernel/kernel-config-checker/
├── kernel_config_checker/
│ ├── schema/
│ │ ├── __init__.py # Package init
│ │ ├── schema.py # Pydantic schema definitions
│ │ └── print_schema.py # Schema utility
│ ├── kernel_configs_json/
│ │ └── azl4-os-required-kernel-configs.json # Main config file
│ ├── __init__.py # Package init
│ ├── add_config.py # Interactive config adder
│ └── check_config.py # Main checker and utilities
├── tests/ # Pytest harness invoked by CI
│ ├── conftest.py # Shared fixtures + git-diff parametrization
│ └── test_kernel_config_validation.py # Policy checks over changed configs
├── requirements.txt # Python dependencies
└── README.md # This file
```

## Examples

### Adding a Config for Single Architecture

```bash
$ python -m kernel_config_checker.check_config --add-config test.json
Adding new kernel configuration...
Enter config name (e.g., CONFIG_EXAMPLE): CONFIG_X86_ONLY
Enter values for each architecture (y/n/m or specific value, leave blank to skip):
x86_64 value: y
arm64 value:
Enter justification: Only needed on x86_64
Add to [d]efault or [o]verride? [d]: d
✓ Added CONFIG_X86_ONLY to default section
```

Results in:

```json
{
"name": "CONFIG_X86_ONLY",
"values": [
{
"architecture": "x86_64",
"value": "y"
}
],
"justification": "Only needed on x86_64"
}
```

### Querying Config Values

```bash
$ python -m kernel_config_checker.check_config --check-all kernel_config_checker/kernel_configs_json/azl4-os-required-kernel-configs.json CONFIG_DRM
Config: CONFIG_DRM
arm64: default=m, kernel-hwe=y
x86_64: default=m
⚠️ Conflicts in: arm64
Reason: amdgpu - https://github.com/microsoft/azurelinux/pull/10612
```

## Contributing

1. Ensure all configs have proper justifications
2. Test schema validation after changes
3. Use the add-config command for consistency
4. Validate configs against actual kernel .config files

## License

This project follows the same licensing as the Azure Linux project.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
Loading
Loading