Skip to content

Add physical Firewall/NAT write lifecycles - #33

Merged
MarcLeinenDE merged 10 commits into
mainfrom
test/firewall-physical-lifecycle
Sep 25, 2026
Merged

MarcLeinenDE merged 10 commits into
mainfrom
test/firewall-physical-lifecycle

Conversation

@MarcLeinenDE

@MarcLeinenDE MarcLeinenDE commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

Prepare persistent public-SDK physical coverage for the 13 Firewall/NAT write methods identified by the canonical API↔SDK audit.

Upstream first:

This branch adds two opt-in physical suites:

  1. reversible lifecycle (NR2301_WRITE_INTEGRATION=1)
    • DMZ enable/disable
    • VPN passthrough
    • admin-from-WAN
    • ping-from-WAN
    • IP-filter list + enable state
    • port-filter list + enable state
    • Port Forward
    • Port Trigger
    • URL filter
    • UPnP
    • exact final semantic snapshot restore
  2. DMZ destination lifecycle (NR2301_DESTRUCTIVE_INTEGRATION=1)
    • uses only the verified non-empty destination setter
    • keeps a stock config backup in memory
    • if the original destination is non-empty, restores through the same setter
    • if the original destination is empty, uses the already live-verified config-backup restore path instead of inventing an unverified DMZ clear API
    • verifies the final Firewall snapshot exactly

No physical result is claimed yet. Keep this PR open until both tests have run against the dedicated router and any new protocol observations have first been normalized in nr2301-api.

Physical run 1 (2026-09-21):

  • DMZ enable/disable: PASS
  • VPN passthrough: PASS
  • admin-from-WAN: PASS
  • ping-from-WAN: PASS
  • IP-filter rule write/read-back: PASS
  • IP-filter mode toggle/read-back: PASS
  • port-filter rule write/read-back: PASS
  • port-filter mode toggle/read-back: PASS
  • Port Forward write succeeded, but the first test compared MAC text case-sensitively
  • ACIY.3 getter returned the same synthetic MAC address bytes with hexadecimal letters lowercased
  • upstream contract was corrected first in nr2301-api PR Add stock configuration backup and restore #29, merged as 228af8452f7b9701411d79d7d2f5bcdf3dd6ce93
  • the SDK physical test now compares Port Forward MAC addresses semantically/case-insensitively while continuing to preserve raw getter values
  • offline CI after the correction: workflow #395, Python 3.10–3.13 + package = SUCCESS

The failed assertion occurred inside a try/finally lifecycle, so the restore path executed. A full rerun is still required to prove final exact semantic restoration and continue through Port Trigger, URL Filter and UPnP.

Physical run 2 (2026-09-21):

  • previous Port Forward MAC-case issue is resolved; Port Forward read-back passed
  • Port Trigger write/read-back also passed
  • immediately after set_url_filter returned successfully, the first get_url_filter call connected to zyxel.home but hit the harness's explicit 5 s HTTP read timeout
  • this was not DNS failure, connection refusal, auth-result failure, or schema rejection
  • prior project evidence shows URL Filter write/read-back/restore passed on 2026-09-14 and again in the 2026-09-18 production-helper smoke without reboot (boot_time 8282→8298)
  • older NR2301 write campaigns already use management recovery/re-login loops after transient API stalls
  • upstream API finding normalized first in nr2301-api PR Add factory reset recovery lifecycle #30, merged as a844a3d1262b65f518f0bd46a514352dc56f9a17
  • physical harness now issues the write only once, then retries URL-filter getter read-back with 10 s timeout/re-login instead of interpreting the first timeout as write failure

Physical run 3 (2026-09-21):

  • all 12 reversible Firewall/NAT write stages passed write + semantic read-back
  • URL Filter passed
  • UPnP passed
  • finally/restore executed without a write-side exception
  • the first final verification snapshot then hit a 5-second HTTP read timeout on get_admin_from_wan after connecting to zyxel.home
  • this broadens the transient stall from a URL-filter-specific observation to general Firewall/NAT management readiness after cumulative writes/restores
  • upstream API evidence/policy normalized first in nr2301-api PR Complete LAN and router write coverage #31, merged as c04c83d960e7c0b7738071ef9fb1580fc6b06f47
  • the SDK physical harness now retries the complete read-only final snapshot with a 10-second read timeout and re-login/recovery, while never blindly repeating writes
  • offline CI after the generalized recovery patch: workflow #398, Python 3.10–3.13 + package = SUCCESS

Physical run 4 / reversible lifecycle closure (2026-09-25):

  • all 12 fully reversible Firewall/NAT writes passed mutation/action + semantic read-back
  • final full Firewall/NAT snapshot matched the original state exactly
  • output ended with:
    FIREWALL_FINAL dmz_restored=True vpn_restored=True wan_controls_restored=True filters_restored=True nat_rules_restored=True upnp_restored=True
    PASSED
  • pytest: 1 passed in 25.64s
  • canonical API evidence was updated first and merged in nr2301-api PR Align SDK auth guidance and full-coverage policy #32 as fbdee20317b160e68d05da6708cbc8a39438d890
  • API validator #212: SUCCESS

Remaining campaign scope after this PR:

  • firewall/fw_edit_dmz_entry still lacks a clean exact-restore physical closure from the original sentinel state
  • recover the router's default/sentinel DMZ state during the planned factory-reset/recovery phase, then rerun the corrected dedicated DMZ test
  • do not treat a rerun starting from the current synthetic residue as closure

Physical run 5 / DMZ destination sentinel finding (2026-09-25):

  • pre-test getter returned the historically known incomplete value 192.168.
  • the harness incorrectly classified non-empty as setter-restorable
  • a valid synthetic IPv4 destination wrote and read back successfully
  • replaying 192.168. through the setter did not restore getter state
  • final getter remained on the synthetic valid IPv4; DMZ itself was restored disabled
  • all other sampled Firewall state matched the original
  • the pre-test config backup was RAM-only and disappeared with the failed test process, so it cannot be used retrospectively
  • upstream API semantics were corrected first in nr2301-api PR Add physical Firewall/NAT write lifecycles #33, merged as e79b5f9db2bf914a71e3a827dccb6676d0986a1a; validator #214 SUCCESS
  • SDK now validates set_dmz_destination input as IPv4 and the integration harness chooses backup restore based on IPv4 validity rather than empty/non-empty text
  • offline CI after SDK correction: workflow #402, Python 3.10–3.13 + package = SUCCESS

Current physical disposition:

  • the router has known synthetic DMZ-destination residue while DMZ is disabled
  • do not rerun the DMZ mutation test against that residue and count it as closure
  • exact sentinel-state recovery is deferred to the campaign's factory-reset/recovery phase, after which the corrected DMZ test can be rerun from the recovered default/sentinel state
  • the 12-method reversible Firewall/NAT lifecycle remains physically closed and unaffected

@MarcLeinenDE
MarcLeinenDE marked this pull request as ready for review September 25, 2026 05:49
@MarcLeinenDE
MarcLeinenDE merged commit d4b2def into main Sep 25, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant