Skip to content

Conversation

@GT-610
Copy link
Collaborator

@GT-610 GT-610 commented Jan 28, 2026

Resolve #969.

Rewrite the whole logic of parsing outputs when accessing Docker though sudo. This should fix all issues about Docker parsing errors when it is installed in Snap, can't directly be accessed by current user, etc.

Summary by CodeRabbit

  • New Features

    • Password caching for container sudo operations and a non-interactive sudo execution method that surfaces password-related outcomes.
  • Bug Fixes

    • Detect and report sudo password failures with distinct outcomes (required vs incorrect) and avoid mixing stderr into normal command output; improved handling when container tooling is unavailable.
  • Documentation

    • Added localized sudo-related messages and clarified database compaction wording (no data will be deleted).

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 28, 2026

📝 Walkthrough

Walkthrough

Adds non-interactive sudo password handling: new SSH client API returns (exitCode, output) detecting sudo password errors; container provider caches/pipes base64-encoded password into sudo, maps password error codes to new enum cases, and adds localized messages.

Changes

Cohort / File(s) Summary
SSH Client Execution
lib/core/extension/ssh_client.dart
Removed PwdRequestFunc and interactive prompt logic; added execWithPwd(...) returning Future<(int?, String)>, suppressing stderr in returned output and detecting password-related stderr to return exit code 2 with output.
Container Provider Logic
lib/data/provider/container.dart
Added _cachedPassword and _getSudoPassword(); adjusted ContainerCmdType.exec/execAll signatures to accept password; added _buildSudoCmd() to pipe base64-decoded password into sudo -S; propagate password into exec flows; treat exit code 2 as incorrect sudo password and clear cache; removed interactive-output filtering.
Error Model
lib/data/model/app/error.dart
Added enum members sudoPasswordRequired and sudoPasswordIncorrect to ContainerErrType.
Localization
lib/l10n/app_*.arb
lib/l10n/app_en.arb, lib/l10n/app_zh.arb, lib/l10n/app_de.arb, lib/l10n/app_es.arb, lib/l10n/app_fr.arb, lib/l10n/app_id.arb, lib/l10n/app_ja.arb, lib/l10n/app_nl.arb, lib/l10n/app_pt.arb, lib/l10n/app_ru.arb, lib/l10n/app_tr.arb, lib/l10n/app_uk.arb, lib/l10n/app_zh_tw.arb
Added containerSudoPasswordRequired and containerSudoPasswordIncorrect localization keys across locales; updated compactDatabaseContent text in app_en.arb.
Resources
lib/data/res/github_id.dart
Added two entries ('wanababy', 'toarujs') to GithubIds.participants.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ContainerProvider as Container Provider
    participant PasswordCache as Password Cache
    participant SSHClient as SSH Client
    participant ErrorHandler as Error Handler

    User->>ContainerProvider: Request run (sudo required)
    ContainerProvider->>PasswordCache: Check cached password
    alt not cached
        ContainerProvider->>User: Prompt for password (_getSudoPassword)
        User-->>ContainerProvider: Enter password
        ContainerProvider->>PasswordCache: Cache password
    end
    ContainerProvider->>ContainerProvider: _buildSudoCmd(password)
    ContainerProvider->>SSHClient: execWithPwd(command, id, onStdout, onStderr)
    SSHClient-->>ContainerProvider: (exitCode, output)
    ContainerProvider->>ErrorHandler: Evaluate exitCode/output
    alt exitCode == 2
        ErrorHandler->>User: Emit sudoPasswordIncorrect
        ContainerProvider->>PasswordCache: Clear cache
    else
        ErrorHandler->>User: Return command result
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(container): Parsing results in sudo mode' accurately describes the main change in the PR, which focuses on fixing Docker command output parsing when Docker is accessed via sudo.
Linked Issues check ✅ Passed The PR addresses issue #969 by implementing sudo password handling, non-interactive password-based command execution, stderr filtering, and improved error detection for Docker commands in sudo mode.
Out of Scope Changes check ✅ Passed All changes are within scope: core sudo/password handling, localization strings, error types, and contributor credits. The only potentially tangential change is adding contributors to GithubIds, which appears to be a minor credit update.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f19516e and 1e657f4.

📒 Files selected for processing (2)
  • lib/data/provider/container.dart
  • lib/data/res/github_id.dart
🧰 Additional context used
📓 Path-based instructions (1)
lib/data/provider/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

Organize Riverpod providers by feature under lib/data/provider/

Files:

  • lib/data/provider/container.dart
