From e3758933819b2f133ebeb73e0065b0a0aaa7c276 Mon Sep 17 00:00:00 2001 From: CamrynCarter Date: Sat, 25 Jul 2026 15:23:47 -0700 Subject: [PATCH] maintain provenance of original artifact reference --- cmd/hauler/cli/store/add.go | 27 +++++++++++++++++++++++++++ pkg/consts/consts.go | 12 ++++++++++++ pkg/store/store.go | 6 ++++++ 3 files changed, 45 insertions(+) diff --git a/cmd/hauler/cli/store/add.go b/cmd/hauler/cli/store/add.go index fe2c598..4a22fcb 100644 --- a/cmd/hauler/cli/store/add.go +++ b/cmd/hauler/cli/store/add.go @@ -128,6 +128,15 @@ func storeFile(ctx context.Context, s *store.Layout, fi v1.File, ro *flags.CliRo resolvedPath = abs } } + + // Preserve the original source (a URL for remote files, an absolute path for + // local ones) so `store create manifest` can recover it later; nothing else in + // the store retains it. + desc.Annotations[consts.OriginalRefAnnotation] = resolvedPath + if err := s.OCI.AddIndex(desc); err != nil { + return err + } + if auditLevel(ro) != "none" { e := audit.Entry{ StoreID: s.StoreID, @@ -1177,6 +1186,15 @@ func fetchChart(ctx context.Context, s *store.Layout, j chartJob, tempRoot strin } } + // Charts have no registry-qualified annotation the way images do (via + // ContainerdImageNameKey), and RepoURL is otherwise never persisted anywhere in + // the store, so capture both here to maintain provenance regardless of whether + // --rewrite is ever applied. + chartDesc.Annotations[consts.OriginalRefAnnotation] = encodeOriginalChartRef(j.cfg.RepoURL, ref.Name()) + if err := s.OCI.AddIndex(chartDesc); err != nil { + return nil, nil, err + } + if auditLevel(ro) != "none" { e := audit.Entry{ StoreID: s.StoreID, @@ -1516,3 +1534,12 @@ func rewriteChartReference(ctx context.Context, s *store.Layout, ref name.Refere return nil } + +// encodeOriginalChartRef combines a chart's source repoURL with its pre-rewrite +// store "repo:tag" into a single string suitable for consts.OriginalRefAnnotation. +// Charts have no registry-qualified annotation the way images do (via +// ContainerdImageNameKey), so the repoURL has to be carried alongside the ref +// itself for `store create manifest` to recover a fully pullable chart reference. +func encodeOriginalChartRef(repoURL, total string) string { + return repoURL + "|" + total +} diff --git a/pkg/consts/consts.go b/pkg/consts/consts.go index 44f0eba..83ab469 100644 --- a/pkg/consts/consts.go +++ b/pkg/consts/consts.go @@ -71,6 +71,18 @@ const ( ImageAnnotationExcludeExtras = "hauler.dev/exclude-extras" ImageRefKey = "org.opencontainers.image.ref.name" + // OriginalRefAnnotation preserves each artifact's original source reference at + // the time it's first added to the store (images, charts, and files alike, + // whether local or remote), regardless of whether --rewrite is ever applied, so + // tooling like `store create manifest` can always recover a pullable source even + // after the store's own ref/containerd-name annotations have since been + // overwritten by a rewrite. For images this is the fully qualified containerd + // image name (registry/repo:tag); for charts, which have no equivalent + // registry-qualified annotation, it's "repoURL|repo:tag" (see + // encodeOriginalChartRef in cmd/hauler/cli/store); for files it's the original + // URL or absolute local path. + OriginalRefAnnotation = "hauler.dev/original-ref" + // cosign keyless validation options ImageAnnotationCertIdentity = "hauler.dev/certificate-identity" ImageAnnotationCertIdentityRegexp = "hauler.dev/certificate-identity-regexp" diff --git a/pkg/store/store.go b/pkg/store/store.go index 7804186..08d966c 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -464,6 +464,9 @@ func (l *Layout) writeImage(ctx context.Context, annotationRef gname.Reference, consts.KindAnnotationName: kind, ocispec.AnnotationRefName: strings.TrimPrefix(annotationRef.Name(), annotationRef.Context().RegistryStr()+"/"), consts.ContainerdImageNameKey: containerdName, + // Captured once at the initial add so the original, pullable reference + // survives even if a later --rewrite overwrites the annotations above. + consts.OriginalRefAnnotation: containerdName, }, } return l.OCI.AddIndex(desc) @@ -539,6 +542,9 @@ func (l *Layout) writeIndex(ctx context.Context, annotationRef gname.Reference, consts.KindAnnotationName: kind, ocispec.AnnotationRefName: strings.TrimPrefix(annotationRef.Name(), annotationRef.Context().RegistryStr()+"/"), consts.ContainerdImageNameKey: annotationRef.Name(), + // Captured once at the initial add so the original, pullable reference + // survives even if a later --rewrite overwrites the annotations above. + consts.OriginalRefAnnotation: annotationRef.Name(), }, } return l.OCI.AddIndex(desc)