feat(auth): non-interactive flags for login/refresh (#211)#243
feat(auth): non-interactive flags for login/refresh (#211)#243
Conversation
Add --email, --token, --client-id, --client-secret to both `jr auth login`
and `jr auth refresh`. Each value resolves via flag > env var > TTY
prompt. Under --no-input, missing credentials produce JrError::UserError
(exit 64) naming the specific flag + env var so agents and CI scripts
can recover.
Env vars:
JR_EMAIL (api_token flow)
JR_API_TOKEN (api_token flow; prefer over --token to avoid
process-list leakage)
JR_OAUTH_CLIENT_ID (OAuth flow)
JR_OAUTH_CLIENT_SECRET (OAuth flow; same preference)
OAuth errors include a dev-console URL hint so first-time agents learn
they must create an app at developer.atlassian.com before passing
credentials — not just *how* to pass them.
refresh_credentials keeps its clear-then-login ordering; the existing
"Credentials were cleared" recovery line is now pinned by an integration
test assertion so a future refactor can't drop the hint silently.
Tests:
- 5 new unit tests on resolve_credential (flag/env/empty/no_input/hint)
- RAII EnvGuard for test env vars so a panic can't leak state across
parallel tests in the same process
- Tightened tests/auth_refresh.rs to assert exit 64, specific flag/env
message, and recovery hint (replaces pre-#211 "fails without panic")
Closes #211
There was a problem hiding this comment.
Pull request overview
Adds non-interactive credential flags to jr auth login / jr auth refresh, resolving credentials via flag → env var → TTY prompt, and producing a JrError::UserError (exit 64) with actionable messaging under --no-input.
Changes:
- Introduces
resolve_credentialhelper +JR_*env var constants to implement consistent credential resolution and--no-inputerror behavior (with OAuth hint URL). - Plumbs new optional credential args through CLI parsing and dispatch (
main.rs,cli/mod.rs,cli/init.rs). - Tightens
auth_refreshintegration test to assert exit code 64 and presence of a recovery message.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/cli/auth.rs |
Adds credential resolution helper (flag/env/prompt), OAuth hinting, and threads new args through login/refresh flows; adds unit tests and env RAII guard. |
src/cli/mod.rs |
Adds --email/--token/--client-id/--client-secret options to auth login and auth refresh clap structs. |
src/main.rs |
Passes new CLI options and --no-input into auth login/refresh functions. |
src/cli/init.rs |
Updates init’s auth calls to new function signatures (interactive-only path uses no_input=false). |
tests/auth_refresh.rs |
Replaces prior “no panic” assertion with --no-input contract checks (exit 64 + actionable stderr). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Document the new flag/env-var surface in three places:
- Quick Start code block: shell examples for both api_token and OAuth
flows under --no-input
- macOS upgrade section: CI/headless recovery path
- Scripting & AI Agents section: bullet referencing all 4 flags + env
vars
- Commands table: expand auth login entry, add auth refresh entry
Paired with the feature commit (9442f4c) on this branch.
Config::load() merges JR_* env vars via figment's Env::prefixed at
src/config.rs:65. A developer with JR_INSTANCE_AUTH_METHOD=oauth
exported in their shell would take the OAuth path under `auth refresh`,
and the test's email/JR_EMAIL stderr assertions would fail.
Explicitly env_remove("JR_INSTANCE_AUTH_METHOD") so the test is
hermetic to parent-env configuration.
Flagged by Copilot on PR #243.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Per Copilot review on PR #243: `EnvGuard` did RAII cleanup but didn't serialize env-var mutation across parallel tests. Since `std::env::set_var` / `remove_var` are unsafe in Rust 2024 (concurrent env access is UB — C's getenv/setenv aren't thread-safe), tests could still race even with distinct per-test keys. Add `static ENV_LOCK: Mutex<()>` and hold the lock for EnvGuard's full lifetime. Also lock reader-only tests that call `resolve_credential` (which reads env via `std::env::var`), since reads must also be serialized against concurrent writes. Matches the established pattern in src/config.rs::ENV_MUTEX and src/cache.rs::ENV_MUTEX.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // stderr assertions would fail. Explicitly clear it to pin the | ||
| // api_token flow for this test. | ||
| .env_remove("JR_INSTANCE_AUTH_METHOD") | ||
| .args(["--no-input", "auth", "refresh"]) |
There was a problem hiding this comment.
This integration test no longer sets stdin for the subprocess (it used to call write_stdin("")). If --no-input handling regresses and the command falls back to an interactive prompt, the test can hang waiting for user input (especially when cargo test is run with an attached TTY). Consider explicitly piping empty stdin (or otherwise closing stdin) so a regression fails fast instead of blocking the test suite.
| .args(["--no-input", "auth", "refresh"]) | |
| .args(["--no-input", "auth", "refresh"]) | |
| .write_stdin("") |
Summary
Adds
--email,--token,--client-id,--client-secrettojr auth loginandjr auth refresh. Each credential resolves via flag → env var → TTY prompt. Under--no-input, missing credentials produceJrError::UserError(exit 64) with a message naming the specific flag and env var so agents and CI can recover.Value resolution
--emailJR_EMAIL--tokenJR_API_TOKEN--client-idJR_OAUTH_CLIENT_ID--client-secretJR_OAUTH_CLIENT_SECRETPrefer env vars over flags for secrets — bare CLI args leak via
ps/audit logs. This is documented in clap help text.Error-path UX for agents
The dev-console URL is appended only to OAuth errors so first-time agents learn where to obtain an app, not just how to pass credentials. Addresses a silent-failure-hunter finding from local review.
Backward compat
jr initstill works (inherently interactive — no flag threading).jr auth refreshpreserves its clear-then-login ordering; if login fails, the user still sees "Credentials were cleared. Run `jr auth login` to restore access."Findings from local review (all addressed)
hintparam toresolve_credential; passedOAUTH_APP_HINTfor both OAuth credsunsafe { set_var }in tests had no panic-safe cleanupEnvGuardRAII struct; all 4 env-setting tests now use itTest plan
cargo fmt --all -- --checkcleancargo clippy --all-targets -- -D warningscleancargo test— 813 passed, 0 failed (baseline 805 + 8 new)resolve_credential_*unit tests (flag/env/empty/no_input/OAuth hint)auth_refresh_no_input_fails_with_clear_messageintegration testScope notes
refresh_credentialsnow has 7 params. Consider aRefreshArgsstruct if it grows further — not needed now, and clippy is silent on it.Closes #211