update vendor

Signed-off-by: Roland.Ma <rolandma@yunify.com>
This commit is contained in:
Roland.Ma
2021-08-11 07:10:14 +00:00
parent a18f72b565
commit ea8f47c73a
2901 changed files with 269317 additions and 43103 deletions

21
vendor/github.com/deislabs/oras/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

View File

@@ -0,0 +1,7 @@
package artifact
const (
// UnknownConfigMediaType is the default mediaType used when no
// config media type is specified.
UnknownConfigMediaType = "application/vnd.unknown.config.v1+json"
)

24
vendor/github.com/deislabs/oras/pkg/auth/client.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
package auth
import (
"context"
"errors"
"net/http"
"github.com/containerd/containerd/remotes"
)
// Common errors
var (
ErrNotLoggedIn = errors.New("not logged in")
)
// Client provides authentication operations for remotes.
type Client interface {
// Login logs in to a remote server identified by the hostname.
Login(ctx context.Context, hostname, username, secret string, insecure bool) error
// Logout logs out from a remote server identified by the hostname.
Logout(ctx context.Context, hostname string) error
// Resolver returns a new authenticated resolver.
Resolver(ctx context.Context, client *http.Client, plainHTTP bool) (remotes.Resolver, error)
}

View File

@@ -0,0 +1,71 @@
package docker
import (
"os"
"github.com/deislabs/oras/pkg/auth"
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/credentials"
"github.com/pkg/errors"
)
// Client provides authentication operations for docker registries.
type Client struct {
configs []*configfile.ConfigFile
}
// NewClient creates a new auth client based on provided config paths.
// If not config path is provided, the default path is used.
// Credentials are read from the first config and fall backs to next.
// All changes will only be written to the first config file.
func NewClient(configPaths ...string) (auth.Client, error) {
var configs []*configfile.ConfigFile
for _, path := range configPaths {
cfg, err := loadConfigFile(path)
if err != nil {
return nil, errors.Wrap(err, path)
}
configs = append(configs, cfg)
}
if len(configs) == 0 {
cfg, err := config.Load(config.Dir())
if err != nil {
return nil, err
}
if !cfg.ContainsAuth() {
cfg.CredentialsStore = credentials.DetectDefaultStore(cfg.CredentialsStore)
}
configs = []*configfile.ConfigFile{cfg}
}
return &Client{
configs: configs,
}, nil
}
func (c *Client) primaryCredentialsStore(hostname string) credentials.Store {
return c.configs[0].GetCredentialsStore(hostname)
}
// loadConfigFile reads the configuration files from the given path.
func loadConfigFile(path string) (*configfile.ConfigFile, error) {
cfg := configfile.New(path)
if _, err := os.Stat(path); err == nil {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
if err := cfg.LoadFromReader(file); err != nil {
return nil, err
}
} else if !os.IsNotExist(err) {
return nil, err
}
if !cfg.ContainsAuth() {
cfg.CredentialsStore = credentials.DetectDefaultStore(cfg.CredentialsStore)
}
return cfg, nil
}

View File

@@ -0,0 +1,45 @@
package docker
import (
"context"
ctypes "github.com/docker/cli/cli/config/types"
"github.com/docker/docker/api/types"
"github.com/docker/docker/registry"
)
// Login logs in to a docker registry identified by the hostname.
func (c *Client) Login(ctx context.Context, hostname, username, secret string, insecure bool) error {
hostname = resolveHostname(hostname)
cred := types.AuthConfig{
Username: username,
ServerAddress: hostname,
}
if username == "" {
cred.IdentityToken = secret
} else {
cred.Password = secret
}
opts := registry.ServiceOptions{}
if insecure {
opts.InsecureRegistries = []string{hostname}
}
// Login to ensure valid credential
remote, err := registry.NewService(opts)
if err != nil {
return err
}
if _, token, err := remote.Auth(ctx, &cred, "oras"); err != nil {
return err
} else if token != "" {
cred.Username = ""
cred.Password = ""
cred.IdentityToken = token
}
// Store credential
return c.primaryCredentialsStore(hostname).Store(ctypes.AuthConfig(cred))
}

View File

@@ -0,0 +1,27 @@
package docker
import (
"context"
"github.com/deislabs/oras/pkg/auth"
"github.com/docker/cli/cli/config/configfile"
)
// Logout logs out from a docker registry identified by the hostname.
func (c *Client) Logout(_ context.Context, hostname string) error {
hostname = resolveHostname(hostname)
var configs []*configfile.ConfigFile
for _, config := range c.configs {
if _, ok := config.AuthConfigs[hostname]; ok {
configs = append(configs, config)
}
}
if len(configs) == 0 {
return auth.ErrNotLoggedIn
}
// Log out form the primary config only as backups are read-only.
return c.primaryCredentialsStore(hostname).Erase(hostname)
}

View File

@@ -0,0 +1,54 @@
package docker
import (
"context"
"net/http"
"github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker"
ctypes "github.com/docker/cli/cli/config/types"
"github.com/docker/docker/registry"
)
// Resolver returns a new authenticated resolver.
func (c *Client) Resolver(_ context.Context, client *http.Client, plainHTTP bool) (remotes.Resolver, error) {
return docker.NewResolver(docker.ResolverOptions{
Credentials: c.Credential,
Client: client,
PlainHTTP: plainHTTP,
}), nil
}
// Credential returns the login credential of the request host.
func (c *Client) Credential(hostname string) (string, string, error) {
hostname = resolveHostname(hostname)
var (
auth ctypes.AuthConfig
err error
)
for _, cfg := range c.configs {
auth, err = cfg.GetAuthConfig(hostname)
if err != nil {
// fall back to next config
continue
}
if auth.IdentityToken != "" {
return "", auth.IdentityToken, nil
}
if auth.Username == "" && auth.Password == "" {
// fall back to next config
continue
}
return auth.Username, auth.Password, nil
}
return "", "", err
}
// resolveHostname resolves Docker specific hostnames
func resolveHostname(hostname string) string {
switch hostname {
case registry.IndexHostname, registry.IndexName, registry.DefaultV2Registry.Host:
return registry.IndexServer
}
return hostname
}

28
vendor/github.com/deislabs/oras/pkg/content/consts.go generated vendored Normal file
View File

