docker

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Apr 4, 2026 License: AGPL-3.0, AGPL-3.0-only Imports: 20 Imported by: 0

Documentation

Overview

Package docker provides Docker lifecycle orchestration for StageFreight. The Compose backend uses docker compose as the execution engine. This is Docker lifecycle orchestration, not a docker-compose wrapper.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllowDestructiveOrphanAction

func AllowDestructiveOrphanAction(trust DiscoveryTrust, knownCount, runningCount, orphanCount, threshold int) (bool, string)

AllowDestructiveOrphanAction checks if the trust level and anomaly guards permit destructive orphan actions (down/prune).

func ComputeBundleHash

func ComputeBundleHash(stack StackInfo, rootDir string, secrets SecretsProvider) string

ComputeBundleHash computes a deterministic SHA256 hash of a stack's rendered desired state. SOPS-encrypted files are decrypted in-memory before hashing — never persisted. Env files are normalized (sorted keys, trimmed whitespace, normalized line endings) for deterministic drift detection. Files are sorted before hashing.

Pipeline: IaC → [SOPS decrypt] → normalize → hash → discard

func RenderPlan

func RenderPlan(w io.Writer, plan *runtime.LifecyclePlan, elapsed time.Duration, color bool)

RenderPlan renders a Docker lifecycle plan to the writer. Shows all stacks with drift status, grouped by scope.

func RenderResult

func RenderResult(w io.Writer, plan *runtime.LifecyclePlan, result *runtime.LifecycleResult, elapsed time.Duration, color bool)

RenderResult renders the execution outcome.

func SaveHashStamps

func SaveHashStamps(rootDir string, stamps *HashStamps) error

SaveHashStamps writes the hash stamps to .stagefreight-state.yml.

Types

type ActionDetail

type ActionDetail struct {
	Requested     string `json:"requested"`
	Effective     string `json:"effective"`
	Allowed       bool   `json:"allowed"`
	BlockedReason string `json:"blocked_reason,omitempty"`
}

ActionDetail shows requested vs effective action.

type AnomalyEntry

type AnomalyEntry struct {
	Type     string `json:"type"`
	Severity string `json:"severity"`
	Message  string `json:"message"`
}

AnomalyEntry represents a detected anomaly on a target.

type AnsibleInventory

type AnsibleInventory struct {
	Path string
}

AnsibleInventory implements InventorySource by parsing Ansible inventory files. Supports YAML and INI formats. Resolves hosts by group membership. DD-UI proven patterns carried forward.

func (*AnsibleInventory) Name

func (a *AnsibleInventory) Name() string

func (*AnsibleInventory) Resolve

func (a *AnsibleInventory) Resolve(_ context.Context, selector TargetSelector) ([]HostTarget, error)

Resolve parses the inventory and returns hosts matching the selector's groups.

type ComposeBackend

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

ComposeBackend implements runtime.LifecycleBackend for Docker lifecycle orchestration using docker compose as the execution engine.

func (*ComposeBackend) Capabilities

func (c *ComposeBackend) Capabilities() []runtime.Capability

func (*ComposeBackend) Cleanup

func (c *ComposeBackend) Cleanup(rctx *runtime.RuntimeContext)

Cleanup closes transports and removes staged secrets.

func (*ComposeBackend) Execute

Execute consumes the plan — applies only actions marked "up". Does NOT rediscover state. Plan decides; execute applies. Idempotent: no drifted actions → no mutations.

func (*ComposeBackend) Name

func (c *ComposeBackend) Name() string

func (*ComposeBackend) Plan

Plan scans IaC, computes drift for each stack on each target. Deterministic: identical config + inputs → identical output.

func (*ComposeBackend) Prepare

func (c *ComposeBackend) Prepare(ctx context.Context, cfg *config.Config, rctx *runtime.RuntimeContext) error

Prepare resolves targets from inventory and establishes transports.

func (*ComposeBackend) Validate

func (c *ComposeBackend) Validate(ctx context.Context, cfg *config.Config, rctx *runtime.RuntimeContext) error

Validate checks prerequisites: inventory parseable, secrets provider available, at least one target resolvable.

