@@ -18,21 +18,27 @@ package pack
1818
1919import (
2020 "context"
21+ "errors"
2122 "fmt"
2223 "io"
2324 "os"
25+ "strings"
2426
2527 "github.com/kitops-ml/kitops/pkg/artifact"
28+ cmdoptions "github.com/kitops-ml/kitops/pkg/cmd/options"
2629 "github.com/kitops-ml/kitops/pkg/lib/constants"
2730 "github.com/kitops-ml/kitops/pkg/lib/constants/mediatype"
2831 "github.com/kitops-ml/kitops/pkg/lib/filesystem"
2932 "github.com/kitops-ml/kitops/pkg/lib/filesystem/ignore"
3033 kfutils "github.com/kitops-ml/kitops/pkg/lib/kitfile"
3134 "github.com/kitops-ml/kitops/pkg/lib/repo/local"
35+ "github.com/kitops-ml/kitops/pkg/lib/repo/remote"
3236 "github.com/kitops-ml/kitops/pkg/lib/repo/util"
3337 "github.com/kitops-ml/kitops/pkg/output"
3438
39+ "github.com/opencontainers/go-digest"
3540 ocispec "github.com/opencontainers/image-spec/specs-go/v1"
41+ "oras.land/oras-go/v2/errdef"
3642)
3743
3844// runPack compresses and stores a modelkit based on a Kitfile. Returns an error if packing
@@ -79,13 +85,21 @@ func runPack(ctx context.Context, options *packOptions) error {
7985
8086func pack (ctx context.Context , opts * packOptions , kitfile * artifact.KitFile , localRepo local.LocalRepo ) (* ocispec.Descriptor , error ) {
8187 var extraLayerPaths []string
88+ var subject * ocispec.Descriptor
8289 if kitfile .Model != nil && artifact .IsModelKitReference (kitfile .Model .Path ) {
8390 baseRef := artifact .FormatRepositoryForDisplay (opts .modelRef .String ())
8491 parentKitfile , err := kfutils .ResolveKitfile (ctx , opts .configHome , kitfile .Model .Path , baseRef )
8592 if err != nil {
8693 return nil , fmt .Errorf ("Failed to resolve referenced modelkit %s: %w" , kitfile .Model .Path , err )
8794 }
8895 extraLayerPaths = util .LayerPathsFromKitfile (parentKitfile )
96+
97+ baseDesc , err := resolveBaseManifestDescriptor (ctx , opts .configHome , kitfile .Model .Path )
98+ if err != nil {
99+ output .Logf (output .LogLevelWarn , "failed to resolve base manifest descriptor for OCI subject: %v" , err )
100+ } else if baseDesc != nil {
101+ subject = baseDesc
102+ }
89103 }
90104
91105 ignore , err := ignore .NewFromContext (opts .contextDir , kitfile , extraLayerPaths ... )
@@ -105,13 +119,61 @@ func pack(ctx context.Context, opts *packOptions, kitfile *artifact.KitFile, loc
105119 ModelFormat : modelFormat ,
106120 Compression : compression ,
107121 LayerFormat : mediatype .TarFormat ,
122+ Subject : subject ,
108123 })
109124 if err != nil {
110125 return nil , err
111126 }
112127 return manifestDesc , nil
113128}
114129
130+ func resolveBaseManifestDescriptor (ctx context.Context , configHome , baseRef string ) (* ocispec.Descriptor , error ) {
131+ if strings .HasPrefix (baseRef , "sha256:" ) {
132+ parsedDigest , err := digest .Parse (baseRef )
133+ if err != nil {
134+ return nil , fmt .Errorf ("failed to parse digest-only base reference: %w" , err )
135+ }
136+ return & ocispec.Descriptor {MediaType : ocispec .MediaTypeImageManifest , Digest : parsedDigest }, nil
137+ }
138+
139+ ref , _ , err := artifact .ParseReference (baseRef )
140+ if err != nil {
141+ return nil , fmt .Errorf ("failed to parse base reference: %w" , err )
142+ }
143+
144+ localRepo , err := local .NewLocalRepo (constants .StoragePath (configHome ), ref )
145+ if err != nil {
146+ return nil , fmt .Errorf ("failed to create local repository: %w" , err )
147+ }
148+
149+ desc , _ , _ , err := util .ResolveManifestAndConfig (ctx , localRepo , ref .Reference )
150+ if err == nil {
151+ return & desc , nil
152+ }
153+ if errors .Is (err , util .ErrNoKitfile ) || errors .Is (err , util .ErrNotAModelKit ) {
154+ return nil , nil
155+ }
156+ if ! errors .Is (err , errdef .ErrNotFound ) && ! errors .Is (err , errdef .ErrMissingReference ) {
157+ return nil , fmt .Errorf ("failed to resolve base descriptor locally: %w" , err )
158+ }
159+
160+ repository , err := remote .NewRepository (ctx , ref .Registry , ref .Repository , cmdoptions .DefaultNetworkOptions (configHome ))
161+ if err != nil {
162+ return nil , fmt .Errorf ("failed to create remote repository: %w" , err )
163+ }
164+
165+ desc , _ , _ , err = util .ResolveManifestAndConfig (ctx , repository , ref .Reference )
166+ if err != nil {
167+ if errors .Is (err , util .ErrNoKitfile ) || errors .Is (err , util .ErrNotAModelKit ) {
168+ return nil , nil
169+ }
170+ output .Logf (output .LogLevelWarn ,
171+ "failed to resolve base descriptor, skipping subject linkage: %v" , err )
172+ return nil , nil
173+ }
174+ return & desc , nil
175+ }
176+
115177func readKitfile (modelFile string ) (* artifact.KitFile , error ) {
116178 // 1. Read the model file
117179 kitfile := & artifact.KitFile {}
0 commit comments