🧠 Learnings (5)
📓 Common learnings
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 1031
File: lib/data/provider/container.dart:360-363
Timestamp: 2026-01-29T08:50:01.572Z
Learning: In lib/data/provider/container.dart's _buildSudoCmd function, do NOT use shell-level stderr redirect (2>/dev/null) when piping password to sudo -S. Shell-level suppression would discard stderr before the SSH client captures it, breaking the onStderr callback in execWithPwd that detects sudo password errors (e.g., "Sorry, try again.") and Podman emulation messages. Instead, use the layered approach: keep stderr flowing at shell level, capture it via onStderr callback at SSH level, and filter it from the returned result using stderr: false at application level in execWithPwd.
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-22T05:10:54.502Z
Learning: For all future pull requests in the flutter_server_box repository, check if participants from issues resolved by the PR are added to the `participants` field in `lib/data/res/github_id.dart`. If any participants are missing, propose adding them. First verify if they already exist or have been added in the PR commits.
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.
📚 Learning: 2026-01-29T08:50:01.572Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 1031
File: lib/data/provider/container.dart:360-363
Timestamp: 2026-01-29T08:50:01.572Z
Learning: In lib/data/provider/container.dart, within the _buildSudoCmd function, do not redirect stderr at the shell level (e.g., 2>/dev/null) when piping the password to sudo -S. Shell-level suppression can swallow stderr before the SSH client receives it, breaking onStderr callbacks in execWithPwd that detect sudo password errors (such as "Sorry, try again.") and Podman emulation messages. Instead, preserve the shell's stderr, receive it via the SSH-level onStderr callback, and filter it from the final result at the application level by using stderr: false in execWithPwd.

Applied to files:

  • lib/data/provider/container.dart
📚 Learning: 2026-01-17T04:24:16.501Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.

Applied to files:

  • lib/data/provider/container.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/data/model/container/**/*.dart : Place container/Docker models under lib/data/model/container/

Applied to files:

  • lib/data/provider/container.dart
📚 Learning: 2026-01-22T05:10:54.502Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-22T05:10:54.502Z
Learning: For all future pull requests in the flutter_server_box repository, check if participants from issues resolved by the PR are added to the `participants` field in `lib/data/res/github_id.dart`. If any participants are missing, propose adding them. First verify if they already exist or have been added in the PR commits.

Applied to files:

  • lib/data/res/github_id.dart
🔇 Additional comments (8)
lib/data/res/github_id.dart (1)

141-143: LGTM!

New participants added to acknowledge contributors from issue #969. The entries follow the existing naming convention and format.

lib/data/provider/container.dart (7)

40-63: LGTM!

The password caching implementation is well-structured:

  • Caches password to avoid repeated prompts within a session
  • Properly handles unmounted context
  • Only stores non-empty passwords

The cached password is correctly cleared on authentication failures (lines 154 and 349), addressing the earlier concern about sticky bad cache.


100-114: LGTM!

Clean early-exit pattern when sudo password is required but not provided. The error state with sudoPasswordRequired gives clear feedback to the user.


152-160: LGTM!

Proper handling of sudo password errors: clears the cached password on exit code 2 and sets a specific error type. This prevents the previously flagged issue of being stuck with an invalid cached password.


121-132: LGTM!

The stderr handling correctly implements the layered approach from project learnings:

  • Shell level: No stderr suppression (preserves error detection)
  • SSH level: onStderr callback captures Podman emulation detection
  • Application level: execWithPwd filters stderr from returned result

This design allows both clean parsing output and reliable error detection.


320-359: LGTM!

The run() method now properly handles sudo password scenarios:

  • Obtains password when needed with appropriate error on failure
  • Clears cached password on exit code 2 (incorrect password)
  • Returns specific error type for sudo authentication failures

This addresses the previously raised concern about sticky bad cache in the run path.


376-379: LGTM!

The _buildSudoCmd helper correctly avoids shell-level stderr suppression, as per project learnings. This preserves stderr flow for the SSH-level onStderr callback to detect sudo password errors and Podman emulation messages.


390-409: LGTM!

Clean refactoring: exec() now focuses solely on building individual container commands, delegating sudo/password handling to execAll(). This separation of concerns improves maintainability.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

@gemini-code-assist
Copy link

Summary of Changes

Hello @GT-610, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the application's ability to interact with container runtimes (Docker, Podman) when elevated privileges via sudo are necessary. The changes focus on improving the reliability of command execution and output parsing, providing more precise error feedback for sudo authentication, and streamlining the user experience by caching passwords and preventing output contamination from stderr messages.

Highlights

  • Sudo Mode Logic Rewrite: The entire logic for parsing outputs when accessing Docker/Podman through sudo has been rewritten to address issues with Docker parsing errors, especially in environments like Snap or when Docker is not directly accessible by the current user.
  • Improved Sudo Password Handling: The application now uses a more robust method for handling sudo passwords. Instead of interactive prompts, passwords are base64 encoded and piped to sudo -S via stdin. This prevents sudo password prompts from interfering with command output parsing.
  • Specific Sudo Error Reporting: New error types (sudoPasswordRequired, sudoPasswordIncorrect) have been introduced to provide clearer feedback to the user regarding sudo authentication failures. The execWithPwd method now returns a specific exit code (2) for incorrect sudo passwords.
  • Sudo Password Caching: A mechanism to cache the sudo password has been added, reducing the need for repeated password prompts during a session.
  • Streamlined Command Output Parsing: The exec method now explicitly captures only stdout for command results, ignoring stderr. This ensures that sudo prompts or other stderr messages do not corrupt the expected command output, simplifying parsing.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
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: 2

