localformat

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Jun 1, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

Package localformat writes the uniform numbered local-chart bundle layout. Currently consumed by the helm deployer (--deployer helm). Designed to be consumable by additional deployers (e.g. helmfile per #632, argocd, Flux) without per-deployer changes to the writer; those integrations are not yet wired in this package.

Layout

Each emitted folder is named NNN-<component>/ where NNN is a zero-padded 1-based index. Folders are one of two kinds, distinguished solely by the presence or absence of Chart.yaml:

  • KindUpstreamHelm — no Chart.yaml. The folder carries values.yaml, cluster-values.yaml, upstream.env (CHART/REPO/VERSION), and a rendered install.sh that installs the upstream chart via `helm upgrade --install`.

  • KindLocalHelm — Chart.yaml + templates/ present. The folder is a self-contained Helm chart; install.sh installs `./` as a local chart.

The Chart.yaml presence rule is the sole branch point for consumers. No component-kind metadata is re-read at deploy time. This is deliberate: a previous design branched deploy.sh on Helm/Kustomize/raw-manifest kinds, which bled component-type classification into every deployer. Chart.yaml presence reduces that to a single on-disk signal every deployer honors.

Classification

Recipe shape determines the folder kind:

Helm repository set, no manifests             → KindUpstreamHelm
Helm repository set, with raw manifests       → KindUpstreamHelm primary +
                                                 KindLocalHelm "-post" injection
Helm repository empty, manifests only         → KindLocalHelm (wrapped)
Kustomize (Tag/Path set)                      → KindLocalHelm (kustomize build
                                                 output wrapped as templates/manifest.yaml)

Mixed components and the "-post" injection

When a single recipe component declares both an upstream Helm chart and raw manifests, Write emits two adjacent folders: the primary NNN-<name>/ as KindUpstreamHelm, immediately followed by (NNN+1)-<name>-post/ as KindLocalHelm wrapping the raw manifests. Subsequent components shift by one. The "mixed" concept does not appear in the recipe types, deployment order, or bundle result — it exists only in the bundle layout.

The -post folder deploys after the upstream chart, so raw manifests that reference the chart's CRDs apply against a cluster where those CRDs already exist. This is what makes the earlier pre-apply-with-retry mechanism (which applied raw manifests before the chart and retried on "CRD not found" errors) structurally unnecessary.

Base-format invariants

These are load-bearing contracts. Callers and contributors should not violate them without changing the design:

  1. localformat never writes deployer-specific files. deploy.sh, helmfile.yaml, argocd Application CRs, Flux HelmReleases, and the like are produced by the respective deployer after Write returns. Write owns per-folder content; deployers own top-level orchestration files. This separation is what makes a single folder layout consumable by every deployer without localformat growing per-deployer branches.

  2. install.sh is never name-customized. Rendered from one of exactly two templates (upstream-helm, local-helm), parameterized only by data (name, namespace, upstream ref). Name-keyed component quirks (kai-scheduler async skip, skyhook taint cleanup, DRA restart, orphan CRD scan) stay in deploy.sh as name-matched blocks — not in install.sh. This is the structural barrier that keeps per-folder scripts from accumulating drift the way deploy.sh's branching did.

  3. Write is deterministic and idempotent. Same Options in, same on-disk bytes and same Folder slice out. Map iteration is sorted; no timestamps or random suffixes are embedded in generated content.

Caller contract

Callers pass an ordered Components slice (sorted by deployment order) and two manifest maps (name → path → rendered bytes):

  • ComponentPostManifests drives both the -post injection for mixed components and the template contents for manifest-only wrapped charts. Populated from ComponentRef.ManifestFiles.
  • ComponentPreManifests carries manifests intended to apply BEFORE each component's primary chart (e.g. an OS-specific namespace). Populated from ComponentRef.PreManifestFiles. The writer emits a wrapped "<name>-pre" local-helm folder ahead of the primary folder when this map has entries for the component; install.sh in the pre folder omits --create-namespace because the chart's Namespace template owns namespace creation.

Write returns a []Folder manifest so deployers can generate their own orchestration files without re-classifying or re-reading disk.

Further detail: ticket #662 carries the original design discussion and alternatives considered.

Index

Constants

View Source
const (
	ProvenanceAPIVersion = "aicr.nvidia.com/v1alpha1"
	ProvenanceKind       = "BundleProvenance"
)

ProvenanceAPIVersion / ProvenanceKind identify the document shape using AICR's K8s-style convention. Bump the apiVersion when a downstream consumer would need to branch on shape (v1alpha1 → v1beta1 → v1). Additive fields do not require a bump.

View Source
const ProvenanceFileName = "provenance.yaml"

ProvenanceFileName is the on-disk filename at the bundle root. Exported so consumers (deployers, downstream tooling) reference the same name.

Variables

This section is empty.

Functions

func InjectPostInstallHooks added in v0.13.0

func InjectPostInstallHooks(in []byte) ([]byte, error)

InjectPostInstallHooks rewrites a multi-document YAML stream to add post-install hook annotations. Exported for deployers that build vendored mixed-component folders outside of localformat.Write() (e.g., flux).

func NestUnderSubchart added in v0.13.0

func NestUnderSubchart(values map[string]any, subchart string) map[string]any

NestUnderSubchart wraps values under a single key so Helm forwards them to the named subchart at install time. Exported for deployers that build vendored folders with a wrapper chart (e.g., flux).

func RenderWrapperChartYAML added in v0.13.0

func RenderWrapperChartYAML(name, parent, chartName, chartVersion string) ([]byte, error)

RenderWrapperChartYAML produces the wrapper Chart.yaml content for a vendored component. Exported for deployers that build their own vendored folder layout (e.g., flux).

func ShouldVendor added in v0.13.0

func ShouldVendor(c Component) bool

ShouldVendor reports whether c should be routed through the vendor path when --vendor-charts is on. Returns false (without error) for shapes that are already local after #662 (Kustomize, manifest-only) — callers fall through to the existing classify() path for those. Exported for deployers that build their own vendored folder layout (e.g., flux) and need the same predicate without duplicating it.

func WriteProvenance added in v0.13.0

func WriteProvenance(ctx context.Context, outputDir string, records []VendorRecord) (string, int64, error)

WriteProvenance sorts records by component name and writes provenance.yaml at the root of outputDir. Returns the absolute file path, byte size, and any error. records MUST be non-empty; callers guard the call so an empty vendor set produces no file.

ctx is checked for cancellation before the filesystem write so a caller-initiated abort short-circuits the I/O. The marshaling and path-safety checks above the write are pure CPU and run regardless.

Mode 0o644: provenance is audit content meant to be read by operators and downstream tooling (yank-list scanners), not a secret.

Types

type CLIChartPuller added in v0.13.0

type CLIChartPuller struct {
	HelmBin string
}

CLIChartPuller shells out to `helm pull` to fetch upstream chart bytes. Used today while legal review of the in-process Helm SDK is pending; will be supplemented by an SDKChartPuller when approved.

Auth flows through helm's own conventions:

  • HTTP(S): HELM_REPOSITORY_USERNAME / HELM_REPOSITORY_PASSWORD env vars.
  • OCI: standard docker config (~/.docker/config.json or $DOCKER_CONFIG), exactly like `helm pull oci://...`.

HelmBin overrides the binary lookup; empty falls back to "helm" on $PATH.

func (*CLIChartPuller) Pull added in v0.13.0

Pull invokes `helm pull` for c, reads the resulting .tgz from a temporary destination, computes its SHA256, and returns the bytes plus a VendorRecord. The temp directory is removed before returning even on error. ctx cancellation interrupts the helm subprocess via os.Interrupt (exec.CommandContext default).

type ChartPuller added in v0.13.0

type ChartPuller interface {
	Pull(ctx context.Context, c Component) (tgz []byte, rec VendorRecord, tarball string, err error)
}

ChartPuller fetches an upstream Helm chart and returns the raw .tgz bytes plus a provenance record. The implementation choice — shelling out to the helm CLI vs the in-process Helm SDK — is hidden behind this interface so the bundle-time path is identical either way.

Implementations MUST honor ctx cancellation, MUST NOT mutate c, and SHOULD return one of the structured error codes from pkg/errors so callers can branch on intent rather than substring matching.

type Component

type Component struct {
	Name      string
	Namespace string
	// Helm upstream ref (empty for manifest-only components)
	Repository string
	ChartName  string
	Version    string
	IsOCI      bool
	// Kustomize (empty for helm components)
	Tag  string
	Path string
	// Values hydrated by the component bundler
	Values       map[string]any
	DynamicPaths []string // paths moved from values.yaml into cluster-values.yaml
}

Component is the per-component input for Write. Fields mirror the subset of pkg/bundler/deployer/helm.ComponentData that localformat needs.

type Folder

type Folder struct {
	Index     int    // 1-based; rendered as zero-padded 3-digit prefix in Dir
	Dir       string // e.g. "001-nfd"
	Kind      FolderKind
	Name      string    // helm release name: component name, or "<name>-pre" / "<name>-post" for injected
	Namespace string    // target namespace for the helm release; matches Component.Namespace
	Parent    string    // component this folder belongs to (== Name for primary)
	Upstream  *Upstream // set iff Kind == KindUpstreamHelm
	Files     []string  // relative paths (to OutputDir) of files written in this folder
	// CreateNamespace is true when the orchestration layer should pass
	// --create-namespace to helm for this folder's release, false when
	// the folder's chart ships its own Namespace resource (the Talos
	// privileged-namespace pre-injection pattern). install.sh already
	// honors this internally; the field exposes the same decision to
	// out-of-band deployers (e.g., helmfile) that bypass install.sh.
	// Helm 3 refuses to import a namespace it created out-of-band via
	// --create-namespace because that namespace lacks the release's
	// ownership annotations.
	CreateNamespace bool
}

Folder describes one written folder. Returned by Write so callers (deployers) can generate orchestration files without re-classifying.

type FolderKind

type FolderKind int

FolderKind classifies a written folder by the presence/absence of Chart.yaml.

const (
	// KindUpstreamHelm: folder contains no Chart.yaml; install.sh references
	// an upstream Helm chart via upstream.env.
	KindUpstreamHelm FolderKind = iota
	// KindLocalHelm: folder contains a generated Chart.yaml + templates/;
	// install.sh installs ./ as a local chart.
	KindLocalHelm
)

func (FolderKind) String

func (k FolderKind) String() string

String returns the stable textual name for the kind. Used by logs and golden-file diagnostics so diffs show kind names rather than integers.

type Options

type Options struct {
	OutputDir  string
	Components []Component // ordered per DeploymentOrder
	// ComponentPreManifests maps component name → manifest path → rendered
	// bytes for manifests that should apply BEFORE each component's primary
	// chart. Populated from ComponentRef.PreManifestFiles. The writer does
	// not yet emit pre-phase folders — Task 4 wires the pre-injection
	// branch; for now the map is threaded through but unread.
	ComponentPreManifests map[string]map[string][]byte
	// ComponentPostManifests maps component name → manifest path → rendered
	// bytes for manifests that should apply AFTER each component's primary
	// chart. Populated from ComponentRef.ManifestFiles. Drives the existing
	// -post injection for mixed components and the template contents for
	// manifest-only wrapped charts.
	ComponentPostManifests map[string]map[string][]byte

	// VendorCharts pulls upstream Helm chart bytes into each Helm-typed
	// component's folder at bundle time. When set, every Helm component
	// emits a single wrapped folder with charts/<chart>-<version>.tgz +
	// wrapper Chart.yaml + (for mixed components) post-install-hook
	// templates. Mixed components no longer split into primary + -post.
	// Off by default — non-vendored bundles preserve the upstream
	// CVE-yank fail-loud signal.
	VendorCharts bool

	// Puller fetches upstream chart bytes when VendorCharts is set. nil
	// is allowed and resolves to a default *CLIChartPuller; tests can
	// inject a stub here without touching package state. Ignored when
	// VendorCharts is false.
	Puller ChartPuller
}

Options configures Write.

type Upstream

type Upstream struct {
	Chart   string
	Repo    string
	Version string
}

Upstream holds upstream chart reference fields written to upstream.env.

type VendorRecord added in v0.13.0

type VendorRecord struct {
	// Name is the recipe component name (folder NNN-<name>).
	Name string `json:"name"`
	// Chart is the upstream chart name as declared in the recipe.
	Chart string `json:"chart"`
	// Version is the chart version pulled.
	Version string `json:"version"`
	// Repository is the resolved upstream URL (HTTP(S) or oci://).
	Repository string `json:"repository"`
	// SHA256 is the hex-encoded digest of the .tgz bytes pulled.
	SHA256 string `json:"sha256"`
	// TarballName is the on-disk filename written under charts/.
	TarballName string `json:"tarballName"`
	// PullerVersion identifies the puller implementation that produced
	// this record (e.g. "helm-cli v3.20.2"). Audit-only; not used by
	// downstream code.
	PullerVersion string `json:"pullerVersion,omitempty"`
}

VendorRecord captures one entry of the bundle-time audit log emitted when --vendor-charts is set. Together the fields let an operator reconstruct provenance for a vendored chart and run yank-list lookups after the fact.

type WriteResult added in v0.13.0

type WriteResult struct {
	// Folders is one entry per emitted NNN-<name>/ directory, in
	// deployment order. Files within each Folder are relative to the
	// Write call's OutputDir.
	Folders []Folder

	// VendoredCharts is non-empty only when Options.VendorCharts was
	// set; one record per upstream chart pulled into the bundle. Pass
	// directly to WriteProvenance to emit the audit log.
	VendoredCharts []VendorRecord
}

WriteResult is the typed return shape from Write. Callers consume Folders for per-component bookkeeping (checksums, output files) and VendoredCharts to emit provenance.yaml or other audit artifacts.

Returned as a struct (rather than (slices..., error)) so future additions — e.g., per-folder warnings, partial-failure detail — do not break the call signature for every downstream consumer.

func Write

func Write(ctx context.Context, opts Options) (WriteResult, error)

Write emits the numbered folder layout. Deterministic and idempotent.

Removes any pre-existing NNN-* folders under OutputDir before writing, so reusing the same --output across recipe regenerations does not leave stale component folders that the deployer's loop would later install. Top-level orchestration files (deploy.sh, README.md, attestation/) are left intact; only files under [0-9][0-9][0-9]-* are removed.

Returns the list of emitted folders plus, when opts.VendorCharts is set, one VendorRecord per pulled upstream chart for inclusion in the bundle's provenance.yaml. The records slice is empty when VendorCharts is false.

Jump to

Keyboard shortcuts

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