@@ -0,0 +1,28 @@
package content
import ocispec "github.com/opencontainers/image-spec/specs-go/v1"
const (
// DefaultBlobMediaType specifies the default blob media type
DefaultBlobMediaType = ocispec.MediaTypeImageLayer
// DefaultBlobDirMediaType specifies the default blob directory media type
DefaultBlobDirMediaType = ocispec.MediaTypeImageLayerGzip
)
const (
// TempFilePattern specifies the pattern to create temporary files
TempFilePattern = "oras"
)
const (
// AnnotationDigest is the annotation key for the digest of the uncompressed content
AnnotationDigest = "io.deis.oras.content.digest"
// AnnotationUnpack is the annotation key for indication of unpacking
AnnotationUnpack = "io.deis.oras.content.unpack"
)
const (
// OCIImageIndexFile is the file name of the index from the OCI Image Layout Specification
// Reference: https://github.com/opencontainers/image-spec/blob/master/image-layout.md#indexjson-file
OCIImageIndexFile = "index.json"
)

17
vendor/github.com/deislabs/oras/pkg/content/errors.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package content
import "errors"
// Common errors
var (
ErrNotFound = errors.New("not_found")
ErrNoName = errors.New("no_name")
ErrUnsupportedSize = errors.New("unsupported_size")
ErrUnsupportedVersion = errors.New("unsupported_version")
)
// FileStore errors
var (
ErrPathTraversalDisallowed = errors.New("path_traversal_disallowed")
ErrOverwriteDisallowed = errors.New("overwrite_disallowed")
)

411
vendor/github.com/deislabs/oras/pkg/content/file.go generated vendored Normal file
View File

