Skip to content

fix(utils): hard-error in get_config_dir when HOME is unresolvable - #15

Open
TheBigWealth89 wants to merge 1 commit into
Txio-labs:mainfrom
TheBigWealth89:fix/get-config-dir-hard-error-on-missing-home
Open

fix(utils): hard-error in get_config_dir when HOME is unresolvable#15
TheBigWealth89 wants to merge 1 commit into
Txio-labs:mainfrom
TheBigWealth89:fix/get-config-dir-hard-error-on-missing-home

Conversation

@TheBigWealth89

Copy link
Copy Markdown

fix(utils): Hard-error in get_config_dir() when HOME is unresolvable

Closes #12

What was broken

get_config_dir() in src/utils/mod.rs silently fell back to PathBuf::from(".") whenever dirs_next::home_dir() returned None. This caused the CLI to write auth tokens and config.json into ./.txio/ in the current working directory instead of the user's home directory.

This introduced two concrete security/reliability risks:

  • Silent credential loss — in ephemeral environments (CI runners, containers, Docker builds), the working directory is wiped after the job finishes, silently destroying any credentials that were written there.
  • Accidental credential exposure — if the CLI was invoked from inside a git-tracked project directory, the newly created .txio/ folder (and its token file) could be inadvertently committed and pushed to a remote.

What changed

src/utils/mod.rs

  • get_config_dir() now returns Result<PathBuf> instead of PathBuf.
  • On dirs_next::home_dir() returning None or an empty string, it immediately returns Err with a clear, actionable message:

    "Could not determine home directory (checked $HOME). Set the HOME environment variable and try again."

  • The empty-string guard (filter(|p| !p.as_os_str().is_empty())) ensures HOME="" is treated identically to HOME being unset.
  • All 11 internal callers propagate the result via ?:
    save_token, get_token, remove_token, save_config, get_config, list_config, remove_config, save_current_chain, get_current_chain, remove_config, load_environment.
  • get_token and get_current_chain return types change from Option<String> to Result<Option<String>>.

src/cli/handlers.rs

  • All call sites of get_token() and get_current_chain() updated to handle the new Result wrapper with ?.
  • Errors propagate naturally to main().

src/main.rs — no changes required

main() already catches any Err returned from CommandHandler::handle(), prints it to stderr in a user-friendly format, and exits with code 1. The new error flows through this existing path automatically.

Tests (src/utils/mod.rs)

  • New: get_config_dir_fails_when_home_unset — unsets HOME under the existing ENV_LOCK mutex (which serializes all env-var-mutating tests), calls get_config_dir(), and asserts the result is Err containing "Could not determine home directory". Restores HOME on exit.
  • Updated: config_dir_created_with_mode_0700 — unwraps the now-Result return value (safe within the test since HOME is explicitly set).

Why the hard-error approach

The alternative (loud eprintln! warning + implicit fallback path) was explicitly considered and rejected. A warning is easy to miss in automated pipelines, and any silent path selection — even a "better" one like $XDG_CONFIG_HOME or /tmp — creates new implicit behaviour that can still surprise users. A hard error ensures the failure is never invisible and forces the operator to fix the root cause ($HOME must be set).

Breaking change

⚠️ This is an intentional breaking change.

Any workflow that relied on the undocumented behaviour of txio writing to ./.txio/ when HOME was unset will now receive an explicit error instead of silently proceeding. This is the desired outcome — the old behaviour was a bug, not a feature.

Acceptance criteria

  • When dirs_next::home_dir() returns None, the CLI exits with a clear error message (no silent fallback to .).
  • The error message clearly states the home directory could not be resolved and tells the user how to fix it.
  • Normal operation (home directory resolvable) is completely unaffected — no new prompts, errors, or behaviour change.
  • A test covers the unresolved-home-directory path.
  • All call sites of get_config_dir() handle the Result properly — no .unwrap()-induced panics introduced.

Previously, get_config_dir() silently fell back to the current working
directory when dirs_next::home_dir() returned None, causing the CLI to
write auth tokens and config.json into ./.txio/ instead of a stable
home directory. This had two real-world risks:

  - Silent credential loss in ephemeral environments (CI, containers)
    where the working directory is wiped after the run.
  - Accidental credential exposure via git if the CLI was run from
    inside a tracked project directory.

Changes:
  - get_config_dir() now returns Result<PathBuf> and fails with a
    clear, actionable error message if home_dir() returns None or an
    empty string: "Could not determine home directory (checked $HOME).
    Set the HOME environment variable and try again."
  - All 11 callers propagate the Result with ? (save_token, get_token,
    remove_token, save_config, get_config, list_config, remove_config,
    save_current_chain, get_current_chain, load_environment).
  - get_token and get_current_chain signatures change from Option<String>
    to Result<Option<String>>; all call sites in handlers.rs updated.
  - Error propagates to main(), which already prints errors to stderr
    and exits with code 1.
  - Added test: get_config_dir_fails_when_home_unset.

BREAKING CHANGE: any workflow relying on the old silent working-directory
fallback (./.txio/) will now receive an explicit error. This is intentional.
@Kingvic300

Copy link
Copy Markdown
Contributor

@TheBigWealth89 kindly resolve conflicts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Config/credential directory silently falls back to the current working directory when HOME can't be resolved

2 participants