Skip to content

fix(import,export): scope-aware writes, refuse dangerous categories by default#17

Merged
ale-rinaldi merged 1 commit into
mainfrom
fix/issue-8-import-scope-guard
May 15, 2026
Merged

fix(import,export): scope-aware writes, refuse dangerous categories by default#17
ale-rinaldi merged 1 commit into
mainfrom
fix/issue-8-import-scope-guard

Conversation

@ale-rinaldi

Copy link
Copy Markdown
Contributor

Closes #8. The full design rationale lives in issue #8's pinned design comment; this PR description focuses on what landed.

Default behaviour change

mythy import now refuses to write keys flagged by either of two locale-independent catalog markers:

  • SKIP="YES" — declared on identification / IP / comm config (in NV10P-EB0-u: SerialNumber, ethernet_hw_address, IP_address, IP_netMsk, IP_gateway, MB_address, MB_485_baudrate, MB_232_baudrate, SelProto, NTPSynch). Writing these over the live Modbus connection drops the connection mid-transaction.
  • VISIBILITY="3" — the Administrator / Menu Riservato subtree. Cascade from the containing <GROUP> is honoured, plus DATA-level overrides like CodeNum that sit in an otherwise-visible group.

READONLY="YES" is still a hard mythy-side refuse (the device empirically accepts writes to fields the catalog labels read-only, so this defensive guard remains load-bearing).

Path-based per-category opt-ins (--include-ntp, --include-oscillography, etc.) from the original issue spec are dropped — top-level menu names are locale-dependent and the catalog markers give a strictly better classification.

Opt-in flags (both import and export)

flag effect
--include-skip allow SKIP="YES"
--include-hidden allow VISIBILITY="3" cascade and DATA-level
--include-readonly export-only: include read-only entries in the YAML
--all shorthand: import = --include-skip + --include-hidden; export = those two plus --include-readonly

Import-only: --yes-i-understand is required when any --include-* is set. Without it, the command prints the banner of keys that would be touched (grouped by reason) and exits with an error. Export has no confirmation gate (non-destructive).

Live verification (NV10P-EX0-u via proxy)

Hand-crafted YAML with one SKIP=YES key (MB_address) and one DATA-level-hidden key (CodeNum):

$ mythy import sample.yml --dry-run
would write 0 key(s): []
would skip 1 SKIP key(s) (use --include-skip to write): [MB_address]
would skip 1 hidden key(s) (use --include-hidden to write): [CodeNum]

$ mythy import sample.yml --include-skip
would write (rerun with --yes-i-understand to proceed) 1 connection-disruptive key(s) (SKIP=YES — identification, IP/comm config): [MB_address]
Error: scope opt-in requires --yes-i-understand to proceed

$ mythy import sample.yml --all --yes-i-understand --dry-run
would write 1 connection-disruptive key(s) (SKIP=YES — identification, IP/comm config): [MB_address]
would write 1 hidden key(s) (VISIBILITY=3 — Administrator subtree): [CodeNum]
would write 2 key(s): [MB_address CodeNum]

Tests

  • pkg/configio/apply_test.go — new tests cover: SKIP key classified-and-skipped by default; SKIP key written when IncludeSkip=true (and still surfaced in InSkipCategory for the CLI banner); hidden key classified via parent-group cascade; hidden key written when IncludeHidden=true; single dry-run pass surfaces all four buckets.
  • pkg/session/filter_test.goTestFilterSkipNeverOverridable updated to the new semantics (it's now overridable via IncludeSkip), default-exclude behaviour preserved.
  • testdata/us/TEST-VB0-a gains two minimal DATA: TEST_IP_Address (SKIP=YES) and TEST_EnableBoard (inside a VISIBILITY=3 group). Picked names that mirror the real-world failure pattern.

Scope notes

  • Auto-snapshot-before-write (mentioned as "ideally" in the issue) and the FATALE-state side observations are out of scope for this PR — separable from the filter design.

🤖 Generated with Claude Code

…y default

mythy import used to write every key the YAML mentioned as long as
the catalog didn't mark it READONLY="YES". That meant a hand-edited
YAML carrying e.g. CodeNum or EnableBoard_* could put a fielded
protection relay into a FATALE state requiring SET_DB_DEFAULT and a
physical power-cycle. Catalog markers exist to flag these cases but
mythy was ignoring them outside of READONLY.

Add two layers of scope filtering on writes, both gated on
locale-independent catalog attributes:

  - SKIP="YES" — identification / IP / comm config. Writing any of
    these over the live Modbus connection typically drops the
    connection mid-transaction. Excluded by default; --include-skip
    plus --yes-i-understand to opt in.
  - VISIBILITY="3" — Administrator / Menu Riservato subtree, plus
    DATA-level overrides like CodeNum. Cascades from the containing
    group AND honored on the DATA element itself. Excluded by default;
    --include-hidden plus --yes-i-understand.
  - --all is shorthand for both opt-ins; READONLY="YES" stays a hard
    mythy-side refuse (the device empirically does not enforce
    read-only on the wire, so this defensive guard remains load-
    bearing).

Path-based per-category opt-ins (--include-ntp, etc.) from the
original spec are dropped: top-level menu names are locale-dependent
(`Network Services` in us vs `Comandi` in it), and the catalog
attributes give a strictly better classification anyway. See the
design note pinned to the issue for the full reasoning.

Banner + abort: when an --include-* flag is set without
--yes-i-understand, the command prints the affected keys grouped by
reason and refuses to proceed. With --yes-i-understand the same
grouped banner prints before the writes hit the device, so even in
the CI case the operator has accountability output.

Export gains the symmetric flag set: --include-skip is new; --all is
new; --include-readonly/--include-hidden already existed. No
confirmation gate on export — it's read-only.

Closes #8

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ale-rinaldi ale-rinaldi merged commit 5038450 into main May 15, 2026
2 checks passed
@ale-rinaldi ale-rinaldi deleted the fix/issue-8-import-scope-guard branch May 15, 2026 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant