Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions .github/workflows/mise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
container: archlinux:latest
steps:
- name: Install prerequisites
run: pacman -Syu --noconfirm mise git zsh lua bun jq python python-yaml
run: pacman -Syu --noconfirm mise git zsh lua bun jq python python-yaml diffutils

- name: Checkout code
uses: actions/checkout@v7
Expand Down Expand Up @@ -123,8 +123,23 @@ jobs:
sudo apt-get update
sudo apt-get install --yes sudo bubblewrap

# Use the packaged bubblewrap/AppArmor policy; never weaken host namespace
# restrictions or run this suite as root. Missing support must fail loudly.
# Ubuntu 24.04 blocks unprivileged user namespaces via AppArmor
# (kernel.apparmor_restrict_unprivileged_userns=1). Grant them to bwrap only,
# through a profile for /usr/bin/bwrap; the sysctl stays on for everything else.
# The suite still runs as the non-root runner. Missing support must fail loudly.
- name: Allow user namespaces for bubblewrap only
run: |
sudo tee /etc/apparmor.d/bwrap >/dev/null <<'EOF'
abi <abi/4.0>,
include <tunables/global>
profile bwrap /usr/bin/bwrap flags=(unconfined) {
userns,
include if exists <local/bwrap>
}
EOF
sudo apparmor_parser -r /etc/apparmor.d/bwrap
bwrap --unshare-user --uid 0 --ro-bind / / true

- name: Test isolated sudoers policy as the runner account
run: bash modules/system/tests/test_sudoers.sh

Expand Down Expand Up @@ -152,7 +167,8 @@ jobs:
- name: Dry-run macos
run: |
cd ~
MISE_AUTO_ENV=true mise bootstrap --dry-run --yes
# The runner image ships ~/.bashrc; bin/dotfiles sets such conflicts aside, raw mise refuses.
MISE_AUTO_ENV=true mise bootstrap --dry-run --yes --force-dotfiles

- name: Tests (all loaded macos modules)
run: |
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ cd ~ &&

It requires a non-root Linux account, installed `visudo`, bubblewrap, permitted unprivileged user/PID namespaces, and an existing `/etc/sudoers.d`. It maps a disposable policy directory and does not invoke real sudo or write a live grant. Run it on a suitable Linux executor; namespace restrictions are a reported failure, not proof that the policy passed.

The workflow defines a dedicated `system-sudoers` Ubuntu job that installs packaged sudo/bubblewrap and runs the same test script directly as the non-root runner account, outside the wildcard suites. It does not weaken host namespace restrictions. This route covers isolated sudoers safety, not full Omarchy/CachyOS provisioning or desktop runtime; consult the workflow results for execution evidence.
The workflow defines a dedicated `system-sudoers` Ubuntu job that installs packaged sudo/bubblewrap, loads an AppArmor profile that grants user namespaces to `/usr/bin/bwrap` only (Ubuntu 24.04 otherwise blocks them for unprivileged programs; the host-wide restriction stays on), and runs the same test script directly as the non-root runner account, outside the wildcard suites. This route covers isolated sudoers safety, not full Omarchy/CachyOS provisioning or desktop runtime; consult the workflow results for execution evidence.

</details>

Expand Down
9 changes: 6 additions & 3 deletions bin/dotfiles
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,12 @@ detect_profile() {
}

validate_purpose_target() {
[ ! -L "$PURPOSE_DIR" ] && { [ ! -e "$PURPOSE_DIR" ] || [ -d "$PURPOSE_DIR" ]; } ||
if ! { [ ! -L "$PURPOSE_DIR" ] && { [ ! -e "$PURPOSE_DIR" ] || [ -d "$PURPOSE_DIR" ]; }; }; then
die "unsafe purpose directory $PURPOSE_DIR; use a real directory"
[ ! -L "$PURPOSE_FILE" ] && { [ ! -e "$PURPOSE_FILE" ] || [ -f "$PURPOSE_FILE" ]; } ||
fi
if ! { [ ! -L "$PURPOSE_FILE" ] && { [ ! -e "$PURPOSE_FILE" ] || [ -f "$PURPOSE_FILE" ]; }; }; then
die "unsafe purpose target $PURPOSE_FILE; use a regular, non-symlink file"
fi
}

