From 8e319fd052374258f8e17df1ff3e7d034d385be8 Mon Sep 17 00:00:00 2001 From: AdamRickards Date: Tue, 29 Sep 2026 18:55:50 +1000 Subject: [PATCH] schema+wire+fixtures: get_ip_addresses flat defaults + SSH prefix (#329) defaults: {ipv4: {}} replaced by the flat scalar shape {ipv4_address: '', ipv4_prefix: 0, ipv4_gateway: ''}, matching the schema's own "Management IP" note that this method is a scalar dict, not a per-interface table. SSH: hm2netprefixlength wired to "show network parms" Subnetmask via a new net_mask_to_prefix value_map (33 entries, prefix 0-32) in base wire/netconfig.yaml. It sits in the base file because the load_wire() overlay merge reads only attributes: (see companion park row). Fixtures: sanitized hm2NetStaticGroup scalar block (RFC 5737 TEST-NET-1 placeholder) added to config_nvm_sample.xml; gold_floors.json get_ip_addresses regenerated from {"ipv4": {}} to the 3 leaves the fixture now produces. The old floor came from 259aee0 (#192) as an empty Offline leaf. floors_provenance ssh untested -> pass and FLOORS_BOARD.md regenerated; catalogue_inventory_draft.md note updated. Schema, wire YAML and test fixtures only; no Engine files. Live sidecar proof: untested (pending). Draft; do not merge. Related #329 --- crude_engine/schemas/interface.yaml | 13 +++++- crude_engine/wire/netconfig.yaml | 41 +++++++++++++++++++ crude_engine/wire/ssh/netconfig.yaml | 8 ++++ docs/FLOORS_BOARD.md | 6 +-- tests/fixtures/floors_provenance.json | 2 +- .../offline_gold/catalogue_inventory_draft.md | 2 +- .../offline_gold/config_nvm_sample.xml | 13 ++++++ tests/fixtures/offline_gold/gold_floors.json | 4 +- 8 files changed, 82 insertions(+), 7 deletions(-) diff --git a/crude_engine/schemas/interface.yaml b/crude_engine/schemas/interface.yaml index d7d4d84..a212818 100644 --- a/crude_engine/schemas/interface.yaml +++ b/crude_engine/schemas/interface.yaml @@ -65,8 +65,19 @@ methods: type: upsert get_ip_addresses: type: dict + # #329: was `defaults: {ipv4: {}}` — a stub for a nested per-interface + # ip_table that never got built (needs an Engine primitive, see + # hitl-engine-park.md). The audit's own "Management IP" schema comment + # (below, on ipv4_address) says this method is a flat scalar dict, not + # a real table — confirmed live 2026-09-27: ipv4_address/ipv4_prefix/ + # ipv4_gateway are already fully wired (SNMP/MOPS always were; SSH as + # of this same patch) and were being silently discarded because they + # were never referenced in defaults, so nothing was ever gathered on + # ANY protocol (confirmed via a live SNMP capture: 0 calls made). defaults: - ipv4: {} + ipv4_address: '' + ipv4_prefix: 0 + ipv4_gateway: '' get_interfaces_ip: schema: get_ip_addresses set_interface: diff --git a/crude_engine/wire/netconfig.yaml b/crude_engine/wire/netconfig.yaml index 7a17075..f29fb3d 100644 --- a/crude_engine/wire/netconfig.yaml +++ b/crude_engine/wire/netconfig.yaml @@ -8,6 +8,47 @@ value_maps: management_protocol: none: static local: static + # #329: SSH's "show network parms" Subnetmask field is dotted-decimal + # text; SNMP/MOPS already give hm2netprefixlength as a plain int (walked + # via OID, no conversion needed there). Full 33-entry enumeration of + # valid dotted-decimal subnet masks (RFC 4632 CIDR, prefix 0-32) — not a + # transform function (regex:/math: can't do multi-octet bit-counting + # arithmetic on a single val; no custom Python needed either, this is a + # finite well-known lookup, same shape as this file's other value_maps). + net_mask_to_prefix: + "0.0.0.0": 0 + "128.0.0.0": 1 + "192.0.0.0": 2 + "224.0.0.0": 3 + "240.0.0.0": 4 + "248.0.0.0": 5 + "252.0.0.0": 6 + "254.0.0.0": 7 + "255.0.0.0": 8 + "255.128.0.0": 9 + "255.192.0.0": 10 + "255.224.0.0": 11 + "255.240.0.0": 12 + "255.248.0.0": 13 + "255.252.0.0": 14 + "255.254.0.0": 15 + "255.255.0.0": 16 + "255.255.128.0": 17 + "255.255.192.0": 18 + "255.255.224.0": 19 + "255.255.240.0": 20 + "255.255.248.0": 21 + "255.255.252.0": 22 + "255.255.254.0": 23 + "255.255.255.0": 24 + "255.255.255.128": 25 + "255.255.255.192": 26 + "255.255.255.224": 27 + "255.255.255.240": 28 + "255.255.255.248": 29 + "255.255.255.252": 30 + "255.255.255.254": 31 + "255.255.255.255": 32 schemas: read_netconfig: type: dict diff --git a/crude_engine/wire/ssh/netconfig.yaml b/crude_engine/wire/ssh/netconfig.yaml index 715a375..d6bc87a 100644 --- a/crude_engine/wire/ssh/netconfig.yaml +++ b/crude_engine/wire/ssh/netconfig.yaml @@ -16,6 +16,14 @@ attributes: ssh: read: {command: "show network parms", field: "Gateway address"} + # #329. value_map lives in base wire/netconfig.yaml, not here — load_wire() + # only merges the overlay's `attributes:`, never a top-level `value_maps:` + # block, so declaring it in this file would have silently never resolved. + hm2netprefixlength: + sources: + ssh: + read: {command: "show network parms", field: "Subnetmask", tag: value_map, map: net_mask_to_prefix} + hm2netvlanid: sources: ssh: diff --git a/docs/FLOORS_BOARD.md b/docs/FLOORS_BOARD.md index 08c8744..2579538 100644 --- a/docs/FLOORS_BOARD.md +++ b/docs/FLOORS_BOARD.md @@ -9,13 +9,13 @@ Cells from Test-owned `tests/fixtures/floors_provenance.json` (redacted aggregat **floor_source=`gold`** only when device-proved MOPS exists (`mops=pass` from `tests/release_matrix.json` verdicts). Sanitized `gold_floors.json` alone never sets gold. -Counts: floor_source gold **75** / 77; offline pass **51**; mops pass **75**; snmp pass **75**; ssh pass **46**. +Counts: floor_source gold **75** / 77; offline pass **51**; mops pass **75**; snmp pass **75**; ssh pass **47**. ## Coverage (Σ end-game progress) Effort **Σ Coverage** (`local/agents/diagrams/effort-board.md` + `diagrams/resolution-loop.md`). **Possible** = rows with `floor_source=gold` × `{offline,mops,snmp,ssh}`. **Proven** = those cells = `pass`. HITL exceptions are explicit only — never silent gaps. -**Rollup: proven `246` / possible `300` (82.0%).** Create→Execute→Resolve thickens this forever; lanes A′/B/C feed it. +**Rollup: proven `247` / possible `300` (82.3%).** Create→Execute→Resolve thickens this forever; lanes A′/B/C feed it. ### Cell vocabulary @@ -59,7 +59,7 @@ Schema typed reads (`type:` in `dict, list, list_append`) union `gold_floors.jso | `get_hidiscovery` | `gold` | `pass` | `pass` | `pass` | `pass` | | `get_interface_statistics` | `gold` | `untested` | `pass` | `pass` | `untested` | | `get_interfaces` | `gold` | `pass` | `pass` | `pass` | `untested` | -| `get_ip_addresses` | `gold` | `pass` | `pass` | `pass` | `untested` | +| `get_ip_addresses` | `gold` | `pass` | `pass` | `pass` | `pass` | | `get_ip_restrict` | `gold` | `pass` | `pass` | `pass` | `pass` | | `get_ip_source_guard_bindings` | `gold` | `untested` | `pass` | `pass` | `pass` | | `get_ip_source_guard_port` | `gold` | `untested` | `pass` | `pass` | `pass` | diff --git a/tests/fixtures/floors_provenance.json b/tests/fixtures/floors_provenance.json index bf561ca..7fc1d20 100644 --- a/tests/fixtures/floors_provenance.json +++ b/tests/fixtures/floors_provenance.json @@ -180,7 +180,7 @@ "offline": "pass", "mops": "pass", "snmp": "pass", - "ssh": "untested" + "ssh": "pass" }, "get_ip_restrict": { "floor_source": "gold", diff --git a/tests/fixtures/offline_gold/catalogue_inventory_draft.md b/tests/fixtures/offline_gold/catalogue_inventory_draft.md index 3249442..0411bdb 100644 --- a/tests/fixtures/offline_gold/catalogue_inventory_draft.md +++ b/tests/fixtures/offline_gold/catalogue_inventory_draft.md @@ -27,7 +27,7 @@ hints until a method is floored and `config_absent` receipts list them. | `get_dhcp_snooping` | `config_backed` | sanitized floor; config-backed attrs only | | `get_gmrp` | `config_backed` | sanitized floor; config-backed attrs only | | `get_gvrp` | `config_backed` | sanitized floor; config-backed attrs only | -| `get_ip_addresses` | `config_backed` | sanitized floor; config-backed attrs only (canonical; schema alias `get_interfaces_ip` not floored) | +| `get_ip_addresses` | `config_backed` | sanitized floor; config-backed attrs only (canonical; schema alias `get_interfaces_ip` not floored). Counted here since #192, but the floor was `{"ipv4": {}}` — vacuously empty, not a real comparison — because `defaults:` never referenced `ipv4_address`/`ipv4_prefix`/`ipv4_gateway`. Fixed #329 (2026-09-27): defaults corrected, `hm2NetStaticGroup` added to the XML sample (TEST-NET-1 placeholder), gold regenerated to 3 real leaves. | | `get_ip_restrict` | `config_backed` | sanitized floor; config-backed attrs only | | `get_login_policy` | `config_backed` | sanitized floor; config-backed attrs only | | `get_loop_protection` | `config_backed` | sanitized floor; config-backed attrs only | diff --git a/tests/fixtures/offline_gold/config_nvm_sample.xml b/tests/fixtures/offline_gold/config_nvm_sample.xml index 34e0b75..a4eb271 100644 --- a/tests/fixtures/offline_gold/config_nvm_sample.xml +++ b/tests/fixtures/offline_gold/config_nvm_sample.xml @@ -108,6 +108,19 @@ 2 2 + + + 1 + C0 00 02 0A + 24 + 1 + C0 00 02 01 + diff --git a/tests/fixtures/offline_gold/gold_floors.json b/tests/fixtures/offline_gold/gold_floors.json index f437588..921cdc5 100644 --- a/tests/fixtures/offline_gold/gold_floors.json +++ b/tests/fixtures/offline_gold/gold_floors.json @@ -348,7 +348,9 @@ } }, "get_ip_addresses": { - "ipv4": {} + "ipv4_address": "192.0.2.10", + "ipv4_prefix": 24, + "ipv4_gateway": "192.0.2.1" }, "get_devsec_status": { "oper_state": "",