🤖 Fix all issues with AI agents
In `@lib/data/provider/container.dart`:
- Around line 139-143: When handling the sudo-password incorrect case in the
error branch that checks for exit code 2 (where state is set with
ContainerErr(type: ContainerErrType.sudoPasswordIncorrect)), also clear the
cached password so subsequent calls to _getSudoPassword() don't return the
invalid value; locate the block around the exit code check in container.dart and
set _cachedPassword to null (or empty) before returning, leaving the
state.copyWith(...) line as-is so the error is still reported.
- Around line 134-137: The execWithPwd helper currently calls exec(...) with
stderr: false so error messages from Docker/Podman end up excluded and the
container-not-found checks (e.g., raw.contains(_dockerNotFound) in the container
state update and the 'podman: not found' check) can miss stderr-only messages;
update the exec(...) call inside execWithPwd to set stderr: true so both stdout
and stderr are captured and the existing ContainerErr detection logic in the
container.dart functions will work reliably. Ensure the returned raw string used
by the checks still concatenates both streams if exec returns separate values.
🧹 Nitpick comments (2)
lib/core/extension/ssh_client.dart (1)

138-144: Remove unnecessary async keyword from callback.

The onStderr callback is marked async but contains no await expressions. This adds unnecessary overhead and can be simplified.

