Skip to main content

Multi-vendor network config translator with a verifiable cross-vendor audit

Project description

Netcanon

Multi-vendor network config translator with a verifiable cross-vendor audit.

Translates running-config between Cisco IOS-XE, Juniper Junos, Aruba AOS-S, Arista EOS, Fortinet FortiGate, MikroTik RouterOS, and OPNsense. You point Netcanon at a config from one vendor and it renders the equivalent config for another — through a shared canonical model, with every translatable field declared as supported, lossy, or unsupported.

What sets it apart is the audit underneath. Every supported vendor pair × every field gets classified into one of eight variance classes (ALIGNED / CODEC_BUG / EXPECTED_LOSSY / EXPECTED_UNSUPPORTED / METHODOLOGY_ISSUE_under / METHODOLOGY_ISSUE_over / STRUCTURAL_ONLY / TRIVIAL_EMPTY). The cross-mesh audit catches silent translation errors — the kind that produce output that looks valid but quietly drops or transforms a field — before they ship.


See it in 10 seconds

docker run --rm ghcr.io/netcanon/netcanon:latest python tools/demo.py --pair cisco__junos

Paste this:

hostname leaf-01
!
vlan 10
 name DATA
!
interface GigabitEthernet0/0/0
 description Uplink to spine
 switchport access vlan 10
!
ip route 0.0.0.0 0.0.0.0 192.168.1.1

Get this:

set system host-name leaf-01
set interfaces GigabitEthernet0/0/0 description "Uplink to spine"
set vlans DATA vlan-id 10
set routing-options static route 0.0.0.0/0 next-hop 192.168.1.1

Same canonical pipeline drives the HTTP API and the browser UI. Run python tools/demo.py --list to see all four embedded scenarios (Cisco→Junos, FortiGate→MikroTik, Aruba→Arista, OPNsense→Junos).


The trust signal — and the invitation

Across every supported vendor pair × every field declared as supported, the cross-mesh audit holds zero CODEC_BUG cells. That's not "we think it works"; that's every cell that should translate, does, by automated test against vendor-doc-grounded expectations.

