Conversation
There was a problem hiding this comment.
Pull request overview
This PR migrates the classroom laptop setup from macOS bootstrap scripts to a declarative NixOS flake that can be built into both an installable system configuration and a bootable installer ISO for Intel MacBooks.
Changes:
- Introduces a NixOS flake with modular system configuration (XFCE desktop, VS Code, Python, networking, Broadcom WiFi).
- Adds a GitHub Actions workflow to build and publish a bootable installer ISO plus a Python-based install/update flow.
- Adds Renovate + dev tooling (direnv + treefmt/pre-commit), and removes the legacy macOS provisioning artifacts.
Reviewed changes
Copilot reviewed 23 out of 26 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| settings.json | Removes legacy macOS VS Code settings bootstrap file. |
| org.weallcode.logon.plist | Removes legacy macOS LaunchAgent. |
| logon.script.sh | Removes legacy macOS logon script. |
| install.sh | Removes legacy macOS installation script. |
| .zshrc | Removes legacy macOS zsh customization. |
| flake.nix | Defines flake inputs, dev tooling (treefmt/pre-commit), and NixOS/ISO outputs. |
| flake.lock | Pins flake inputs for reproducible builds. |
| modules/base.nix | Main classroom NixOS configuration, packages, Home Manager wiring, update shortcut. |
| modules/disk.nix | Disk partitioning layout for disko-based installs. |
| modules/hardware-configuration.nix | Hardware/boot settings targeting Intel MacBooks (incl. Broadcom import). |
| modules/broadcom.nix | Enables Broadcom STA driver and related kernel module settings. |
| modules/networkmanager.nix | Enables NetworkManager and configures system-wide WiFi connection storage. |
| modules/nix-settings.nix | Sets Nix daemon settings, substituters, and GC defaults. |
| modules/python.nix | Provides Python environment (tkinter/rich/pip) for classroom usage and scripts. |
| modules/vscode.nix | Home Manager VS Code config: extensions, interpreter path, AI feature disabling, editor defaults. |
| modules/xfce.nix | XFCE desktop setup: autologin, wallpaper, panel/launcher config. |
| modules/iso.nix | Installer ISO configuration and desktop “Classroom Setup” shortcut. |
| scripts/machine-setup.py | Installer-side script that partitions, installs NixOS from the flake, and reboots. |
| scripts/update.py | Classroom update script that rebuilds from GitHub flake and upgrades weallcode-robot via pip. |
| README.md | Documents new NixOS-based install/update process and repo structure. |
| .envrc | Enables direnv flake-based dev shell. |
| .gitignore | Updates ignored files for direnv/pre-commit/ruff cache. |
| renovate.json | Adds Renovate configuration for monthly dependency updates (incl. Nix). |
| .github/workflows/build-iso.yml | Builds the installer ISO in CI and uploads it as an artifact. |
| .github/workflows/renovate.yml | Runs Renovate on a schedule / manually. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| console.rule("Installing weallcode-robot") | ||
| subprocess.run( | ||
| ["pip", "install", "--user", "--upgrade", ROBOT_PKG], | ||
| check=True, | ||
| ) |
There was a problem hiding this comment.
The update script shells out to pip directly and installs from an unpinned Git URL. Using pip (vs python -m pip) can pick up a different interpreter than the one configured for the system, and installing from a moving Git HEAD is a supply-chain/reproducibility risk. Consider invoking pip via the intended interpreter and pinning weallcode-robot to a tag/commit (or a published version) if you need deterministic updates.
| "/mnt", | ||
| "--flake", | ||
| FLAKE_REF, | ||
| "--no-root-password", |
There was a problem hiding this comment.
nixos-install --no-root-password can result in a system where the root account has an empty password (depending on installer defaults), which is risky on shared devices. Consider explicitly locking the root account after install and relying on a dedicated admin user, or setting a root password via a hashed secret if root login is needed.
| "--no-root-password", |
| { pkgs, ... }: | ||
| let | ||
| python = pkgs.python3.withPackages (ps: [ ps.tkinter ps.rich ps.pip ]); | ||
| in | ||
| { | ||
| environment.systemPackages = [ python ]; |
There was a problem hiding this comment.
The PR description lists weallcode_robot as part of the base Python setup, but this module only installs tkinter, rich, and pip. If weallcode-robot is expected to be available immediately after installation (before running the update shortcut), consider adding it here (via Nix or by running the pip install as part of the install flow) or updating the PR description to match the actual behavior.
| users.users.weallcode = { | ||
| isNormalUser = true; | ||
| extraGroups = [ "wheel" "networkmanager" "audio" "video" ]; | ||
| initialPassword = "Coder4life!"; | ||
| }; |
There was a problem hiding this comment.
users.users.weallcode.initialPassword hard-codes a known plaintext password in the repo. Since the user is also in wheel, anyone with access can gain admin privileges (and the password is effectively public). Consider removing the plaintext password from the flake (e.g., set a locked password and rely on auto-login + passwordless sudo for only specific commands, or use a hashed password sourced from a non-committed secret).
| initialPassword = "Coder4life!"; | ||
| }; | ||
|
|
||
| security.sudo.wheelNeedsPassword = false; |
There was a problem hiding this comment.
The installer user is configured with a plaintext initialPassword and passwordless sudo for the entire wheel group. Combined with auto-login, this makes the live environment trivially root-accessible. If this ISO could be used outside a controlled setup flow, consider locking the account password and/or narrowing passwordless sudo to just the commands needed for installation (e.g., disko, nixos-install, reboot).
| initialPassword = "Coder4life!"; | |
| }; | |
| security.sudo.wheelNeedsPassword = false; | |
| # Lock the password to avoid a reusable plaintext installer password. | |
| # Auto-login via the display manager still works without a usable password hash. | |
| initialHashedPassword = "!"; | |
| }; | |
| security.sudo = { | |
| # Require a password for general wheel usage. | |
| wheelNeedsPassword = true; | |
| # Allow the installer user to run only the necessary installation commands | |
| # without a password, rather than granting full passwordless root access. | |
| extraRules = [ | |
| { | |
| users = [ "nixos" ]; | |
| commands = [ | |
| { command = "/run/current-system/sw/bin/disko"; options = [ "NOPASSWD" ]; } | |
| { command = "/run/current-system/sw/bin/nixos-install"; options = [ "NOPASSWD" ]; } | |
| { command = "/run/current-system/sw/bin/reboot"; options = [ "NOPASSWD" ]; } | |
| ]; | |
| } | |
| ]; | |
| }; |
| "editor.wordWrap" = "on"; | ||
| "editor.defaultFormatter" = "charliermarsh.ruff"; | ||
| "editor.minimap.enabled" = false; | ||
| "editor.formatOnSave" = true; |
There was a problem hiding this comment.
editor.defaultFormatter is set globally to the Ruff extension. That will apply to non-Python files too, which can break formatting (and also prevents Prettier from being used where intended). Consider scoping Ruff as the default formatter only under [python] and setting Prettier for relevant filetypes (or omitting a global default).
Summary
Replaces the previous scripts for macOS config with a NixOS flake configuration for the classroom laptops (Intel MacBooks).
We ran into issues getting programs to run consistently across these machines, especially because modern versions of MacOS do not support these MacBooks. With Linux we can run an up-to-date system on legacy hardware. NixOS lets us declare the entire system config in code so every laptop is identical.
Omar and I have successfully installed this configuration on the laptops that have USB-A ports. During setup we verified that Python with
tkinterruns successfully in VS Code, all VS Code extensions are installed, and AI features are turned off.Included in this PR:
NixOS system config
XFCE desktop
WeAllCode wallpaper
auto-login
Python 3
tkinterweallcode_robotrich(used in scripts)VS Code
Firefox
Broadcom WiFi driver
Bootable installer ISO
.isoClassroom Update script
weallcode-robotvia pipRenovate
Dev environment