Skip to content

Improve j commands exception handling#328

Merged
mangelajo merged 5 commits into
jumpstarter-dev:mainfrom
bkhizgiy:excp
Mar 18, 2026
Merged

Improve j commands exception handling#328
mangelajo merged 5 commits into
jumpstarter-dev:mainfrom
bkhizgiy:excp

Conversation

@bkhizgiy
Copy link
Copy Markdown
Member

@bkhizgiy bkhizgiy commented Mar 17, 2026

Updated exception handling for J commands to show cleaner, actionable errors for common failures: timeouts, TLS/certificate issues, DNS/connection problems, file and permission errors, bad JSON, and user cancellations. It also now maps key gRPC errors (DEADLINE_EXCEEDED, UNAVAILABLE, UNAUTHENTICATED/PERMISSION_DENIED, INVALID_ARGUMENT) to friendlier messages.

Also made sure the re-auth wrapper uses the same fallback mapping and improved jmp login fetch handling so invalid JSON/content-type responses are reported clearly.

Related to: #57

Summary by CodeRabbit

  • New Features

    • Improved error messaging: timeouts, TLS cert issues, DNS, file/JSON errors, gRPC auth/argument problems and interrupts now map to clear, actionable CLI messages.
    • Stricter login validation: tighter checks on login endpoints, auth-config payloads, argument parsing, and conflicting insecure-flag handling.
  • Refactor

    • Centralized exception translation for consistent error handling across sync/async flows.
  • Tests

    • Added comprehensive tests for exception mappings, reauthentication flows, gRPC cases, and login validation.

Normalize common runtime/network exceptions into user friendly messages and add validation for login and flashing inputs so users get actionable
errors before long running operations start.

Assisted-by: GPT-5.3 Codex
Signed-off-by: Bella Khizgiyaev <bkhizgiy@redhat.com>
Add unit and cli tests for login and flasher validation plus common exception mapping to ensure user facing errors remain clear and consistent.

Assisted-by: GPT-5.3 Codex
Signed-off-by: Bella Khizgiyaev <bkhizgiy@redhat.com>
Handle cancel/abort, invalid JSON, auth/permission gRPC failures, and invalid argument responses with concise actionable messages,
and add tests to keep the mappings stable.

Assisted-by: GPT-5.3 Codex
Signed-off-by: Bella Khizgiyaev <bkhizgiy@redhat.com>
Map common exceptions in the reauth decorator fallback, tighten test fixtures for stable local execution, and drop redundant flasher preflight validation/tests to keep behavior aligned with existing downstream handling.

Assisted-by: GPT-5.3 Codex
Signed-off-by: Bella Khizgiyaev <bkhizgiy@redhat.com>
@netlify
Copy link
Copy Markdown

netlify Bot commented Mar 17, 2026

Deploy Preview for jumpstarter-docs ready!

Name Link
🔨 Latest commit 3a8ee7e
🔍 Latest deploy log https://app.netlify.com/projects/jumpstarter-docs/deploys/69b9862564d95300086aefeb
😎 Deploy Preview https://deploy-preview-328--jumpstarter-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9311085c-94cd-44d9-933d-47a123efcc3d

📥 Commits

Reviewing files that changed from the base of the PR and between c7a0668 and 3a8ee7e.

📒 Files selected for processing (3)
  • python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py
  • python/packages/jumpstarter-cli/jumpstarter_cli/login.py
  • python/packages/jumpstarter-cli/jumpstarter_cli/login_test.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • python/packages/jumpstarter-cli/jumpstarter_cli/login_test.py

📝 Walkthrough

Walkthrough

Centralizes CLI exception translation by adding private mappers for runtime, TLS, I/O, JSON, DNS, KeyboardInterrupt/Abort and gRPC errors; routes all sync/async handlers and reauth flows through the mapper; adds login endpoint and auth-config payload validation; and adds tests for mappings and login behavior.

Changes

