Documentation
¶
Index ¶
- func HashSelection(sel Selection, baseName string) (string, error)
- func RenderDockerfile(rv ResolvedValues, base Base) (string, error)
- func SeedCatalog(ctx context.Context, store SeedCatalogStore) error
- func ValidateResolved(rv ResolvedValues) error
- func ValidateSelection(sel Selection) error
- type Base
- type Build
- type BuildStatus
- type Config
- type ConfigScope
- type ConfigStatus
- type Extension
- type ExtensionType
- type FileSpec
- type KnownFailure
- type PlatformConfig
- type ResolvedValue
- type ResolvedValues
- type SeedCatalogData
- type SeedCatalogStore
- type SeedExtensionEntry
- type Selection
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func HashSelection ¶
HashSelection computes the content-addressed schematic hash over the sorted-deduped selection IDs + base name. Pure, deterministic, no I/O. Returns "s-" + first 16 hex chars of SHA-256 (design/0046 #1, #2).
Version is deliberately NOT in the preimage — version is a separate axis (design/0046 #2): the same schematic hash identifies a family of images, one per base version that has been built.
func RenderDockerfile ¶
func RenderDockerfile(rv ResolvedValues, base Base) (string, error)
RenderDockerfile renders the deterministic Dockerfile for a workspace image from frozen resolved values + a base. Pure function of (ResolvedValues, Base): identical inputs always render an identical Dockerfile byte-for-byte, so a content-addressed tag maps to exactly one reproducible build (design/0046 build-execution section).
The Dockerfile only ever layers onto the operator-approved base (base.Ref()). It cannot reference an arbitrary image, and every layer is derived from operator-authored catalog values (no user free text) — this is the structural guard against the injection surface.
func SeedCatalog ¶ added in v0.8.0
func SeedCatalog(ctx context.Context, store SeedCatalogStore) error
SeedCatalog idempotently upserts the seed data into the store. For each extension: if it already exists in the DB, it is NOT overwritten (runtime admin changes — retire, review flag — take precedence). Only NEW extensions are inserted. A transient DB error on GetExtension propagates (does NOT fall through to insert). Bases are always upserted (they're version-pinned and immutable per version).
func ValidateResolved ¶
func ValidateResolved(rv ResolvedValues) error
ValidateResolved checks the resolved shape: if non-empty, every entry has a known type, a non-empty value, and (for file) an absolute non-traversal path + valid octal mode. Empty is valid — an extension-less config is a named alias for the base image (design permits it; the picker shows it). Used as a defensive check on data crossing the DB boundary.
func ValidateSelection ¶
ValidateSelection checks that the selection is non-empty and every ID matches the extension ID charset. It does NOT check existence in the catalog — that is the store's concern (ResolveSelection does it).
Types ¶
type Base ¶
type Base struct {
Name string `json:"name" yaml:"name"`
Version string `json:"version" yaml:"version"`
Image string `json:"image" yaml:"image"`
Tag string `json:"tag,omitempty" yaml:"tag,omitempty"`
Digest string `json:"digest,omitempty" yaml:"digest,omitempty"`
IsDefault bool `json:"isDefault" yaml:"isDefault"`
}
Base is a (name, version) row of an operator-approved base image. Composite-keyed: old versions persist (design/0046 #8).
type Build ¶
type Build struct {
ID string `json:"id"`
ConfigID string `json:"configId"`
Hash string `json:"hash"`
BaseName string `json:"baseName"`
BaseVersion string `json:"baseVersion"`
ResolvedValues ResolvedValues `json:"resolvedValues"`
Architectures []string `json:"architectures"`
ImageRef string `json:"imageRef,omitempty"`
Digest string `json:"digest,omitempty"`
Status BuildStatus `json:"status"`
GHRunID *int64 `json:"ghRunId,omitempty"`
FailureReason string `json:"-"` // admin-only
Explanation string `json:"explanation,omitempty"`
TriggeredBy *string `json:"triggeredBy,omitempty"`
StartedAt time.Time `json:"startedAt"`
FinishedAt *time.Time `json:"finishedAt,omitempty"`
CallbackToken string `json:"-"` // per-build secret; ConstantTimeCompare on callback
}
Build is one row of image_factory_builds. One row per API dispatch — transient retry happens inside the GH Actions workflow (design/0046 #12), so the API sees exactly one dispatch + one final result.
type BuildStatus ¶
type BuildStatus string
BuildStatus enumerates the build lifecycle.
const ( BuildDispatched BuildStatus = "dispatched" BuildSucceeded BuildStatus = "succeeded" BuildFailed BuildStatus = "failed" )
type Config ¶
type Config struct {
ID string `json:"id"`
Hash string `json:"hash"`
Name string `json:"name"`
Selection Selection `json:"selection"`
ResolvedValues ResolvedValues `json:"resolvedValues"`
BaseName string `json:"baseName"`
BaseVersion string `json:"baseVersion"`
Scope ConfigScope `json:"scope"`
OwnerID *string `json:"ownerId,omitempty"`
OrgID *string `json:"orgId,omitempty"`
Status ConfigStatus `json:"status"`
}
Config is a saved user/org/platform config.
type ConfigScope ¶
type ConfigScope string
ConfigScope enumerates the three friendly-name scopes (design/0046 #25).
const ( ScopeMember ConfigScope = "member" ScopeOrg ConfigScope = "org" ScopePlatform ConfigScope = "platform" )
type ConfigStatus ¶
type ConfigStatus string
ConfigStatus is the config lifecycle pill (design/0046 #20).
const ( StatusBuilding ConfigStatus = "building" StatusReady ConfigStatus = "ready" StatusRejected ConfigStatus = "rejected" )
type Extension ¶
type Extension struct {
ID string `json:"id"`
Type ExtensionType `json:"type"`
Value string `json:"value"`
FileSpec *FileSpec `json:"fileSpec,omitempty"`
SupportedBases []string `json:"supportedBases"`
Retired bool `json:"retired"`
ReviewRequested bool `json:"reviewRequested"`
Description string `json:"description,omitempty"`
}
Extension is a catalog row. Immutable-once-published (design/0046 #7): the build-relevant fields (Type, Value, FileSpec, SupportedBases) do not change after creation. Only Retired, ReviewRequested, Description mutate.
type ExtensionType ¶
type ExtensionType string
ExtensionType enumerates the catalog extension kinds. "run" and "env" are deliberately absent — they were the injection vectors (design/0046 #5).
const ( ExtensionTypeApt ExtensionType = "apt" ExtensionTypeMise ExtensionType = "mise" ExtensionTypeFile ExtensionType = "file" )
type FileSpec ¶
type FileSpec struct {
Path string `json:"path"`
Mode string `json:"mode,omitempty"` // octal string "0755"; empty → "0644"
}
FileSpec is the target for a type=file extension. Path must be absolute (no traversal); Mode defaults to "0644" when empty.
type KnownFailure ¶
type KnownFailure struct {
SelectionHash string `json:"selectionHash"`
Selection Selection `json:"selection"`
BaseName string `json:"baseName"`
Explanation string `json:"explanation,omitempty"`
FailureReason string `json:"-"` // admin-only; never serialized to non-admins
DetectedAt time.Time `json:"detectedAt"`
Retriable bool `json:"retriable"`
}
KnownFailure is a row of image_factory_known_failures — the blocklist.
type PlatformConfig ¶
type PlatformConfig struct {
Architectures []string `json:"architectures"`
}
PlatformConfig is the single-row platform-level factory config.
type ResolvedValue ¶
type ResolvedValue struct {
Type ExtensionType `json:"type"`
Value string `json:"value"`
FileSpec *FileSpec `json:"fileSpec,omitempty"`
}
ResolvedValue is one entry in the resolved_values JSONB. It is the cached projection of an Extension's build fields, frozen at config-save time. Shape pinned per design/0047.
type ResolvedValues ¶
type ResolvedValues map[string]ResolvedValue
ResolvedValues maps extension ID → frozen resolved value. This is the exact JSONB shape stored on image_factory_configs.resolved_values and image_factory_builds.resolved_values.
func ResolveSelection ¶
func ResolveSelection(sel Selection, exts map[string]Extension, baseName string) (ResolvedValues, error)
ResolveSelection joins a Selection against a set of catalog Extensions and returns the frozen ResolvedValues projection stored on the config (design/0046 #10). Errors if any ID is missing, retired, or unsupported on baseName. Pure: no I/O.
func (ResolvedValues) Selection ¶
func (rv ResolvedValues) Selection() Selection
Selection recovers the extension IDs from the resolved values map, sorted. Used by the callback handler to reconstruct the selection for the known_failures row (the build stores resolved_values, not the selection).
type SeedCatalogData ¶ added in v0.8.0
type SeedCatalogData struct {
Architectures []string `json:"architectures" yaml:"architectures"`
Bases []Base `json:"bases" yaml:"bases"`
Extensions []SeedExtensionEntry `json:"extensions" yaml:"extensions"`
}
SeedCatalogData is the parsed structure of catalog.seed.yaml.
func LoadSeed ¶ added in v0.8.0
func LoadSeed() (SeedCatalogData, error)
LoadSeed parses catalog.seed.yaml (embedded via go:embed). If an env var CATALOG_SEED_PATH is set, loads from that file instead (operator override). Returns the parsed seed data.
type SeedCatalogStore ¶ added in v0.8.0
type SeedCatalogStore interface {
SetPlatformConfig(ctx context.Context, pc PlatformConfig) error
UpsertBase(ctx context.Context, b Base) error
GetExtension(ctx context.Context, id string) (Extension, error)
PublishExtension(ctx context.Context, e Extension) error
}
SeedCatalogStore is the subset of the DB store needed to seed the catalog.
type SeedExtensionEntry ¶ added in v0.8.0
type SeedExtensionEntry struct {
ID string `json:"id" yaml:"id"`
Type ExtensionType `json:"type" yaml:"type"`
Value string `json:"value" yaml:"value"`
FileSpec *FileSpec `json:"fileSpec,omitempty" yaml:"fileSpec,omitempty"`
SupportedBases []string `json:"supportedBases" yaml:"supportedBases"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
}
SeedExtensionEntry is one extension in the seed file. The YAML uses camelCase for fileSpec (matching the JSON tag on FileSpec).
func (SeedExtensionEntry) ToExtension ¶ added in v0.8.0
func (s SeedExtensionEntry) ToExtension() Extension
ToExtension converts a seed entry to a domain Extension.