Support scripted updates: modes and policy flags - #11018
Open
SomeoneWithOptions wants to merge 8 commits into
Open
Support scripted updates: modes and policy flags#11018SomeoneWithOptions wants to merge 8 commits into
SomeoneWithOptions wants to merge 8 commits into
Conversation
SomeoneWithOptions
marked this pull request as ready for review
September 9, 2026 18:28
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Scripted
omarchy updatecurrently has no supported contract:--yesis absent, and-yleaks prompts under a transcript PTY (orphangum confirm, rebootgum confirmreachable with a terminal attached), which the prior audit reproduced. This change adds explicit unattended modes plus per-area policy flags with deterministic parsing, a subprocess-scoped nonprompting privilege environment covering the whole descendant tree (including migrations), policy gating for hooks/AUR/mise/orphans/reboot/restarts, failure-closed keyring/inhibitor/git/conflict/migration-deferral semantics, and user plus internal docs. Interactive no-argument behavior is unchanged. This belongs to the #9501 family (scripted-update support).Flag contract
omarchy update [--yes|-y|--non-interactive] [--hooks=run|skip] [--aur=run|skip] [--mise=run|skip] [--orphans=ask|keep|remove] [--reboot=ask|never|if-needed] [--restarts=run|skip]-y,--yes--non-interactiveskip.--hooksrun|skip--aurrun|skip--miserun|skip--orphansask|keep|removeremoveauthorizes removal without confirmation.--rebootask|never|if-neededif-neededauthorizes automatic reboot on success path only.--restartsrun|skipskipdefers service/shell restarts, keeps markers.Parsing rules: exact
--name=valueonly; repeating the same policy with the same value is allowed; contradictory repeats fail exit 2;-y/--yesand--non-interactivemay combine with strict winning regardless of order;askwith either unattended mode fails exit 2 regardless of order; unknown args, missing/invalid values, and positional args fail exit 2 before transcript creation, lock acquisition, or side effects;-h/--helpanywhere prints usage with exit 0 without validating other args or running steps.Behavior defaults per mode
runrunrunaskaskrun-y/--yes(full)runrunrunkeepneverrun--non-interactive(strict)skipskipskipkeepneverrunUnattended runs print
Unattended update (full): ...(or the(strict)form) with normalized policies, plusOrphan policy: remove -- orphaned packages will be removed without confirmationfor--orphans=removeandReboot policy: if-needed -- system will reboot automatically when required (may close unsaved applications)for--reboot=if-needed. Skipped hooks/AUR/mise printSkipping post-update hooks (--hooks=skip)/Skipping AUR package updates (--aur=skip)/Skipping mise updates (--mise=skip); strict opt-in (--hooks=run,--aur=run,--mise=run) runs but first warns on stderr that the non-interactive guarantee is relaxed for that component. Normalized exports:OMARCHY_UPDATE_UNATTENDED=1(either unattended mode, unset interactive),OMARCHY_UPDATE_STRICT=1(strict only, unset otherwise),OMARCHY_UPDATE_HOOKS/OMARCHY_UPDATE_AUR/OMARCHY_UPDATE_MISE(run|skip),OMARCHY_UPDATE_ORPHANS(ask|keep|remove),OMARCHY_UPDATE_REBOOT(ask|never|if-needed),OMARCHY_UPDATE_RESTARTS(run|skip).Guarantees and explicit boundaries
Guaranteed: deterministic parsing/validation before mutation; subprocess-scoped
sudo -nadaptation inherited by plain-sudodescendants (nested bash, xargs/env, migration helpers) with stdin/stdout/stderr and exit-status preservation;pkexecfails closed with no graphical dialog; keyring/inhibitor/reboot/restart/migration/conflict/git failure semantics below; required-migration ordering with deferral staying pending. Explicitly not guaranteed: the adapter directory is subprocessPATHprepend only, not a security boundary and not installed as systemsudo; absolute-path sudo, cleared-PATHcallers, and custom programs bypass it. User hooks, AUR PKGBUILDs, mise backends, package ALPM hooks, and git credential helpers / customcore.sshCommandprograms are cooperative external execution outside the guarantee (strictrunopt-in warns per flag). Sudo credential precondition: unattended runs need a cached ticket or NOPASSWD; otherwisesudo -nfails promptly with no password/GUI dialog (keyring precheck exits 1 withomarchy-update-keyring: unattended update cannot authenticate with sudo (sudo -n failed); run interactively or refresh sudo credentials before retrying).Destructive-policy warnings
--orphans=removeremoves the currently detected orphan packages without confirmation (sudo pacman -Rns --noconfirm, existing recursive semantics); it is not authorization to resolve arbitrary package conflicts.--reboot=if-neededreboots automatically viasudo systemctl --no-ask-password reboot --no-wallonly after all required work succeeds and update-owned inhibitors are released; it never reboots midway or after failure, keeps the reboot marker when the reboot request fails, and can close unsaved applications.What changed (file by file)
bin/omarchy-update: CLI parse/validate/normalize/export, unattended runner re-exec before transcript/lock/space checks, transcript (script(1)→/tmp/omarchy-update.log) and lock order preserved, hooks/AUR/mise gating with skip/warning/summary lines, destructive-policy summaries, preserved order and failure propagation.bin/omarchy-update-run(new): hidden runner installing the scoped privilege environment (OMARCHY_UPDATE_REAL_SUDOcapture,update-binprepend,OMARCHY_UPDATE_ENV_READY=1,OMARCHY_UPDATE_RUN_REEXEC=1re-entry guard).default/omarchy/update-bin/sudo(new): unattended adapter execing captured real sudo with-n, rejecting-S/--stdin,-A/--askpass,-p/--prompt.default/omarchy/update-bin/pkexec(new): unattended fail-closed adapter, exit 1, no dialog.bin/omarchy-update-orphan-pkgs:OMARCHY_UPDATE_ORPHANSpolicy (askinteractive gum flow preserved byte-for-byte;keeplists/retains;removenonconfirm removal with error propagation; unattended/headless ask reports without gum; invalid exits 2).bin/omarchy-update-restart:OMARCHY_UPDATE_REBOOT/OMARCHY_UPDATE_RESTARTSpolicies, single automatic reboot on final success path only,Reboot required: ...reporting,Skipping service restarts .../Shell restart deferredforskip, marker retention on failures, no gum unattended even with PTY.bin/omarchy-update-stay-awake: unattendedsudo -nrunner selection (neverpkexec), observed acquisition withWarning: sleep inhibitor failed to start; continuing without sleep inhibition.warn-and-continue, PID/lock-FD/cleanup semantics preserved.bin/omarchy-update-keyring:set -euo pipefailplus unattendedsudo -n trueprecheck described above;Keys are correctonly on success.bin/omarchy-update-dev,bin/omarchy-update-available: unattendedGIT_TERMINAL_PROMPT=0, emptyGIT_ASKPASS=,GIT_SSH_COMMAND="${GIT_SSH_COMMAND:-ssh -oBatchMode=yes}"(explicit env preserved, custom sshCommand never executed, no new-host-key autoaccept); dev pull failure propagates nonzero, available fetch failure keeps quiet cached-state fallback.migrations/1786643346.sh: unattended browser-open deferral with actionable stderr and exit 1, marker absent, interactive unchanged.migrations/1787760281.sh: strict-plus-OMARCHY_UPDATE_MISE!=runexplicit deferral before either installer branch (never swallowed by|| true), true no-ops preserved.docs/update-process.md(full flag/mode/env/runner/adapter/keyring/inhibitor/git/exit-code contract, interactive unchanged),manual/30-updates.md(new user-facing Non-interactive updates section with defaults table, examples, prerequisites, warnings, boundaries, restarts/reboot/migration/conflict notes),agents/skills/migrations.md(new Unattended updates authoring subsection citing both migration patterns).test/shell.d/update-environment-test.sh,test/shell.d/update-options-test.sh,test/shell.d/update-restart-test.sh,test/shell.d/update-keyring-test.sh,test/shell.d/update-migration-policy-test.sh,test/shell.d/update-unattended-test.sh(35-check mocked PTY/headless end-to-end); rewrittentest/shell.d/update-sequence-test.sh; extendedtest/shell.d/update-orphan-test.sh,test/shell.d/update-lock-test.sh,test/shell.d/update-dev-test.sh,test/shell.d/update-available-test.sh; focusedtest/shell.d/update-disk-space-test.shfixture/assertion updates.Test plan
Focused suites via the sandbox runner (
python3 <run-dir>/sandbox.py -- ...):update-options-test.sh,update-sequence-test.sh,update-orphan-test.sh,update-restart-test.sh,update-lock-test.sh,update-keyring-test.sh,update-migration-policy-test.sh,update-dev-test.sh,update-available-test.sh,update-disk-space-test.sh,update-environment-test.sh, plusbash -non touched bash andgit diff --check. Integration:update-unattended-test.shpasses 35 checks (interactive accept/decline,-y/--yes/strict defaults and overrides, PTY plus headless, orphan remove/keep, reboot if-needed success/failure/single-request, restarts skip, conflict stop, keyring no-auth stop, concurrent lock, transcript/summary presence)../test/clipasses../test/allshows only the 4 pre-existing environment failures from baseline (3 from the missing omarchy-pkgs checkout plus the isolated-network QR sandbox artifact). PTY mutation proofs: disposable-copy removal of the orphan unattended guard and the restart unattended no-gum condition makes the matching PTY tests call gum, confirming the tests catch regressions. No live package operations, reboots, removals, or desktop use in tests.Relation to existing PRs
Related: #9511 (open), #8894, #8992, #9875, #6830. Overlap is expected around scripted-update modes and prompt suppression. What this draft adds beyond that overlap: the full explicit flag contract with per-mode defaults and order-independent parsing/validation rules; a privilege adapter scoped to updater descendants that also covers migrations and transitive first-party sudo callers; keyring unattended precheck and inhibitor acquisition failure semantics; reboot/restarts policies with single-request automatic reboot; git unattended env for dev/available with custom-helper boundaries; migration deferral patterns for unattended and strict-mise cases; plus user and internal docs. Happy to rebase onto whichever related branch lands first and to coordinate rather than duplicate: please point out the preferred base and I will reshape this accordingly.
Limitations
Packaging rule verified for
default/**copy into/usr/share/omarchy/default/(covers the new adapters and preserves executability) from the omarchy-pkgs PKGBUILD, but a full package build was not run and the omarchy-pkgs repo was not checked out here. No live update was executed; end-to-end means the full orchestrator flow with real transcript/lock/helpers and mocked package/system boundaries, not a live upgrade. No timeout is imposed on real package transactions. Upstream package hooks and third-party prompts remain outside the guarantee as documented.Compliance notes
Docs follow repo
AGENTS.mdmarkdown style (full lines, two-space indent). Suggested atomic commits, one per area: CLI/runner/adapters plus environment tests; orphan policy plus tests; restart/reboot policy plus tests; stay-awake/keyring plus tests; migrations plus policy tests; git/dev/available plus tests; unattended integration test; docs (update-process, manual, migrations skill). No commits made here; branchfeat/update-automation-policiesholds unstaged implementation plus docs for review.