type DeployResult

type DeployResult struct {
	Host     string
	Stack    string
	Success  bool
	Duration time.Duration
	Message  string
}

DeployResult describes the outcome of deploying a single stack.

type DiscoveryTrust

type DiscoveryTrust struct {
	Level             TrustLevel
	Sentinel          bool                 // .stagefreight.yml exists
	IaCRootExists     bool                 // expected IaC directory exists
	ScanSucceeded     bool                 // scan completed without error
	RepoIdentityMatch bool                 // origin URL matches expected
	DeclaredTargets   bool                 // host resolution succeeded
	StackCount        int                  // stacks discovered
	Reasons           []TrustFailureReason // why trust failed
}

DiscoveryTrust captures whether the repo discovery is authoritative enough for destructive operations (orphan cleanup, prune). Never destroy from absence unless the source of truth is positively validated.

func EvaluateTrust

func EvaluateTrust(rootDir, iacPath, expectedMode string) DiscoveryTrust

EvaluateTrust determines how authoritative the repository discovery is. Destructive actions (orphan down/prune) require TrustAuthoritative. Never destroy from absence unless the source of truth is positively validated.

func (*DiscoveryTrust) MarkDeclaredTargets

func (t *DiscoveryTrust) MarkDeclaredTargets(resolved bool)

MarkDeclaredTargets records whether host target resolution succeeded.

func (*DiscoveryTrust) MarkScanResult

func (t *DiscoveryTrust) MarkScanResult(succeeded bool, stackCount int)

MarkScanResult records whether the IaC scan succeeded and how many stacks were found.

type DockerPlanMeta

type DockerPlanMeta struct {
	Scope      string
	ScopeKind  string
	Stack      string
	Path       string
	BundleHash string
	StoredHash string
	DriftTier  int
	DeployKind string

	// Signals for truthful output (not inferred from action).
	DriftDetected   bool   // true if drift was found (independent of action taken)
	DriftReason     string // human-readable drift reason
	IsOrphan        bool   // true if this is an orphaned project
	RequestedAction string // what policy wanted (before trust/safety gates)
	BlockedReason   string // structured reason if action was degraded/blocked (empty = allowed)
}

DockerPlanMeta is the typed metadata for a Docker plan action. Internally, backends operate on this. Serialized to Metadata map for transport. Carries ALL signals needed for truthful output — no inference from action type.

func ParseDockerPlanMeta

func ParseDockerPlanMeta(m map[string]string) DockerPlanMeta

ParseDockerPlanMeta deserializes from the generic transport map.

func (DockerPlanMeta) ToMetadata

func (m DockerPlanMeta) ToMetadata() map[string]string

ToMetadata serializes to the generic transport map.

type DriftDetail

type DriftDetail struct {
	Detected bool   `json:"detected"`
	Kind     string `json:"kind"` // tier1 | tier2 | none | unknown
	Reason   string `json:"reason"`
}

DriftDetail provides structured drift information.

type DriftPolicy

type DriftPolicy struct {
	Tier2Action               string `yaml:"tier2_action"`                // report | reconcile
	OrphanAction              string `yaml:"orphan_action"`               // report | down | prune
	OrphanThreshold           int    `yaml:"orphan_threshold"`            // block if more than N orphans
	PruneRequiresConfirmation bool   `yaml:"prune_requires_confirmation"` // require --force for prune
}

DriftPolicy configures drift detection behavior.

func DefaultDriftPolicy

func DefaultDriftPolicy() DriftPolicy

DefaultDriftPolicy returns safe defaults.

type DriftResult

type DriftResult struct {
	Host       string
	Stack      string
	Drifted    bool
	Tier       int // 1 = bundle hash, 2 = container config hash
	Reason     string
	BundleHash string // current computed hash
	StoredHash string // last known hash
}

DriftResult describes the drift state of a single stack on a host.

func DetectDrift

func DetectDrift(ctx context.Context, stack StackInfo, rootDir string, stamps *HashStamps, secrets SecretsProvider, transport HostTransport) DriftResult

