driver / standard (pull_request) Successful in 56s
driver / lint (pull_request) Successful in 49s
driver / types (pull_request) Failing after 1m6s
driver / test (3.10) (pull_request) Failing after 5m48s
driver / test (3.11) (pull_request) Failing after 3m11s
driver / test (3.12) (pull_request) Successful in 2m48s
driver / test (3.13) (pull_request) Successful in 4m16s
driver / lowest (pull_request) Successful in 4m47s
driver / security (pull_request) Successful in 6m8s
driver / build (pull_request) Failing after 52s
CI / driver (pull_request) Failing after 30m42s
driver / publish (pull_request) Skipped
- CI moves to .gitea/workflows/ci.yml and calls the shared driver workflow of NAPALM/driver-standard; napalm-device-types comes from git until it is on PyPI. - requires-python >=3.10 (napalm-device-types needs it), LICENSE file, py.typed, SPDX license string, links to git.netork.io. - mypy strict for the package; napalm_linux.linux is exempt for now (21 errors), recorded in the quality baseline with its long functions and the 2200-line module. Coverage floor 58 % (measured 58.23 %).
170 lines
9.4 KiB
Markdown
170 lines
9.4 KiB
Markdown
# Changelog
|
||
|
||
All notable changes to this project will be documented in this file.
|
||
|
||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||
|
||
## [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. The package now ships `py.typed`
|
||
and a LICENSE file. **Python 3.9 is no longer supported**; napalm-device-types never
|
||
ran on it.
|
||
- Exceptions the driver deliberately ignores (the PTY width at login, closing a dead
|
||
session, unreadable route lines, the snmpd.conf community and port) are now logged
|
||
at debug level.
|
||
|
||
### Added
|
||
- `get_host_firewall()` (napalm-device-types' `HostFirewallMixin`, NetOrk/netork#1344): the host's own netfilter rules — `nft -j list ruleset`, with the tables iptables manages taken from `iptables-save` — as chains and rules in one shape. Read-only, as root, on an exec channel (the nft JSON is one long line). Requires napalm-device-types 4.21.0; version 0.13.0.
|
||
- `get_service_packages()` (napalm-device-types' `ServicePackagesMixin`, NetOrk/netork#1236): which installed packages each systemd service is made of — the one shipping its unit file and the one shipping its `ExecStart` binary. Read-only, on an exec channel under `sh`, without sudo. Requires napalm-device-types 4.20.0; version 0.12.0.
|
||
|
||
### Security
|
||
- The SSH host key is verified (NetOrk/netork#1167). `open()` hands netmiko the key the caller expects for the port in `optional_args["ssh_host_keys"]` (as a `known_hosts` file that exists only while it connects, with `ssh_strict`), so any other key is refused before the login (`SshHostKeyMismatch`); without one netmiko accepts the first key. Every key seen goes to `optional_args["ssh_host_key_observer"]`. OpenMediaVault and QNAP get this through `LinuxDriver.open()`. Requires napalm-device-types 4.19.0; version 0.11.0.
|
||
|
||
### Changed
|
||
- **Breaking:** `get_device_warnings` is gone, and with it the `apt_proxy_url` argument.
|
||
The driver reports facts and the application names warnings (napalm-device-types 4.14):
|
||
`get_package_proxy()` says which proxy apt fetches through; pending updates were always
|
||
in `get_available_updates()`. Requires napalm-device-types 4.14.0; version 0.9.0.
|
||
|
||
### Changed
|
||
|
||
- **Breaking:** `run_device_action` is gone, with `fix_snmp`, `fix_apt_proxy`,
|
||
`fix_docker_permissions` and the unused `apt_update_upgrade`. The driver implements
|
||
napalm-device-types 4.13's fix templates instead, and the caller supplies every value:
|
||
`configure_snmp_agent(settings)` (one `rocommunity` line per allowed source, udp/161
|
||
opened in ufw or iptables for those sources only, each step judged by its exit
|
||
status), `configure_package_proxy(url)`, `grant_container_engine_access(user)` and
|
||
`ensure_package(name)`. No community, contact, location or address of an application
|
||
is built in any more. Requires napalm-device-types 4.13.0 or later; version 0.8.0.
|
||
- The sudo hint names no application's settings.
|
||
|
||
### Fixed
|
||
|
||
- The type annotations resolve: `Dict`, `List` and `Optional` were used without an
|
||
import (#29).
|
||
|
||
### Added
|
||
|
||
- `get_system_identity()` (napalm-device-types 4.9 `SystemIdentityMixin`): the host's
|
||
SMBIOS system UUID, product serial and board serial, read as root on an exec channel,
|
||
vendor placeholders empty. netOrk matches a server to its BMC on these. Requires
|
||
napalm-device-types 4.9.0 or later; version 0.7.0.
|
||
|
||
### Changed
|
||
|
||
- Requires napalm-device-types 4.7.1 or later; version 0.6.0.
|
||
- **Breaking:** `get_users()` is now `get_os_users()`, following napalm-device-types
|
||
4.7, which renamed `OSDriver.get_users` because NAPALM's own `get_users` has
|
||
another shape. The return value is unchanged (a list of `UserDict`).
|
||
`get_users()` is NAPALM's again and raises `NotImplementedError`.
|
||
|
||
### Fixed
|
||
|
||
- Listing updates on yum hosts (RHEL 7, CentOS 7) no longer fails with
|
||
napalm-device-types 4.7: its `parse_dnf_security` needs the `__DNF_RC=<status>`
|
||
line `DNF_SECURITY_COMMAND` prints, and the yum security query had none, so it
|
||
raised `ValueError`. The yum query now prints that marker the same way
|
||
(`{ ...; echo __DNF_RC=$?; } | cat`). A yum or dnf security query that failed,
|
||
or whose output was cut short before the marker, still leaves `security` unknown
|
||
(`None`) instead of reporting no advisories.
|
||
|
||
### Security
|
||
|
||
- `run_command(privileged=True, stdin=...)` raises `ValueError` while a sudo
|
||
password is set. `sudo -S` reads the password from stdin, and a sudo that does
|
||
not prompt (NOPASSWD, a cached timestamp) left it for the command, which read
|
||
it as the first line of the data: netOrk wrote it into a file that way
|
||
(NetOrk/netork#1029). Stage the data without privilege and have root install
|
||
that file. Without a sudo password (`sudo -n`) or for a root login, stdin
|
||
still goes to the command.
|
||
- The sudo password is no longer typed into the interactive shell
|
||
(NetOrk/netork#1039). Every privileged command ran there as
|
||
`echo '<password>' | sudo -S -p "" <command>`: bash kept it in its history,
|
||
so each poll wrote the password into the login user's `~/.bash_history`, and
|
||
while the command ran it was in the process list for every local user.
|
||
Privileged commands (`_sudo`, `_sudo_status`, and `_run_privileged` with a
|
||
sudo password) now run on an exec channel like `run_command(privileged=True)`:
|
||
the password reaches `sudo -S` on stdin, there is no PTY to echo it, and the
|
||
whole command runs as root in one `sh -c` (before, only the part up to the
|
||
first `;`, `&&` or `|` did, so `mv … && chown root:root …` failed its chown).
|
||
The interactive session also switches its history off before its first
|
||
command (` unset HISTFILE; set +o history`). **History files written before
|
||
this version may still hold the sudo password**: remove those lines from the
|
||
login user's `~/.bash_history` on your hosts and consider changing the
|
||
password. `_sudo_status` takes the exit status from the channel; it is `None`
|
||
only when the channel closed without one.
|
||
- The snmpd and apt proxy fixes no longer stage their files at a fixed path in
|
||
/tmp (`/tmp/netork_snmpd.conf`, `/tmp/netork_00proxy`) and then `mv`,
|
||
`chown` and `chmod` them as root. Another local user could create that path
|
||
first as a symlink, for example to `/etc/shadow`, and root's `chown`/`chmod`
|
||
followed it. The content now goes to a fresh `mktemp` file under `umask 077`,
|
||
written without privilege, and root `install`s it as a new file owned by root
|
||
(mode 644) next to the target and renames it into place
|
||
(`_install_file_as_root`). Nothing runs as root when staging failed.
|
||
- `get_vpn_tunnels()` without a sudo password no longer writes `wg show all dump`
|
||
(which includes the interfaces' private keys) to the predictable
|
||
`/tmp/.netork_wg_<hash>`; the dump comes straight from the exec channel.
|
||
|
||
## [0.4.0] – 2026-10-08
|
||
|
||
### Added
|
||
|
||
- `get_virtual_ips()` through napalm-device-types' `VirtualIpsMixin` (4.2.0): the
|
||
addresses vip-manager and keepalived configuration lets float onto this host,
|
||
whether or not it holds them right now (NetOrk/netork#829). The command goes on
|
||
the exec channel (`run_command`): with its awk filter it is about 4 kB, past the
|
||
line the PTY reliably takes. Root first, then without it.
|
||
|
||
## [0.3.0] – 2026-10-08
|
||
|
||
### Removed
|
||
|
||
- `get_docker_info()`, `get_docker_outdated()`, `reconstruct_docker_run()` and
|
||
the `_docker_bin()` hook, with the image-ID helpers they used. netOrk reads
|
||
and handles containers itself over the Engine API, through
|
||
`open_container_engine()` (NetOrk/netork#765), and no longer calls them.
|
||
`run_device_action("fix_docker_permissions")` stays: letting the login user
|
||
use Docker is an OS action.
|
||
|
||
## [0.2.0] – 2026-10-07
|
||
|
||
### Added
|
||
|
||
- `run_command()` and `open_stream()`, the public command channel from
|
||
napalm-device-types 2.6.0: an exec channel on the existing SSH transport, so
|
||
no PTY, separate stderr and a real exit code. `privileged=True` runs as root
|
||
directly, through `sudo -S` with the password on stdin (never on the command
|
||
line), or through `sudo -n`, which fails instead of prompting.
|
||
- `ContainerEngineMixin`: `container_engines()` and `open_container_engine()`,
|
||
whose `open_api()` streams the Docker Engine API over `docker system
|
||
dial-stdio` (NetOrk/netork#765). The existing Docker methods are unchanged.
|
||
|
||
### Changed
|
||
|
||
- Requires napalm-device-types >= 2.6.0.
|
||
|
||
## [0.1.0] – 2026-05-29
|
||
|
||
### Added
|
||
|
||
- Initial release
|
||
- `LinuxDriver` inheriting from `napalm_device_types.OSDriver`
|
||
- SSH transport via Netmiko `linux` device type
|
||
- Auto-detection of package manager: `apt`, `dnf`, `yum`, `apk`, `pacman`
|
||
- Standard NAPALM methods: `get_facts()`, `get_interfaces()`, `get_interfaces_ip()`,
|
||
`get_arp_table()`, `get_config()`, `ping()`
|
||
- OS-specific methods: `get_packages()`, `get_pending_updates()`, `apply_updates()`,
|
||
`get_services()`, `get_users()`, `get_processes()`, `get_cron_jobs()`
|
||
- `apply_updates()` validates all package names against `^[a-zA-Z0-9_\-\+\.]+$`
|
||
to prevent shell injection before passing them to the package manager
|
||
- SysV fallback for `get_services()` on non-systemd systems
|
||
- Unit tests with mocked SSH connections
|
||
|
||
[Unreleased]: https://github.com/chrismanivong/napalm-linux/compare/v0.1.0...HEAD
|
||
[0.1.0]: https://github.com/chrismanivong/napalm-linux/releases/tag/v0.1.0
|