kitio

package
v0.43.0 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package kitio imports Git-owned stackkit.yaml definitions and generates reviewable CUE, Terraform, Docker Compose, and YAML artifacts.

Index

Constants

This section is empty.

Variables

View Source
var ApplicationToGroup = map[string]string{
	"photos":     "photo-management",
	"media":      "media-streaming",
	"vault":      "password-vault",
	"smart-home": "smart-home",
	"files":      "file-sharing",
	"ai":         "ai-workloads",
	"dev":        "dev-platform",
	"mail":       "mail-server",
	"game":       "game-server",
	"remote":     "remote-desktop",
}

ApplicationToGroup maps stackkit.yaml `application.<key>` to sk_service_group.slug. Pre-2026-04 named UseCaseToGroup with key `useCases.<key>`. See migration 000084.

View Source
var FoundationToGroup = map[string]string{
	"security-baseline": "security-baseline",
	"admin-bootstrap":   "admin-bootstrap",
}

FoundationToGroup maps stackkit.yaml `foundation.<key>` to sk_service_group.slug.

Note (migration 000085): `login-gateway` was previously here. Per ARCHITECTURE_V6 §4, login-gateway (TinyAuth + PocketID) is L2 Platform, not L1 Foundation — the admin bootstrap step is Foundation, the identity service itself is Platform. login-gateway moved to PlatformToGroup.

View Source
var PlatformToGroup = map[string]string{
	"traefik":       "reverse-proxy",
	"tinyauth":      "forward-auth",
	"login-gateway": "forward-auth",
	"pocketid":      "oidc-provider",
	"paas":          "paas",
	"monitoring":    "uptime-monitoring",
	"dashboard":     "dashboard",
	"dozzle":        "container-logs",
	"socket-proxy":  "docker-socket-proxy",
	"unbound":       "dns-resolver",
	"adguard-home":  "dns-filter",
	"crowdsec":      "intrusion-detection",
}

PlatformToGroup maps stackkit.yaml `platform.<key>` to sk_service_group.slug.

Functions

func CanonicalHash

func CanonicalHash(def KitDefinition) (string, error)

CanonicalHash returns sha256(canonical-json(def)) — same algorithm as the kit-import endpoint server-side. Used for drift detection + golden tests.

func ExportCUE

func ExportCUE(def KitDefinition) (stackfileBytes, servicesBytes []byte, err error)

ExportCUE renders a kit definition into CUE form.

