Epic: one standard for every NAPALM driver, releases on PyPI #2

Open
opened 2026-10-22 17:31:47 +00:00 by christianmanivong · 2 comments
Owner

Every driver in the NAPALM org follows one standard for TDD, clean code and repository
usage, and publishes releases to PyPI. Decided by Christian on 2026-10-22; this settles
NetOrk/netork#734 as option A.

Decisions

  • Releases by hand, by tag. Version and CHANGELOG are bumped by hand, vX.Y.Z is tagged, CI publishes. No schedule.
  • PyPI names: free napalm-<x> names stay; only collisions get a new name (napalm-netgear belongs to a third party; napalm-vyos, -s350, -fortios are the upstream projects). The entry-point driver names do not change.
  • netOrk pins released == versions with hashes in a lock. A git SHA pin stays allowed as a justified exception.
  • Quality ratchet. ruff, ruff format and bandit hold from day one. mypy-strict exemptions and the coverage floor start at each repo's current state and only improve.
  • Defaults: main everywhere, Python >= 3.10, Apache-2.0, project links on git.netork.io, one PyPI token per project (Trusted Publishing does not work from Gitea), and the stale PyPI uploads of device-types 0.1.0 and tplink 0.1.x get yanked.

Phases

  • 1. Standard: STANDARDS.md, the shared workflow driver.yml, napalm-standard (check, ratchet, release), template. Pilot findings in #1.
  • 2. Pilot: device-types (NAPALM/napalm-device-types#52) and linux (NAPALM/napalm-linux#38). Both are green except pip-audit, which #1 fixes. Then the first release to TestPyPI, then PyPI.
  • 3. Rollout to the other drivers in dependency order, one issue and one PR each (table below).
  • 4. netOrk: vendor-drivers.txt with versions, requirements-drivers.lock with hashes, Dockerfiles without the install-order hack, --check-pins asks PyPI, docs.
  • 5. Forks: vyos, s350, fortios and lancom, after their port onto device-types and under new names.

Needs Christian

  • A PyPI account with 2FA (optionally a PyPI organisation "NAPALM"), and a TestPyPI account.
  • Tokens as repo secret PYPI_TOKEN: account-wide for the first upload, then scoped to the project.
  • Netgear package name: napalm-netgear-switches (decided 2026-10-22).
  • master → main: each repo is renamed right before its adoption PR merges (decided 2026-10-22).

Old Co-Authored-By lines in the history of 13 repos are rewritten only after phase 4, once netOrk no longer pins commit SHAs (decided 2026-10-22).

Repositories

Repo Issue Status ruff (fixable) mypy strict Coverage
napalm-device-types NAPALM/napalm-device-types#54 pilot, PR #52 clean baseline 95 %
napalm-linux NAPALM/napalm-linux#40 pilot, PR #38 clean baseline 58 %
napalm-openmediavault NAPALM/napalm-openmediavault#8 open (after linux) 14 (fixable 4) 5 in 1 file 16%
napalm-qnap-qts NAPALM/napalm-qnap-qts#10 open (after linux) 0 (fixable 0) 9 in 1 file 76%
napalm-amt NAPALM/napalm-amt#1 open 0 (fixable 0) 5 in 1 file n/a
napalm-bsd NAPALM/napalm-bsd#19 open 22 (fixable 20) 27 in 4 files 95%
napalm-fritzbox NAPALM/napalm-fritzbox#6 open 10 (fixable 3) 6 in 1 file 81%
napalm-hpe-aruba-procurve NAPALM/napalm-hpe-aruba-procurve#18 open 200 (fixable 188) 1 in 1 file n/a
napalm-hpe-officeconnect NAPALM/napalm-hpe-officeconnect#5 open 0 (fixable 0) 4 in 1 file 92%
napalm-netgear NAPALM/napalm-netgear#14 open 168 (fixable 159) 139 in 2 files 47%
napalm-openwrt NAPALM/napalm-openwrt#20 open 24 (fixable 15) 130 in 9 files 65%
napalm-opnsense NAPALM/napalm-opnsense#30 open 91 (fixable 48) 50 in 7 files 79%
napalm-proxmox NAPALM/napalm-proxmox#32 open 97 (fixable 68) 200 in 11 files 69%
napalm-redfish NAPALM/napalm-redfish#2 open 12 (fixable 12) 50 in 8 files n/a
napalm-sonos NAPALM/napalm-sonos#5 open 5 (fixable 2) 5 in 1 file 71%
napalm-tplink-jetstream NAPALM/napalm-tplink-jetstream#8 open 23 (fixable 5) 96 in 1 file 37%
napalm-vmware NAPALM/napalm-vmware#7 open 4 (fixable 1) 35 in 11 files 97%
napalm-windows NAPALM/napalm-windows#4 open 0 (fixable 0) 1 in 1 file 96%
napalm-yealink NAPALM/napalm-yealink#4 open 11 (fixable 5) 20 in 1 file 42%
napalm-zyxel NAPALM/napalm-zyxel#8 open 13 (fixable 3) 24 in 1 file 69%

Also in the org, not yet in scope: napalm-vyos, napalm-s350, napalm-fortios, napalm-lancom (phase 5).

Every driver in the NAPALM org follows one standard for TDD, clean code and repository usage, and publishes releases to PyPI. Decided by Christian on 2026-10-22; this settles NetOrk/netork#734 as option A. ## Decisions - **Releases by hand, by tag.** Version and CHANGELOG are bumped by hand, `vX.Y.Z` is tagged, CI publishes. No schedule. - **PyPI names:** free `napalm-<x>` names stay; only collisions get a new name (`napalm-netgear` belongs to a third party; `napalm-vyos`, `-s350`, `-fortios` are the upstream projects). The entry-point driver names do not change. - **netOrk pins** released `==` versions with hashes in a lock. A git SHA pin stays allowed as a justified exception. - **Quality ratchet.** ruff, ruff format and bandit hold from day one. mypy-strict exemptions and the coverage floor start at each repo's current state and only improve. - **Defaults:** `main` everywhere, Python >= 3.10, Apache-2.0, project links on git.netork.io, one PyPI token per project (Trusted Publishing does not work from Gitea), and the stale PyPI uploads of device-types 0.1.0 and tplink 0.1.x get yanked. ## Phases - [x] **1. Standard:** STANDARDS.md, the shared workflow `driver.yml`, `napalm-standard` (check, ratchet, release), template. Pilot findings in #1. - [ ] **2. Pilot:** device-types (NAPALM/napalm-device-types#52) and linux (NAPALM/napalm-linux#38). Both are green except pip-audit, which #1 fixes. Then the first release to TestPyPI, then PyPI. - [ ] **3. Rollout** to the other drivers in dependency order, one issue and one PR each (table below). - [ ] **4. netOrk:** `vendor-drivers.txt` with versions, `requirements-drivers.lock` with hashes, Dockerfiles without the install-order hack, `--check-pins` asks PyPI, docs. - [ ] **5. Forks:** vyos, s350, fortios and lancom, after their port onto device-types and under new names. ## Needs Christian - [ ] A PyPI account with 2FA (optionally a PyPI organisation "NAPALM"), and a TestPyPI account. - [ ] Tokens as repo secret `PYPI_TOKEN`: account-wide for the first upload, then scoped to the project. - [x] Netgear package name: **`napalm-netgear-switches`** (decided 2026-10-22). - [x] `master` → `main`: each repo is renamed right before its adoption PR merges (decided 2026-10-22). Old `Co-Authored-By` lines in the history of 13 repos are rewritten only after phase 4, once netOrk no longer pins commit SHAs (decided 2026-10-22). ## Repositories | Repo | Issue | Status | ruff (fixable) | mypy strict | Coverage | |---|---|---|---|---|---| | napalm-device-types | NAPALM/napalm-device-types#54 | pilot, PR #52 | clean | baseline | 95 % | | napalm-linux | NAPALM/napalm-linux#40 | pilot, PR #38 | clean | baseline | 58 % | | napalm-openmediavault | NAPALM/napalm-openmediavault#8 | open (after linux) | 14 (fixable 4) | 5 in 1 file | 16% | | napalm-qnap-qts | NAPALM/napalm-qnap-qts#10 | open (after linux) | 0 (fixable 0) | 9 in 1 file | 76% | | napalm-amt | NAPALM/napalm-amt#1 | open | 0 (fixable 0) | 5 in 1 file | n/a | | napalm-bsd | NAPALM/napalm-bsd#19 | open | 22 (fixable 20) | 27 in 4 files | 95% | | napalm-fritzbox | NAPALM/napalm-fritzbox#6 | open | 10 (fixable 3) | 6 in 1 file | 81% | | napalm-hpe-aruba-procurve | NAPALM/napalm-hpe-aruba-procurve#18 | open | 200 (fixable 188) | 1 in 1 file | n/a | | napalm-hpe-officeconnect | NAPALM/napalm-hpe-officeconnect#5 | open | 0 (fixable 0) | 4 in 1 file | 92% | | napalm-netgear | NAPALM/napalm-netgear#14 | open | 168 (fixable 159) | 139 in 2 files | 47% | | napalm-openwrt | NAPALM/napalm-openwrt#20 | open | 24 (fixable 15) | 130 in 9 files | 65% | | napalm-opnsense | NAPALM/napalm-opnsense#30 | open | 91 (fixable 48) | 50 in 7 files | 79% | | napalm-proxmox | NAPALM/napalm-proxmox#32 | open | 97 (fixable 68) | 200 in 11 files | 69% | | napalm-redfish | NAPALM/napalm-redfish#2 | open | 12 (fixable 12) | 50 in 8 files | n/a | | napalm-sonos | NAPALM/napalm-sonos#5 | open | 5 (fixable 2) | 5 in 1 file | 71% | | napalm-tplink-jetstream | NAPALM/napalm-tplink-jetstream#8 | open | 23 (fixable 5) | 96 in 1 file | 37% | | napalm-vmware | NAPALM/napalm-vmware#7 | open | 4 (fixable 1) | 35 in 11 files | 97% | | napalm-windows | NAPALM/napalm-windows#4 | open | 0 (fixable 0) | 1 in 1 file | 96% | | napalm-yealink | NAPALM/napalm-yealink#4 | open | 11 (fixable 5) | 20 in 1 file | 42% | | napalm-zyxel | NAPALM/napalm-zyxel#8 | open | 13 (fixable 3) | 24 in 1 file | 69% | Also in the org, not yet in scope: napalm-vyos, napalm-s350, napalm-fortios, napalm-lancom (phase 5).
christianmanivong added the
prio
P3
enhancement
labels 2026-10-22 17:31:47 +00:00
Author
Owner

Found during the rollout (2026-10-23), not fixed in the adoption PRs

These are outside the standard's scope. Each one needs its own issue, or a decision.

A driver names its consumer (STANDARDS.md §3)

  • opnsense: writes the [netork] tag as the description of entries it creates. The ping job is called "netork ping sweep".
  • proxmox: creates /var/lib/vz/template/netork-images/netork-<key>-… and /tmp/_netork_hosts.
  • device-types (ssh_server) and linux: stage files through /tmp/netork-ssh.*, .netork-tmp and /tmp/netork-stage.*.
  • vmware: user-facing error texts name netOrk.
  • Many repos: comments and READMEs mention netOrk, netork#1167 or "NetOrk Authors" headers.

A failed read returns empty instead of raising (§3)

  • zyxel: _dal_query swallows every exception.
  • yealink: get_facts.
  • fritzbox: get_wan_status and get_facts.
  • sonos: all getters.
  • tplink: get_snmp_config reports an invented "public".

Policy in a driver

  • get_device_warnings in procurve, tplink and redfish.

Tests open sockets (§4)

  • fritzbox and sonos: napalm's NetworkDriver.__del__ calls is_alive() on a MagicMock connection, so the test makes a real TCP connect to fritz.box or 192.168.1.100 and waits 5 s per test.

Security-relevant

  • zyxel: fixed AES IV; ping() reports invented success; session.timeout has no effect, so requests run without a timeout.
  • TLS verify off by default: zyxel, yealink, procurve and officeconnect.
  • amt: a DTD in a UTF-16 answer slipped past the old <!DOCTYPE check. This is fixed in napalm-amt#2 with defusedxml, test first.

Contract and typing

  • sonos: get_playback_state and get_zone_info break the MediaDriver contract.
  • device-types: fingerprint attributes are declared as instance variables, while drivers declare them as ClassVar. This hits every strict driver (officeconnect).
  • Undeclared imports: proxmox yaml, redfish requests, zyxel cryptography.

Lowest-version floors (CI lowest job)

  • Unfloored dependencies resolved to unusable versions:
    • netaddr 0.3.1 (no IPAddress)
    • urllib3 1.21
    • napalm 0.10
    • redfish < 3.4.1
    • pyghmi 1.5.0
  • These are fixed in the PRs; openwrt got its netaddr floor afterwards.
## Found during the rollout (2026-10-23), not fixed in the adoption PRs These are outside the standard's scope. Each one needs its own issue, or a decision. **A driver names its consumer (STANDARDS.md §3)** - **opnsense:** writes the `[netork]` tag as the description of entries it creates. The ping job is called "netork ping sweep". - **proxmox:** creates `/var/lib/vz/template/netork-images/netork-<key>-…` and `/tmp/_netork_hosts`. - **device-types (`ssh_server`) and linux:** stage files through `/tmp/netork-ssh.*`, `.netork-tmp` and `/tmp/netork-stage.*`. - **vmware:** user-facing error texts name netOrk. - **Many repos:** comments and READMEs mention netOrk, `netork#1167` or "NetOrk Authors" headers. **A failed read returns empty instead of raising (§3)** - zyxel: `_dal_query` swallows every exception. - yealink: `get_facts`. - fritzbox: `get_wan_status` and `get_facts`. - sonos: all getters. - tplink: `get_snmp_config` reports an invented `"public"`. **Policy in a driver** - `get_device_warnings` in procurve, tplink and redfish. **Tests open sockets (§4)** - fritzbox and sonos: napalm's `NetworkDriver.__del__` calls `is_alive()` on a MagicMock connection, so the test makes a real TCP connect to `fritz.box` or 192.168.1.100 and waits 5 s per test. **Security-relevant** - **zyxel:** fixed AES IV; `ping()` reports invented success; `session.timeout` has no effect, so requests run without a timeout. - **TLS verify off by default:** zyxel, yealink, procurve and officeconnect. - **amt:** a DTD in a UTF-16 answer slipped past the old `<!DOCTYPE` check. This is **fixed in napalm-amt#2** with defusedxml, test first. **Contract and typing** - **sonos:** `get_playback_state` and `get_zone_info` break the MediaDriver contract. - **device-types:** fingerprint attributes are declared as instance variables, while drivers declare them as `ClassVar`. This hits every strict driver (officeconnect). - **Undeclared imports:** proxmox `yaml`, redfish `requests`, zyxel `cryptography`. **Lowest-version floors (CI `lowest` job)** - Unfloored dependencies resolved to unusable versions: - netaddr 0.3.1 (no `IPAddress`) - urllib3 1.21 - napalm 0.10 - redfish < 3.4.1 - pyghmi 1.5.0 - These are fixed in the PRs; openwrt got its netaddr floor afterwards.
Author
Owner

Release backlog on the single NAPALM runner (capacity 1, 30+ runs): duplicate main-push runs are cancelled where a tag run tests the same commit; raising the capacity is drafted as christianmanivong/infrastructure#52 (for an infrastructure session).

Release backlog on the single NAPALM runner (capacity 1, 30+ runs): duplicate main-push runs are cancelled where a tag run tests the same commit; raising the capacity is drafted as christianmanivong/infrastructure#52 (for an infrastructure session).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: NAPALM/driver-standard#2