sandbox

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package sandbox manages the isolated Docker environment in which a restored PostgreSQL database is started and validated.

Index

Constants

View Source
const ArtifactMountDir = "/restorelab/artifact"

ArtifactMountDir is the directory inside the container where the parent directory of the restored artifact is bind-mounted read-only. The artifact itself is accessible at ArtifactMountDir/<basename>.

View Source
const ContainerNamePrefix = "restorelab-postgres-"

ContainerNamePrefix is prepended to every sandbox container name.

View Source
const InspectionNamePrefix = "restorelab-inspect-"

InspectionNamePrefix is prepended to inspection container names.

View Source
const NetworkCleanupTimeout = 30 * time.Second

NetworkCleanupTimeout is the deadline for network removal.

View Source
const NetworkNamePrefix = "restorelab-"

NetworkNamePrefix is prepended to every sandbox network name so stray networks can be identified easily.

View Source
const VolumeNamePrefix = "restorelab-"

VolumeNamePrefix is prepended to every sandbox volume name.

Variables

This section is empty.

Functions

func AllPassed

func AllPassed(results []AuditResult) bool

AllPassed reports whether every AuditResult passed.

func ArtifactPathInContainer

func ArtifactPathInContainer(hostPath string) string

ArtifactPathInContainer returns the absolute path of hostPath as seen from inside the sandbox container.

func CreateInternalNetwork

func CreateInternalNetwork(ctx context.Context, cli *client.Client, runID string) (string, error)

CreateInternalNetwork creates a Docker network with Internal=true so containers attached to it cannot reach the outside world. It returns the network ID.

Note: internal=true prevents egress through the default gateway but does NOT prevent DNS queries via the host resolver on unpatched Docker Engine versions. See CVE-2024-29018.

func CreatePGDataVolume

func CreatePGDataVolume(ctx context.Context, cli *client.Client, runID string) (string, error)

CreatePGDataVolume creates a temporary volume to hold PGDATA. Using a volume (rather than tmpfs) is essential: tmpfs would keep the entire database in RAM, which is impractical for datasets larger than memory.

The volume is registered in the cleanup registry by the caller.

func InspectArchive

func InspectArchive(ctx context.Context, cli *client.Client, cfg InspectConfig) error

InspectArchive runs `pg_restore --list` on the artifact using a disposable container built from the same image as the sandbox.

The container is deliberately minimal and hostile to the archive:

  • no network (NetworkMode = "none")
  • no writable volume
  • readonly rootfs
  • one read-only bind mount of the artifact's parent directory
  • cap_drop = ALL
  • one tmpfs (/tmp) for any transient files pg_restore may need

The container is removed unconditionally when this function returns, whether the check succeeded or failed.

This implements Design Document v2.0.0 step 12: fail-fast on structurally broken archives before allocating the full sandbox.

func StartContainer

func StartContainer(ctx context.Context, cli *client.Client, c *Container) error

StartContainer starts a previously-created sandbox container.

func Summary

func Summary(results []AuditResult) string

Summary returns a one-line summary of the audit results. For any failed check, the summary includes the check's Details string so operators can see exactly what went wrong without opening the full report.

Types

type AuditResult

type AuditResult struct {
	Name    string
	Passed  bool
	Details string
}

AuditResult is the outcome of a single isolation property check.

func AuditContainer

func AuditContainer(ctx context.Context, cli *client.Client, containerID, expectedNetwork string) ([]AuditResult, error)

AuditContainer inspects a running container and verifies each isolation invariant required by the RestoreLab design document (sections 10-12):

  • no published ports
  • exactly one network, matching expectedNetwork
  • no Docker socket bind
  • no read-write bind mounts
  • ReadonlyRootfs = true
  • privileged = false
  • "no-new-privileges" present in SecurityOpt
  • CapDrop contains "ALL"
  • CapAdd is exactly the expected minimal set
  • Memory limit is set (> 0)
  • PidsLimit is set (> 0)

It returns one AuditResult per property, in a stable order.

type Container

type Container struct {
	ID          string
	Name        string
	NetworkName string

	// ArtifactPathInContainer is the path where the artifact is
	// accessible inside the container. Empty if no artifact was
	// mounted.
	ArtifactPathInContainer string
}

Container is a handle to a running sandbox container.

func CreatePostgresContainer

func CreatePostgresContainer(ctx context.Context, cli *client.Client, cfg ContainerConfig) (*Container, error)

CreatePostgresContainer creates (but does not start) a hardened PostgreSQL container attached to the internal network.

Security properties enforced here:

  • cap_drop=ALL + cap_add=<minimal set>
  • no-new-privileges:true
  • ReadonlyRootfs=true (writable paths via tmpfs and the volume)
  • no published ports (PortBindings=nil, PublishAllPorts=false)
  • no privileged mode
  • no docker.sock mount
  • resource limits: ShmSize, Memory, PidsLimit
  • attached only to the internal sandbox network
  • artifact bind-mounted read-only (if ArtifactPath is set)

type ContainerConfig

type ContainerConfig struct {
	// Image is the pinned-by-digest image reference.
	Image string

	// RunID uniquely identifies this recovery drill.
	RunID string

	// NetworkName is the internal network the container joins.
	NetworkName string

	// PGDataVolume is the volume name mounted at PGDATA.
	PGDataVolume string

	// ArtifactPath is the absolute path on the host to the
	// restored artifact file. When non-empty, its parent
	// directory is bind-mounted read-only at ArtifactMountDir
	// so pg_restore can read it without any write access.
	ArtifactPath string

	// Database, Username, Password seed the initial database.
	Database string
	Username string
	Password string

	// ShmSize in bytes. Must be > 0 and <= Memory.
	ShmSize int64

	// Memory limit in bytes. Must be > 0.
	Memory int64

	// PidsLimit must be > 0.
	PidsLimit int64
}

ContainerConfig collects every input needed to create a hardened PostgreSQL container.

func (ContainerConfig) Validate

func (c ContainerConfig) Validate() error

Validate checks that the configuration is internally consistent before we call Docker. This is a defense-in-depth check on top of the contract validator.

type InspectConfig

type InspectConfig struct {
	Image        string
	RunID        string
	ArtifactPath string
}

InspectConfig collects inputs for a one-shot inspection.

type Registry

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

Registry tracks every Docker resource the sandbox creates so they can all be removed even if the run fails halfway through.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns an empty Registry.

func (*Registry) Add

func (r *Registry) Add(kind ResourceKind, id, name string)

Add records a resource for later cleanup. It is safe to call from any goroutine.

func (*Registry) Cleanup

func (r *Registry) Cleanup(ctx context.Context, cli *client.Client, logger *slog.Logger) []error

Cleanup removes every tracked resource in reverse order (containers first, then volumes, then networks). It is best-effort: errors are logged but do not stop cleanup of remaining resources.

func (*Registry) Snapshot

func (r *Registry) Snapshot() []Resource

Snapshot returns a copy of the tracked resources.

type Resource

type Resource struct {
	Kind ResourceKind
	ID   string
	Name string
}

Resource is a single Docker object that must be cleaned up.

type ResourceKind

type ResourceKind string

ResourceKind identifies the type of Docker resource tracked.

const (
	KindContainer ResourceKind = "container"
	KindVolume    ResourceKind = "volume"
	KindNetwork   ResourceKind = "network"
)

Jump to

Keyboard shortcuts

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