Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Three documentation trees, split by genre and audience:
- Prefer `(( ))` over numeric operators inside `[[ ]]` (e.g., `(( count < 50 ))`, not `[[ $count -lt 50 ]]`)
- Prefer a full `if`/`else` conditional for simple two-path control flow; don't rely on `exec` or `exit` in one branch to make following statements unreachable
- For strings/paths with spaces, quote them instead of escaping spaces with `\ ` (e.g., `"$APP_DIR/Disk Usage.desktop"`, not `$APP_DIR/Disk\ Usage.desktop`)
- Shebangs must use `#!/bin/bash` consistently (never `#!/usr/bin/env bash`)
- Shebangs must use `#!/bin/bash` consistently (never `#!/usr/bin/env bash`). A security-sensitive entrypoint may use the exact `#!/bin/bash -p` form only when it must suppress `BASH_ENV` and exported-function startup injection before its first command; that exception must be explained at the boundary and covered by a regression that rejects an ordinary Bash launch with a decoy `-p` argument.
- Scripts under `install/` and `migrations/` may be sourced and intentionally omit shebangs

# Command Naming
Expand Down
4 changes: 3 additions & 1 deletion bin/omarchy
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ register_route() {
register_command() {
local file="$1"
local file_binary="${file##*/}"
local metadata_file="$OMARCHY_BIN_DIR/../share/omarchy/command-metadata/$file_binary"
local group=""
local name=""
local summary=""
Expand All @@ -186,6 +187,7 @@ register_command() {
local has_summary="false"
local metadata_errors=""

[[ -f $metadata_file && -r $metadata_file ]] || metadata_file="$file"
while IFS= read -r line && (( line_count < METADATA_SCAN_LIMIT )); do
line_count=$((line_count + 1))

Expand Down Expand Up @@ -248,7 +250,7 @@ register_command() {
fallback_summary=""
fi
fi
done <"$file"
done <"$metadata_file"

local stem="${file_binary#omarchy-}"
local fallback_group="$stem"
Expand Down
139 changes: 81 additions & 58 deletions bin/omarchy-debug
Original file line number Diff line number Diff line change
@@ -1,40 +1,59 @@
#!/bin/bash
#!/bin/bash -p

# omarchy:summary=Print debugging information
# omarchy:args=[--no-sudo] [--print]
# omarchy:examples=omarchy debug --print --no-sudo
# omarchy:requires-sudo=true

NO_SUDO=false
PRINT_ONLY=false
# The settings package installs a root-owned, non-setuid static launcher as
# /usr/bin/omarchy-debug and this Bash payload at a fixed /usr/lib path. The
# launcher is the first process: it cold-revokes sudo, performs only the fixed
# `sudo -N dmesg` operation, revokes again, then starts this collector with a
# sanitized shell. Running this source payload directly is unsupported and
# cannot reach a sudo operation because the collector itself contains none.
if [[ ${1:-} == "--omarchy-debug-native-boundary-v1" &&
${OMARCHY_DEBUG_NATIVE_BOUNDARY:-} == 1 && -r /proc/self/fd/3 ]]; then
shift
DMESG_OUTPUT=$(/usr/bin/cat <&3) || {
echo "Could not read the private kernel log staging descriptor." >&2
exit 1
}
exec 3<&-
exec 4<&-

while (( $# > 0 )); do
case "$1" in
--no-sudo)
NO_SUDO=true
shift
;;
--print)
PRINT_ONLY=true
shift
;;
*)
echo "Unknown option: $1"
echo "Usage: omarchy-debug [--no-sudo] [--print]"
exit 1
;;
esac
done
set -uo pipefail

LOG_FILE="/tmp/omarchy-debug.log"
NO_SUDO=false
PRINT_ONLY=false

if [[ $NO_SUDO = "true" ]]; then
DMESG_OUTPUT="(skipped - --no-sudo flag used)"
else
DMESG_OUTPUT="$(sudo dmesg)"
fi
while (( $# > 0 )); do
case "$1" in
--no-sudo)
NO_SUDO=true
shift
;;
--print)
PRINT_ONLY=true
shift
;;
*)
echo "Unknown option: $1"
echo "Usage: omarchy-debug [--no-sudo] [--print]"
exit 1
;;
esac
done

cat > "$LOG_FILE" <<EOF
# OM-SEC-06 owns this private staging change in #8370. Keep its -T guard so a
# directory at the fixed log name is rejected rather than accepted by install.
log_dir="${XDG_RUNTIME_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/omarchy}"
LOG_FILE="$log_dir/omarchy-debug.log"
if ! /usr/bin/mkdir -p "$log_dir" || ! /usr/bin/install -T -m 600 /dev/null "$LOG_FILE"; then
echo "Error: Failed to create $LOG_FILE" >&2
exit 1
fi

cat >"$LOG_FILE" <<EOF
Date: $(date)
Hostname: $(hostname)
Omarchy Package: $(pacman -Q omarchy-dev 2>/dev/null || pacman -Q omarchy 2>/dev/null || echo "unknown")
Expand All @@ -60,37 +79,41 @@ INSTALLED PACKAGES
$({ expac -S '%n %v (%r)' $(pacman -Qqe) 2>/dev/null; comm -13 <(pacman -Sql | sort) <(pacman -Qqe | sort) | xargs -r expac -Q '%n %v (AUR)'; } | sort)
EOF

if [[ $PRINT_ONLY = "true" ]]; then
cat "$LOG_FILE"
exit 0
fi
if [[ $PRINT_ONLY == true ]]; then
cat "$LOG_FILE"
exit 0
fi

OPTIONS=("View log" "Save in current directory")
if ping -c 1 8.8.8.8 >/dev/null 2>&1; then
OPTIONS=("Upload log" "${OPTIONS[@]}")
fi
OPTIONS=("View log" "Save in current directory")
if ping -c 1 8.8.8.8 >/dev/null 2>&1; then
OPTIONS=("Upload log" "${OPTIONS[@]}")
fi

ACTION=$(gum choose "${OPTIONS[@]}")
ACTION=$(gum choose "${OPTIONS[@]}")

case "$ACTION" in
"Upload log")
echo "Uploading debug log to logs.omarchy.org..."
URL=$(curl -sf -F "file=@$LOG_FILE" -Fexpires=24 https://logs.omarchy.org/)
if (( $? == 0 )) && [[ -n $URL ]]; then
echo "✓ Log uploaded successfully!"
echo "Share this URL:"
echo ""
echo " $URL"
else
echo "Error: Failed to upload log file"
exit 1
fi
;;
"View log")
less "$LOG_FILE"
;;
"Save in current directory")
cp "$LOG_FILE" "./omarchy-debug.log"
echo "✓ Log saved to $(pwd)/omarchy-debug.log"
;;
esac
case "$ACTION" in
"Upload log")
echo "Uploading debug log to logs.omarchy.org..."
if URL=$(curl -sf -F "file=@$LOG_FILE" -Fexpires=24 https://logs.omarchy.org/) && [[ -n $URL ]]; then
echo "✓ Log uploaded successfully!"
echo "Share this URL:"
echo ""
echo " $URL"
else
echo "Error: Failed to upload log file"
exit 1
fi
;;
"View log")
less "$LOG_FILE"
;;
"Save in current directory")
cp "$LOG_FILE" "./omarchy-debug.log"
echo "✓ Log saved to $(pwd)/omarchy-debug.log"
;;
esac
else
echo "Run the packaged omarchy-debug command directly; do not invoke its Bash payload." >&2
return 126 2>/dev/null
exit 126
fi
93 changes: 93 additions & 0 deletions bin/omarchy-security-functions
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/bin/bash