@@ -0,0 +1,411 @@
package content
import (
"compress/gzip"
"context"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
// ensure interface
var (
_ ProvideIngester = &FileStore{}
)
// FileStore provides content from the file system
type FileStore struct {
DisableOverwrite bool
AllowPathTraversalOnWrite bool
// Reproducible enables stripping times from added files
Reproducible bool
root string
descriptor *sync.Map // map[digest.Digest]ocispec.Descriptor
pathMap *sync.Map
tmpFiles *sync.Map
}
// NewFileStore creats a new file store
func NewFileStore(rootPath string) *FileStore {
return &FileStore{
root: rootPath,
descriptor: &sync.Map{},
pathMap: &sync.Map{},
tmpFiles: &sync.Map{},
}
}
// Add adds a file reference
func (s *FileStore) Add(name, mediaType, path string) (ocispec.Descriptor, error) {
if path == "" {
path = name
}
path = s.MapPath(name, path)
fileInfo, err := os.Stat(path)
if err != nil {
return ocispec.Descriptor{}, err
}
var desc ocispec.Descriptor
if fileInfo.IsDir() {
desc, err = s.descFromDir(name, mediaType, path)
} else {
desc, err = s.descFromFile(fileInfo, mediaType, path)
}
if err != nil {
return ocispec.Descriptor{}, err
}
if desc.Annotations == nil {
desc.Annotations = make(map[string]string)
}
desc.Annotations[ocispec.AnnotationTitle] = name
s.set(desc)
return desc, nil
}
func (s *FileStore) descFromFile(info os.FileInfo, mediaType, path string) (ocispec.Descriptor, error) {
file, err := os.Open(path)
if err != nil {
return ocispec.Descriptor{}, err
}
defer file.Close()
digest, err := digest.FromReader(file)
if err != nil {
return ocispec.Descriptor{}, err
}
if mediaType == "" {
mediaType = DefaultBlobMediaType
}
return ocispec.Descriptor{
MediaType: mediaType,
Digest: digest,
Size: info.Size(),
}, nil
}
func (s *FileStore) descFromDir(name, mediaType, root string) (ocispec.Descriptor, error) {
// generate temp file
file, err := s.tempFile()
if err != nil {
return ocispec.Descriptor{}, err
}
defer file.Close()
s.MapPath(name, file.Name())
// compress directory
digester := digest.Canonical.Digester()
zw := gzip.NewWriter(io.MultiWriter(file, digester.Hash()))
defer zw.Close()
tarDigester := digest.Canonical.Digester()
if err := tarDirectory(root, name, io.MultiWriter(zw, tarDigester.Hash()), s.Reproducible); err != nil {
return ocispec.Descriptor{}, err
}
// flush all
if err := zw.Close(); err != nil {
return ocispec.Descriptor{}, err
}
if err := file.Sync(); err != nil {
return ocispec.Descriptor{}, err
}
// generate descriptor
if mediaType == "" {
mediaType = DefaultBlobDirMediaType
}
info, err := file.Stat()
if err != nil {
return ocispec.Descriptor{}, err
}
return ocispec.Descriptor{
MediaType: mediaType,
Digest: digester.Digest(),
Size: info.Size(),
Annotations: map[string]string{
AnnotationDigest: tarDigester.Digest().String(),
AnnotationUnpack: "true",
},
}, nil
}
func (s *FileStore) tempFile() (*os.File, error) {
file, err := ioutil.TempFile("", TempFilePattern)
if err != nil {
return nil, err
}
s.tmpFiles.Store(file.Name(), file)
return file, nil
}
// Close frees up resources used by the file store
func (s *FileStore) Close() error {
var errs []string
s.tmpFiles.Range(func(name, _ interface{}) bool {
if err := os.Remove(name.(string)); err != nil {
errs = append(errs, err.Error())
}
return true
})
return errors.New(strings.Join(errs, "; "))
}
// ReaderAt provides contents
func (s *FileStore) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
desc, ok := s.get(desc)
if !ok {
return nil, ErrNotFound
}
name, ok := ResolveName(desc)
if !ok {
return nil, ErrNoName
}
path := s.ResolvePath(name)
file, err := os.Open(path)
if err != nil {
return nil, err
}
return sizeReaderAt{
readAtCloser: file,
size: desc.Size,
}, nil
}
// Writer begins or resumes the active writer identified by desc
func (s *FileStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
var wOpts content.WriterOpts
for _, opt := range opts {
if err := opt(&wOpts); err != nil {
return nil, err
}
}
desc := wOpts.Desc
name, ok := ResolveName(desc)
if !ok {
return nil, ErrNoName
}
path, err := s.resolveWritePath(name)
if err != nil {
return nil, err
}
file, afterCommit, err := s.createWritePath(path, desc, name)
if err != nil {
return nil, err
}
now := time.Now()
return &fileWriter{
store: s,
file: file,
desc: desc,
digester: digest.Canonical.Digester(),
status: content.Status{
Ref: name,
Total: desc.Size,
StartedAt: now,
UpdatedAt: now,
},
afterCommit: afterCommit,
}, nil
}
func (s *FileStore) resolveWritePath(name string) (string, error) {
path := s.ResolvePath(name)
if !s.AllowPathTraversalOnWrite {
base, err := filepath.Abs(s.root)
if err != nil {
return "", err
}
target, err := filepath.Abs(path)
if err != nil {
return "", err
}
rel, err := filepath.Rel(base, target)
if err != nil {
return "", ErrPathTraversalDisallowed
}
rel = filepath.ToSlash(rel)
if strings.HasPrefix(rel, "../") || rel == ".." {
return "", ErrPathTraversalDisallowed
}
}
if s.DisableOverwrite {
if _, err := os.Stat(path); err == nil {
return "", ErrOverwriteDisallowed
} else if !os.IsNotExist(err) {
return "", err
}
}
return path, nil
}
func (s *FileStore) createWritePath(path string, desc ocispec.Descriptor, prefix string) (*os.File, func() error, error) {
if value, ok := desc.Annotations[AnnotationUnpack]; !ok || value != "true" {
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return nil, nil, err
}
file, err := os.Create(path)
return file, nil, err
}
if err := os.MkdirAll(path, 0755); err != nil {
return nil, nil, err
}
file, err := s.tempFile()
checksum := desc.Annotations[AnnotationDigest]
afterCommit := func() error {
return extractTarGzip(path, prefix, file.Name(), checksum)
}
return file, afterCommit, err
}
// MapPath maps name to path
func (s *FileStore) MapPath(name, path string) string {
path = s.resolvePath(path)
s.pathMap.Store(name, path)
return path
}
// ResolvePath returns the path by name
func (s *FileStore) ResolvePath(name string) string {
if value, ok := s.pathMap.Load(name); ok {
if path, ok := value.(string); ok {
return path
}
}
// using the name as a fallback solution
return s.resolvePath(name)
}
func (s *FileStore) resolvePath(path string) string {
if filepath.IsAbs(path) {
return path
}
return filepath.Join(s.root, path)
}
func (s *FileStore) set(desc ocispec.Descriptor) {
s.descriptor.Store(desc.Digest, desc)
}
func (s *FileStore) get(desc ocispec.Descriptor) (ocispec.Descriptor, bool) {
value, ok := s.descriptor.Load(desc.Digest)
if !ok {
return ocispec.Descriptor{}, false
}
desc, ok = value.(ocispec.Descriptor)
return desc, ok
}
type fileWriter struct {
store *FileStore
file *os.File
desc ocispec.Descriptor
digester digest.Digester
status content.Status
afterCommit func() error
}
func (w *fileWriter) Status() (content.Status, error) {
return w.status, nil
}
// Digest returns the current digest of the content, up to the current write.
//
// Cannot be called concurrently with `Write`.
func (w *fileWriter) Digest() digest.Digest {
return w.digester.Digest()
}
// Write p to the transaction.
func (w *fileWriter) Write(p []byte) (n int, err error) {
n, err = w.file.Write(p)
w.digester.Hash().Write(p[:n])
w.status.Offset += int64(len(p))
w.status.UpdatedAt = time.Now()
return n, err
}
func (w *fileWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
var base content.Info
for _, opt := range opts {
if err := opt(&base); err != nil {
return err
}
}
if w.file == nil {
return errors.Wrap(errdefs.ErrFailedPrecondition, "cannot commit on closed writer")
}
file := w.file
w.file = nil
if err := file.Sync(); err != nil {
file.Close()
return errors.Wrap(err, "sync failed")
}
fileInfo, err := file.Stat()
if err != nil {
file.Close()
return errors.Wrap(err, "stat failed")
}
if err := file.Close(); err != nil {
return errors.Wrap(err, "failed to close file")
}
if size > 0 && size != fileInfo.Size() {
return errors.Wrapf(errdefs.ErrFailedPrecondition, "unexpected commit size %d, expected %d", fileInfo.Size(), size)
}
if dgst := w.digester.Digest(); expected != "" && expected != dgst {
return errors.Wrapf(errdefs.ErrFailedPrecondition, "unexpected commit digest %s, expected %s", dgst, expected)
}
w.store.set(w.desc)
if w.afterCommit != nil {
return w.afterCommit()
}
return nil
}
// Close the writer, flushing any unwritten data and leaving the progress in
// tact.
func (w *fileWriter) Close() error {
if w.file == nil {
return nil
}
w.file.Sync()
err := w.file.Close()
w.file = nil
return err
}
func (w *fileWriter) Truncate(size int64) error {
if size != 0 {
return ErrUnsupportedSize
}
w.status.Offset = 0
w.digester.Hash().Reset()
if _, err := w.file.Seek(0, io.SeekStart); err != nil {
return err
}
return w.file.Truncate(0)
}

View File

@@ -0,0 +1,9 @@
package content
import "github.com/containerd/containerd/content"
// ProvideIngester is the interface that groups the basic Read and Write methods.
type ProvideIngester interface {
content.Provider
content.Ingester
}

210
vendor/github.com/deislabs/oras/pkg/content/memory.go generated vendored Normal file
View File

