feat(system): add login shell bootstrap support#10377
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds a declarative ChangesLogin Shell System Feature
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Greptile SummaryThis PR introduces
Confidence Score: 5/5Safe to merge; the change is correctly gated on experimental, the sudo/SUDO_USER path is handled, and the e2e test covers the critical apply flows. The core logic in login_shell.rs and the install/status wiring is solid. The two doctor output issues are cosmetic inconsistencies that do not affect correctness or safety. src/cli/doctor/mod.rs — the SystemLoginShellDiagnosis::Checked variant loses shell_listed and user from LoginShellStatus, producing less informative doctor output than system status --json. Important Files Changed
Reviews (3): Last reviewed commit: "fix(system): tighten login shell converg..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@e2e/cli/test_system_login_shell`:
- Around line 3-9: Ensure the test setup creates the bin directory and resets
the log before installing the fake chsh: create "$HOME/bin" with mkdir -p
"$HOME/bin", export CHSH_LOG="$PWD/chsh.log" (move the export above the
here-doc), remove any stale log (rm -f "$CHSH_LOG" or >"$CHSH_LOG") before the
test runs, then write the chsh stub to "$HOME/bin/chsh" (the here-doc should
append to "$CHSH_LOG" as before) and chmod +x "$HOME/bin/chsh"; this guarantees
CHSH_LOG and the target directory exist and the log is deterministic across
runs.
In `@mise.usage.kdl`:
- Line 291: The text currently groups "[system].login_shell" with macOS, which
is incorrect; update both occurrences so platform scope is explicit: leave
macOS-specific mentions tied to "[system.defaults]" or "(macOS)" only, and
clarify that "[system].login_shell" is a Unix-wide feature (e.g., "on Unix
systems, [system].login_shell — settable via chsh -s"); for example replace
ambiguous fragments like "(macOS) and [system].login_shell" with two clear
phrases such as "(macOS) and, separately, on Unix systems [system].login_shell
(set via chsh -s)". Ensure both places in the file use this clarified wording.
- Around line 2992-2993: The text mistakenly uses "version-differs" for the
login_shell status; update the wording around the existing phrase that lists
"missing/version-differs categories for configured login shell" to instead use a
non-versioned term such as "differs" or "out-of-sync" (e.g., replace
"version-differs" with "differs" so the login_shell is described as either
"missing" or "differs/out-of-sync"); target the occurrence referencing
login_shell in the sentence so no other versioned entries are changed.
In `@schema/mise.json`:
- Around line 2964-2967: The schema allows any string for the login_shell
property but the description requires an absolute path; tighten the
"login_shell" JSON Schema by adding a constraint such as "pattern": "^/.*" (or
an appropriate absolute-path regex) and, if desired, "minLength": 1 to reject
empty strings so that only absolute-paths (starting with "/") are accepted;
update the "login_shell" schema entry to include this pattern property while
leaving the existing "type" and "description" intact.
In `@xtasks/fig/src/mise.ts`:
- Around line 3345-3346: The help text for the "system status --missing" command
omits edits even though the implementation checks
system::edits::edits_from_config() and sets any_missing when a FileState !=
Applied; update the command help/description string to mention "[system.edits]"
alongside "packages, files, defaults, or login shell" and regenerate/modify the
corresponding generated entry in mise.ts so the displayed help includes
"[system.edits]" as well (ensure the same wording appears in the CLI source
description and the generated xtasks entry).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: e4bb3fde-e3b3-4fdb-81a0-ed4a7094a36b
📒 Files selected for processing (20)
docs/cli/bootstrap.mddocs/cli/system.mddocs/cli/system/install.mddocs/cli/system/status.mddocs/system-login-shell.mddocs/system-packages/index.mddocs/tips-and-tricks.mde2e/cli/test_system_login_shellman/man1/mise.1mise.usage.kdlschema/mise.jsonsrc/cli/bootstrap.rssrc/cli/doctor/mod.rssrc/cli/system/install.rssrc/cli/system/mod.rssrc/cli/system/status.rssrc/config/config_file/mise_toml.rssrc/system/login_shell.rssrc/system/mod.rsxtasks/fig/src/mise.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/system/login_shell.rs`:
- Around line 67-70: The apply() function calls
ensure_shell_listed(&request.shell, dry_run) before resolving the user, which
can mutate /etc/shells even if user resolution fails; change the call order so
you first resolve the user and compute chsh args (call target_user() and
chsh_args(request, &user)), and only after those succeed call
ensure_shell_listed(&request.shell, dry_run) (so ensure_shell_listed runs after
target_user() and chsh_args()). Update apply() to return errors from
target_user()/chsh_args() without having already modified shells.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: c6984b1c-6f8d-494b-9599-04ccd54e50ae
📒 Files selected for processing (10)
docs/cli/system/install.mddocs/system-login-shell.mddocs/system-packages/index.mde2e/cli/test_system_login_shellman/man1/mise.1mise.usage.kdlsrc/cli/system/install.rssrc/cli/system/status.rssrc/system/login_shell.rssrc/system/sudo.rs
✅ Files skipped from review due to trivial changes (5)
- src/system/sudo.rs
- docs/cli/system/install.md
- docs/system-packages/index.md
- man/man1/mise.1
- mise.usage.kdl
🚧 Files skipped from review as they are similar to previous changes (4)
- docs/system-login-shell.md
- e2e/cli/test_system_login_shell
- src/cli/system/status.rs
- src/cli/system/install.rs
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 11a13a2. Configure here.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/system/login_shell.rs (1)
71-85:⚠️ Potential issue | 🟠 Major | ⚡ Quick winSkip
chshwhen the requested shell is already current.
status()now distinguishesMissingFromShells, butapply()still always executeschshafter repairing/etc/shells. When the passwd entry already matchesrequest.shell, that turns a shells-allowlist fix into an unnecessarychshcall and makes the install/bootstrap path prompt for work that is already applied. Please short-circuit this branch afterensure_shell_listed()and add a regression test for thecurrent == requested && !shell_listedcase.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/system/login_shell.rs` around lines 71 - 85, In apply(), after calling ensure_shell_listed(&request.shell, dry_run) and before building/printing/executing the chsh command, check the current shell for the target user (reusing target_user() result or calling the same lookup used by status()) and if the current shell equals request.shell return Ok(()) (or log that no chsh is needed) to short-circuit the unnecessary chsh; update or reuse functions chsh_args(), target_user(), and ensure_shell_listed() as needed to get the current value without duplicating logic, and add a regression test exercising the case where current == requested && !shell_listed to ensure apply() repairs /etc/shells but does not call chsh.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/system/login_shell.rs`:
- Around line 71-85: In apply(), after calling
ensure_shell_listed(&request.shell, dry_run) and before
building/printing/executing the chsh command, check the current shell for the
target user (reusing target_user() result or calling the same lookup used by
status()) and if the current shell equals request.shell return Ok(()) (or log
that no chsh is needed) to short-circuit the unnecessary chsh; update or reuse
functions chsh_args(), target_user(), and ensure_shell_listed() as needed to get
the current value without duplicating logic, and add a regression test
exercising the case where current == requested && !shell_listed to ensure
apply() repairs /etc/shells but does not call chsh.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: dec4fd46-0652-491b-a05e-d68c08bb30f1
📒 Files selected for processing (14)
docs/cli/bootstrap.mddocs/cli/system.mddocs/cli/system/install.mddocs/cli/system/status.mde2e/cli/test_system_login_shellman/man1/mise.1mise.usage.kdlschema/mise.jsonsrc/cli/bootstrap.rssrc/cli/system/install.rssrc/cli/system/mod.rssrc/cli/system/status.rssrc/system/login_shell.rsxtasks/fig/src/mise.ts
✅ Files skipped from review due to trivial changes (7)
- src/cli/system/mod.rs
- docs/cli/system/install.md
- docs/cli/bootstrap.md
- xtasks/fig/src/mise.ts
- docs/cli/system/status.md
- man/man1/mise.1
- mise.usage.kdl
🚧 Files skipped from review as they are similar to previous changes (5)
- docs/cli/system.md
- src/cli/bootstrap.rs
- schema/mise.json
- src/cli/system/status.rs
- e2e/cli/test_system_login_shell
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.6.5 x -- echo |
17.8 ± 0.7 | 16.4 | 22.1 | 1.00 |
mise x -- echo |
18.5 ± 2.0 | 16.9 | 57.7 | 1.04 ± 0.12 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.6.5 env |
17.8 ± 0.7 | 16.2 | 21.0 | 1.00 |
mise env |
18.3 ± 0.7 | 16.8 | 21.8 | 1.03 ± 0.06 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.6.5 hook-env |
18.3 ± 0.7 | 16.9 | 22.3 | 1.00 |
mise hook-env |
18.9 ± 0.7 | 17.5 | 22.0 | 1.03 ± 0.06 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.6.5 ls |
15.0 ± 0.7 | 13.7 | 18.6 | 1.00 |
mise ls |
15.7 ± 0.7 | 14.2 | 18.8 | 1.04 ± 0.07 |
xtasks/test/perf
| Command | mise-2026.6.5 | mise | Variance |
|---|---|---|---|
| install (cached) | 131ms | 132ms | +0% |
| ls (cached) | 58ms | 59ms | -1% |
| bin-paths (cached) | 63ms | 63ms | +0% |
| task-ls (cached) | 122ms | 123ms | +0% |

Summary
[system].login_shellas a declarative current-user login shell settingchsh -sfrommise system installandmise bootstrapmise system status,mise doctor, schema, and docsTests
cargo fmt --all -- --checkcargo check --all-targetsmise run rendermise run test:e2e e2e/cli/test_system_login_shellmise run test:unitThis PR was generated by an AI coding assistant.
Note
High Risk
Changes the user's login shell and may modify
/etc/shellsvia sudo—account-level, irreversible-feeling effects that only run on explicit install/bootstrap but warrant careful review.Overview
Adds
[system].login_shellsomise.tomlcan declare the current user's desired login shell (absolute path) and converge it withmise system installormise bootstrap, alongside existing system packages, files, edits, and defaults.On Unix when
chshis available, install appends the shell to/etc/shellsif needed (reusing the system-packages sudo path when the file isn't writable), then runschsh -swith optional confirmation, dry-run, and--yes. Under sudo it targetsSUDO_USER; invalid or relative paths are warned and skipped. Most-local config wins for the single desired value.mise system status(table + JSON) and--missingnow include login-shell drift; scoped installs (--manageror explicit packages) still apply packages only.mise doctorreportssystem_login_shellin text and JSON. Schema, CLI help, man page, and a new System Login Shell doc page are updated; an e2e test covers status, override, dry-run, and apply with stubbedchshand/etc/shells.Reviewed by Cursor Bugbot for commit b4404eb. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
Behavior & UX
Documentation
Tests