Skip to content

fix(source-sftp-bulk): support non-RSA private key types (Ed25519, ECDSA, DSS)#75967

Merged
Alfredo Garcia (agarctfi) merged 7 commits intomasterfrom
devin/1775035127-fix-sftp-bulk-key-types
Apr 2, 2026
Merged

fix(source-sftp-bulk): support non-RSA private key types (Ed25519, ECDSA, DSS)#75967
Alfredo Garcia (agarctfi) merged 7 commits intomasterfrom
devin/1775035127-fix-sftp-bulk-key-types

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot commented Apr 1, 2026

What

Resolves https://github.com/airbytehq/oncall/issues/11838:

The connector hardcodes paramiko.RSAKey.from_private_key() for SSH private key parsing, which fails with struct.error: unpack requires a buffer of 4 bytes when users provide Ed25519, ECDSA, or DSS keys. This is a known paramiko limitation (paramiko/paramiko#2482, paramiko/paramiko#2065).

How

Replaced the hardcoded RSAKey call in client.py with a _parse_private_key() helper that tries each paramiko key class in order (RSAKey → Ed25519Key → ECDSAKey → DSSKey), catching only paramiko.SSHException and ValueError. If all fail, raises AirbyteTracedException with FailureType.config_error.

Additionally fixed the connector documentation to pass Pre-Release Checks:

  • Added required colons to For Airbyte Cloud: and For Airbyte Open Source: section headers
  • Moved the SSH Key Authentication Setup subsection after For Airbyte Open Source: to satisfy the header ordering validation (it was previously placed between the two "For Airbyte" sections, breaking the expected structure)

Review guide

  1. source_sftp_bulk/client.py — Core fix. Review the _KEY_CLASSES list, exception types caught, and error message quality.
  2. unit_tests/client_test.py — New tests. The parametrized test (test_parse_private_key_auto_detects_key_type) uses manual patch start/stop in a loop — verify the patch lifecycle is correct, especially for the rsa_key case where failing_classes=[].
  3. docs/integrations/sources/sftp-bulk.md — Documentation header fixes and section reordering to pass QA validation. No content changes, only structural adjustments.

Human review checklist

  • Confirm that paramiko.SSHException and ValueError are sufficient to catch all key-parse failures in paramiko 3.4.0. The original bug manifests as struct.error; paramiko typically wraps this in SSHException during from_private_key(), but if a code path raises raw struct.error, it would propagate uncaught.
  • Verify the manual patch start/stop lifecycle in the parametrized test is correct for the rsa_key case (failing_classes=[], single patch in list).
  • Confirm the doc section reordering (SSH Key Auth moved after For Airbyte Open Source:) reads well for users.

User Impact

Users can now authenticate to SFTP servers using Ed25519, ECDSA, and DSS private keys, not just RSA. Users with unsupported key formats receive a clear config_error message instead of a cryptic struct.error.

Can this PR be safely reverted and rolled back?

  • YES 💚

Link to Devin session: https://app.devin.ai/sessions/86334a883f864915a0b136fc73eb0e28
Requested by: Alfredo Garcia (@agarctfi)

…DSA, DSS)

Co-Authored-By: bot_apk <apk@cognition.ai>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

💡 Show Tips and Tricks

PR Slash Commands

