sync: auto-sync from HOWARD-HOME at 2026-06-21 11:27:38

Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-21 11:27:38
This commit is contained in:
2026-06-21 11:28:23 -07:00
parent 96a5dd6e7a
commit 6c0beb5a96
2 changed files with 170 additions and 0 deletions

View File

@@ -17,6 +17,12 @@ Categories (the `[type]` tag): _(none)_ = skill/command execution failure ·
<!-- Append entries below this line -->
2026-06-21 | Howard-Home | bitdefender | GravityZone API error [policies.getPolicyDetails]: Invalid value for 'policyId' parameter. [ctx: cmd=policy]
2026-06-21 | Howard-Home | bitdefender | GravityZone API error [network.getManagedEndpointDetails]: Invalid value for 'endpointId' parameter. Expected format: 24-char hex ID [ctx: cmd=endpoint]
2026-06-21 | Howard-Home | bitdefender | GravityZone API error [network.getEndpointsList]: Invalid value for 'parentId' parameter. [ctx: cmd=endpoints]
2026-06-21 | Howard-Home | bitdefender | GravityZone API error [network.createCustomGroup]: The required parameter is missing : groupName [ctx: cmd=raw]
2026-06-21 | Howard-Home | bitdefender | GravityZone API error [network.createCustomGroup]: One or more parameters are not expected: name [ctx: cmd=make-group]

View File

