Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
68d8141
OM-SEC-12: Bind update inhibitor cleanup to process identity
AFOliveira Aug 31, 2026
061dce7
OM-SEC-08: Publish SSH only after proving key-only access
AFOliveira Aug 31, 2026
1136a71
OM-SEC-14: Run update hooks without reusable sudo authority
AFOliveira Aug 31, 2026
87625c2
OM-SEC-01: Make passwordless sudo expiry fail closed
AFOliveira Aug 31, 2026
2f816a8
Document privileged Bash startup exception
AFOliveira Sep 1, 2026
94a84d7
Narrow OM-SEC-19 to migration sudo lifetime
AFOliveira Aug 31, 2026
7f9a401
Merge commit 'b71dcad96e9d0b2962b7d225828a5cb6000ad720' into codex/re…
AFOliveira Sep 6, 2026
35b318e
Complete command-scoped authentication across update phases
AFOliveira Sep 6, 2026
c52381f
Keep update regressions isolated from host authentication
AFOliveira Sep 6, 2026
d91d43b
Integrate shared sudo boundaries and revoke failed migration work
AFOliveira Sep 6, 2026
458813c
Merge update regression fixture fixes
AFOliveira Sep 6, 2026
e09df2d
Stop package helpers when environment sanitization fails
AFOliveira Sep 6, 2026
f2c3925
Revoke before session cleanup and protect standalone inhibition
AFOliveira Sep 6, 2026
f705edc
Integrate final inhibitor and update cleanup boundaries
AFOliveira Sep 6, 2026
1f8f5ba
Integrate current quattro before security review
AFOliveira Sep 6, 2026
0b346fa
Integrate current quattro into migration review
AFOliveira Sep 6, 2026
2a3c299
Integrate authentication prompt documentation
AFOliveira Sep 6, 2026
a9e9954
Clarify unattended updates still require sudo authorization
AFOliveira Sep 6, 2026
6434683
Isolate fingerprint regression from fixed privileged package paths
AFOliveira Sep 6, 2026
978dffa
Use required gum directly in AI removal prompts
AFOliveira Sep 6, 2026
fe8cc53
Integrate command style correction
AFOliveira Sep 6, 2026
d41ca88
Wait for the actual Stay Awake launcher
AFOliveira Sep 6, 2026
0db6a9d
Merge branch 'codex/review-9469-20260906' into codex/review-9474-2026…
AFOliveira Sep 6, 2026
177d572
Wait for notifications when restarting the shell
AFOliveira Sep 6, 2026
a075272
Merge branch 'codex/review-9469-20260906' into codex/review-9474-2026…
AFOliveira Sep 6, 2026
35551b0
Disable the Yay sudo loop with its supported option
AFOliveira Sep 6, 2026
2680c31
Merge branch 'codex/review-9469-20260906' into codex/review-9474-2026…
AFOliveira Sep 6, 2026
aa422fc
Merge current Quattro while preserving command checks
AFOliveira Sep 7, 2026
0bb5c2f
Merge current update security foundation
AFOliveira Sep 7, 2026
5b692c5
Preserve user PATH across updater relaunches
AFOliveira Sep 7, 2026
cc73ff1
Merge branch 'codex/review-9469-20260906' into codex/review-9474-2026…
AFOliveira Sep 7, 2026
f37c73f
Bind protected update commands to their source root
AFOliveira Sep 7, 2026
5bc41b2
Resolve security libraries beside canonical entrypoints
AFOliveira Sep 7, 2026
aa88e7d
Merge branch 'codex/review-9469-20260906' into codex/review-9474-2026…
AFOliveira Sep 7, 2026
c869740
Keep channel transitions inside command-scoped sudo
AFOliveira Sep 7, 2026
0f31620
Validate migration and SSH setup source boundaries
AFOliveira Sep 7, 2026
0add43f
Check dev update support before changing the system
AFOliveira Sep 7, 2026
23252a0
Merge branch 'codex/review-9469-20260906' into codex/review-9474-2026…
AFOliveira Sep 7, 2026
bc235d2
Merge remote-tracking branch 'refs/remotes/portfolio/quattro' into co…
AFOliveira Sep 7, 2026
4ae25cd
Keep temporary sudo grants bounded through lifecycle failures
AFOliveira Sep 7, 2026
a6385e6
Bound sudo policy natively and guard expiry package transactions
AFOliveira Sep 7, 2026
75e58f0
Integrate the shared sudo lifecycle foundation
AFOliveira Sep 7, 2026
104c776
Merge update inhibitor identity hardening
AFOliveira Sep 7, 2026
76f0abe
Roll back interrupted inhibitor launches
AFOliveira Sep 7, 2026
0240113
Open launch authorization without recreating cancelled state
AFOliveira Sep 7, 2026
bf871a2
Merge commit 'a6385e60b836f41895fd016bf170c9b62128c59a' into codex/po…
AFOliveira Sep 7, 2026
fd1ad6d
Merge commit '0240113da2f92d176ce3131d3a0f7755488891eb' into codex/po…
AFOliveira Sep 7, 2026
ffdf342
Make SSH migration machine-scoped
AFOliveira Sep 7, 2026
372b179
Batch fixed migration machine repairs
AFOliveira Sep 7, 2026
517c674
Merge commit 'ffdf34209a719eaec7f2e7e997b4796018c52e55' into codex/po…
AFOliveira Sep 7, 2026
1fc0511
Prove SSH service and account admission state
AFOliveira Sep 7, 2026
3ecdb8b
Handle migration discovery failures safely
AFOliveira Sep 7, 2026
684c08d
Merge corrected SSH migration transaction
AFOliveira Sep 7, 2026
fef8d82
Harden migration repair failure handling
AFOliveira Sep 7, 2026
17a3076
Keep failed T2 repairs retryable
AFOliveira Sep 7, 2026
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
38 changes: 33 additions & 5 deletions bin/omarchy-channel-set
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
#!/bin/bash
#!/bin/bash -p