The honest follow-up: the audit only covers cells we have fixtures for. Real-world configs exercise paths the synthetic fixtures haven't reached — and that's where you come in. If you have a running-config that translates wrong (or doesn't translate at all), that's the highest-impact bug report this project can receive. See BUG_REPORTING.md for the workflow — Netcanon ships its own sanitiser (netcanon sanitize ...) so you never paste real WAN IPs, hashes, or hostnames into a public issue.

For the full audit narrative + the variance-class taxonomy, see docs/HOW_WE_TEST.md.


Install

Docker (recommended)

docker run --rm -p 8000:8000 \
    -v $(pwd)/configs:/app/configs \
    -v $(pwd)/data:/app/data \
    ghcr.io/netcanon/netcanon:latest
# -> http://127.0.0.1:8000        (UI)
# -> http://127.0.0.1:8000/docs   (Swagger)
# -> http://127.0.0.1:8000/health (health probe)

configs/ is where backed-up running-configs land; data/ holds device profiles, schedules, and job state. Don't bind-mount definitions/ — those YAMLs are baked into the image as tracked content; mounting an empty host directory over them will crash startup.

The published image is signed via Sigstore (cosign verify ghcr.io/netcanon/netcanon ...) with an SBOM attestation.

Docker Hub mirror — same image, convenience-mirrored to Docker Hub if your tooling defaults to docker.io:

docker run --rm -p 8000:8000 netcanon/netcanon:latest

The Docker Hub mirror has the same image bytes but no cosign signature or SBOM attestation — operators in regulated environments should pull from GHCR for the attested provenance chain. See SECURITY.md for the supply-chain story.

Pip

pip install netcanon
uvicorn netcanon.main:app --host 127.0.0.1 --port 8000

netcanon also installs the netcanon CLI — netcanon sanitize -i my-config.txt --source-vendor cisco_iosxe_cli --dry-run is the typical entrypoint for the bug-reporting workflow.

Desktop (Windows)

Download the MSI from Releases, or from source:

pip install -e ".[desktop]"
python -m netcanon_desktop

The desktop shell runs the same FastAPI app inside a PySide6 webview with a tray icon — same UI, no command-line.


Walkthroughs — "is this the right tool for my migration?"

Each walkthrough is paired 1:1 with a runnable demo scenario. Read the narrative first, run python tools/demo.py --pair <key> to see the actual translation.

Walkthrough Demo scenario Frame
Cisco IOS-XE → Juniper Junos cisco__junos DC leaf migration: VLANs + interfaces + routes
FortiGate → MikroTik RouterOS fortigate__mikrotik Branch-firewall consolidation: DNS + interfaces + DHCP pools
Aruba AOS-S → Arista EOS aruba__arista Switch refresh: VLAN-centric → port-centric grammar
OPNsense → Juniper Junos opnsense__junos Edge-firewall migration with explicit Tier-3 boundary

Each walkthrough ends in a manual-review checklist — what to verify on the device after the rendered config lands, before you apply it.


What translates, and what doesn't

The canonical model classifies every field by semantic stability across vendors. Full per-codec matrix is in docs/CAPABILITIES.md; the short version:

  • Tier 1 — auto-translatable. hostname, interfaces (name / description / enabled state / IPv4 + IPv6 addresses / per-interface VRF binding), VLANs, static routes, DNS / NTP / syslog servers, timezone. Every shipped codec parses + renders these fully.
  • Tier 2 — translatable with caveats. SNMP (incl. SNMPv3 USM), LAGs, local users, RADIUS, DHCP server pools, VXLAN VNIs, EVPN type-5 routes, routing instances / VRFs, Junos apply-groups. Hashes that the target's CLI cannot consume surface as commented review lines, never as plaintext fallback.
  • Tier 3 — opaque carry / never auto-rendered. Firewall rules, NAT, IPsec / OpenVPN / WireGuard, QoS, route-maps, dynamic routing protocol stanzas, PKI. These are vendor-specific stateful policy that doesn't translate cross-vendor cleanly — Netcanon detects them, surfaces them via the migrate-page banner with a count and section names, and deliberately doesn't auto-render. Hand-build them natively on the target.

If your migration's primary need is firewall translation, docs/COMPARISON.md names adjacent tools (Capirca / Aerleon) that handle that scope. Netcanon is the right tool for the router portion of a migration — and explicitly the wrong tool to claim it does the firewall portion.


Two concerns, one app

Netcanon co-hosts:

  1. Backup — pulls running-config (or vendor equivalent) from network devices over SSH / NETCONF / REST and stores it verbatim in configs/<hostname>.<ext>. Runs on a schedule or on demand.
  2. Migration — translates a stored backup from one vendor's config grammar to another through the canonical intent tree.

Same FastAPI process; same UI; same Docker image. Use whichever half (or both). See ARCHITECTURE.md for the four-layer design.


Found a bug? Got a config that breaks it?

That's the contribution this project values most. Workflow:

  1. Sanitise your config with netcanon sanitize — strips hostnames, IPs, hashes, certs, SNMP communities, etc., with a counter-per- session stable substitution table you can audit before submission.
  2. Open a bug report or fixture submission.
  3. The fixture lands in tests/fixtures/real/<vendor>/, the cross-mesh audit re-runs, and the variance class your fixture surfaces gets a row in tests/fixtures/real/PHASE4_RECONCILIATION.md.

Full workflow is in BUG_REPORTING.md.


For contributors

You want to… Start here
Understand the architecture ARCHITECTURE.md — four-layer model, canonical bridge, codec types
Follow the contributor rules AGENTS.md — hard rules, parity checklist, gotchas
Read the slower-changing methodology docs/METHODOLOGY.md — matrix-honesty discipline distilled, portable to other projects
Look up project jargon docs/glossary.md — canonical, codec, mesh, ship-before-wire, target profile
Read the canonical model overview netcanon/migration/canonical/README.md
Add or change an HTTP route netcanon/api/routes/README.md — frozen pipeline-stage signatures, endpoint inventory
Add a new codec netcanon/migration/codecs/README.md
Add a new device definition / target profile definitions/README.md
Add a new canonical field docs/adding-a-canonical-field.md
Ship a feature across web + desktop docs/feature-parity-walkthrough.md
See what's shipped recently CHANGELOG.md
Check codec certification tiers tests/fixtures/real/RESULTS.md
Manually exercise recent changes HUMAN_TESTING.md
Write tests tests/README.md
Review the security model SECURITY.md

Run the test suite

pip install -e ".[dev]"
pytest                       # unit + integration + desktop (fast)
pytest -m e2e                # Playwright browser tests (slower)

Tests run across four layers: unit (pure functions, no I/O — the real-capture validation harness lives here as a unit subset), integration (TestClient + mocked SSH at the get_collector factory), e2e (Playwright against a live Uvicorn), and desktop (PySide6 + pystray mocked). CI runs the full matrix on Python 3.11 / 3.12 / 3.13 against Ubuntu. CI output is the source of truth for pass counts.

Layout

netcanon/              FastAPI application (shared by both platforms)
 ├── api/routes/          HTTP endpoints
 ├── collectors/          SSH/NETCONF/REST fetchers — one factory,
 │                        one mock-point (`get_collector`)
 ├── migration/           Cross-vendor translation pipeline
 │   ├── canonical/         CanonicalIntent model + shared transforms
 │   └── codecs/            Per-vendor parse/render implementations
 ├── services/            Plain-function orchestrators (pipeline, detect, …)
 ├── storage/             FileConfigStore
 ├── tools/               sanitize, etc.
 └── templates/           Jinja2 templates (every interactive element
                          carries a data-testid — see AGENTS.md)

netcanon_desktop/      Windows tray/webview shell around the same server
definitions/            Device definition YAMLs
tools/demo.py           One-command cross-vendor translation demo
docs/walkthroughs/      Narrative migration walkthroughs (paired with demo)
docs/vendors/           Per-vendor "what works for me?" pages
tests/unit/             Pure-function tests, no I/O
tests/integration/      FastAPI TestClient tests, SSH mocked
tests/e2e/              Playwright browser tests
tests/desktop/          PySide6/pystray-mocked desktop shell tests
tests/fixtures/real/    Real-capture validation corpus (see RESULTS.md)

License

MIT. See LICENSE. Third-party fixtures keep their upstream licences — see tests/fixtures/real/NOTICE.md for provenance.

For responsible disclosure of security issues, see SECURITY.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

netcanon-0.1.0rc5.tar.gz (3.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

netcanon-0.1.0rc5-py3-none-any.whl (625.6 kB view details)

Uploaded Python 3

File details

Details for the file netcanon-0.1.0rc5.tar.gz.

File metadata

  • Download URL: netcanon-0.1.0rc5.tar.gz
  • Upload date:
  • Size: 3.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for netcanon-0.1.0rc5.tar.gz
Algorithm Hash digest
SHA256 3aca67c1b660fca90b144f0ee03eda9f0e6f4b7299b1e5f23c709bf5a0ae7e12
MD5 22ae7f64c617290a8b8903a4db55fe4f
BLAKE2b-256 69441fe66a91dd2742f3f557e3017a84ee2cedc81870f264c06bed39608bb357

See more details on using hashes here.

Provenance

The following attestation bundles were made for netcanon-0.1.0rc5.tar.gz:

Publisher: pypi-publish.yml on netcanon/netcanon

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file netcanon-0.1.0rc5-py3-none-any.whl.

File metadata

  • Download URL: netcanon-0.1.0rc5-py3-none-any.whl
  • Upload date:
  • Size: 625.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for netcanon-0.1.0rc5-py3-none-any.whl
Algorithm Hash digest
SHA256 5fa9bc84826bd658b2d877931c5ae42f746109d7cee1ea155ff22d1390becdce
MD5 19c4ab78be47a64894afa56d191be67c
BLAKE2b-256 11aca6d575212b103a268145cce75a218f19fa5e5e119c6aa4c8710afd545a23

See more details on using hashes here.

Provenance

The following attestation bundles were made for netcanon-0.1.0rc5-py3-none-any.whl:

Publisher: pypi-publish.yml on netcanon/netcanon

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page