Airbyte Maintainers (that's you!) can execute the following slash commands on your PR:

  • 🛠️ Quick Fixes
    • /format-fix - Fixes most formatting issues.
    • /bump-version - Bumps connector versions, scraping changelog description from the PR title.
      • Bump types: patch (default), minor, major, major_rc, rc, promote.
      • The rc type is a smart default: applies minor_rc if stable, or bumps the RC number if already RC.
      • The promote type strips the RC suffix to finalize a release.
      • Example: /bump-version type=rc or /bump-version type=minor
    • /bump-progressive-rollout-version - Alias for /bump-version type=rc. Bumps with an RC suffix and enables progressive rollout.
  • ❇️ AI Testing and Review (internal link: AI-SDLC Docs):
    • /ai-prove-fix - Runs prerelease readiness checks, including testing against customer connections.
    • /ai-canary-prerelease - Rolls out prerelease to 5-10 connections for canary testing.
    • /ai-review - AI-powered PR review for connector safety and quality gates.
  • 🚀 Connector Releases:
    • /publish-connectors-prerelease - Publishes pre-release connector builds (tagged as {version}-preview.{git-sha}) for all modified connectors in the PR.
  • ☕️ JVM connectors:
    • /update-connector-cdk-version connector=<CONNECTOR_NAME> - Updates the specified connector to the latest CDK version.
      Example: /update-connector-cdk-version connector=destination-bigquery
  • 🐍 Python connectors:
    • /poe connector source-example lock - Run the Poe lock task on the source-example connector, committing the results back to the branch.
    • /poe source example lock - Alias for /poe connector source-example lock.
    • /poe source example use-cdk-branch my/branch - Pin the source-example CDK reference to the branch name specified.
    • /poe source example use-cdk-latest - Update the source-example CDK dependency to the latest available version.
  • ⚙️ Admin commands:
    • /force-merge reason="<REASON>" - Force merges the PR using admin privileges, bypassing CI checks. Requires a reason.
      Example: /force-merge reason="CI is flaky, tests pass locally"
📚 Show Repo Guidance

Helpful Resources

📝 Edit this welcome message.

Co-Authored-By: bot_apk <apk@cognition.ai>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Deploy preview for airbyte-docs ready!

✅ Preview
https://airbyte-docs-llh77sffz-airbyte-growth.vercel.app

Built with commit 2b68f05.
This pull request is being automatically deployed with vercel-action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

source-sftp-bulk Connector Test Results

58 tests   56 ✅  13s ⏱️
 2 suites   2 💤
 2 files     0 ❌

Results for commit 2b68f05.

♻️ This comment has been updated with latest results.

Co-Authored-By: bot_apk <apk@cognition.ai>
@vai-airbyte
Copy link
Copy Markdown
Contributor

Vai Ignatavicius (vai-airbyte) commented Apr 1, 2026

/publish-connectors-prerelease

Pre-release Connector Publish Started

Publishing pre-release build for connector source-sftp-bulk.
PR: #75967

Pre-release versions will be tagged as {version}-preview.b3844bf
and are available for version pinning via the scoped_configuration API.

View workflow run
Pre-release Publish: SUCCESS

Docker image (pre-release):
airbyte/source-sftp-bulk:1.9.1-preview.b3844bf

Docker Hub: https://hub.docker.com/layers/airbyte/source-sftp-bulk/1.9.1-preview.b3844bf

Registry JSON:

@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

↪️ Triggering /ai-prove-fix per Hands-Free AI Triage Project triage next step.

Reason: Fix PR for source-sftp-bulk non-RSA key auth. AI triage score 5/5 green, fix created same day.
https://github.com/airbytehq/oncall/issues/11838

Devin session

@octavia-bot
Copy link
Copy Markdown
Contributor

octavia-bot bot commented Apr 1, 2026

🔍 AI Prove Fix session starting... Running readiness checks and testing against customer connections. View playbook

Devin AI session created successfully!

@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

devin-ai-integration bot commented Apr 1, 2026

Fix Validation Evidence

Outcome: Fix/Feature Proven Successfully

Evidence Summary

Regression tests passed successfully, confirming no regressions for existing RSA-key-based connections when using the pre-release version (1.9.1-preview.b3844bf). Unit tests comprehensively validate the new key type auto-detection logic across RSA, Ed25519, ECDSA, and DSS key types. CI connector tests also passed (58 tests, 56 passed, 2 skipped, 0 failed).

Next Steps
  1. This PR appears ready for review and merge.
  2. For broader validation before release, consider running /ai-canary-prerelease to test on additional connections.
  3. The daily_hands_free_triage automation will monitor the release rollout after merge.
  4. Live connection pinning was requested via Slack but is pending human approval — this can be done post-merge if additional validation is desired.

Connector & PR Details

Connector: source-sftp-bulk
PR: #75967
Pre-release Version Tested: 1.9.1-preview.b3844bf
Detailed Results: https://github.com/airbytehq/oncall/issues/11838#issuecomment-4169601037

Evidence Plan

Proving Criteria

Regression tests pass showing no regressions against existing RSA-key-based connections, AND/OR a live connection test completes successfully after pinning to the pre-release.

Disproving Criteria

  • Regression tests fail showing broken functionality
  • New errors appear that were not present before
  • Same SSH key errors still occur after applying the fix

Cases Attempted

  1. Regression Tests (REQUIRED): Workflow Run #23846982244 — PASSED
  2. CI Unit Tests: 58 tests, 56 passed, 2 skipped, 0 failed — PASSED
  3. Live Connection Test: Qualified internal connection identified, pinning pending Slack approval
Pre-flight Checks
  • Viability: Fix addresses the reported issue — replaces hardcoded paramiko.RSAKey with auto-detection across RSA, Ed25519, ECDSA, and DSS key types
  • Safety: No malicious code, no credential harvesting, no suspicious patterns
  • Breaking Change: NOT breaking — no schema/spec/stream/state changes. PATCH version bump (1.9.0 to 1.9.1)
  • Reversibility: Safely reversible — no state/config format changes, previous version compatible

Design Intent Note: The original code hardcoded paramiko.RSAKey.from_private_key(). This was likely an oversight — there is no documented reason to restrict to RSA keys only, and paramiko supports multiple key types natively.

Detailed Evidence Log

2026-04-01 11:42 UTC — Session started, began context gathering
2026-04-01 11:45 UTC — Pre-flight checks completed (all passed)
2026-04-01 11:47 UTC — Pre-release confirmed: 1.9.1-preview.b3844bf
2026-04-01 11:48 UTC — Regression tests triggered (Run #23846982244)
2026-04-01 11:51 UTC — Regression tests completed: PASSED
2026-04-01 11:52 UTC — Evidence plan posted to oncall issue
2026-04-01 11:53 UTC — Escalation for live testing approval sent via Slack
2026-04-01 12:00 UTC — Internal test connection qualified (not pinned, v1.9.0)
2026-04-01 12:04 UTC — Live pinning blocked pending Slack approval; proceeding with report

Note: Connection IDs and detailed logs are recorded in the linked private issue.


Devin session

@vai-airbyte Vai Ignatavicius (vai-airbyte) marked this pull request as ready for review April 1, 2026 16:42
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

↪️ Triggering /ai-review per Hands-Free AI Triage Project triage next step.

Reason: CI passing, /ai-prove-fix completed with regression tests passing. Ready for automated review.
https://github.com/airbytehq/oncall/issues/11838

Devin session

@octavia-bot
Copy link
Copy Markdown
Contributor

octavia-bot bot commented Apr 2, 2026

AI PR Review starting...

Reviewing PR for connector safety and quality.
View playbook

Devin AI session created successfully!

@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

devin-ai-integration bot commented Apr 2, 2026

🔍 AI PR Review — source-sftp-bulk

Review Action: NO ACTION — All gates pass. Functional code changes require human reviewer sign-off (not auto-approve eligible).

HEAD SHA: 32060482eb1666ba52d320113c1088bc7746f37a

Gate Summary

# Gate Category Result
1 PR Hygiene Code Quality ✅ PASS
2 Code Hygiene Code Quality ✅ PASS
3 Test Coverage Code Quality ✅ PASS
4 Code Security Code Quality ✅ PASS
5 Per-Record Performance Code Quality ✅ PASS
6 Breaking Dependencies Code Quality ✅ PASS
7 Backwards Compatibility Anti-Pattern ✅ PASS
8 Forwards Compatibility Anti-Pattern ✅ PASS
9 Behavioral Changes Anti-Pattern ✅ PASS
10 Out-of-Scope Changes Anti-Pattern ✅ PASS
11 CI Checks Evidence ✅ PASS
12 Live / E2E Tests Evidence ✅ PASS

Result: 12/12 PASS | Auto-approve eligible: No (functional code changes)


Code Quality Gate Details

Gate 1: PR Hygiene ✅ PASS

  • PR Description: Detailed and well-structured (>50 chars after stripping). Includes What/How/Review Guide/User Impact/Revert Safety sections.
  • Linked Issue: airbytehq/oncall#11838
  • Docs Changelog: docs/integrations/sources/sftp-bulk.md updated with changelog entry for v1.9.1.
  • Peer Feedback: Code quality bot flagged unused import io in test file — addressed in commit b3844bf.

Gate 2: Code Hygiene ✅ PASS

  • Source code modified: source_sftp_bulk/client.py
  • Tests modified: unit_tests/client_test.py — 5 new test functions added.
  • Test-to-code ratio is appropriate for the scope of changes.

Gate 3: Test Coverage ✅ PASS

  • This is a bug fix (fix/ prefix, linked issue) — behavioral change requires tests.
  • New tests cover:
    • test_parse_private_key_auto_detects_key_type — parametrized across RSA, Ed25519, ECDSA, DSS
    • test_parse_private_key_unrecognized_format_raises_config_error
    • test_parse_private_key_catches_value_error
    • test_client_with_private_key_calls_parse
    • test_client_without_private_key_skips_parse

Gate 4: Code Security ✅ PASS

  • No auth/credential file patterns in diff.
  • Private keys handled as opaque strings passed to paramiko — no key content logged or exposed.
  • Error messages do not leak key material.

Gate 5: Per-Record Performance ✅ PASS

  • _parse_private_key() is called once during client initialization, not per-record.
  • No per-record iteration changes introduced.

Gate 6: Breaking Dependencies ✅ PASS

  • No dependency changes in pyproject.toml (only version bump 1.9.0 → 1.9.1).
  • No new packages added.
Anti-Pattern Gate Details

Gate 7: Backwards Compatibility ✅ PASS

  • No spec file modifications (no spec.json, spec.yaml, or spec section changes).
  • No new required fields, no removed properties.
  • RSA key users unaffected — RSAKey is tried first in _KEY_CLASSES list.

Gate 8: Forwards Compatibility ✅ PASS

  • No state/cursor/pagination changes.
  • No stream discovery or catalog changes.

Gate 9: Behavioral Changes ✅ PASS

  • No rate limit/retry/timeout changes.
  • Error handling improved: unrecognized key formats now raise AirbyteTracedException with FailureType.config_error instead of raw struct.error.
  • Exception catching scope is conservative: only paramiko.SSHException and ValueError.

Gate 10: Out-of-Scope Changes ✅ PASS

  • All changes scoped to source-sftp-bulk connector.
  • Files modified: client.py, client_test.py, metadata.yaml, pyproject.toml, sftp-bulk.md.
  • No cross-connector or platform changes.
Evidence Gate Details

Gate 11: CI Checks ✅ PASS

  • Core CI: 43 passed, 9 skipped, 0 pending.
  • Connector tests: 58 tests, 56 passed, 2 skipped, 0 failed.
  • Failed check: pre-release publish validation (docs template sections "For Airbyte Cloud:" / "For Airbyte Open Source:" missing) — excluded per playbook (pre-release checks are not core CI).

Gate 12: Live / E2E Tests ✅ PASS

  • Validation required: Yes (bug fix with fix/ prefix).
  • Pre-release published: airbyte/source-sftp-bulk:1.9.1-preview.b3844bf (confirmed in prod registry).
  • Regression tests: PASSED (Workflow Run #23846982244).
  • MCP verification: Pre-release version 1.9.1-preview.b3844bf (version_id: bee6720f-73c4-453d-a25f-64ce047d92f4) confirmed published 2026-04-01. No pinned production syncs found (live pinning pending human approval).
  • Prove-fix evidence: Fix Validation Evidence comment confirms regression tests passed with no regressions for existing RSA-key connections.
Scope & Auto-Approve Assessment
  • In-scope: Yes — connector-only changes.
  • Auto-approve eligible: No — PR contains functional code changes (client.py adds _parse_private_key() helper with new key type detection logic). Only docs-only, additive spec, patch/minor deps, or comment/whitespace-only changes are eligible for auto-approval.
  • Review action: NO ACTION — All gates pass, but human reviewer sign-off required for functional code changes.

Devin session

… checks

Co-Authored-By: alfredo.garcia@airbyte.io <freddy.garcia7.fg@gmail.com>
…e Open Source

Co-Authored-By: alfredo.garcia@airbyte.io <freddy.garcia7.fg@gmail.com>
@agarctfi
Copy link
Copy Markdown
Contributor

Alfredo Garcia (agarctfi) commented Apr 2, 2026

/ai-canary-prerelease

AI Canary Prerelease Started

Rolling out to 5-10 connections, watching results, and reporting findings.
View workflow run
🐤 AI Canary Prerelease session starting... Rolling out to 5-10 connections, watching results, and reporting findings. View playbook

Devin AI session created successfully!

@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🐤 AI Canary Prerelease: Starting

Connector: source-sftp-bulk
PR: #75967

Beginning canary prerelease testing. I will:

  1. Evaluate breaking change / reversibility safety gates
  2. Select 5-10 canary connections
  3. Request approval and pin connections to the prerelease version
  4. Monitor sync results and report findings

Session: https://app.devin.ai/sessions/f849d5093d7046289bc5c6ab5371309c

Updates will follow as testing progresses.

@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

Canary Prerelease Update — Connections Pinned

Connector: source-sftp-bulk
Prerelease Version: 1.9.1-preview.b3844bf
Previous Version: 1.9.0 (all connections)
Approval: Approved by Alfredo Garcia (@agarctfi) via Slack HITL

Safety Gates

  • Breaking Change Gate: PASS — PATCH version bump, no schema/spec/stream/state changes
  • Reversibility Gate: PASS — fully reversible, no state format changes

Canary Connections (8 total, 6 customers, 2 regions)

Reference Region Destination Status
Customer-A-US-1 US Snowflake Pinned
Customer-A-US-2 US Snowflake Pinned
Customer-B-EU-1 EU PostgreSQL Pinned
Customer-B-EU-2 EU BigQuery Pinned
Customer-C-EU-1 EU BigQuery Pinned
Customer-D-US-1 US Databricks Pinned
Customer-F-US-1 US S3 Pinned
Customer-G-EU-1 EU BigQuery Pinned

All 8 connections successfully pinned to 1.9.1-preview.b3844bf. Now monitoring sync results. Will post updates every 1-2 hours.


Devin session

@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

Canary Prerelease Update — 1-Hour Check-In

Connector: source-sftp-bulk
Prerelease Version: 1.9.1-preview.b3844bf
Monitoring Period: 46 minutes (16:04 – 16:50 UTC)

Results So Far

Reference Region Destination Post-Pin Syncs Succeeded Failed
Customer-A-US-1 US Snowflake 3 3 0
Customer-A-US-2 US Snowflake 3 3 0
Customer-B-EU-1 EU PostgreSQL 3 3 0
Customer-B-EU-2 EU BigQuery 0
Customer-C-EU-1 EU BigQuery 1 1 0
Customer-D-US-1 US Databricks 1 1 0
Customer-F-US-1 US S3 1 1 0
Customer-G-EU-1 EU BigQuery 1 1 0

Summary: 13 post-pin syncs completed, 13/13 succeeded (100%), 0 failures. 7/8 connections have completed at least one sync on the prerelease version. Customer-B-EU-2 has not yet triggered a sync (likely on a longer schedule).

No errors, warnings, or regressions observed. Continuing to monitor for at least 1 more hour before issuing final verdict.


Devin session

@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

Canary Prerelease Final Report — source-sftp-bulk v1.9.1-preview.b3844bf

Verdict: ✅ PASS

Connector: source-sftp-bulk
Prerelease Version: 1.9.1-preview.b3844bf
Monitoring Period: 101 minutes (16:04 – 17:45 UTC, 2026-04-02)
Connections Tested: 8 across 6 customers, 2 regions (US + EU)

Results

Reference Region Destination Post-Pin Syncs Succeeded Failed Success Rate
Customer-A-US-1 US Snowflake 6 6 0 100%
Customer-A-US-2 US Snowflake 5 5 0 100%
Customer-B-EU-1 EU PostgreSQL 7 6 0 100%
Customer-B-EU-2 EU BigQuery 1 1 0 100%
Customer-C-EU-1 EU BigQuery 2 1 0 100%
Customer-D-US-1 US Databricks 2 2 0 100%
Customer-F-US-1 US S3 2 2 0 100%
Customer-G-EU-1 EU BigQuery 2 2 0 100%
TOTAL 27 25 0 100%

2 syncs currently running at time of report

Summary

  • 25/25 completed post-pin syncs succeeded (100% success rate)
  • 8/8 connections completed at least one sync on the prerelease version
  • 0 failures, 0 regressions, 0 new error patterns
  • Tested across 5 destination types (Snowflake, PostgreSQL, BigQuery, Databricks, S3)
  • Tested across 2 regions (US, EU)
  • No performance degradation observed

Recommendation

Proceed to formal release. The prerelease version 1.9.1-preview.b3844bf has been validated across a diverse set of production connections with zero failures. The fix for non-RSA private key support (Ed25519, ECDSA, DSS) does not introduce any regressions to existing RSA-based connections.

Cleanup

All 8 canary connections remain pinned to 1.9.1-preview.b3844bf. Pins will be removed after this PR is merged and the GA version is published.


Devin session

@agarctfi Alfredo Garcia (agarctfi) merged commit b7d8bdd into master Apr 2, 2026
43 checks passed
@agarctfi Alfredo Garcia (agarctfi) deleted the devin/1775035127-fix-sftp-bulk-key-types branch April 2, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants