lab

package
v0.10.9 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2026 License: MIT Imports: 81 Imported by: 0

Documentation

Overview

Package lab runs the maintained acceptance modules against a workspace and a target.

The package is importable: a separate device lab, with its own drivers, target matrix, Apple credentials and private evidence, registers its own modules against these types and reuses this runner, result model and report rather than reimplementing them.

Design

A workspace keeps local identities and configuration across runs. Start can embed the server runtime or launch dmserver processes, using the same server configuration in either case. Up supervises those processes in the foreground; other commands attach through an authenticated loopback control endpoint.

The catalogue is one ordered inventory of modules. A module declares the workspace modes whose server environment it needs, the target capabilities it uses and the lifecycle stage that orders it. Modes select the service environment: simulated workspaces provide local Apple-service fixtures, while live workspaces use the operator's Apple credentials and a real device. Targets, in package target, supply the device side. A run writes JSON, JUnit and a self-contained HTML report, distinguishing failures from unavailable prerequisites and inapplicable modules.

Doctor and the offline preflight report missing prerequisites without enrolling a device or changing its trust settings.

ADE modules separate read-only server-token/API evidence, explicitly opted-in designated assignment with private recovery fencing, and actual native enrollment proof. API and fixture passes cannot certify hardware. Per-platform results retain unexercised scope, and DDM exchange and cleanup have independent evidence. See docs/operations/ade-acceptance.md for private inputs and executable live steps.

Apps and Books checks independently collect read-only location evidence, exercise explicitly designated free-app licensing through SDK and reference paths with private original-state fencing, and inspect actual native app installation/version. Licensing callbacks, aggregate status, per-target readback and cleanup are separate requirements. An inspection never removes a preexisting app or claims restoration after external preparation. User licensing retains Apple's clientUserId independently of hardware serials. See docs/operations/apps-and-books-acceptance.md for private inputs and scope.

References

Index

Constants

View Source
const (

	// ComposeFile is the lab stack, relative to the repository root.
	ComposeFile = "deploy/lab/compose.yaml"
	// EnvFile is the generated container environment, private to the workspace.
	EnvFile = "lab.env"
)

Container layout. The workspace's mdm directory is the container's data volume, so identities, the database and any configured policy file keep one home on the host.

View Source
const (
	StagePreflight     = 0
	StageProvision     = 10
	StageEnroll        = 20
	StageReadiness     = 30
	StageInventory     = 40
	StageConfiguration = 50
	StageApps          = 60
	StageSecurity      = 70
	StageEvents        = 80
	StageReplacement   = 85
	StageDestructive   = 90
	StageUnenroll      = 99
)

Lifecycle stages order modules for one target. Modules with equal stages keep catalogue order.

View Source
const (
	StatusPassed      = "passed"
	StatusFailed      = "failed"
	StatusBlocked     = "blocked"
	StatusUnsupported = "unsupported"
)

Result statuses. Blocked and unsupported are distinct from failed: blocked means a prerequisite or an earlier gate was not met, unsupported means the module does not apply to the selected mode or target.

View Source
const (
	ResultsFile = "results.json"
	JUnitFile   = "junit.xml"
	HTMLFile    = "report.html"
)

Report file names written into a run directory.

View Source
const (
	WorkspaceFile       = "lab.json"
	LegacyWorkspaceFile = "bench.json"
)

WorkspaceFile is the private workspace document. LegacyWorkspaceFile is the name used before the lab replaced the bench; Load still reads it so existing live workspaces keep their identities, database and storage-key names.

View Source
const (
	AdapterProcess = "process"
	AdapterDocker  = "docker"
)

Server adapters.

View Source
const DefaultModuleTimeout = 2 * time.Minute

DefaultModuleTimeout bounds one module when Options.Timeout is zero.

View Source
const TagDestructive = "destructive"

TagDestructive marks modules that erase, lock or restart a device. They run only when Options.Destructive is set.

Variables

View Source
var ErrBlocked = errors.New("scenario prerequisites unavailable")

Functions

func Command added in v0.10.4

func Command(ctx context.Context, e *Environment, path string, cmd *mdm.Command, evidence string) ([]byte, error)

Command queues a fresh command, requires APNs acceptance, and waits for the exact enrollment's acknowledgment. Evidence includes request, push and reply. Wake acceptance and acknowledgment each wait up to 45 seconds, bounded by context.

func EnrollmentPreflight

func EnrollmentPreflight(w *Workspace, identity string) map[string]any

EnrollmentPreflight checks local prerequisites without installing profiles or changing trust. Service discovery and device delivery have separate scenarios.

func ExportTrust

func ExportTrust(w *Workspace, destination string) error

ExportTrust bootstraps private HTTPS trust before the Mac can fetch an HTTPS profile.

func HTTP

func HTTP(
	ctx context.Context,
	c *http.Client,
	base, token, method, path string,
	body io.Reader,
	headers ...http.Header,
) ([]byte, int, error)

HTTP performs a bounded admin request. Errors contain status, never bodies or tokens.

func Init