# omarchy:hidden=true
# omarchy:summary=Provide internal fail-closed helpers for security-sensitive commands

# Shared fail-closed primitives for security-sensitive Omarchy commands. This
# file is sourced from the same package-owned bin directory as its consumers.

if [[ ${BASH_SOURCE[0]} == "$0" ]]; then
echo "omarchy-security-functions is an internal function library." >&2
exit 64
fi

omarchy_security_require_privileged_bash_startup() {
local expected_script=${1:-} pid=${2:-$$}

[[ $- == *p* && $pid =~ ^[1-9][0-9]*$ ]] || return 1
/usr/bin/env -i /usr/bin/bash -p -c '
mapfile -d "" -t argv <"/proc/$1/cmdline" || exit 1
executable=$(/usr/bin/readlink -e -- "/proc/$1/exe") || exit 1
[[ $executable == /usr/bin/bash ]]
[[ ${argv[0]:-} == /bin/bash || ${argv[0]:-} == /usr/bin/bash ]]
[[ ${argv[1]:-} == -p ]]
if [[ -n $2 ]]; then
script=$(/usr/bin/readlink -e -- "${argv[2]:-}") || exit 1
expected=$(/usr/bin/readlink -e -- "$2") || exit 1
[[ $script == "$expected" ]]
fi
' omarchy-bash-startup "$pid" "$expected_script"
}