@@ -0,0 +1,210 @@
package content
import (
"bytes"
"context"
"sync"
"time"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
// ensure interface
var (
_ content.Provider = &Memorystore{}
_ content.Ingester = &Memorystore{}
)
// Memorystore provides content from the memory
type Memorystore struct {
descriptor map[digest.Digest]ocispec.Descriptor
content map[digest.Digest][]byte
nameMap map[string]ocispec.Descriptor
lock *sync.Mutex
}
// NewMemoryStore creats a new memory store
func NewMemoryStore() *Memorystore {
return &Memorystore{
descriptor: make(map[digest.Digest]ocispec.Descriptor),
content: make(map[digest.Digest][]byte),
nameMap: make(map[string]ocispec.Descriptor),
lock: &sync.Mutex{},
}
}
// Add adds content
func (s *Memorystore) Add(name, mediaType string, content []byte) ocispec.Descriptor {
var annotations map[string]string
if name != "" {
annotations = map[string]string{
ocispec.AnnotationTitle: name,
}
}
if mediaType == "" {
mediaType = DefaultBlobMediaType
}
desc := ocispec.Descriptor{
MediaType: mediaType,
Digest: digest.FromBytes(content),
Size: int64(len(content)),
Annotations: annotations,
}
s.Set(desc, content)
return desc
}
// ReaderAt provides contents
func (s *Memorystore) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
desc, content, ok := s.Get(desc)
if !ok {
return nil, ErrNotFound
}
return sizeReaderAt{
readAtCloser: nopCloser{
ReaderAt: bytes.NewReader(content),
},
size: desc.Size,
}, nil
}
// Writer begins or resumes the active writer identified by desc
func (s *Memorystore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
var wOpts content.WriterOpts
for _, opt := range opts {
if err := opt(&wOpts); err != nil {
return nil, err
}
}
desc := wOpts.Desc
name, _ := ResolveName(desc)
now := time.Now()
return &memoryWriter{
store: s,
buffer: bytes.NewBuffer(nil),
desc: desc,
digester: digest.Canonical.Digester(),
status: content.Status{
Ref: name,
Total: desc.Size,
StartedAt: now,
UpdatedAt: now,
},
}, nil
}
// Set adds the content to the store
func (s *Memorystore) Set(desc ocispec.Descriptor, content []byte) {
s.lock.Lock()
defer s.lock.Unlock()
s.descriptor[desc.Digest] = desc
s.content[desc.Digest] = content
if name, ok := ResolveName(desc); ok && name != "" {
s.nameMap[name] = desc
}
}
// Get finds the content from the store
func (s *Memorystore) Get(desc ocispec.Descriptor) (ocispec.Descriptor, []byte, bool) {
s.lock.Lock()
defer s.lock.Unlock()
desc, ok := s.descriptor[desc.Digest]
if !ok {
return ocispec.Descriptor{}, nil, false
}
content, ok := s.content[desc.Digest]
return desc, content, ok
}
// GetByName finds the content from the store by name (i.e. AnnotationTitle)
func (s *Memorystore) GetByName(name string) (ocispec.Descriptor, []byte, bool) {
s.lock.Lock()
defer s.lock.Unlock()
desc, ok := s.nameMap[name]
if !ok {
return ocispec.Descriptor{}, nil, false
}
content, ok := s.content[desc.Digest]
return desc, content, ok
}
type memoryWriter struct {
store *Memorystore
buffer *bytes.Buffer
desc ocispec.Descriptor
digester digest.Digester
status content.Status
}
func (w *memoryWriter) Status() (content.Status, error) {
return w.status, nil
}
// Digest returns the current digest of the content, up to the current write.
//
// Cannot be called concurrently with `Write`.
func (w *memoryWriter) Digest() digest.Digest {
return w.digester.Digest()
}
// Write p to the transaction.
func (w *memoryWriter) Write(p []byte) (n int, err error) {
n, err = w.buffer.Write(p)
w.digester.Hash().Write(p[:n])
w.status.Offset += int64(len(p))
w.status.UpdatedAt = time.Now()
return n, err
}
func (w *memoryWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
var base content.Info
for _, opt := range opts {
if err := opt(&base); err != nil {
return err
}
}
if w.buffer == nil {
return errors.Wrap(errdefs.ErrFailedPrecondition, "cannot commit on closed writer")
}
content := w.buffer.Bytes()
w.buffer = nil
if size > 0 && size != int64(len(content)) {
return errors.Wrapf(errdefs.ErrFailedPrecondition, "unexpected commit size %d, expected %d", len(content), size)
}
if dgst := w.digester.Digest(); expected != "" && expected != dgst {
return errors.Wrapf(errdefs.ErrFailedPrecondition, "unexpected commit digest %s, expected %s", dgst, expected)
}
w.store.Set(w.desc, content)
return nil
}
func (w *memoryWriter) Close() error {
w.buffer = nil
return nil
}
func (w *memoryWriter) Truncate(size int64) error {
if size != 0 {
return ErrUnsupportedSize
}
w.status.Offset = 0
w.digester.Hash().Reset()
w.buffer.Truncate(0)
return nil
}

169
vendor/github.com/deislabs/oras/pkg/content/oci.go generated vendored Normal file
View File

@@ -0,0 +1,169 @@
package content
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/content/local"
specs "github.com/opencontainers/image-spec/specs-go"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// OCIStore provides content from the file system with the OCI-Image layout.
// Reference: https://github.com/opencontainers/image-spec/blob/master/image-layout.md
type OCIStore struct {
content.Store
root string
index *ocispec.Index
nameMap map[string]ocispec.Descriptor
}
// NewOCIStore creates a new OCI store
func NewOCIStore(rootPath string) (*OCIStore, error) {
fileStore, err := local.NewStore(rootPath)
if err != nil {
return nil, err
}
store := &OCIStore{
Store: fileStore,
root: rootPath,
}
if err := store.validateOCILayoutFile(); err != nil {
return nil, err
}
if err := store.LoadIndex(); err != nil {
return nil, err
}
return store, nil
}
// LoadIndex reads the index.json from the file system
func (s *OCIStore) LoadIndex() error {
path := filepath.Join(s.root, OCIImageIndexFile)
indexFile, err := os.Open(path)
if err != nil {
if !os.IsNotExist(err) {
return err
}
s.index = &ocispec.Index{
Versioned: specs.Versioned{
SchemaVersion: 2, // historical value
},
}
s.nameMap = make(map[string]ocispec.Descriptor)
return nil
}
defer indexFile.Close()
if err := json.NewDecoder(indexFile).Decode(&s.index); err != nil {
return err
}
s.nameMap = make(map[string]ocispec.Descriptor)
for _, desc := range s.index.Manifests {
if name := desc.Annotations[ocispec.AnnotationRefName]; name != "" {
s.nameMap[name] = desc
}
}
return nil
}
// SaveIndex writes the index.json to the file system
func (s *OCIStore) SaveIndex() error {
indexJSON, err := json.Marshal(s.index)
if err != nil {
return err
}
path := filepath.Join(s.root, OCIImageIndexFile)
return ioutil.WriteFile(path, indexJSON, 0644)
}
// AddReference adds or updates an reference to index.
func (s *OCIStore) AddReference(name string, desc ocispec.Descriptor) {
if desc.Annotations == nil {
desc.Annotations = map[string]string{
ocispec.AnnotationRefName: name,
}
} else {
desc.Annotations[ocispec.AnnotationRefName] = name
}
if _, ok := s.nameMap[name]; ok {
for i, ref := range s.index.Manifests {
if name == ref.Annotations[ocispec.AnnotationRefName] {
s.index.Manifests[i] = desc
return
}
}
// Process should not reach here.
// Fallthrough to `Add` scenario and recover.
}
s.index.Manifests = append(s.index.Manifests, desc)
s.nameMap[name] = desc
return
}
// DeleteReference deletes an reference from index.
func (s *OCIStore) DeleteReference(name string) {
if _, ok := s.nameMap[name]; !ok {
return
}
delete(s.nameMap, name)
for i, desc := range s.index.Manifests {
if name == desc.Annotations[ocispec.AnnotationRefName] {
s.index.Manifests[i] = s.index.Manifests[len(s.index.Manifests)-1]
s.index.Manifests = s.index.Manifests[:len(s.index.Manifests)-1]
return
}
}
}
// ListReferences lists all references in index.
func (s *OCIStore) ListReferences() map[string]ocispec.Descriptor {
return s.nameMap
}
// validateOCILayoutFile ensures the `oci-layout` file
func (s *OCIStore) validateOCILayoutFile() error {
layoutFilePath := filepath.Join(s.root, ocispec.ImageLayoutFile)
layoutFile, err := os.Open(layoutFilePath)
if err != nil {
if !os.IsNotExist(err) {
return err
}
layout := ocispec.ImageLayout{
Version: ocispec.ImageLayoutVersion,
}
layoutJSON, err := json.Marshal(layout)
if err != nil {
return err
}
return ioutil.WriteFile(layoutFilePath, layoutJSON, 0644)
}
defer layoutFile.Close()
var layout *ocispec.ImageLayout
err = json.NewDecoder(layoutFile).Decode(&layout)
if err != nil {
return err
}
if layout.Version != ocispec.ImageLayoutVersion {
return ErrUnsupportedVersion
}
return nil
}

