Skip to content

Commit

Permalink
fixed OCI image import bug (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
mathieu-benoit authored Nov 1, 2024
2 parents b5497ab + f743ee2 commit 20d69ce
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 24 deletions.
30 changes: 21 additions & 9 deletions uriget/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func ExampleWithHttpClient() {
// Output: failed to make get request: Get "https://example.com": no proxy
}
func ExampleGetFile_oci() {
testUrl := "oci://ghcr.io/score-spec/score-compose:0.18.0"
testUrl := "oci://ghcr.io/score-spec/score-compose-community-provisioners:v0.1.0#00-service.provisioners.yaml"
buff, err := GetFile(context.Background(), testUrl)
if err != nil {
fmt.Println("failed to pull OCI image:", err)
Expand All @@ -63,26 +63,38 @@ func ExampleGetFile_oci() {
// true
}

func ExampleGetFile_ociNoTag() {
testUrl := "oci://ghcr.io/score-spec/score-compose"
buff, err := GetFile(context.Background(), testUrl)
func ExampleGetFile_oci_git() {
ociTestUrl := "oci://ghcr.io/score-spec/score-compose-community-provisioners:v0.1.0#00-service.provisioners.yaml"
ociBuff, err := GetFile(context.Background(), ociTestUrl)
if err != nil {
fmt.Println("failed to pull OCI image:", err)
return
}
fmt.Println(len(buff) > 0)
gitTestUrl := "git-https://github.com/score-spec/community-provisioners.git/score-compose/00-service.provisioners.yaml"
gitBuff, err := GetFile(context.Background(), gitTestUrl)
if err != nil {
fmt.Println("failed to pull file in git:", err)
return
}
fmt.Println(len(ociBuff) == len(gitBuff))
// Output:
// true
}

func ExampleGetFile_ociWithDigest() {
testUrl := "oci://ghcr.io/score-spec/score-compose@sha256:f3d8d5485a751cbdc91e073df1b6fbcde83f85a86ee3bc7d53e05b00452baedd"
buff, err := GetFile(context.Background(), testUrl)
func ExampleGetFile_oci_https() {
ociTestUrl := "oci://ghcr.io/score-spec/score-compose-community-provisioners:v0.1.0#00-service.provisioners.yaml"
ociBuff, err := GetFile(context.Background(), ociTestUrl)
if err != nil {
fmt.Println("failed to pull OCI image:", err)
return
}
fmt.Println(len(buff) > 0)
httpsTestUrl := "https://github.com/score-spec/community-provisioners/raw/v0.1.0/score-compose/00-service.provisioners.yaml"
httpsbuff, err := GetFile(context.Background(), httpsTestUrl)
if err != nil {
fmt.Println("failed to pull file by HTTPS:", err)
return
}
fmt.Println(len(ociBuff) == len(httpsbuff))
// Output:
// true
}
57 changes: 42 additions & 15 deletions uriget/uriget.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package uriget

import (
"context"
"encoding/json"
"fmt"
"io"
"log"
Expand All @@ -17,8 +18,7 @@ import (
"strings"
"time"

"oras.land/oras-go/v2"
"oras.land/oras-go/v2/content/oci"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/v2/registry"
"oras.land/oras-go/v2/registry/remote"
)
Expand Down Expand Up @@ -244,25 +244,52 @@ func (o *options) getGit(ctx context.Context, u *url.URL) ([]byte, error) {
func (o *options) getOci(ctx context.Context, u *url.URL) ([]byte, error) {
ref, err := registry.ParseReference(u.Host + u.Path)
if err != nil {
return nil, fmt.Errorf("can't parse artifact URL into a valid reference: %w", err)
return nil, fmt.Errorf("invalid artifact URL: %w", err)
}
store, err := oci.New(o.tempDir)
if err != nil {
return nil, fmt.Errorf("failed to create OCI layout store: %w", err)
if ref.Reference == "" {
ref.Reference = "latest"
}
specifiedFile := strings.TrimPrefix(u.Fragment, "#")
remoteRepo, err := remote.NewRepository(ref.String())
if err != nil {
return nil, fmt.Errorf("failed to connect to remote repository: %w", err)
return nil, fmt.Errorf("connection to remote repository failed: %w", err)
}
_, rc, err := remoteRepo.Manifests().FetchReference(ctx, ref.Reference)
if err != nil {
return nil, fmt.Errorf("manifest fetch failed: %w", err)
}
defer rc.Close()
var manifest v1.Manifest
if err = json.NewDecoder(rc).Decode(&manifest); err != nil {
return nil, fmt.Errorf("manifest decode failed: %w", err)
}
var selectedLayer *v1.Descriptor
yamlFileCount := 0
for _, layer := range manifest.Layers {
title := layer.Annotations[v1.AnnotationTitle]
if strings.HasSuffix(title, ".yaml") {
yamlFileCount++
if specifiedFile == "" && yamlFileCount > 1 {
return nil, fmt.Errorf("manifest contains %d .yaml files; specify a specific file in the URL fragment", yamlFileCount)
}
if specifiedFile == "" || title == specifiedFile {
selectedLayer = &layer
break
}
}
}
tag := "latest"
if ref.Reference != "" {
tag = ref.Reference
if selectedLayer == nil {
return nil, fmt.Errorf("no matching .yaml file found in layers")
}
manifestDescriptor, err := oras.Copy(ctx, remoteRepo, tag, store, tag, oras.DefaultCopyOptions)
_, rc, err = remoteRepo.Blobs().FetchReference(ctx, selectedLayer.Digest.String())
if err != nil {
return nil, fmt.Errorf("failed to pull OCI image: %w", err)
return nil, fmt.Errorf("blob fetch failed: %w", err)
}

o.logger.Printf("Pulled OCI image: %s with manifest descriptor: %v", u.String(), manifestDescriptor.Digest)
return []byte(manifestDescriptor.Digest), nil
defer rc.Close()
buff, err := readLimited(rc, o.limit)
if err != nil {
return nil, fmt.Errorf("blob read failed: %w", err)
}
o.logger.Printf("Read %d bytes from %s", len(buff), specifiedFile)
return buff, nil
}

0 comments on commit 20d69ce

Please sign in to comment.