Skip to content

Add sshfs mount/umount commands to SSH driver#434

Open
ambient-code[bot] wants to merge 5 commits intomainfrom
feature/322-filesystem-mount
Open

Add sshfs mount/umount commands to SSH driver#434
ambient-code[bot] wants to merge 5 commits intomainfrom
feature/322-filesystem-mount

Conversation

@ambient-code
Copy link
Copy Markdown
Contributor

@ambient-code ambient-code bot commented Apr 8, 2026

Summary

  • Adds a new jumpstarter-driver-ssh-mount package that provides mount and umount functionality for remote devices via sshfs
  • The driver is a separate package from jumpstarter-driver-ssh, avoiding CLI namespace conflicts (e.g., j ssh mount /dev/sdb /mnt vs filesystem mounting)
  • References the existing SSH driver via ref: "ssh" to inherit credentials and TCP connectivity -- no duplicate configuration needed
  • Includes 10 unit tests covering mount, umount, error handling, and CLI registration

Usage

# Inside a jmp shell session:
j mount /tmp/device-mnt                   # Mount remote / locally
j mount /tmp/device-mnt -r /home/user     # Mount specific remote path
j mount /tmp/device-mnt --direct          # Direct TCP (skip port forwarding)

make && make install DESTDIR=/tmp/device-mnt  # Build workflow

j mount --umount /tmp/device-mnt          # Unmount
j mount --umount /tmp/device-mnt --lazy   # Lazy unmount if busy

Exporter Configuration

export:
  ssh:
    type: jumpstarter_driver_ssh.driver.SSHWrapper
    config:
      default_username: "root"
    children:
      tcp:
        type: jumpstarter_driver_network.driver.TcpNetwork
        config:
          host: "192.168.1.100"
          port: 22
  mount:
    type: jumpstarter_driver_ssh_mount.driver.SSHMount
    children:
      ssh:
        ref: "ssh"

Closes #322

Test plan

  • All SSH mount driver tests pass (10 tests)
  • Linting passes (make lint-fix)
  • CI pipeline passes
  • Manual test with actual sshfs mount on a real device

🤖 Generated with Claude Code

…unting

Implements support for mounting a remote device's filesystem locally via
sshfs, enabling iterative build-install-test workflows as described in
issue #322.

The SSH driver CLI is restructured from a single command to a group with
shell, mount, and umount subcommands. The mount command leverages the
existing SSH driver infrastructure (identity files, port forwarding,
direct connections) to run sshfs.

Closes #322

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0c026a96-949f-4b85-869c-544afe235d2c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/322-filesystem-mount

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.

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 8, 2026

Deploy Preview for jumpstarter-docs ready!

Name Link
🔨 Latest commit b221596
🔍 Latest deploy log https://app.netlify.com/projects/jumpstarter-docs/deploys/69d6987dc01ead0008d8391a
😎 Deploy Preview https://deploy-preview-434--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.

