# Network & Sharing redesign — the last punt dies Approved mock: `home-mocks/network.html` (scratchpad, :8642). Spec wins over mock on conflict. ## Goals 1. **Connections becomes a full network manager**: per-connection details (IP/DNS/gateway/MAC), forget + autoconnect + MAC randomization, native VPN card with import, hotspot, airplane mode, enterprise Wi-Fi join, system proxy. The "Owned by Fedora" card and both GNOME punt rows are removed. 2. **Firewall gains its add side**: allow service/port flow, per-connection zone dropdowns, default zone, zone browser — all existing helper verbs plus one new read-only one. 3. **Printers**: per-printer defaults (paper size, two-sided) and job hold/release. 4. **Sharing**: copy/structure polish only (error banner into a card, honest Samba row, RDP credential flow copy without naming the terminal in user-facing text). 5. Search stops lying ("Managed by GNOME Settings" entries die; duplicate Printers entry deduped; new entries for VPN, hotspot, airplane, proxy, IP address). Non-goals: Samba share management (not installed here — the row explains what installing unlocks), PPD/vendor drivers (contract-banned), WWAN (no hardware), per-connection static IP editing (view-only details this phase). ## New helper: `scripts/panama-network` (pinned verbs) Python, the panama-vpn/panama-sharing discipline: validated inputs, JSON out, bounded timeouts, mutations return fresh state. Input validation: connection/SSID names against a conservative charset, file paths must exist and end in .conf/.ovpn for import. - `details ` → `{ ip4, gateway, dns: [], mac, macRandomized }` — **never secrets**. - `forget ` — `nmcli connection delete`. - `set-autoconnect `. - `set-mac-random ` — `wifi.cloned-mac-address random|permanent`; the JSON notes a reconnect is needed to take effect. - `import-vpn ` — `nmcli connection import type wireguard|openvpn file …` (type by extension); returns the imported connection's name. - `hotspot start ` / `hotspot stop` / `hotspot status` — `nmcli device wifi hotspot`; the generated password is read back via `nmcli device wifi show-password` and returned once for the UI to display alongside a QR (reuse the panama-wifi-qr pipeline if trivial, else text-only this phase). - `join-enterprise` — SSID + eap profile (peap-mschapv2 | ttls-pap) + identity on argv, **password on stdin, never argv**. Mechanism: probe for python NM gi bindings (`gi.require_version('NM','1.0')`) and use D-Bus AddConnection when present; else fall back to a scripted `nmcli connection edit` session over stdin (which keeps the secret out of ps). Agent A picks after probing and documents the choice in the script header. - `proxy get` / `proxy set [host port | pac-url]` — gsettings `org.gnome.system.proxy` (mode none|manual|auto; manual sets http+https+socks host/port together this phase). - `airplane status` / `airplane set ` — rfkill, matching the existing keybind path. ## Services (A) - **`services/NetworkTools.qml`** (new singleton) wraps panama-network: cached `detailsFor (connection)` (refreshed on page open + active-connection change), `forget`, `setAutoconnect`, `setMacRandom`, `importVpn(path)`, hotspot state/start/stop, `proxyMode`+setters, `airplaneOn`+toggle, `joinEnterprise(...)` (password handed through a Process stdin write), `busy`/`lastError`. Test seam: `PANAMA_NETWORK_HELPER` env override for the helper path. - **`services/Connectivity.qml`** stays pure-native (contract-pinned no-shell-out): add `setWifiEnabled(bool)` and `setBluetoothEnabled(bool)` wrappers (native writes) so the page toggles stop bypassing the service; add `objectName`-friendly derived state if needed. - **`services/Firewall.qml`** + `scripts/panama-firewall`: new read-only verb `zone-info ` → services/ports/summary for the zone browser; service exposes `zoneInfo(zone)` with a small cache. Existing verbs untouched. - **`services/Printers.qml`** + `scripts/panama-printers`: new verbs `get-options ` (lpoptions: media, sides — curated keys only), `set-option ` (validated against a closed key/value vocabulary: media=Letter|A4|Legal, sides=one-sided|two-sided-long-edge|two-sided-short-edge), `hold ` / `release ` (python3-cups). Mutations return fresh snapshots. - `services/Vpn.qml` untouched (import lands through NetworkTools; the list/toggle stays as-is, now also consumed by the page). ## UI (B) **ConnectivityPage.qml** rebuilt: Wired card (connection row expands to a details KV grid); Wi-Fi card (toggle via `Connectivity.setWifiEnabled`, connected network expands to details + autoconnect + MAC-randomize + QR share + Forget with a two-stage confirm; other networks keep Join/inline password; enterprise networks get an inline join form — auth dropdown, identity, password field, optional CA file path, Connect; hotspot row at the bottom); **VPN card** (list from `Vpn.qml` with per-VPN toggles, empty state + Import row → file path entry or zenity-free inline TextField this phase); Bluetooth card (toggle via service wrapper); **Radios & proxy card** (airplane toggle, proxy dropdown expanding to manual host/port or PAC URL fields). The "Owned by Fedora" card is deleted. Page gains `objectName: "connectivity"`. KV details grid is a new small component (`ConnectionDetails.qml`) with mono values. **FirewallPage.qml**: existing exposure/remove flows untouched; "Allow something new" row expanding to a kind dropdown (Named service / Port) + validated TextField + Allow button + the "permanent rule, the system will ask for your password" caption; Zones card gains per-connection zone dropdowns (`setZone`, with a confirm that names the interface), default zone dropdown (`setDefaultZone`), and a zone-browser chip row driving `zoneInfo` into a detail line. Only render `zones[0]`'s rules card per current behavior, but the zones card now lists every active zone. **SharingPage.qml**: error banner moves into the This-machine card; Remote-login card compresses port/password-mode/connect-with into row details; RDP credentials copy becomes "Set in a terminal so the password never passes through Panama" (kitty stays the mechanism); Samba row explains "install it and this becomes a switch". **PrintersPage.qml**: expanded printer gains Paper size + Two-sided dropdowns (from `get-options`, written via `set-option`); queue rows gain Hold/Release next to Cancel; the two duplicate "Search the network" rows merge into the single empty-state card per mock. ## Search & docs (C) Delete the three "Managed by GNOME Settings" connectivity entries and the duplicate Printers entry. Add (page connectivity): VPN, Import a VPN, Hotspot, Airplane mode, Network proxy, IP address, Forget a Wi-Fi network, Enterprise Wi-Fi. Keep existing printers/firewall/sharing entries. Docs regen: none needed (no schema keys) — verify. ## Contracts (C — write, never run) - `connectivity-contract`: still native-only — verify the no-shell-out pin survives (all nmcli lives in NetworkTools/panama-network); add needles for the service-wrapper toggles. - New `network-tools-contract`: stubbed-nmcli fixtures (the vpn-contract pattern): details excludes secrets, forget/autoconnect argv shapes, import type-by-extension, enterprise password arrives via stdin and NEVER argv (assert the argv builder), proxy gsettings calls, airplane rfkill. - `firewall-contract`: extend for the add flow (additions are non-destructive, no confirm required; zone changes ARE consequence-bearing — pin that changing a connection's zone names the interface in its confirm), `zone-info` read-only. - `printers-contract`: closed option vocabulary pinned (no arbitrary lpadmin -o passthrough), hold/release verbs, driverless pins untouched. - `gnome-handoff-contract`: the `network` exclusion reason ("Panama has no VPN or per-connection routing") is now false — move `network` and `wifi` into OWNED so no page may punt to them, and verify nothing does. - `sharing-contract`, `settings-pages-contract`: needles reconciled. - Backlog: Phase 9 section. ## Agent ownership (parallel) - **A**: `scripts/panama-network` (new), `scripts/panama-firewall`, `scripts/panama-printers`, `services/NetworkTools.qml` (new), `services/Connectivity.qml`, `services/Firewall.qml`, `services/Printers.qml`. - **B**: the four pages + new components (+ qmldir). - **C**: `services/SettingsSearch.qml`, contracts above, backlog, README count line only if count changes. B programs against the pinned verbs/APIs; A must not change them without updating this spec. Live-desktop rules apply to everyone: no test runs, no harness boots, valid QML/Python at every save, and **no live mutations** — no nmcli writes, no firewall-cmd writes, no lpadmin, no rfkill, no gsettings writes; read-only probes only.