DetectDrift computes drift state for a stack against stored hash stamps. Two-tier detection:

  • Tier 1: bundle hash comparison (local, fast, no remote calls)
  • Tier 2: container config hash via transport (remote, only if Tier 1 passes)

If transport is nil, Tier 2 is skipped (read-only/local mode).

type EnvFile

type EnvFile struct {
	Path      string // relative to stack dir
	FullPath  string // absolute path
	Encrypted bool   // SOPS-encrypted (detected by naming or content)
}

EnvFile describes a discovered environment file within a stack.

type ExecResult

type ExecResult struct {
	Success  bool
	ExitCode int
	Stdout   string
	Stderr   string
	Duration time.Duration
}

ExecResult is the structured outcome of a transport execution. All transports (local, SSH, future agents) return the same shape. Full stderr captured — renderer decides how to tail/truncate.

type HashStamps

type HashStamps struct {
	Stacks map[string]StackStamp `yaml:"stacks"` // key: "scope/stack"
}

HashStamps tracks last-known hashes for drift detection. Stored in .stagefreight-state.yml (git-tracked).

func LoadHashStamps

func LoadHashStamps(rootDir string) (*HashStamps, error)

LoadHashStamps reads the .stagefreight-state.yml file. Returns empty stamps if file doesn't exist.

type Hook

type Hook struct {
	Phase string // "pre" | "post"
	Path  string // relative to BundleDir
}

Hook is a lifecycle hook within a stack action.

type HostTarget

type HostTarget struct {
	Name      string
	Address   string
	Groups    []string          // populated from inventory group membership
	Vars      map[string]string // host variables from inventory
	Transport HostTransport     // established during Prepare phase
}

HostTarget represents a resolved Docker reconciliation target.

type HostTransport

type HostTransport interface {
	ExecuteAction(ctx context.Context, action StackAction) (ExecResult, error)
	// InspectStack queries runtime state for a compose project.
	// Read-only. Returns structured runtime facts, not CLI output.
	// Selects containers by Compose project label, not name.
	InspectStack(ctx context.Context, project string) (StackInspection, error)
	// ListProjects returns all compose project names running on this host.
	// Uses -a to include stopped containers (stopped = still logically exists).
	ListProjects(ctx context.Context) ([]string, error)
	Close() error
}

HostTransport executes typed stack actions on a target host. Transport compiles the intent to whatever execution form it needs. It does NOT know compose lifecycle semantics — it executes steps.

func ResolveTransport

func ResolveTransport(target HostTarget) HostTransport

ResolveTransport creates the appropriate transport for a host target.

type InventorySource

type InventorySource interface {
	Name() string
	Resolve(ctx context.Context, selector TargetSelector) ([]HostTarget, error)
}

InventorySource resolves candidate hosts from an external source. Adapter boundary: no source-specific concepts (Ansible, etc.) leak past this.

type LocalTransport

type LocalTransport struct{}

LocalTransport executes stack actions directly on the local host. Compiles StackAction → local exec commands.

func (*LocalTransport) Close

func (l *LocalTransport) Close() error

func (*LocalTransport) ExecuteAction

func (l *LocalTransport) ExecuteAction(ctx context.Context, action StackAction) (ExecResult, error)

func (*LocalTransport) InspectStack

func (l *LocalTransport) InspectStack(ctx context.Context, project string) (StackInspection, error)

InspectStack queries running containers for a compose project by label. Thin: lists container IDs, delegates parsing to inspect.go.

func (*LocalTransport) ListProjects

func (l *LocalTransport) ListProjects(ctx context.Context) ([]string, error)

ListProjects returns all compose project names on the local host.

type OrphanPlan

type OrphanPlan struct {
	Project string       `json:"project"`
	Scope   string       `json:"scope"`
	Reason  string       `json:"reason"`
	Action  ActionDetail `json:"action"`
}

OrphanPlan represents a running project with no IaC declaration.

type PlanOutput

type PlanOutput struct {
	Mode      string       `json:"mode"`
	Backend   string       `json:"backend"`
	Generated time.Time    `json:"generated_at"`
	Summary   PlanSummary  `json:"summary"`
	Trust     TrustOutput  `json:"trust"`
	Targets   []TargetPlan `json:"targets"`
}

