netops-admin
Bounded, reversible changes to network devices: one object of a supported table per request, planned from a fresh snapshot and executed behind a rollback safeguard on the device itself.
This source tree targets netops-admin/v0.2.2 (2026-09-24) and pins netops-auditor==0.2.7 and netops-core==0.2.4; pip install netops-admin installs all three from PyPI. Version 0.1.0 was an unpublished internal milestone.
Start here: enrollment, policies and the new operations.
What it does
request (JSON) + configuration snapshot → netops-admin plan → plan (JSON)
plan + later snapshot → netops-admin verify → match | mismatch
request (JSON) + configured device → netops-admin apply → confirmed | reverted | rejected | unknown | revert-failed
agent → MCP admin_apply → the same operation as apply
configured device → netops-admin doctor → ready | the conditions that fail
request (JSON) + configured device → netops-admin preview → ready | rejected, with the plan
planvalidates the request against a table profile and the snapshot and either prints a plan or refuses with reasons. A plan holds the commands, the inverse commands, the predicted object state before and after, the prechecks that passed and digests binding it to the snapshot.verify --expect afterchecks that a snapshot taken after applying the commands holds exactly the predicted object and that nothing else in the evaluated scope changed.verify --expect beforechecks the same after applying the inverse.applyexecutes one request on a configured device: it installs a one-shot safeguard that would apply the inverse, applies the change, compares a new snapshot with the prediction, and removes the safeguard only when everything matches.doctorandpreviewonly read.doctorreports for one configured device every conditionapplydepends on - credentials, pinned host key, both identities, firmware and the tables measured on it, enrollment, leftover safeguards, the audit policy, audit export, notification, the journal and the budgets - asok,missing,refusedorskipped, without secrets.previewruns the same checks, planner, audit prediction and check-account read asapplyfor one request and returns the plan, the predicted object state and every reasonapplywould refuse it, a missing enrollment included. Neither installs a safeguard, writes a journal record or an audit event, blocks a device, counts against a budget or sends a notification; they only probe that the journal and the audit log are writable.applyplans again from a fresh snapshot.status,recover,notify-retry,unblockandundoare commands for a person: read an operation, settle one left running by an interruption, resend its notification, lift a device block after an investigation, and return a confirmed operation as a new operation behind a new safeguard.python -m netops_admin.mcp_serveroffers an agent four tools:admin_apply,admin_statusand the read-onlyadmin_previewandadmin_doctor. There is no tool to cancel a safeguard, unblock a device, undo a change or edit a plan.
Execution, the journal, the limits, the audit log, its export and the notification: docs/execution.md. Planning rules and refusals: docs/planning.md. Installation and configuration: docs/installation.md. Release process: docs/releasing.md.
Exit codes: 0 plan printed, snapshot matches, change confirmed, or preview or doctor ready, 1 snapshot does not match, 3 request refused or preview not ready, 4 change not confirmed, 5 doctor found the device not ready, 2 usage error.
Profiles
| Platform | Table | Firmware | Operations | Attributes | Safeguard |
|---|---|---|---|---|---|
| FortiOS | firewall address (ipmask) |
7.6.x; 8.0.0 build0167 | create, update, delete | subnet, comment |
automation stitch |
| FortiOS | firewall addrgrp (static) |
7.6.x | update | member list |
automation stitch |
| FortiOS | system dhcp server/reserved-address |
7.6.x | create, update, delete | ip, mac, description |
automation stitch |
| ExtremeXOS | vlan |
33.7.x | create, update, delete | tag (create), description |
UPM timer |
| ExtremeXOS | ports |
33.7.x | update | display-string |
UPM timer |
| ExtremeXOS | vlan-membership |
33.7.x | update | tagged list, untagged VLAN |
UPM timer |
Every device and build requires a successful operator enrollment before writing. The new FortiOS profiles were measured on 7.6.7 build3704; EXOS profiles on 33.7.1.6.
Example
{
"table": "firewall address",
"op": "create",
"key": "web-01",
"changes": {"subnet": "192.0.2.10/32", "comment": "web server"},
"reason": "new web server",
"user_request": "add an address object for the new web server",
"request_id": "change-0001"
}
netops-admin plan --platform fortios --snapshot before.conf --request request.json > plan.json
netops-admin apply --config admin.json --device fw-lab --request request.json
netops-admin undo --config admin.json --change-id <change_id> --reason "what was investigated"
An ExtremeXOS configuration does not state its firmware, so plan needs --firmware 33.7.1.6 there; a FortiOS snapshot must carry its #config-version header.
Known limits
- The tool cannot know that a person wrote
user_request: the agent fills it in. An agent misled by text read from a device can request a valid, unwanted change inside the allowed scope, and the safeguard will not return it because the change verifies. The defences are the narrow scope, protected objects, the immediate notification andundo. - Before writing, the predicted snapshot must pass the auditor and operator policy. Before confirming, a second, read-only account reads the object and the auditor evaluates its rules on the new snapshot. The check account uses the same management path as the write account and checks configuration, not traffic.
- On FortiOS the safeguard needs an access profile with
admin read-write, with which the write account can create another administrator and edit an administrator whose profile its own contains, such as the check account. The write account therefore has to see exactly the configured accounts, and a fingerprint of their entries has to stay unchanged between operations and during a change; otherwise the device is refused and blocked. - A privileged write account can remove the safeguard itself. The release does not protect against a compromised executor.
- One admin host, one operation at a time per server, one object per request. Each device query is its own SSH connection.
- Profiles are fixed schemas, not schemas learned from a device. Enrollment tests the rollback path on each build inside the permitted family; it does not prove every possible configuration combination.
- The audit log records the lengths of the reason and of the user request, never their text: it proves that a request was made and what was changed, not what the person wrote.
- The notification carries the result, the operation and the number of differences, not the differences themselves.
- The tool does not restrict its own network egress; the admin host has to be limited by the deployment.
- Another administrator logged in to the device is recorded and notified, not refused.
- The branch that refuses to confirm when too little time is left before the safeguard fires is covered by tests only.
Development
python -m pytest -q
python scripts/check_gates.py
Tests import the parsers from ../netops-auditor/src and the transport from ../netops-core/src and simulate the devices; they never contact one. The MCP tests need fastmcp from requirements-mcp.txt and are skipped without it. The gate keeps the planning modules free of any import that could reach a device, allows the device access layer only the core transport and the auditor collector, refuses programs started from the package, compares the version in pyproject.toml, the package and the SBOM, and scans every released file for private material.
Release files for netops-admin 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| netops_admin-0.2.2.tar.gz | 77.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| netops_admin-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 139.2 kB
Release files / netops_admin-0.2.2.tar.gz
| Download URL | netops_admin-0.2.2.tar.gz |
|---|---|
| Size | 77.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a7832257ca90c60a18c433f3a8b4a7af5f577a9d40256e248048f1356744482f
|
|
BLAKE2b-256 checksum How to use checksums |
aac7fd17c77dbfbc3292b9104305104a0a01326130e834e67c0e191cd541b8a6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / netops_admin-0.2.2-py3-none-any.whl
| Download URL | netops_admin-0.2.2-py3-none-any.whl |
|---|---|
| Size | 61.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0522162309872ce5b1c0732d1aacd9aa0e58e4527e9c58490f8189e8ca5db67b
|
|
BLAKE2b-256 checksum How to use checksums |
d924e7e9814ad18e5f21d44feb14e07fa439777d8273f84c6c1c595d2314eb51
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency log