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 `/@sha256:…` is kept as its path; an // archive it named `http:///v2//blobs/` 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: `/@` // for an image, `//blobs/` for a bundle or an archive. **It reads both forms** (novox/hq ADR // 0605 §9): the older `artifact-store://`, and the form a registry seat answers, `//@` // 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 == contractseats.OciArtifactRegistry { 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{contractseats.ContainerImageRegistry, contractseats.OciArtifactRegistry} // InRegistrySeat reads a reference in the form a registry seat answers, `//@sha256:`: // 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 }