Files
mesh-sdk/go/catalogue/artifacts.go
T
jschoubben d15c1bc814 ADR 0625 §3, ADR 0627 §4: mesh-sdk imports the seat set in catalogue alone, and names no client seat outside it
buscompose, delivery's builder and step asks, handacts, health and provisions take their seat names from catalogue.
The package-list test refuses any other contracts import, the client seats' names outside catalogue, and the moved
packages (asks, asker, publish) by name; what the group's join still moves (asks, asker, the vault module's name in
delivery and provisions) is listed and only shrinks.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 13:20:35 +01:00

110 lines
4.6 KiB
Go

package catalogue
import (
"strings"
contractseats "git.novox.be/novox/mesh-contracts/go/seats"
)
// ArtifactStoreScheme marks a reference to something in the mesh's artifact store, kept without
// the store's address.
const ArtifactStoreScheme = ArtifactStoreProvision + "://"
// Recorded is a reference as the mesh records it: the artifact store's address, if the builder wrote
// one, taken off.
//
// For a reference the builder announced — one it pushed to the store — which is the only kind
// this is called on. An image the builder named `<host>/<path>@sha256:…` is kept as its path; an
// archive it named `http://<host>/v2/<path>/blobs/<digest>` likewise. A reference with no address
// in it — an image id from a genesis build that had nowhere to publish, a package version — is
// what it was.
func Recorded(reference string) string {
if _, _, seat := InRegistrySeat(reference); seat || strings.HasPrefix(reference, ArtifactStoreScheme) {
return reference
}
if rest, isURL := strings.CutPrefix(reference, "http://"); isURL {
if _, path, ok := strings.Cut(rest, "/v2/"); ok && strings.Contains(path, "/blobs/") {
return ArtifactStoreScheme + path
}
return reference
}
host, path, ok := strings.Cut(reference, "/")
if !ok || !isRegistryHost(host) || !strings.Contains(path, "@sha256:") {
return reference
}
return ArtifactStoreScheme + path
}
// isRegistryHost is the runtime's own rule for reading the first component of a reference as a
// registry rather than as a namespace: it has a dot or a port in it, or it is localhost.
func isRegistryHost(component string) bool {
return component == "localhost" || strings.ContainsAny(component, ".:")
}
// InArtifactStore reports whether a reference is a kept one, and what it names there: `<module>/<artifact>@<digest>`
// for an image, `<module>/<artifact>/blobs/<digest>` for a bundle or an archive. **It reads both forms** (novox/hq ADR
// 0605 §9): the older `artifact-store://<path>`, and the form a registry seat answers, `<seat>/<module>/<artifact>@<digest>`
// through container-image-registry or oci-artifact-registry, whose blob it names the way the older form did.
func InArtifactStore(reference string) (path string, kept bool) {
if seat, rest, ok := InRegistrySeat(reference); ok {
if seat == OciArtifactRegistrySeat {
name, digest, _ := strings.Cut(rest, "@")
return name + "/blobs/" + digest, true
}
return rest, true
}
return strings.CutPrefix(reference, ArtifactStoreScheme)
}
// RegistrySeats are the seats a reference of the registry form names first, the two that front the artifact store
// (novox/hq ADR 0605 §1, §9).
var RegistrySeats = []string{ContainerImageRegistrySeat, OciArtifactRegistrySeat}
// The four registry seats (novox/hq ADR 0605 §1), named here so the rest of mesh-sdk takes them from the seat set
// through catalogue alone (ADR 0625 §3).
const (
NpmPackageRegistrySeat = contractseats.NpmPackageRegistry
GoPackageRegistrySeat = contractseats.GoPackageRegistry
ContainerImageRegistrySeat = contractseats.ContainerImageRegistry
OciArtifactRegistrySeat = contractseats.OciArtifactRegistry
)
// PublishSeats are the seats an artifact is published through (ADR 0605 §1).
var PublishSeats = []string{NpmPackageRegistrySeat, GoPackageRegistrySeat, ContainerImageRegistrySeat, OciArtifactRegistrySeat}
// The seats of the vault, the provisioner, the hand acts' record and the conditions' keeper, as the seat set names them,
// for the rest of mesh-sdk (ADR 0625 §3).
const (
VaultSeat = contractseats.MeshVault
ProvisionerSeat = contractseats.MeshProvisioner
)
// InRegistrySeat reads a reference in the form a registry seat answers, `<seat>/<module>/<artifact>@sha256:<digest>`:
// the seat it came through and the rest. A seat's name holds no dot or port, so no image of an outside registry reads
// as one, and a kept `artifact-store://` reference is not one.
func InRegistrySeat(reference string) (seat, path string, ok bool) {
first, rest, found := strings.Cut(reference, "/")
if !found || !strings.Contains(rest, "@sha256:") || strings.Count(rest, "/") != 1 {
return "", "", false
}
for _, s := range RegistrySeats {
if first == s {
return s, rest, true
}
}
return "", "", false
}
// Routed is a kept reference as a machine fetches it, through the artifact store at `address`
// (host:port). A reference that is not a kept one is what it was.
func Routed(reference, address string) string {
path, kept := InArtifactStore(reference)
if !kept {
return reference
}
if strings.Contains(path, "/blobs/") {
return "http://" + address + "/v2/" + path
}
return address + "/" + path
}