@@ -0,0 +1,164 @@
# Session — unifi-wifi pfSense SSH gateway-control verbs (ROADMAP §E)
## User
- **User:** Howard Enos (howard)
- **Machine:** Howard-Home
- **Role:** tech
## Session Summary
Picked up the unifi-wifi skill build-out, specifically the open WIP in ROADMAP §E — the pfSense
gateway "compatibility layer". The skill already had a working read-only SSH backend
(`pfsense-ssh.sh`: `audit`/`dhcp`/`run`/`shell`) and a superseded REST backend
(`pfsense-backend.sh`) that held the full control-verb contract. Per Mike's 2026-06-16 decision
(SSH, not the REST API package), the remaining work was to implement gated CONTROL verbs on the
SSH backend mirroring the `gw-control` contract, then rewire `gw-audit.sh`/`gw-control.sh` dispatch
to the SSH backend.
Before writing code, ran read-only discovery against the live Cascades pfSense (Plus 25.07-RELEASE,
reachable at 192.168.0.1 over the Cascades site VPN) to pin the exact config schema rather than
guess. Discovery established: `pfSsh.php` does NOT eval piped ad-hoc code (only its built-in
`playback` scripts), so the reliable primitive is `php` with a `require_once("config.inc")`
bootstrap, which loads `$config` + `write_config()` + `filter_configure()`. Filter rules are keyed
on `tracker` (the `id` field is empty on 25.07); enabled/disabled is the PRESENCE of a `disabled`
key. `easyrule` supports `block/unblock/showblock <interface> <source>` and auto-manages its alias
+ WAN rule. Cascades has 20 filter rules and 0 NAT port-forwards.
Built a new versioned PHP helper `scripts/pfsense-gwc.php` (argv-driven, no operator data
interpolated into PHP source) for list/toggle/set/delete against `$config`, with a config backup +
`write_config()` + `filter_configure()` on every write. Extended `pfsense-ssh.sh` with 12 verbs
(`pf-list`, `fw-list`, `showblock`, `pf-disable/enable/delete`, `pf-set-ports`, `pf-set-src`,
`fw-disable/enable`, `block-ips`, `unblock`) — DRY-RUN by default, `--apply` to commit. The helper
ships to the box via `base64 | openssl base64 -A -d` and runs with argv. Rewired dispatch in both
`gw-control.sh` and `gw-audit.sh` to prefer the SSH backend (keyed on
`clients/<slug>/pfsense-firewall`), running the dispatch BEFORE UOS site resolution so a
pfSense-only client slug works; the REST backend is now a dormant fallback.
Validated live on Cascades: reads (`fw-list` all 20 rules with correct schema, `pf-list`,
`showblock`), tracker- and descr-based matching, the full `block-ips`/`unblock` cycle on a TEST-NET
documentation IP (192.0.2.123), and the `pfsense-gwc.php` write path via a `fw-disable`/`fw-enable`
round-trip on an inert rule (config backup + reload confirmed, rule returned to original state).
Updated ROADMAP §E status to done, recorded the pfSense PHP gotchas, and updated SKILL.md's verb
reference + dispatch description.
## Key Decisions
- **`php` + `config.inc` bootstrap, not config.xml text parsing.** Robust against version drift and
gives pfSense's own `write_config()`/`filter_configure()` for safe commit + reload. Chosen after
confirming `pfSsh.php` only runs its built-in `playback` scripts, not piped code.
- **Versioned PHP helper file (`pfsense-gwc.php`) instead of a bash heredoc.** Keeps the control
logic readable/lintable; shipped to the box per-call via base64 over the existing SSH session.
- **argv-driven helper.** All operator data passed as positional args, never interpolated into PHP
source — no shell/PHP injection surface.
- **Match filter rules by `tracker` or exact `descr`, not `id`.** The `id` field is empty on pf25.07;
`tracker` is the stable unique key.
- **Dispatch runs before UOS site resolution.** A pfSense-only site is keyed by client slug (not a
UOS site name), so resolving the UOS site first would hard-exit before dispatch could fire.
- **SSH backend preferred, REST kept dormant.** Honors Mike's 2026-06-16 decision; REST
(`pfsense-backend.sh` + `clients/<slug>/pfsense-api`) stays in-tree only as a fallback.
- **`block-ips` via `easyrule`, toggles via the PHP path.** easyrule is the cleanest, canonical
pfSense block mechanism (auto alias + rule); rule toggles need direct `$config` edits.
## Problems Encountered
- **pfSsh.php piped code did nothing.** Expected `echo '...; exec' | pfSsh.php` to eval; it only
prints its banner + `playback` command list. Switched to `php` with a temp-file script.
- **php_rc=255 with no error output.** pfSense runs `display_errors=Off`, so fatals are silent.
Fixed by running php with `2>&1` AND `ini_set("display_errors","1")` in the helper.
- **`Cannot redeclare backup_config()` fatal.** pfSense's `config.lib.inc` already defines it (and
many generic names). Prefixed all helper functions with `gwc_`. Also dropped the extra
`require_once` of util/functions/filter — `config.inc` already pulls them; re-requiring caused
the redeclare fatal.
- **Empty output on first `fw-list` runs.** Root-caused via step markers in the remote script (the
three issues above), not by guessing.
- **`No such file or directory` on a verb test.** Working dir had persisted from an earlier `cd`
into the scripts dir; relative script path broke. Re-ran with `cd /c/claudetools` + path.
## Configuration Changes
Created:
- `.claude/skills/unifi-wifi/scripts/pfsense-gwc.php` — argv-driven pfSense config control helper.
Modified:
- `.claude/skills/unifi-wifi/scripts/pfsense-ssh.sh` — added 12 control verbs, `--apply`/`--if`
parsing, `sq()` shell-quote + `run_gwc()` ship-and-run helper, fixed `run` to use preserved args.
- `.claude/skills/unifi-wifi/scripts/gw-control.sh` — SSH-first dispatch (pfsense-firewall cred),
moved above UOS site resolution; REST kept as fallback.
- `.claude/skills/unifi-wifi/scripts/gw-audit.sh` — same SSH-first dispatch for `audit`.
- `.claude/skills/unifi-wifi/references/ROADMAP.md` — §E status → done; verb list; pfSense PHP
gotchas added to cross-platform notes.
- `.claude/skills/unifi-wifi/SKILL.md` — pfSense section rewritten (read/write verb tables,
dispatch); gw-control usage block corrected (routes to pfsense-ssh.sh, match by tracker/descr).
## Credentials & Secrets
No new credentials created or discovered. Used existing vault entries (read-only):
- `clients/cascades-tucson/pfsense-firewall` — host 192.168.0.1, user `admin`, password stored.
Used by `pfsense-ssh.sh` (system OpenSSH via askpass).
- `clients/cascades-tucson/pfsense-openvpn-howard` — the Cascades site VPN profile (referenced for
reachability; not directly used by the scripts).
## Infrastructure & Servers
- **Cascades pfSense** — 192.168.0.1 (LAN), pfSense Plus **25.07-RELEASE**, admin SSH drops straight
to a shell. Reachable over the Cascades site VPN (16ms). 20 filter rules, 0 NAT port-forwards.
- PHP include_path on the box: `.:/etc/inc:/usr/local/pfSense/include:...``require_once("config.inc")`
resolves from anywhere.
- Test residue left on Cascades: an inert `'Blocked via EasyRule'` WAN block rule (tracker
1782065739) + empty `EasyRuleBlockHostsWAN` alias, created by the `block-ips` validation. Blocks
nothing (empty alias); returned to enabled state. Pending operator decision to remove or keep.
## Commands & Outputs
```
# Discovery (read-only) — schema + tooling
pfsense-ssh.sh cascades-tucson run 'cat /etc/version' # 25.07-RELEASE
# php bootstrap works; pfSsh.php only runs playback scripts (not piped code)
php /tmp/q.php -> NAT_RULES=0 FILTER_RULES=20
easyrule -> block|unblock|showblock <if> <src>; pass <if> <proto> <src> <dst> [port]
# New read verbs
pfsense-ssh.sh cascades-tucson fw-list # 20 rules, keyed on tracker
pfsense-ssh.sh cascades-tucson pf-list # (no NAT port-forwards configured)
pfsense-ssh.sh cascades-tucson showblock # No entries are blocked on interface: wan
# Live write validations
pfsense-ssh.sh cascades-tucson block-ips 192.0.2.123 --apply # Block added successfully
pfsense-ssh.sh cascades-tucson showblock # 192.0.2.123/32
pfsense-ssh.sh cascades-tucson unblock 192.0.2.123 --apply # Entry unblocked successfully
pfsense-ssh.sh cascades-tucson fw-disable 1782065739 --apply # backup + write_config + filter reload -> [off]
pfsense-ssh.sh cascades-tucson fw-enable 1782065739 --apply # -> [on] (restored)
# Dispatch validation
gw-control.sh cascades-tucson fw-list # -> dispatches to pfsense-ssh.sh
gw-control.sh cascades-tucson fw-disable 1772841904 # dry-run via dispatch
# Syntax check
bash -n pfsense-ssh.sh gw-control.sh gw-audit.sh # all [OK]
```
Key gotcha encoded in scripts: pfSense `display_errors=Off` (run php with `2>&1` + `ini_set`),
`backup_config()` collision (prefix `gwc_*`), `config.inc`-only bootstrap (no re-require).
## Pending / Incomplete Tasks
- **`pf-*` (NAT port-forward) verbs are built but NOT live-verified.** Cascades has 0 port-forwards,
so they were coded against the documented pfSense NAT schema (`destination.port`, `target`,
`local-port`, `associated-rule-id`). Need a pfSense box with an actual port-forward + a vaulted
`clients/<slug>/pfsense-firewall` cred to confirm field names before trusting `--apply`. Marked
live-verify-pending in ROADMAP §E.
- **Cascades easyrule test residue** — decide whether to remove the inert
`'Blocked via EasyRule'` rule (tracker 1782065739) + empty `EasyRuleBlockHostsWAN` alias.
- **Optional `pf-add`/create verbs** — not needed today (we only close/scope existing exposure);
noted in ROADMAP as future.
- Other §B/§C/§D ROADMAP items remain (per-client AP creds, gateway-hosted VPN server, read-only
vault cred) — untouched this session.
## Reference Information
- Session-log path: `session-logs/2026-06/2026-06-21-howard-unifi-pfsense-control-verbs.md`
- Skill: `.claude/skills/unifi-wifi/` — ROADMAP §E is the design/verb-map + pfSense PHP gotchas.
- Verb contract source (UniFi side): `scripts/gw-control.sh` header.
- Prior sync commits this session: `5ede4fe` (earlier auto-sync), `96a5dd6` (the pfSense build).
- pfSense filter-rule schema: keyed on `tracker`; `type` = pass/block/reject; `disabled` key
presence = off; `source`/`destination` are objects (`{any:""}` or `{network,port}`).