deploy

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Feb 22, 2026 License: MIT Imports: 18 Imported by: 0

README

deploy

Project Badges

Automated Continuous Deployment (CD) framework for Windows/Linux. Designed around a Push/Pull model: includes a Puller agent that orchestrates updates on the server, and multiple Pusher implementations (Cloudflare, SSH, Webhooks) to trigger or execute deployments. Features automatic health checks and rollbacks.

Documentation

Document Description
Architecture & Design Executive summary, security model, workflow, and setup
Implementation Guide [TEMPORARY] Phase 1 Windows work prompt
System Components Directory layout, keyring, and network ports
Process Flow High-level deployment flow on Windows Server
Deployment Workflow Detailed sequence diagram (GitHub Actions → Windows)
Setup Flow Interactive first-run setup wizard flow

Quick Summary

  • Push/Pull Model: Decoupled architecture where a local Puller agent handles the lifecycle, triggered by external Pushers.
  • Security: HMAC-SHA256 request validation + cross-platform keyring for multi-service secret storage.
  • Resilient: Automatic health-check verification and atomic rollback if the new version fails.
  • Zero-dependency binary: Single .exe, no runtime required

Dependencies

  • tinywasm/keyring — Cross-platform secret storage (DPAPI on Windows, Keychain on macOS, Secret Service on Linux)

Documentation

Overview

Daemon composes the goflare Edge Worker compiler with the Puller orchestrator into a single unit for tinywasm/app. app imports only tinywasm/deploy.

Package deploy implements a lightweight continuous deployment agent. It supports three modes:

  • cloudflare: uploads build artifacts to Cloudflare Pages via API.
  • webhook: an HTTP daemon on the server that GitHub Actions triggers via POST.
  • ssh: generates a shell script that GitHub Actions runs via SSH on the server.

Usage:

d := &deploy.Deploy{Store: db, Process: mgr, Downloader: dl, Checker: checker}
d.Run()

Index

Constants

View Source
const KeyringServiceName = "tinywasm-deploy"

Variables

This section is empty.

Functions

func AvailablePushers added in v0.1.0

func AvailablePushers() []string

AvailablePushers returns the names of all registered pushers.

func CreateDefaultConfig added in v0.0.3

func CreateDefaultConfig(path string) error

CreateDefaultConfig creates a default deploy.yaml if it does not exist.

func CreateShortcut added in v0.0.3

func CreateShortcut(linkPath, targetPath, workDir string) error

func RegisterPusher added in v0.1.0

func RegisterPusher(s Pusher)

RegisterPusher adds a pusher to the global registry.

func SSHCommand added in v0.0.3

func SSHCommand(sshKey, sshUser, sshHost, script string) string

SSHCommand returns the ssh command string to run the generated script on a remote host. Intended for GitHub Actions step generation / documentation.

func SSHScript added in v0.0.3

func SSHScript(app AppConfig, downloadURL, githubPAT string) string

SSHScript generates a shell script that a GitHub Action runs via SSH to deploy a new binary version directly on the server.

The generated script:

  1. Downloads the release asset from GitHub
  2. Stops the service (systemctl or pkill)
  3. Replaces the binary (with backup)
  4. Starts the service
  5. Checks health URL

Types

type AppConfig added in v0.0.3

type AppConfig struct {
	Name              string         `yaml:"name"`
	Version           string         `yaml:"version"`
	Executable        string         `yaml:"executable"`
	Path              string         `yaml:"path"`
	Port              int            `yaml:"port"`
	HealthEndpoint    string         `yaml:"health_endpoint"`
	HealthTimeout     time.Duration  `yaml:"health_timeout"`
	StartupDelay      time.Duration  `yaml:"startup_delay"`
	BusyRetryInterval time.Duration  `yaml:"busy_retry_interval"` // default: 10s
	BusyTimeout       time.Duration  `yaml:"busy_timeout"`        // default: 5m
	Rollback          RollbackConfig `yaml:"rollback"`
}

AppConfig represents a single application configuration.

