Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entirely Internal Connection #1610

Merged
merged 10 commits into from
Dec 23, 2024
Merged

Conversation

oneirocosm
Copy link
Member

This change allows the user to specify all connection details in an internal connection rather than forcing them to rely on the ssh config for certain keywords.

Copy link
Contributor

coderabbitai bot commented Dec 23, 2024

Walkthrough

This pull request introduces several modifications across multiple files to enhance SSH connection handling and configuration management. The changes primarily focus on improving flexibility and robustness in SSH-related functionality.

Key modifications include the addition of a new optional property "conn:overrideconfig" of type boolean in the ConnKeywords type declaration, updates to the connutil.go file that simplify port handling and improve error management, and enhancements in the sshclient.go file with new utility functions for safer pointer dereferencing. Additionally, various SSH configuration parameters in the ConnKeywords struct have been changed to pointer types, allowing for nullable values.

The modifications span four files: frontend/types/gotypes.d.ts, pkg/remote/connutil.go, pkg/remote/sshclient.go, and pkg/wshrpc/wshrpctypes.go, with each file receiving targeted updates to support more dynamic and flexible SSH connection configurations.

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 0

🧹 Nitpick comments (1)
pkg/remote/sshclient.go (1)

882-933: mergeKeywords function is comprehensive.
Each pointer-based SSH field is replaced if non-nil. The function is consistent, though consider also reviewing ConnOverrideConfig if relevant here.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dbacae8 and 23223d5.

📒 Files selected for processing (4)
  • frontend/types/gotypes.d.ts (1 hunks)
  • pkg/remote/connutil.go (2 hunks)
  • pkg/remote/sshclient.go (15 hunks)
  • pkg/wshrpc/wshrpctypes.go (2 hunks)
🔇 Additional comments (22)
pkg/remote/sshclient.go (16)

156-156: Validate agent availability with caution.
Ensuring that keys are only added to the SSH agent when it is genuinely available can help avoid unintended errors or security risks.


170-170: Confirm default behavior for batch mode.
Relying on the default value from safeDeref is good, but confirm the fallback logic if the user explicitly sets an unexpected value for SshBatchMode.


199-199: Same key-adding pattern as at line 156.
This code repeats the logic for adding keys to the SSH agent. Make sure to keep both in sync if logic changes.


555-561: safeDeref utility is well-implemented.
This approach neatly avoids nil pointer dereferences by returning a zero value when pointers are nil.


562-565: ptr utility for generic pointer creation.
This straightforward function is useful for succinct pointer creation, especially for complex struct fields.


596-598: Appropriate conditional logic for SSH authentication methods.
Tying pubkey, password, and keyboard-interactive authentication to batch mode and booleans is a valid approach.


665-671: Parsed SSH user/port from opts.
This is a clear approach: only set fields when non-empty, preventing unintended overrides.


674-675: Reading full config for internal SSH keywords.
No concurrency or error checks are performed, but it may be acceptable if fullConfig is guaranteed.


677-677: Initialize empty config if not found.
Creating a new ConnKeywords struct is a safe fallback.


680-684: Merging internal config conditionally.
The approach of only merging config when ConnOverrideConfig is true is consistent with user expectations.


686-688: Sequential merging approach.
Merging flags into partialMerged and then parsedKeywords is straightforward for applying layered overrides.


689-696: Appending identity files.
The reversed order for appended identity files is intentional. Ensure this aligns with user expectations.


721-721: Same port-check concern as line 619.
See prior note about an empty or malformed SshPort leading to a trailing colon in the address.


575-575: Check empty SSH agent path.
When safeDeref(sshKeywords.SshIdentityAgent) is empty, net.Dial may fail. Ensure it’s caught gracefully.

✅ Verification successful

Let me verify how the empty SSH agent path is handled by examining the code context around this line.


Let me check the implementation of safeDeref with a different pattern since the previous one didn't yield results.


Empty SSH agent path is handled gracefully

