porter

package module
v0.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 15, 2026 License: MIT Imports: 24 Imported by: 0

README

Porter

Go Reference CI Go Report Card

A declarative deployment system for Go. Porter "carries" files and commands to remote servers over SSH.

Installation

go get github.com/booyaka101/porter

Quick Start

package main

import (
    "log"
    "github.com/booyaka101/porter"
)

func main() {
    // Connect to remote server
    client, err := porter.Connect("192.168.1.100", porter.DefaultConfig("user", "password"))
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    // Define tasks
    tasks := porter.Tasks(
        porter.Upload("/local/app", "/remote/app"),
        porter.Chmod("/remote/app").Mode("755"),
        porter.Svc("myapp").Restart(),
        porter.WaitForPort("127.0.0.1", "8080").Timeout("30s"),
    )

    // Execute
    vars := porter.NewVars()
    vars.Set("version", "1.0.0")

    executor := porter.NewExecutor(client, "password")
    stats, err := executor.Run("Deploy App", tasks, vars)
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("Completed: %d OK, %d Changed, %d Failed", stats.OK, stats.Changed, stats.Failed)
}

Features

  • Declarative DSL - Fluent API for defining deployment tasks
  • SSH/SFTP - Secure file transfers and command execution
  • Retry Logic - Automatic retries with configurable delays
  • Conditional Tasks - Execute tasks based on variables
  • Loop Support - Iterate over lists of items
  • Health Checks - Wait for ports, HTTP endpoints, or files
  • Output Capture - Store command output in variables
  • Systemd Integration - Manage services (user and system)
  • Journalctl Support - Retrieve and analyze systemd logs with shell injection protection
  • Docker Support - Container and Compose management
  • Template Expansion - Variable substitution in files and commands
  • Idempotent Operations - Skip tasks when target path exists with Creates()
Modern (2026) capabilities
  • Verified host keys - TOFU by default (pins on first use, rejects changed keys as MITM); SetHostKeyMode(HostKeyStrict) and TrustHostCA() for step-ca host certificates. No more InsecureIgnoreHostKey.
  • SSH certificate auth - ConnectWithCert() for short-lived certs (step-ca / Vault SSH / Teleport); keepalives via StartKeepalive(); non-default Config.Port.
  • Bastion / ProxyJump - ConnectViaJump(target, jumps...) tunnels through one or more bastions without exposing an SSH agent on intermediate hosts; host keys verified at every hop.
  • Local→host file transfer - Upload(local, remote) streams a control-machine file (binary, image tar, key) over SFTP with .Mode()/.Owner()/.Sudo(); Run(cmd).StdinFile(local) pipes a local file into a remote command's stdin with zero disk staging (e.g. docker load).
  • Trust-store install - TrustCA(path).As(name) installs a CA already on the host; TrustCAContent(pem).As(name) installs an in-memory PEM CA in one step (write + update-ca-certificates) for fleets that distribute their own root.
  • Declarative state - EnsureFile/EnsureDir/EnsureSymlink/EnsurePackage/EnsureLine/EnsureSystemdKey/EnsureServiceRunning/EnsureServiceEnabled/EnsureCron/EnsureUser/EnsureMode/EnsureOwner/EnsureAbsent/EnsureGitRepo gather a fact, diff, and no-op when already converged (pyinfra-style; EnsureCron/EnsureUser fix the duplicate-append / non-idempotent gaps of CronAdd/UserAdd; EnsureSystemdKey inserts a directive under the right [section] instead of appending a stray line). A real SetDryRun(true) previews exactly what would change.
  • Health assertions (Goss-style) - AssertServiceActive/AssertServiceEnabled/AssertProcessRunning/AssertPortListening/AssertFileExists/AssertFileContains/AssertPackageInstalled/AssertHTTPStatus/AssertCommandSucceeds/AssertCertValid fail the deploy if reality doesn't match (post-deploy smoke test or pre-flight guard).
  • Post-quantum SSH - the underlying x/crypto/ssh negotiates mlkem768x25519-sha256 (ML-KEM hybrid) by default when both ends support it (OpenSSH ≥ 10.0).
  • Atomic releases & rollback - NewRelease(base).HealthCheck(cmd).Deploy(...) deploys into a timestamped dir, health-checks, then flips current via an atomic rename(2); Rollback(base) reverts in one step. (Kamal-style, but for plain systemd/VM targets.)
  • Deploy-as-a-trace - SetTracer(NewTracer(w, env, service)) records each deploy as an OpenTelemetry-shaped span tree (JSONL); SetLogger() adds structured logs with trace_id correlation. The web UI records every deploy to <dataDir>/traces/ and serves a waterfall viewer at /traces.
  • Secrets (SOPS+age + pluggable) - Secret(sopsFile, dest) decrypts locally and ships the plaintext over SFTP at 0600 — never in a shell command, never logged. SecretCommand(fetchCmd, dest) does the same for any backend with a CLI (Vault, OpenBao, 1Password, Infisical).
  • Supply-chain gate - VerifyBlob/VerifyImage run cosign verify as a pre-deploy admission gate; an unsigned/untampered-failed artifact aborts the deploy.
  • Meaningful change accounting - the RECAP changed= count now reflects real mutations (read-only and converged tasks report ok, not changed).
  • Audited commands - the shell each action emits is reviewed against 2026 practice: apt runs non-interactively, tar is quiet in automation, curl blocks https→http downgrade on redirect. Docker runs can opt into service hardening with .Restart(), .Init(), .LogRotate().

See examples/modern/main.go for an end-to-end deploy using all of the above.

Web UI security