type Checker added in v0.0.3

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

func NewChecker added in v0.0.3

func NewChecker() *Checker

func (*Checker) Check added in v0.0.3

func (c *Checker) Check(url string) (*HealthStatus, error)

Check performs a health check on the given URL.

type CloudflarePagesPusher added in v0.1.0

type CloudflarePagesPusher struct {
	// Goflare instance used for deployment.
	Goflare *goflare.Goflare
}

CloudflarePagesPusher implements deployment specifically to Cloudflare Pages.

func (*CloudflarePagesPusher) Name added in v0.1.0

func (s *CloudflarePagesPusher) Name() string

func (*CloudflarePagesPusher) Run added in v0.1.0

func (s *CloudflarePagesPusher) Run(cfg *Config, p *Puller) error

func (*CloudflarePagesPusher) WizardSteps added in v0.1.0

func (s *CloudflarePagesPusher) WizardSteps(store Store, log func(...any)) []*wizard.Step

type CloudflareWorkerPusher added in v0.1.0

type CloudflareWorkerPusher struct {
	// Goflare instance used for deployment.
	Goflare *goflare.Goflare
}

CloudflareWorkerPusher implements deployment specifically to Cloudflare Workers.

func (*CloudflareWorkerPusher) Name added in v0.1.0

func (s *CloudflareWorkerPusher) Name() string

func (*CloudflareWorkerPusher) Run added in v0.1.0

func (s *CloudflareWorkerPusher) Run(cfg *Config, p *Puller) error

func (*CloudflareWorkerPusher) WizardSteps added in v0.1.0

func (s *CloudflareWorkerPusher) WizardSteps(store Store, log func(...any)) []*wizard.Step

type Config added in v0.0.3

type Config struct {
	Updater ConfigUpdater `yaml:"updater"`
	Apps    []AppConfig   `yaml:"apps"`
}

Config represents the application configuration.

func Load added in v0.0.3

func Load(path string) (*Config, error)

Load loads the configuration from the specified path.

type ConfigUpdater added in v0.0.3

type ConfigUpdater struct {
	Port     int         `yaml:"port"` // default: 8080
	LogLevel string      `yaml:"log_level"`
	LogFile  string      `yaml:"log_file"`
	TempDir  string      `yaml:"temp_dir"`
	Retry    RetryConfig `yaml:"retry"`
}

ConfigUpdater holds updater-specific configuration.

type Daemon added in v0.1.0

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

Daemon composes the goflare Edge Worker handler with the Puller orchestrator.

func NewDaemon added in v0.1.0

func NewDaemon(cfg *DaemonConfig) *Daemon

NewDaemon creates a Daemon with fully-initialised goflare and Puller internals.

func (*Daemon) EdgeWorker added in v0.1.0

func (d *Daemon) EdgeWorker() any

EdgeWorker returns the goflare handler for TUI registration (AddHandler).

func (*Daemon) GetSteps added in v0.1.0

func (d *Daemon) GetSteps() []*wizard.Step

GetSteps delegates to Puller — satisfies the wizard.New item interface.

func (*Daemon) IsConfigured added in v0.1.0

func (d *Daemon) IsConfigured() bool

IsConfigured reports whether a deploy method has been stored.

func (*Daemon) MainInputFileRelativePath added in v0.1.0

func (d *Daemon) MainInputFileRelativePath() string

func (*Daemon) NewFileEvent added in v0.1.0

func (d *Daemon) NewFileEvent(fileName, extension, filePath, event string) error

func (*Daemon) Puller added in v0.1.0

func (d *Daemon) Puller() any

Puller returns the puller handler for TUI registration (AddHandler).

func (*Daemon) SetLog added in v0.1.0

func (d *Daemon) SetLog(f func(...any))

SetLog injects a logger into both components.

func (*Daemon) SupportedExtensions added in v0.1.0

func (d *Daemon) SupportedExtensions() []string

func (*Daemon) UnobservedFiles added in v0.1.0

func (d *Daemon) UnobservedFiles() []string