View File

@@ -0,0 +1,34 @@
package content
import (
"io"
"github.com/containerd/containerd/content"
)
// ensure interface
var (
_ content.ReaderAt = sizeReaderAt{}
)
type readAtCloser interface {
io.ReaderAt
io.Closer
}
type sizeReaderAt struct {
readAtCloser
size int64
}
func (ra sizeReaderAt) Size() int64 {
return ra.size
}
type nopCloser struct {
io.ReaderAt
}
func (nopCloser) Close() error {
return nil
}

171
vendor/github.com/deislabs/oras/pkg/content/utils.go generated vendored Normal file
View File

@@ -0,0 +1,171 @@
package content
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
// ResolveName resolves name from descriptor
func ResolveName(desc ocispec.Descriptor) (string, bool) {
name, ok := desc.Annotations[ocispec.AnnotationTitle]
return name, ok
}
// tarDirectory walks the directory specified by path, and tar those files with a new
// path prefix.
func tarDirectory(root, prefix string, w io.Writer, stripTimes bool) error {
tw := tar.NewWriter(w)
defer tw.Close()
if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// Rename path
name, err := filepath.Rel(root, path)
if err != nil {
return err
}
name = filepath.Join(prefix, name)
name = filepath.ToSlash(name)
// Generate header
var link string
mode := info.Mode()
if mode&os.ModeSymlink != 0 {
if link, err = os.Readlink(path); err != nil {
return err
}
}
header, err := tar.FileInfoHeader(info, link)
if err != nil {
return errors.Wrap(err, path)
}
header.Name = name
header.Uid = 0
header.Gid = 0
header.Uname = ""
header.Gname = ""
if stripTimes {
header.ModTime = time.Time{}
header.AccessTime = time.Time{}
header.ChangeTime = time.Time{}
}
// Write file
if err := tw.WriteHeader(header); err != nil {
return errors.Wrap(err, "tar")
}
if mode.IsRegular() {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
if _, err := io.Copy(tw, file); err != nil {
return errors.Wrap(err, path)
}
}
return nil
}); err != nil {
return err
}
return nil
}
// extractTarDirectory extracts tar file to a directory specified by the `root`
// parameter. The file name prefix is ensured to be the string specified by the
// `prefix` parameter and is trimmed.
func extractTarDirectory(root, prefix string, r io.Reader) error {
tr := tar.NewReader(r)
for {
header, err := tr.Next()
if err != nil {
if err == io.EOF {
return nil
}
return err
}
// Name check
name := header.Name
path, err := filepath.Rel(prefix, name)
if err != nil {
return err
}
if strings.HasPrefix(path, "../") {
return fmt.Errorf("%q does not have prefix %q", name, prefix)
}
path = filepath.Join(root, path)
// Create content
switch header.Typeflag {
case tar.TypeReg:
err = writeFile(path, tr, header.FileInfo().Mode())
case tar.TypeDir:
err = os.MkdirAll(path, header.FileInfo().Mode())
case tar.TypeLink:
err = os.Link(header.Linkname, path)
case tar.TypeSymlink:
err = os.Symlink(header.Linkname, path)
default:
continue // Non-regular files are skipped
}
if err != nil {
return err
}
// Change access time and modification time if possible (error ignored)
os.Chtimes(path, header.AccessTime, header.ModTime)
}
}
func writeFile(path string, r io.Reader, perm os.FileMode) error {
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, r)
return err
}
func extractTarGzip(root, prefix, filename, checksum string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
zr, err := gzip.NewReader(file)
if err != nil {
return err
}
defer zr.Close()
var r io.Reader = zr
var verifier digest.Verifier
if checksum != "" {
if digest, err := digest.Parse(checksum); err == nil {
verifier = digest.Verifier()
r = io.TeeReader(r, verifier)
}
}
if err := extractTarDirectory(root, prefix, r); err != nil {
return err
}
if verifier != nil && !verifier.Verified() {
return errors.New("content digest mismatch")
}
return nil
}

View File

@@ -0,0 +1,9 @@
package context
import "context"
// Background returns a default context with logger discarded.
func Background() context.Context {
ctx := context.Background()
return WithLoggerDiscarded(ctx)
}

35
vendor/github.com/deislabs/oras/pkg/context/logger.go generated vendored Normal file
View File