The dashboard now enforces JWT auth by default (set PORTER_AUTH=0 only on a fully trusted isolated network; the wiring previously didn't apply the middleware at all); WebSocket upgrades and SSE streams are origin-checked (PORTER_ALLOWED_ORIGINS for cross-origin frontends); machine-to-machine agent channels take an optional shared secret (PORTER_AGENT_TOKEN) so they can be locked down independently of human auth; stored credentials encrypt/decrypt fail closed; the default admin password is random (or PORTER_ADMIN_PASSWORD), logged once.

DSL Reference

File Operations
porter.Upload(src, dest)           // Upload local file to remote
porter.Copy(src, dest)             // Copy remote file
porter.Move(src, dest)             // Move remote file
porter.Write(dest, content)        // Write content to file
porter.Mkdir(path)                 // Create directory
porter.Rm(path)                    // Remove file/directory
porter.Chmod(path).Mode("755")     // Change permissions
porter.Chown(path).Owner("user")   // Change ownership
porter.Symlink(src, dest)          // Create symlink
porter.Template(dest, content)     // Write with variable expansion
Commands
porter.Run("echo hello")           // Run command
porter.Run("apt update").Sudo()    // Run with sudo
porter.Capture("hostname")         // Capture output to variable
Services (Systemd)
porter.Svc("nginx").Start()        // Start service
porter.Svc("nginx").Stop()         // Stop service
porter.Svc("nginx").Restart()      // Restart service
porter.Svc("nginx").Enable()       // Enable service
porter.Svc("app").Start().User()   // User service (systemctl --user)
porter.DaemonReload()              // Reload systemd
Service File Management

Idempotent helpers for managing systemd service files:

// Escape special characters for sed replacement strings
escaped := porter.EscapeSed("/path/with&special")  // "\/path\/with\&special"

// Update a service parameter while preserving quote style
// Works with both -port=3099 and -port="3099"
porter.UpdateServiceParamTask("/etc/systemd/system/myapp.service", "port", "8080")

// Full service file management (create if missing, update params if exists)
tasks := porter.ManageServiceFile(porter.ServiceFileConfig{
    Name:     "myapp",
    Template: appServiceTemplate,
    IsUser:   true,  // ~/.config/systemd/user/ (false = /etc/systemd/system/)
    Params: map[string]string{
        "port": "8080",
        "host": "0.0.0.0",
    },
    When: porter.IfEquals("env", "production"),  // Optional: condition for all tasks
})

// With automatic daemon-reload and service restart
tasks := porter.ManageServiceFileWithReload(porter.ServiceFileConfig{
    Name:      "worker",
    Template:  workerTemplate,
    IsUser:    false,
    NeedsSudo: true,  // Use sudo for file operations (always true for system services)
    Params:    map[string]string{"workers": "4"},
    When:      porter.If("deploy_worker"),  // Only deploy if flag is set
})
Logs (Journalctl)
// Get logs for a specific service
porter.JournalUnit("nginx").Lines("100").Sudo().Register("logs")

// Filter by time and priority
porter.JournalUnit("myapp").
    Since("1 hour ago").
    Priority("err").
    Sudo().
    Register("errors")

// Search logs with pattern (shell-escaped)
porter.JournalUnit("docker").Grep("error|failed").Lines("200").Sudo()

// Kernel logs
porter.Journal().Kernel().Lines("50").Sudo()

// JSON output for parsing
porter.JournalUnit("app").Output("json").Lines("10").Sudo()

// Additional options
.Boot("")              // Current boot logs
.Reverse()             // Newest first
.UTC()                 // UTC timestamps
.Catalog()             // Add explanatory help texts
.Dmesg()               // Kernel ring buffer
.User()                // User-level systemd

See JOURNALCTL_EXAMPLES.md for comprehensive examples and troubleshooting patterns.

Docker
porter.Docker("nginx").Start()     // Start container
porter.Docker("nginx").Stop()      // Stop container
porter.Docker("nginx").Restart()   // Restart container
porter.Docker("nginx").Remove()    // Remove container
porter.DockerPull("nginx:latest")  // Pull image

porter.Compose("/path").Up()       // docker compose up
porter.Compose("/path").Down()     // docker compose down
porter.Compose("/path").Pull()     // docker compose pull
Rsync
// Ensure rsync is installed
porter.RsyncInstall()              // Auto-detect package manager
porter.RsyncCheck()                // Check if installed
porter.RsyncVersion()              // Get version
porter.RsyncEnsure()               // Install only if missing

// Basic sync
porter.Rsync("./src/", "/dest/").Build()

// With options
porter.Rsync("./src/", "/dest/").
    Delete().                      // Remove extraneous files
    Exclude("*.log,*.tmp,.git").   // Exclude patterns
    Include("*.go,*.mod").         // Include patterns
    Progress().                    // Show progress
    Checksum().                    // Use checksum verification
    Partial().                     // Keep partial files
    BwLimit("1000").               // Bandwidth limit (KB/s)
    DryRun().                      // Preview only
    Sudo().                        // Run with sudo
    Build()

// Local-to-remote sync (runs rsync on local machine with SSH destination)
// Useful for Docker environments where you can't SSH into the container
porter.Rsync("/local/path/", "/remote/path/").
    Local().                       // Run rsync locally, sync to remote via SSH
    SSHPort("2222").               // Custom SSH port (optional)
    SSHKey("~/.ssh/id_rsa").       // SSH key path (optional)
    Delete().
    Build()

// Custom flags
porter.Rsync("./src/", "/dest/").Flags("-rlptD").NoCompress().Build()
Wait/Health Checks
porter.WaitForPort("127.0.0.1", "8080").Timeout("30s")
porter.WaitForHttp("http://localhost/health").ExpectCode("200")
porter.WaitForFile("/var/run/app.pid").Timeout("10s")
Conditions
porter.If("enabled")               // True if var is "true"
porter.IfNot("disabled")           // True if var is not "true"
porter.IfSet("version")            // True if var is set (non-empty)
porter.IfNotSet("version")         // True if var is not set (empty)
porter.IfEquals("env", "prod")     // True if var equals value
porter.IfNotEquals("env", "dev")   // True if var does not equal value
porter.And(cond1, cond2)           // All conditions true
porter.Or(cond1, cond2)            // Any condition true
porter.Not(cond)                   // Negate condition
Task Options
task.When(porter.If("enabled"))    // Conditional execution
task.Loop("a", "b", "c")           // Loop over items (use {{item}})
task.Retry(3)                      // Retry on failure
task.Timeout("30s")                // Set timeout
task.Ignore()                      // Ignore errors
task.Name("My Task")               // Set display name
task.Register("result")            // Store output in variable
task.Creates("/path/to/file")      // Skip if path exists (idempotent)
Idempotent Operations with Creates

Use Creates() to skip tasks when a path already exists on the remote server. This keeps logs clean for idempotent operations:

porter.Mkdir("/var/data").Creates("/var/data")           // Skip if dir exists
porter.Install("/tmp/app", "/usr/bin/app").Creates("/usr/bin/app")  // Skip if installed
porter.GitClone(repo, "/opt/app").Creates("/opt/app")    // Skip if already cloned

Variables

vars := porter.NewVars()
vars.Set("key", "value")           // Set string
vars.SetBool("enabled", true)      // Set boolean
vars.SetBytes("data", []byte{})    // Set binary data

vars.Get("key")                    // Get string
vars.GetBool("enabled")            // Get boolean
vars.GetBytes("data")              // Get binary data

vars.Expand("Hello {{key}}")       // Expand variables in string
vars.Clear()                       // Clear all variables

Progress Tracking

Track task progress with callbacks:

executor := porter.NewExecutor(client, password)

// Set progress callback
executor.OnProgress(func(p porter.TaskProgress) {
    // p.Index      - 0-based task index
    // p.Total      - Total number of tasks
    // p.Name       - Task name
    // p.Action     - Task action type
    // p.Status     - pending, running, ok, changed, skipped, failed, retrying
    // p.Attempt    - Current attempt (1-based)
    // p.MaxAttempt - Max attempts
    // p.Duration   - Time taken (on completion)
    // p.Error      - Error if failed
    
    // Built-in helpers
    fmt.Printf("%s %s\n", p.ProgressBar(30), p.String())
})

stats, err := executor.Run("Deploy", tasks, vars)
TaskProgress Status Values
  • pending - Task not yet started
  • running - Task currently executing
  • retrying - Task failed, retrying
  • ok - Task completed successfully (no changes)
  • changed - Task completed with changes
  • skipped - Task skipped (condition not met or Creates path exists)
  • failed - Task failed

Example: Full Deployment Manifest

func buildManifest() []porter.Task {
    return porter.Tasks(
        // Stop services
        porter.Svc("app").Stop().Ignore(),
        
        // Upload files
        porter.Upload("/local/app", "/home/app/bin").Retry(2),
        porter.Chmod("/home/app/bin").Mode("755"),
        
        // Configure service
        porter.Template("/etc/systemd/user/app.service", serviceTemplate),
        porter.DaemonReload().User(),
        
        // Start and verify
        porter.Svc("app").Enable().User(),
        porter.Svc("app").Start().User().Retry(2),
        porter.WaitForPort("127.0.0.1", "{{port}}").Timeout("30s"),
    )
}

func deploy(ip, user, pass string) error {
    client, err := porter.Connect(ip, porter.DefaultConfig(user, pass))
    if err != nil {
        return err
    }
    defer client.Close()

    vars := porter.NewVars()
    vars.Set("port", "8080")
    vars.Set("version", "1.2.3")

    executor := porter.NewExecutor(client, pass)
    _, err = executor.Run("Deploy", buildManifest(), vars)
    return err
}

Examples

See the examples directory for complete working examples:

  • basic - Simple deployment workflow
  • docker - Docker and Docker Compose management
  • conditional - Conditions, loops, and variable expansion
  • rsync - File synchronization with rsync
  • systemd - Systemd service file management

Porter UI (Web Interface)

Porter includes a full-featured web interface for managing remote servers. The UI provides:

  • Dashboard - Overview of all machines with health status
  • Interactive Terminal - SSH terminal in the browser
  • File Manager - Browse, edit, upload, and download files
  • Service Manager - Control systemd services
  • Docker Manager - Manage containers, images, and compose stacks
  • Live Logs - Real-time log streaming with filtering
  • System Monitor - CPU, memory, disk, and network graphs
  • Remote Desktop - VNC access via noVNC
  • Script Runner - Execute deployment scripts with progress tracking
  • Network Tools - Ping, traceroute, DNS lookup, port scan
Building and Running
# Build everything (UI + Go binary)
make build

# Run the server
./porter-ui

# Or in development mode
make dev

See web/ui/ for the React frontend and web/ for the dashboard backend.

Docker Deployment

Run Porter as a complete packaged application using Docker:

# Single container with SQLite (default, includes auth)
docker compose up -d

# With MySQL instead of SQLite
docker compose --profile mysql up -d

Access the UI at http://localhost:8069

Authentication is on by default. On first boot a random admin password is generated and printed once in the server log (or set PORTER_ADMIN_PASSWORD). Set PORTER_AUTH=0 only on a fully trusted, isolated network.

Docker Environment Variables
Variable Default Description
PORT 8069 Server port
USE_SQLITE true Use SQLite database (default, embedded)
USE_MYSQL false Use MySQL instead of SQLite
SQLITE_PATH data/porter.db SQLite database file path
DB_HOST localhost MySQL host (when USE_MYSQL=true)
DB_PORT 3306 MySQL port
DB_USER porter MySQL username
DB_PASSWORD - MySQL password
DB_NAME porter MySQL database name
Migrating from MySQL to SQLite

If you have an existing Porter installation using MySQL and want to switch to SQLite:

# Run migration (connects to MySQL, exports to SQLite)
docker run --rm \
  -e MIGRATE_FROM_MYSQL=true \
  -e DB_HOST=your-mysql-host \
  -e DB_USER=porter \
  -e DB_PASSWORD=your-password \
  -e DB_NAME=porter \
  -v porter-data:/app/data \
  porter:latest

# Then start Porter with SQLite
docker compose up -d

Or using the binary directly:

./porter-ui -migrate-mysql \
  -portable

This will migrate all users, machines, scheduled jobs, history, and settings from MySQL to SQLite.

Documentation

Contributing

Contributions are welcome — see CONTRIBUTING.md for the development setup, project layout, and how to add a new action. Please report security issues privately per SECURITY.md.

License

Porter is released under the MIT License.

Documentation

Overview

Package porter provides a declarative deployment system for Go.

Porter "carries" files and commands to remote servers over SSH, using a fluent DSL for defining deployment tasks.

Quick Start

client, err := porter.Connect("192.168.1.100", porter.DefaultConfig("user", "pass"))
if err != nil {
    log.Fatal(err)
}
defer client.Close()

tasks := porter.Tasks(
    porter.Upload("./app", "/home/app/bin"),
    porter.Chmod("/home/app/bin").Mode("755"),
    porter.Svc("app").Restart(),
)

executor := porter.NewExecutor(client, "pass")
stats, err := executor.Run("Deploy", tasks, porter.NewVars())

Shipping a Docker image

Upload pushes a local file to the host (SFTP); StdinFile pipes a local file straight into a remote command without staging it on the target's disk:

tasks := []porter.Task{
    // stage the tar on the host, then load it
    porter.Upload("build/app.tar", "/tmp/app.tar").Build(),
    porter.Run("docker load -i /tmp/app.tar").Sudo().Build(),

    // or, zero-disk: pipe the local tar into `docker load` over stdin
    porter.Run("docker load").StdinFile("build/app.tar").Sudo().Build(),
}

Features

  • Declarative DSL for defining deployment tasks
  • SSH/SFTP file transfers and command execution
  • Verified host keys (TOFU/strict) plus SSH-certificate auth (ConnectWithCert), bastion/ProxyJump (ConnectViaJump) and keepalives
  • Idempotent state primitives (EnsureFile, EnsureService, EnsureCron, ...) that gather a fact, diff, and no-op when already converged
  • Goss-style health assertions (AssertServiceActive, AssertHTTPStatus, ...)
  • Atomic releases with health-gated cutover and rollback (NewRelease, Rollback)
  • Deploy-as-a-trace via NewTracer (OpenTelemetry-shaped spans) and slog
  • Secrets: SOPS+age (Secret) and pluggable backends (SecretCommand)
  • Supply-chain gate: cosign verification (VerifyBlob, VerifyImage)
  • Retry/loop/conditional execution, health checks, variable expansion
  • A real --dry-run that previews exactly what would change

The optional web dashboard lives under web/ and ships as the cmd/porter-ui binary; it is not part of this library's public API.

Index

Constants

View Source
const Version = "0.15.0"

Version is the current version of Porter.

Variables

This section is empty.

Functions

func AgentAuth added in v0.10.0

func AgentAuth() (goph.Auth, error)

AgentAuth builds ssh-agent auth for a Hop.

func Connect

func Connect(ip string, cfg Config) (*goph.Client, error)

Connect establishes an SSH connection to the remote host.

func ConnectViaJump added in v0.10.0

func ConnectViaJump(target Hop, jumps ...Hop) (*goph.Client, error)

ConnectViaJump connects to target by tunnelling through one or more bastion hops (ProxyJump). This is the modern bastion pattern: the connection is proxied hop-by-hop and the target session runs over the tunnel — no SSH agent is forwarded to (and thus exposed on) any intermediate host. Host keys are verified at every hop via HostKeyCallback.

porter.ConnectViaJump(target, bastion)            // single bastion
porter.ConnectViaJump(target, edge, inner)        // chained: edge -> inner -> target

func ConnectWithAgent added in v0.9.0

func ConnectWithAgent(ip string, user string, timeout time.Duration) (*goph.Client, error)

ConnectWithAgent establishes an SSH connection using the SSH agent.

func ConnectWithCert added in v0.10.0

func ConnectWithCert(ip, user, keyPath, certPath, passphrase string, port uint, timeout time.Duration) (*goph.Client, error)

ConnectWithCert establishes an SSH connection authenticating with an SSH user certificate (the modern, short-lived-credential model — e.g. issued by step-ca, Vault SSH, or Teleport). keyPath is the private key; certPath is the matching certificate (step-ca writes it as "<key>-cert.pub"). passphrase may be "" for an unencrypted key. port 0 defaults to 22.

Certificate auth eliminates static-key distribution: the CA signs a cert scoped to a short TTL, so a leaked key expires on its own. Host-key verification still applies (see HostKeyCallback / TrustHostCA).

func ConnectWithKey added in v0.9.0

func ConnectWithKey(ip string, user string, keyPath string, timeout time.Duration) (*goph.Client, error)

ConnectWithKey establishes an SSH connection using a private key file.

func ConnectWithKeyAndPassphrase added in v0.9.0

func ConnectWithKeyAndPassphrase(ip string, user string, keyPath string, passphrase string, timeout time.Duration) (*goph.Client, error)

ConnectWithKeyAndPassphrase establishes an SSH connection using a passphrase-protected key.

func DownloadDir added in v0.9.0

func DownloadDir(client *goph.Client, remoteDir, localDir string) error

DownloadDir downloads an entire directory from the remote server.

func EscapeSed added in v0.6.0

func EscapeSed(value string) string

EscapeSed escapes special characters for sed replacement strings. Use this when passing dynamic values to Sed() to avoid syntax errors.

func HostKeyCallback added in v0.10.0

func HostKeyCallback() ssh.HostKeyCallback

HostKeyCallback returns the ssh.HostKeyCallback porter uses for every connection, honouring the current mode and any registered host CA.

func KeyAuth added in v0.10.0

func KeyAuth(keyPath, passphrase string) (goph.Auth, error)

KeyAuth builds private-key auth for a Hop (passphrase may be "").

func PasswordAuth added in v0.10.0

func PasswordAuth(password string) goph.Auth

PasswordAuth builds password auth for a Hop.

func RunStreaming added in v0.9.0

func RunStreaming(client *goph.Client, cmd string, callback StreamFunc) (string, int, error)

RunStreaming executes a command with real-time output streaming. The callback is called for each line of stdout/stderr output. Returns the combined output, exit code, and any error.

func SSHPing added in v0.9.0

func SSHPing(ip string, cfg Config) (time.Duration, error)

SSHPing checks if a host is reachable via SSH and returns response time.

func SetHostKeyMode added in v0.10.0

func SetHostKeyMode(m HostKeyMode)

SetHostKeyMode sets the global host-key verification policy.

func SetKnownHostsPath added in v0.10.0

func SetKnownHostsPath(path string)

SetKnownHostsPath overrides the known_hosts file porter reads and pins to.

func StartKeepalive added in v0.10.0

func StartKeepalive(client *goph.Client, interval time.Duration) (stop func())

StartKeepalive sends OpenSSH keepalive requests over the connection every interval so a long deploy across an idle or NAT'd link isn't silently dropped. It returns a stop function; call it (e.g. with defer) when the connection is no longer needed. A nil client or non-positive interval is a no-op returning a no-op stop.

func TestConnection added in v0.9.0

func TestConnection(ip string, cfg Config) error

TestConnection tests if an SSH connection can be established. Returns nil if connection succeeds, error otherwise.

func TestConnectionWithKey added in v0.9.0

func TestConnectionWithKey(ip string, user string, keyPath string) error

TestConnectionWithKey tests SSH connection using a key file.

func TrustHostCA added in v0.10.0

func TrustHostCA(path string)

TrustHostCA registers a file of SSH host-CA public keys (the public half of a step-ca host CA, one key per line). When set, hosts presenting a valid certificate signed by that CA are accepted without a known_hosts entry — the modern way to eliminate TOFU. Plain (non-cert) host keys still fall through to known_hosts verification.

func UpdateServiceParam added in v0.6.0

func UpdateServiceParam(paramName, newValue string) string

UpdateServiceParam creates a sed pattern that updates a systemd service parameter while preserving its existing quote style (quoted vs unquoted). For example, updating -port=3099 or -port="3099" will preserve the original format. The pattern matches: -paramName="value" or -paramName=value

func UploadDir added in v0.9.0

func UploadDir(client *goph.Client, localDir, remoteDir string) error

UploadDir uploads an entire directory to the remote server. It creates a tar archive locally, uploads it, and extracts on the remote.

Types

type ActiveSpan added in v0.10.0

type ActiveSpan struct {
	// contains filtered or unexported fields
}

ActiveSpan is an in-flight span; call End to emit it.

func (*ActiveSpan) End added in v0.10.0

func (a *ActiveSpan) End(err error)

End finalises the span with a status ("ok"/"error") and emits it. err, if non-nil, is recorded as the error.message attribute and forces error status.

func (*ActiveSpan) ID added in v0.10.0

func (a *ActiveSpan) ID() string

ID returns the span's id (use as a parent for child spans).

func (*ActiveSpan) SetAttribute added in v0.10.0

func (a *ActiveSpan) SetAttribute(key string, value any)

SetAttribute attaches a key/value to this span only.

type ComposeBuilder

type ComposeBuilder struct {
	// contains filtered or unexported fields
}

ComposeBuilder provides a fluent API for Docker Compose operations.

func Compose

func Compose(path string) ComposeBuilder

Compose creates a compose builder for the specified compose file path.

func (ComposeBuilder) Build

func (c ComposeBuilder) Build() TaskBuilder

Build builds service images.

func (ComposeBuilder) Cp

func (c ComposeBuilder) Cp(src, dest string) TaskBuilder

Cp copies files between container and host.

func (ComposeBuilder) Down

func (c ComposeBuilder) Down() TaskBuilder

Down stops and removes containers.

func (ComposeBuilder) Exec

func (c ComposeBuilder) Exec(service, cmd string) TaskBuilder

Exec executes a command in a running service container.

func (ComposeBuilder) Kill

func (c ComposeBuilder) Kill() TaskBuilder

Kill sends SIGKILL to containers.

func (ComposeBuilder) Logs

func (c ComposeBuilder) Logs() TaskBuilder

Logs retrieves container logs.

func (ComposeBuilder) Pause

func (c ComposeBuilder) Pause() TaskBuilder

Pause pauses containers.

func (ComposeBuilder) Ps

func (c ComposeBuilder) Ps() TaskBuilder

Ps lists containers.

func (ComposeBuilder) Pull

func (c ComposeBuilder) Pull() TaskBuilder

Pull pulls service images.

func (ComposeBuilder) Restart

func (c ComposeBuilder) Restart() TaskBuilder

Restart restarts containers.

func (ComposeBuilder) Rm

func (c ComposeBuilder) Rm() TaskBuilder

Rm removes stopped containers.

func (ComposeBuilder) Run

func (c ComposeBuilder) Run(service, cmd string) TaskBuilder

Run runs a one-off command in a service container.

func (ComposeBuilder) Start

func (c ComposeBuilder) Start() TaskBuilder

Start starts existing containers.

func (ComposeBuilder) Stop

func (c ComposeBuilder) Stop() TaskBuilder

Stop stops running containers.

func (ComposeBuilder) Top

func (c ComposeBuilder) Top() TaskBuilder

Top displays running processes.

func (ComposeBuilder) Unpause

func (c ComposeBuilder) Unpause() TaskBuilder

Unpause unpauses containers.

func (ComposeBuilder) Up

func (c ComposeBuilder) Up() TaskBuilder

Up creates and starts containers.

type Config

type Config struct {
	User, Password string
	Timeout        time.Duration
	Port           uint // SSH port; 0 means the default (22)
}

Config holds SSH connection configuration.

func DefaultConfig

func DefaultConfig(user, password string) Config

DefaultConfig creates a Config with default timeout.

type DockerBuilder

type DockerBuilder struct {
	// contains filtered or unexported fields
}

DockerBuilder provides a fluent API for Docker container operations.

func Docker

func Docker(container string) DockerBuilder

Docker creates a container builder for the named container.

func (DockerBuilder) Exec

func (d DockerBuilder) Exec(cmd string) TaskBuilder

Exec executes a command in a running container.

func (DockerBuilder) Logs

func (d DockerBuilder) Logs() TaskBuilder

Logs retrieves container logs.

func (DockerBuilder) Remove

func (d DockerBuilder) Remove() TaskBuilder

Remove removes a container.

func (DockerBuilder) Restart

func (d DockerBuilder) Restart() TaskBuilder

Restart restarts a container.

func (DockerBuilder) Run

func (d DockerBuilder) Run(image string) TaskBuilder

Run creates and starts a new container from an image.

func (DockerBuilder) Start

func (d DockerBuilder) Start() TaskBuilder

Start starts an existing container.

func (DockerBuilder) Stop

func (d DockerBuilder) Stop() TaskBuilder

Stop stops a running container.

type Executor

type Executor struct {
	// contains filtered or unexported fields
}

Executor runs tasks on a remote server.

func NewExecutor

func NewExecutor(client *goph.Client, password string) *Executor

NewExecutor creates a new Executor.

func (*Executor) OnProgress added in v0.3.0

func (e *Executor) OnProgress(fn ProgressFunc) *Executor

OnProgress sets a callback function that is called for each task state change.

func (*Executor) Run

func (e *Executor) Run(name string, tasks []Task, vars *Vars) (*Stats, error)

Run executes a list of tasks.

func (*Executor) SetDryRun

func (e *Executor) SetDryRun(v bool) *Executor

SetDryRun enables or disables dry-run mode.

func (*Executor) SetLogger added in v0.10.0

func (e *Executor) SetLogger(l *slog.Logger) *Executor

SetLogger attaches a structured logger. One record is emitted per task at completion (action, status, changed, duration, and the trace_id when a Tracer is set — enabling log<->trace correlation). Pass nil to disable.

func (*Executor) SetTracer added in v0.10.0

func (e *Executor) SetTracer(t *Tracer) *Executor

SetTracer attaches a Tracer so the deploy is recorded as a trace (one root span per Run, one child span per task). Pass nil to disable.

func (*Executor) SetVerbose

func (e *Executor) SetVerbose(v bool) *Executor

SetVerbose enables or disables verbose output.

type GoBuilder added in v0.9.0

type GoBuilder struct {
	// contains filtered or unexported fields
}

GoBuilder provides a fluent API for Go build operations.

func Go added in v0.9.0

func Go(path string) GoBuilder

Go creates a Go build task builder.

func (GoBuilder) Build added in v0.9.0

func (g GoBuilder) Build(output string) TaskBuilder

Build compiles the Go package.

func (GoBuilder) ModDownload added in v0.9.0

func (g GoBuilder) ModDownload() TaskBuilder

ModDownload downloads Go module dependencies.

func (GoBuilder) Test added in v0.9.0

func (g GoBuilder) Test() TaskBuilder

Test runs Go tests.

func (GoBuilder) Vet added in v0.9.0

func (g GoBuilder) Vet() TaskBuilder

Vet runs go vet on the package.

type Hop added in v0.10.0

type Hop struct {
	User    string
	Host    string
	Port    uint // 0 -> 22
	Auth    goph.Auth
	Timeout time.Duration
}

Hop describes one SSH endpoint (a bastion or the final target) for a jump-host connection. Build Auth with PasswordAuth / KeyAuth / AgentAuth.

type HostKeyMode added in v0.10.0

type HostKeyMode int

HostKeyMode controls how porter verifies remote SSH host keys.

const (
	// HostKeyTOFU trusts an unknown host on first use, pins it to the
	// known_hosts file, and verifies on every subsequent connection.
	// A key that changes after pinning is a hard failure (possible MITM).
	// This matches OpenSSH's default StrictHostKeyChecking=ask behaviour
	// minus the interactive prompt, and is porter's default.
	HostKeyTOFU HostKeyMode = iota
	// HostKeyStrict refuses any host not already present in known_hosts.
	HostKeyStrict
	// HostKeyInsecure disables verification entirely. Opt-in only; intended
	// for tests and throwaway hosts. Logs nothing — the caller chose this.
	HostKeyInsecure
)

type LogLine added in v0.9.0

type LogLine struct {
	Line      string // The log line content
	Source    string // "journalctl", "tail", or custom identifier
	Timestamp string // Optional timestamp if parsed
	Error     error  // Error if stream encountered an issue
}

LogLine represents a single line from a log stream.

type LogMultiplexer added in v0.9.0

type LogMultiplexer struct {
	// contains filtered or unexported fields
}

LogMultiplexer allows streaming from multiple sources and combining them.

func NewLogMultiplexer added in v0.9.0

func NewLogMultiplexer(callback LogStreamFunc) *LogMultiplexer

NewLogMultiplexer creates a new multiplexer for combining multiple log streams.

func (*LogMultiplexer) Add added in v0.9.0

func (m *LogMultiplexer) Add(stream *LogStream)

Add adds a log stream to the multiplexer.

func (*LogMultiplexer) StopAll added in v0.9.0

func (m *LogMultiplexer) StopAll()

StopAll stops all streams in the multiplexer.

func (*LogMultiplexer) WaitAll added in v0.9.0

func (m *LogMultiplexer) WaitAll()

WaitAll waits for all streams to finish.

type LogStream added in v0.9.0

type LogStream struct {
	// contains filtered or unexported fields
}

LogStream represents an active log streaming session that can be stopped.

func CustomLogStream added in v0.9.0

func CustomLogStream(client *goph.Client, cmd string, source string, callback LogStreamFunc) (*LogStream, error)

CustomLogStream starts streaming output from any command. This is useful for custom log formats or monitoring commands.

func DockerComposeLogs added in v0.9.0

func DockerComposeLogs(client *goph.Client, composePath string, service string, lines int, callback LogStreamFunc) (*LogStream, error)

DockerComposeLogs starts streaming Docker Compose logs.

func DockerLogs added in v0.9.0

func DockerLogs(client *goph.Client, container string, lines int, callback LogStreamFunc) (*LogStream, error)

DockerLogs starts streaming Docker container logs.

func JournalFollow added in v0.9.0

func JournalFollow(client *goph.Client, unit string, lines int, filters string, callback LogStreamFunc) (*LogStream, error)

JournalFollow starts streaming journalctl logs in real-time. Returns a LogStream that can be used to stop the streaming.

Options:

  • unit: systemd unit name (empty for all logs)
  • lines: number of initial lines to show (0 for default)
  • filters: additional journalctl filters (e.g., "--priority=err")

func JournalFollowUser added in v0.9.0

func JournalFollowUser(client *goph.Client, unit string, lines int, filters string, callback LogStreamFunc) (*LogStream, error)

JournalFollowUser starts streaming user-level journalctl logs.

func TailFollow added in v0.9.0

func TailFollow(client *goph.Client, path string, lines int, callback LogStreamFunc) (*LogStream, error)

TailFollow starts streaming a file using tail -f. Returns a LogStream that can be used to stop the streaming.

Options:

  • path: path to the file to tail
  • lines: number of initial lines to show (0 for default 10)

func TailFollowMultiple added in v0.9.0

func TailFollowMultiple(client *goph.Client, paths []string, lines int, callback LogStreamFunc) (*LogStream, error)

TailFollowMultiple starts streaming multiple files using tail -f.

func TailFollowWithSudo added in v0.9.0

func TailFollowWithSudo(client *goph.Client, path string, lines int, password string, callback LogStreamFunc) (*LogStream, error)

TailFollowWithSudo starts streaming a file that requires sudo access.

func (*LogStream) Done added in v0.9.0

func (s *LogStream) Done() <-chan struct{}

Done returns a channel that's closed when the stream finishes.

func (*LogStream) Err added in v0.9.0

func (s *LogStream) Err() error

Err returns any error that occurred during streaming.

func (*LogStream) Stop added in v0.9.0

func (s *LogStream) Stop()

Stop terminates the log streaming session.

func (*LogStream) Wait added in v0.9.0

func (s *LogStream) Wait() error

Wait blocks until the stream finishes (either by Stop() or error).

type LogStreamFunc added in v0.9.0

type LogStreamFunc func(line LogLine)

LogStreamFunc is called for each line received from the log stream.

type NpmBuilder added in v0.9.0

type NpmBuilder struct {
	// contains filtered or unexported fields
}

NpmBuilder provides a fluent API for npm operations.

func Npm added in v0.9.0

func Npm(path string) NpmBuilder

Npm creates an npm task builder for the specified directory.

func (NpmBuilder) Build added in v0.9.0

func (n NpmBuilder) Build() TaskBuilder

Build runs npm run build.

func (NpmBuilder) CI added in v0.9.0

func (n NpmBuilder) CI() TaskBuilder

CI runs npm ci (clean install from lockfile).

func (NpmBuilder) Install added in v0.9.0

func (n NpmBuilder) Install() TaskBuilder

Install runs npm install.

func (NpmBuilder) RunScript added in v0.9.0

func (n NpmBuilder) RunScript(script string) TaskBuilder

RunScript runs a custom npm script.

func (NpmBuilder) Test added in v0.9.0

func (n NpmBuilder) Test() TaskBuilder

Test runs npm test.

type ProgressFunc added in v0.3.0

type ProgressFunc func(TaskProgress)

ProgressFunc is called for each task state change.

type Release added in v0.10.0

type Release struct {
	// contains filtered or unexported fields
}

Release describes an atomic release deploy rooted at a base directory:

<base>/releases/<timestamp>/   the new release (deploy your payload here)
<base>/shared/                 persistent data shared across releases
<base>/current -> releases/..  the live symlink, swapped atomically

func NewRelease added in v0.10.0

func NewRelease(baseDir string) *Release

NewRelease starts a release rooted at baseDir. The release directory is stamped once, now, so every task in this deploy targets the same path.

func (*Release) Activate added in v0.10.0

func (r *Release) Activate() []TaskBuilder

Activate returns the health-check (if any) and the atomic symlink swap. The swap stages the link then renames it over `current`, so the cutover is a single atomic rename(2) — never a window with no `current`.

func (*Release) Current added in v0.10.0

func (r *Release) Current() string

Current is the live symlink path (point your systemd unit / web root here).

func (*Release) Deploy added in v0.10.0

func (r *Release) Deploy(deploySteps ...TaskBuilder) []Task

Deploy assembles the full release sequence ready for Executor.Run: prepare -> your deploySteps (which deploy into r.Dir()) -> health-gated atomic activate -> prune. If any step (including the health check) fails the run aborts before activation, leaving the previous release live.

func (*Release) Dir added in v0.10.0

func (r *Release) Dir() string

Dir is the new release directory — deploy your payload (binary, build output, extracted archive) into this path.

func (*Release) HealthCheck added in v0.10.0

func (r *Release) HealthCheck(cmd string) *Release

HealthCheck sets a command run inside the new release directory before the symlink swap. A non-zero exit aborts the deploy with `current` still pointing at the previous release — health-gated cutover.

func (*Release) Keep added in v0.10.0

func (r *Release) Keep(n int) *Release

Keep sets how many past releases to retain after a deploy (default 5).

func (*Release) Prepare added in v0.10.0

func (r *Release) Prepare() []TaskBuilder

Prepare returns the tasks that create the releases/shared/release dirs.

func (*Release) Prune added in v0.10.0

func (r *Release) Prune() TaskBuilder

Prune returns a task that removes all but the newest Keep release dirs.

func (*Release) Shared added in v0.10.0

func (r *Release) Shared() string

Shared is the cross-release persistent directory (configs, uploads, data).

func (*Release) Sudo added in v0.10.0

func (r *Release) Sudo() *Release

Sudo runs the release's own filesystem operations (mkdir, symlink, prune) with elevated privileges.

type RsyncBuilder added in v0.3.0

type RsyncBuilder struct {
	// contains filtered or unexported fields
}

RsyncBuilder provides a fluent API for building rsync tasks.

func Rsync

func Rsync(src, dest string) RsyncBuilder

Rsync creates a new rsync task from src to dest.

func (RsyncBuilder) Build added in v0.3.0

func (r RsyncBuilder) Build() TaskBuilder

Build returns a TaskBuilder for use with Tasks().

func (RsyncBuilder) BwLimit added in v0.3.0

func (r RsyncBuilder) BwLimit(kbps string) RsyncBuilder

BwLimit limits bandwidth in KB/s.

func (RsyncBuilder) Checksum added in v0.3.0

func (r RsyncBuilder) Checksum() RsyncBuilder

Checksum uses checksum instead of mod-time & size.

func (RsyncBuilder) Delete added in v0.3.0

func (r RsyncBuilder) Delete() RsyncBuilder

Delete enables --delete flag (remove extraneous files from dest).

func (RsyncBuilder) Delta added in v0.3.0

func (r RsyncBuilder) Delta() RsyncBuilder

Delta enables delta-transfer algorithm (only send changed parts of files). This is the key option for faster syncs of large files with small changes.

func (RsyncBuilder) DryRun added in v0.3.0

func (r RsyncBuilder) DryRun() RsyncBuilder

DryRun performs a trial run with no changes made.

func (RsyncBuilder) Exclude added in v0.3.0

func (r RsyncBuilder) Exclude(patterns string) RsyncBuilder

Exclude adds patterns to exclude (comma-separated).

func (RsyncBuilder) Fast added in v0.3.0

func (r RsyncBuilder) Fast() RsyncBuilder

Fast is a convenience method that enables both Inplace and Delta for fastest incremental syncs.

func (RsyncBuilder) Flags added in v0.3.0

func (r RsyncBuilder) Flags(f string) RsyncBuilder

Flags sets custom rsync flags (default: -avz).

func (RsyncBuilder) Ignore added in v0.3.0

func (r RsyncBuilder) Ignore() RsyncBuilder

Ignore ignores errors from this task.

func (RsyncBuilder) Include added in v0.3.0

func (r RsyncBuilder) Include(patterns string) RsyncBuilder

Include adds patterns to include (comma-separated).

func (RsyncBuilder) Inplace added in v0.3.0

func (r RsyncBuilder) Inplace() RsyncBuilder

Inplace updates files in-place (don't create temp file).

func (RsyncBuilder) Local added in v0.4.0

func (r RsyncBuilder) Local() RsyncBuilder

Local runs rsync on the local machine instead of remote, syncing local files to remote via SSH. This is useful for Docker environments where you can't SSH into the container. The destination path will be prefixed with user@host: automatically.

func (RsyncBuilder) Name added in v0.3.0

func (r RsyncBuilder) Name(n string) RsyncBuilder

Name sets a custom name for the task.

func (RsyncBuilder) NoCompress added in v0.3.0

func (r RsyncBuilder) NoCompress() RsyncBuilder

NoCompress disables compression.

func (RsyncBuilder) Partial added in v0.3.0

func (r RsyncBuilder) Partial() RsyncBuilder

Partial keeps partially transferred files.

func (RsyncBuilder) Progress added in v0.3.0

func (r RsyncBuilder) Progress() RsyncBuilder

Progress shows progress during transfer.

func (RsyncBuilder) SSHKey added in v0.4.0

func (r RsyncBuilder) SSHKey(keyPath string) RsyncBuilder

SSHKey sets the SSH key path for local-to-remote rsync (only used with Local()).

func (RsyncBuilder) SSHPort added in v0.4.0

func (r RsyncBuilder) SSHPort(port string) RsyncBuilder

SSHPort sets a custom SSH port for local-to-remote rsync (only used with Local()).

func (RsyncBuilder) Sudo added in v0.3.0

func (r RsyncBuilder) Sudo() RsyncBuilder

Sudo runs rsync with sudo.

func (RsyncBuilder) When added in v0.3.0

func (r RsyncBuilder) When(w When) RsyncBuilder

When sets a condition for execution.

type ServiceFileConfig added in v0.6.0

type ServiceFileConfig struct {
	Name      string            // Service name (e.g., "myapp", "worker")
	Template  string            // Service file template content
	IsUser    bool              // true for user services (~/.config/systemd/user/), false for system (/etc/systemd/system/)
	Params    map[string]string // Parameters to update if service file exists (key=param name, value=new value)
	NeedsSudo bool              // true if template creation needs sudo (always true for system services; sed updates always use sudo)
	When      When              // Optional condition to apply to all generated tasks (combined with internal conditions via And)
}

ServiceFileConfig defines configuration for managing a systemd service file.

type Span added in v0.10.0

type Span struct {
	TraceID    string         `json:"trace_id"`
	SpanID     string         `json:"span_id"`
	ParentID   string         `json:"parent_span_id,omitempty"`
	Name       string         `json:"name"`
	Start      time.Time      `json:"start"`
	End        time.Time      `json:"end"`
	DurationMs int64          `json:"duration_ms"`
	Status     string         `json:"status"` // "ok" or "error"
	Attributes map[string]any `json:"attributes,omitempty"`
}

Span is a single emitted span (OTel-shaped, JSON-serialisable).

type Stats

type Stats struct {
	Total, OK, Changed, Skipped, Failed int
}

Stats holds execution statistics.

type StreamEvent added in v0.9.0

type StreamEvent struct {
	Type string // "stdout", "stderr", "exit", "error"
	Data string // Line of output or error message
	Code int    // Exit code (only for "exit" type)
}

StreamEvent represents a real-time output event during command execution.

type StreamFunc added in v0.9.0

type StreamFunc func(event StreamEvent)

StreamFunc is called for each line of output during streaming execution.

type StreamingExecutor added in v0.9.0

type StreamingExecutor struct {
	*Executor
	// contains filtered or unexported fields
}

StreamingExecutor wraps an Executor with streaming capabilities.

func NewStreamingExecutor added in v0.9.0

func NewStreamingExecutor(client *goph.Client, password string) *StreamingExecutor

NewStreamingExecutor creates an executor that streams output.

func (*StreamingExecutor) OnOutput added in v0.9.0

OnOutput sets a callback for real-time output streaming.

func (*StreamingExecutor) RunWithStreaming added in v0.9.0

func (e *StreamingExecutor) RunWithStreaming(cmd string) (string, int, error)

RunWithStreaming executes a single command with streaming output. This is useful for long-running scripts where you want real-time feedback.

type SvcBuilder

type SvcBuilder struct {
	// contains filtered or unexported fields
}

SvcBuilder provides a fluent API for systemd service operations.

func Svc

func Svc(name string) SvcBuilder

Svc creates a service builder for the named systemd unit.

func (SvcBuilder) Disable added in v0.9.0

func (s SvcBuilder) Disable() TaskBuilder

Disable disables the service from starting on boot.

func (SvcBuilder) Enable

func (s SvcBuilder) Enable() TaskBuilder

Enable enables the service to start on boot.

func (SvcBuilder) Restart

func (s SvcBuilder) Restart() TaskBuilder

Restart restarts the service.

func (SvcBuilder) Start

func (s SvcBuilder) Start() TaskBuilder

Start starts the service.

func (SvcBuilder) Status added in v0.9.0

func (s SvcBuilder) Status() TaskBuilder

Status gets the status of the service.

func (SvcBuilder) Stop

func (s SvcBuilder) Stop() TaskBuilder

Stop stops the service.

type Task

type Task struct {
	Name      string        // Display name for the task
	Action    string        // Action type (e.g., "upload", "run", "service")
	Src       string        // Source path or value
	Dest      string        // Destination path or target
	Body      string        // Command body or content
	State     string        // State for services/containers (start, stop, etc.)
	User      bool          // Use user-level systemd
	Sudo      bool          // Run with sudo
	Rec       bool          // Recursive flag
	Perm      string        // File mode (chmod, write) e.g. "0600"
	Own       string        // Owner spec (chown, write) e.g. "idx:idx"
	When      When          // Condition for execution
	Loop      []string      // Items to loop over
	Ignore    bool          // Ignore errors
	Retry     int           // Retry count on failure
	Delay     time.Duration // Delay between retries
	Timeout   time.Duration // Timeout for wait operations
	Register  string        // Variable name to store output
	Creates   string        // Skip if this path exists
	StdinFile string        // Local file streamed into the command's stdin (Run)
}

Task represents a single deployment action.

func BuildServiceTasks added in v0.7.0

func BuildServiceTasks(cfg ServiceFileConfig) []Task

BuildServiceTasks is an alias for ManageServiceFile that makes the conditional execution pattern more explicit. Use this when you want to emphasize that the When condition controls whether the entire service management workflow runs.

Example:

tasks := porter.BuildServiceTasks(porter.ServiceFileConfig{
    Name:     "myapp",
    Template: appServiceTemplate,
    IsUser:   true,
    Params:   map[string]string{"port": "8080"},
    When:     porter.IfEquals("env", "production"),
})

func ManageServiceFile added in v0.6.0

func ManageServiceFile(cfg ServiceFileConfig) []Task

ManageServiceFile creates a task group that idempotently manages a systemd service file: 1. Checks if the service file exists 2. Creates from template if missing 3. Updates parameters if the file exists

The returned tasks use a variable named "<serviceName>_service_exists" to track state. For user services, tasks are configured with .User(). For system services, tasks use .Sudo().

Example usage:

tasks := porter.ManageServiceFile(porter.ServiceFileConfig{
    Name:     "myapp",
    Template: appServiceTemplate,
    IsUser:   true,
    Params: map[string]string{
        "port": "8080",
        "host": "0.0.0.0",
    },
    When: porter.IfEquals("env", "production"), // Optional: only run in production
})

func ManageServiceFileWithReload added in v0.6.0

func ManageServiceFileWithReload(cfg ServiceFileConfig) []Task

ManageServiceFileWithReload is like ManageServiceFile but also adds daemon-reload and service restart tasks at the end.

func ManageServiceFiles added in v0.8.0

func ManageServiceFiles(configs []ServiceFileConfig) []Task

ManageServiceFiles creates tasks for multiple systemd service files. This is a convenience wrapper that calls ManageServiceFile for each config.

func RsyncEnsure added in v0.3.0

func RsyncEnsure() []Task

RsyncEnsure ensures rsync is installed (installs if not present).

func Tasks

func Tasks(builders ...TaskBuilder) []Task

Tasks converts multiple TaskBuilders into a slice of Tasks. This is the primary way to create task lists for execution.

Example:

tasks := porter.Tasks(
    porter.Upload("app.tar.gz", "/tmp/app.tar.gz"),
    porter.Run("tar -xzf /tmp/app.tar.gz -C /opt"),
    porter.Svc("myapp").Restart(),
)

type TaskBuilder

type TaskBuilder struct {
	// contains filtered or unexported fields
}

TaskBuilder provides a fluent API for building tasks. All DSL functions return a TaskBuilder that can be chained with modifiers.

func AptInstall

func AptInstall(packages ...string) TaskBuilder

AptInstall installs one or more packages.

func AptRemove

func AptRemove(packages ...string) TaskBuilder

AptRemove removes one or more packages.

func AptUpdate

func AptUpdate() TaskBuilder

AptUpdate updates the package index.

func AptUpgrade

func AptUpgrade() TaskBuilder

AptUpgrade upgrades all installed packages.

func AssertCertValid added in v0.13.0

func AssertCertValid(path string, within time.Duration) TaskBuilder

AssertCertValid fails unless the X.509 certificate at path stays valid for at least `within` from now (its NotAfter is more than `within` in the future). Use it as a pre-flight guard ("the leaf cert isn't about to expire, don't deploy on top of a dying one") or a post-renewal smoke test. The check runs on the remote host via `openssl x509 -checkend` (openssl must be installed there); a missing, unreadable, or already-expired cert fails the assertion. Use .Sudo() for a root-only cert path.

porter.AssertCertValid("/var/lib/idxgames/certs/leaf.crt", 30*24*time.Hour)

func AssertCommandSucceeds added in v0.10.0

func AssertCommandSucceeds(cmd string) TaskBuilder

AssertCommandSucceeds fails unless the command exits zero on the remote.

func AssertFileContains added in v0.10.0

func AssertFileContains(file, substr string) TaskBuilder

AssertFileContains fails unless file contains the literal substring.

func AssertFileExists added in v0.10.0

func AssertFileExists(path string) TaskBuilder

AssertFileExists fails unless the path exists on the remote.

func AssertHTTPStatus added in v0.10.0

func AssertHTTPStatus(url, code string) TaskBuilder

AssertHTTPStatus fails unless an HTTP GET of url returns the expected status code (checked from the remote host).

func AssertPackageInstalled added in v0.10.0

func AssertPackageInstalled(name string) TaskBuilder

AssertPackageInstalled fails unless the apt package is installed.

func AssertPortListening added in v0.10.0

func AssertPortListening(port string) TaskBuilder

AssertPortListening fails unless something is listening on the TCP port.

func AssertProcessRunning added in v0.10.0

func AssertProcessRunning(pattern string) TaskBuilder

AssertProcessRunning fails unless a process matching pattern is running (pgrep -f).

func AssertServiceActive added in v0.10.0

func AssertServiceActive(name string) TaskBuilder

AssertServiceActive fails unless the systemd unit is active. .UserMode() for a --user unit.

func AssertServiceEnabled added in v0.10.0

func AssertServiceEnabled(name string) TaskBuilder

AssertServiceEnabled fails unless the systemd unit is enabled at boot.

func Backup

func Backup(path string) TaskBuilder

Backup creates a timestamped backup of a file or directory.

func CPUInfo added in v0.9.0

func CPUInfo() TaskBuilder

CPUInfo gets CPU information. Use .Register("varname") to store the result.

func Capture

func Capture(cmd string) TaskBuilder

Capture executes a command and stores its output in a variable. Use .Register("varname") to specify the variable name.

func CaptureSudo

func CaptureSudo(cmd string) TaskBuilder

CaptureSudo executes a command with sudo and stores its output. Use .Register("varname") to specify the variable name.

func Cat

func Cat(path string) TaskBuilder

Cat reads and outputs file contents.

func Chmod

func Chmod(path string) TaskBuilder

Chmod changes file permissions (use .Mode("755")).

func Chown

func Chown(path string) TaskBuilder

Chown changes file ownership (use .Owner("user:group")).

func CommandExists added in v0.9.0

func CommandExists(cmd string) TaskBuilder

CommandExists checks if a command is available. Use .Register("varname") to store "true" or "false".

func Copy

func Copy(src, dest string) TaskBuilder

Copy copies a file on the remote server.

func CronAdd

func CronAdd(schedule, command string) TaskBuilder

CronAdd adds a cron job with the specified schedule and command. Example: CronAdd("0 * * * *", "/usr/bin/backup.sh")

func CronRemove

func CronRemove(pattern string) TaskBuilder

CronRemove removes cron jobs matching the pattern.

func Curl

func Curl(url, output string) TaskBuilder

Curl downloads a file using curl.

func DaemonReload

func DaemonReload() TaskBuilder

DaemonReload reloads systemd configuration.

func DirExists

func DirExists(path string) TaskBuilder

DirExists checks if a directory exists and stores the result ("true"/"false") in a variable. Use .Register("varname") to specify the variable name.

func DiskSpace added in v0.9.0

func DiskSpace(path string) TaskBuilder

DiskSpace checks available disk space on a path. Use .Register("varname") to store the result in GB.

func DockerBuild

func DockerBuild(path, tag string) TaskBuilder

DockerBuild builds an image from a Dockerfile.

func DockerExport

func DockerExport(container, tarFile string) TaskBuilder

DockerExport exports a container's filesystem to a tar archive.

func DockerImages added in v0.9.0

func DockerImages() TaskBuilder

DockerImages lists images.

func DockerImport

func DockerImport(tarFile, image string) TaskBuilder

DockerImport imports a tar archive as a new image.

func DockerInfo added in v0.9.0

func DockerInfo() TaskBuilder

DockerInfo returns Docker system information.

func DockerLoad

func DockerLoad(tarFile string) TaskBuilder

DockerLoad loads an image from a tar archive.

func DockerNetworks added in v0.9.0

func DockerNetworks() TaskBuilder

DockerNetworks lists networks.

func DockerPrune

func DockerPrune() TaskBuilder

DockerPrune removes unused Docker resources.

func DockerPs added in v0.9.0

func DockerPs() TaskBuilder

DockerPs lists containers. Use .All() to include stopped containers.

func DockerPull

func DockerPull(image string) TaskBuilder

DockerPull pulls an image from a registry.

func DockerPush

func DockerPush(image string) TaskBuilder

DockerPush pushes an image to a registry.

func DockerRmi

func DockerRmi(image string) TaskBuilder

DockerRmi removes an image.

func DockerSave

func DockerSave(image, tarFile string) TaskBuilder

DockerSave saves an image to a tar archive.

func DockerTag

func DockerTag(src, dest string) TaskBuilder

DockerTag tags an image with a new name.

func DockerVolumes added in v0.9.0

func DockerVolumes() TaskBuilder

DockerVolumes lists volumes.

func Download

func Download(remotePath string) TaskBuilder

Download downloads a remote file to a local variable (for binary data). Use .Register("varname") to store the file contents.

func EnsureAbsent added in v0.10.0

func EnsureAbsent(path string) TaskBuilder

EnsureAbsent ensures path does NOT exist (removed if present; no-op if already gone). Use .Sudo() for root-owned paths.

func EnsureCron added in v0.10.0

func EnsureCron(schedule, command string) TaskBuilder

EnsureCron ensures a crontab line (schedule + command) is present exactly once. Unlike CronAdd (which appends every run, duplicating the line), this is idempotent: no-op when the line already exists, and the value is escaped.

func EnsureDir added in v0.10.0

func EnsureDir(path string) TaskBuilder

EnsureDir ensures a directory exists at path. No-op if it already exists.

func EnsureFile added in v0.10.0

func EnsureFile(dest, content string) TaskBuilder

EnsureFile ensures dest contains exactly content. The remote file is hashed (SHA-256) and rewritten only if absent or different. Combine with .Mode() and .Owner() to also pin permissions, and .Sudo() for privileged paths.

func EnsureGitRepo added in v0.10.0

func EnsureGitRepo(url, dest string) TaskBuilder

EnsureGitRepo ensures dest is a checkout of url's upstream HEAD: cloned if absent, fast-forwarded (hard reset to upstream) if behind, no-op if already at upstream. A declarative "deploy from git".

func EnsureLine added in v0.10.0

func EnsureLine(file, line string) TaskBuilder

EnsureLine ensures the exact line is present in file (appended if absent). No-op if an identical line already exists. Use .Sudo() for root-owned files.

func EnsureMode added in v0.10.0

func EnsureMode(path, mode string) TaskBuilder

EnsureMode ensures path has exactly the given octal mode (e.g. "0640"). No-op when already correct. Use .Sudo() for root-owned paths.

func EnsureOwner added in v0.10.0

func EnsureOwner(path, owner string) TaskBuilder

EnsureOwner ensures path is owned by owner ("user" or "user:group"). No-op when already correct. Use .Sudo() for root-owned paths.

func EnsurePackage added in v0.10.0

func EnsurePackage(name string) TaskBuilder

EnsurePackage ensures an apt package is installed. No-op if dpkg already reports it installed.

func EnsureServiceEnabled added in v0.10.0

func EnsureServiceEnabled(name string) TaskBuilder

EnsureServiceEnabled ensures a systemd unit is enabled at boot (enabled if not). No-op if already enabled. Use .UserMode() for a --user unit.

func EnsureServiceRunning added in v0.10.0

func EnsureServiceRunning(name string) TaskBuilder

EnsureServiceRunning ensures a systemd unit is active (started if not). No-op if already running. Use .UserMode() for a --user unit.

func EnsureSymlink(src, dest string) TaskBuilder

EnsureSymlink ensures dest is a symlink pointing at src. No-op if it already points there; repointed otherwise.

func EnsureSystemdKey added in v0.14.0

func EnsureSystemdKey(path, section, key, value string) TaskBuilder

EnsureSystemdKey ensures `key=value` exists under the given systemd unit [section] (e.g. "Unit", "Service", "Timer", "Install") of the unit file at path. Unlike EnsureLine, which appends a bare line at end-of-file, this inserts the directive directly after the section header — the only correct place for a systemd key. Idempotent and operator-friendly: if a line starting with `key=` already appears anywhere in the file it is left untouched and the task is a no-op (a hand-edited value wins). The section header must already exist, else the task fails. Use .Sudo() for a unit under /etc/systemd/system, and follow a change with Run("systemctl daemon-reload"). CRLF endings are preserved; surrounding blank lines are normalized.

porter.EnsureSystemdKey("/etc/systemd/system/app.service", "Service", "Restart", "always").Sudo()

func EnsureUser added in v0.10.0

func EnsureUser(username string) TaskBuilder

EnsureUser ensures a user account exists (created if absent; no-op if it already exists — unlike UserAdd, which errors on a second run). Chain .Groups()/.Shell()/.Home() to set properties at creation.

func EnvDelete

func EnvDelete(file, key string) TaskBuilder

EnvDelete removes a key from an environment file.

func EnvSet

func EnvSet(file, key, value string) TaskBuilder

EnvSet sets a key-value pair in an environment file (.env format).

func FileExists

func FileExists(path string) TaskBuilder

FileExists checks if a file exists and stores the result ("true"/"false") in a variable. Use .Register("varname") to specify the variable name.

func GitCheckout

func GitCheckout(path, ref string) TaskBuilder

GitCheckout checks out a specific branch, tag, or commit.

func GitClean added in v0.9.0

func GitClean(path string) TaskBuilder

GitClean removes untracked files.

func GitClone

func GitClone(repo, dest string) TaskBuilder

GitClone clones a repository to the specified path.

func GitDescribe added in v0.9.0

func GitDescribe(path string) TaskBuilder

GitDescribe gets version info from tags.

func GitFetch added in v0.9.0

func GitFetch(path string) TaskBuilder

GitFetch fetches from remote.

func GitLfsPull added in v0.9.0

func GitLfsPull(path string) TaskBuilder

GitLfsPull pulls LFS files in a repository.

func GitPull

func GitPull(path string) TaskBuilder

GitPull pulls the latest changes in a repository.

func GitReset added in v0.9.0

func GitReset(path, ref string) TaskBuilder

GitReset resets the repository to a specific state.

func Hostname

func Hostname(name string) TaskBuilder

Hostname sets the system hostname.

func Install

func Install(src, dest string) TaskBuilder

Install copies a file and sets permissions atomically.

func Journal added in v0.5.0

func Journal() TaskBuilder

Journal returns a TaskBuilder for retrieving all system journal logs.

func JournalUnit added in v0.5.0

func JournalUnit(unit string) TaskBuilder

JournalUnit returns a TaskBuilder for retrieving logs for a specific systemd unit.

func Kill

func Kill(pid string) TaskBuilder

Kill sends a signal to a process by PID.

func Killall

func Killall(name string) TaskBuilder

Killall kills all processes with the given name.

func LoadAverage added in v0.9.0

func LoadAverage() TaskBuilder

LoadAverage gets system load average. Use .Register("varname") to store the result.

func MemoryInfo added in v0.9.0

func MemoryInfo() TaskBuilder

MemoryInfo gets available memory information. Use .Register("varname") to store the result.

func Mkdir

func Mkdir(path string) TaskBuilder

Mkdir creates a directory (use .Recursive() for nested directories).

func Move

func Move(src, dest string) TaskBuilder

Move moves/renames a file on the remote server.

func NginxReload

func NginxReload() TaskBuilder

NginxReload reloads the nginx configuration without downtime.

func NginxTest

func NginxTest() TaskBuilder

NginxTest tests the nginx configuration for syntax errors.

func Nproc added in v0.9.0

func Nproc() TaskBuilder

Nproc gets the number of CPU cores. Use .Register("varname") to store the result.

func Pause

func Pause(duration string) TaskBuilder

Pause waits for the specified duration (e.g., "5s", "1m").

func Ping

func Ping(host string) TaskBuilder

Ping tests network connectivity to a host.

func Pkill

func Pkill(pattern string) TaskBuilder

Pkill kills processes matching a pattern.

func ReadFile

func ReadFile(remotePath string) TaskBuilder

ReadFile reads a remote file content into a variable.

func Reboot

func Reboot() TaskBuilder

Reboot reboots the remote system.

func RequireCommand added in v0.9.0

func RequireCommand(cmd string) TaskBuilder

RequireCommand fails if the command is not available.

func RequireDiskSpace added in v0.9.0

func RequireDiskSpace(path string, minGB int) TaskBuilder

RequireDiskSpace fails if available space is less than minGB.

func RequireMemory added in v0.9.0

func RequireMemory(minGB int) TaskBuilder

RequireMemory fails if available memory is less than minGB.

func Restore

func Restore(path string) TaskBuilder

Restore restores a file or directory from a backup.

func Rm

func Rm(path string) TaskBuilder

Rm removes a file or directory (use .Recursive() for directories).

func Rollback added in v0.10.0

func Rollback(baseDir string) TaskBuilder

Rollback returns a task that re-points `current` at the previous release (the second-newest releases/* dir) via an atomic rename. Use when a deploy looked healthy at cutover but misbehaved afterward.

func RsyncCheck added in v0.3.0

func RsyncCheck() TaskBuilder

RsyncCheck checks if rsync is installed (use .Register("varname") to store result).

func RsyncInstall added in v0.3.0

func RsyncInstall() TaskBuilder

RsyncInstall installs rsync on the remote system using the appropriate package manager.

func RsyncVersion added in v0.3.0

func RsyncVersion() TaskBuilder

RsyncVersion gets the rsync version (use .Register("varname") to store result).

func Run

func Run(cmd string) TaskBuilder

Run executes a shell command on the remote server.

func Secret added in v0.10.0

func Secret(sopsFile, dest string) TaskBuilder

Secret decrypts a SOPS-encrypted file locally (via the `sops` CLI) and writes the plaintext to the remote dest over SFTP with mode 0600. This is the 2026 file-based deploy-secret pattern (SOPS + age): the encrypted file is committable to git, decrypted only at deploy time, and the plaintext:

  • never lands on the controller's disk (held in memory),
  • never appears in a shell command (written via SFTP, not a heredoc),
  • is never logged (only the task name, which is the destination path).

Requires `sops` and the relevant decryption key (age/PGP/KMS) on the machine running porter. Override the remote mode with .Mode(); set ownership with .Owner().

func SecretCommand added in v0.10.0

func SecretCommand(fetchCmd, dest string) TaskBuilder

SecretCommand fetches a secret by running fetchCmd locally and writing its stdout to the remote dest at 0600 over SFTP (never logged, never in a remote shell command). This is the pluggable backend escape hatch — works with any secrets manager that has a CLI:

porter.SecretCommand("vault kv get -field=env secret/myapp", "/etc/myapp/env")
porter.SecretCommand("bao kv get -field=env secret/myapp", "/etc/myapp/env")   // OpenBao
porter.SecretCommand("op read op://vault/myapp/env", "/etc/myapp/env")          // 1Password
porter.SecretCommand("infisical secrets get FOO --plain", "/etc/myapp/foo")

Override the remote mode with .Mode() and ownership with .Owner().

func Sed

func Sed(pattern, file string) TaskBuilder

Sed performs in-place text substitution using sed patterns.

func ServiceRunning

func ServiceRunning(name string) TaskBuilder

ServiceRunning checks if a systemd service is running and stores the result. Use .Register("varname") to specify the variable name.

func Shutdown

func Shutdown() TaskBuilder

Shutdown shuts down the remote system.

func SvcList added in v0.9.0

func SvcList() TaskBuilder

SvcList lists all systemd services. Use .User() for user services.

func SvcTimers added in v0.9.0

func SvcTimers() TaskBuilder

SvcTimers lists all systemd timers. Use .User() for user timers.

func Symlink(src, dest string) TaskBuilder

Symlink creates a symbolic link from src to dest.

func Sysctl

func Sysctl(key, value string) TaskBuilder

Sysctl sets a kernel parameter.

func Tar

func Tar(src, dest string) TaskBuilder

Tar creates a tar archive.

func TarGz

func TarGz(src, dest string) TaskBuilder

TarGz creates a gzip-compressed tar archive.

func Template

func Template(name, content string) TaskBuilder

Template creates a file from a template with variable expansion.

func Touch

func Touch(path string) TaskBuilder

Touch creates an empty file or updates timestamps.

func TrustCA added in v0.9.54

func TrustCA(certPath string) TaskBuilder

TrustCA installs the CA certificate at certPath into the machine's OS trust store (/usr/local/share/ca-certificates + update-ca-certificates), so the machine trusts HTTPS peers signed by that authority without warnings.

certPath is a path to a PEM cert already present on the remote host (stage it first with Write). The trust-store anchor filename defaults to certPath's base name; override it with .As(name) when several hosts would otherwise collide on a generic name like "ca.crt".

func TrustCAContent added in v0.11.0

func TrustCAContent(pem string) TaskBuilder

TrustCAContent installs an in-memory PEM CA certificate into the machine's OS trust store in one step: it writes the PEM straight into /usr/local/share/ca-certificates/<anchor>.crt (atomically, mode 0644, with sudo) and runs update-ca-certificates. Unlike TrustCA, the certificate does not need to already be on the remote host — pass the PEM directly (e.g. a CA root your program holds in memory). Set the anchor filename with .As(name) (defaults to "custom-ca").

porter.TrustCAContent(rootCAPEM).As("idx-root-ca")

func UfwAllow

func UfwAllow(port string) TaskBuilder

UfwAllow allows traffic on the specified port.

func UfwDeny

func UfwDeny(port string) TaskBuilder

UfwDeny denies traffic on the specified port.

func UfwDisable

func UfwDisable() TaskBuilder

UfwDisable disables the firewall.

func UfwEnable

func UfwEnable() TaskBuilder

UfwEnable enables the firewall.

func Untar

func Untar(src, dest string) TaskBuilder

Untar extracts a tar archive.

func UntarGz

func UntarGz(src, dest string) TaskBuilder

UntarGz extracts a gzip-compressed tar archive.

func Unzip

func Unzip(src, dest string) TaskBuilder

Unzip extracts a zip archive.

func UpdateServiceParamTask added in v0.6.0

func UpdateServiceParamTask(servicePath, paramName, newValue string) TaskBuilder

UpdateServiceParamTask creates a TaskBuilder that updates a systemd service parameter in the specified file while preserving quote style.

func Upload

func Upload(src, dest string) TaskBuilder

Upload streams the LOCAL file at src to dest on the target via SFTP. Unlike Write (a text heredoc) and Install (a remote-to-remote cp), Upload moves a file from the control machine — suitable for binaries and large payloads (image tars, keys). Honors .Sudo(), .Mode(), and .Owner() for final placement (staged via a private 0600 temp when any of those is set, so a secret never sits world-readable).

func UploadBytes

func UploadBytes(varName, remotePath string) TaskBuilder

UploadBytes uploads binary data from a variable to remote path. varName: the variable containing the data (set via vars.SetBytes)

func UserAdd

func UserAdd(username string) TaskBuilder

UserAdd creates a new user account.

func UserDel

func UserDel(username string) TaskBuilder

UserDel deletes a user account.

func UserMod

func UserMod(username string) TaskBuilder

UserMod modifies a user account. Chain with .Groups(), .Shell(), or .Home() to set properties.

func VerifyBlob added in v0.10.0

func VerifyBlob(artifact, args string) TaskBuilder

VerifyBlob verifies a Sigstore/cosign signature over a local artifact BEFORE it is deployed; a failed verification aborts the deploy (a pre-deploy admission gate — the thing no SSH-push tool ships natively). Pass cosign flags in args, e.g. key-based `--key cosign.pub --signature app.sig` or keyless `--certificate-identity=ci@org.com --certificate-oidc-issuer=https://token.actions.githubusercontent.com`. Requires the `cosign` CLI on the machine running porter. Args are split on whitespace (use simple `--flag=value` form).

func VerifyImage added in v0.10.0

func VerifyImage(ref, args string) TaskBuilder

VerifyImage verifies a container image's cosign signature/attestation before deploy. Same gate semantics and args as VerifyBlob.

func WaitForFile

func WaitForFile(path string) TaskBuilder

WaitForFile waits until a file exists.

func WaitForHttp

func WaitForHttp(url string) TaskBuilder

WaitForHttp waits until an HTTP endpoint returns a successful response.

func WaitForPort

func WaitForPort(host, port string) TaskBuilder

WaitForPort waits until a TCP port is accepting connections.

func Wget

func Wget(url, output string) TaskBuilder

Wget downloads a file using wget.

func WibuApply

func WibuApply(input string) TaskBuilder

WibuApply applies a license update file using cmu. input: path to the .WibuCmRaU file

func WibuGenerate

func WibuGenerate(container, output string) TaskBuilder

WibuGenerate generates a license request file using cmu. container: CodeMeter container number (e.g., "6000930") output: output file path for the .WibuCmRaC file

func WibuInfo

func WibuInfo() TaskBuilder

WibuInfo gets license info from CodeMeter.

func WibuList

func WibuList() TaskBuilder

WibuList lists all CodeMeter containers.

func Write

func Write(dest, content string) TaskBuilder

Write creates a file with the specified content.

func WriteBytes

func WriteBytes(remotePath string) TaskBuilder

WriteBytes writes raw bytes to a remote file (from Body).

func Zip

func Zip(src, dest string) TaskBuilder

Zip creates a zip archive.

func (TaskBuilder) All added in v0.9.0

func (b TaskBuilder) All() TaskBuilder

All includes all items (e.g., stopped containers).

func (TaskBuilder) As added in v0.9.54

func (b TaskBuilder) As(anchor string) TaskBuilder

As sets the trust-store anchor filename for TrustCA (the name the cert is installed under in /usr/local/share/ca-certificates). A ".crt" suffix is added if missing, since update-ca-certificates only consumes *.crt.

func (TaskBuilder) Boot added in v0.5.0

func (b TaskBuilder) Boot(id string) TaskBuilder

Boot shows logs from a specific boot (empty string for current boot).

func (TaskBuilder) Build

func (b TaskBuilder) Build() Task

Build returns the underlying Task.

func (TaskBuilder) Catalog added in v0.5.0

func (b TaskBuilder) Catalog() TaskBuilder

Catalog adds explanatory help texts to log messages.

func (TaskBuilder) Creates added in v0.2.0

func (b TaskBuilder) Creates(path string) TaskBuilder

Creates skips the task if the specified path already exists.

func (TaskBuilder) Depth added in v0.9.0

func (b TaskBuilder) Depth(n int) TaskBuilder

Depth sets clone depth.

func (TaskBuilder) Detach

func (b TaskBuilder) Detach() TaskBuilder

Detach runs the container in the background.

func (TaskBuilder) Dmesg added in v0.5.0

func (b TaskBuilder) Dmesg() TaskBuilder

Dmesg shows kernel ring buffer (similar to dmesg command).

func (TaskBuilder) Env

func (b TaskBuilder) Env(e string) TaskBuilder

Env sets environment variables (e.g., "KEY=value").

func (TaskBuilder) ExpectCode

func (b TaskBuilder) ExpectCode(code string) TaskBuilder

ExpectCode sets the expected HTTP status code for WaitForHttp.

func (TaskBuilder) Failfast added in v0.9.0

func (b TaskBuilder) Failfast() TaskBuilder

Failfast stops tests on first failure.

func (TaskBuilder) Follow added in v0.5.0

func (b TaskBuilder) Follow() TaskBuilder

Follow enables real-time log following (use with caution in automation).

func (TaskBuilder) Force added in v0.9.0

func (b TaskBuilder) Force() TaskBuilder

Force enables force operations.

func (TaskBuilder) GOARCH added in v0.9.0

func (b TaskBuilder) GOARCH(arch string) TaskBuilder

GOARCH sets the target architecture.

func (TaskBuilder) GOOS added in v0.9.0

func (b TaskBuilder) GOOS(os string) TaskBuilder

GOOS sets the target operating system.

func (TaskBuilder) Grep added in v0.5.0

func (b TaskBuilder) Grep(pattern string) TaskBuilder

Grep filters logs matching a pattern.

func (TaskBuilder) Groups

func (b TaskBuilder) Groups(g string) TaskBuilder

Groups sets the supplementary groups for a user.

func (TaskBuilder) Hard added in v0.9.0

func (b TaskBuilder) Hard() TaskBuilder

Hard enables hard reset.

func (TaskBuilder) Home

func (b TaskBuilder) Home(h string) TaskBuilder

Home sets the home directory for a user.

func (TaskBuilder) Ignore

func (b TaskBuilder) Ignore() TaskBuilder

Ignore continues execution even if this task fails.

func (TaskBuilder) Init added in v0.10.0

func (b TaskBuilder) Init() TaskBuilder

Init runs the container with a tiny init process (--init) that reaps zombie processes and forwards signals — recommended when the image's entrypoint is not itself a proper init. Off by default.

func (TaskBuilder) Kernel added in v0.5.0

func (b TaskBuilder) Kernel() TaskBuilder

Kernel shows kernel logs only.

func (TaskBuilder) LDFlags added in v0.9.0

func (b TaskBuilder) LDFlags(flags string) TaskBuilder

LDFlags sets linker flags (e.g., "-s -w" for stripped binaries).

func (TaskBuilder) LegacyPeerDeps added in v0.9.0

func (b TaskBuilder) LegacyPeerDeps() TaskBuilder

LegacyPeerDeps uses legacy peer dependency resolution.

func (TaskBuilder) Lines added in v0.5.0

func (b TaskBuilder) Lines(n string) TaskBuilder

Lines limits the number of log lines to retrieve.

func (TaskBuilder) LogRotate added in v0.10.0

func (b TaskBuilder) LogRotate(maxSize, maxFiles string) TaskBuilder

LogRotate caps the json-file log driver (--log-opt max-size / max-file) so a container's logs can't fill the host disk. Example: LogRotate("10m", "3"). Off by default (Docker's default json-file driver has no rotation).

func (TaskBuilder) Loop

func (b TaskBuilder) Loop(items ...string) TaskBuilder

Loop executes the task once for each item in the list. Use {{item}} in task fields to reference the current item.

func (TaskBuilder) Mode

func (b TaskBuilder) Mode(m string) TaskBuilder

Mode sets the file mode/permissions (used with Chmod and Write).

func (TaskBuilder) Name

func (b TaskBuilder) Name(n string) TaskBuilder

Name sets a custom display name for the task.

func (TaskBuilder) Network

func (b TaskBuilder) Network(n string) TaskBuilder

Network connects the container to a network.

func (TaskBuilder) NoPager added in v0.5.0

func (b TaskBuilder) NoPager() TaskBuilder

NoPager disables pager output.

func (TaskBuilder) Output added in v0.5.0

func (b TaskBuilder) Output(format string) TaskBuilder

Output sets the output format (short, json, json-pretty, verbose, cat, etc.).

func (TaskBuilder) Owner

func (b TaskBuilder) Owner(o string) TaskBuilder

Owner sets the owner for file operations (used with Chown and Write).

func (TaskBuilder) Parallel added in v0.9.0

func (b TaskBuilder) Parallel(n int) TaskBuilder

Parallel sets the number of parallel test jobs.

func (TaskBuilder) Ports

func (b TaskBuilder) Ports(p string) TaskBuilder

Ports maps container ports to host ports (e.g., "8080:80").

func (TaskBuilder) Priority added in v0.5.0

func (b TaskBuilder) Priority(level string) TaskBuilder

Priority filters logs by priority level (emerg, alert, crit, err, warning, notice, info, debug).

func (TaskBuilder) Production added in v0.9.0

func (b TaskBuilder) Production() TaskBuilder

Production installs only production dependencies.

func (TaskBuilder) Race added in v0.9.0

func (b TaskBuilder) Race() TaskBuilder

Race enables race detector.

func (TaskBuilder) Recursive

func (b TaskBuilder) Recursive() TaskBuilder

Recursive enables recursive operation for file commands.

func (TaskBuilder) Register

func (b TaskBuilder) Register(varName string) TaskBuilder

Register stores the task output in a variable for later use.

func (TaskBuilder) RemoveOrphans

func (b TaskBuilder) RemoveOrphans() TaskBuilder

RemoveOrphans removes containers for services not defined in the compose file.

func (TaskBuilder) RemoveVolumes

func (b TaskBuilder) RemoveVolumes() TaskBuilder

RemoveVolumes removes volumes when stopping containers.

func (TaskBuilder) Restart added in v0.10.0

func (b TaskBuilder) Restart(policy string) TaskBuilder

Restart sets the container restart policy (e.g. "unless-stopped", "always", "on-failure"). Recommended for long-lived services so they survive a daemon or host restart. Off by default.

func (TaskBuilder) Retry

func (b TaskBuilder) Retry(count int) TaskBuilder

Retry sets the number of retry attempts on failure.

func (TaskBuilder) RetryDelay

func (b TaskBuilder) RetryDelay(d string) TaskBuilder

RetryDelay sets the delay between retry attempts.

func (TaskBuilder) Reverse added in v0.5.0

func (b TaskBuilder) Reverse() TaskBuilder

Reverse shows newest entries first.

func (TaskBuilder) Service

func (b TaskBuilder) Service(s string) TaskBuilder

Service targets a specific service.

func (TaskBuilder) Shallow added in v0.9.0

func (b TaskBuilder) Shallow() TaskBuilder

Shallow enables shallow clone (depth 1).

func (TaskBuilder) Shell

func (b TaskBuilder) Shell(s string) TaskBuilder

Shell sets the login shell for a user.

func (TaskBuilder) Silent added in v0.9.0

func (b TaskBuilder) Silent() TaskBuilder

Silent suppresses npm output.

func (TaskBuilder) Since added in v0.5.0

func (b TaskBuilder) Since(time string) TaskBuilder

Since filters logs from a specific time (e.g., "2024-12-11 10:00:00", "1 hour ago").

func (TaskBuilder) StdinFile added in v0.12.0

func (b TaskBuilder) StdinFile(path string) TaskBuilder

StdinFile streams the LOCAL file at path into this command's stdin on the remote host — e.g. Run("docker load").StdinFile("app.tar").Sudo() pipes the local tar into `docker load` without ever writing it to the target's disk.

func (TaskBuilder) Sudo

func (b TaskBuilder) Sudo() TaskBuilder

Sudo runs the task with elevated privileges.

func (TaskBuilder) System added in v0.5.0

func (b TaskBuilder) System() TaskBuilder

System shows system logs explicitly.

func (TaskBuilder) Tags added in v0.9.0

func (b TaskBuilder) Tags(tags string) TaskBuilder

Tags sets build tags.

func (TaskBuilder) Timeout

func (b TaskBuilder) Timeout(d string) TaskBuilder

Timeout sets the maximum duration for wait operations.

func (TaskBuilder) UTC added in v0.5.0

func (b TaskBuilder) UTC() TaskBuilder

UTC shows timestamps in UTC.

func (TaskBuilder) Until added in v0.5.0

func (b TaskBuilder) Until(time string) TaskBuilder

Until filters logs until a specific time.

func (TaskBuilder) User

func (b TaskBuilder) User() TaskBuilder

User runs the task in user-level systemd context.

func (TaskBuilder) UserMode added in v0.9.0

func (b TaskBuilder) UserMode() TaskBuilder

UserMode is an alias for User() - runs the task in user-level systemd context.

func (TaskBuilder) Verbose added in v0.9.0

func (b TaskBuilder) Verbose() TaskBuilder

Verbose enables verbose output.

func (TaskBuilder) Volumes

func (b TaskBuilder) Volumes(v string) TaskBuilder

Volumes mounts volumes (e.g., "/host/path:/container/path").

func (TaskBuilder) When

func (b TaskBuilder) When(w When) TaskBuilder

When sets a condition that must be true for the task to execute.

func (TaskBuilder) WithBuild

func (b TaskBuilder) WithBuild() TaskBuilder

WithBuild builds images before starting containers.

type TaskProgress added in v0.3.0

type TaskProgress struct {
	Index      int           // 0-based task index
	Total      int           // Total number of tasks
	Name       string        // Task name (expanded)
	Action     string        // Task action type
	Status     TaskStatus    // Current status
	Attempt    int           // Current attempt (1-based, for retries)
	MaxAttempt int           // Max attempts (1 + Retry count)
	Error      error         // Error if failed
	Duration   time.Duration // Time taken (set on completion)
	StartTime  time.Time     // When task started
}

TaskProgress represents the progress of a single task.

func (TaskProgress) ProgressBar added in v0.3.0

func (p TaskProgress) ProgressBar(width int) string

ProgressBar returns a simple text progress bar for the task

func (TaskProgress) String added in v0.3.0

func (p TaskProgress) String() string

String returns a formatted string representation of the progress

type TaskStatus added in v0.3.0

type TaskStatus string

TaskStatus represents the current status of a task.

const (
	StatusPending  TaskStatus = "pending"
	StatusRunning  TaskStatus = "running"
	StatusOK       TaskStatus = "ok"
	StatusChanged  TaskStatus = "changed"
	StatusSkipped  TaskStatus = "skipped"
	StatusFailed   TaskStatus = "failed"
	StatusRetrying TaskStatus = "retrying"
)

type Tracer added in v0.10.0

type Tracer struct {
	// contains filtered or unexported fields
}

Tracer records a deployment as a trace: one root span per Run, one child span per task. Spans are emitted as JSON lines (one object per line) to an io.Writer, so a deploy can be replayed as a waterfall in the dashboard or piped to an OTLP/JSONL consumer (e.g. otel-tui). It deliberately has no OpenTelemetry SDK dependency — the schema mirrors the OTel span model and uses the stable `deployment.environment.name` attribute (2026 semconv).

A Tracer is safe for concurrent span emission.

func NewTracer added in v0.10.0

func NewTracer(w io.Writer, env, service string) *Tracer

NewTracer creates a Tracer that writes JSONL spans to w. env is the deployment environment ("production", "staging", …) and service is the logical service being deployed; both are attached to every span. Passing a nil writer yields a no-op tracer (every method is safe to call).

func (*Tracer) SetAttribute added in v0.10.0

func (t *Tracer) SetAttribute(key string, value any)

SetAttribute attaches a key/value to every subsequently emitted span (e.g. vcs.commit.sha, deployment.id). Safe before or during a deploy.

func (*Tracer) StartSpan added in v0.10.0

func (t *Tracer) StartSpan(name, parentID string) *ActiveSpan

StartSpan begins a span named name, optionally as a child of parentID (empty for a root span). Returns an ActiveSpan whose End emits it.

func (*Tracer) TraceID added in v0.10.0

func (t *Tracer) TraceID() string

TraceID returns the trace's id (a deploy is one trace).

type Vars

type Vars struct {
	Item string // Current loop item
	// contains filtered or unexported fields
}

Vars holds variables for template expansion during task execution.

func NewVars

func NewVars() *Vars

NewVars creates a new Vars instance.

func (*Vars) Clear

func (v *Vars) Clear()

Clear removes all variables.

func (*Vars) Expand

func (v *Vars) Expand(s string) string

Expand replaces {{key}} placeholders with variable values.

func (*Vars) Get

func (v *Vars) Get(key string) string

Get retrieves a string value.

func (*Vars) GetBool

func (v *Vars) GetBool(key string) bool

GetBool retrieves a boolean value (true if value is "true").

func (*Vars) GetBytes

func (v *Vars) GetBytes(key string) []byte

GetBytes retrieves binary data.

func (*Vars) Set

func (v *Vars) Set(key, val string) *Vars

Set stores a string value.

func (*Vars) SetBool

func (v *Vars) SetBool(key string, b bool) *Vars

SetBool stores a boolean value.

func (*Vars) SetBytes

func (v *Vars) SetBytes(key string, data []byte) *Vars

SetBytes stores binary data.

type When

type When func(*Vars) bool

When is a condition function that determines if a task should run.

func Always

func Always() When

Always returns a condition that is always true.

func And

func And(conds ...When) When

And returns true if all conditions are true.

func If

func If(key string) When

If returns true if the variable value is "true".

func IfEquals

func IfEquals(key, val string) When

IfEquals returns true if the variable equals the given value.

func IfNot

func IfNot(key string) When

IfNot returns true if the variable value is not "true".

func IfNotEquals added in v0.9.0

func IfNotEquals(key, val string) When

IfNotEquals returns true if the variable does not equal the given value.

func IfNotSet added in v0.9.0

func IfNotSet(key string) When

IfNotSet returns true if the variable is not set (empty).

func IfSet

func IfSet(key string) When

IfSet returns true if the variable is set (non-empty).

func Never

func Never() When

Never returns a condition that is always false.

func Not

func Not(c When) When

Not negates a condition.

func Or

func Or(conds ...When) When

Or returns true if any condition is true.

type WorkflowProgress added in v0.3.0

type WorkflowProgress struct {
	Name      string        // Workflow name
	Total     int           // Total tasks
	Completed int           // Completed tasks (ok + changed + skipped + failed)
	OK        int           // Successful tasks
	Changed   int           // Changed tasks
	Skipped   int           // Skipped tasks
	Failed    int           // Failed tasks
	Current   *TaskProgress // Current task (nil if not running)
	Percent   float64       // Completion percentage
	Elapsed   time.Duration // Total elapsed time
	StartTime time.Time     // When workflow started
}

WorkflowProgress represents overall workflow progress.

Directories

Path Synopsis
cmd
porter-ui command
examples
basic command
Example: Basic deployment using Porter
Example: Basic deployment using Porter
conditional command
Example: Conditional deployment using Porter
Example: Conditional deployment using Porter
docker command
Example: Docker deployment using Porter
Example: Docker deployment using Porter
modern command
Example: the 2026 feature set — declarative state, atomic releases with health-gated cutover and rollback, SOPS+age secrets, cosign verify gate, SSH-certificate auth, and deploy-as-an-OpenTelemetry-trace.
Example: the 2026 feature set — declarative state, atomic releases with health-gated cutover and rollback, SOPS+age secrets, cosign verify gate, SSH-certificate auth, and deploy-as-an-OpenTelemetry-trace.
rsync command
Example: Rsync operations using Porter
Example: Rsync operations using Porter
systemd command
Example: Systemd service file management using Porter
Example: Systemd service file management using Porter

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL