Skip to content

Commit a2e323f

Browse files
RobarePruynclaude
andcommitted
Initial scaffold: catalog data + Rust core stubs + Python bindings
Bootstrap repository with research-grade catalog YAML for 7 vendors (Cisco IOS-XE/NX-OS, Aruba AOS-CX, Juniper Junos, Arista EOS, HPE ProCurve, Cisco Meraki MS) covering 25 abstract command types each. Catalog data was produced by Mediacast NetCaster's 2026-04 vendor doc-crawl effort (parallel research agents over vendor command refs + YANG repos + community sources). Every entry cites its source. Rust core scaffolds: - Catalog::load_bundled / load_dir - FirmwareVersion parser (handles Aruba FL./GL., Cisco 9.3(5), Junos R3-S2) - VersionRange w/ >=, <, , (AND), || (OR), * + most-specific-wins - CommandType enum (25 variants) + lookup pipeline PyO3 bindings under mediacast_netcatalog._native (feature: python). Stub probe CLI (feature: bin) — implementation lands in v0.2. CI: cargo fmt+clippy+test on stable/MSRV across Linux/macOS/Windows; maturin wheel build on Python 3.9+3.12; yamllint on catalog/. Dual-licensed MIT OR Apache-2.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 parents  commit a2e323f

32 files changed

Lines changed: 10398 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
RUSTFLAGS: "-D warnings"
12+
13+
jobs:
14+
rust:
15+
name: Rust ${{ matrix.toolchain }} on ${{ matrix.os }}
16+
runs-on: ${{ matrix.os }}
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
os: [ubuntu-latest, macos-latest, windows-latest]
21+
toolchain: [stable, "1.78"]
22+
steps:
23+
- uses: actions/checkout@v4
24+
- uses: dtolnay/rust-toolchain@master
25+
with:
26+
toolchain: ${{ matrix.toolchain }}
27+
components: rustfmt, clippy
28+
- uses: Swatinem/rust-cache@v2
29+
- name: Format check
30+
run: cargo fmt --all -- --check
31+
- name: Clippy
32+
run: cargo clippy --all-targets --no-default-features -- -D warnings
33+
- name: Build (default features)
34+
run: cargo build --no-default-features
35+
- name: Test (default features)
36+
run: cargo test --no-default-features
37+
- name: Build (bin feature)
38+
run: cargo build --no-default-features --features bin
39+
- name: Run example
40+
run: cargo run --example basic_lookup --no-default-features
41+
42+
python:
43+
name: Python wheel build
44+
runs-on: ${{ matrix.os }}
45+
strategy:
46+
fail-fast: false
47+
matrix:
48+
os: [ubuntu-latest, macos-latest, windows-latest]
49+
python-version: ["3.9", "3.12"]
50+
steps:
51+
- uses: actions/checkout@v4
52+
- uses: actions/setup-python@v5
53+
with:
54+
python-version: ${{ matrix.python-version }}
55+
- uses: dtolnay/rust-toolchain@stable
56+
- uses: Swatinem/rust-cache@v2
57+
- name: Install maturin
58+
run: pip install "maturin>=1.5,<2.0"
59+
- name: Build wheel
60+
run: maturin build --release --features python --out dist
61+
- name: Install built wheel
62+
shell: bash
63+
run: pip install --no-index --find-links dist mediacast-netcatalog
64+
- name: Smoke test bindings
65+
run: |
66+
python -c "from mediacast_netcatalog._native import Catalog; c = Catalog.load_bundled(); print(c.vendors())"
67+
68+
yaml-lint:
69+
name: Catalog YAML lint
70+
runs-on: ubuntu-latest
71+
steps:
72+
- uses: actions/checkout@v4
73+
- uses: actions/setup-python@v5
74+
with:
75+
python-version: "3.12"
76+
- name: Install yamllint
77+
run: pip install yamllint
78+
- name: Lint catalog/
79+
run: yamllint -d "{extends: relaxed, rules: {line-length: disable}}" catalog/