type DaemonConfig added in v0.1.0

type DaemonConfig struct {
	AppRootDir          string
	CmdEdgeWorkerDir    string // relative input dir for edge worker source
	DeployEdgeWorkerDir string // relative output dir for compiled artifacts
	OutputWasmFileName  string // e.g. "app.wasm"
	DeployConfigPath    string // path to deploy.yaml
	Store               Store
}

DaemonConfig holds all configuration needed to initialise both goflare and Puller.

type Downloader added in v0.0.3

type Downloader interface {
	Download(url, dest, token string) error
}

type HMACValidator added in v0.0.3

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

func NewHMACValidator added in v0.0.3

func NewHMACValidator(secret string) *HMACValidator

func (*HMACValidator) ValidateRequest added in v0.0.3

func (v *HMACValidator) ValidateRequest(payload []byte, signature string) error

type HTTPDownloader added in v0.0.3

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

func NewDownloader added in v0.0.3

func NewDownloader() *HTTPDownloader

func (*HTTPDownloader) Download added in v0.0.3

func (d *HTTPDownloader) Download(url, dest, token string) error

type Handler added in v0.0.3

type Handler struct {
	Config     *Config
	ConfigPath string
	Validator  *HMACValidator
	Downloader Downloader
	Process    ProcessManager
	Checker    HealthChecker // Use interface
	Keys       Store
}

func (*Handler) HandleUpdate added in v0.0.3

func (h *Handler) HandleUpdate(w http.ResponseWriter, r *http.Request)

type HealthChecker added in v0.0.3

type HealthChecker interface {
	Check(url string) (*HealthStatus, error)
}

type HealthStatus added in v0.0.3

type HealthStatus struct {
	Status     string `json:"status"`
	CanRestart bool   `json:"can_restart"`
}

func ParseHealthResponse added in v0.0.3

func ParseHealthResponse(r io.Reader) (*HealthStatus, error)

type LinuxManager added in v0.0.3

type LinuxManager struct{}

func (*LinuxManager) Start added in v0.0.3

func (m *LinuxManager) Start(exePath string) error

func (*LinuxManager) Stop added in v0.0.3

func (m *LinuxManager) Stop(exeName string) error

type ProcessManager added in v0.0.3

type ProcessManager interface {
	Start(exePath string) error
	Stop(exeName string) error
}

ProcessManager defines the interface for managing processes.

func NewProcessManager added in v0.0.3

func NewProcessManager() ProcessManager

type Puller added in v0.1.0

type Puller struct {
	Store      Store
	Process    ProcessManager
	Downloader Downloader
	Checker    HealthChecker
	ConfigPath string
	Goflare    *goflare.Goflare // Injected for edgeWorker strategy
	// contains filtered or unexported fields
}

Puller is the main orchestrator for all deployment modes. Store must be injected — kvdb.KVStore satisfies the Store interface directly.

func (*Puller) GetSteps added in v0.1.0

func (p *Puller) GetSteps() []*wizard.Step

GetSteps implements the interface expected by tinywasm/wizard.New(). Returns the initial steps; method-specific steps are injected dynamically via the Step 1 OnInputFn after the user chooses a deploy method.

func (*Puller) IsConfigured added in v0.1.0

func (p *Puller) IsConfigured() bool

IsConfigured returns true if a deploy method has been stored.

func (*Puller) Name added in v0.1.0

func (p *Puller) Name() string

Name returns the TUI tab label for the orchestrator.

func (*Puller) Run added in v0.1.0

func (p *Puller) Run() error

Run executes the deployment based on the stored DEPLOY_METHOD. Called from cmd/deploy/main.go for standalone daemon mode.

func (*Puller) SetLog added in v0.1.0

func (p *Puller) SetLog(f func(...any))

SetLog injects a logger (called by tinywasm/app after registration with TUI).

type Pusher added in v0.1.0