PlanOutput is the stable external schema for Docker lifecycle plan data. Designed for DD-UI consumption, CI artifacts, and --output json. Backend decides; frontend renders. No frontend guesswork.

func BuildPlanOutput

func BuildPlanOutput(plan *runtime.LifecyclePlan, trust DiscoveryTrust, targets []HostTarget) PlanOutput

BuildPlanOutput converts internal plan + trust into the stable external schema. Uses DockerPlanMeta signals directly — no inference from action type.

func (PlanOutput) JSON

func (p PlanOutput) JSON() ([]byte, error)

JSON produces the stable JSON output.

type PlanSummary

type PlanSummary struct {
	Total   int            `json:"total"`
	Drifted int            `json:"drifted"`
	Orphans int            `json:"orphans"`
	Blocked int            `json:"blocked"`
	Actions map[string]int `json:"actions"`
}

PlanSummary provides top-level counts.

type SOPSProvider

type SOPSProvider struct{}

SOPSProvider implements SecretsProvider using the sops CLI.

func (*SOPSProvider) Decrypt

func (s *SOPSProvider) Decrypt(_ context.Context, path string) ([]byte, error)

Decrypt decrypts a SOPS-encrypted file and returns the plaintext.

func (*SOPSProvider) Encrypt

func (s *SOPSProvider) Encrypt(_ context.Context, path string, data []byte) error

Encrypt encrypts data and writes it to path using SOPS.

func (*SOPSProvider) IsEncrypted

func (s *SOPSProvider) IsEncrypted(path string) bool

IsEncrypted checks if a file path matches SOPS naming conventions.

func (*SOPSProvider) Name

func (s *SOPSProvider) Name() string

type SSHTransport

type SSHTransport struct {
	Host    string
	User    string
	KeyPath string
}

SSHTransport executes stack actions on a remote host via SSH. Copies bundle to remote tmpdir, executes, cleans up.

func (*SSHTransport) Close

func (s *SSHTransport) Close() error

func (*SSHTransport) ExecuteAction

func (s *SSHTransport) ExecuteAction(ctx context.Context, action StackAction) (ExecResult, error)

func (*SSHTransport) InspectStack

func (s *SSHTransport) InspectStack(ctx context.Context, project string) (StackInspection, error)

InspectStack queries running containers for a compose project on the remote host. Thin: lists container IDs via SSH, delegates parsing to inspect.go.

func (*SSHTransport) ListProjects

func (s *SSHTransport) ListProjects(ctx context.Context) ([]string, error)

ListProjects returns all compose project names on the remote host.

type SecretsProvider

type SecretsProvider interface {
	Name() string
	Decrypt(ctx context.Context, path string) ([]byte, error)
	Encrypt(ctx context.Context, path string, data []byte) error
	IsEncrypted(path string) bool
}

SecretsProvider handles encryption/decryption for stack secret files. SOPS today, Vault/Infisical later.

func ResolveSecretsProvider

func ResolveSecretsProvider(name string) (SecretsProvider, error)

ResolveSecretsProvider returns the appropriate provider by name.

type ServiceRuntimeState

type ServiceRuntimeState struct {
	Service     string
	ConfigHash  string // com.docker.compose.config-hash label
	Image       string
	Running     bool
	State       string // running, exited, dead, etc.
	ContainerID string
}

ServiceRuntimeState is the canonical runtime state of a single compose service. Primary Tier 2 signal: ConfigHash.

type StackAction

type StackAction struct {
	Target      string // host identity
	Stack       string // scope/name
	Action      string // "up", "down", "restart"
	ProjectName string // docker compose -p flag
	WorkDir     string // working directory (relative to bundle or host-resolved)

	// Staged bundle: transport decides how to materialize this.
	// SSH copies it to remote tmpdir. Agent receives it as payload.
	BundleDir string // local staging root containing all needed files

	// Compose file and env files — relative to BundleDir.
	ComposeFile string   // e.g. "compose.yaml"
	EnvFiles    []string // e.g. [".env", "app_secret.env"]

	// Hooks as ordered execution steps, not raw paths.
	Hooks []Hook
}