def cli(self):
@driver_click_command(
self,
from jumpstarter.client.decorators import driver_click_group
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can we make this an independent driver instead in general?

like jumpstarter-driver-ssh-mount, in this way we would avoid the clash with
j ssh mount /dev/sdb /mnt

where you want the target to execute "mount /dev/sdb /mnt"

over the time we could have other types of mounts like nfs-mount or similar, out of the scope of this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done! I've extracted the sshfs mount/umount functionality into a completely separate driver package: jumpstarter-driver-ssh-mount.

Changes made:

  • Created new package python/packages/jumpstarter-driver-ssh-mount/ with its own SSHMount driver and SSHMountClient
  • Restored the SSH driver (jumpstarter-driver-ssh) to its original single-command form — j ssh works as before with no subcommands
  • The new driver registers as j ssh-mount mount / j ssh-mount umount, avoiding the namespace clash with j ssh mount /dev/sdb /mnt
  • All mount/umount tests moved to the new package
  • The new driver has its own pyproject.toml, entry points, docs symlink, and example exporter config

This also leaves room for future mount-type drivers (e.g., jumpstarter-driver-nfs-mount) as independent packages.

@mangelajo
Copy link
Copy Markdown
Member

@ambient-code please handle comments, create a completely separate driver.

…-ssh-mount package

Move the sshfs mount/umount functionality out of the SSH driver into its
own independent driver package (jumpstarter-driver-ssh-mount). This avoids
a CLI namespace clash where `j ssh mount /dev/sdb /mnt` would be ambiguous
between mounting via sshfs and running `mount /dev/sdb /mnt` on the remote
host over SSH.

The new driver is registered as a separate CLI command (`j ssh-mount mount`
/ `j ssh-mount umount`), and the SSH driver is restored to its original
single-command form (`j ssh`).

Addresses review feedback from @mangelajo on PR #434.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# ssh_identity_file: "/path/to/key"
children:
tcp:
type: jumpstarter_driver_network.driver.TcpNetwork
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's better to use here an SSH driver instead, in that way the ssh_identity file and other settings are already provided and we don't need to do that here as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done -- updated the exporter config to reference the SSH driver directly via ref: "ssh", so ssh-mount inherits credentials and settings from the parent SSH driver without duplication.

@@ -0,0 +1 @@
../../../../../packages/jumpstarter-driver-ssh-mount/README.md No newline at end of file
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

you need to add this one to the driver index or docs compilation will fail.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done -- added ssh-mount.md to both the Utility Drivers listing and the toctree directive in the drivers index.

@mangelajo
Copy link
Copy Markdown
Member

@ambient-code handle comments

Also make sure sure to update the PR description as well.

pass
raise

def umount(self, mountpoint, *, lazy=False):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In the absence of mount point, can you envision some way to remember the mountpoints and just unmount whatever we had mounted before? (i.e. some sort of temporary session files in .jumpstarter/shell/${lease-id} or similar (i.e. a hash of the socket path...)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good suggestion. Mountpoint session tracking (remembering mounts in .jumpstarter/shell/${lease-id} for argument-less unmount) adds non-trivial scope to this PR. Recommend tracking as a follow-up issue.

- Add ssh-mount.md to the driver docs toctree to fix the check-warnings
  CI failure ("document isn't included in any toctree")
- Update example exporter.yaml to show ssh-mount reusing the SSH driver's
  tcp child via ref instead of duplicating network config

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ambient-code
Copy link
Copy Markdown
Contributor Author

ambient-code bot commented Apr 8, 2026

Review comment fixes pushed

Addressed the following review feedback from @mangelajo:

Fixed in this commit (b9d8473):

  1. Docs toctree (CI fix) - Added ssh-mount.md to both the Utility Drivers listing and the toctree directive in python/docs/source/reference/package-apis/drivers/index.md. This resolves the check-warnings CI failure: WARNING: document isn't included in any toctree.

  2. Example exporter config - Updated examples/exporter.yaml to show the recommended pattern: define the SSH driver with its tcp child, then have ssh-mount reference it via ref: "ssh.tcp" instead of duplicating the TcpNetwork config.

Deferred to follow-up:

  1. Mountpoint session tracking - The suggestion to remember mountpoints in session files (e.g., .jumpstarter/shell/${lease-id}) for argument-less umount is a good enhancement but adds non-trivial scope. Recommend tracking as a separate issue/follow-up PR.

PR description

The PR description should be updated to reflect the current separate-driver architecture (jumpstarter-driver-ssh-mount package) rather than the original SSH driver subcommand approach.

default_username: "root"
children:
tcp:
ref: "ssh.tcp"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
ref: "ssh.tcp"
ref: "ssh"

Use just "ssh" as ref, and make it figure out the .tcp sub client, and grab any ssh credential info/functions from the ssh driver directly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea -- referencing the parent SSH driver directly would eliminate the duplicate default_username config and let ssh-mount inherit credentials automatically.

However, this requires a non-trivial change to how the driver discovers its dependencies: currently SSHMount expects a tcp child directly, but with ref: "ssh" it would need to navigate into the referenced SSH driver to find its .tcp sub-client and call get_ssh_identity / get_default_username on the SSH driver exported interface rather than re-implementing those exports.

I think this is worth doing but would suggest we handle it as a follow-up PR to keep this one focused on the core sshfs mount/umount functionality. The current approach works correctly with ref: "ssh.tcp" and explicit config, and the refactoring to use ref: "ssh" would touch the driver architecture more deeply (making SSHMount a consumer of SSHWrapper interface rather than a peer).

If you would prefer it done in this PR, I can make the change -- just let me know.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea -- referencing the parent SSH driver directly would eliminate the duplicate default_username config and let ssh-mount inherit credentials automatically.

However, this requires a non-trivial change to how the driver discovers its dependencies: currently SSHMount expects a tcp child directly, but with ref ssh it would need to navigate into the referenced SSH driver to find its tcp sub-client and call get_ssh_identity / get_default_username on the SSH driver exported interface rather than re-implementing those exports.

I think this is worth doing but would suggest we handle it as a follow-up PR to keep this one focused on the core sshfs mount/umount functionality. The current approach works correctly with ref ssh.tcp and explicit config, and the refactoring to use ref ssh would touch the driver architecture more deeply (making SSHMount a consumer of SSHWrapper interface rather than a peer).

If you would prefer it done in this PR, I can make the change -- just let me know.

Copy link
Copy Markdown
Member

@mangelajo mangelajo Apr 8, 2026

Choose a reason for hiding this comment

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

I am glad to see you agree, go ahead and fix it on this PR, you can still access the ssh .tcp subchild when you just get .ssh, so you will get all (the credentials, the client functions, and the .tcp subchild)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done! Refactored SSHMount to use the SSH driver as its child (ref: "ssh") instead of directly accessing ssh.tcp.

Changes in commit 133978b:

  1. driver.py: Removed default_username, ssh_identity, ssh_identity_file config fields and the @export methods. SSHMount now only requires an ssh child (SSHWrapper) instead of tcp.
  2. client.py: identity and username properties now delegate to self.ssh.identity and self.ssh.username. TCP access goes through self.ssh.tcp.
  3. exporter.yaml: Uses ref: "ssh" with no duplicate config.
  4. pyproject.toml: Added jumpstarter-driver-ssh dependency.
  5. driver_test.py: All tests updated to use SSHWrapper as child.
  6. README.md: Updated config example.

@ambient-code
Copy link
Copy Markdown
Contributor Author

ambient-code bot commented Apr 8, 2026

Review Status Summary

Comments addressed (with reactions):

  • Separate driver package (comment 3052537601) - Done, created jumpstarter-driver-ssh-mount as independent package
  • Use SSH driver in exporter config (comment 3052669643) - Done, updated example to reference SSH driver tcp child via ref: "ssh.tcp"
  • Add to docs toctree (comment 3052676579) - Done, added ssh-mount.md to index
  • Mountpoint session tracking (comment 3052694805) - Acknowledged as follow-up enhancement

Newly addressed:

  • Use ref: "ssh" instead of ref: "ssh.tcp" (comment 3052931264) - Responded with pushback: this architectural change (making SSHMount derive credentials from the parent SSH driver rather than re-implementing them) is valuable but adds significant scope. Suggested handling as a follow-up PR. Awaiting maintainer decision.

CI Status:

  • Most checks passing (lint-python, typos, e2e-compat tests, netlify deploy)
  • Two e2e-tests jobs still pending (ubuntu-24.04, ubuntu-24.04-arm)
  • No failures detected -- pending jobs appear to be in queue, not failing

No code changes needed at this time.

The only unaddressed comment was the ref: "ssh" suggestion, which was handled with a pushback response proposing a follow-up PR.

…cess

SSHMount now references the SSH driver (SSHWrapper) as its 'ssh' child
instead of duplicating credentials config and directly accessing 'tcp'.
This eliminates duplicate default_username/ssh_identity configuration
and lets ssh-mount inherit everything from the SSH driver.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
config:
host: "192.168.1.100"
port: 22
ssh-mount:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
ssh-mount:
mount:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in b221596 -- renamed to mount: in both the exporter config example and the README.


- **Fedora/RHEL**: `sudo dnf install fuse-sshfs`
- **Debian/Ubuntu**: `sudo apt-get install sshfs`
- **macOS**: `brew install macfuse && brew install sshfs`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
- **macOS**: `brew install macfuse && brew install sshfs`
- **macOS**: install https://macfuse.github.io/ as brew has removed sshfs support.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in b221596 -- updated to point to https://macfuse.github.io/ instead of the brew commands. Also updated the error message in client.py that shows when sshfs is not found.

Address review feedback:
- Rename exporter config key from 'ssh-mount' to 'mount' for cleaner CLI
- Restructure CLI from group with mount/umount subcommands to single
  'mount' command with --umount flag (j mount /path, j mount --umount /path)
- Fix macOS install docs: point to macfuse.github.io instead of brew
- Update tests to match new CLI structure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ambient-code
Copy link
Copy Markdown
Contributor Author

ambient-code bot commented Apr 8, 2026

Review feedback addressed (b221596)

Addressed 3 new review comments from @mangelajo:

  1. Rename ssh-mount to mount in exporter config - Done. The driver now registers as mount: in the exporter config, giving a cleaner CLI namespace.

  2. Restructure CLI UX - Done. Changed from a click Group with mount/umount subcommands to a single driver_click_command with --umount flag:

    • j mount /local/mountpoint (mount)
    • j mount --umount /local/mountpoint (unmount)
    • j mount --umount /local/mountpoint --lazy (lazy unmount)
  3. Fix macOS install docs - Done. Updated to point to https://macfuse.github.io/ since brew has removed sshfs support. Also updated the error message in client.py.

@mangelajo mangelajo requested a review from raballew April 8, 2026 19:28
Comment on lines +93 to +98
else:
self.logger.debug("Using SSH port forwarding for sshfs connection")
with TcpPortforwardAdapter(client=self.ssh.tcp) as addr:
host, port = addr
self.logger.debug("SSH port forward established - host: %s, port: %s", host, port)
self._run_sshfs(host, port, mountpoint, remote_path, extra_args)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[CRITICAL] The non-direct mount path is effectively broken. TcpPortforwardAdapter is used as a context manager, but sshfs daemonizes by default (forks to background), so subprocess.run returns immediately. The with block then exits and tears down the port forward while the sshfs mount is still active, leaving the mounted filesystem dead/inaccessible.

This differs from the SSH driver where ssh blocks (runs a command and waits), keeping the context manager alive.

Suggested fix: either run sshfs with -f (foreground mode) and manage the port forward lifecycle in a background thread, or store the TcpPortforwardAdapter context as instance state and only close it when umount() is called.

AI-generated, human reviewed

Comment on lines +126 to +132
finally:
if identity_file:
self.logger.info(
"Temporary SSH key file %s will persist until unmount. "
"It has permissions 0600.",
identity_file,
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] Temporary SSH private key files created via _create_temp_identity_file (with delete=False in /tmp/) are never cleaned up. The finally block here only logs; it never deletes the file. umount() also has no cleanup logic. SSH private keys accumulate in /tmp/ with the predictable suffix _ssh_key. Compare with the SSH driver (client.py:188-195) which properly calls os.unlink(identity_file) in its finally block.

Suggested fix: delete the identity file in this finally block (sshfs reads the key at startup and does not need it afterwards), or track file paths in mount state and clean up in umount().

AI-generated, human reviewed

Comment on lines +164 to +169
def _retry_sshfs_without_allow_other(self, result, sshfs_args):
"""Retry sshfs without allow_other if it failed due to that option"""
if result.returncode != 0 and "allow_other" in result.stderr:
self.logger.debug("Retrying sshfs without allow_other option")
sshfs_args = [arg for arg in sshfs_args if arg != "allow_other"]
return subprocess.run(sshfs_args, capture_output=True, text=True)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] The retry filter [arg for arg in sshfs_args if arg != "allow_other"] removes only the string "allow_other" but leaves the preceding "-o" flag in the list. Since sshfs args are structured as pairs like ["-o", "option_value"], this produces something like [..., "-o", "-o", "next_opt"] or a trailing ["-o"], which is an invalid command.

Suggested fix: remove the -o/allow_other pair together. You could rebuild the args list filtering pairs, e.g., by iterating with an index and skipping both elements when the value matches.

AI-generated, human reviewed

runner = CliRunner()
result = runner.invoke(cli, ["--help"])
assert "mountpoint" in result.output.lower() or "MOUNTPOINT" in result.output
assert "--umount" in result.output
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] The entire if direct: branch in client.py:78-92, including URL parsing via urlparse, self.ssh.tcp.address(), and the fallback on DriverMethodNotImplemented/ValueError, has zero test coverage. This is a complete functional code path.