# omarchy:summary=Set the Omarchy package channel.
# omarchy:args=<stable|rc|edge|dev>
# omarchy:requires-sudo=true

if [[ $- != *p* ]]; then
echo "Refusing an unsafe Bash startup for channel switching." >&2
exit 126
fi
security_entrypoint=$(/usr/bin/readlink -e -- "${BASH_SOURCE[0]}") || exit 126
source "${security_entrypoint%/*}/omarchy-security-functions" || exit 126
omarchy_security_require_privileged_bash_startup || exit 126
set -euo pipefail
omarchy_security_sanitize_bash_environment "$0" "$@"
omarchy_security_require_source_root "$0"
user_path=$PATH
omarchy_security_revoke_sudo_timestamp || exit 1
omarchy_security_install_sudo_cleanup_traps
omarchy_security_enable_no_update_sudo

usage() { echo "Usage: omarchy-channel-set [stable|rc|edge|dev]"; }
fail() { echo "Error: $*" >&2; exit 1; }
Expand Down Expand Up @@ -33,9 +46,18 @@ validate_dev_checkout() {
}

link_dev_checkout() {
local checkout="$1"
local checkout="$1" required
[[ -d $checkout/.git ]] || git clone https://github.com/basecamp/omarchy.git "$checkout"

# Check the destination before changing /etc/omarchy.conf or sudo's path.
# An existing checkout is not pulled automatically and may predate this policy.
for required in bin/omarchy-security-functions bin/omarchy-update bin/omarchy-refresh-pacman default/omarchy/sudo-no-update/sudo; do
if [[ ! -f $checkout/$required || ! -r $checkout/$required ||
( $required != "bin/omarchy-security-functions" && ! -x $checkout/$required ) ]]; then
fail "Update the checkout before switching to dev; missing required update support in $required."
fi
done

omarchy-dev-link "$checkout" --no-reboot
}

Expand Down Expand Up @@ -79,21 +101,27 @@ fi
if [[ -n $dev_checkout ]]; then
link_dev_checkout "$dev_checkout"
export OMARCHY_PATH="$dev_checkout"
export PATH="$OMARCHY_PATH/bin:$PATH"
omarchy_security_enable_no_update_sudo
omarchy-state set reboot-required
fi

