From c9a7ee4378f3256531707fe70eef6a87268dcc85 Mon Sep 17 00:00:00 2001 From: Christian Manivong Date: Fri, 23 Oct 2026 08:37:32 +0200 Subject: [PATCH] chore: adopt the NAPALM driver standard - CI arrives in .gitea/workflows/ci.yml and calls the shared driver workflow of NAPALM/driver-standard; the repo had none before. - setuptools>=77 and the SPDX license string PEP 639 wants, without the License classifier; napalm-device-types>=4.21.1 from PyPI; Issues and Changelog links on git.netork.io. LICENSE, NOTICE and py.typed were already there and stay. - The test extra becomes the dev extra of the standard, plus responses, which the tests mock AMT with. - mypy strict with the untyped imports (napalm, requests, defusedxml) named instead of ignored globally; napalm_amt.driver is exempt for now (5 errors: getters return dicts where the role declares TypedDicts), recorded in tests/quality_baseline.json with get_event_log's complexity of 11. - Coverage floor 95 % (measured 95.87 %). - CHANGELOG.md in Keep a Changelog form; the README's development steps install from PyPI. --- .gitea/workflows/ci.yml | 15 +++++++++++++++ .gitignore | 3 +++ CHANGELOG.md | 23 ++++++++++++++++++++-- README.md | 13 +++++++------ pyproject.toml | 38 ++++++++++++++++++++++++------------- tests/quality_baseline.json | 12 ++++++++++++ 6 files changed, 83 insertions(+), 21 deletions(-) create mode 100644 .gitea/workflows/ci.yml create mode 100644 tests/quality_baseline.json diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..7530c79 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,15 @@ +name: CI + +on: + push: + branches: [main] + tags: ["v*"] + pull_request: + +jobs: + driver: + uses: NAPALM/driver-standard/.gitea/workflows/driver.yml@main + with: + standard-ref: main + secrets: + PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} diff --git a/.gitignore b/.gitignore index 3b4fdc1..cca36af 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ build/ dist/ .venv/ .pytest_cache/ +.coverage +.mypy_cache/ +.ruff_cache/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bc7107..11a8641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,31 @@ # Changelog -## 0.1.1 +All notable changes to this driver. The format follows +[Keep a Changelog](https://keepachangelog.com/), versions follow +[Semantic Versioning](https://semver.org/). +## [Unreleased] + +### Changed +- The driver follows the NAPALM driver standard + (https://git.netork.io/NAPALM/driver-standard): CI on Gitea runs ruff, mypy, the + tests on Python 3.10–3.13 and at the lowest declared versions, bandit, pip-audit and + a build check, and a release tag publishes to PyPI. Python 3.10 stays the floor; the + license is declared as the SPDX string `Apache-2.0`, next to the LICENSE file and + `py.typed` the package already shipped. napalm-device-types now comes from PyPI + (4.21.1 or later). +- AMT's answers are parsed with defusedxml (a new dependency). An answer that carries a + DTD is refused in any encoding; before, one in UTF-16 got through. + +## [0.1.1] - 2026-10-18 + +### Fixed - `SNMP_CAPABLE = False`: AMT runs no SNMP agent, so netOrk does not poll it over SNMP as it does other management controllers. -## 0.1.0 +## [0.1.0] - 2026-10-18 +### Added - `amt` driver (`napalm_amt.AmtDriver`), a `ManagementControllerDriver` for Intel AMT over WS-Management: facts, AMT's network port, hardware inventory with the SMBIOS system UUID, firmware (AMT with build, BIOS), power state and power control, the hardware event diff --git a/README.md b/README.md index 44d46e1..1aba640 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ nothing with napalm-redfish beyond the role, so it lives here. `optional_args`: `port` (16992; 16993 means TLS), `tls` (overrides what the port implies), `verify_ssl` (`True`, a CA file path, or `False`), `retries` (1). -The WS-Management client in `napalm_amt/wsman.py` is self-contained (requests and -ElementTree). Neither `pywsman` (a C binding) nor `python-amt` (unmaintained, power only) +The WS-Management client in `napalm_amt/wsman.py` is self-contained (requests, and +defusedxml to parse the answers). Neither `pywsman` (a C binding) nor `python-amt` (unmaintained, power only) is used. ## What AMT knows, and what it does not @@ -54,12 +54,13 @@ of its own in the MEBx ([docs/lenovo-m910x.md](docs/lenovo-m910x.md)). ## Development +The rules are in [STANDARDS.md](https://git.netork.io/NAPALM/driver-standard/src/branch/main/STANDARDS.md). + ```bash python -m venv .venv -.venv/bin/pip install -e ../napalm-device-types # not on PyPI -.venv/bin/pip install -e '.[test]' ruff mypy types-requests -.venv/bin/python -m pytest -.venv/bin/ruff check . && .venv/bin/mypy napalm_amt +.venv/bin/pip install -e '.[dev]' +.venv/bin/pytest --cov +.venv/bin/ruff format --check . && .venv/bin/ruff check . && .venv/bin/mypy napalm_amt ``` ## Conventions diff --git a/pyproject.toml b/pyproject.toml index bfec2e6..ef134e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=64"] +requires = ["setuptools>=77"] build-backend = "setuptools.build_meta" [project] @@ -7,17 +7,15 @@ name = "napalm-amt" version = "0.1.1" description = "NAPALM driver for Intel Active Management Technology (AMT) over WS-Management" readme = "README.md" -license = { file = "LICENSE" } +license = "Apache-2.0" requires-python = ">=3.10" dependencies = [ "napalm>=5.0", - # Not on PyPI: install from git before this package (see README). - "napalm-device-types>=4.16", + "napalm-device-types>=4.21.1", "requests>=2.31", "defusedxml>=0.7", ] classifiers = [ - "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3", "Topic :: System :: Hardware", "Topic :: System :: Networking", @@ -25,12 +23,12 @@ classifiers = [ [project.urls] Repository = "https://git.netork.io/NAPALM/napalm-amt" +Issues = "https://git.netork.io/NAPALM/napalm-amt/issues" +Changelog = "https://git.netork.io/NAPALM/napalm-amt/src/branch/main/CHANGELOG.md" [project.optional-dependencies] -test = [ - "pytest>=7", - "responses>=0.23", -] +# responses mocks AMT's HTTP answers in the tests. +dev = ["pytest>=8", "pytest-cov>=5", "mypy>=1.11", "ruff>=0.6", "responses>=0.23"] [project.entry-points."napalm.drivers"] amt = "napalm_amt:AmtDriver" @@ -41,9 +39,6 @@ include = ["napalm_amt*"] [tool.setuptools.package-data] napalm_amt = ["py.typed"] -[tool.pytest.ini_options] -testpaths = ["tests"] - [tool.ruff] line-length = 100 target-version = "py310" @@ -58,6 +53,23 @@ select = ["E", "F", "I", "UP", "B"] [tool.mypy] python_version = "3.10" strict = true -ignore_missing_imports = true # napalm itself is untyped, so every driver subclasses Any. disallow_subclassing_any = false + +[[tool.mypy.overrides]] +module = ["napalm.*", "requests.*", "defusedxml.*"] +ignore_missing_imports = true + +[[tool.mypy.overrides]] +# Not yet under strict mypy (quality baseline); may only shrink. +module = ["napalm_amt.driver"] +ignore_errors = true + +[tool.pytest.ini_options] +testpaths = ["tests"] + +[tool.coverage.run] +source = ["napalm_amt"] + +[tool.coverage.report] +fail_under = 95 diff --git a/tests/quality_baseline.json b/tests/quality_baseline.json new file mode 100644 index 0000000..2f8b93e --- /dev/null +++ b/tests/quality_baseline.json @@ -0,0 +1,12 @@ +{ + "coverage_floor": 95.0, + "function_complexity": { + "napalm_amt/driver.py::AmtDriver.get_event_log": 11 + }, + "function_lines": {}, + "mypy_relaxed": [ + "napalm_amt.driver" + ], + "python_file_lines": {}, + "untyped_public": [] +}