Cohort / File(s) Summary
Exception handling core
python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py
Adds private helpers (_append_details, _map_runtime_exception, _extract_grpc_code_and_details, _map_grpc_exception, _map_common_exception, _map_cli_exception) and maps timeouts, SSL/TLS, DNS/connection, file/JSON/OSError, KeyboardInterrupt/Abort, and gRPC status codes into ClickExceptions; replaces ad-hoc handling in sync/async wrappers and integrates mapping into reauthentication paths.
Exception tests
python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions_test.py
New test suite verifying sync/async exception mappings (timeout, TLS cert, FileNotFound, connection refused, JSON decode, KeyboardInterrupt, click.Abort), gRPC status mappings (UNAUTHENTICATED, INVALID_ARGUMENT), and reauth flow behavior.
Login validation & CLI
python/packages/jumpstarter-cli/jumpstarter_cli/login.py, python/packages/jumpstarter-cli/jumpstarter_cli/login_test.py
Adds _validate_login_endpoint_url and _validate_auth_config_payload; tightens fetch_auth_config (adds use_http param) to validate URL/payload and convert TLS/JSON/timeout errors to ClickExceptions; enforces trimming/emptiness checks for login args and disallows simultaneous --insecure-login-http and --insecure-login-tls; tests added for parsing, URL scheme/host checks, payload requirements, injected network/TLS failures, and conflicting flags.
Test utility tweak
python/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/client_test.py
Initializes children and methods_description in MockFlasherClient test fixture (minor test helper state addition).

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI
    participant Backend as Network / gRPC / File IO
    participant Mapper as Exception Mapper (private helpers)
    participant Reauth as Reauth Handler
    participant Click as ClickException output

    CLI->>Backend: perform operation (sync/async)
    Backend-->>CLI: raises exception (timeout / ssl / gRPC / JSON / IO / KeyboardInterrupt)
    CLI->>Mapper: submit exception for mapping
    alt mapped to ClickException
        Mapper-->>Click: return user-facing ClickException
        CLI-->>Click: raise/display ClickException
    else authentication error
        Mapper-->>Reauth: indicate auth failure
        Reauth-->>CLI: attempt reauthentication (may invoke login callback)
        Reauth-->>Mapper: provide retry outcome
        Mapper-->>Click: return/display final ClickException or success
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • NickCao
  • mangelajo
  • bennyz

Poem

🐇
I hop through code where errors hide,
I stitch their paths and smooth their stride.
Timeouts, TLS, and gRPC’s plea,
Now speak like friends — polite and free.
— a joyful rabbit 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: improving exception handling in j commands to produce clearer error messages for common failures.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@bkhizgiy
Copy link
Copy Markdown
Member Author

There are many cases that could be covered, and I’m not sure how many of them are actually needed vs. overkill, so feel free to suggest adding anything missing or removing anything unnecessary.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py`:
- Around line 79-89: The linter flags B009 for using getattr with a constant
after hasattr checks; update the exception attribute access by replacing
getattr(exc, "code") and getattr(exc, "details") with direct attribute access
(exc.code and exc.details) in the block that computes grpc_code/code and
details, and similarly replace getattr(grpc_code, "name", str(grpc_code)) with
direct attribute access to grpc_code.name when present (falling back to
str(grpc_code)) so the code uses exc.code(), exc.details(), and grpc_code.name
directly in the try/except handling.
- Around line 54-57: The long error message inside the ConnectionRefusedError
branch in exceptions.py exceeds 120 chars; split the string literal into two (or
use implicit concatenation inside the existing parentheses) so the line length
is under 120. Edit the block that returns ClickExceptionRed in the
isinstance(exc, ConnectionRefusedError) branch and break the message into
multiple shorter string literals (or use +/adjacent quoted strings) while
preserving the same message and the {message} interpolation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ddb68d07-fec0-4096-9730-4200279a9cb9

📥 Commits

Reviewing files that changed from the base of the PR and between ec11dc4 and 563b1bc.

📒 Files selected for processing (5)
  • python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py
  • python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions_test.py
  • python/packages/jumpstarter-cli/jumpstarter_cli/login.py
  • python/packages/jumpstarter-cli/jumpstarter_cli/login_test.py
  • python/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/client_test.py

Comment thread python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py Outdated
Comment thread python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py`:
- Around line 225-226: Replace uses of _map_common_exception with
_map_cli_exception in the reauthentication branches so the CLI mapping is
applied consistently: locate the branches that do "elif common_exc :=
_map_common_exception(exc): raise common_exc from None" (and the similar
occurrence later) and call _map_cli_exception(exc) instead, assign to common_exc
as before and re-raise it ("raise common_exc from None") so the reauth flow uses
the same CLI exception translator as the main decorators.

