imagebuilder

package
v0.0.0-...-890248b Latest Latest
Warning

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

Go to latest
Published: May 21, 2026 License: AGPL-3.0 Imports: 15 Imported by: 0

Documentation

Overview

Package imagebuilder ports the v26.2.7 image builder module forward into the v26.5.1 AGPL build. It tracks Dockerfile build jobs against the local Docker daemon, persists a small library of starter templates, and (when configured) hooks each successful build into the existing imagesign service so the resulting image gets a Sigstore cosign signature on the way out.

Improvements vs v26.2.7:

  • Build logs stream through Redis pub/sub instead of being buffered in memory inside the service. The handler subscribes per-build and bridges the stream into a WebSocket / SSE response. The output column on the row is filled only at the end with a tail-window of the log so the table view stays bounded.
  • The build daemon is invoked through the docker.ClientAPI surface the rest of the codebase already depends on; no new socket mount is opened.
  • Build context uploads are capped at 256 MiB by default (configurable). The cap is enforced at the service boundary so an oversized payload is rejected before it reaches the daemon.
  • The starter template seeder writes a curated set of AGPL-safe Dockerfile snippets on first start. Each template is tagged IsBuiltin so the UI can hide the delete button.
  • The optional imagesign hook signs the resulting image when cfg.Sign.Enabled is true; failures are logged but do not flip the build to failed (the image is already on disk by then).
  • No biz gating, no edition checks, no call-home.

Index

Constants

View Source
const DefaultLogTailBytes = 64 * 1024

DefaultLogTailBytes is the size of the trailing slice of the build log persisted to image_build_jobs.output. The Redis pub/sub stream carries the full log during the run; the database column only retains the tail so a single bad build cannot bloat the row.

View Source
const DefaultMaxContextBytes int64 = 256 * 1024 * 1024

DefaultMaxContextBytes caps the build-context upload at 256 MiB. The figure matches the value documented in session-08-image-builder.md (Risks section). Operators raise the cap via Config.MaxContextBytes when their Dockerfiles ship genuinely large assets.

Variables

View Source
var (
	// ErrInvalidInput is returned when the caller supplies malformed
	// fields (empty Dockerfile, no tag, etc.).
	ErrInvalidInput = stderrors.New("imagebuilder: invalid input")

	// ErrContextTooLarge is returned when the build-context upload
	// exceeds Config.MaxContextBytes.
	ErrContextTooLarge = stderrors.New("imagebuilder: build context exceeds maximum size")

	// ErrBuilderUnavailable is returned when the docker client is not
	// configured (typically because the socket is not mounted).
	ErrBuilderUnavailable = stderrors.New("imagebuilder: docker client not configured")

	// ErrBuiltinDelete is returned when a caller tries to delete a
	// built-in template.
	ErrBuiltinDelete = stderrors.New("imagebuilder: built-in templates cannot be deleted")
)

Sentinel errors. API and web handlers map these to typed responses.

Functions

This section is empty.

Types

type BuildJobRepository

type BuildJobRepository interface {
	Create(ctx context.Context, job *models.ImageBuildJob) error
	GetByID(ctx context.Context, id uuid.UUID) (*models.ImageBuildJob, error)
	Update(ctx context.Context, job *models.ImageBuildJob) error
	ListByHost(ctx context.Context, hostID uuid.UUID, limit, offset int) ([]models.ImageBuildJob, int, error)
	GetStats(ctx context.Context, hostID uuid.UUID) (*models.ImageBuildJobStats, error)
}

BuildJobRepository defines persistence for image build jobs.

type Config

type Config struct {
	// MaxContextBytes caps the build-context tar upload. Defaults to
	// DefaultMaxContextBytes (256 MiB).
	MaxContextBytes int64

	// LogTailBytes is the number of trailing bytes of the build log
	// persisted to the row. Defaults to DefaultLogTailBytes (64 KiB).
	LogTailBytes int

	// LogChannelPrefix is the Redis pub/sub channel prefix. Builds are
	// published to "<prefix>:<build_id>". Empty disables publishing.
	LogChannelPrefix string
}

Config holds runtime knobs for the image builder.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns the canonical knobs.

type DockerBuilder

type DockerBuilder interface {
	ImageBuild(ctx context.Context, buildContext io.Reader, opts types.ImageBuildOptions) (types.ImageBuildResponse, error)
}

DockerBuilder is the narrow surface the service consumes from the docker package. Declaring it here lets the unit tests pass a fake.

type LogPublisher

type LogPublisher interface {
	Publish(ctx context.Context, channel string, payload []byte) error
}

LogPublisher abstracts Redis pub/sub. Production wires in a thin adapter over *redis.PubSub; unit tests pass a memory channel so they can assert what gets published.

type RedisLogPublisher

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

RedisLogPublisher adapts *redis.PubSub onto the LogPublisher interface the service depends on. The build path stays free of pub-sub specifics so unit tests can substitute a memory channel.

func NewRedisLogPublisher

func NewRedisLogPublisher(pub *redis.PubSub) *RedisLogPublisher

NewRedisLogPublisher returns a publisher backed by the given pub/sub client. Pass nil pub when Redis is not configured; the resulting publisher is a no-op so the build path still completes.

func (*RedisLogPublisher) PubSub

func (p *RedisLogPublisher) PubSub() *redis.PubSub

PubSub exposes the underlying pub-sub so the API handler can subscribe on the same instance. Returns nil when Redis is not configured.