The code already handles empty SSH agent path appropriately:

  1. safeDeref returns a zero value when the pointer is nil
  2. If net.Dial fails (due to empty path or any other reason), the error is logged and the code continues execution
  3. The authentication process falls back to other methods (public key, keyboard-interactive, password) as seen in the subsequent code
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Let's check the context around the net.Dial call and how safeDeref is implemented
rg -B 10 -A 10 'conn, err := net\.Dial\("unix", safeDeref\(sshKeywords\.SshIdentityAgent\)\)' pkg/remote/sshclient.go

Length of output: 1183


Script:

#!/bin/bash
# Let's also check the implementation of safeDeref
ast-grep --pattern 'func safeDeref($_) {
  $$$
}'

Length of output: 51


Script:

#!/bin/bash
# Let's see how sshKeywords.SshIdentityAgent is used elsewhere
rg "SshIdentityAgent" pkg/remote/sshclient.go

Length of output: 318


Script:

#!/bin/bash
# Let's find safeDeref implementation with a simpler pattern
rg -B 2 -A 5 "func safeDeref" pkg/remote/sshclient.go

Length of output: 152


Script:

#!/bin/bash
# Let's also see where the error from net.Dial is used in the function
rg -B 5 -A 10 "Failed to open Identity Agent Socket:" pkg/remote/sshclient.go

Length of output: 830


619-619: Ensure chosenPort is set.
If chosenPort is empty, networkAddr might become "hostname:". Verify that a default port is set elsewhere in the flow.

✅ Verification successful

Let me verify how chosenPort is handled by examining the code.


Let me check how sshKeywords.SshPort is handled and if there's a default value set.


Let me check one more thing to see how the SSH port is handled in the configuration and if there's a default port setting.


Port handling is properly implemented with fallback to default port 22

From the code analysis, I can confirm that the port handling is safe:

  1. The code shows that when SSHPort is empty or "22", it's handled gracefully in the String() method:
if opts.SSHPort != "22" && opts.SSHPort != "" {
    stringRepr = stringRepr + ":" + fmt.Sprint(opts.SSHPort)
}
  1. The port is obtained through SSH config using WaveSshConfigUserSettings().GetStrict(hostPattern, "Port"), which will return the standard SSH port 22 if not explicitly set.

  2. Even if chosenPort is empty in the network address formation (networkAddr := chosenHostName + ":" + chosenPort), the SSH client library will default to port 22, which is the standard SSH port.

Therefore, the original concern is not an issue as the SSH port handling is implemented with proper defaults.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# First, let's look at the file content around the usage of chosenPort
rg -B 10 -A 5 "chosenPort" pkg/remote/sshclient.go

# Also check where chosenPort is set or initialized
ast-grep --pattern 'chosenPort := $_'
ast-grep --pattern 'chosenPort = $_'

Length of output: 1789


Script:

#!/bin/bash
# Look for the definition of SshPort in the ConnKeywords struct
rg -B 5 -A 5 "type ConnKeywords struct" 

# Check for any default port assignments
rg -B 3 -A 3 "SshPort.*=.*"

# Look for the safeDeref function implementation
ast-grep --pattern 'func safeDeref($_) $_'

Length of output: 2004


Script:

#!/bin/bash
# Look for SSH default port definitions or configurations
rg -B 5 -A 5 "22" pkg/remote/sshclient.go

# Check for port validation or default port handling
rg -B 5 -A 5 "port" pkg/remote/sshclient.go --ignore-case

# Look for the complete struct definition to see SshPort field
rg -A 20 "SshPort.*\*string" 

Length of output: 6504


568-571: Verify behavior of non-numeric ports.
If SshPort contains a non-numeric or empty string, confirm if downstream usage handles it gracefully.

✅ Verification successful

Let me gather information about how the port value is used and validated in the codebase.


Let me search for more specific information about port handling and network connection establishment.


Let me check one final aspect - the actual network connection handling and any port validation that might occur in the Go SSH package usage.


Based on the gathered information, I can now provide a final response about the port handling behavior:

