# Changelog 2026-07-09 -- opnsense-edge module + prep scripts (DOCFIX-146)

No live infrastructure touched -- unapplied IaC/scripts only. Implements the
mechanism identified in the same-day OPNsense deployment research
(`docs/changelog-20260709-opnsense-research.md`).

## Items

### 1. DOCFIX-146 -- `scripts/opnsense-prep-image.sh`
FILE (new): `scripts/opnsense-prep-image.sh` + `tests/opnsense-prep-image/run-tests.sh`.

WHAT: downloads the OPNsense nano image, decompresses it, converts raw ->
qcow2, and grows it -- the preprocessing `libvirt_volume`'s `create.content.url`
can't do itself (it almost certainly performs a plain fetch, no
decompression). No mirror URL is hardcoded -- `OPNSENSE_MIRROR_BASE` is a
required env var (hard rule 2: never use an inferred value; OPNsense
publishes multiple mirrors and a silently-hardcoded one risks going stale
unnoticed).

HARNESS: 4/4 green, but only the guard-clause paths this environment can
exercise -- `qemu-img` is genuinely absent here, so that failure path is
real, not synthetic; the actual download/convert/resize behavior is
UNTESTED (would need `qemu-img` + network access to a real mirror).

### 2. DOCFIX-146 (cont.) -- `scripts/opnsense-build-config-iso.sh`
FILE (new): `scripts/opnsense-build-config-iso.sh` + `tests/opnsense-build-config-iso/run-tests.sh`.

WHAT: builds a plain ISO9660 image containing `/conf/config.xml`, for
OPNsense's Configuration Importer (see the OPNsense research changelog --
ISO9660 support was added to the Importer specifically for VM/cloud
automation). Uses `genisoimage`/`xorriso`, whichever is present.

HARNESS: 3/3 green, same caveat -- neither ISO tool is present in this
environment, so the missing-tool guard is exercised for real, but the actual
ISO construction and whether OPNsense's Importer picks it up on a real boot
are UNTESTED. The exact genisoimage/xorriso invocation is a reasonable,
standard construction for a plain ISO9660 volume with one file at a fixed
path -- not independently verified.

### 3. DOCFIX-146 (cont.) -- `opentofu/modules/opnsense-edge`
FILES (new): `opentofu/modules/opnsense-edge/{main,variables,outputs}.tf`.

WHAT: one OPNsense edge VM per call. Mechanically identical to
`modules/cloudinit-vm`'s shape (a `backing_store` overlay disk + a secondary
volume attached as `cdrom`), but with the config-seed volume's
`create.content.url` pointing directly at the ISO9660 file built by script 2
above -- no `libvirt_cloudinit_disk` resource involved (that's NoCloud-format,
wrong for this). Two explicit variables, `lan_network_name` and
`wan_network_name`, rather than a generic ordered list -- OPNsense's own
interface-1-is-LAN/interface-2-is-WAN convention makes list-ordering a real
silent-mistake risk, so the names are explicit instead. No PXE `boot`-order
attribute used (unlike `node-vm`): this VM boots from its own pre-installed
disk, not over the network, so the field flagged UNVERIFIED in
`node-vm/main.tf` doesn't need touching here at all.

TWO THINGS FLAGGED, NOT PRESENTED AS FACT: (a) whether the Configuration
Importer's ISO9660 support behaves as described on a real boot -- the
research is well-sourced (a closed, milestone-targeted, core-developer-
assigned GitHub issue plus a corroborating later bug report) but not
independently tested this session; (b) whether `devices.interfaces` list
order reliably maps to which NIC FreeBSD/OPNsense enumerates first vs.
second -- assumed consistent with general libvirt XML ordering, not
independently confirmed for this specific guest OS.

`config_iso_path` has no default and no fallback: the real `config.xml`
content for any site's LAN/WAN/routing role is design work that hasn't
happened. Not instantiated in root `main.tf`.

`opentofu/README.md` updated: the "Scope of this delivery" and OPNsense
research sections both now describe this as BUILT (not just researched),
with the schema notes section gaining a new entry on `create.content.url`
accepting local filesystem paths (the mechanism both new scripts' outputs
rely on, inferred from `examples/alpine_cloudinit.tf`'s
`libvirt_cloudinit_disk.path` usage, not independently named in the docs
pages fetched this session). Workflow doc gap register item 4 and its
summary-table row updated to match; companion visual tracker (same Artifact
URL) redeployed.

REVERT: `git rm -r opentofu/modules/opnsense-edge scripts/opnsense-prep-image.sh
scripts/opnsense-build-config-iso.sh tests/opnsense-prep-image
tests/opnsense-build-config-iso`; revert the `opentofu/README.md` and
workflow-doc sections if reverting fully.

## Next actionable step

Same underlying need as DOCFIX-144/145: a machine with the `tofu` binary,
`qemu-img`, and `genisoimage`/`xorriso` to actually run the full chain --
`opnsense-prep-image.sh` for real, `opnsense-build-config-iso.sh` for real,
then `tofu apply` the module and boot it, to confirm the Configuration
Importer's ISO9660 behavior and the LAN/WAN interface-ordering assumption
against a real OPNsense instance rather than sourced-but-unverified research.