StackAction is a typed execution intent for the transport layer. Represents WHAT to execute, not HOW today's transport executes it. Transport receives this, compiles it to whatever form it needs. No absolute paths, no filesystem assumptions, no transport coupling.

type StackInfo

type StackInfo struct {
	Scope          string // host name or group name
	ScopeKind      string // "host" or "group"
	Name           string // stack directory name
	Path           string // relative path from repo root
	ComposeFile    string // detected compose filename
	ComposeProject string // canonical compose project name (for container identity)
	EnvFiles       []EnvFile
	Scripts        []string // pre.sh, deploy.sh, post.sh
	DeployKind     string   // "compose", "script", "unmanaged"
}

StackInfo describes a discovered IaC stack.

func ScanIaC

func ScanIaC(rootDir, iacPath string, knownHosts map[string]bool) ([]StackInfo, error)

ScanIaC walks the IaC directory and discovers all compose stacks. Directory convention: <iac_path>/<scope>/<stack>/ DD-UI proven discovery patterns carried forward.

type StackInspection

type StackInspection struct {
	Project  string
	Services []ServiceRuntimeState
}

StackInspection is the canonical runtime state of a compose project. Reduced model — only the signals needed for drift detection.

type StackPlan

type StackPlan struct {
	Name    string       `json:"name"`
	Project string       `json:"project"`
	Scope   string       `json:"scope"`
	Status  string       `json:"status"` // in_sync | drift | blocked | unknown
	Drift   DriftDetail  `json:"drift"`
	Action  ActionDetail `json:"action"`
}

StackPlan is the resolved state of a declared stack.

type StackStamp

type StackStamp struct {
	BundleHash string    `yaml:"bundle_hash"`
	ConfigHash string    `yaml:"config_hash"` // runtime compose config hash from last apply
	DeployedAt time.Time `yaml:"deployed_at"`
}

StackStamp records the hash state of a stack after successful deployment.

type TargetPlan

type TargetPlan struct {
	Name      string         `json:"name"`
	Transport string         `json:"transport"`
	Stacks    []StackPlan    `json:"stacks"`
	Orphans   []OrphanPlan   `json:"orphans,omitempty"`
	Anomalies []AnomalyEntry `json:"anomalies,omitempty"`
}

TargetPlan groups stacks and orphans per host.

type TargetSelector

type TargetSelector struct {
	Groups []string `yaml:"groups"`
}

TargetSelector declares which hosts are eligible for reconciliation. Group-based initially (existing Ansible groups). Extensible later only if groups become insufficient.

type TrustChecks

type TrustChecks struct {
	Sentinel        bool `json:"sentinel"`
	IaCRoot         bool `json:"iac_root"`
	Scan            bool `json:"scan"`
	RepoIdentity    bool `json:"repo_identity"`
	DeclaredTargets bool `json:"declared_targets"`
}

TrustChecks shows individual trust gate results.

type TrustFailureReason

type TrustFailureReason string

TrustFailureReason is a typed, machine-meaningful reason for trust failure.

const (
	ReasonNoSentinel        TrustFailureReason = "no_sentinel"
	ReasonIaCRootMissing    TrustFailureReason = "iac_root_missing"
	ReasonScanFailed        TrustFailureReason = "scan_failed"
	ReasonRepoMismatch      TrustFailureReason = "repo_identity_mismatch"
	ReasonTargetNotDeclared TrustFailureReason = "target_not_declared"
	ReasonLifecycleMismatch TrustFailureReason = "lifecycle_mode_mismatch"
)

type TrustLevel

type TrustLevel string

TrustLevel indicates how authoritative the repository discovery is. Destructive actions require Authoritative. Uncertain → observe only.

const (
	TrustNone          TrustLevel = "none"
	TrustPartial       TrustLevel = "partial"
	TrustAuthoritative TrustLevel = "authoritative"
)

type TrustOutput

type TrustOutput struct {
	Level   string      `json:"level"`
	Checks  TrustChecks `json:"checks"`
	Reasons []string    `json:"reasons,omitempty"`
}

TrustOutput is the external representation of DiscoveryTrust.

Jump to

Keyboard shortcuts

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