validation

package
v0.8.1 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

README

pkg/controller/validation

HAProxy configuration validator with per-call sandboxing.

Overview

ValidationService writes the rendered HAProxy config and auxiliary files into an isolated os.MkdirTemp tree, rewrites default-path origin to that tree, and invokes haproxy -c. A cancellable gate bounds concurrent binary checks.

Every call executes HAProxy, including calls with byte-identical output. The binary, executor, DNS state, and other runtime inputs can change between calls, so a content checksum alone cannot carry a prior verdict forward. Future result reuse requires an authenticated hermetic-environment root bound to the exact config and auxiliary bytes.

The service is used by strict pipeline validation and the leader-side render gate. Snapshot entry points authenticate and materialize their immutable input before invoking the same check.

Quick Start

import (
    "github.com/haproxy-haptic/HAPTIC/pkg/controller/validation"
    "github.com/haproxy-haptic/HAPTIC/pkg/dataplane"
)

svc := validation.NewValidationService(&validation.ValidationServiceConfig{
    Logger:            logger,
    SkipDNSValidation: false,
    BaseDir:           "/etc/haproxy",
    MapsDir:           "maps",
    SSLCertsDir:       "ssl",
    GeneralDir:        "general",
    CheckGate:         dataplane.NewCheckGate(0),
})

// The checksum remains the render's downstream content identity. It never
// authorizes validation reuse.
checksum := dataplane.ComputeContentChecksum(haproxyConfig, auxFiles)
result := svc.ValidateWithChecksum(ctx, haproxyConfig, auxFiles, checksum)
// result.Valid, result.Phase, result.Error

SkipDNSValidation adds HAProxy's -dr flag. Runtime checks use it so a temporarily unresolvable backend starts down instead of blocking convergence; strict proposal validation can leave it false.

Validation semantics

Call Behaviour
Any authenticated input, including an exact repeat Materialize the files and run haproxy -c
HAProxy refusal Return a semantic validation error
Cancellation before, during, or immediately after the check Return the cancellation cause; never report success
Invalid snapshot authentication Fail during setup without running HAProxy

See Also

License

Apache-2.0 — see root LICENSE.

Documentation

Overview

Package validation provides pure validation services for HAProxy configuration.

Index

Constants

View Source
const (
	// DefaultBaseDir is the default base directory for HAProxy configuration.
	DefaultBaseDir = "/etc/haproxy"

	// DefaultMapsDir is the default relative directory name for map files.
	DefaultMapsDir = "maps"

	// DefaultSSLCertsDir is the default relative directory name for SSL certificates.
	DefaultSSLCertsDir = "ssl"

	// DefaultGeneralDir is the default relative directory name for general files.
	DefaultGeneralDir = "general"
)

Default directory paths for HAProxy validation.

View Source
const (
	CheckPassed    = "passed"
	CheckRefused   = "refused"
	CheckError     = "error"
	CheckCancelled = "cancelled"
)

Check results reported to a CheckObserver.

View Source
const (
	// DefaultValidationTimeout is the default timeout for validation operations.
	// This is used by event handlers and webhook validators to prevent indefinite hangs.
	// 30 seconds allows sufficient time for render + validate while preventing stuck requests.
	DefaultValidationTimeout = 30 * time.Second
)

Timeout constants for validation operations.

Variables

This section is empty.

Functions

func CheckResult

func CheckResult(ctx context.Context, err error) string

CheckResult classifies a check's error: HAProxy's verdict, a cancellation, or a check that could not run.

Types

type CheckObserver

type CheckObserver func(result string, reused bool)

CheckObserver receives one check's result (see CheckResult) and whether its verdict was reused instead of running `haproxy -c`.

type ValidationResult

type ValidationResult struct {
	// Valid is true if the configuration passed all validation phases.
	Valid bool

	// Error contains the validation error if Valid is false.
	Error error

	// Phase indicates which validation phase failed (semantic, render, setup).
	// Empty if validation succeeded.
	Phase string

	// DurationMs is the total validation duration in milliseconds.
	DurationMs int64

	// Warnings contains non-fatal diagnostics from additional validation stages.
	Warnings []string
}