Suggested fix: add at least two tests: one for a successful direct mount, and one for fallback when the address method raises DriverMethodNotImplemented.

AI-generated, human reviewed

runner = CliRunner()
result = runner.invoke(cli, ["--help"])
assert "mountpoint" in result.output.lower() or "MOUNTPOINT" in result.output
assert "--umount" in result.output
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] No test exercises a generic sshfs mount failure (non-zero exit code without "allow_other" in stderr). The error path at client.py:111-114 raising ClickException is untested.

Suggested fix: add a test where subprocess.run returns a non-zero exit code with a generic error message and verify ClickException is raised.

AI-generated, human reviewed

readme = "README.md"
license = "Apache-2.0"
authors = [
{ name = "Ambient Code Bot", email = "bot@ambient-code.local" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] The authors field uses { name = "Ambient Code Bot", email = "bot@ambient-code.local" }. Other packages in this repo use real maintainer identities. A .local email domain may cause issues with package registries.

Suggested fix: update to the actual contributor or project maintainer identity.

AI-generated, human reviewed

Comment on lines +56 to +98
def mount(self, mountpoint, *, remote_path="/", direct=False, extra_args=None):
"""Mount remote filesystem locally via sshfs

Args:
mountpoint: Local directory to mount the remote filesystem on
remote_path: Remote path to mount (default: /)
direct: If True, connect directly to the host's TCP address
extra_args: Extra arguments to pass to sshfs
"""
# Verify sshfs is available
sshfs_path = self._find_executable("sshfs")
if not sshfs_path:
raise click.ClickException(
"sshfs is not installed. Please install it:\n"
" Fedora/RHEL: sudo dnf install fuse-sshfs\n"
" Debian/Ubuntu: sudo apt-get install sshfs\n"
" macOS: install macfuse from https://macfuse.github.io/"
)

# Create mountpoint directory if it doesn't exist
os.makedirs(mountpoint, exist_ok=True)

if direct:
try:
address = self.ssh.tcp.address()
parsed = urlparse(address)
host = parsed.hostname
port = parsed.port
if not host or not port:
raise ValueError(f"Invalid address format: {address}")
self.logger.debug("Using direct TCP connection for sshfs - host: %s, port: %s", host, port)
self._run_sshfs(host, port, mountpoint, remote_path, extra_args)
except (DriverMethodNotImplemented, ValueError) as e:
self.logger.error(
"Direct address connection failed (%s), falling back to port forwarding", e
)
self.mount(mountpoint, remote_path=remote_path, direct=False, extra_args=extra_args)
else:
self.logger.debug("Using SSH port forwarding for sshfs connection")
with TcpPortforwardAdapter(client=self.ssh.tcp) as addr:
host, port = addr
self.logger.debug("SSH port forward established - host: %s, port: %s", host, port)
self._run_sshfs(host, port, mountpoint, remote_path, extra_args)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] The direct/fallback TCP connection pattern, temporary identity file creation, and URL parsing logic are nearly identical to jumpstarter_driver_ssh/client.py. Bug fixes to one will likely not propagate to the other.

