No description
  • Lua 59.2%
  • Shell 40.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Samuel Mellert a3276f43b2
feat(bootstrap): adaptive MDM-aware provisioner with tool allow-list
Rework bootstrap-minimal.sh from a fixed minimal installer into an
environment-adaptive provisioner:

- Detect context: Jamf/MDM enrollment, brew/Workbrew presence, admin.
- Inline manifest: CLI tools (mise), GUI apps with a per-app method chain
  (cask -> jamf-ss), and a user-maintained MDM_ALLOWED allow-list. On a
  managed Mac, GUI apps not on the allow-list are skipped; non-automatable
  installs (Self-Service-only, Workbrew-refused casks) are collected into a
  manual to-do report printed at the end.
- git is now optional: repo, oh-my-zsh and plugins fetched via tarball when
  git is absent (no Xcode CLT dependency).
- eza pinned to aqua backend (git-free + checksum-verified); its registry
  default is asdf which requires git.
- Enable mise lockfile + paranoid + aqua cosign/slsa before installing tools.
- bash 3.2 compatible (fresh Macs ship /bin/bash 3.2): no associative arrays,
  guarded empty-array expansions under `set -u`.

Verified: shellcheck clean, parses under /bin/bash 3.2.57, detection correct.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 16:37:51 +02:00
.githooks fix(dotfiles): pre-commit hook only runs on secret-touching commits 2026-06-04 16:29:40 +02:00
files feat(bootstrap): minimal MDM-friendly bootstrap (no sudo/brew) 2026-07-07 16:04:17 +02:00
roles feat(dotfiles): migrate mise, gh, atuin, btop, htop, bpytop, karabiner from legacy clone 2026-06-04 16:29:40 +02:00
secrets chore(ssh): rock via static IP 192.168.0.63 instead of hostname 2026-06-04 16:29:41 +02:00
.gitignore feat(dotfiles): migrate mise, gh, atuin, btop, htop, bpytop, karabiner from legacy clone 2026-06-04 16:29:40 +02:00
.sops.yaml Add base setup with dev-tools (ssh, git, terminal emulators, prompt) 2025-12-28 22:15:28 +01:00
ansible.cfg Add initial bootstrap code 2025-12-28 18:38:39 +01:00
bootstrap-minimal.sh feat(bootstrap): adaptive MDM-aware provisioner with tool allow-list 2026-07-07 16:37:51 +02:00
bootstrap.sh fix(sudo): Keep sudo alive for the duration of the script execution 2026-02-07 11:39:40 +01:00
inventory Add initial bootstrap code 2025-12-28 18:38:39 +01:00
playbook.yml feat(midnight-commander): Add midnight-commander configuration + skin 2026-02-08 21:43:27 +01:00
PROJECT_MISSION.md Add initial bootstrap code 2025-12-28 18:38:39 +01:00
README.md feat(bootstrap): adaptive MDM-aware provisioner with tool allow-list 2026-07-07 16:37:51 +02:00
update_secrets.sh feat(secrets): Add git pre-commit hook to ensure secrets are up-to-date 2025-12-30 10:36:16 +01:00

Dotfiles 🚀

Automated, reproducible macOS development environment setup using Ansible, GNU Stow, Mise, and SOPS.

Quick Start

/bin/bash -c "$(curl -fsSL https://git.smlit.de/samuel/dotfiles/raw/branch/main/bootstrap.sh)"

Adaptive / MDM-aware Bootstrap

For a "fresh" or MDM-managed Mac. Detects the environment and installs the tools permitted in that context — the userspace tier needs no sudo, no Homebrew, no git:

/bin/bash -c "$(curl -fsSL https://git.smlit.de/samuel/dotfiles/raw/branch/main/bootstrap-minimal.sh)"