ValidationResult contains the output of a validation operation.

func (*ValidationResult) ErrorMessage

func (r *ValidationResult) ErrorMessage() string

ErrorMessage returns a user-friendly error message. Returns empty string if validation succeeded.

type ValidationService

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

ValidationService is a pure service that validates HAProxy configuration.

This service encapsulates temp directory lifecycle internally: - Creates an isolated temp directory for each validation - Writes config and auxiliary files - Runs haproxy -c for semantic validation - Cleans up temp directory after validation

HAProxy's own verdict is the whole check: it is a strict superset of any parse HAPTIC could run over the same bytes (ADR-0022).

The service can be called concurrently from multiple goroutines.

func NewValidationService

func NewValidationService(cfg *ValidationServiceConfig) *ValidationService

NewValidationService creates a new ValidationService.

func (*ValidationService) ValidateOutputSnapshotWithChecksum

func (s *ValidationService) ValidateOutputSnapshotWithChecksum(
	ctx context.Context,
	snapshot *renderoutput.Snapshot,
	_ string,
) *ValidationResult

ValidateOutputSnapshotWithChecksum validates one authenticated complete render output.

func (*ValidationService) ValidateSnapshotWithChecksum

func (s *ValidationService) ValidateSnapshotWithChecksum(
	ctx context.Context,
	config string,
	snapshot *renderartifact.Snapshot,
	_ string,
) *ValidationResult

ValidateSnapshotWithChecksum validates an authenticated immutable auxiliary-file set.

func (*ValidationService) ValidateWithChecksum

func (s *ValidationService) ValidateWithChecksum(ctx context.Context, config string, auxFiles *dataplane.AuxiliaryFiles, _ string) *ValidationResult

ValidateWithChecksum validates HAProxy configuration. The checksum never authorizes skipping HAProxy's runtime verdict.

This method: 1. Creates an isolated temp directory 2. Replaces production baseDir with temp directory in config (for default-path origin) 3. Writes the config and auxiliary files 4. Runs `haproxy -c` using the MODIFIED config 5. Cleans up the temp directory

Parameters:

  • ctx: Context for cancellation
  • config: The rendered HAProxy configuration content
  • auxFiles: Auxiliary files (maps, certificates, general files)
  • checksum: Caller-provided content identity; it never authorizes verdict reuse

type ValidationServiceConfig

type ValidationServiceConfig struct {
	// Logger is the structured logger for logging.
	Logger *slog.Logger

	// SkipDNSValidation controls whether to skip DNS resolution failures during validation.
	// When true, servers with unresolvable hostnames start in DOWN state instead of failing.
	// When false (strict mode), DNS resolution failures cause validation to fail.
	SkipDNSValidation bool

	// BaseDir is the production base directory used in "default-path origin" directive.
	// During local validation, this is replaced with the temp directory path so that
	// HAProxy resolves relative paths from the temp directory instead of production paths.
	// Example: "/etc/haproxy"
	BaseDir string

	// MapsDir is the relative directory name for map files (e.g., "maps").
	// Should match the basename of the dataplane MapsDir config.
	MapsDir string

	// SSLCertsDir is the relative directory name for SSL certificates (e.g., "ssl").
	// Should match the basename of the dataplane SSLCertsDir config.
	SSLCertsDir string

	// GeneralDir is the relative directory name for general files (e.g., "general").
	// Should match the basename of the dataplane GeneralStorageDir config.
	GeneralDir string

	// CheckGate serializes this service's `haproxy -c` runs. Give the render
	// gate its own so admission never waits out a fleet-sized config check.
	CheckGate *dataplane.CheckGate

	// Verdicts answers an input set HAProxy already judged; services sharing
	// one never check the same bytes twice. Nil checks every time, and a
	// strict-DNS service never reuses a verdict.
	Verdicts *dataplane.CheckVerdicts

	// CheckObserver is told about every check this service asks HAProxy for.
	CheckObserver CheckObserver
}

ValidationServiceConfig contains configuration for creating a ValidationService.

Jump to

Keyboard shortcuts

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