In `@python/packages/jumpstarter-cli/jumpstarter_cli/login.py`:
- Around line 28-36: The _validate_login_endpoint_url function currently accepts
"http" without checking the CLI flag; update it so that if parsed.scheme ==
"http" it raises a click.ClickException unless the explicit opt-in flag is set
(--insecure-login-http). Modify _validate_login_endpoint_url to accept an
insecure_login_http: bool parameter (or read from
click.get_current_context().params["insecure_login_http"]) and if scheme ==
"http" and not insecure_login_http raise a clear error instructing the user to
pass --insecure-login-http to allow plain HTTP; keep the existing checks for
unsupported schemes and missing host intact.
- Around line 128-131: The validation currently checks parts[0] and parts[1] for
empty strings but doesn't trim whitespace, so inputs like "name@   " slip
through; update the code that handles the split result (the parts list) to trim
whitespace (e.g., use parts[0].strip() and parts[1].strip() or reassign trimmed
variables) before performing the empty checks and raising the ClickException
messages, ensuring you validate the trimmed values rather than the raw split
tokens.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 04c38fec-2220-480f-ae49-062733cda8a1

📥 Commits

Reviewing files that changed from the base of the PR and between 563b1bc and c7a0668.

📒 Files selected for processing (2)
  • python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py
  • python/packages/jumpstarter-cli/jumpstarter_cli/login.py

Comment thread python/packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py Outdated
Comment thread python/packages/jumpstarter-cli/jumpstarter_cli/login.py Outdated
Comment thread python/packages/jumpstarter-cli/jumpstarter_cli/login.py Outdated
Refine shared exception translation paths and tighten login endpoint parsing/validation so insecure HTTP requires explicit opt-in and whitespace-only login target segments fail with clear errors.

Assisted-by: GPT-5.3 Codex
Signed-off-by: Bella Khizgiyaev <bkhizgiy@redhat.com>
@mangelajo
Copy link
Copy Markdown
Member

Nice improvement!

@mangelajo mangelajo merged commit 9494928 into jumpstarter-dev:main Mar 18, 2026
31 checks passed
Copy link
Copy Markdown
Member

@raballew raballew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timeout type tuple in _map_runtime_exception lists TimeoutError, asyncio.TimeoutError, socket.timeout, and FutureTimeoutError -- but since Python 3.11 (your minimum) these are all the same object. Just TimeoutError is enough.

handle_exceptions_with_reauthentication is missing a KeyboardInterrupt handler. The other two decorators both catch it and show "Cancelled by user." cleanly, but this one only has except Exception which won't catch KeyboardInterrupt (it inherits from BaseException), so the user gets a raw traceback instead.

The login tests (test_login_cli_shows_timeout_message, test_login_cli_shows_certificate_message) monkeypatch fetch_auth_config to raise click.ClickException directly, so they never exercise the exception mapping logic in fetch_auth_config. If that mapping code were removed, the tests would still pass.

@bkhizgiy
Copy link
Copy Markdown
Member Author

@raballew thanks for the feedback, I"ll post it as a follow-up PR.

@mangelajo
Copy link
Copy Markdown
Member

oops, thank you @raballew and @bkhizgiy

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.

3 participants