Tutorial: Build an SFTP Plugin
This tutorial walks you through building a complete formae plugin that manages files on an SFTP server. By the end, you'll have a production-ready plugin with:
- A
Fileresource type with mutable and immutable properties - Full CRUD operations (Create, Read, Update, Delete)
- Discovery to find existing files on the server
- Integration tests and conformance tests
- CI configuration for GitHub Actions
Prerequisites
Before starting, ensure you have:
- Go 1.25 or later -
go version - PKL CLI - Installation guide
- formae CLI - Installed and accessible in your PATH
- Docker - For running the test SFTP server
Test Server Setup
We'll use a Docker-based SFTP server for development and testing:
docker run -p 2222:22 -d --name sftp-test atmoz/sftp testuser:testpass:::upload
This creates an SFTP server with:
- Host: localhost
- Port: 2222
- Username: testuser
- Password: testpass
- Writable directory: /upload
Verify it's running:
sftp -P 2222 testuser@localhost
# Enter password: testpass
# sftp> ls
# sftp> exit
Tutorial Structure
This tutorial uses test-driven development (TDD). For each CRUD operation, we'll:
- Write a failing test
- Implement the code to make it pass
- Refactor if needed
| Section | What You'll Learn |
|---|---|
| 01 - Project Scaffold | Initialize the plugin project structure |
| 02 - Resource Schema | Define the File resource in PKL |
| 03 - Target Configuration | Configure SFTP connection settings |
| 04 - Plugin Configuration | Implement RateLimit and LabelConfig |
| 05 - Create | Implement file creation (async pattern) |
| 06 - Read | Implement file reading (NotFound semantics) |
| 07 - Update | Implement file updates |
| 08 - Delete | Implement file deletion (NotFound semantics) |
| 09 - List | Implement List for file discovery |
| 10 - Error Handling | OperationErrorCode patterns |
| 11 - Conformance & CI | Conformance tests and GitHub Actions |
| 12 - CI Setup | Setting up CI/CD pipelines |
| 13 - Local Testing | Testing plugins locally |
| 14 - Observability | Logging and metrics for plugins |
| 15 - Real-World Plugins | Examples from production plugins |
The asyncsftp Library
SFTP operations are inherently synchronous (blocking I/O), but formae's plugin SDK supports an async pattern for long-running operations. We provide an asyncsftp library that wraps the standard SFTP client with an async interface:
// Start an upload (returns immediately)
opID, err := client.StartUpload(path, content)
// Poll for completion
status, err := client.GetStatus(opID)
if status.State == asyncsftp.StateCompleted {
// Operation finished
}
This pattern is common when integrating with infrastructure APIs. The library handles the complexity internally - your plugin code just uses the clean async interface.
Source Code
The complete source code for this tutorial is available at:
github.com/platform-engineering-labs/formae-plugin-sftp
Ready? Let's start with 01 - Project Scaffold.