Two outputs:

  • stackfileBytes: package <slug> with #StackKitConfig including metadata + supportedOS + modes + features.
  • servicesBytes: package <slug> with the per-service-group selections and per-tier sizing as commented-out placeholder records (the actual module CUE definitions live in modules/*/module.cue and are not duplicated here).

This is a *valid CUE* representation of the DB-shape — it is NOT meant to byte-equal the hand-written basement-kit/stackfile.cue, which carries hand-curated comments + schema constraints. The roundtrip test validates `cue eval` succeeds, not byte-equality.

func ExportCompose

func ExportCompose(def KitDefinition, outDir string) error

ExportCompose produces a Docker-Compose-style overview file at the kit level — NOT per-module compose fragments (those are generated by stackkit generate at deploy-time from the StackSpec + selected modules).

What this writes is a `kit-overview.compose.yml` that records the kit's service-group selections in compose-comment form, useful for operators who want to read what a kit "is" without running stackkit generate.

func ExportTerraform

func ExportTerraform(def KitDefinition, outDir string) error

ExportTerraform produces a `terraform.tfvars.json` from the kit definition's compute-tier requirements + selections + features.

This is intentionally a thin "kit-level" tfvars surface:

  • tier sizing -> tfvars (cpu, memory, disk per tier)
  • selected modules per group -> tfvars enable_<module> bool
  • features -> tfvars feature_<name> bool

Per-module Terraform fragments are still generated by the existing internal/cue Generator at deploy-time from a StackSpec, not here. This export covers the kit-definition contract surface only — what a downstream installer needs to know about the kit's defaults.

func ExportYAML

func ExportYAML(def KitDefinition) ([]byte, error)

ExportYAML produces a stackkit.yaml byte representation of the kit definition. The output is structurally equivalent to the original stackkit.yaml — same sections, same keys, same nesting — modulo cosmetic ordering and whitespace.

Used by:

  • stackkit kit export (writes to disk)
  • stackkit kit roundtrip (compares against original)
  • kit_export_test.go golden tests

func SortedModeKeys

func SortedModeKeys(m map[string]ModeDef) []string

SortedModeKeys returns mode keys in stable order.

Types

type AddonsDef

type AddonsDef struct {
	AutoActivated []string `yaml:"autoActivated,omitempty" json:"autoActivated,omitempty"`
	Optional      []string `yaml:"optional,omitempty" json:"optional,omitempty"`
}

AddonsDef holds autoActivated + optional addon slug lists.

type ApplicationConnectorDef

type ApplicationConnectorDef struct {
	Kind          string   `yaml:"kind,omitempty" json:"kind,omitempty"`
	Name          string   `yaml:"name,omitempty" json:"name,omitempty"`
	Owner         string   `yaml:"owner,omitempty" json:"owner,omitempty"`
	Endpoint      string   `yaml:"endpoint,omitempty" json:"endpoint,omitempty"`
	Transport     string   `yaml:"transport,omitempty" json:"transport,omitempty"`
	Auth          string   `yaml:"auth,omitempty" json:"auth,omitempty"`
	NativeProduct bool     `yaml:"nativeProduct,omitempty" json:"nativeProduct,omitempty"`
	Capabilities  []string `yaml:"capabilities,omitempty" json:"capabilities,omitempty"`
}

type ApplicationDef

type ApplicationDef struct {
	Role                  string                                  `yaml:"role" json:"role"`
	DefaultTool           string                                  `yaml:"defaultTool,omitempty" json:"defaultTool,omitempty"`
	Alternatives          []string                                `yaml:"alternatives,omitempty" json:"alternatives,omitempty"`
	Description           string                                  `yaml:"description,omitempty" json:"description,omitempty"`
	Package               string                                  `yaml:"package,omitempty" json:"package,omitempty"`
	DefaultRuntimeProfile string                                  `yaml:"defaultRuntimeProfile,omitempty" json:"defaultRuntimeProfile,omitempty"`
	RuntimeProfiles       map[string]ApplicationRuntimeProfileDef `yaml:"runtimeProfiles,omitempty" json:"runtimeProfiles,omitempty"`
	Connectors            map[string]ApplicationConnectorDef      `yaml:"connectors,omitempty" json:"connectors,omitempty"`
	ProductAPIs           map[string]ApplicationProductAPIDef     `yaml:"productApis,omitempty" json:"productApis,omitempty"`
	RIL                   *ApplicationRILDef                      `yaml:"ril,omitempty" json:"ril,omitempty"`
}

ApplicationDef is a user-facing application category (photos, media, ...). Lives under stackkit.yaml `application:` key (canonical L3 layer per ADR-0012). Pre-2026-04 this was named UseCaseDef under `useCases:` — see migration 000084.

type ApplicationProductAPIDef

type ApplicationProductAPIDef struct {
	Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"`
	BasePath string `yaml:"basePath,omitempty" json:"basePath,omitempty"`
	Auth     string `yaml:"auth,omitempty" json:"auth,omitempty"`
	Purpose  string `yaml:"purpose,omitempty" json:"purpose,omitempty"`
}

type ApplicationRILCapabilityDef

type ApplicationRILCapabilityDef struct {
	Mode             string `yaml:"mode,omitempty" json:"mode,omitempty"`
	Authority        string `yaml:"authority,omitempty" json:"authority,omitempty"`
	Source           string `yaml:"source,omitempty" json:"source,omitempty"`
	RequiresApproval bool   `yaml:"requiresApproval,omitempty" json:"requiresApproval,omitempty"`
	Evidence         string `yaml:"evidence,omitempty" json:"evidence,omitempty"`
}

type ApplicationRILDef

type ApplicationRILDef struct {
	Capabilities map[string]ApplicationRILCapabilityDef `yaml:"capabilities,omitempty" json:"capabilities,omitempty"`
}

type ApplicationRuntimeProfileDef

type ApplicationRuntimeProfileDef struct {
	DisplayName               string   `yaml:"displayName,omitempty" json:"displayName,omitempty"`
	Description               string   `yaml:"description,omitempty" json:"description,omitempty"`
	Realization               string   `yaml:"realization,omitempty" json:"realization,omitempty"`
	PlacementModes            []string `yaml:"placementModes,omitempty" json:"placementModes,omitempty"`
	Contexts                  []string `yaml:"contexts,omitempty" json:"contexts,omitempty"`
	ManagedServerlessEligible bool     `yaml:"managedServerlessEligible,omitempty" json:"managedServerlessEligible,omitempty"`
	RequiresControlPlane      bool     `yaml:"requiresControlPlane,omitempty" json:"requiresControlPlane,omitempty"`
	RequiresLocalBridge       bool     `yaml:"requiresLocalBridge,omitempty" json:"requiresLocalBridge,omitempty"`
	Notes                     []string `yaml:"notes,omitempty" json:"notes,omitempty"`
}

type ChangelogEntry

type ChangelogEntry struct {
	Version string   `yaml:"version" json:"version"`
	Date    string   `yaml:"date,omitempty" json:"date,omitempty"`
	Changes []string `yaml:"changes,omitempty" json:"changes,omitempty"`
}

ChangelogEntry mirrors a YAML changelog item.

type ComputeTierDef

type ComputeTierDef struct {
	Requirements       ResourceRequirements   `yaml:"requirements,omitempty" json:"requirements,omitempty"`
	AdditionalServices []string               `yaml:"additionalServices,omitempty" json:"additionalServices,omitempty"`
	ServiceOverrides   map[string]interface{} `yaml:"serviceOverrides,omitempty" json:"serviceOverrides,omitempty"`
	PaasOverride       string                 `yaml:"paasOverride,omitempty" json:"paasOverride,omitempty"`
}

ComputeTierDef is a tier sizing entry (low/standard/high).

type FieldDifference

type FieldDifference struct {
	Path          string      `json:"path"`
	Severity      string      `json:"severity"` // "critical" | "cosmetic"
	Original      interface{} `json:"original,omitempty"`
	Reconstructed interface{} `json:"reconstructed,omitempty"`
	Note          string      `json:"note,omitempty"`
}

FieldDifference is a single field-level diff entry.

func Diff

func Diff(a, b KitDefinition) []FieldDifference

Diff produces a list of FieldDifference entries between two KitDefinition values. Tracks the most relevant top-level + nested field paths for roundtrip validation.

type FoundationDef

type FoundationDef struct {
	Role         string   `yaml:"role" json:"role"`
	Alternatives []string `yaml:"alternatives,omitempty" json:"alternatives,omitempty"`
	Description  string   `yaml:"description,omitempty" json:"description,omitempty"`
}

FoundationDef is a foundation-layer service slot.

type KitDefinition

type KitDefinition struct {
	APIVersion   string                    `yaml:"apiVersion,omitempty" json:"apiVersion,omitempty"`
	Kind         string                    `yaml:"kind,omitempty" json:"kind,omitempty"`
	Metadata     KitMetadata               `yaml:"metadata" json:"metadata"`
	SupportedOS  []string                  `yaml:"supportedOS,omitempty" json:"supportedOS,omitempty"`
	Requirements map[string]interface{}    `yaml:"requirements,omitempty" json:"requirements,omitempty"`
	Modes        map[string]ModeDef        `yaml:"modes,omitempty" json:"modes,omitempty"`
	AutoSelect   map[string]interface{}    `yaml:"autoSelect,omitempty" json:"autoSelect,omitempty"`
	Application  map[string]ApplicationDef `yaml:"application,omitempty" json:"application,omitempty"`
	Foundation   map[string]FoundationDef  `yaml:"foundation,omitempty" json:"foundation,omitempty"`
	Platform     PlatformField             `yaml:"platform,omitempty" json:"platform,omitempty"`
	Features     map[string]bool           `yaml:"features,omitempty" json:"features,omitempty"`
	ComputeTiers map[string]ComputeTierDef `yaml:"computeTiers,omitempty" json:"computeTiers,omitempty"`
	Outputs      map[string]interface{}    `yaml:"outputs,omitempty" json:"outputs,omitempty"`
	Changelog    []ChangelogEntry          `yaml:"changelog,omitempty" json:"changelog,omitempty"`

	// Multi-node kit fields
	NodeTypes map[string]NodeTypeDef `yaml:"nodeTypes,omitempty" json:"nodeTypes,omitempty"`
	Addons    AddonsDef              `yaml:"addons,omitempty" json:"addons,omitempty"`
	Identity  map[string]interface{} `yaml:"identity,omitempty" json:"identity,omitempty"`
	Pattern   map[string]interface{} `yaml:"pattern,omitempty" json:"pattern,omitempty"`
	PaaS      map[string]interface{} `yaml:"paas,omitempty" json:"paas,omitempty"`
	Secrets   map[string]interface{} `yaml:"secrets,omitempty" json:"secrets,omitempty"`

	// Cluster-oriented kit fields
	Swarm    map[string]interface{} `yaml:"swarm,omitempty" json:"swarm,omitempty"`
	Services []ServiceSpecDef       `yaml:"services,omitempty" json:"services,omitempty"`
	Extends  string                 `yaml:"extends,omitempty" json:"extends,omitempty"`

	// Common optional
	Architecture    string   `yaml:"architecture,omitempty" json:"architecture,omitempty"`
	TunnelOptions   []string `yaml:"tunnelOptions,omitempty" json:"tunnelOptions,omitempty"`
	SecretsProvider string   `yaml:"-" json:"secretsProvider,omitempty"`

	// Publication fields materialized by the private Git/CUE publisher.
	CueSourcePath string `yaml:"-" json:"cueSourcePath,omitempty"`
	ContractHash  string `yaml:"-" json:"contractHash,omitempty"`
}

KitDefinition is the canonical in-process shape for a Git-owned Kit source.

func Import

func Import(yamlBytes []byte) (KitDefinition, error)

Import parses stackkit.yaml bytes into a KitDefinition.

Two-pass approach:

  1. yaml.Unmarshal into KitDefinition struct (typed sections).
  2. Re-parse as generic map to preserve unknown keys (Outputs, Pattern etc. that the struct surfaces as map[string]interface{}).

type KitMetadata

type KitMetadata = models.KitMetadata

KitMetadata is a source-compatible alias to the one concrete Go schema.

type ModeDef

type ModeDef struct {
	Description    string                   `yaml:"description,omitempty" json:"description,omitempty"`
	TemplateDir    string                   `yaml:"templateDir,omitempty" json:"templateDir,omitempty"`
	Engine         string                   `yaml:"engine,omitempty" json:"engine,omitempty"`
	Recommended    bool                     `yaml:"recommended,omitempty" json:"recommended,omitempty"`
	Features       []string                 `yaml:"features,omitempty" json:"features,omitempty"`
	Requires       []string                 `yaml:"requires,omitempty" json:"requires,omitempty"`
	RecommendedFor []string                 `yaml:"recommended_for,omitempty" json:"recommended_for,omitempty"`
	Stacks         []map[string]interface{} `yaml:"stacks,omitempty" json:"stacks,omitempty"`
}

ModeDef captures an install/lifecycle mode such as bare, bootstrapped, or advanced.

type NodeTypeDef

type NodeTypeDef struct {
	Description  string                 `yaml:"description,omitempty" json:"description,omitempty"`
	Access       string                 `yaml:"access,omitempty" json:"access,omitempty"`
	Role         string                 `yaml:"role,omitempty" json:"role,omitempty"`
	Requirements map[string]interface{} `yaml:"requirements,omitempty" json:"requirements,omitempty"`
	Providers    []string               `yaml:"providers,omitempty" json:"providers,omitempty"`
}

NodeTypeDef describes local/cloud node roles in multi-node kit definitions.

type PlatformDef

type PlatformDef struct {
	Role         string   `yaml:"role" json:"role"`
	DefaultTool  string   `yaml:"defaultTool,omitempty" json:"defaultTool,omitempty"`
	Alternatives []string `yaml:"alternatives,omitempty" json:"alternatives,omitempty"`
	Description  string   `yaml:"description,omitempty" json:"description,omitempty"`
}

PlatformDef is a platform-layer service slot.

type PlatformField

type PlatformField struct {
	// AsString holds the scalar form, e.g. "docker".
	AsString string
	// AsMap holds the structured form (basement-kit).
	AsMap map[string]PlatformDef
}

PlatformField is a polymorphic yaml `platform:` value.

In basement-kit it is a map of platform service slots:

platform:
  traefik: { role: default }
  paas: { role: optional, defaultTool: coolify }

In future kit definitions it may be represented as a single string:

platform: docker

We keep both forms reachable.

func (PlatformField) IsEmpty

func (p PlatformField) IsEmpty() bool

IsEmpty reports whether the field carries no data.

func (PlatformField) MarshalJSON

func (p PlatformField) MarshalJSON() ([]byte, error)

MarshalJSON keeps the symmetry for kit-import POST body.

func (PlatformField) MarshalYAML

func (p PlatformField) MarshalYAML() (interface{}, error)

MarshalYAML emits the string form when set, otherwise the map form, otherwise nothing.

func (*PlatformField) UnmarshalJSON

func (p *PlatformField) UnmarshalJSON(b []byte) error

UnmarshalJSON accepts string-or-map for kit-export round-trip.

func (*PlatformField) UnmarshalYAML

func (p *PlatformField) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML accepts both yaml shapes.

type ResourceRequirements

type ResourceRequirements struct {
	CPU      int    `yaml:"cpu,omitempty" json:"cpu,omitempty"`
	Memory   int    `yaml:"memory,omitempty" json:"memory,omitempty"`
	Disk     int    `yaml:"disk,omitempty" json:"disk,omitempty"`
	DiskType string `yaml:"diskType,omitempty" json:"diskType,omitempty"`
	// Multi-node
	ManagerNodes int `yaml:"managerNodes,omitempty" json:"managerNodes,omitempty"`
	WorkerNodes  int `yaml:"workerNodes,omitempty" json:"workerNodes,omitempty"`
	Nodes        int `yaml:"nodes,omitempty" json:"nodes,omitempty"`
}

ResourceRequirements captures cpu/memory/disk + optional disk type.

type ReverseMapping

type ReverseMapping struct {
	Section SectionKind
	Key     string
}

ReverseMapping records the original section + key that produced a given service-group slug. Used by export to put selections back into the right stackkit.yaml section.

func GroupReverseMappings

func GroupReverseMappings(groupSlug string) []ReverseMapping

GroupReverseMappings returns the section/key pairs that map to a given service-group slug. Some groups (e.g. "forward-auth") have multiple sources (foundation.login-gateway + platform.tinyauth) — both are returned.

type RoundTripReport

type RoundTripReport struct {
	Slug              string            `json:"slug"`
	OriginalHash      string            `json:"originalHash"`
	ReconstructedHash string            `json:"reconstructedHash"`
	HashesEqual       bool              `json:"hashesEqual"`
	Differences       []FieldDifference `json:"differences,omitempty"`
	CosmeticOnly      bool              `json:"cosmeticOnly"`
	Formats           []string          `json:"formats"`
}

RoundTripReport captures the structural diff between the original kit definition and the reconstructed one.

func LocalRoundTrip

func LocalRoundTrip(yamlBytes []byte) (RoundTripReport, error)

LocalRoundTrip runs the YAML-only roundtrip cycle in memory:

  1. Import original yaml -> KitDefinition A
  2. Export A -> reconstructed yaml
  3. Import reconstructed yaml -> KitDefinition B
  4. Compare A vs B as structs (cosmetic yaml differences ignored)
  5. Compute hashes; match indicates lossless roundtrip

This is the cheap, no-API check that ships with `stackkit kit roundtrip` and runs in unit tests. The live API counterpart lives in client.go + kit_roundtrip_live_test.go.

type SectionKind

type SectionKind string

SectionKind identifies which yaml section a service-group belongs to.

const (
	SectionApplication SectionKind = "application"
	SectionFoundation  SectionKind = "foundation"
	SectionPlatform    SectionKind = "platform"
)

func PreferredSection

func PreferredSection(groupSlug string) (SectionKind, string, bool)

PreferredSection picks the canonical section for a group when multiple sources exist. Rule: foundation > platform > application. Within the same section, we prefer the SHORTER key, then lexicographically earlier — this keeps `login-gateway` (the documented canonical) winning over `tinyauth` (the legacy alias) for forward-auth, deterministically.

Migration 000086 (P1-2 fix): login-gateway moved from foundation to platform per ARCHITECTURE_V6 §4. Both login-gateway and tinyauth are now in platform; the deterministic-within-section rule keeps the canonical pair stable.

type ServiceSpecDef

type ServiceSpecDef struct {
	Name        string                 `yaml:"name" json:"name"`
	Required    bool                   `yaml:"required,omitempty" json:"required,omitempty"`
	Description string                 `yaml:"description,omitempty" json:"description,omitempty"`
	Status      string                 `yaml:"status,omitempty" json:"status,omitempty"`
	Replicas    *int                   `yaml:"replicas,omitempty" json:"replicas,omitempty"`
	SwarmMode   bool                   `yaml:"swarmMode,omitempty" json:"swarmMode,omitempty"`
	Deploy      map[string]interface{} `yaml:"deploy,omitempty" json:"deploy,omitempty"`
}

ServiceSpecDef declares deployment overrides per service.

Jump to

Keyboard shortcuts

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