Ask for the sudo password once per omarchy update (#13323)
* Ask for the sudo password once per omarchy update Every sudo call in omarchy update prompted, because the no-update wrapper covered the whole run on top of per-phase revokes, and stay-awake revoked the timestamp on its own entry and exit. A single update could ask four times before the snapshot finished (#13319). Authorize once, right after confirmation, starting from a revoked timestamp so the prompt always belongs to this update. A background keepalive refreshes it until the update is done. Prune, snapshot, stay-awake, keyring, system packages, migrations, orphan removal, service restarts, the post-update hook, and mise all share that authorization. AUR builds run third-party PKGBUILD code, so they move to the end and run cold: the keepalive stops, the timestamp is revoked, and yay and any bare sudo use the no-update wrapper. The timestamp is revoked again after AUR and on every exit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep the single authorization for passwordless sudo and ttyless inhibition Authorize by running a command instead of sudo -v. Under the default verifypw=all, -v prompts even when passwordless sudo is enabled, which would have added a prompt those users never had. Inside an update without a terminal, stay-awake now reuses the update's authorization with a non-interactive sudo instead of asking again through polkit. It falls back to polkit only if that authorization is gone. The test sudo refuses a cold non-interactive call, as the real one does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7b336b1b0d
commit
e1614f2bdb
9 files changed
+163
-51
No files matched your search
+10
-9
@@ -57,7 +57,7 @@ privileged work should invoke the appropriate helper or privilege prompt.
|
||||
Migrations must be idempotent; if one user already applied a machine-wide repair,
|
||||
the migration should no-op for other users.
|
||||
|
||||
When invoked by the update, migrations inherit its cold credential state and no-update sudo wrapper. The standalone migration runner has its own security changes in the migration-boundary PR; this update change does not establish that standalone boundary. Historical migrations remain strictly ordered.
|
||||
When invoked by the update, migrations share its single sudo authorization. The standalone migration runner has its own security changes in the migration-boundary PR; this update change does not establish that standalone boundary. Historical migrations remain strictly ordered.
|
||||
|
||||
For watchers and diagnostics, `omarchy-migrate --pending` prints pending
|
||||
migration names and exits `0` when any are pending. When no migrations are
|
||||
@@ -126,6 +126,7 @@ omarchy-update
|
||||
├─ omarchy-update-requires-free-space
|
||||
│ └─ abort below the configured free-space threshold on /
|
||||
├─ confirm unless -y
|
||||
├─ authorize sudo once, then keep the timestamp fresh in the background
|
||||
├─ omarchy-update-pkg-prune
|
||||
│ └─ trim the pacman cache to two versions per package, deliberately
|
||||
│ before the snapshot since the cache lives on the snapshotted subvolume
|
||||
@@ -134,14 +135,14 @@ omarchy-update
|
||||
│ install/config/snapper.sh, and the update continues without one)
|
||||
├─ omarchy-update-stay-awake start
|
||||
├─ run system-package updates
|
||||
├─ invalidate sudo, then run migrations and all later privileged work with
|
||||
│ no-update authentication
|
||||
├─ run migrations
|
||||
├─ run orphan review and log analysis
|
||||
├─ omarchy-update-status
|
||||
│ └─ refresh or clear the shell update indicator
|
||||
├─ restart marked services and the shell
|
||||
├─ invalidate sudo credentials, then update AUR packages
|
||||
├─ invalidate again, run the post-update hook, invalidate again, then update mise tools
|
||||
├─ run the post-update hook, then update mise tools
|
||||
├─ stop the keepalive and invalidate sudo, then update AUR packages with
|
||||
│ no-update authentication, and invalidate again
|
||||
├─ omarchy-update-stay-awake stop
|
||||
│ └─ release the sleep inhibitor and restore shell idle state, if changed
|
||||
└─ offer the unprivileged reboot prompt
|
||||
@@ -149,15 +150,15 @@ omarchy-update
|
||||
|
||||
Important behavior:
|
||||
|
||||
- Protected update entrypoints require the session's canonical `OMARCHY_PATH` to match their own checkout or the packaged `/usr/bin` entrypoint before selecting commands or the sudo wrapper. This preserves intentionally trusted development checkouts while rejecting a command paired with a different source root. System phases use a fixed command search path; user PATH is restored behind the sudo wrapper for hooks and mise.
|
||||
- Protected update entrypoints require the session's canonical `OMARCHY_PATH` to match their own checkout or the packaged `/usr/bin` entrypoint before selecting commands or the sudo wrapper. This preserves intentionally trusted development checkouts while rejecting a command paired with a different source root. System phases use a fixed command search path; user PATH is restored for hooks and mise.
|
||||
- Mixed-trust update entrypoints start Bash in privileged mode, discard `BASH_ENV`, `ENV`, and exported-function records before launching helpers, and reject an ordinary `bash path/to/command` invocation. Run them as executables (normally through the `omarchy` CLI); `/usr/bin/bash -p path/to/command` is the explicit interpreter form. This keeps shell startup injection from replacing the no-update sudo boundary.
|
||||
- In dev-link mode, `omarchy update` fast-forwards the active checkout from its configured upstream before changing system packages or running migrations.
|
||||
- Migrations remain in chronological order even though historical entries mix user-controlled code with later privileged repairs. Before entering that mixed-trust tail, Omarchy invalidates its timestamp and forces every later sudo call—including AUR's configurable sudo command—to use `--no-update`; prompts authorize one command without publishing a reusable timestamp. Yay's credential loop is disabled for the update.
|
||||
- User-controlled post-update hooks and mise tools run only after every sudo-capable update stage. Omarchy invalidates its sudo timestamp before each boundary and on every exit; detached children therefore have no later reusable update authorization to wait for.
|
||||
- The update asks for the sudo password once, right after confirmation. It first invalidates any existing timestamp so that prompt always belongs to this update, then a background keepalive refreshes the timestamp every minute so long downloads, migrations, hooks, and mise never outlast it. Everything except AUR shares that one authorization: package prune, snapshot, stay-awake, keyring, system packages, migrations, orphan removal, service restarts, the post-update hook, and mise. Stay-awake sees `OMARCHY_UPDATE_SUDO_SESSION=1`, uses that authorization non-interactively whatever its stdin is, and leaves it to the update instead of revoking it. The authorization runs a command rather than `sudo -v`, so passwordless sudo still needs no prompt. Standalone commands that keep their own cold boundary, such as `omarchy-refresh-pacman`, still revoke if a post-update hook calls them.
|
||||
- AUR builds run third-party PKGBUILD code, so they run last and never see the update's authorization. The update stops the keepalive, invalidates the timestamp, and runs yay with the no-update wrapper as its sudo command and its credential loop disabled; an AUR install prompts per command without publishing a reusable timestamp. The timestamp is invalidated again afterwards and on every exit.
|
||||
- This lifecycle controls authorization created by the protected workflow. `sudo -N` prevents cache updates but can use an existing valid credential, and `sudo -k` revokes the current session's timestamp. It does not isolate the account from unrelated concurrent authentication in another workflow.
|
||||
- Sleep inhibition authenticates before detaching, drops the held command back to the caller, and closes both update lock descriptors before the persistent process starts. Cleanup accepts only caller-owned, mode-0600, single-link state and revalidates the recorded PID, process start time, owner, and random token immediately before every signal.
|
||||
- Channel switching establishes the same boundary before dev link/unlink, refresh and package operations. It keeps the wrapper first when changing source roots, carries the original user PATH into update hooks and mise, and checks after each package transaction that the wrapper still exists before any further privileged step, since a transaction can replace the running tree with a release that predates it; when it is gone, or the destination otherwise lacks it, the switch stops after the package switch with instructions to run that release's update from a fresh session rather than letting a bare `sudo` or an updater that authenticates without `--no-update` publish a timestamp. Failed and interrupted channel switches revoke on exit.
|
||||
- `-y` exports `OMARCHY_UPDATE_UNATTENDED=1` and suppresses Omarchy confirmation prompts. Interactive review steps (orphan removal, conflict handoff) report and skip instead of blocking. Privileged commands still require sudo authorization, and command-scoped authentication can prompt separately for each command.
|
||||
- `-y` exports `OMARCHY_UPDATE_UNATTENDED=1` and suppresses Omarchy confirmation prompts. Interactive review steps (orphan removal, conflict handoff) report and skip instead of blocking. Privileged commands still require the one sudo authorization, and AUR installs can prompt separately.
|
||||
- The free-space requirement uses a 10 GiB threshold and stops the update before
|
||||
confirmation when it is not met. If free space cannot be determined, the
|
||||
check is silently skipped. Set `OMARCHY_UPDATE_FORCE=1` to bypass the check.
|
||||
|
||||
Reference in new issue
Block a user