.gitignore

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Rust
2+
/target/
3+
**/*.rs.bk
4+
Cargo.lock
5+
6+
# Python / maturin
7+
__pycache__/
8+
*.py[cod]
9+
*$py.class
10+
*.so
11+
.Python
12+
build/
13+
develop-eggs/
14+
dist/
15+
eggs/
16+
.eggs/
17+
sdist/
18+
wheels/
19+
*.egg-info/
20+
*.egg
21+
.venv/
22+
venv/
23+
.pytest_cache/
24+
.mypy_cache/
25+
.ruff_cache/
26+
27+
# Editors
28+
.vscode/
29+
.idea/
30+
*.swp
31+
*.swo
32+
.DS_Store
33+
34+
# Maturin output
35+
target/wheels/
36+
37+
# Local-only secrets / credentials (catalog itself ships clean)
38+
.env
39+
.env.local
40+
secrets/
41+
42+
# Coverage
43+
coverage/
44+
*.lcov
45+
htmlcov/
46+
.coverage
47+
48+
# Generated docs
49+
/docs/_build/

CHANGELOG.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
## [0.1.0] — 2026-04-29
11+
12+
### Added
13+
14+
- Initial release. Repository scaffold + research-grade catalog data layer.
15+
- Catalog YAML for seven vendors:
16+
- Cisco IOS / IOS-XE (`catalog/cisco-ios-xe.yaml`)
17+
- Cisco NX-OS (`catalog/cisco-nxos.yaml`)
18+
- Aruba AOS-CX (`catalog/aruba-aoscx.yaml`)
19+
- Juniper Junos (`catalog/juniper-junos.yaml`)
20+
- Arista EOS (`catalog/arista-eos.yaml`)
21+
- HPE / Aruba ProCurve (`catalog/hpe-procurve.yaml`)
22+
- Cisco Meraki MS (`catalog/meraki-mx-ms.yaml`)
23+
- 25 abstract command types covered per vendor (see `catalog/COMMAND_TYPES.md`).
24+
- Schema documented in `catalog/SCHEMA.md` with extensions for eAPI,
25+
vendor-proprietary REST, SNMP, and cloud Dashboard API.
26+
- Cross-vendor synthesis in `catalog/FINDINGS.md`.
27+
- Rust core scaffold:
28+
- `Catalog::load_bundled` + `Catalog::load_dir`
29+
- `FirmwareVersion` parser handling Aruba family prefixes (`FL.`, `GL.`,
30+
etc.), Cisco-style parens (`9.3(5)`), Junos suffixes (`R3-S2.4`)
31+
- `VersionRange` with `>=`, `<`, `,` (AND), `||` (OR), `*` (wildcard)
32+
and most-specific-wins matching
33+
- PyO3 bindings under `mediacast_netcatalog._native` (feature `python`).
34+
- Stub `mediacast-netcatalog probe` CLI binary (feature `bin`).
35+
- CI: cargo fmt + clippy + test on stable/MSRV across Linux/macOS/Windows;
36+
maturin wheel build + smoke test on Python 3.9 + 3.12; yamllint on catalog.
37+
38+
### Provenance
39+
40+
- Catalog data produced by [Mediacast NetCaster](https://github.com/Mediacastnet)'s
41+
2026-04 vendor doc-crawl effort: seven parallel research agents over vendor
42+
command references, YANG model repos, and community sources. Every entry
43+
cites its source in the `sources:` block.
44+
45+
### Known limitations
46+
47+
- Probe implementation is a stub. v0.2 wires up NETCONF/gNMI/RESTCONF/SSH
48+
fingerprints.
49+
- API is unstable. Expect breaking changes before v0.2.
50+
- Catalog entries marked `unverified: true` are heuristic and want validation
51+
against real gear.
52+
53+
[Unreleased]: https://github.com/Mediacastnet/mediacast-netcatalog/compare/v0.1.0...HEAD
54+
[0.1.0]: https://github.com/Mediacastnet/mediacast-netcatalog/releases/tag/v0.1.0

CONTRIBUTING.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Contributing to mediacast-netcatalog
2+
3+
Thanks for your interest. This project is **research-grade data + a Rust
4+
crate** maintained by [Mediacast Network Solutions](https://github.com/Mediacastnet).
5+
First production consumer is our own [NetCaster](https://github.com/Mediacastnet/netcaster);
6+
that biases what we accept, but the project is genuinely open and high-value
7+
contributions from outside the venue-network space are welcome.
8+
9+
## What we want
10+
11+
### Catalog contributions (highest value)
12+
13+
- **New vendor catalogs**. Extreme, FortiSwitch, MikroTik, Brocade/RUCKUS,
14+
Dell EMC, Edgecore, Cumulus/SONiC. Aim for ≥80% of the 25 abstract command
15+
types. Cite vendor docs in the `sources:` block.
16+
- **Firmware-version drift entries** for vendors already covered. If you
17+
hit an output-format change between firmware revisions on a vendor we
18+
ship, send a PR adding a `versions:` block + sample output.
19+
- **Real-gear validation**. Take an entry marked `unverified: true`, run it
20+
against actual hardware, capture the real output, and PR a fix that
21+
removes the flag.
22+
23+
### Crate contributions
24+
25+
- **Probe protocol additions**. v0.1 stubs NETCONF/gNMI/RESTCONF/SSH;
26+
IPMI, ONIE, SONiC discovery would round it out.
27+
- **Version-matcher edge cases**. If your vendor's firmware string format
28+
doesn't parse cleanly, send a failing test + the fix.
29+
- **Performance**. Catalog loading is `O(files)`, lookup is `O(versions
30+
blocks)`. If you're driving high volume and have a profile, send a PR.
31+
32+
### What we don't want
33+
34+
- Drive-by formatting or rename PRs.
35+
- New abstract command types without a real-world consumer requesting them.
36+
The 25 we have were extracted from a working codebase; new ones need the
37+
same provenance.
38+
- Refactors that don't fix anything.
39+
40+
## Catalog YAML conventions
41+
42+
See `catalog/SCHEMA.md` for the full spec. Quick rules:
43+
44+
- Every entry **must** cite its source. URL + access date in the
45+
`sources:` block, or per-version `notes:` if the source is the same as
46+
another entry.
47+
- `cli` is a single line. Multi-line composite commands (Junos `configure
48+
→ set → commit`) use a multi-line YAML string with one CLI command per
49+
line.
50+
- `applies_to` is a SemVer-flavored range. See the schema doc for the
51+
recognized syntax.
52+
- For commands the vendor genuinely doesn't expose, set `cli:
53+
"NOT_SUPPORTED"` and document why in `notes`.
54+
- Mark `unverified: true` if the data was extracted from heuristic /
55+
community sources rather than vendor docs.
56+
57+
## Development setup
58+
59+
```bash
60+
git clone https://github.com/Mediacastnet/mediacast-netcatalog
61+
cd mediacast-netcatalog
62+
63+
# Rust
64+
cargo test --no-default-features
65+
cargo run --example basic_lookup
66+
67+
# Python bindings
68+
pip install "maturin>=1.5,<2.0"
69+
maturin develop --features python
70+
python -c "from mediacast_netcatalog import Catalog; print(Catalog.load_bundled().vendors())"
71+
```
72+
73+
## PR process
74+
75+
1. Open an issue first for substantive changes (new vendor, schema
76+
change, breaking API). For obvious fixes, just send the PR.
77+
2. Run `cargo fmt`, `cargo clippy`, `cargo test`, and `yamllint catalog/`
78+
before submitting.
79+
3. Add an entry to `CHANGELOG.md` under `[Unreleased]`.
80+
4. CI must pass on Linux + macOS + Windows.
81+
82+
## License
83+
84+
By contributing, you agree your contribution is dual-licensed under
85+
MIT or Apache-2.0, matching the rest of the project. See `LICENSE-MIT`
86+
and `LICENSE-APACHE`.
87+
88+
## Code of conduct
89+
90+
Be kind. Disagree on technical merit, not on people. Maintainers will
91+
moderate at their discretion.

Cargo.toml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
[package]
2+
name = "mediacast-netcatalog"
3+
version = "0.1.0"
4+
edition = "2021"
5+
rust-version = "1.78"
6+
description = "Vendor command catalog + version matcher + protocol probe for multi-vendor network automation."
7+
license = "MIT OR Apache-2.0"
8+
repository = "https://github.com/Mediacastnet/mediacast-netcatalog"
9+
homepage = "https://github.com/Mediacastnet/mediacast-netcatalog"
10+
documentation = "https://docs.rs/mediacast-netcatalog"
11+
readme = "README.md"
12+
keywords = ["networking", "cisco", "aruba", "juniper", "automation"]
13+
categories = ["network-programming", "parser-implementations", "api-bindings"]
14+
authors = ["Robare Pruyn <robare@mediacastnet.com>", "Mediacast Network Solutions"]
15+
include = [
16+
"src/**/*.rs",
17+
"catalog/*.yaml",
18+
"catalog/*.md",
19+
"Cargo.toml",
20+
"README.md",
21+
"LICENSE-MIT",
22+
"LICENSE-APACHE",
23+
"CHANGELOG.md",
24+
]
25+
26+
[lib]
27+
name = "mediacast_netcatalog"
28+
crate-type = ["cdylib", "rlib"]
29+
30+
[features]
31+
default = []
32+
# Enable the PyO3 Python bindings. Activated by maturin during wheel builds.
33+
python = ["dep:pyo3"]
34+
# Enable the `mediacast-netcatalog probe` CLI binary.
35+
bin = ["dep:clap", "dep:tokio", "dep:reqwest", "dep:serde_json", "dep:anyhow"]
36+
37+
[dependencies]
38+
serde = { version = "1.0", features = ["derive"] }
39+
serde_yaml = "0.9"
40+
thiserror = "1.0"
41+
once_cell = "1.19"
42+
indexmap = { version = "2.2", features = ["serde"] }
43+
tracing = "0.1"
44+
45+
# Optional — Python bindings
46+
pyo3 = { version = "0.21", features = ["extension-module", "abi3-py39"], optional = true }
47+
48+
# Optional — probe binary
49+
clap = { version = "4.5", features = ["derive"], optional = true }
50+
tokio = { version = "1.36", features = ["macros", "rt-multi-thread", "net", "io-util", "time"], optional = true }
51+
reqwest = { version = "0.12", features = ["rustls-tls", "json"], default-features = false, optional = true }
52+
serde_json = { version = "1.0", optional = true }
53+
anyhow = { version = "1.0", optional = true }
54+
55+
[dev-dependencies]
56+
anyhow = "1.0"
57+
pretty_assertions = "1.4"
58+
rstest = "0.21"
59+
60+
[[example]]
61+
name = "basic_lookup"
62+
required-features = []
63+
64+
[[bin]]
65+
name = "mediacast-netcatalog"
66+
path = "src/bin/probe.rs"
67+
required-features = ["bin"]
68+
69+
[profile.release]
70+
lto = "thin"
71+
codegen-units = 1
72+
strip = "symbols"
73+
74+
[package.metadata.docs.rs]
75+
all-features = false
76+
features = []
77+
rustdoc-args = ["--cfg", "docsrs"]

0 commit comments

Comments
 (0)