func Init(dir, mode, storage, listen, adapter string, hosts []string) error

Init creates the persistent lab workspace with its selected mode, storage, listener and server adapter. hosts adds device-facing names to the generated HTTPS leaf.

func Markdown

func Markdown() string

Markdown is generated directly from executable metadata.

func Profile

func Profile(ctx context.Context, e *Environment, device, destination string) error

Profile requests the actual configured enrollment service and writes a new file.

func ProfileWithIdentity

func ProfileWithIdentity(
	ctx context.Context,
	e *Environment,
	device, identity, destination string,
) error

ProfileWithIdentity exports the configured profile with the rights needed for inventory and controlled profile replacement. Empty identity uses server defaults.

func ReissueTLS

func ReissueTLS(w *Workspace, hosts []string) error

ReissueTLS replaces the workspace HTTPS leaf with one covering loopback and hosts, signed by the retained workspace CA. Devices that already trust the CA keep working, so the trust profile does not have to be installed again.

func Replace

func Replace(ctx context.Context, e *Environment, device, identity string) (map[string]any, error)

Replace starts an authorized update; the existing push route wakes the device.

func Up

func Up(ctx context.Context, w *Workspace, binary string, out io.Writer) error

Up supervises processes in the foreground. A separate dmctl lab down uses the authenticated loopback control endpoint, never a possibly recycled PID.

func WriteHTML

func WriteHTML(dir string, results []Result) error

WriteHTML renders the results as a self-contained report.html in dir.

func WriteReports

func WriteReports(dir string, results []Result) error

WriteReports writes private JSON evidence, a JUnit projection and a self-contained HTML report. Non-passes never become successes merely because the selected execution mode lacks a device.

Types

type Connection added in v0.10.4

type Connection struct {
	URL, CAFile, TokenFile, EvidenceDirectory string
}

Connection attaches the harness to a managed deployment without creating another database or identity set. Paths refer to the host filesystem.

type Environment

type Environment struct {

	// InstallingUserID is the local user's GeneratedUID, supplied by the operator
	// for live enrollment acceptance. It is not inferred from an arbitrary child.
	InstallingUserID string
	DEP              *deptest.Server
	ABM              *axmtest.Server
	Provider         *webauthtest.Provider
	Authority        *testpki.CA
	Instance
	Client    *http.Client
	Token     string
	APNS      *pushtest.Server
	Workspace *Workspace
	// contains filtered or unexported fields
}

Environment owns fixture services and the ordinary server runtime(s).

func Attach

func Attach(w *Workspace) (*Environment, error)

Attach loads the recorded lab instance and its HTTP credentials from an existing workspace.

func AttachURL

func AttachURL(w *Workspace, address string) (*Environment, error)

AttachURL connects to an existing live server using the workspace's trust and admin credential. It does not start a supervisor, replace state or migrate SQL.

func Connect added in v0.10.4

func Connect(ctx context.Context, cfg Connection) (*Environment, error)

Connect validates trust and credentials and verifies the managed principal. Close releases the HTTP transport; it never stops the attached server.

func Start

func Start(ctx context.Context, w *Workspace, binary string, out io.Writer) (*Environment, error)

Start uses the same configuration and runtime in both adapters. A nonempty binary launches dmserver; an empty binary embeds runtime.ServeListener for E2E tests.

func (*Environment) Close

func (e *Environment) Close()

Close stops all runtimes before releasing fixture services.

func (*Environment) Control

func (e *Environment) Control(
	ctx context.Context,
	method, path string,
	body io.Reader,
) ([]byte, error)

Control executes the requested lifecycle control against the lab environment.

type Instance

type Instance struct {
	Binary       string `json:"Binary"`
	URL          string `json:"URL"`
	ControlURL   string `json:"ControlURL"`
	ControlToken string `json:"ControlToken"`
	Mode         string `json:"Mode"`
}

Instance describes the running workspace. The control credential stays private.

Private lab documents use the same PascalCase convention as admin responses.

type Module

type Module struct {
	// Timeout is a protocol-specific default. An explicit Options.Timeout wins.
	Timeout       time.Duration            `json:"-"`
	Settings      map[string]string        `json:"Settings,omitempty"`
	ID            string                   `json:"ID"`
	Name          string                   `json:"Name"`
	Theme         string                   `json:"Theme"`
	Stage         int                      `json:"Stage"`
	Regression    string                   `json:"Regression"`
	Modes         []string                 `json:"Modes"`
	Prerequisites []string                 `json:"Prerequisites"`
	Requires      []string                 `json:"Requires,omitempty"`
	Tags          []string                 `json:"Tags,omitempty"`
	Gate          bool                     `json:"Gate,omitempty"`
	Applies       func(target.Info) string `json:"-"`
	Steps         []Step                   `json:"-"`
}

Module is one maintained acceptance check. Implementations never depend on testing.T. Modes names the workspace modes whose server environment the module needs; Requires names target capabilities; Applies adds target-specific conditions. Regression names the detailed component test retained in server/e2e.

Catalogue JSON uses the administration PascalCase convention.