omarchy-refresh-pacman "$pacman_channel"
omarchy-refresh-pacman "$pacman_channel" defer-hook
# --ask 4 accepts omarchy <-> omarchy-dev replacement prompts without file overwrites.
sudo env OMARCHY_UPDATE_PACMAN=1 pacman -S --needed --noconfirm --ask 4 "${packages[@]}"

if [[ -z $dev_checkout ]]; then
omarchy-dev-unlink --no-reboot
export OMARCHY_PATH=/usr/share/omarchy
omarchy_security_enable_no_update_sudo

if (( leaving_dev )); then
omarchy-state set reboot-required
fi
fi

omarchy-update -y
OMARCHY_UPDATE_USER_PATH="$user_path" "$OMARCHY_PATH/bin/omarchy-update" -y

# No channel-owned privileged work follows the historical refresh hook.
omarchy_security_revoke_sudo_timestamp
PATH="$OMARCHY_PATH/default/omarchy/sudo-no-update:$user_path" \
"$OMARCHY_PATH/bin/omarchy-refresh-pacman" "$pacman_channel" run-deferred
38 changes: 35 additions & 3 deletions bin/omarchy-migrate
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
#!/bin/bash
#!/bin/bash -p

# omarchy:summary=Run pending Omarchy migrations.
# omarchy:args=[--pending]

if [[ $- != *p* ]]; then
echo "Refusing an unsafe Bash startup for Omarchy migrations." >&2
exit 126
fi

security_entrypoint=$(/usr/bin/readlink -e -- "${BASH_SOURCE[0]}") || exit 126
source "${security_entrypoint%/*}/omarchy-security-functions" || exit 126

if ! omarchy_security_require_privileged_bash_startup; then
echo "Refusing an unsafe Bash startup for Omarchy migrations." >&2
exit 126
fi

set -euo pipefail

omarchy_security_sanitize_bash_environment "$0" "$@"
omarchy_security_require_source_root "$0"

PATH="$OMARCHY_PATH/bin:/usr/bin:/usr/sbin:/bin:/sbin"
export PATH

mode="run"

usage() {
Expand All @@ -28,7 +47,6 @@ while (($#)); do
esac
done

OMARCHY_PATH="${OMARCHY_PATH:-/usr/share/omarchy}"
STATE_DIR="${OMARCHY_MIGRATION_STATE:-$HOME/.local/state/omarchy/migrations}"
MIGRATIONS_DIR="$OMARCHY_PATH/migrations"

Expand Down Expand Up @@ -80,22 +98,36 @@ wait_for_pacman_transaction() {
exit 0
}

# Revoke before waiting or touching state. Every exit, including failed and
# interrupted migrations, must revoke again before returning to user code.
omarchy_security_revoke_sudo_timestamp || exit 1
omarchy_security_install_sudo_cleanup_traps
omarchy_security_enable_no_update_sudo

wait_for_pacman_transaction

mkdir -p "$STATE_DIR"
[[ -d $MIGRATIONS_DIR ]] || exit 0

# Migrations are strictly ordered and may mix user-controlled code (mise,
# themes, AUR builds) with later privileged repairs. Start cold and force every
# migration sudo through -N so authentication authorizes only that command and
# never creates a timestamp a detached earlier child can reuse.

while IFS=$'\t' read -r name file marker <&3; do
[[ -n $name ]] || continue

if [[ ! -f $marker ]]; then
echo -e "\e[32m\nRunning migration (${name%.sh})\e[0m"
OMARCHY_PATH="$OMARCHY_PATH" bash -euo pipefail "$file" 3<&-
OMARCHY_PATH="$OMARCHY_PATH" /usr/bin/bash -p -euo pipefail "$file" 3<&-
omarchy_security_revoke_sudo_timestamp || exit 1
mkdir -p "$(dirname "$marker")"
touch "$marker"
fi
done 3< <(migration_entries)

omarchy_security_revoke_sudo_timestamp || exit 1

# Clear a login-time notification the user left sitting there and then resolved
# by running migrations some other way. The substring matches both the current
# and legacy notification titles.
Expand Down
Loading