♻️ Suggested fix
-      onStderr: (data, session) async { // stderr is in `data`
+      onStderr: (data, session) {
         onStderr?.call(data, session);
         if (data.contains('Sorry, try again.') ||
             data.contains('incorrect password attempt')) {
           hasPasswordError = true;
         }
       },
lib/data/provider/container.dart (1)

312-316: Dead code: else if (needSudo) branch is unreachable.

If needSudo is true and password is null, the function returns early at lines 307-309. Therefore, the else if (needSudo) branch at line 314 can never execute.

♻️ Proposed fix
-    if (needSudo && password != null) {
+    if (needSudo) {
+      // password is guaranteed non-null here due to early return above
       cmd = _buildSudoCmd(cmd, password);
-    } else if (needSudo) {
-      cmd = 'sudo -S $cmd';
     }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a0a62ac and 34191e9.

⛔ Files ignored due to path filters (13)
  • lib/generated/l10n/l10n.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_de.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_en.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_es.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_fr.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_id.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_ja.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_nl.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_pt.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_ru.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_tr.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_uk.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_zh.dart is excluded by !**/generated/**
📒 Files selected for processing (5)
  • lib/core/extension/ssh_client.dart
  • lib/data/model/app/error.dart
  • lib/data/provider/container.dart
  • lib/l10n/app_en.arb
  • lib/l10n/app_zh.arb
🧰 Additional context used
📓 Path-based instructions (3)
lib/data/model/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

After modifying annotated model files, run: dart run build_runner build --delete-conflicting-outputs

Files:

  • lib/data/model/app/error.dart
lib/l10n/**/*.arb

📄 CodeRabbit inference engine (CLAUDE.md)

lib/l10n/**/*.arb: After modifying ARB files, run: flutter gen-l10n to regenerate localization
Keep localized strings in ARB files under lib/l10n/ (Flutter i18n)

Files:

  • lib/l10n/app_en.arb
  • lib/l10n/app_zh.arb
lib/data/provider/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

Organize Riverpod providers by feature under lib/data/provider/

Files:

  • lib/data/provider/container.dart
🧠 Learnings (4)
📓 Common learnings
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/data/model/container/**/*.dart : Place container/Docker models under lib/data/model/container/

Applied to files:

  • lib/data/model/app/error.dart
  • lib/data/provider/container.dart
📚 Learning: 2026-01-17T04:24:16.501Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.

Applied to files:

  • lib/data/model/app/error.dart
  • lib/data/provider/container.dart
  • lib/core/extension/ssh_client.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/data/model/ssh/**/*.dart : Place SSH models under lib/data/model/ssh/

Applied to files:

  • lib/core/extension/ssh_client.dart
🔇 Additional comments (6)
lib/data/model/app/error.dart (1)

30-31: LGTM!

The new enum variants sudoPasswordRequired and sudoPasswordIncorrect properly extend the error type system for sudo password handling. They align with the corresponding localization keys and error handling in container.dart.

lib/l10n/app_en.arb (1)

61-62: LGTM!

The new localization strings are clear and provide helpful guidance to users encountering sudo password prompts.

Remember to run flutter gen-l10n to regenerate localization files after merging. As per coding guidelines: "After modifying ARB files, run: flutter gen-l10n to regenerate localization".

lib/l10n/app_zh.arb (1)

61-62: LGTM!

Chinese translations are accurate and maintain localization parity with the English strings.

lib/core/extension/ssh_client.dart (1)

111-154: LGTM - Well-documented new method.

The execWithPwd method is well-designed with clear documentation explaining the exit codes and stderr handling rationale. The password error detection via stderr inspection is a good approach for non-interactive sudo usage.

lib/data/provider/container.dart (2)

351-354: LGTM - Secure password piping approach.

Using base64 encoding to pipe the password into sudo -S is a reasonable approach for non-interactive sudo usage. While the base64-encoded password is visible in process listings, this is a common and accepted pattern that avoids plain-text passwords in command arguments.


53-63: LGTM - Password caching implementation.

The password caching approach with null-check and dialog prompt is well-structured. It correctly handles the empty string case by only caching non-empty passwords.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the logic for executing commands with sudo, which is a great improvement for handling Docker access in various environments. The new approach of piping the password to sudo -S is more robust and less prone to parsing errors.

I've identified a couple of areas for improvement. One is a minor issue regarding an unused parameter in execPowerShell which could cause confusion. The other is a more significant regression where error details from stderr are no longer being captured, which can make debugging failed commands difficult. Please see my detailed comments.

Copy link
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: 2

🤖 Fix all issues with AI agents
In `@lib/core/extension/ssh_client.dart`:
- Around line 111-122: The doc comment for the method that calls exec()
incorrectly states "[stderr: false] ensures only stdout...", but the exec()
invocation (exec()) does not pass stderr:false and therefore includes stderr by
default; update the method's documentation to state that stderr is included in
the returned output (exec defaults to stderr:true) and that stderr is used for
error detection, or alternatively change the exec() call to explicitly pass
stderr:false if the intent is to exclude stderr—reference the exec() call in
this method when making the change.

In `@lib/data/provider/container.dart`:
- Around line 350-353: The current _buildSudoCmd returns a shell string that
discards stderr (2>/dev/null), which hides errors like "docker: not found" and
breaks detection in execWithPwd and the checks against _dockerNotFound and
'podman: not found'; update _buildSudoCmd to pipe the base64 password as before
but redirect stderr into stdout (e.g., use 2>&1) instead of discarding so stderr
messages are captured in SSH output for detection while still relying on
execWithPwd's exit-code/password handling to avoid interactive prompts.
🧹 Nitpick comments (3)
lib/core/extension/ssh_client.dart (1)

138-143: Remove unnecessary async keyword from callback.

The onStderr callback is marked async but contains no await expressions. This is harmless but misleading.

♻️ Proposed fix
-      onStderr: (data, session) async { // stderr is in `data`
+      onStderr: (data, session) { // stderr is in `data`
         onStderr?.call(data, session);
         if (data.contains('Sorry, try again.') ||
             data.contains('incorrect password attempt')) {
           hasPasswordError = true;
         }
       },
lib/data/provider/container.dart (2)

318-331: Consider including actual error output in the error message.

When the command fails (code != 0), the error message is generic. The actual output from the command (captured in the discarded _ variable at line 318) could provide useful debugging information for users.

♻️ Proposed fix
-    final (code, _) = await client!.execWithPwd(
+    final (code, output) = await client!.execWithPwd(
       _wrap(cmd),
       context: context,
       onStdout: (data, _) {
         state = state.copyWith(runLog: '${state.runLog}$data');
       },
       id: hostId,
     );

     state = state.copyWith(runLog: null);

     if (code != 0) {
-      return ContainerErr(type: ContainerErrType.unknown, message: 'Command execution failed');
+      return ContainerErr(type: ContainerErrType.unknown, message: output.isNotEmpty ? output : 'Command execution failed');
     }

382-388: Optional: Improve defensive programming for exec() method.

The sudo -S $baseCmd fallback on line 386 can only be reached if sudo=true and password=null. While current callers (refresh() on line 115 and the one direct call on line 79) validate that password is non-null when sudo is required, this creates implicit coupling.

Consider either:

  1. Making password non-nullable when sudo is true (e.g., required String password if sudo=true)
  2. Throwing an error instead of the sudo -S fallback, making the API contract explicit

This prevents accidental misuse if the method is called directly in the future.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34191e9 and 9d25f90.

📒 Files selected for processing (2)
  • lib/core/extension/ssh_client.dart
  • lib/data/provider/container.dart
🧰 Additional context used
📓 Path-based instructions (1)
lib/data/provider/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

Organize Riverpod providers by feature under lib/data/provider/

Files:

  • lib/data/provider/container.dart
🧠 Learnings (4)
📓 Common learnings
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.
📚 Learning: 2026-01-17T04:24:16.501Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.

Applied to files:

  • lib/core/extension/ssh_client.dart
  • lib/data/provider/container.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/data/model/ssh/**/*.dart : Place SSH models under lib/data/model/ssh/

Applied to files:

  • lib/core/extension/ssh_client.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/data/model/container/**/*.dart : Place container/Docker models under lib/data/model/container/

Applied to files:

  • lib/data/provider/container.dart
🔇 Additional comments (6)
lib/core/extension/ssh_client.dart (1)

46-47: LGTM!

Comment clarifies that stderr is intentionally excluded from the result in PowerShell execution, which aligns with the documented behavior.

lib/data/provider/container.dart (5)

40-40: LGTM!

Password caching field introduced to avoid repeated prompts during a session.


53-63: LGTM!

The _getSudoPassword method properly checks for mounted context before showing dialog and caches the password only when non-empty.


100-111: LGTM!

Good defensive handling: when sudo is required but password is not provided (user cancels dialog), the method returns early with an appropriate error state instead of proceeding with a null password.


139-144: LGTM!

Good fix: the cached password is now cleared when an incorrect password error is detected (exit code 2), allowing the user to retry with a correct password.


391-395: LGTM!

The execAll method properly passes through the password parameter to each individual exec call.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link
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: 2

🤖 Fix all issues with AI agents
In `@lib/data/provider/container.dart`:
- Around line 360-363: The _buildSudoCmd currently pipes a base64-decoded
password into sudo -S but doesn't suppress sudo's stderr prompt; update
_buildSudoCmd to append shell-level stderr redirection (e.g., 2>/dev/null) to
the returned command so the sudo prompt won't leak into captured stderr, and
modify the sudo+password sh-wrapper branch in execAll (the code path that builds
a shell wrapper when a password is provided) to call and reuse _buildSudoCmd
instead of duplicating logic so both paths get the same 2>/dev/null suppression;
ensure execWithPwd's stderr capture (raw) no longer receives the sudo prompt.
- Around line 406-424: The debug prints currently leak credentials by logging
the constructed sudo command that includes the base64-encoded password; in the
block that checks needsShWrapper and the branches using sudo && password != null
(referencing variables sudo, password, pwdBase64, cmd, and commands) remove or
redact any print/log lines that would output the full cmd containing the
password (and do the same for the analogous prints further down), or replace
them with a non-sensitive message such as indicating a sudo command was
constructed without including pwdBase64 or the raw command string.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d25f90 and 421b4e6.

📒 Files selected for processing (2)
  • lib/core/extension/ssh_client.dart
  • lib/data/provider/container.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/core/extension/ssh_client.dart
🧰 Additional context used
📓 Path-based instructions (1)
lib/data/provider/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

Organize Riverpod providers by feature under lib/data/provider/

Files:

  • lib/data/provider/container.dart
🧠 Learnings (4)
📓 Common learnings
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 1031
File: lib/data/provider/container.dart:350-353
Timestamp: 2026-01-28T16:13:47.416Z
Learning: In lib/data/provider/container.dart's _buildSudoCmd function, using shell-level stderr redirect (2>/dev/null) when piping password to sudo -S does not break Docker/Podman "not installed" detection because the detection primarily relies on exit code 127 (command not found) rather than stderr messages. The 2>/dev/null is necessary to suppress sudo password prompts that would otherwise contaminate stdout and cause parsing failures.
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.
📚 Learning: 2026-01-28T16:13:47.416Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 1031
File: lib/data/provider/container.dart:350-353
Timestamp: 2026-01-28T16:13:47.416Z
Learning: In lib/data/provider/container.dart, for the _buildSudoCmd function, use shell-level stderr redirection (2>/dev/null) when piping a password to sudo -S to suppress password prompts that could pollute stdout and break parsing. This detection relies on the exit code (e.g., 127 for command not found) rather than stderr messages, so redirecting stderr helps maintain reliable stdout parsing. Ensure this change does not alter the actual exit codes and that error handling remains correct.

Applied to files:

  • lib/data/provider/container.dart
📚 Learning: 2026-01-17T04:24:16.501Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.

Applied to files:

  • lib/data/provider/container.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/data/model/container/**/*.dart : Place container/Docker models under lib/data/model/container/

Applied to files:

  • lib/data/provider/container.dart

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Add support for sudo password verification for Docker container operations, including:
1. Added ContainerErrType.sudoPasswordRequired error type
2. Add password prompt text in multi-language files
3. Modify the SSH execution logic to correctly handle the input of sudo password
4. Implement password caching and verification mechanism
Add a new error type `sudoPasswordIncorrect` to handle situations where the sudo password is incorrect

Modify the password verification logic in the SSH client, and return a specific error code when a password error is detected

Update multilingual files to support password error prompt information
…d handling

Clean up the no longer needed stderr parameter in the SSH client, which was originally used to handle sudo password prompts

Unify the sudo command construction logic, always use the _buildSudoCmd method, and add stderr redirection
Clear cached passwords when passwords are incorrect
…detection

Fix the sudo command processing logic, remove the masking of stderr to capture password errors

Override the detection logic simulated by Podman

Refactor the command building logic to support sh wrapping of multi-line commands
Update the sudo password error prompt messages for all languages to more accurately reflect situations of incorrect password or lack of permission

Fix the password error detection logic for both the SSH client and container providers simultaneously
@GT-610 GT-610 force-pushed the fix/container/sudo-parsing branch from 421b4e6 to 0d80cd8 Compare January 29, 2026 09:29
Copy link
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: 1

🤖 Fix all issues with AI agents
In `@lib/data/provider/container.dart`:
- Around line 404-406: The branch that returns 'sudo -S $baseCmd' when sudo is
true can hang if password is null; update the code where that branch lives (the
method that constructs the command containing "if (sudo) { return 'sudo -S
$baseCmd'; }") to validate state: if sudo is true but password is null/empty,
throw an ArgumentError or assert (or otherwise fail fast) rather than returning
a sudo command that expects stdin; keep callers exec(), execAll(), refresh(),
and run() assumptions intact but enforce the invariant here so the API cannot
produce a hanging sudo invocation.
🧹 Nitpick comments (2)
lib/core/extension/ssh_client.dart (1)

141-144: Password detection strings may be locale-dependent.

The detection relies on English error messages from sudo ("Sorry, try again.", "incorrect password attempt", "a password is required"). On systems with non-English locales configured, sudo may output localized error messages, causing detection to fail silently.

Consider adding a note in documentation about this limitation, or explore detecting patterns that are more universal (e.g., checking exit codes combined with stderr presence).

lib/data/provider/container.dart (1)

415-439: Unreachable code and duplicated logic.

  1. Dead code (lines 431-439): Since ContainerCmdType.values always has 4 enum values, commands will always contain \necho ${ScriptConstants.separator}\n. This means needsShWrapper is always true, making the non-wrapper branches unreachable.

  2. Duplicated logic (lines 419-420): The base64 encoding logic is duplicated from _buildSudoCmd().

♻️ Proposed refactor
 static String execAll(ContainerType type, {bool sudo = false, bool includeStats = false, String? password}) {
   final commands = ContainerCmdType.values
       .map((e) => e.exec(type, sudo: false, includeStats: includeStats))
       .join('\necho ${ScriptConstants.separator}\n');

-  final needsShWrapper = commands.contains('\n') || commands.contains('echo ${ScriptConstants.separator}');
-
-  if (needsShWrapper) {
-    if (sudo && password != null) {
-      final pwdBase64 = base64Encode(utf8.encode(password));
-      final cmd = 'echo "$pwdBase64" | base64 -d | sudo -S sh -c \'${commands.replaceAll("'", "'\\''")}\'';
-      return cmd;
-    }
-    if (sudo) {
-      final cmd = 'sudo -S sh -c \'${commands.replaceAll("'", "'\\''")}\'';
-      return cmd;
-    }
-    final cmd = 'sh -c \'${commands.replaceAll("'", "'\\''")}\'';
-    return cmd;
-  }
-
-  if (sudo && password != null) {
-    final cmd = _buildSudoCmd(commands, password);
-    return cmd;
-  }
-  if (sudo) {
-    final cmd = 'sudo -S $commands';
-    return cmd;
-  }
-  return commands;
+  final wrappedCommands = 'sh -c \'${commands.replaceAll("'", "'\\''")}\'';
+  
+  if (sudo && password != null) {
+    return _buildSudoCmd(wrappedCommands, password);
+  }
+  if (sudo) {
+    return 'sudo -S $wrappedCommands';
+  }
+  return wrappedCommands;
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 421b4e6 and 0d80cd8.

⛔ Files ignored due to path filters (13)
  • lib/generated/l10n/l10n.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_de.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_en.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_es.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_fr.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_id.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_ja.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_nl.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_pt.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_ru.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_tr.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_uk.dart is excluded by !**/generated/**
  • lib/generated/l10n/l10n_zh.dart is excluded by !**/generated/**
📒 Files selected for processing (16)
  • lib/core/extension/ssh_client.dart
  • lib/data/model/app/error.dart
  • lib/data/provider/container.dart
  • lib/l10n/app_de.arb
  • lib/l10n/app_en.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_fr.arb
  • lib/l10n/app_id.arb
  • lib/l10n/app_ja.arb
  • lib/l10n/app_nl.arb
  • lib/l10n/app_pt.arb
  • lib/l10n/app_ru.arb
  • lib/l10n/app_tr.arb
  • lib/l10n/app_uk.arb
  • lib/l10n/app_zh.arb
  • lib/l10n/app_zh_tw.arb
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/l10n/app_zh.arb
  • lib/data/model/app/error.dart
🧰 Additional context used
📓 Path-based instructions (2)
lib/l10n/**/*.arb

📄 CodeRabbit inference engine (CLAUDE.md)

lib/l10n/**/*.arb: After modifying ARB files, run: flutter gen-l10n to regenerate localization
Keep localized strings in ARB files under lib/l10n/ (Flutter i18n)

Files:

  • lib/l10n/app_es.arb
  • lib/l10n/app_fr.arb
  • lib/l10n/app_ru.arb
  • lib/l10n/app_de.arb
  • lib/l10n/app_id.arb
  • lib/l10n/app_pt.arb
  • lib/l10n/app_tr.arb
  • lib/l10n/app_ja.arb
  • lib/l10n/app_nl.arb
  • lib/l10n/app_uk.arb
  • lib/l10n/app_zh_tw.arb
  • lib/l10n/app_en.arb
lib/data/provider/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

Organize Riverpod providers by feature under lib/data/provider/

Files:

  • lib/data/provider/container.dart
🧠 Learnings (7)
📓 Common learnings
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 1031
File: lib/data/provider/container.dart:360-363
Timestamp: 2026-01-29T08:50:01.572Z
Learning: In lib/data/provider/container.dart's _buildSudoCmd function, do NOT use shell-level stderr redirect (2>/dev/null) when piping password to sudo -S. Shell-level suppression would discard stderr before the SSH client captures it, breaking the onStderr callback in execWithPwd that detects sudo password errors (e.g., "Sorry, try again.") and Podman emulation messages. Instead, use the layered approach: keep stderr flowing at shell level, capture it via onStderr callback at SSH level, and filter it from the returned result using stderr: false at application level in execWithPwd.
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.
📚 Learning: 2026-01-29T08:50:01.572Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 1031
File: lib/data/provider/container.dart:360-363
Timestamp: 2026-01-29T08:50:01.572Z
Learning: In lib/data/provider/container.dart's _buildSudoCmd function, do NOT use shell-level stderr redirect (2>/dev/null) when piping password to sudo -S. Shell-level suppression would discard stderr before the SSH client captures it, breaking the onStderr callback in execWithPwd that detects sudo password errors (e.g., "Sorry, try again.") and Podman emulation messages. Instead, use the layered approach: keep stderr flowing at shell level, capture it via onStderr callback at SSH level, and filter it from the returned result using stderr: false at application level in execWithPwd.

Applied to files:

  • lib/l10n/app_es.arb
  • lib/l10n/app_de.arb
  • lib/core/extension/ssh_client.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/l10n/**/*.arb : Keep localized strings in ARB files under lib/l10n/ (Flutter i18n)

Applied to files:

  • lib/l10n/app_fr.arb
  • lib/l10n/app_id.arb
  • lib/l10n/app_en.arb
📚 Learning: 2026-01-17T04:24:16.501Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.

Applied to files:

  • lib/core/extension/ssh_client.dart
  • lib/data/provider/container.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/data/model/ssh/**/*.dart : Place SSH models under lib/data/model/ssh/

Applied to files:

  • lib/core/extension/ssh_client.dart
📚 Learning: 2026-01-29T08:50:01.572Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 1031
File: lib/data/provider/container.dart:360-363
Timestamp: 2026-01-29T08:50:01.572Z
Learning: In lib/data/provider/container.dart, within the _buildSudoCmd function, do not redirect stderr at the shell level (e.g., 2>/dev/null) when piping the password to sudo -S. Shell-level suppression can swallow stderr before the SSH client receives it, breaking onStderr callbacks in execWithPwd that detect sudo password errors (such as "Sorry, try again.") and Podman emulation messages. Instead, preserve the shell's stderr, receive it via the SSH-level onStderr callback, and filter it from the final result at the application level by using stderr: false in execWithPwd.

Applied to files:

  • lib/data/provider/container.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/data/model/container/**/*.dart : Place container/Docker models under lib/data/model/container/

Applied to files:

  • lib/data/provider/container.dart
🔇 Additional comments (15)
lib/l10n/app_id.arb (1)

60-61: Run localization generation after ARB updates.

Please run flutter gen-l10n so generated localization files pick up the new keys.
As per coding guidelines: After modifying ARB files, run: flutter gen-l10n to regenerate localization.

lib/core/extension/ssh_client.dart (3)

46-46: LGTM!

Clear comment explaining the intentional exclusion of stderr from the combined result in execPowerShell.


111-123: LGTM - Documentation accurately describes the layered stderr handling.

The documentation now correctly explains the layered approach: stderr is captured via onStderr callback for password error detection, while being excluded from the returned output via stderr: false. This aligns with the project's established pattern for sudo password error detection.


132-155: LGTM - Password error detection and exit code handling.

The implementation correctly:

  1. Uses hasPasswordError flag set via onStderr callback
  2. Passes stderr: false to exclude stderr from returned output (while still capturing via callback)
  3. Returns exit code 2 for password errors as documented

This follows the layered approach from project learnings.

lib/l10n/app_ru.arb (1)

61-62: LGTM - Russian translations added correctly.

The new localization keys containerSudoPasswordRequired and containerSudoPasswordIncorrect are properly added with appropriate Russian translations. As per coding guidelines, remember to run flutter gen-l10n to regenerate localization after modifying ARB files.

lib/l10n/app_es.arb (1)

60-61: LGTM - Spanish translations added correctly.

The localization keys are properly added with appropriate Spanish translations.

lib/l10n/app_ja.arb (1)

60-61: LGTM - Japanese translations added correctly.

The localization keys are properly added with appropriate Japanese translations.

lib/l10n/app_de.arb (1)

61-62: LGTM - German translations added correctly.

The localization keys are properly added with appropriate German translations.

lib/l10n/app_fr.arb (1)

60-61: LGTM - French translations added correctly.

The localization keys are properly added with appropriate French translations.

lib/l10n/app_en.arb (1)

61-62: LGTM!

New localization keys containerSudoPasswordRequired and containerSudoPasswordIncorrect are well-named and provide clear, actionable messages for users.

As per coding guidelines: Remember to run flutter gen-l10n to regenerate localization files after this change.

lib/data/provider/container.dart (5)

53-63: LGTM!

The password caching implementation correctly:

  • Returns cached password if available
  • Checks context.mounted before showing dialog
  • Only caches non-null, non-empty passwords

100-114: LGTM!

The password acquisition flow properly handles the case where sudo is required but no password is provided, setting an appropriate error state and returning early.


152-160: LGTM!

Password cache is correctly cleared on authentication failure, and the error state is properly set with a localized message.

Note: Exit code 2 for sudo password failures is common but not guaranteed across all systems/configurations. The current approach should work for most environments.


320-344: LGTM!

The run() method consistently handles sudo password acquisition and command construction using the shared _buildSudoCmd helper.


369-372: LGTM!

The _buildSudoCmd helper correctly:

  • Uses base64 encoding to safely pass passwords containing special characters
  • Does not suppress stderr, allowing the onStderr callback to capture sudo errors and Podman emulation messages

Based on learnings: This layered approach (shell → SSH → application) ensures error detection works correctly.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

…ec method

Simplify the exec method signature by removing the sudo and password parameters that are no longer needed, as these functions are no longer in use
Copy link
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: 1

🤖 Fix all issues with AI agents
In `@lib/data/provider/container.dart`:
- Around line 320-350: The run() path must detect execWithPwd returning exit
code 2 as a sudo-password failure: if (code == 2) clear the cached sudo
credential (reset/complete sudoCompleter or call the existing helper that clears
stored sudo password), set state.runLog back to null, and return a ContainerErr
that specifically signals a sudo/password problem (use
ContainerErrType.sudoPasswordRequired and a localized message such as
l10n.containerSudoPasswordIncorrect or similar) so the bad cached password is
discarded and a clear error is surfaced instead of the generic unknown error.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d80cd8 and f19516e.

📒 Files selected for processing (1)
  • lib/data/provider/container.dart
🧰 Additional context used
📓 Path-based instructions (1)
lib/data/provider/**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

Organize Riverpod providers by feature under lib/data/provider/

Files:

  • lib/data/provider/container.dart
🧠 Learnings (4)
📓 Common learnings
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 1031
File: lib/data/provider/container.dart:360-363
Timestamp: 2026-01-29T08:50:01.572Z
Learning: In lib/data/provider/container.dart's _buildSudoCmd function, do NOT use shell-level stderr redirect (2>/dev/null) when piping password to sudo -S. Shell-level suppression would discard stderr before the SSH client captures it, breaking the onStderr callback in execWithPwd that detects sudo password errors (e.g., "Sorry, try again.") and Podman emulation messages. Instead, use the layered approach: keep stderr flowing at shell level, capture it via onStderr callback at SSH level, and filter it from the returned result using stderr: false at application level in execWithPwd.
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.
📚 Learning: 2026-01-29T08:50:01.572Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 1031
File: lib/data/provider/container.dart:360-363
Timestamp: 2026-01-29T08:50:01.572Z
Learning: In lib/data/provider/container.dart, within the _buildSudoCmd function, do not redirect stderr at the shell level (e.g., 2>/dev/null) when piping the password to sudo -S. Shell-level suppression can swallow stderr before the SSH client receives it, breaking onStderr callbacks in execWithPwd that detect sudo password errors (such as "Sorry, try again.") and Podman emulation messages. Instead, preserve the shell's stderr, receive it via the SSH-level onStderr callback, and filter it from the final result at the application level by using stderr: false in execWithPwd.

Applied to files:

  • lib/data/provider/container.dart
📚 Learning: 2026-01-17T04:24:16.501Z
Learnt from: GT-610
Repo: lollipopkit/flutter_server_box PR: 0
File: :0-0
Timestamp: 2026-01-17T04:24:16.501Z
Learning: In lib/core/extension/ssh_client.dart and lib/data/provider/container.dart, when executing Docker/Podman commands via SSH, stderr must be included in the output (not set to stderr: false) because the error detection logic relies on stderr messages like "command not found" to properly detect when Docker/Podman is not installed and display appropriate error prompts to users.

Applied to files:

  • lib/data/provider/container.dart
📚 Learning: 2025-10-08T09:36:41.682Z
Learnt from: CR
Repo: lollipopkit/flutter_server_box PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-08T09:36:41.682Z
Learning: Applies to lib/data/model/container/**/*.dart : Place container/Docker models under lib/data/model/container/

Applied to files:

  • lib/data/provider/container.dart
🔇 Additional comments (7)
lib/data/provider/container.dart (7)

40-63: Good password caching + mounted guard.

This avoids repeated prompts and safely skips dialog display when the context is no longer active.


100-115: Graceful sudo-password requirement handling.

The early return with a clear error state keeps refresh behavior predictable.


118-133: stderr hook for Podman emulation looks solid.

Capturing emulation signals via onStderr without mixing it into parsing output is a clean approach.


147-176: Clear error mapping for not-installed / sudo password / podman emulation.

The updated error branches are straightforward and reduce ambiguity for the UI.


369-372: LGTM: no shell-level stderr suppression in _buildSudoCmd.

This preserves SSH-level stderr handling for sudo-related diagnostics. Based on learnings: In lib/data/provider/container.dart's _buildSudoCmd function, do NOT use shell-level stderr redirect (2>/dev/null) when piping password to sudo -S; keep stderr flowing and filter at the SSH/application level.


383-401: Simplified exec() base command construction looks good.

The streamlined signature is clear and keeps command generation focused.


404-434: Password-aware execAll() construction is consistent.

The sudo + password handling across wrapper and non-wrapper paths is clear and readable.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Add two new contributors to the GithubIds list and refactor the container command processing logic:
1. Simplify the command wrapping logic and uniformly use `sh -c` for processing
2. Specific error handling when adding a sudo password incorrectly
3. Remove redundant conditional checks and temporary variables
@GT-610 GT-610 merged commit 9281a57 into lollipopkit:main Jan 29, 2026
2 checks passed
@GT-610 GT-610 deleted the fix/container/sudo-parsing branch January 29, 2026 10:07
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.

snap安装的docker无法读取,有时候能读到版本号,但是具体内容读不出来

1 participant