read_purpose() {
Expand Down Expand Up @@ -318,8 +320,9 @@ validate_miserc_target() {
local rc="$MISE_DIR/miserc.local.toml"
{ [ ! -e "$MISE_DIR" ] || [ -d "$MISE_DIR" ]; } ||
die "unsafe mise configuration directory $MISE_DIR"
[ ! -L "$rc" ] && { [ ! -e "$rc" ] || [ -f "$rc" ]; } ||
if ! { [ ! -L "$rc" ] && { [ ! -e "$rc" ] || [ -f "$rc" ]; }; }; then
die "unsafe mise discovery target $rc; use a regular, non-symlink file"
fi
}

write_miserc() {
Expand Down
3 changes: 2 additions & 1 deletion modules/base/tests/test_bin_dotfiles.sh
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ expect_no_provisioning
new_case purpose-set-without-mise-or-checkout
mkdir -p "$C/path" "$MISE_DIR/conf.d"
for cmd in bash cmp cat mkdir mktemp mv rm; do
ln -s "$(command -v "$cmd")" "$C/path/$cmd"
tool=$(command -v "$cmd") || fail "test needs $cmd on PATH"
[ -z "$tool" ] || ln -s "$tool" "$C/path/$cmd"
done
echo retained >"$MISE_DIR/conf.d/user.toml"
echo '[settings]' >"$MISE_DIR/config.toml"
Expand Down
17 changes: 17 additions & 0 deletions modules/clangd/bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -uo pipefail

# Homebrew's llvm is keg-only; link its clangd into ~/.local/bin. A [dotfiles] entry
# cannot do this: its source only exists once llvm is installed, so every dry run fails.
dst="$HOME/.local/bin/clangd"
prefix="$(brew --prefix llvm 2>/dev/null)" || prefix=""
src="${prefix:+$prefix/bin/clangd}"

if [ -z "$src" ] || [ ! -x "$src" ]; then
echo "clangd: brew llvm not installed, skipped"
elif [ -e "$dst" ] && [ ! -L "$dst" ]; then
echo "clangd: $dst is not a link, skipped"
elif [ "$(readlink "$dst" 2>/dev/null)" != "$src" ]; then
mkdir -p "${dst%/*}" && ln -sfn "$src" "$dst" || echo "clangd: linking $dst failed, skipped"
fi
exit 0
5 changes: 3 additions & 2 deletions modules/clangd/mise.macos.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[bootstrap.packages]
"brew:llvm" = "latest"

[dotfiles]
"~/.local/bin/clangd" = { source = "/opt/homebrew/opt/llvm/bin/clangd" }
[tasks."bootstrap:clangd"]
description = "Link Homebrew llvm's clangd into ~/.local/bin"
run = "./bootstrap.sh"
3 changes: 2 additions & 1 deletion modules/git/tests/test_global_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ def setUp(self):
self.fail("real Git is required by the Git module test gate")
self.temp = tempfile.TemporaryDirectory(prefix="dotfiles-git-")
self.addCleanup(self.temp.cleanup)
self.home = Path(self.temp.name) / "home"
# macOS TMPDIR is a /var -> /private/var alias; a real HOME is canonical.
self.home = Path(self.temp.name).resolve(strict=True) / "home"
self.home.mkdir(mode=0o700)
self.config = self.home / ".gitconfig"
self.git_dir = self.home / ".config/git"
Expand Down
2 changes: 1 addition & 1 deletion modules/hammerspoon/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ tmp=$(mktemp -d) || { echo "hammerspoon: could not create temp dir, skipped"; ex
transaction=""
committed=0
# Invoked indirectly by the EXIT trap below.
# shellcheck disable=SC2317
# shellcheck disable=SC2317,SC2329
cleanup() {
trap '' HUP INT TERM
local name failed=0
Expand Down
2 changes: 1 addition & 1 deletion modules/k9s/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ rendered=$HOME/.local/state/omarchy/current/theme/k9s.yaml
if [ -f "$HOME/.local/state/omarchy/current/theme.name" ] &&
{ [ ! -f "$rendered" ] || [ "$here/k9s.yaml.tpl" -nt "$rendered" ]; }; then
if command -v omarchy-theme-refresh >/dev/null 2>&1; then
# shellcheck source=../omarchy/hypr-instance.sh
# shellcheck source=../omarchy/hypr-instance.sh source-path=SCRIPTDIR
. "$here/../omarchy/hypr-instance.sh"
hypr_live_sig
if [ -n "$HYPR_SIG" ]; then
Expand Down
Loading