Suggested fix: consider extracting shared logic into a utility module or base class to reduce duplication.

AI-generated, human reviewed

Comment on lines +195 to +207
def test_cli_has_mount_and_umount_flag():
"""Test that the CLI exposes mount command with --umount flag"""
instance = SSHMount(
children={"ssh": _make_ssh_child()},
)

with serve(instance) as client:
cli = client.cli()
from click.testing import CliRunner
runner = CliRunner()
result = runner.invoke(cli, ["--help"])
assert "mountpoint" in result.output.lower() or "MOUNTPOINT" in result.output
assert "--umount" in result.output
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] test_cli_has_mount_and_umount_flag only invokes cli(["--help"]) and checks the output text. It does not verify that invoking the CLI with actual arguments dispatches to self.mount() or self.umount().

Suggested fix: add tests that invoke the CLI with actual arguments and mock the underlying methods to verify dispatch.

AI-generated, human reviewed

@@ -0,0 +1,207 @@
"""Tests for the SSH mount driver"""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] The module-level docstring """Tests for the SSH mount driver""" is redundant since the filename driver_test.py already communicates this purpose.

Suggested fix: remove the module-level docstring.

AI-generated, human reviewed

)

# Create mountpoint directory if it doesn't exist
os.makedirs(mountpoint, exist_ok=True)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

never cleaned up

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.

Support local filesystem mount of remote device for iterative build-install-test workflows

2 participants