@@ -0,0 +1,35 @@
package context
import (
"context"
"io"
"io/ioutil"
"github.com/containerd/containerd/log"
"github.com/sirupsen/logrus"
)
// WithLogger returns a new context with the provided logger.
// This method wraps github.com/containerd/containerd/log.WithLogger()
func WithLogger(ctx context.Context, logger *logrus.Entry) context.Context {
return log.WithLogger(ctx, logger)
}
// WithLoggerFromWriter returns a new context with the logger, writting to the provided logger.
func WithLoggerFromWriter(ctx context.Context, writer io.Writer) context.Context {
logger := logrus.New()
logger.Out = writer
entry := logrus.NewEntry(logger)
return WithLogger(ctx, entry)
}
// WithLoggerDiscarded returns a new context with the logger, writting to nothing.
func WithLoggerDiscarded(ctx context.Context) context.Context {
return WithLoggerFromWriter(ctx, ioutil.Discard)
}
// GetLogger retrieves the current logger from the context.
// This method wraps github.com/containerd/containerd/log.GetLogger()
func GetLogger(ctx context.Context) *logrus.Entry {
return log.GetLogger(ctx)
}

24
vendor/github.com/deislabs/oras/pkg/oras/errors.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
package oras
import (
"errors"
"fmt"
)
// Common errors
var (
ErrResolverUndefined = errors.New("resolver undefined")
ErrEmptyDescriptors = errors.New("empty descriptors")
)
// Path validation related errors
var (
ErrDirtyPath = errors.New("dirty path")
ErrPathNotSlashSeparated = errors.New("path not slash separated")
ErrAbsolutePathDisallowed = errors.New("absolute path disallowed")
ErrPathTraversalDisallowed = errors.New("path traversal disallowed")
)
// ErrStopProcessing is used to stop processing an oras operation.
// This error only makes sense in sequential pulling operation.
var ErrStopProcessing = fmt.Errorf("stop processing")

135
vendor/github.com/deislabs/oras/pkg/oras/pull.go generated vendored Normal file
View File

@@ -0,0 +1,135 @@
package oras
import (
"context"
"sync"
orascontent "github.com/deislabs/oras/pkg/content"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/remotes"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/sync/semaphore"
)
// Pull pull files from the remote
func Pull(ctx context.Context, resolver remotes.Resolver, ref string, ingester content.Ingester, opts ...PullOpt) (ocispec.Descriptor, []ocispec.Descriptor, error) {
if resolver == nil {
return ocispec.Descriptor{}, nil, ErrResolverUndefined
}
opt := pullOptsDefaults()
for _, o := range opts {
if err := o(opt); err != nil {
return ocispec.Descriptor{}, nil, err
}
}
_, desc, err := resolver.Resolve(ctx, ref)
if err != nil {
return ocispec.Descriptor{}, nil, err
}
fetcher, err := resolver.Fetcher(ctx, ref)
if err != nil {
return ocispec.Descriptor{}, nil, err
}
layers, err := fetchContent(ctx, fetcher, desc, ingester, opt)
if err != nil {
return ocispec.Descriptor{}, nil, err
}
return desc, layers, nil
}
func fetchContent(ctx context.Context, fetcher remotes.Fetcher, desc ocispec.Descriptor, ingester content.Ingester, opts *pullOpts) ([]ocispec.Descriptor, error) {
var descriptors []ocispec.Descriptor
lock := &sync.Mutex{}
picker := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
if isAllowedMediaType(desc.MediaType, opts.allowedMediaTypes...) {
if opts.filterName(desc) {
lock.Lock()
defer lock.Unlock()
descriptors = append(descriptors, desc)
}
return nil, nil
}
return nil, nil
})
store := opts.contentProvideIngester
if store == nil {
store = newHybridStoreFromIngester(ingester)
}
handlers := []images.Handler{
filterHandler(opts, opts.allowedMediaTypes...),
}
handlers = append(handlers, opts.baseHandlers...)
handlers = append(handlers,
remotes.FetchHandler(store, fetcher),
picker,
images.ChildrenHandler(store),
)
handlers = append(handlers, opts.callbackHandlers...)
if err := opts.dispatch(ctx, images.Handlers(handlers...), nil, desc); err != nil {
return nil, err
}
return descriptors, nil
}
func filterHandler(opts *pullOpts, allowedMediaTypes ...string) images.HandlerFunc {
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
switch {
case isAllowedMediaType(desc.MediaType, ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex):
return nil, nil
case isAllowedMediaType(desc.MediaType, allowedMediaTypes...):
if opts.filterName(desc) {
return nil, nil
}
log.G(ctx).Warnf("blob no name: %v", desc.Digest)
default:
log.G(ctx).Warnf("unknown type: %v", desc.MediaType)
}
return nil, images.ErrStopHandler
}
}
func isAllowedMediaType(mediaType string, allowedMediaTypes ...string) bool {
if len(allowedMediaTypes) == 0 {
return true
}
for _, allowedMediaType := range allowedMediaTypes {
if mediaType == allowedMediaType {
return true
}
}
return false
}
// dispatchBFS behaves the same as images.Dispatch() but in sequence with breath-first search.
func dispatchBFS(ctx context.Context, handler images.Handler, weighted *semaphore.Weighted, descs ...ocispec.Descriptor) error {
for i := 0; i < len(descs); i++ {
desc := descs[i]
children, err := handler.Handle(ctx, desc)
if err != nil {
switch err := errors.Cause(err); err {
case images.ErrSkipDesc:
continue // don't traverse the children.
case ErrStopProcessing:
return nil
}
return err
}
descs = append(descs, children...)
}
return nil
}
func filterName(desc ocispec.Descriptor) bool {
name, ok := orascontent.ResolveName(desc)
return ok && len(name) > 0
}

89
vendor/github.com/deislabs/oras/pkg/oras/pull_opts.go generated vendored Normal file
View File

