Documentation
¶
Overview ¶
Package header provides common header types for AICR data structures.
This package defines the Header type used across recipes, snapshots, and other AICR data structures to provide consistent metadata and versioning information.
Header Structure ¶
The Header contains standard fields for API versioning and metadata:
type Header struct {
Kind Kind `json:"kind,omitempty" yaml:"kind,omitempty"` // Resource type (Snapshot, Recipe, RecipeResult)
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` // API version (e.g., "aicr.run/v1")
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"` // Free-form string metadata (timestamp, version, etc.)
}
Metadata is a flat map[string]string populated by Init / InitWithTime with the unprefixed keys "timestamp" (RFC3339 UTC) and "version" (when supplied).
Usage ¶
Initialize a header for a recipe via Init:
var h header.Header
h.Init(header.KindRecipe, header.StableGroupVersion, "v1.0.0")
// h.Metadata == map[string]string{"timestamp": "...", "version": "v1.0.0"}
KindRecipe shown here is the legacy input kind, distinct from KindRecipeResult and normalized to it per ADR-022 §2; both sit on the stable artifact track alongside Snapshot, hence StableGroupVersion. An authored catalog RecipeMetadata is colloquially a "recipe" too but sits on the authoring track, and a profile-bearing artifact on its own track, so those emitters pass AuthoringGroupVersion or ProfileGroupVersion instead; see the API Versioning section below.
For reproducible-build callers (SLSA, signed artifacts) inject a fixed timestamp via InitWithTime instead of Init:
var h header.Header h.InitWithTime(header.KindSnapshot, header.StableGroupVersion, "v1.0.0", buildTime)
Serialization ¶
Headers serialize consistently to JSON and YAML:
{
"apiVersion": "aicr.run/v1",
"kind": "Recipe",
"metadata": {
"timestamp": "2025-12-30T10:30:00Z",
"version": "v1.0.0"
}
}
API Versioning ¶
The APIVersion field enables evolution of data formats. APIGroup derives from Domain. Per ADR-013 the move from the legacy aicr.nvidia.com/v1alpha1 group was a hard break — the old value is rejected, not migrated.
ADR-022 splits artifacts across three schema tracks. An emitter aliases the constant for its track — StableGroupVersion, AuthoringGroupVersion, or ProfileGroupVersion — never the string it happens to equal. The three carried one shared value before the v0.22 switch (#2416), so aliasing by value rather than by track compiled and passed tests while emitting the wrong version later. That switch separated them, which turns the mistake into a visible wrong value instead of a latent one.
Callers should select the gate for the artifact's schema track rather than comparing literals, so the single source of truth in this package stays authoritative. IsSupportedAPIVersion covers the stable artifact track. Since ADR-022 N+2 (#2417) an absent apiVersion is not special-cased: it fails the gate like any other unaccepted value, and RetirementNote supplies the clause that tells its author why an artifact that used to load no longer does:
if !header.IsSupportedAPIVersion(h.APIVersion) {
return errors.New(errors.ErrCodeInvalidRequest,
fmt.Sprintf("unsupported apiVersion %q%s; expected %q",
h.APIVersion, header.RetirementNote(h.APIVersion),
header.GroupVersionV1))
}
RetirementNote is the right default. Only a reader that itself accepted a headerless artifact until AlphaRemovedIn substitutes RetirementNoteWithAbsent; the tolerance varied by track, so the empty case is opt-in rather than a property of the value.
Kind Field ¶
The Kind field is a typed constant identifying the resource:
- KindSnapshot ("Snapshot"): System configuration capture
- KindRecipe ("Recipe"): Configuration recommendations
- KindRecipeResult ("RecipeResult"): Resolved recipe with hydrated values
Custom Metadata ¶
Because Metadata is a flat map[string]string, callers may add their own keys alongside the Init-populated "timestamp" and "version":
h.Metadata["node"] = "gpu-node-1" h.Metadata["cluster"] = "production" h.Metadata["environment"] = "staging"
Timestamps ¶
Init writes the timestamp using RFC3339 format in UTC:
h.Init(header.KindRecipe, header.StableGroupVersion, "v1.0.0") // h.Metadata["timestamp"] == "2025-12-30T10:30:00Z"
Validation ¶
While Header doesn't enforce validation, consumers should verify:
- APIVersion is supported
- Kind is recognized
- Metadata["timestamp"] is reasonable
- Version is a valid semantic version (if present)
Index ¶
- Constants
- func IsSupportedAPIVersion(v string) bool
- func IsSupportedAuthoringAPIVersion(v string) bool
- func IsSupportedBundleInfoAPIVersion(v string) bool
- func IsSupportedProfileAPIVersion(v string) bool
- func IsSupportedRecipeResultAPIVersion(v string) bool
- func RetirementNote(apiVersion string) string
- func RetirementNoteWithAbsent(apiVersion string) string
- type Header
- type Kind
Constants ¶
const ( // Domain is the single source of truth for the AICR API domain. Every // role (apiVersion group, K8s label/annotation keys, attestation and // provenance URI hosts, UUIDv5 namespace seed) derives from this value. Domain = "aicr.run" // APIGroup is the API group for AICR artifacts. APIGroup = Domain // APIVersionV1Beta1 is the ADR-022 target for authoring and configuration // artifacts: AICRConfig, ordinary RecipeMetadata, RecipeMixin, and // ComponentRegistry. APIVersionV1Beta1 = "v1beta1" // APIVersionV1Beta2 is the ADR-022 target for profile-bearing // RecipeMetadata and RecipeResult artifacts. APIVersionV1Beta2 = "v1beta2" // APIVersionV1 is the ADR-022 target for stable public artifacts: // Snapshot, default RecipeResult, RecipeCriteria, and BundleProvenance. APIVersionV1 = "v1" // StableGroupVersion is the value emitted for the ADR-022 stable artifact // track: Snapshot, the default RecipeResult, RecipeCriteria, and // BundleProvenance. It reached its §2 target in v0.22 (#2416). StableGroupVersion = GroupVersionV1 // AuthoringGroupVersion is the value emitted for the ADR-022 authoring and // configuration track: AICRConfig, ordinary RecipeMetadata, RecipeMixin, // and ComponentRegistry. It reached its §2 target in v0.22 (#2416). AuthoringGroupVersion = GroupVersionV1Beta1 // ProfileGroupVersion is the value emitted for the ADR-022 profile-bearing // track: profile RecipeMetadata and RecipeResult. It reached its §2 target // in v0.22 (#2416). ProfileGroupVersion = GroupVersionV1Beta2 // GroupVersionV1Beta1 is the target authoring/configuration group/version. GroupVersionV1Beta1 = APIGroup + "/" + APIVersionV1Beta1 // GroupVersionV1Beta2 is the target profile-bearing group/version. GroupVersionV1Beta2 = APIGroup + "/" + APIVersionV1Beta2 // GroupVersionV1 is the target stable public artifact group/version. GroupVersionV1 = APIGroup + "/" + APIVersionV1 )
AICR artifact API versioning. These constants are the single source of truth for every AICR artifact group/version. Package-local emitters and readers select a version by wire kind and schema track; see ADR-022.
Three tracks exist. StableGroupVersion, AuthoringGroupVersion, and ProfileGroupVersion name the value each track emits; since the v0.22 emitter switch (#2416) each equals its target, GroupVersionV1, GroupVersionV1Beta1 and GroupVersionV1Beta2 respectively.
The three carried one shared string before the v0.22 emitter switch, which is what let a package alias that string directly and still look correct while emitting the wrong value later. Alias the constant for your track, never the string it happens to equal; the tracks hold distinct values now and a collapsed alias shows up as a wrong value rather than a latent one.
Evolution policy (see docs/design/011-artifact-apiversion-policy.md and docs/design/022-artifact-maturity-and-deprecation.md): schema changes within a version must be additive-only; a breaking change requires a new version segment. Alpha versions owe no deprecation window. Beta versions remain readable for two AICR releases after deprecation, and GA versions remain readable through the current AICR major version. Version bumps that owe a window stage readers before emitters.
const ( RetiredGroupVersionV1Alpha2 = APIGroup + "/v1alpha2" RetiredGroupVersionV1Alpha3 = APIGroup + "/v1alpha3" )
Retired artifact API versions. ADR-022 §3 bound the alpha values to N+2, which is v1.0.0 (#2417); at that release they left every accepted set.
They survive only so a rejection can name what the value was. An artifact written by an older aicr is a common and recoverable situation, and "unsupported apiVersion" alone does not tell its author that the value was withdrawn deliberately or which release withdrew it. Never add either to an accepted set — RetirementNote is their only legitimate consumer.
const ( AnnotationComponentVersion = Domain + "/component-version" AnnotationGeneratedBy = Domain + "/generated-by" )
Annotations AICR stamps onto a generated Helm wrapper chart, derived from Domain per ADR-013 so an API-domain migration cannot leave them behind.
They live here rather than beside the writer that emits them because the reader that consumes them is `aicr upgrade-check --from cluster`, which reads a cluster and has no business importing the bundle writer. A single spelling is the whole point: a reader looking up a key the writer stopped emitting sees an unstamped chart, and reports a wrapper's version as the payload's.
AnnotationComponentVersion carries the free-form version of the payload the wrapper contains, and AnnotationGeneratedBy the AICR build version that produced the wrapper, mirroring Chart.yaml `version:`.
The rule for a reader is one sentence with two branches: use AnnotationComponentVersion when it is present, otherwise use the release's own chart version. Its presence is exactly the signal that the chart version describes the wrapper rather than the payload: an upstream chart installed directly carries neither annotation, and its release version IS the payload version (ADR-021 Decision 7).
const AlphaRemovedIn = "v1.0.0"
AlphaRemovedIn is the release that stopped reading the alpha apiVersion values and the legacy empty header.
Variables ¶
This section is empty.
Functions ¶
func IsSupportedAPIVersion ¶ added in v0.16.0
IsSupportedAPIVersion reports whether v is an artifact apiVersion this binary understands. The empty string is intentionally NOT supported here: callers that tolerate a missing apiVersion for backward compatibility with older artifacts must special-case "" before calling this.
This compatibility helper covers the stable artifact track only. Callers reading authoring or profile-bearing artifacts must use the corresponding schema-track helper instead of treating versions as globally interchangeable.
func IsSupportedAuthoringAPIVersion ¶ added in v0.21.0
IsSupportedAuthoringAPIVersion reports whether v is accepted for an ADR-022 authoring/configuration artifact.
func IsSupportedBundleInfoAPIVersion ¶ added in v0.22.0
IsSupportedBundleInfoAPIVersion reports whether v is accepted for a BundleInfo. Unlike the other stable-track artifacts, this kind shipped directly at its ADR-022 target with no alpha predecessor, so no BundleInfo carrying a retired value ever legitimately existed. Kept distinct from IsSupportedAPIVersion, which the two now agree with only by coincidence.
func IsSupportedProfileAPIVersion ¶ added in v0.21.0
IsSupportedProfileAPIVersion reports whether v is accepted for a profile-bearing RecipeMetadata or RecipeResult.
func IsSupportedRecipeResultAPIVersion ¶ added in v0.19.0
IsSupportedRecipeResultAPIVersion reports whether v is a RecipeResult version understood by this binary. The gate is the union of the default and profile-bearing schema tracks; callers must still enforce the bidirectional version/profile discriminator contract.
func RetirementNote ¶ added in v1.0.0
RetirementNote returns a parenthetical explaining that an apiVersion was withdrawn, or "" for any other value — including one that is merely unknown, where there is nothing specific to say.
Callers append it to a message that already names the observed value, the expected value, and how to regenerate the artifact. Splitting it out this way keeps each caller's message in its own vocabulary ("recapture the snapshot", "regenerate the criteria") while the reason an old artifact stopped working is worded once.
An absent apiVersion gets no note here, because whether that value ever loaded is a property of the calling reader rather than of the value. Readers that did accept it call RetirementNoteWithAbsent instead.
func RetirementNoteWithAbsent ¶ added in v1.0.0
RetirementNoteWithAbsent is RetirementNote for the five readers whose tolerance of an absent apiVersion survived until AlphaRemovedIn: the Snapshot, RecipeCriteria, and RecipeResult inputs whose artifacts predate the field.
Every other reader must call RetirementNote. An AICRConfig never loaded without a header, and a RecipeMetadata overlay stopped in v0.21 with the catalog scanner (#2421) — telling either author the value "was accepted" until v1.0.0 sends them looking for a regression that never happened, which is worse than the bare "unsupported apiVersion" this clause exists to improve.
Types ¶
type Header ¶
type Header struct {
// Kind is the type of the snapshot object.
Kind Kind `json:"kind,omitempty" yaml:"kind,omitempty"`
// APIVersion is the API version of the snapshot object.
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
// Metadata contains key-value pairs with metadata about the snapshot.
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`
}
Header contains metadata and versioning information for AICR resources. It follows Kubernetes-style resource conventions with Kind, APIVersion, and Metadata fields.
func (*Header) Init ¶
Init initializes the Header with the specified kind, apiVersion, and version. It sets the Kind, APIVersion, and populates Metadata with timestamp and version. Uses unprefixed keys (timestamp, version) for all kinds.
The timestamp is wall-clock time. Reproducible-build callers (SLSA, signed artifacts) must inject a fixed timestamp via InitWithTime to keep the serialized header byte-stable across runs.
func (*Header) InitWithTime ¶ added in v0.14.0
InitWithTime is like Init but uses the caller-supplied timestamp. Use this when the header feeds into a digest, signature, or otherwise reproducible artifact — derive ts from a content-addressable source (commit SHA, the SOURCE_DATE_EPOCH environment variable, etc.).
type Kind ¶
type Kind string
Kind represents the type of AICR resource. All AICR resources should use these constants for consistency.