Tier 0 — always (userspace):

  • mise self-installs to ~/.local/bin and provides starship, eza, direnv, zoxide, bat, ripgrep, fzf, fd, atuin, zellij, jq as static binaries via the aqua backend (checksum-verified; lockfile
    • paranoid + cosign/slsa are enabled before install).
  • oh-my-zsh + plugins, JetBrainsMono Nerd Font (~/Library/Fonts), and the same .zshrc/.zprofile as the full setup — guarded with command -v so they degrade gracefully when a tool is missing.
  • git is optional: repo, oh-my-zsh and plugins are fetched via tarball when git is absent (no Xcode Command Line Tools needed).

GUI layer — environment-dependent (detects Jamf/MDM, brew/Workbrew, admin):

  • unmanaged + brew → installs casks (Raycast, Ghostty, kitty).
  • Jamf-managed + Workbrew → installs only casks on the MDM allow-list (edit MDM_ALLOWED in the script); everything else (Self-Service-only apps, or casks Workbrew refuses) is collected into a manual to-do report.
  • locked (no brew) → GUI apps reported for manual install.

The tool manifest and MDM allow-list live in a clearly-marked block at the top of bootstrap-minimal.sh. Run ./bootstrap.sh (Ansible) for the full unmanaged environment incl. SOPS secrets and language runtimes.

Manual Setup

  1. Clone the repository:
git clone https://git.smlit.de/samuel/dotfiles.git ~/development/dotfiles
cd ~/development/dotfiles
  1. Ensure Age Key exists: Place your Age secret key at ~/.config/sops/age/keys.txt. This is required to decrypt secrets (Git identities, etc.).

  2. Run Bootstrap:

./bootstrap.sh
  • Installs Homebrew & Ansible (if missing).
  • Installs Core Tools & Apps.
  • Symlinks Dotfiles.
  • Decrypts Secrets.

Manual Steps

Due to macOS security restrictions (TCC/SIP), some things cannot be automated:

  1. Full Disk Access: Grant "Full Disk Access" to your terminal (Ghostty/Kitty/WezTerm) in System Settings -> Privacy & Security.
  2. WireGuard: Open the WireGuard app and import tunnels from ~/development/dotfiles/files/wireguard/.
  3. Safari Extensions: Enable 1Password and AdGuard extensions in Safari Settings.

🏗 Architecture

  • Orchestration: Ansible (Local Playbook).
  • Package Management:
    • Homebrew: GUI Apps (Casks) & CLI Utilities (git, starship, atuin).
    • Mise: Runtimes (node, python, go) & Infra Tools (sops, age, direnv). pinned versions.
  • Dotfile Management: GNU Stow.
    • Symlinks configurations from files/ to ~/.config/ or ~/.
  • Secrets: SOPS + Age.
    • Encrypted files live in secrets/.
    • Decrypted on bootstrap to files/ (gitignored).

🛠 Features

Shell & Terminal

  • Terminals: Configurations for Ghostty, Kitty, and WezTerm.
  • Shell: Zsh with starship prompt, atuin history, zoxide navigation, and eza ls-replacement.

Git Setup

  • Identity Management: Context-aware configs via [includeIf].
  • Signing: SSH Signing configured via 1Password.
  • Aliases: Pre-configured shortcuts (git s, git co, git lg).

🔐 Secrets Workflow

To update a secret:

  1. Edit the plaintext file locally (e.g. files/git/.config/git/identity-work).
  2. Run the update script to re-encrypt into secrets/:
    ./update_secrets.sh
    
  3. Commit the changes in secrets/.

📂 Repository Structure

├── bootstrap.sh        # Entry point
├── playbook.yml        # Main Ansible Playbook
├── inventory           # Localhost definition
├── roles/
│   ├── core/           # Brew, Mise, MAS
│   ├── dotfiles/       # Stow, Secrets, Backups
│   └── term/           # (Deprecated/Merged)
├── files/              # Plaintext Configs (Stow Source)
└── secrets/            # Encrypted Secrets (SOPS Source)