Non-numeric ports will cause connection failures at the network dial stage

The code shows that:

  • The port string is directly concatenated into the network address (networkAddr := chosenHostName + ":" + chosenPort)
  • This address is used in net.Dialer.DialContext(ctx, "tcp", networkAddr)
  • Invalid ports will fail at the TCP dial stage with standard Go network errors
  • The error is properly wrapped in a ConnectionError structure and propagated to the caller

The behavior is safe because:

  • Empty or non-numeric ports will fail early during TCP connection establishment
  • Errors are properly handled and propagated through the connection stack
  • No risk of undefined behavior or security issues
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for usages of SshPort and port validation
rg -A 5 "SshPort" 

# Search for usages of the remoteName variable to see how it's used downstream
rg "remoteName :=" 

# Look for any port validation or parsing functions
rg -A 5 "port.*validation|validatePort|parsePort"

# Search for xknownhosts.Normalize to understand its behavior with invalid ports
rg -A 5 "xknownhosts.Normalize"

Length of output: 4317


Script:

#!/bin/bash
# Look for the connectInternal function implementation to see how the port is used
ast-grep --pattern 'func connectInternal($$$) {
  $$$
}'

# Search for net.Dial usage to see how the network address is handled
rg -A 5 'net.Dial\('

# Look for the implementation of safeDeref function
ast-grep --pattern 'func safeDeref($$$) {
  $$$
}'

# Search for any error handling related to connection failures
rg -B 2 -A 5 'ConnectionError'

Length of output: 5663


Script:

#!/bin/bash
# Look for the actual SSH connection establishment
ast-grep --pattern 'func connectInternal($$$) {
  $$$
}'

# Search for any SSH dial or connection configuration
rg -B 2 -A 5 'ssh.Dial|ssh.Client'

# Look for any port-related error handling
rg -B 2 -A 5 'dial.*error|connection.*refused|invalid.*port'

Length of output: 6851

pkg/remote/connutil.go (1)

29-29: Port handling now directly relies on the regex capture.
Replacing integer conversion with a string-based approach simplifies parsing but verify that invalid ports (e.g., alphabetic) are handled as intended.

pkg/wshrpc/wshrpctypes.go (4)

464-464: Added ConnOverrideConfig field.
Allows ignoring or overwriting default configs if set to true. This is a useful extension for advanced connection scenarios.


474-476: Pointer-based approach for user, hostname, and port.
These fields elegantly support optional or unset values; safeDeref usage is consistent with these changes.


478-481: Pointer-based boolean fields for SSH authentication.
This design allows explicit differentiation between “false” and “unset.”


483-484: SshAddKeysToAgent and SshIdentityAgent as pointers.
Enables flexible control over agent usage. The new pointer type approach aligns with existing safeDeref patterns.

frontend/types/gotypes.d.ts (1)

293-293: New "conn:overrideconfig" field in ConnKeywords.
Ensures TypeScript type definitions mirror the new Go struct field for configuration overrides.

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: 0

🧹 Nitpick comments (3)
pkg/remote/sshclient.go (3)

564-564: Failure logging on IdentityAgent.
A log is printed if the socket isn't found. Consider including more context or ways to recover if the agent is essential.


663-664: Fetching fullConfig.
This is a straightforward config initialization. Suggest verifying presence of any newly introduced fields.


871-922: mergeKeywords function.
This merges new keyword pointers into an existing struct. The approach is correct; ensure references are not inadvertently shared.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 813e4fa and 68ed622.

📒 Files selected for processing (2)
  • pkg/remote/sshclient.go (16 hunks)
  • pkg/util/utilfn/utilfn.go (1 hunks)
🔇 Additional comments (31)
pkg/util/utilfn/utilfn.go (2)

945-956: Ensure thorough test coverage for SafeDeref.
The new SafeDeref function is well-defined for generic pointer safety. However, consider unit tests for corner cases, such as nil pointers, zero values, and reference types.


958-966: Ptr function is concise and clear.
This utility cleanly creates pointers without requiring intermediate variables. Good addition for improved readability and maintainability.