@@ -0,0 +1,89 @@
package oras
import (
"context"
orascontent "github.com/deislabs/oras/pkg/content"
"github.com/containerd/containerd/images"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/sync/semaphore"
)
type pullOpts struct {
allowedMediaTypes []string
dispatch func(context.Context, images.Handler, *semaphore.Weighted, ...ocispec.Descriptor) error
baseHandlers []images.Handler
callbackHandlers []images.Handler
contentProvideIngester orascontent.ProvideIngester
filterName func(ocispec.Descriptor) bool
}
// PullOpt allows callers to set options on the oras pull
type PullOpt func(o *pullOpts) error
func pullOptsDefaults() *pullOpts {
return &pullOpts{
dispatch: images.Dispatch,
filterName: filterName,
}
}
// WithAllowedMediaType sets the allowed media types
func WithAllowedMediaType(allowedMediaTypes ...string) PullOpt {
return func(o *pullOpts) error {
o.allowedMediaTypes = append(o.allowedMediaTypes, allowedMediaTypes...)
return nil
}
}
// WithAllowedMediaTypes sets the allowed media types
func WithAllowedMediaTypes(allowedMediaTypes []string) PullOpt {
return func(o *pullOpts) error {
o.allowedMediaTypes = append(o.allowedMediaTypes, allowedMediaTypes...)
return nil
}
}
// WithPullByBFS opt to pull in sequence with breath-first search
func WithPullByBFS(o *pullOpts) error {
o.dispatch = dispatchBFS
return nil
}
// WithPullBaseHandler provides base handlers, which will be called before
// any pull specific handlers.
func WithPullBaseHandler(handlers ...images.Handler) PullOpt {
return func(o *pullOpts) error {
o.baseHandlers = append(o.baseHandlers, handlers...)
return nil
}
}
// WithPullCallbackHandler provides callback handlers, which will be called after
// any pull specific handlers.
func WithPullCallbackHandler(handlers ...images.Handler) PullOpt {
return func(o *pullOpts) error {
o.callbackHandlers = append(o.callbackHandlers, handlers...)
return nil
}
}
// WithContentProvideIngester opt to the provided Provider and Ingester
// for file system I/O, including caches.
func WithContentProvideIngester(store orascontent.ProvideIngester) PullOpt {
return func(o *pullOpts) error {
o.contentProvideIngester = store
return nil
}
}
// WithPullEmptyNameAllowed allows pulling blobs with empty name.
func WithPullEmptyNameAllowed() PullOpt {
return func(o *pullOpts) error {
o.filterName = func(ocispec.Descriptor) bool {
return true
}
return nil
}
}

110
vendor/github.com/deislabs/oras/pkg/oras/push.go generated vendored Normal file
View File