func Catalogue

func Catalogue() []Module

Catalogue returns a fresh module inventory in stable ID order. Modules without an explicit Stage take their theme's lifecycle stage.

func Select

func Select(selector string) ([]Module, error)

Select resolves a comma-separated selector of module IDs, themes or all against the catalogue and rejects unknown selections.

func SelectFrom added in v0.10.4

func SelectFrom(modules []Module, selector string) ([]Module, error)

SelectFrom resolves IDs and themes against an extended catalogue without changing the shared registry. all retains the caller's catalogue order.

func SelectMode

func SelectMode(mode, selector string) ([]Module, error)

SelectMode makes all select the modules applicable to mode; explicit IDs and themes still report unsupported modes rather than being silently ignored.

func (Module) Execute

func (m Module) Execute(ctx context.Context, e *Environment, t target.Target) error

Execute runs the module's steps against e and t without applicability checks or isolated settings, returning the first step error. Run is the reporting entry point.

type Options

type Options struct {
	Adapter, Revision string
	Timeout           time.Duration
	Destructive       bool
	Evidence          string
}

Options configure a run. Timeout bounds each module; zero selects the module's protocol-specific timeout or DefaultModuleTimeout. Evidence is the run directory; each module writes beneath Evidence/evidence/<ID>.

type Result

type Result struct {
	ID       string        `json:"ID"`
	Name     string        `json:"Name"`
	Theme    string        `json:"Theme"`
	Stage    int           `json:"Stage"`
	Mode     string        `json:"Mode"`
	Adapter  string        `json:"Adapter"`
	Revision string        `json:"Revision"`
	Status   string        `json:"Status"`
	Detail   string        `json:"Detail"`
	Target   target.Info   `json:"Target"`
	Steps    []StepResult  `json:"Steps,omitempty"`
	Evidence []string      `json:"Evidence,omitempty"`
	Started  time.Time     `json:"Started"`
	Duration time.Duration `json:"Duration"`
}

Result distinguishes unavailable prerequisites from an assertion failure.

Evidence JSON uses the administration PascalCase convention.

func ReadResults

func ReadResults(dir string) ([]Result, error)

ReadResults loads the results.json written by WriteReports.

func Run

func Run(ctx context.Context, e *Environment, t target.Target, m Module, opts Options) Result

Run executes one module against t and returns its status, steps, duration and evidence. It never returns an error: every outcome is a Result.

func RunAll

func RunAll(
	ctx context.Context,
	e *Environment,
	t target.Target,
	modules []Module,
	opts Options,
	observe func(Result),
) []Result

RunAll runs modules against one target in lifecycle order. A gate module that does not pass blocks every later module. observe, when non-nil, receives each result as it completes. Run cancellation stops before the next module.

type Session

type Session struct {
	Env      *Environment
	Target   target.Target
	Info     target.Info
	Evidence string
}

Session is the context a step executes in. Evidence is the module's private evidence directory, or empty when the run keeps no evidence files.

type Step

type Step struct {
	Name string
	Run  func(context.Context, *Session) error
}

Step is one named action of a module. A module stops at its first non-passing step.

type StepResult

type StepResult struct {
	Name     string        `json:"Name"`
	Status   string        `json:"Status"`
	Detail   string        `json:"Detail,omitempty"`
	Duration time.Duration `json:"Duration"`
}

StepResult records one executed or skipped step.

type Workspace

type Workspace struct {
	Settings map[string]string `json:"Settings,omitempty"`
	Version  int               `json:"Version"`
	Mode     string            `json:"Mode"`
	Storage  string            `json:"Storage"`
	Listen   string            `json:"Listen"`
	DSN      string            `json:"DSN,omitempty"`
	// Adapter is how dmserver runs: AdapterProcess (default) or AdapterDocker.
	Adapter string `json:"Adapter,omitempty"`
	// Hosts are the DNS names and IP addresses in the HTTPS leaf beyond loopback. The
	// first entry names the server in device-facing URLs.
	Hosts []string `json:"Hosts,omitempty"`
	// Bind is the host address the container adapter publishes its ports on. Empty
	// publishes on loopback only.
	Bind      string `json:"Bind,omitempty"`
	Directory string `json:"-"`
}

Workspace contains non-secret settings. Existing local identities stay in mdm/.

Preserve the private workspace document schema.

func Load

func Load(dir string) (*Workspace, error)

Load reads and validates an existing persistent lab workspace.

func (*Workspace) Doctor

func (w *Workspace) Doctor() map[string]any

Doctor checks prerequisites without enrolling a device or altering trust.

func (*Workspace) Path

func (w *Workspace) Path(parts ...string) string

Path resolves a workspace-owned artifact path for operator output.

func (*Workspace) PublicBase

func (w *Workspace) PublicBase() string

PublicBase returns the device-facing origin: the first configured host, or the loopback listener when no host is configured.

Directories

Path Synopsis
Package target defines the device side of lab acceptance runs.
Package target defines the device side of lab acceptance runs.

Jump to

Keyboard shortcuts

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