func (*RedisLogPublisher) Publish

func (p *RedisLogPublisher) Publish(ctx context.Context, channel string, payload []byte) error

Publish forwards raw log bytes to the named channel. A nil pub-sub returns nil so the build does not abort when Redis is unavailable — the API handler degrades to "log streaming disabled" instead.

type Service

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

Service implements the image builder business logic.

func NewService

func NewService(builds BuildJobRepository, templates TemplateRepository, docker DockerBuilder, publisher LogPublisher, cfg Config, log *logger.Logger) *Service

NewService creates a new image builder service. docker, publisher and signHook are optional — the service degrades gracefully when any of them is nil. A nil logger is replaced with a no-op.

func (*Service) CreateTemplate

func (s *Service) CreateTemplate(ctx context.Context, hostID uuid.UUID, name, description, category, dockerfile string, userID *uuid.UUID) (*models.DockerfileTemplate, error)

CreateTemplate creates a new user-defined Dockerfile template. Builtin templates are seeded via SeedBuiltinTemplates and never created via this entry point.

func (*Service) DeleteTemplate

func (s *Service) DeleteTemplate(ctx context.Context, id uuid.UUID) error

DeleteTemplate deletes a Dockerfile template, refusing to delete one that the binary seeded.

func (*Service) GetBuild

func (s *Service) GetBuild(ctx context.Context, id uuid.UUID) (*models.ImageBuildJob, error)

GetBuild returns a build job by ID.

func (*Service) GetStats

func (s *Service) GetStats(ctx context.Context, hostID uuid.UUID) (*models.ImageBuildJobStats, error)

GetStats returns aggregate build statistics for a host.

func (*Service) GetTemplate

func (s *Service) GetTemplate(ctx context.Context, id uuid.UUID) (*models.DockerfileTemplate, error)

GetTemplate returns a template by ID.

func (*Service) ListBuilds

func (s *Service) ListBuilds(ctx context.Context, hostID uuid.UUID, limit, offset int) ([]models.ImageBuildJob, int, error)

ListBuilds returns paginated build jobs for a host.

func (*Service) ListTemplates

func (s *Service) ListTemplates(ctx context.Context, hostID uuid.UUID) ([]models.DockerfileTemplate, error)

ListTemplates returns all Dockerfile templates for a host.

func (*Service) LogChannel

func (s *Service) LogChannel(buildID uuid.UUID) string

LogChannel returns the Redis pub/sub channel for a given build. The API handler uses the same helper so the publisher and subscriber stay in lock-step.

func (*Service) MaxContextBytes

func (s *Service) MaxContextBytes() int64

MaxContextBytes returns the configured upload cap. Exported so the API handler can produce a precise 413 error.

func (*Service) SeedBuiltinTemplates

func (s *Service) SeedBuiltinTemplates(ctx context.Context, hostID uuid.UUID) error

SeedBuiltinTemplates ensures the curated AGPL-compatible starter templates are present for the given host. Calling SeedBuiltinTemplates twice is a no-op — the seeder skips templates whose name + IsBuiltin pair already exists.

Each shipped template is a minimal Dockerfile snippet that pulls only from public, AGPL-compatible upstreams (alpine, debian-slim, the official language image families). Operators add proprietary content via user-defined templates.

func (*Service) SetSignHook

func (s *Service) SetSignHook(hook SignHook)

SetSignHook installs (or replaces) the optional image signing hook. Pass nil to disable signing.

func (*Service) StartBuild

func (s *Service) StartBuild(ctx context.Context, opts StartBuildOptions) (*models.ImageBuildJob, error)

StartBuild creates a new build job, queues the build, and returns the job row. The actual docker build runs synchronously inside StartBuild so callers that want to stream logs subscribe to LogChannel(job.ID) before the call returns. The handler handles the dispatch.

Improvements vs v26.2.7: explicit context-size enforcement, real Docker invocation (the v26.2.7 service stubbed it out with a fake "build completed" string), Redis log streaming with a bounded tail persisted, and the optional imagesign hook on success.

type SignHook

type SignHook func(ctx context.Context, imageRef string) (signatureRef string, err error)

SignHook is the optional integration with the imagesign service. When non-nil and the build succeeds, the service calls Sign with the resulting image reference. The returned signature reference (SHA256 of the cosign payload, or empty if signing was disabled) is recorded on the job row.

type StartBuildOptions

type StartBuildOptions struct {
	HostID       uuid.UUID
	Name         string
	Tags         []string
	Dockerfile   string
	ContextPath  string
	BuildContext []byte // raw tar.gz of the build context. May be nil for the inline-Dockerfile case.
	BuildArgs    map[string]string
	Labels       map[string]string
	NoCache      bool
	Pull         bool
	Platform     string
	Target       string
	UserID       *uuid.UUID
}

StartBuildOptions bundles the per-build parameters. Promoted to a struct so the API handler does not have to track an ever-lengthening positional argument list.

type TemplateRepository

type TemplateRepository interface {
	Create(ctx context.Context, t *models.DockerfileTemplate) error
	GetByID(ctx context.Context, id uuid.UUID) (*models.DockerfileTemplate, error)
	List(ctx context.Context, hostID uuid.UUID) ([]models.DockerfileTemplate, error)
	Update(ctx context.Context, t *models.DockerfileTemplate) error
	Delete(ctx context.Context, id uuid.UUID) error
}

TemplateRepository defines persistence for Dockerfile templates.

Jump to

Keyboard shortcuts

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