Skip to content

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 File resource 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:

  1. Write a failing test
  2. Implement the code to make it pass
  3. 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.