Documentation
¶
Overview ¶
Package release builds immutable, content-addressed release bundles: a deterministic tar holding manifest.json plus every rendered file (as blobs/<sha256>). The tar's sha256 is the release digest.
Index ¶
- Constants
- func BuildRing(org *policy.Org, ring string, opts Options) (rel *Release, variants []*Release, err error)
- func CheckRendered(harnessName string, os harness.OS, files []harness.File, p *policy.Profile, ...) error
- func Diff(a, b *Release) string
- func VariantVersion(ver, ring, exp, variant string) string
- func VerifyAttestations(rel *Release, bom, prov []byte) error
- type Artifact
- type ArtifactKind
- type ArtifactResolver
- type AttestOptions
- type Attestations
- type CloudAgentFile
- type Experiment
- type ExperimentVariant
- type FileEntry
- type HarnessEntry
- type Manifest
- type Options
- type ProfileResolver
- type Release
- type RemoteAgentEntry
- type SupplyChainEntry
- type ToggleEntry
- type UnitEntry
Constants ¶
const ( BOMMediaType = "application/vnd.cyclonedx+json" ProvenanceMediaType = "application/vnd.in-toto+json" StatementType = "https://in-toto.io/Statement/v1" SLSAProvenanceType = "https://slsa.dev/provenance/v1" BuildType = "https://github.com/dshakes/halos/release-build/v1" )
Media and predicate types.
const AnyPlatform = "any"
AnyPlatform keys an artifact that is the same on every OS/arch (npm).
Variables ¶
This section is empty.
Functions ¶
func BuildRing ¶
func BuildRing(org *policy.Org, ring string, opts Options) (rel *Release, variants []*Release, err error)
BuildRing builds ring's release plus one release per variant of every running client-axis experiment enrolling ring. The ring release manifest lists those experiments (salt, weights, channel per variant) so halod can assign a device to a variant with the gateway's hash and pull the channel. Each variant release is built from the variant's profile (extends resolved) with Experiment/Variant set, so its harness config carries the attribution.
func CheckRendered ¶
func CheckRendered(harnessName string, os harness.OS, files []harness.File, p *policy.Profile, g *policy.Gateway) error
CheckRendered asserts security invariants on the files an adapter rendered, by parsing the output rather than trusting how it was produced. It is the backstop for adapter regressions and for harnesses.<h>.overrides, which are deep-merged after rendering. Any violation fails the build.
func Diff ¶
Diff returns a human-readable summary of what changes going from a to b: harness version/install changes, and per-file added/removed/changed with a line diff (changed lines only, no context; ponytail: add hunks if reviewers ask). Empty string means no differences.
func VariantVersion ¶
VariantVersion is the version label of the variant release published with ring release ver: "<ver>-x-<experiment>.<variant>" (or the hashed channel suffix, see policy.ChannelName). Deterministic, so a rollback of the ring to ver can re-point every channel at the variant releases published with it.
func VerifyAttestations ¶ added in v0.4.0
VerifyAttestations checks that bom and prov describe rel: both name rel's digest, every rendered file, artifact and install artifact in the manifest is in the BOM with the same hash and nothing else is, the provenance's artifact and install dependencies match the manifest, and its BOM byproduct digest is bom's. Signatures are checked by internal/bundle.
Types ¶
type Artifact ¶
type Artifact struct {
URL string `json:"url"`
SHA256 string `json:"sha256,omitempty"` // lowercase hex
Integrity string `json:"integrity,omitempty"` // SRI "sha512-<base64>" (npm dist.integrity)
Size int64 `json:"size,omitempty"` // exact byte size when known
Kind ArtifactKind `json:"kind"`
BinPath string `json:"binPath"` // binary: installed file name; npm: bin command name
Package string `json:"package,omitempty"` // npm package name
}
Artifact is one downloadable, hash-pinned installer input.
type ArtifactKind ¶
type ArtifactKind string
ArtifactKind says how halod installs an artifact.
const ( // KindBinary is a single self-contained executable, placed atomically in // halod's root-owned bin dir. KindBinary ArtifactKind = "binary" // KindNPMTgz is an npm package tarball installed with lifecycle scripts // disabled and no user/global npmrc. KindNPMTgz ArtifactKind = "npm-tgz" )
type ArtifactResolver ¶
type ArtifactResolver struct {
HTTP *http.Client // default: 60s timeout
ClaudeBase string // default https://downloads.claude.ai/claude-code-releases
NPMRegistry string // default https://registry.npmjs.org
}
ArtifactResolver fills HarnessEntry.Artifacts from the vendors' release metadata.
type AttestOptions ¶ added in v0.4.0
type AttestOptions struct {
HalosVersion string // version of the halo that built it
BuilderID string // default https://github.com/dshakes/halos/cmd/halo@<HalosVersion>
PolicyRepo string // policy repo URL, if known
PolicyCommit string // policy repo commit (git rev-parse HEAD), if known
PolicyDirty bool // the working tree had uncommitted changes
}
AttestOptions are the build facts the release itself does not carry.
type Attestations ¶ added in v0.4.0
Attestations are a release's CycloneDX 1.6 AI-BOM and its in-toto Statement v1 with a SLSA provenance v1 predicate, as JSON.
func Attest ¶ added in v0.4.0
func Attest(rel *Release, org *policy.Org, o AttestOptions) (*Attestations, error)
Attest builds rel's AI-BOM and provenance. org supplies the models and MCP servers rel's profile references (nil: only what the manifest holds). The output is deterministic for the same inputs.
type CloudAgentFile ¶ added in v0.4.0
type CloudAgentFile struct {
Vendor string `json:"vendor"`
Path string `json:"path"` // relative to the repository root
SHA256 string `json:"sha256"`
Repos []string `json:"repos,omitempty"` // policy repo patterns it is for
}
CloudAgentFile is one rendered cloud agent repository file.
type Experiment ¶
type Experiment struct {
Name string `json:"name"`
Salt string `json:"salt"`
Variants []ExperimentVariant `json:"variants"`
}
Experiment is one client-axis experiment in a ring release manifest: just what halod needs to compute the same assignment as the gateway.
func (Experiment) Policy ¶
func (e Experiment) Policy(ring string) *policy.Experiment
Policy returns the policy experiment halod evaluates for a manifest entry: running, enrolling ring, with the manifest's salt and weights, so policy.Experiment.ResolveVariant (the gateway's function) does the hashing.
type ExperimentVariant ¶
type ExperimentVariant struct {
Name string `json:"name"`
Weight float64 `json:"weight"`
Channel string `json:"channel"`
}
ExperimentVariant is a variant and the channel serving its release.
type FileEntry ¶
type FileEntry struct {
Path string `json:"path"`
Mode uint32 `json:"mode"`
SHA256 string `json:"sha256"`
// Artifact/ArtifactPath tie the file to a Manifest.SupplyChain entry and
// its path inside it; halod checks both before writing (ADR-0028).
Artifact string `json:"artifact,omitempty"`
ArtifactPath string `json:"artifactPath,omitempty"`
}
FileEntry describes one rendered file in the manifest.
type HarnessEntry ¶
type HarnessEntry struct {
Version string `json:"version"`
InstallCommand map[string]string `json:"installCommand,omitempty"`
Files map[string][]FileEntry `json:"files"`
// Artifacts are verified install artifacts keyed by "<goos>-<goarch>"
// (or "any"), filled by ResolveArtifacts; see artifacts.go.
Artifacts map[string]Artifact `json:"artifacts,omitempty"`
}
HarnessEntry is one harness's pinned version, installer and files, per OS.
func (HarnessEntry) ArtifactFor ¶
func (h HarnessEntry) ArtifactFor(goos, goarch string) (Artifact, bool)
ArtifactFor picks the artifact for goos/goarch, falling back to AnyPlatform.
type Manifest ¶
type Manifest struct {
SchemaVersion int `json:"schemaVersion"`
Org string `json:"org"`
Version string `json:"version"`
Profile string `json:"profile"`
Ring string `json:"ring"`
CreatedAt time.Time `json:"createdAt"`
Harnesses map[string]HarnessEntry `json:"harnesses"`
Warnings []string `json:"warnings,omitempty"`
// Experiment/Variant are set on a client-axis variant release only: the
// release served on channel policy.ChannelName(Ring, Experiment, Variant).
Experiment string `json:"experiment,omitempty"`
Variant string `json:"variant,omitempty"`
// Experiments (ring releases only) lists the running client-axis
// experiments enrolling Ring. Signed with the release, it is what halod
// uses to pick a device's variant channel.
Experiments []Experiment `json:"experiments,omitempty"`
// Toggles are the client-axis feature toggles: targeting rules plus the
// per-harness fragments halod merges for the toggles that are on for it.
Toggles []ToggleEntry `json:"toggles,omitempty"`
// Units are the org units (ADR-0018): member selectors plus each unit's
// rendered files, which halod applies in place of the release's own.
Units []UnitEntry `json:"units,omitempty"`
// RemoteAgents pins the A2A agents this ring's members (or some of its
// units' members) may call, with each AgentCard's digest (ADR-0024):
// signed with the release, so a changed card is a policy change.
RemoteAgents []RemoteAgentEntry `json:"remoteAgents,omitempty"`
// SupplyChain pins the extension artifacts this release delivers
// (ADR-0028): each one's digest and file listing, signed with the release.
SupplyChain []SupplyChainEntry `json:"supplyChain,omitempty"`
// MCPMode and MCPServers carry the halos.yaml mcp registry (ADR-0029):
// its mode and the servers ring's members (or some of its units' members)
// get, pinned, so halod reports unapproved and version-drifted servers in
// user configs. Empty when the policy has no registry.
MCPMode string `json:"mcpMode,omitempty"`
MCPServers []policy.MCPPin `json:"mcpServers,omitempty"`
// CloudAgents are the repository files of the workflow-configured cloud
// agents (ADR-0034), signed with the release for review and the PR that
// adds them. halod never writes them: they belong in repositories.
CloudAgents []CloudAgentFile `json:"cloudAgents,omitempty"`
}
Manifest is manifest.json inside the bundle.
func (Manifest) Artifact ¶ added in v0.4.0
func (m Manifest) Artifact(name string) (SupplyChainEntry, bool)
Artifact returns the supply-chain entry named name.
func (Manifest) Channels ¶
Channels returns the variant channels m routes ring's devices to. A release built for another ring (promoted across rings) routes nowhere: its experiments enrolled the ring it was built for.
func (Manifest) CheckArtifactFile ¶ added in v0.4.0
CheckArtifactFile is what halod runs before writing an artifact file: the artifact's listing must hash to its pinned digest and list f's path with f's hash, and data (when non-nil) must hash to that too.
func (Manifest) CheckArtifactFiles ¶ added in v0.4.0
CheckArtifactFiles runs CheckArtifactFile (without content) over every artifact file the manifest delivers: harness, unit and toggle files.
type Options ¶
type Options struct {
Org string // defaults to the resolver's Org.Name when it is a *policy.Org
Version string // release version label, e.g. "1.4.0"
CreatedAt time.Time // zero => Unix epoch, keeping builds reproducible
OSes []harness.OS // defaults to darwin, linux, windows
Gateway *policy.Gateway // defaults to Org.Gateway when resolver is a *policy.Org
// Experiment/Variant mark a client-axis variant release: stamped into the
// manifest and into the harness config (telemetry resource attributes).
Experiment, Variant string
// Experiments is the ring release's client-axis experiment table (see BuildRing).
Experiments []Experiment
}
Options tunes Build. Zero value is valid.
type ProfileResolver ¶
ProfileResolver is satisfied by *policy.Org once it grows ResolveProfile.
type Release ¶
type Release struct {
Manifest Manifest
Blobs map[string][]byte // sha256 hex -> content
Tar []byte
Digest string // "sha256:<hex>" of Tar
// Attestations (AI-BOM and provenance, see Attest) describe the release
// by digest; they are not part of Tar. bundle.Publish stores them as a
// signed OCI referrer when set.
Attestations *Attestations
}
Release is a built (or opened) bundle.
func Build ¶
func Build(org ProfileResolver, profileName, ringName string, opts Options) (*Release, error)
Build renders profileName for every enabled harness and OS.
func Open ¶
Open parses a bundle tar and verifies every blob against its name and every manifest entry against a blob. It does NOT verify signatures; see internal/bundle. Only regular files are accepted, and since the tar is uncompressed no entry may yield more bytes than the tar itself holds: archive/tar expands PAX/GNU sparse entries, so a few KiB could otherwise decode to gigabytes.
type RemoteAgentEntry ¶ added in v0.3.0
type RemoteAgentEntry struct {
Name string `json:"name"`
CardURL string `json:"cardURL"`
Digest string `json:"digest"`
Skills []string `json:"skills,omitempty"`
// Units, when set, are the only units (and units below them) whose
// members may call it; empty = every member of the ring.
Units []string `json:"units,omitempty"`
}
RemoteAgentEntry is one allowlisted remote agent in a release manifest.
type SupplyChainEntry ¶ added in v0.4.0
type SupplyChainEntry struct {
Name string `json:"name"`
Kind string `json:"kind"`
Source string `json:"source"`
// Digest is supplychain.DigestOf(Files): the content pin.
Digest string `json:"digest"`
// Signer is the trusted identity whose signature over Digest verified at
// build time, if the artifact is signed.
Signer string `json:"signer,omitempty"`
// Files is the listing the digest covers: path in the artifact -> sha256
// hex. Empty when the content was not resolved (nothing is delivered).
Files map[string]string `json:"files,omitempty"`
}
SupplyChainEntry is one extension artifact in a release manifest (ADR-0028).
type ToggleEntry ¶
type ToggleEntry struct {
Name string `json:"name"`
Default bool `json:"default"`
Expires string `json:"expires,omitempty"`
Rules []policy.ToggleRule `json:"rules,omitempty"`
// Fragments is harness -> OS -> deltas, one per file the toggle changes
// (FileEntry.Path is the managed file the delta applies to; the blob is
// JSON, see toggle.Delta). The release's own files are the toggle-off state.
Fragments map[string]map[string][]FileEntry `json:"fragments,omitempty"`
}
ToggleEntry is one client-axis toggle in a release manifest. Being inside the signed manifest, neither the rules nor the fragments can be altered in transit.
type UnitEntry ¶ added in v0.3.0
type UnitEntry struct {
Name string `json:"name"`
Parent string `json:"parent,omitempty"`
Groups []string `json:"groups,omitempty"`
Users []string `json:"users,omitempty"`
// Files is harness -> OS -> the files the unit's effective profile renders
// differently from the release's own: whole files (not deltas), so an
// overlay can narrow a list. The release's own files are the no-unit state.
Files map[string]map[string][]FileEntry `json:"files,omitempty"`
}
UnitEntry is one org unit in a release manifest (ADR-0018): its member selector, so halod picks the device's unit with policy.MatchUnit, and the unit's rendered files. Being inside the signed manifest, neither can be altered in transit.