...

Source file src/sigs.k8s.io/kustomize/api/internal/localizer/locloader.go

Documentation: sigs.k8s.io/kustomize/api/internal/localizer

     1  // Copyright 2022 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package localizer
     5  
     6  import (
     7  	"path/filepath"
     8  
     9  	"sigs.k8s.io/kustomize/api/ifc"
    10  	"sigs.k8s.io/kustomize/api/internal/git"
    11  	"sigs.k8s.io/kustomize/api/internal/loader"
    12  	"sigs.k8s.io/kustomize/kyaml/errors"
    13  	"sigs.k8s.io/kustomize/kyaml/filesys"
    14  )
    15  
    16  // Args holds localize arguments
    17  type Args struct {
    18  	// target; local copy if remote
    19  	Target filesys.ConfirmedDir
    20  
    21  	// directory that bounds target's local references
    22  	// repo directory of local copy if target is remote
    23  	Scope filesys.ConfirmedDir
    24  
    25  	// localize destination
    26  	NewDir filesys.ConfirmedDir
    27  }
    28  
    29  // Loader is an ifc.Loader that enforces additional constraints specific to kustomize localize.
    30  type Loader struct {
    31  	fSys filesys.FileSystem
    32  
    33  	args *Args
    34  
    35  	// loader at Loader's current directory
    36  	ifc.Loader
    37  
    38  	// whether Loader and all its ancestors are the result of local references
    39  	local bool
    40  }
    41  
    42  var _ ifc.Loader = &Loader{}
    43  
    44  // NewLoader is the factory method for Loader, under localize constraints, at rawTarget. For invalid localize arguments,
    45  // NewLoader returns an error.
    46  func NewLoader(rawTarget string, rawScope string, rawNewDir string, fSys filesys.FileSystem) (*Loader, Args, error) {
    47  	// check earlier to avoid cleanup
    48  	repoSpec, err := git.NewRepoSpecFromURL(rawTarget)
    49  	if err == nil && repoSpec.Ref == "" {
    50  		return nil, Args{}, errors.Errorf("localize remote root %q missing ref query string parameter", rawTarget)
    51  	}
    52  
    53  	// for security, should enforce load restrictions
    54  	ldr, err := loader.NewLoader(loader.RestrictionRootOnly, rawTarget, fSys)
    55  	if err != nil {
    56  		return nil, Args{}, errors.WrapPrefixf(err, "unable to establish localize target %q", rawTarget)
    57  	}
    58  
    59  	scope, err := establishScope(rawScope, rawTarget, ldr, fSys)
    60  	if err != nil {
    61  		_ = ldr.Cleanup()
    62  		return nil, Args{}, errors.WrapPrefixf(err, "invalid localize scope %q", rawScope)
    63  	}
    64  
    65  	newDir, err := createNewDir(rawNewDir, ldr, repoSpec, fSys)
    66  	if err != nil {
    67  		_ = ldr.Cleanup()
    68  		return nil, Args{}, errors.WrapPrefixf(err, "invalid localize destination %q", rawNewDir)
    69  	}
    70  
    71  	args := Args{
    72  		Target: filesys.ConfirmedDir(ldr.Root()),
    73  		Scope:  scope,
    74  		NewDir: newDir,
    75  	}
    76  	return &Loader{
    77  		fSys:   fSys,
    78  		args:   &args,
    79  		Loader: ldr,
    80  		local:  scope != "",
    81  	}, args, nil
    82  }
    83  
    84  // Load returns the contents of path if path is a valid localize file.
    85  // Otherwise, Load returns an error.
    86  func (ll *Loader) Load(path string) ([]byte, error) {
    87  	// checks in root, and thus in scope
    88  	content, err := ll.Loader.Load(path)
    89  	if err != nil {
    90  		return nil, errors.WrapPrefixf(err, "invalid file reference")
    91  	}
    92  	if filepath.IsAbs(path) {
    93  		return nil, errors.Errorf("absolute paths not yet supported in alpha: file path %q is absolute", path)
    94  	}
    95  	if !loader.IsRemoteFile(path) && ll.local {
    96  		cleanPath := cleanFilePath(ll.fSys, filesys.ConfirmedDir(ll.Root()), path)
    97  		cleanAbs := filepath.Join(ll.Root(), cleanPath)
    98  		dir := filesys.ConfirmedDir(filepath.Dir(cleanAbs))
    99  		// target cannot reference newDir, as this load would've failed prior to localize;
   100  		// not a problem if remote because then reference could only be in newDir if repo copy,
   101  		// which will be cleaned, is inside newDir
   102  		if dir.HasPrefix(ll.args.NewDir) {
   103  			return nil, errors.Errorf("file %q at %q enters localize destination %q", path, cleanAbs, ll.args.NewDir)
   104  		}
   105  	}
   106  	return content, nil
   107  }
   108  
   109  // New returns a Loader at path if path is a valid localize root.
   110  // Otherwise, New returns an error.
   111  func (ll *Loader) New(path string) (ifc.Loader, error) {
   112  	ldr, err := ll.Loader.New(path)
   113  	if err != nil {
   114  		return nil, errors.WrapPrefixf(err, "invalid root reference")
   115  	}
   116  
   117  	if repo := ldr.Repo(); repo == "" {
   118  		if ll.local && !filesys.ConfirmedDir(ldr.Root()).HasPrefix(ll.args.Scope) {
   119  			return nil, errors.Errorf("root %q outside localize scope %q", ldr.Root(), ll.args.Scope)
   120  		}
   121  		if ll.local && filesys.ConfirmedDir(ldr.Root()).HasPrefix(ll.args.NewDir) {
   122  			return nil, errors.Errorf(
   123  				"root %q references into localize destination %q", ldr.Root(), ll.args.NewDir)
   124  		}
   125  	} else if !hasRef(path) {
   126  		return nil, errors.Errorf("localize remote root %q missing ref query string parameter", path)
   127  	}
   128  
   129  	return &Loader{
   130  		fSys:   ll.fSys,
   131  		args:   ll.args,
   132  		Loader: ldr,
   133  		local:  ll.local && ldr.Repo() == "",
   134  	}, nil
   135  }
   136  

View as plain text