Skip to content

Replace pysftp with paramiko, lift paramiko ceiling to <6#683

Merged
CasperWA merged 5 commits into
masterfrom
cwa/replace-pysftp-with-paramiko
May 11, 2026
Merged

Replace pysftp with paramiko, lift paramiko ceiling to <6#683
CasperWA merged 5 commits into
masterfrom
cwa/replace-pysftp-with-paramiko

Conversation

@CasperWA

@CasperWA CasperWA commented May 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Replace the unmaintained pysftp dependency with direct paramiko calls in the SFTP download strategy, and update the paramiko version constraint from <4 to >=4,<6.
pysftp 0.2.9 imports DSSKey from paramiko at module load time; paramiko 4.0 removed DSSKey, causing an ImportError whenever paramiko>=4 is installed.
This also resolves the pip-audit CVE-2026-44405 advisory that was blocked by the old paramiko<4 pin.

Motivation

Fixes #682

Dependabot PR #678 tried raising paramiko<4 to <6, but all pytest jobs failed with:

ImportError: cannot import name 'DSSKey' from 'paramiko'

pysftp 0.2.9 is unmaintained (last release 2016) and will never be updated.
No maintained PyPI fork exists.
The entire role of pysftp in this codebase is a thin wrapper around three paramiko calls, making a direct replacement straightforward.

Changes

oteapi/strategies/download/sftp.py

  • Replace import pysftp with import paramiko
  • Replace pysftp.CnOpts(hostkeys=None) + pysftp.Connection(...) with paramiko.SSHClient used as a context manager with AutoAddPolicy (equivalent host-key behaviour; # nosec B507 added as the lax policy is intentional)
  • Replace sftp.get(path, localpath=Path(...)) with sftp.get(path, str(localpath))
  • Add a runtime guard using falsy checks on url.host and url.path so both None and empty-string values raise a clear error; the message exposes only host and path (not credentials)

tests/strategies/download/test_sftp.py

  • Replace MockSFTPConnection (patching pysftp.Connection) with MockSSHClient + MockSFTPClient (patching paramiko.SSHClient)

pyproject.toml

  • Remove pysftp~=0.2.9 from dependencies
  • Change paramiko<4paramiko>=4,<6 (lower bound ensures we're past the DSSKey removal and the CVE; upper bound guards against future breaking changes in 6.x)
  • Remove the filterwarnings entry for pysftp's HostKeys warning (no longer needed)

.pre-commit-config.yaml

  • Add types-paramiko to the mypy hook's additional_dependencies so mypy can type-check paramiko calls

.gitignore

  • Add .claude/ to avoid accidentally committing Claude Code session files

Test Plan

@codecov

codecov Bot commented May 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.88889% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 83.38%. Comparing base (36f8c9e) to head (1c52c66).

Files with missing lines Patch % Lines
oteapi/strategies/download/sftp.py 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #683      +/-   ##
==========================================
- Coverage   83.44%   83.38%   -0.06%     
==========================================
  Files          14       14              
  Lines         610      614       +4     
==========================================
+ Hits          509      512       +3     
- Misses        101      102       +1     
Flag Coverage Δ
linux 83.38% <88.88%> (-0.06%) ⬇️
linux-strategies 83.38% <88.88%> (-0.06%) ⬇️
windows 82.73% <88.88%> (-0.06%) ⬇️
windows-strategies 82.73% <88.88%> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This pull request replaces the unmaintained pysftp dependency with direct paramiko usage in the (s)ftp download strategy, enabling paramiko>=4 and lifting the upper constraint to <6 to resolve the DSSKey import breakage and unblock dependency auditing.

Changes:

  • Reworked SFTPStrategy.get() to use paramiko.SSHClient + open_sftp() instead of pysftp.Connection.
  • Updated the SFTP strategy unit test to mock paramiko.SSHClient/SFTP behavior instead of pysftp.
  • Updated project/developer tooling: removed pysftp, raised paramiko ceiling to <6, and added types-paramiko for mypy.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
oteapi/strategies/download/sftp.py Replace pysftp connection logic with paramiko (SSHClient + open_sftp) and add a URL host/path guard.
tests/strategies/download/test_sftp.py Replace pysftp-based mocks with paramiko-style SSH/SFTP client mocks and patching.
pyproject.toml Drop pysftp, widen paramiko constraint to <6, and remove pysftp-specific warning filter.
.pre-commit-config.yaml Add types-paramiko to mypy hook dependencies for better type-checking of the new calls.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread oteapi/strategies/download/sftp.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread .pre-commit-config.yaml
Comment thread oteapi/strategies/download/sftp.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread oteapi/strategies/download/sftp.py

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 1 comment.

Comment thread pyproject.toml Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated no new comments.

@CasperWA

Copy link
Copy Markdown
Contributor Author

Squash commit message:

Title

Replace pysftp with paramiko, constrain paramiko>=4,<6 (#682)

Body

pysftp 0.2.9 imports DSSKey from paramiko at module load time, but
paramiko 4.0 removed DSSKey. Replace pysftp.Connection with direct
paramiko.SSHClient usage in sftp.py, remove pysftp from
dependencies, and add types-paramiko to the mypy hook. The lower
bound >=4 pins past the DSSKey removal and CVE-2026-44405.

pysftp 0.2.9 imports DSSKey from paramiko at module load time, but
paramiko 4.0 removed DSSKey entirely. Replace the three pysftp
calls in sftp.py with equivalent paramiko.SSHClient usage, remove
pysftp from dependencies, and add types-paramiko to the mypy hook.
@CasperWA CasperWA force-pushed the cwa/replace-pysftp-with-paramiko branch from d5951f6 to 1c52c66 Compare May 11, 2026 10:22
@CasperWA CasperWA merged commit 6d4de5e into master May 11, 2026
20 checks passed
@CasperWA CasperWA deleted the cwa/replace-pysftp-with-paramiko branch May 11, 2026 10:30
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.

Replace pysftp with paramiko to support paramiko >=4

3 participants