type Pusher interface {
	// Name returns the unique identifier for this pusher (e.g., "webhook", "ssh", "edgeWorker").
	Name() string
	// Run executes the deployment logic.
	Run(cfg *Config, p *Puller) error
	// WizardSteps returns the interactive setup steps for this pusher.
	WizardSteps(store Store, log func(...any)) []*wizard.Step
}

Pusher defines the interface for a deployment method.

func GetPusher added in v0.1.0

func GetPusher(name string) (Pusher, error)

GetPusher retrieves a pusher by its name (case-insensitive).

type RetryConfig added in v0.0.3

type RetryConfig struct {
	MaxAttempts int           `yaml:"max_attempts"`
	Delay       time.Duration `yaml:"delay"`
}

RetryConfig holds retry configuration.

type RollbackConfig added in v0.0.3

type RollbackConfig struct {
	Enabled               bool `yaml:"enabled"`
	KeepVersions          int  `yaml:"keep_versions"` // Only -older
	AutoRollbackOnFailure bool `yaml:"auto_rollback_on_failure"`
}

RollbackConfig holds rollback configuration.

type SSHPusher added in v0.1.0

type SSHPusher struct{}

func (*SSHPusher) Name added in v0.1.0

func (s *SSHPusher) Name() string

func (*SSHPusher) Run added in v0.1.0

func (s *SSHPusher) Run(cfg *Config, p *Puller) error

func (*SSHPusher) WizardSteps added in v0.1.0

func (s *SSHPusher) WizardSteps(store Store, log func(...any)) []*wizard.Step

type SecureStore added in v0.1.0

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

SecureStore wraps a base Store and routes sensitive keys securely to the OS keyring. Minimal interface: no adapter needed for the base KVStore.

func NewSecureStore added in v0.1.0

func NewSecureStore(base Store) *SecureStore

NewSecureStore initializes a new SecureStore wrapping the given base store.

func (*SecureStore) Get added in v0.1.0

func (s *SecureStore) Get(key string) (string, error)

Get retrieves a key. Sensitive keys are fetched only from the keyring.

func (*SecureStore) Set added in v0.1.0

func (s *SecureStore) Set(key, value string) error

Set stores a key. Sensitive keys are saved only to the keyring, and concurrently wiped from the base store to prevent plaintext leaks.

type Store added in v0.0.4

type Store interface {
	Get(key string) (string, error)
	Set(key, value string) error
}

Store is a flat key-value store for deploy configuration and secrets. kvdb.KVStore satisfies this interface directly — no adapter needed.

Keys used by deploy:

DEPLOY_METHOD       → "cloudflarePages" | "cloudflareWorker" | "webhook" | "ssh"
DEPLOY_GITHUB_PAT   → GitHub Personal Access Token
DEPLOY_HMAC_SECRET  → HMAC-SHA256 secret for webhook validation
DEPLOY_SERVER_HOST  → host:port for webhook or SSH host
DEPLOY_SSH_USER     → SSH username
DEPLOY_SSH_KEY      → SSH private key path/content
CF_ACCOUNT_ID       → Cloudflare account ID
CF_PAGES_TOKEN      → Cloudflare scoped Pages:Edit token (auto-created)
CF_PROJECT          → Cloudflare project name
CF_WORKER_TOKEN     → Cloudflare scoped Workers:Edit token

type UpdateRequest added in v0.0.3

type UpdateRequest struct {
	Repo        string `json:"repo"`
	Tag         string `json:"tag"`
	Executable  string `json:"executable"`
	DownloadURL string `json:"download_url"`
}

type WebhookTrigger added in v0.1.0

type WebhookTrigger struct{}

func (*WebhookTrigger) Name added in v0.1.0

func (s *WebhookTrigger) Name() string

func (*WebhookTrigger) Run added in v0.1.0

func (s *WebhookTrigger) Run(cfg *Config, p *Puller) error

func (*WebhookTrigger) WizardSteps added in v0.1.0

func (s *WebhookTrigger) WizardSteps(store Store, log func(...any)) []*wizard.Step

Directories

Path Synopsis
cmd
puller command

Jump to

Keyboard shortcuts

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