@@ -0,0 +1,110 @@
package oras
import (
"context"
"encoding/json"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/remotes"
artifact "github.com/deislabs/oras/pkg/artifact"
digest "github.com/opencontainers/go-digest"
specs "github.com/opencontainers/image-spec/specs-go"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// Push pushes files to the remote
func Push(ctx context.Context, resolver remotes.Resolver, ref string, provider content.Provider, descriptors []ocispec.Descriptor, opts ...PushOpt) (ocispec.Descriptor, error) {
if resolver == nil {
return ocispec.Descriptor{}, ErrResolverUndefined
}
if len(descriptors) == 0 {
return ocispec.Descriptor{}, ErrEmptyDescriptors
}
opt := pushOptsDefaults()
for _, o := range opts {
if err := o(opt); err != nil {
return ocispec.Descriptor{}, err
}
}
if opt.validateName != nil {
for _, desc := range descriptors {
if err := opt.validateName(desc); err != nil {
return ocispec.Descriptor{}, err
}
}
}
pusher, err := resolver.Pusher(ctx, ref)
if err != nil {
return ocispec.Descriptor{}, err
}
desc, store, err := pack(provider, descriptors, opt)
if err != nil {
return ocispec.Descriptor{}, err
}
var wrapper func(images.Handler) images.Handler
if len(opt.baseHandlers) > 0 {
wrapper = func(h images.Handler) images.Handler {
return images.Handlers(append(opt.baseHandlers, h)...)
}
}
if err := remotes.PushContent(ctx, pusher, desc, store, nil, wrapper); err != nil {
return ocispec.Descriptor{}, err
}
return desc, nil
}
//func pack(store *hybridStore, descriptors []ocispec.Descriptor, opts *pushOpts) (ocispec.Descriptor, error) {
func pack(provider content.Provider, descriptors []ocispec.Descriptor, opts *pushOpts) (ocispec.Descriptor, content.Store, error) {
store := newHybridStoreFromProvider(provider)
// Config
var config ocispec.Descriptor
if opts.config == nil {
configBytes := []byte("{}")
config = ocispec.Descriptor{
MediaType: artifact.UnknownConfigMediaType,
Digest: digest.FromBytes(configBytes),
Size: int64(len(configBytes)),
}
store.Set(config, configBytes)
} else {
config = *opts.config
}
if opts.configAnnotations != nil {
config.Annotations = opts.configAnnotations
}
if opts.configMediaType != "" {
config.MediaType = opts.configMediaType
}
// Manifest
if opts.manifest != nil {
return *opts.manifest, store, nil
}
manifest := ocispec.Manifest{
Versioned: specs.Versioned{
SchemaVersion: 2, // historical value. does not pertain to OCI or docker version
},
Config: config,
Layers: descriptors,
Annotations: opts.manifestAnnotations,
}
manifestBytes, err := json.Marshal(manifest)
if err != nil {
return ocispec.Descriptor{}, nil, err
}
manifestDescriptor := ocispec.Descriptor{
MediaType: ocispec.MediaTypeImageManifest,
Digest: digest.FromBytes(manifestBytes),
Size: int64(len(manifestBytes)),
}
store.Set(manifestDescriptor, manifestBytes)
return manifestDescriptor, store, nil
}

129
vendor/github.com/deislabs/oras/pkg/oras/push_opts.go generated vendored Normal file
View File

@@ -0,0 +1,129 @@
package oras
import (
"path/filepath"
"strings"
"github.com/containerd/containerd/images"
orascontent "github.com/deislabs/oras/pkg/content"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
type pushOpts struct {
config *ocispec.Descriptor
configMediaType string
configAnnotations map[string]string
manifest *ocispec.Descriptor
manifestAnnotations map[string]string
validateName func(desc ocispec.Descriptor) error
baseHandlers []images.Handler
}
func pushOptsDefaults() *pushOpts {
return &pushOpts{
validateName: ValidateNameAsPath,
}
}
// PushOpt allows callers to set options on the oras push
type PushOpt func(o *pushOpts) error
// WithConfig overrides the config - setting this will ignore WithConfigMediaType and WithConfigAnnotations
func WithConfig(config ocispec.Descriptor) PushOpt {
return func(o *pushOpts) error {
o.config = &config
return nil
}
}
// WithConfigMediaType overrides the config media type
func WithConfigMediaType(mediaType string) PushOpt {
return func(o *pushOpts) error {
o.configMediaType = mediaType
return nil
}
}
// WithConfigAnnotations overrides the config annotations
func WithConfigAnnotations(annotations map[string]string) PushOpt {
return func(o *pushOpts) error {
o.configAnnotations = annotations
return nil
}
}
// WithManifest overrides the manifest - setting this will ignore WithManifestConfigAnnotations
func WithManifest(manifest ocispec.Descriptor) PushOpt {
return func(o *pushOpts) error {
o.manifest = &manifest
return nil
}
}
// WithManifestAnnotations overrides the manifest annotations
func WithManifestAnnotations(annotations map[string]string) PushOpt {
return func(o *pushOpts) error {
o.manifestAnnotations = annotations
return nil
}
}
// WithNameValidation validates the image title in the descriptor.
// Pass nil to disable name validation.
func WithNameValidation(validate func(desc ocispec.Descriptor) error) PushOpt {
return func(o *pushOpts) error {
o.validateName = validate
return nil
}
}
// ValidateNameAsPath validates name in the descriptor as file path in order
// to generate good packages intended to be pulled using the FileStore or
// the oras cli.
// For cross-platform considerations, only unix paths are accepted.
func ValidateNameAsPath(desc ocispec.Descriptor) error {
// no empty name
path, ok := orascontent.ResolveName(desc)
if !ok || path == "" {
return orascontent.ErrNoName
}
// path should be clean
if target := filepath.ToSlash(filepath.Clean(path)); target != path {
return errors.Wrap(ErrDirtyPath, path)
}
// path should be slash-separated
if strings.Contains(path, "\\") {
return errors.Wrap(ErrPathNotSlashSeparated, path)
}
// disallow absolute path: covers unix and windows format
if strings.HasPrefix(path, "/") {
return errors.Wrap(ErrAbsolutePathDisallowed, path)
}
if len(path) > 2 {
c := path[0]
if path[1] == ':' && path[2] == '/' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
return errors.Wrap(ErrAbsolutePathDisallowed, path)
}
}
// disallow path traversal
if strings.HasPrefix(path, "../") || path == ".." {
return errors.Wrap(ErrPathTraversalDisallowed, path)
}
return nil
}
// WithPushBaseHandler provides base handlers, which will be called before
// any push specific handlers.
func WithPushBaseHandler(handlers ...images.Handler) PushOpt {
return func(o *pushOpts) error {
o.baseHandlers = append(o.baseHandlers, handlers...)
return nil
}
}

119
vendor/github.com/deislabs/oras/pkg/oras/store.go generated vendored Normal file
View File

@@ -0,0 +1,119 @@
package oras
import (
"context"
"errors"
orascontent "github.com/deislabs/oras/pkg/content"
"github.com/containerd/containerd/content"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ensure interface
var (
_ content.Store = &hybridStore{}
)
type hybridStore struct {
cache *orascontent.Memorystore
provider content.Provider
ingester content.Ingester
}
func newHybridStoreFromProvider(provider content.Provider) *hybridStore {
return &hybridStore{
cache: orascontent.NewMemoryStore(),
provider: provider,
}
}
func newHybridStoreFromIngester(ingester content.Ingester) *hybridStore {
return &hybridStore{
cache: orascontent.NewMemoryStore(),
ingester: ingester,
}
}
func (s *hybridStore) Set(desc ocispec.Descriptor, content []byte) {
s.cache.Set(desc, content)
}
// ReaderAt provides contents
func (s *hybridStore) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
readerAt, err := s.cache.ReaderAt(ctx, desc)
if err == nil {
return readerAt, nil
}
if s.provider != nil {
return s.provider.ReaderAt(ctx, desc)
}
return nil, err
}
// Writer begins or resumes the active writer identified by desc
func (s *hybridStore) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
var wOpts content.WriterOpts
for _, opt := range opts {
if err := opt(&wOpts); err != nil {
return nil, err
}
}
if isAllowedMediaType(wOpts.Desc.MediaType, ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex) || s.ingester == nil {
return s.cache.Writer(ctx, opts...)
}
return s.ingester.Writer(ctx, opts...)
}
// TODO: implement (needed to create a content.Store)
// TODO: do not return empty content.Info
// Abort completely cancels the ingest operation targeted by ref.
func (s *hybridStore) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
return content.Info{}, nil
}
// TODO: implement (needed to create a content.Store)
// Update updates mutable information related to content.
// If one or more fieldpaths are provided, only those
// fields will be updated.
// Mutable fields:
// labels.*
func (s *hybridStore) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
return content.Info{}, errors.New("not yet implemented: Update (content.Store interface)")
}
// TODO: implement (needed to create a content.Store)
// Walk will call fn for each item in the content store which
// match the provided filters. If no filters are given all
// items will be walked.
func (s *hybridStore) Walk(ctx context.Context, fn content.WalkFunc, filters ...string) error {
return errors.New("not yet implemented: Walk (content.Store interface)")
}
// TODO: implement (needed to create a content.Store)
// Delete removes the content from the store.
func (s *hybridStore) Delete(ctx context.Context, dgst digest.Digest) error {
return errors.New("not yet implemented: Delete (content.Store interface)")
}
// TODO: implement (needed to create a content.Store)
func (s *hybridStore) Status(ctx context.Context, ref string) (content.Status, error) {
// Status returns the status of the provided ref.
return content.Status{}, errors.New("not yet implemented: Status (content.Store interface)")
}
// TODO: implement (needed to create a content.Store)
// ListStatuses returns the status of any active ingestions whose ref match the
// provided regular expression. If empty, all active ingestions will be
// returned.
func (s *hybridStore) ListStatuses(ctx context.Context, filters ...string) ([]content.Status, error) {
return []content.Status{}, errors.New("not yet implemented: ListStatuses (content.Store interface)")
}
// TODO: implement (needed to create a content.Store)
// Abort completely cancels the ingest operation targeted by ref.
func (s *hybridStore) Abort(ctx context.Context, ref string) error {
return errors.New("not yet implemented: Abort (content.Store interface)")
}