- Go 50.1%
- TypeScript 29.3%
- Shell 18.3%
- C 1.2%
- CSS 0.5%
- Other 0.6%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
- build/version.sh: YY.MM comes from the branch when it is exactly release/YY.MM, otherwise from the build month; PATCH stays the patch id and VERSION= overrides. The Makefile, build.sh, plugin builds and QEMU suites ask it; a unit suite covers 22 cases. - mkartifacts.sh: the .ironkey check no longer fails when objdump is killed by SIGPIPE under pipefail. - QEMU suites: boot-screen reads /dev/vcs1 with LC_ALL=C; plugin suites take the newest build; test-backup polls for the dropped checkpoint; test-site-shots watches the display through QMP when the image has no serial console. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XvgVC2H8Wa7QukpNzTJia9 |
||
| build | ||
| cmd | ||
| docs | ||
| initramfs | ||
| internal | ||
| locales | ||
| pluginsdk | ||
| rootfs | ||
| sdk | ||
| test | ||
| tools | ||
| web | ||
| .gitignore | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| eslint.config.js | ||
| go.mod | ||
| go.sum | ||
| iron-icon.png | ||
| iron-product-logo-white.png | ||
| iron-product-logo.png | ||
| LICENSE.md | ||
| Makefile | ||
| NOTICE.md | ||
| README.md | ||
Wise Foundry Iron
Wise Foundry Iron is the bare-metal host OS of Wise Foundry: an immutable Alpine Linux appliance that runs KVM virtual machines (libvirt QEMU), system containers (libvirt LXC), and Docker workloads, managed by a local agent and the Iron Console status screen.
- Read-only, dm-verity verified EROFS root in two A/B slots
- Signed unified kernel images booted by systemd-boot, with boot counting and a post-boot health check for automatic rollback
- Host configuration on
/persist, workload data on/var; an OS rollback never touches either - Signed update bundles (
.ironupd), a hybrid installer ISO, and a pre-installed raw disk image
Design, disk layout, persistence map, and all tool contracts: docs/architecture.md.
Evaluating Iron
If you are evaluating the CTP Preview, start with the evaluator guide: hardware and guest support, installation with Secure Boot, networking, workloads, operations and known issues.
Building
Requirements: podman, make. Builds run rootless in an Alpine 3.24 builder
container; no loop devices or root privileges are needed.
A bare make (or make help) lists every target and the variables that
matter; it builds nothing. There are two variants: VARIANT=dev, the debug
build (the default; development keys in ./keys, depots for PREREL), and
VARIANT=release (keys outside the repository, depots for PRODUCTION).
make help # every target, grouped, with the variables
make keys # development signing keys in ./keys (never commit)
make image # dev (debug) variant -> out/iron-<v>-dev.*
make release # installable images -> out/iron-<v>.{iso,raw,ironupd}, v = YY.MM.PATCH, plugins -> out/plugins/release/ (IRON_SIGNING_KEYS; docs/release-keys.md)
make test-images # images for the QEMU tests -> out/test/ (never install these)
make plugins # plugins -> out/plugins/dev/ (needs this version's image for its SBOM)
<v> is YY.MM.PATCH (build/version.sh): YY.MM is this repository's
branch when it is release/YY.MM, else (dev, any other branch, a detached
HEAD, no git) the year and month of the build (UTC); PATCH is 0 unless given
(make release PATCH=1); VERSION=YY.MM.PATCH overrides both. On dev, a
later make plugins, depot or usb in another month needs
VERSION=YY.MM.PATCH to find the build.
Outputs in out/:
| File | Use |
|---|---|
iron-<v>.iso |
UEFI installer (CD or USB); also upgrades existing hosts |
iron-<v>.raw |
Pre-installed 16 GiB disk, slot A populated |
iron-<v>.ironupd |
Signed update bundle for iron-update apply |
iron-<v>.txt |
Build ID, root hash, checksums |
Write the hybrid installer ISO to a USB stick on Linux by identifying its
whole-disk device with lsblk, then running:
sudo make usb USB_DEVICE=/dev/sdX USB_IMAGE=out/iron-<v>.iso
This erases the selected disk. The writer refuses partitions, mounted disks and
the disk containing the running system, and asks you to type the full device
name before it writes. Use the .iso, not the pre-installed .raw image, for
an installer USB.
Development images (-dev) add a root automation shell on ttyS1 (used by the
QEMU tests) and are labelled "development" everywhere. No image has a login
getty: the only local shell is the credential-protected emergency shell (the
Iron Console, or tty2 on the machine's own screen), which is a service and
off by default.
Everything under out/test/ exists only for automated tests: some of those
images are deliberately broken (-fault-*) and must never be installed.
Testing
make test-unit # host tool unit tests (Alpine container)
make test-go # Go vet + unit tests
make test-web # web console typecheck, lint, unit tests
make test-images # out/test: this version as base, PATCH+1 good, PATCH+2 faulty
make test-guest-media # out/test/cache: LXC rootfs, Alpine cloud image and virt ISO for guest tests
make test-lxc # LXC containers on a real image (datastore, runtime mounts, snapshots, clones)
make test-vm # virtual machines under nested KVM (cloud-init, consoles, snapshots, clones, OVMF + TPM)
make test-guest-controls # NUMA, USB, throttling, blockers, monitor, guest agent, console expiry, snapshot chains, quotas, interrupted moves
make test-network # kSwitches, teams, oSwitches, port groups, routers, revert protection
make test-datastores # directory, disk and NFS datastores, health and the content browser
make test-docker # Docker containers and Compose stacks
make test-maintenance # maintenance mode
make test-ova # OVA/OVF import and export
make test-plugin-caps # the plugin capability framework (builds the fixture plugin first)
make test-bind-mounts # datastore bind-mount security regressions (symlinks, Compose, restarts)
make test-dd-usb # the ISO written raw to a USB disk boots and installs
make test-iscsi # iSCSI initiator and target plugins (builds the shipping plugins first)
make test-zfs # ZFS plugin
make test-cluster-fs # shared OCFS2 datastore on an iSCSI LUN
make test-secureboot # Secure Boot enrollment and refusals
make test-alloy # host side of Alloy enrollment against the reference alloy-dev
make test-qemu # the QEMU suite (test/qemu/run-all.sh): boot, install, update/rollback, upgrades,
# web API, network, storage, plugins, LXC, VMs, OVA, recovery ISO; not secureboot or alloy
bash test/qemu/test-web-screenshots.sh # Foundry Console screenshots from a real VM (out/web-screenshots)
QEMU tests need /dev/kvm, qemu-system-x86_64, OVMF (edk2-ovmf),
socat, and python3 on the host; the VM test also needs nested KVM (it falls
back to TCG) and ssh-keygen, and the guest tests download media once
(curl, mkfs.ext4).
Host console
The physical console, BMC viewer and serial port show the Iron Console, laid
out like the ESXi DCUI with orange in place of yellow: host and hardware summary,
management URLs, and <F2> Customize System/View Logs / <F12> Shut Down/Restart.
F2 opens System Customization (password, management network with automatic
revert, network tests and restore, maintenance mode, rollback, plugins,
troubleshooting options with the emergency shell, logs, support information)
after signing in with a local account. Upgrades, Alloy enrollment and turning
SSH on are done in the web console. Screens and keys:
docs/console-ui.md.
Web console and users
Each host serves the Foundry Console at https://<host>/, laid out like the
ESXi Host Client: host summary and monitoring, system settings (host name, DNS,
time, services, certificate), users and roles, updates and rollback,
datastores with a datastore browser, containers (Docker: create and edit,
logs, browser shell, stats, images, volumes, networks), and networking
(kSwitches with NIC teaming, kernel adapters with automatic revert, oSwitches,
port groups, virtual routers, physical NICs).
Long operations run as tasks shown in Recent tasks.
The certificate is self-signed on first boot; compare its SHA-256 fingerprint
with System information on the web console's Host page, opened from a trusted
network, before trusting it.
Local accounts are shared by the web console and the Iron Console:
| Role | Can |
|---|---|
| Administrator | everything, including users, network and storage configuration, upgrades and the emergency shell |
| Operator | power, maintenance mode, service restarts, network tests, audit log, datastore files, and creating and operating VMs, LXC and Docker containers (including logs and shell), without host devices or privileged guests |
| Read-only | view status, configuration, logs, datastores, VMs, LXC and Docker containers (without environment values); change own password |
The built-in admin account is the break-glass administrator and cannot be
removed.
Local accounts can add two-factor sign-in (TOTP, with recovery codes) for the web console, the API and the recovery console, and an Administrator can require it for administrators (docs/mfa.md); the Iron Console and SSH do not ask for it.
SSH is off by default. An Administrator can enable it in Manage › Services
(the Iron Console's Troubleshooting Options only shows its state); it then
accepts only root with public keys added under Manage › Services › SSH, and
both consoles show a warning while it is enabled. Manage accounts in Host ›
Manage › Security & users, or from the emergency shell with
iron-agent user list|add|passwd|set-role|disable|enable|delete|reset-mfa.
API and screens: docs/web-api.md,
docs/web-console.md.
Build the web console with the image (make image); make test-web runs its
type checks, lint and unit tests.
Virtual machines
Virtual machines run on libvirt QEMU/KVM (Host › Virtual machines). Disks,
EFI variable stores and cloud-init seeds are stored on datastores; ISO images
come from each datastore's iso/ folder or are downloaded from a URL. VMs
support the Proxmox VE hardware and options — SeaBIOS or OVMF, TPM 2.0, q35 or
i440fx, CPU topology, types and limits, ballooning and hugepages, VirtIO SCSI,
VirtIO, SATA and IDE disks with cache, discard, I/O threads and limits,
network models, PCI and USB passthrough, cloud-init, virtiofs shares, guest
agent — plus snapshots, full clones, disk import, resize and move, OVA import
and export, and noVNC and serial consoles in the browser. Details: docs/vm.md.
Datastores and stacks
Datastores can be local directories, ext4 or xfs disks, or NFS shares (for
example a shared ISO library); see docs/datastores.md. Plugins add ZFS pools,
iSCSI LUNs and shared OCFS2 volumes. Docker containers can
also be deployed as Compose stacks with the same safety rules as single
containers; see docs/compose.md.
Networking
Networking has two layers. kSwitches are kernel bridges on the physical
NICs: they carry NIC teaming (active-backup, LACP and the other bonding modes)
and the kernel adapters (krn0 for management) that hold the host's addresses.
oSwitches are Open vSwitch bridges, each tied to a kSwitch; their port
groups (external VLANs or host-internal networks) are what VMs, LXC and Docker
containers attach to. Virtual routers connect port groups with DHCP, DNS,
source NAT, port forwards, floating addresses and static routes. Docker uses
Iron's iron network driver, so docker run --network and Compose work with
port groups. Hosts on the earlier iSwitch model migrate automatically. Details:
docs/networking.md.
LXC containers
System containers run on libvirt LXC (Host › LXC containers). Create them
from the images.linuxcontainers.org catalog or from a custom root filesystem
on a datastore; each container's root disk and volumes are qcow2 images on
datastores, attached only while it runs. Containers are unprivileged by
default and support the Proxmox VE container options plus snapshots, full
clones, CPU pinning and more. Details: docs/lxc.md.
Plugins
Plugins are signed layers (packages, drivers, kernel modules, development
tools) stacked over the read-only system image at boot; none are installed by
default. Install and enable them in Host › Manage › Plugins (or with
iron-plugin install FILE --enable) and restart. make plugins builds the
plugins under build/plugins/ into out/plugins/dev/; make release into
out/plugins/release/, the only directory for an Alloy holding the release key
(docs/release-keys.md "Where plugins go").
A plugin can also extend the Foundry Console — a tab, a toolbar button, a group of fields — and that code ships in its layer rather than in the base image, so a host without the plugin never downloads it (docs/console-extensions.md).
APK is not part of the base image, and neither is its package database. A
plugin built with --writable-root gives the host a persistent writable root
layer for development (none is built today). While one is enabled both consoles
show a development-mode warning; Discard development changes returns the root
to the stock image at the next restart.
Writing one: docs/plugins.md. The format and the boot-time checks: "Plugins" in docs/architecture.md. The plugins in this tree have their own documents — ZFS, NFS exports, iSCSI initiator and target, cluster filesystem, Proxmox import and Intel Quick Sync.
Upgrading
Every Iron release can upgrade any earlier installation: the bundle format and
disk layout are stable, the new version goes to the unused A/B slot, and the
previous version stays installed for rollback. A newer build of the same
version also counts as an upgrade; an equal or older build needs Allow
downgrade. Host configuration (/persist)
and workload data (/var, datastores) are never rewritten.
From installer media (like an ESXi upgrade): boot the newer ISO, select the
disk marked * (contains Wise Foundry Iron), choose
Upgrade Wise Foundry Iron, preserve configuration and data, and confirm with F11.
For unattended upgrades put an iron-answers.conf with MODE=upgrade and
DISK=/dev/… on media labelled IRONANSWERS. If the host's last upgrade never
confirmed (for example it shows "Boot not yet confirmed"), the installer keeps
the last confirmed version and replaces the unconfirmed one.
From the running host: in the web console, Host › Manage › Updates › Upgrade, then upload a bundle, give a URL for the host to download, or pick attached installer media. The bundle's signature, compatibility and space checks are listed before the upgrade starts; the new version starts when you restart the host. The Iron Console does not upgrade; it only rolls back.
From a shell (emergency shell or automation):
iron-update find-media # attached installer media
iron-update fetch https://updates.example/iron-26.09.0.ironupd
iron-update verify --json /var/lib/iron/staging/iron-26.09.0.ironupd
iron-update apply --reboot /var/lib/iron/staging/iron-26.09.0.ironupd
iron-update status
The new deployment boots with three tries. iron-health blesses it once its
checks pass (the management network, local datastores, /dev/kvm, libvirt
answering and every agent component; docs/architecture.md "Health check and
boot blessing"); otherwise the host reboots until systemd-boot
falls back to the previous deployment, and the Iron Console shows the
rollback. Rollback to Previous Version (or iron-update rollback --reboot)
returns to the previous deployment on request.
Support bundles
Host › Monitor › Support in the web console (or POST /api/v1/support/bundles,
or iron-support bundle --output FILE) collects logs, configuration and
diagnostics for Wise Global Solutions support into one gzip tar. Password hashes,
private keys, enrollment codes, container environments, .env files and
cloud-init user data are never included; the host keeps the five newest bundles.
A host whose boot stopped before the agent started can still hand one over
through the recovery console on port 9443
(docs/recovery-console.md).
See docs/support-bundles.md.
Wise Foundry Alloy
A host joins Wise Foundry Alloy with an enrollment code created in Alloy (Host ›
Manage › Alloy › Enroll, the Iron Console's F2 › Wise Foundry Alloy, or
iron-agent alloy enroll CODE).
The host pins Alloy's certificate and stores Alloy's Ed25519 public key; Alloy then
signs every call to the host API and the host checks each one against that key.
make alloy-dev builds a reference Alloy for development and tests. How the
association works is described in docs/alloy.md.
Secure Boot
UKIs and systemd-boot are signed with the db key of the build's key set:
keys/ for development builds, a directory outside the repository
(IRON_SIGNING_KEYS) for release builds. Images carry PK.auth,
KEK.auth and db.auth in loader/keys/iron/ on the ESP; with the firmware in
setup mode, choose Enroll Secure Boot keys: iron in the boot menu. Key sets,
enrollment files, the no-rotation rule and the enforcement test are described in
docs/release-keys.md; evaluators follow
docs/guide/install.md.
License
Wise Foundry Iron is licensed under the Apache License, Version 2.0; see LICENSE.md. Third-party components and their licenses are listed in NOTICE.md.