Infrastructure-as-Code for ClockworkPi uConsole CM4 - base image customizations, LUKS provisioning, cyberdeck UI, security toolset. Run bootstrap.sh on a freshly LUKS-provisioned SD to restore full state.
- Shell 87.1%
- Python 8.8%
- CSS 4.1%
THREE INDEPENDENT FIXES BUNDLED:
1. cyberdeck-swayidle.service — was permanently inactive (screen+kbd never
sleep on battery). Root cause: bound to graphical-session.target, which
labwc never activates (no session.target hook on uConsole). Rewired to
default.target — service is now active on every login, and the existing
ExecStartPre wayland-socket guard keeps it patient until labwc is up.
Same bug pattern affects cyberdeck-waybar/swaybg/ac-watcher but those
are masked by labwc autostart launching the binaries directly — left
alone to avoid double-launches; tracked separately.
2. /etc/modprobe.d/cfg80211.conf — persist 802.11 regdomain=US at module
load. Without this, cfg80211 boots country=00 (passive-scan world) and
most 5GHz channels are blocked. Manual 'iw reg set US' works but resets
on every reboot. modprobe option fires early in boot before NM.
3. wifi CLI auth stack (yesterday's work, validated live by user):
- polkit rule: local active-session callers get admin-free NM access
via netdev group membership
- sudoers rule: SSH/non-active-session callers get NOPASSWD on
/usr/bin/nmcli — works around NM's polkit short-circuit for
non-active sessions
- /usr/local/bin/wifi symlink: puts the script on root's secure_path
so 'sudo wifi' works
Verified live on uConsole 2026-06-28 07:11 CDT:
cyberdeck-swayidle.service: active (running) since 07:11:46
iw reg get: country US (DFS-FCC)
wifi connect / status / list: all working over SSH
|
||
|---|---|---|
| docs | ||
| files | ||
| modules | ||
| provision | ||
| .gitignore | ||
| bootstrap.sh | ||
| README.md | ||
uConsole IaC — Infrastructure as Code
ClockworkPi uConsole CM4 Lite | jbelec | hostname: clockworkpi | Tailscale: 100.127.123.24
This repository captures the complete configuration of jbelec's uConsole CM4 as of 2026-06-19 11:46 CDT — the last known-good state before the LUKS lockout incident.
It enables full state reconstruction on a fresh SD card with a single command.
⚡ Quickstart (Reflash + Bootstrap)
Flash a new SD card (runs on Tower, via UA agent)
Ask Pete: "Reflash the uConsole SD at /dev/disk/by-id/<SD_DEVICE> using the recovery key from vault"
Or manually:
# On Tower — inject recovery key from vault:
cd /workspaces/repos/uconsole-iac
# Pete (agent) runs:
# mem_env_exec("sudo provision/reflash.sh /dev/disk/by-id/<SD>", secrets='{"RECOVERY_KEY":"uconsole-luks-recovery-key"}')
After first boot (runs on uConsole)
# SSH in (wait ~60s for Tailscale):
ssh jbelec@100.127.123.24
# Bootstrap everything:
git clone https://git.lab.lostsource.net/jbelec/uconsole-iac
cd uconsole-iac && ./bootstrap.sh
# Reboot when done:
sudo reboot
CRITICAL: Change LUKS passphrase after first boot
sudo cryptsetup luksChangeKey /dev/mmcblk0p2 --key-slot 0
# Old: password (default) → New: your chosen passphrase
Repo Structure
uconsole-iac/
├── README.md ← You are here
├── bootstrap.sh ← Top-level runner: runs all modules in order
├── .gitignore
│
├── modules/ ← Idempotent setup modules
│ ├── 00-apt-base.sh ← System update + base utilities
│ ├── 10-network-modem.sh ← NetworkManager, ModemManager, 4G, Tailscale watchdog
│ ├── 20-power-display.sh ← rpi-backlight, cpu governor, audio, screen sleep
│ ├── 30-security-toolset.sh ← Pentest stack (Bookworm apt + pipx)
│ ├── 40-cyberdeck-ui.sh ← Waybar, wofi, foot, gtk theme, wallpaper, ~/bin scripts
│ ├── 50-keyboard-input.sh ← USB autosuspend, keyboard backlight, sudoers
│ └── 99-finalize.sh ← initramfs rebuild, service enable, sanity check
│
├── files/ ← Config files installed to / at apply time
│ ├── boot/firmware/ ← config.txt + cmdline.txt (post-LUKS migration)
│ ├── etc/ ← systemd services, udev rules, NM conf, initramfs
│ ├── usr/local/bin/ ← uconsole-* scripts + audio + rpi-backlight
│ ├── usr/local/sbin/ ← uconsole-power-profile
│ └── home/jbelec/ ← .config/waybar, wofi, foot, gtk-3.0, labwc, bin/*
│
├── provision/ ← SD card provisioning (runs on Tower)
│ ├── prepare-sd.sh ← Engine: partition + LUKS + btrfs + chroot (PATCHED: +recovery keyslot)
│ ├── provision-uconsole-sd.sh ← Orchestrator (PATCHED: --recovery-key-secret flag)
│ ├── reflash.sh ← NEW: end-to-end reflash wrapper
│ ├── firstboot.{sh,service} ← ua-deck firstboot (mesh cert injection)
│ └── README.md ← Provisioning docs
│
└── docs/
├── REFLASH.md ← Step-by-step reflash + bootstrap procedure
├── KEYSLOTS.md ← Two-keyslot design + recovery procedure
├── CUSTOMIZATIONS.md ← Full inventory: 2026-06-10 → 2026-06-19
└── CHANGELOG.md ← What's in this initial commit
Device Specs
| Item | Value |
|---|---|
| Device | ClockworkPi uConsole CM4 Lite |
| SoC | Raspberry Pi CM4 (4GB RAM, WiFi) |
| Display | 720×1280 DSI (landscape via fbcon=rotate:1) |
| Keyboard | j1n6 QMK firmware (flashed 2026-06-17) |
| Storage | 512 GB PNY High Endurance microSD |
| Cellular | SIMCom SIM7600G-H (Google Fi, T-Mobile/QMI/IPv6-only) |
| OS | Raspberry Pi OS Bookworm 64-bit (v3.1 image, 2025-03-12) |
| Kernel | 6.12.62-v8+ (4K page) |
| LUKS | LUKS2, Argon2id, aes-xts-plain64, iter-time 5000ms |
| Filesystem | btrfs at LUKS top-level (subvolid=5) |
| Tailscale | clockworkpi, 100.127.123.24, mesh upstream: agents.lab.lostsource.net |
Key Customizations Timeline
| Date | Change |
|---|---|
| 2026-06-10 | ua-deck-01 node cert minted (expires 2028-06-09) |
| 2026-06-11 | SD provisioned (prepare-sd.sh run 2, 11 min, 32 GB card) |
| 2026-06-17 | j1n6 QMK keyboard firmware flashed |
| 2026-06-17 | LUKS migration: 32 GB → 512 GB PNY card |
| 2026-06-17 | Tailscale MagicDNS watchdog installed |
| 2026-06-17 | QMI modem mode bringup |
| 2026-06-18 | CPU governor tuning (ondemand AC-aware, 1500 MHz peak both modes) |
| 2026-06-18 | Security toolset installed (Bookworm apt + pipx) |
| 2026-06-18 | USB autosuspend udev (ACTION=="add" only — critical) |
| 2026-06-18 | Keyboard backlight follows screen sleep state |
| 2026-06-19 | Cyberdeck UI: waybar + wofi + foot + gtk theme + wallpaper |
| 2026-06-19 | libgtk-3-bin fix (gtk-launch for wofi drun) |
| 2026-06-19 | dbus-update-activation-environment in labwc autostart |
| 2026-06-19 | LUKS lockout incident — this repo created for recovery |
LUKS Keyslot Design
Two keyslots are now mandatory:
- Slot 0: User passphrase (typed at boot prompt)
- Slot 1: 64-hex recovery key from UA vault (
uconsole-luks-recovery-key)
See docs/KEYSLOTS.md for full design rationale and recovery procedure.
Security Toolset
Pentest stack installed from Debian Bookworm (no Kali overlay — glibc incompatibility):
- Wireless: aircrack-ng, wifite, hcxtools, reaver, bettercap, masscan
- SDR: gnuradio, gqrx-sdr, rtl-sdr, rtl-433
- GPS: gpsd, foxtrotgps, gpsprune
- Recon: nmap, nikto, gobuster, sqlmap, hashcat, john, hydra
- pipx: impacket 0.13.1, meshtastic 2.7.9
See modules/30-security-toolset.sh for full list and known gaps.
Secrets (never in this repo)
| Secret | Vault Key | Used By |
|---|---|---|
| LUKS recovery key | uconsole-luks-recovery-key |
reflash.sh, KEYSLOTS.md |
| Forgejo git token | forgejo-git-token |
git push |
| Forgejo admin token | forgejo-admin-token |
repo admin |
| Tailscale auth key | (in firstboot bundle) | provision/firstboot.sh |
Forgejo Repo
https://git.lab.lostsource.net/jbelec/uconsole-iac