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%
Find a file
SysAdmin Pete 07a3e71265 uConsole power/network fixes: swayidle activation, regdomain persistence, wifi CLI auth stack
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
2026-06-28 12:46:43 +00:00
docs Full IaC build: all modules, files, provision, cyberdeck UI, docs 2026-06-20 10:23:44 +00:00
files uConsole power/network fixes: swayidle activation, regdomain persistence, wifi CLI auth stack 2026-06-28 12:46:43 +00:00
modules uConsole power/network fixes: swayidle activation, regdomain persistence, wifi CLI auth stack 2026-06-28 12:46:43 +00:00
provision Recovery fixes from 2026-06-20 reflash session 2026-06-20 07:14:29 -05:00
.gitignore Full IaC build: all modules, files, provision, cyberdeck UI, docs 2026-06-20 10:23:44 +00:00
bootstrap.sh Recovery fixes from 2026-06-20 reflash session 2026-06-20 07:14:29 -05:00
README.md Full IaC build: all modules, files, provision, cyberdeck UI, docs 2026-06-20 10:23:44 +00:00

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