Skip to content

03 - Target Configuration

This section explains how plugins receive target configuration.

What is a Target?

A target uniquely identifies a deployment location for your infrastructure. Think of it as "where" your resources live:

  • For AWS: a region like us-east-1
  • For Kubernetes: a cluster endpoint
  • For SFTP: a server URL like sftp://files.example.com:22

Targets are stored in formae's database in plaintext, so they must never contain secrets. The target identifies the location; credentials are provided separately.

Target vs Credentials

Target Credentials
Purpose Identifies deployment location Authenticates to the location
Storage Plaintext in database Environment variables / secrets
Example (SFTP) sftp://files.example.com:22 Username, password
Example (AWS) us-east-1 Access key, secret key

Target Configuration in Requests

Every request to your plugin includes a TargetConfig field:

type CreateRequest struct {
    ResourceType string
    Properties   json.RawMessage
    TargetConfig json.RawMessage  // <-- Target configuration (no secrets!)
}

Define the Target Config Type

For our SFTP plugin, the target is just the server URL. Add this to sftp.go:

// TargetConfig holds SFTP target settings.
// Contains only the deployment location, NOT credentials.
type TargetConfig struct {
    URL string `json:"url"` // sftp://host:port
}

func parseTargetConfig(data json.RawMessage) (*TargetConfig, error) {
    var cfg TargetConfig
    if err := json.Unmarshal(data, &cfg); err != nil {
        return nil, fmt.Errorf("invalid target config: %w", err)
    }
    if cfg.URL == "" {
        return nil, fmt.Errorf("target config missing 'url'")
    }
    return &cfg, nil
}

func parseURL(sftpURL string) (host string, port string, err error) {
    u, err := url.Parse(sftpURL)
    if err != nil {
        return "", "", fmt.Errorf("invalid URL: %w", err)
    }
    if u.Scheme != "sftp" {
        return "", "", fmt.Errorf("expected sftp:// URL, got %s://", u.Scheme)
    }
    host = u.Hostname()
    port = u.Port()
    if port == "" {
        port = "22"
    }
    return host, port, nil
}

Update sftp.go

Add the target configuration and credentials code. Update the imports and add the helper functions:

package main

import (
    "context"
    "encoding/json"
    "errors"
    "fmt"
    "net/url"
    "os"

    "github.com/platform-engineering-labs/formae/pkg/plugin"
    "github.com/platform-engineering-labs/formae/pkg/plugin/resource"
)

// TargetConfig holds SFTP target settings.
// Contains only the deployment location, NOT credentials.
type TargetConfig struct {
    URL string `json:"url"` // sftp://host:port
}

func parseTargetConfig(data json.RawMessage) (*TargetConfig, error) {
    var cfg TargetConfig
    if err := json.Unmarshal(data, &cfg); err != nil {
        return nil, fmt.Errorf("invalid target config: %w", err)
    }
    if cfg.URL == "" {
        return nil, fmt.Errorf("target config missing 'url'")
    }
    return &cfg, nil
}

func parseURL(sftpURL string) (host string, port string, err error) {
    u, err := url.Parse(sftpURL)
    if err != nil {
        return "", "", fmt.Errorf("invalid URL: %w", err)
    }
    if u.Scheme != "sftp" {
        return "", "", fmt.Errorf("expected sftp:// URL, got %s://", u.Scheme)
    }
    host = u.Hostname()
    port = u.Port()
    if port == "" {
        port = "22"
    }
    return host, port, nil
}

func getCredentials() (username, password string, err error) {
    username = os.Getenv("SFTP_USERNAME")
    password = os.Getenv("SFTP_PASSWORD")
    if username == "" || password == "" {
        return "", "", fmt.Errorf("SFTP_USERNAME and SFTP_PASSWORD must be set")
    }
    return username, password, nil
}

// ... rest of Plugin implementation

Verify

To verify that the target configuration code compiles correctly:

cd formae-plugin-sftp
make build

Next: 04 - Plugin Configuration