0.2.0
[0.2.0] — 2026-07-09
Hardware verification + hardening + boot-time tuning pass. All 0.1.0
functionality still applies; this release focuses on making the appliance
faster to boot, safer to compromise, and more visible in the Devices tab.
Added
- Dump a device to a disk image (new). Devices tab gets a Dump…
button; pick a compression (xz / gz / none) and the browser streams
the raw block device down as a downloadable image with a generated
filename (airlock-<label>-<date>.img[.xz|.gz]). Read-only op —
sync()first, thenos.Open("/dev/<parent>"), pipe through the
compressor (xz -c -T 0for parallel or stdlibcompress/gzip),
write straight to the response body. No unmount, so SMB sessions
aren't disturbed. Endpoint:GET /api/devices/{parent}/dump?compression=…. - fsck per partition (new). Devices tab gets a Check button on
every partition with a supported filesystem. Modal picks Check
(read-only) or Repair (auto-fix,-p/-a/-yper tool),
unmounts, runse2fsck/fsck.vfat/fsck.exfat/ntfsfix/
fsck.hfsplus, streams stdout+stderr live via SSE into a scrollable
log in the modal, remounts. Endpoint:
POST /api/partitions/{name}/fsck?mode=check|repair. stage-airlock/06-fast-boot: pi-gen sub-stage that bakes the
same service disables +dtoverlay=disable-btwe ship in
AIRLOCK_FAST_BOOT=1directly into the image. Fresh flashes boot in
~14 s without needing the installer flag.- Release workflow now builds
.img.xz: taggingx.y.znow runs
a second CI job (~45 min) that clones pi-gen inside GitHub Actions,
syncsstage-airlock/, produces the flashable image, and attaches
airlock-<tag>-linux-arm64.img.xz+ sha256 to the same GitHub
Release alongside the binary tarball + install bundle. - Flash OS images to a drive (new). Devices tab gets a Flash…
button; the modal takes a.img,.img.xz, or.img.gzfile, streams
the upload through the appropriate decompressor (xz -dcor stdlib
compress/gzip) straight onto/dev/<parent>in 4 MB blocks with
per-500 ms SSE progress events. Zero intermediate storage — a 3 GB Pi
OS image never lands on the airlock SD, only on the target. Adds
xz-utilsto the installer's package list and the pi-gen stage.
Endpoint:POST /api/devices/{parent}/flash?compression=none|xz|gz
(raw body,text/event-streamresponse). Safety-gated to USB
devices, uses the same quarantine mechanism as format so the daemon
doesn't auto-mount the fresh partition table mid-write. - Mount button on the Devices tab for USB partitions that have a
supported filesystem but aren't currently mounted by airlock. Backed
byPOST /api/partitions/{name}/mount— safety-gated to USB-attached
devices, firesudevadm trigger --action=addand the daemon's normal
event handler picks up the mount. AIRLOCK_FAST_BOOT=1installer flag. Disables services not needed
on a headless appliance (bluetooth, hciuart, triggerhappy, ModemManager,
unused Samba flavoursnmbd/winbind/samba-ad-dc,apt-daily
timers,e2scrub,dphys-swapfile,NetworkManager-wait-online,
rpi-eeprom-update); maskskeyboard-setupandconsole-setup;
disables cloud-init post-first-boot; addsdtoverlay=disable-btto
/boot/firmware/config.txtto skip Bluetooth radio init.AIRLOCK_DISABLE_WIFI=1installer flag. Addsdtoverlay=disable-wifi
after checking thateth0is up — refuses to run if not, so it can't
accidentally orphan a Wi-Fi-only Pi.AIRLOCK_HARDEN_USB=1installer flag plusscripts/modprobe-airlock.conf.
Blocks HID (keyboards / mice) and CDC-* (USB Ethernet / serial) driver
binding at attach time while leaving USB mass storage alone —
neutralizes "BadUSB" / "USB Rubber Ducky" attacks against the console.- systemd seccomp + prctl sandbox on
airlockd.service:
NoNewPrivileges,LockPersonality,RestrictSUIDSGID,
RestrictRealtime,RestrictNamespaces,
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK.
Mount-namespace-inducing directives are deliberately excluded (see
Fixed below). - New docs sections in
docs/install.md: Optional: faster boot
(with per-service explanation, measured impact, and a manual recipe),
Additional hardening (systemd sandbox + optional USB blocklist),
and Flashing OS images to a drive. - "Why the name" section in the README explaining the security
posture — Airlock as the isolation chamber between untrusted media
and your primary machine (nosuid,nodev,noexec, no autorun, BadUSB
neutralization on a headless box, kernel FS-parser CVEs land on the
Pi instead of your laptop). Explicit note that endpoint hygiene
(AV, sandbox) is still the user's job. - Devices tab payload now includes
can_mount,can_relabel, and
can_fsckflags per partition, so the UI shows only the actions
that make sense for each filesystem.
Fixed
- Duplicate mDNS advertisement removed. Samba's built-in mDNS
publisher was shipping a competing_device-info._tcp(and
_smb._tcp) record under the NetBIOS nameAIRLOCKwith
model=MacSamba, which shadowed the record our Avahi service
publishes. Suppressed viamulticast dns register = noin
smb.conf. The Avahi service still advertises
_device-info._tcpwithmodel=MacPro7,1@ECOLOR=226,226,224; the
actual icon Finder draws depends on macOS's undocumented icon
table, and reliably matching a specific "network storage"
appearance (e.g. TrueNAS's) requires macOS-side vendor recognition
we can't advertise. - SMB shares appeared empty when the systemd sandbox created a private
mount namespace.ProtectSystem=strict+ReadWritePathsbind-mounted
/mnt/airlockinto the service's own namespace as slave, so mounts
airlockd made were invisible to smbd running in the host namespace.
MountFlags=shareddidn't fix it (a slave mount only propagates
host→service, not back). Sandbox reduced to seccomp/prctl only —
no private mount namespace, mounts propagate correctly. - Format operation "device or resource busy" during
wipefs— added a
device quarantine so the daemon ignores auto-mount events for the
target device between unmount and mkfs. udevadm trigger --subsystem-match=blockno longer accidentally
matches the Pi's own boot media (mmcblk*) — the udev rule requires
ID_BUS=usb, and every mount pass additionally cross-checks
/proc/self/mountinfobefore touching a device.- Windows-friendly Copy button on the Mounts tab now sends
\\host\shareon Windows andsmb://host/shareeverywhere else.
Boot-time measurements (Pi 4 / Trixie reference hardware)
| Configuration | multi-user.target reached |
|---|---|
| Stock Pi OS Lite Trixie | 24.0 s |
+ AIRLOCK_FAST_BOOT=1 |
14.2 s |
+ AIRLOCK_DISABLE_WIFI=1 |
13.7 s |