pkg/remote/sshclient.go (29)

30-30: Import addition seems appropriate.
Importing “github.com/wavetermdev/waveterm/pkg/util/utilfn” expands utility usage. Ensure there are no cyclical dependencies.


157-157: Use of SafeDeref for SshAddKeysToAgent.
This safely dereferences the pointer. Ensure that the default value is correct in all usage contexts.


171-171: SafeDeref usage for SshBatchMode.
This is correct for preventing nil pointer issues. Confirm that skipping passphrase input is the desired default when SshBatchMode is nil.


200-200: Additional SafeDeref check for SshAddKeysToAgent.
This pattern is consistent. No major issues.


557-560: Check default SSH user, host, or port values carefully.
At lines 557-560, SafeDeref ensures we don’t panic on nil. Make sure any fallback logic is correct if these fields are unset.


585-587: Batch mode concurrency check.
The combined conditions ensure keyboard-interactive or password authentication is skipped in batch mode. This is logically sound.


608-608: networkAddr usage.
Make sure that host and port are combined precisely, especially for IPv6 addresses.


610-610: Explicit user field assignment.
Line 610 sets ssh.ClientConfig.User to the derived user. No issues spotted.


654-654: Initialize local parsedKeywords.
This pointer-based struct usage is consistent with the rest of the code.


655-657: Conditional user assignment.
If opts.SSHUser is non-empty, store it in parsedKeywords. Matches desired logic.


658-660: Conditional port assignment.
Similar logic for port. Helps unify the final merged config.


666-666: Defaulting to empty ConnKeywords.
If no internal config is found, we create an empty struct. Good to prevent nil references.


669-673: mergeKeywords usage #1.
The cascading approach is clear. Ensure the final merges preserve user overrides properly.


675-677: mergeKeywords usage #2.
Continuing to merge in user flag overrides. This chain-of-responsibility pattern is logically consistent.


678-682: Appending identity files #1.
Appending to SshIdentityFile in reverse order is intentional for prioritization. No issues spotted.


683-685: Appending identity files #2.
Combines sshConfigKeywords last. This is consistent with the comment describing the order.


710-710: networkAddr usage in connectInternal.
Combining SshHostName + SshPort through SafeDeref. Carefully handle blank values if the struct is partially nil.


736-744: User resolution fallback logic.
If no user is specified by config, it defaults to current OS user. This is standard SSH behavior. Good approach.


750-756: HostName fallback logic.
If HostName is missing, fallback uses the original host pattern. Ensure the normalized pattern is correct for multi-part host specs.


762-762: Port assignment with Ptr(...)
The usage of utilfn.Ptr ensures correct conversion to pointer. Straightforward.


774-774: BatchMode assignment.
This approach sets the boolean correctly based on “yes” or “no.” Looks good.


781-781: PubkeyAuthentication defaults to true.
In openSSH config, “yes” is typical. Non-‘no’ strings become true. This matches existing patterns.


787-787: PasswordAuthentication logic.
Similar “!= no” condition used. Maintains consistent default.


793-793: KbdInteractiveAuthentication logic.
Again, consistent with the “!= no” pattern.


806-806: AddKeysToAgent detection.
Sets SshAddKeysToAgent to true if the config is “yes.” Matches openSSH usage.


821-821: ExpandHomeDir.
This ensures the IdentityAgent path is properly expanded. Make sure no edge cases for unusual HOME.


830-830: Set SshIdentityAgent pointer.
For explicit IdentityAgent settings, the code is consistent.


856-856: SSHPort type changed to string.
Switching from int to string broadens input flexibility. Thoroughly test for invalid port strings.


865-865: Conditional port display on String().
This logic only appends the port if it’s not 22 and not empty. Standard approach.

@oneirocosm oneirocosm merged commit b778417 into main Dec 23, 2024
8 checks passed
@oneirocosm oneirocosm deleted the sylvie/entirely-internal-connection branch December 23, 2024 23:12
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.

1 participant