Skip to content

Commit

Permalink
Migrate ORAS Go library from v1.2.2 to v2
Browse files Browse the repository at this point in the history
This change migrates the ORAS Go library from v1.2.2 to v2.
The OCI downloader which uses this lib was updated as per
the new API changes in the library.

The v1.2.2 of the ORAS library had a dependency on the docker package.
The library used a version of that package that had some
reported vulnerabilities such as CVE-2022-41716, CVE-2022-41720.

The ORAS Go library v2 removes the dependency on the docker package.

Signed-off-by: Ashutosh Narkar <anarkar4387@gmail.com>
(cherry picked from commit 83b1614)
  • Loading branch information
ashutosh-narkar committed Feb 24, 2023
1 parent cbf6fab commit 6e2facf
Show file tree
Hide file tree
Showing 329 changed files with 6,421 additions and 35,815 deletions.
123 changes: 90 additions & 33 deletions download/oci_dowload.go → download/oci_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"context"
"crypto/tls"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"math/rand"
"net/http"
"net/url"
Expand All @@ -14,10 +16,14 @@ import (
"sync"
"time"

"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/pkg/content"
"oras.land/oras-go/pkg/oras"
"oras.land/oras-go/v2"
oraslib "oras.land/oras-go/v2"
"oras.land/oras-go/v2/content/oci"

"github.com/open-policy-agent/opa/bundle"
"github.com/open-policy-agent/opa/logging"
Expand All @@ -42,13 +48,13 @@ type OCIDownloader struct {
mtx sync.Mutex
stopped bool
persist bool
store *content.OCI
store *oci.Store
etag string
}

// New returns a new Downloader that can be started.
func NewOCI(config Config, client rest.Client, path, storePath string) *OCIDownloader {
localstore, err := content.NewOCI(storePath)
localstore, err := oci.New(storePath)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -232,19 +238,20 @@ func (d *OCIDownloader) download(ctx context.Context, m metrics.Metrics) (*downl
d.client = d.client.WithHeader("Prefer", preferValue)

m.Timer(metrics.BundleRequest).Start()
_, layers, err := d.pull(ctx, d.path)
desc, err := d.pull(ctx, d.path)
if err != nil {
return &downloaderResponse{}, fmt.Errorf("failed to pull %s: %w", d.path, err)
}
//currently it has 3 as it has the manifest, tar and config layers
if len(layers) != 3 {
return nil, fmt.Errorf("expected 3 layers only")

manifest, err := manifestFromDesc(ctx, d.store, desc)
if err != nil {
return nil, err
}

tarballDescriptor := ocispec.Descriptor{}
for i := range layers {
if layers[i].MediaType == "application/vnd.oci.image.layer.v1.tar+gzip" {
tarballDescriptor = layers[i]
for _, descriptor := range manifest.Layers {
if descriptor.MediaType == "application/vnd.oci.image.layer.v1.tar+gzip" {
tarballDescriptor = descriptor
break
}
}
Expand Down Expand Up @@ -286,39 +293,25 @@ func (d *OCIDownloader) download(ctx context.Context, m metrics.Metrics) (*downl
}, nil
}

func (d *OCIDownloader) pull(ctx context.Context, ref string) (*ocispec.Descriptor, []ocispec.Descriptor, error) {
func (d *OCIDownloader) pull(ctx context.Context, ref string) (*ocispec.Descriptor, error) {
authHeader := make(http.Header)
client, err := d.getHTTPClient(&authHeader)
if err != nil {
return nil, nil, err
return nil, err
}
urlInfo, err := url.Parse(d.client.Config().URL)
if err != nil {
return nil, nil, fmt.Errorf("invalid host url %s: %w", d.client.Config().URL, err)
return nil, fmt.Errorf("invalid host url %s: %w", d.client.Config().URL, err)
}
resolver := docker.NewResolver(docker.ResolverOptions{
Hosts: d.getResolverHost(client, urlInfo),
Headers: authHeader,
})

allowedMediaTypes := []string{
"application/vnd.oci.image.manifest.v1+json",
"application/octet-stream",
"application/vnd.oci.image.config.v1+json",
"application/vnd.oci.image.layer.v1.tar+gzip",
}
var layers []ocispec.Descriptor
opts := []oras.CopyOpt{
oras.WithAllowedMediaTypes(allowedMediaTypes),
oras.WithAdditionalCachedMediaTypes(allowedMediaTypes...),
oras.WithLayerDescriptors(func(d []ocispec.Descriptor) { layers = d }),
}
manifestDescriptor, err := oras.Copy(ctx, resolver, ref, d.store, "", opts...)
target := newRemoteManager(d.getResolverHost(client, urlInfo), authHeader, ref)

manifestDescriptor, err := oraslib.Copy(ctx, target, ref, d.store, "", oraslib.DefaultCopyOptions)
if err != nil {
return nil, nil, fmt.Errorf("download for '%s' failed: %w", ref, err)
return nil, fmt.Errorf("download for '%s' failed: %w", ref, err)
}

return &manifestDescriptor, layers, nil
return &manifestDescriptor, nil
}

func (d *OCIDownloader) getResolverHost(client *http.Client, urlInfo *url.URL) docker.RegistryHosts {
Expand Down Expand Up @@ -382,3 +375,67 @@ func (d *OCIDownloader) getHTTPClient(authHeader *http.Header) (*http.Client, er
}
return client, nil
}

func manifestFromDesc(ctx context.Context, target oras.Target, desc *ocispec.Descriptor) (*ocispec.Manifest, error) {
var manifest ocispec.Manifest

descReader, err := target.Fetch(ctx, *desc)
if err != nil {
return nil, fmt.Errorf("unable to fetch descriptor with digest %q: %w", desc.Digest, err)
}
defer descReader.Close()

descBytes, err := io.ReadAll(descReader)
if err != nil {
return nil, fmt.Errorf("unable to read bytes from descriptor: %w", err)
}

if err = json.Unmarshal(descBytes, &manifest); err != nil {
return nil, fmt.Errorf("unable to unmarshal manifest: %w", err)
}

if len(manifest.Layers) < 1 {
return nil, fmt.Errorf("no layers in manifest")
}

return &manifest, nil
}

type remoteManager struct {
resolver remotes.Resolver
srcRef string
}

func newRemoteManager(hosts docker.RegistryHosts, headers http.Header, srcRef string) *remoteManager {
resolver := docker.NewResolver(docker.ResolverOptions{
Hosts: hosts,
Headers: headers,
})

return &remoteManager{resolver: resolver, srcRef: srcRef}
}

func (r *remoteManager) Resolve(ctx context.Context, ref string) (ocispec.Descriptor, error) {
_, desc, err := r.resolver.Resolve(ctx, ref)
if err != nil {
return ocispec.Descriptor{}, err
}
return desc, nil
}

func (r *remoteManager) Fetch(ctx context.Context, target ocispec.Descriptor) (io.ReadCloser, error) {
fetcher, err := r.resolver.Fetcher(ctx, r.srcRef)
if err != nil {
return nil, err
}
return fetcher.Fetch(ctx, target)
}

func (r *remoteManager) Exists(ctx context.Context, target ocispec.Descriptor) (bool, error) {
_, err := r.Fetch(ctx, target)
if err == nil {
return true, nil
}

return !errdefs.IsNotFound(err), err
}
12 changes: 1 addition & 11 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@ require (
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
google.golang.org/grpc v1.52.3
gopkg.in/yaml.v2 v2.4.0
oras.land/oras-go v1.2.2
oras.land/oras-go/v2 v2.0.0
)

require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
Expand All @@ -55,13 +54,6 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/docker/cli v20.10.21+incompatible // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v20.10.21+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
Expand All @@ -78,8 +70,6 @@ require (
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/miekg/dns v1.1.43 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
Expand Down

0 comments on commit 6e2facf

Please sign in to comment.