omarchy_security_sudo_supports_no_update() {
LC_ALL=C /usr/bin/sudo -h 2>&1 |
/usr/bin/grep -Eq '^usage: sudo .*\[[^]]*N[^]]*\]'
}

omarchy_security_revoke_sudo_timestamp() {
/usr/bin/sudo -k >/dev/null 2>&1
}

omarchy_security_exit_with_revoked_sudo() {
local status=$1
local message=${2:-Could not invalidate cached sudo authorization.}

trap - EXIT
trap '' HUP INT TERM
if ! omarchy_security_revoke_sudo_timestamp; then
echo "$message" >&2
(( status != 0 )) || status=1
fi
exit "$status"
}

omarchy_security_install_signal_exit_traps() {
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
}

omarchy_security_run_sudo_cleanup_trap() {
local status=$?

omarchy_security_exit_with_revoked_sudo "$status" \
"${OMARCHY_SECURITY_SUDO_CLEANUP_MESSAGE:-Could not invalidate cached sudo authorization.}"
}

omarchy_security_install_sudo_cleanup_traps() {
OMARCHY_SECURITY_SUDO_CLEANUP_MESSAGE=${1:-Could not invalidate cached sudo authorization.}
trap omarchy_security_run_sudo_cleanup_trap EXIT
omarchy_security_install_signal_exit_traps
}

omarchy_security_assert_root_directory() {
local path=$1 expected_mode=$2 canonical owner actual_mode

[[ $path == /* && -d $path && ! -L $path ]] || return 1
canonical=$(/usr/bin/realpath -e -- "$path") || return 1
[[ $canonical == "$path" ]] || return 1
read -r owner actual_mode < <(/usr/bin/stat -Lc '%u %a' -- "$path") || return 1
[[ $owner == "0" && $actual_mode == "$expected_mode" ]]
}

omarchy_security_prepare_private_root_directory() {
local path=$1 parent=$2

omarchy_security_assert_root_directory "$parent" 755 || return 1
if [[ -e $path || -L $path ]]; then
omarchy_security_assert_root_directory "$path" 700
else
/usr/bin/install -d -o root -g root -m 0700 -- "$path" || return 1
omarchy_security_assert_root_directory "$path" 700
fi
}
4 changes: 4 additions & 0 deletions default/omarchy/command-metadata/omarchy-debug
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# omarchy:summary=Print debugging information
# omarchy:args=[--no-sudo] [--print]
# omarchy:examples=omarchy debug --print --no-sudo
# omarchy:requires-sudo=true
Loading