Add load_restrictor flag.

This commit is contained in:
Jeffrey Regan
2019-04-18 19:25:06 -07:00
parent a5bb5479fb
commit 3b8c5ee96d
9 changed files with 142 additions and 15 deletions

2
go.mod
View File

@@ -25,7 +25,7 @@ require (
github.com/onsi/gomega v1.5.0 // indirect github.com/onsi/gomega v1.5.0 // indirect
github.com/pkg/errors v0.8.0 github.com/pkg/errors v0.8.0
github.com/spf13/cobra v0.0.2 github.com/spf13/cobra v0.0.2
github.com/spf13/pflag v1.0.1 // indirect github.com/spf13/pflag v1.0.1
github.com/stretchr/testify v1.3.0 // indirect github.com/stretchr/testify v1.3.0 // indirect
golang.org/x/net v0.0.0-20190225153610-fe579d43d832 // indirect golang.org/x/net v0.0.0-20190225153610-fe579d43d832 // indirect
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 // indirect golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 // indirect

View File

@@ -38,6 +38,7 @@ import (
type Options struct { type Options struct {
kustomizationPath string kustomizationPath string
outputPath string outputPath string
loadRestrictor loader.LoadRestrictorFunc
} }
// NewOptions creates a Options object // NewOptions creates a Options object
@@ -45,6 +46,7 @@ func NewOptions(p, o string) *Options {
return &Options{ return &Options{
kustomizationPath: p, kustomizationPath: p,
outputPath: o, outputPath: o,
loadRestrictor: loader.RestrictionRootOnly,
} }
} }
@@ -88,13 +90,14 @@ func NewCmdBuild(
&o.outputPath, &o.outputPath,
"output", "o", "", "output", "o", "",
"If specified, write the build output to this path.") "If specified, write the build output to this path.")
loader.AddLoadRestrictionsFlag(cmd.Flags())
cmd.AddCommand(NewCmdBuildPrune(out, fs, rf, ptf, pc)) cmd.AddCommand(NewCmdBuildPrune(out, fs, rf, ptf, pc))
return cmd return cmd
} }
// Validate validates build command. // Validate validates build command.
func (o *Options) Validate(args []string) error { func (o *Options) Validate(args []string) (err error) {
if len(args) > 1 { if len(args) > 1 {
return errors.New( return errors.New(
"specify one path to " + pgmconfig.KustomizationFileNames[0]) "specify one path to " + pgmconfig.KustomizationFileNames[0])
@@ -104,8 +107,8 @@ func (o *Options) Validate(args []string) error {
} else { } else {
o.kustomizationPath = args[0] o.kustomizationPath = args[0]
} }
o.loadRestrictor, err = loader.ValidateLoadRestrictorFlag()
return nil return
} }
// RunBuild runs build command. // RunBuild runs build command.
@@ -113,7 +116,8 @@ func (o *Options) RunBuild(
out io.Writer, fSys fs.FileSystem, out io.Writer, fSys fs.FileSystem,
rf *resmap.Factory, ptf transformer.Factory, rf *resmap.Factory, ptf transformer.Factory,
pc *types.PluginConfig) error { pc *types.PluginConfig) error {
ldr, err := loader.NewLoader(o.kustomizationPath, fSys) ldr, err := loader.NewLoader(
o.loadRestrictor, o.kustomizationPath, fSys)
if err != nil { if err != nil {
return err return err
} }
@@ -133,7 +137,8 @@ func (o *Options) RunBuildPrune(
out io.Writer, fSys fs.FileSystem, out io.Writer, fSys fs.FileSystem,
rf *resmap.Factory, ptf transformer.Factory, rf *resmap.Factory, ptf transformer.Factory,
pc *types.PluginConfig) error { pc *types.PluginConfig) error {
ldr, err := loader.NewLoader(o.kustomizationPath, fSys) ldr, err := loader.NewLoader(
o.loadRestrictor, o.kustomizationPath, fSys)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -31,12 +31,22 @@ type FakeLoader struct {
} }
// NewFakeLoader returns a Loader that uses a fake filesystem. // NewFakeLoader returns a Loader that uses a fake filesystem.
// The argument should be an absolute file path. // The loader will be restricted to root only.
// The initialDir argument should be an absolute file path.
func NewFakeLoader(initialDir string) FakeLoader { func NewFakeLoader(initialDir string) FakeLoader {
return NewFakeLoaderWithRestrictor(
loader.RestrictionRootOnly, initialDir)
}
// NewFakeLoaderWithRestrictor returns a Loader that
// uses a fake filesystem.
// The initialDir argument should be an absolute file path.
func NewFakeLoaderWithRestrictor(
lr loader.LoadRestrictorFunc, initialDir string) FakeLoader {
// Create fake filesystem and inject it into initial Loader. // Create fake filesystem and inject it into initial Loader.
fSys := fs.MakeFakeFS() fSys := fs.MakeFakeFS()
fSys.Mkdir(initialDir) fSys.Mkdir(initialDir)
ldr, err := loader.NewLoader(initialDir, fSys) ldr, err := loader.NewLoader(lr, initialDir, fSys)
if err != nil { if err != nil {
log.Fatalf("Unable to make loader: %v", err) log.Fatalf("Unable to make loader: %v", err)
} }

View File

@@ -288,7 +288,7 @@ func doSanityChecksAndDropIntoBase(
return l return l
} }
func TestRestrictionRootInRealLoader(t *testing.T) { func TestRestrictionRootOnlyInRealLoader(t *testing.T) {
dir, fSys, err := commonSetupForLoaderRestrictionTest() dir, fSys, err := commonSetupForLoaderRestrictionTest()
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)

View File

@@ -26,10 +26,11 @@ import (
// NewLoader returns a Loader pointed at the given target. // NewLoader returns a Loader pointed at the given target.
// If the target is remote, the loader will be restricted // If the target is remote, the loader will be restricted
// to the root and below only. If the target is local, the // to the root and below only. If the target is local, the
// loader will have no restrictions. If the local target // loader will have the restrictions passed in. Regardless,
// attempts to transitively load remote bases, they will all // if a local target attempts to transitively load remote bases,
// be root-only restricted. // the remote bases will all be root-only restricted.
func NewLoader( func NewLoader(
lr LoadRestrictorFunc,
target string, fSys fs.FileSystem) (ifc.Loader, error) { target string, fSys fs.FileSystem) (ifc.Loader, error) {
repoSpec, err := git.NewRepoSpecFromUrl(target) repoSpec, err := git.NewRepoSpecFromUrl(target)
if err == nil { if err == nil {
@@ -42,5 +43,5 @@ func NewLoader(
return nil, err return nil, err
} }
return newLoaderAtConfirmedDir( return newLoaderAtConfirmedDir(
RestrictionNone, root, fSys, nil, git.ClonerUsingGitExec), nil lr, root, fSys, nil, git.ClonerUsingGitExec), nil
} }

View File

@@ -19,9 +19,50 @@ package loader
import ( import (
"fmt" "fmt"
"github.com/spf13/pflag"
"sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/fs"
) )
//go:generate stringer -type=loadRestrictions
type loadRestrictions int
const (
unknown loadRestrictions = iota
rootOnly
none
)
const (
flagName = "load_restrictor"
)
var (
flagValue = rootOnly.String()
flagHelp = "if set to '" + none.String() +
"', local kustomizations may load files from outside their root. " +
"This does, however, break the relocatability of the kustomization."
)
func AddLoadRestrictionsFlag(set *pflag.FlagSet) {
set.StringVar(
&flagValue, flagName,
rootOnly.String(), flagHelp)
}
func ValidateLoadRestrictorFlag() (LoadRestrictorFunc, error) {
switch flagValue {
case rootOnly.String():
return RestrictionRootOnly, nil
case none.String():
return RestrictionNone, nil
default:
return nil, fmt.Errorf(
"illegal flag value --%s %s; legal values: %v",
flagName, flagValue,
[]string{rootOnly.String(), none.String()})
}
}
type LoadRestrictorFunc func( type LoadRestrictorFunc func(
fs.FileSystem, fs.ConfirmedDir, string) (string, error) fs.FileSystem, fs.ConfirmedDir, string) (string, error)

View File

@@ -0,0 +1,25 @@
// Code generated by "stringer -type=loadRestrictions"; DO NOT EDIT.
package loader
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[unknown-0]
_ = x[rootOnly-1]
_ = x[none-2]
}
const _loadRestrictions_name = "unknownrootOnlynone"
var _loadRestrictions_index = [...]uint8{0, 7, 15, 19}
func (i loadRestrictions) String() string {
if i < 0 || i >= loadRestrictions(len(_loadRestrictions_index)-1) {
return "loadRestrictions(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _loadRestrictions_name[_loadRestrictions_index[i]:_loadRestrictions_index[i+1]]
}

View File

@@ -17,7 +17,11 @@ limitations under the License.
package target_test package target_test
import ( import (
"strings"
"testing" "testing"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/pkg/loader"
) )
func writeSmallBase(th *KustTestHarness) { func writeSmallBase(th *KustTestHarness) {
@@ -181,8 +185,42 @@ spec:
`) `)
} }
func TestSharedPatchDisAllowed(t *testing.T) {
th := NewKustTestHarnessFull(
t, "/app/overlay",
loader.RestrictionRootOnly, plugin.DefaultPluginConfig())
writeSmallBase(th)
th.writeK("/app/overlay", `
commonLabels:
env: prod
bases:
- ../base
patchesStrategicMerge:
- ../shared/deployment-patch.yaml
`)
th.writeF("/app/shared/deployment-patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
replicas: 1000
`)
_, err := th.makeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(
err.Error(),
"security; file '/app/shared/deployment-patch.yaml' is not in or below '/app/overlay'") {
t.Fatalf("unexpected error: %s", err)
}
}
func TestSharedPatchAllowed(t *testing.T) { func TestSharedPatchAllowed(t *testing.T) {
th := NewKustTestHarness(t, "/app/overlay") th := NewKustTestHarnessFull(
t, "/app/overlay",
loader.RestrictionNone, plugin.DefaultPluginConfig())
writeSmallBase(th) writeSmallBase(th)
th.writeK("/app/overlay", ` th.writeK("/app/overlay", `
commonLabels: commonLabels:

View File

@@ -28,6 +28,7 @@ import (
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"sigs.k8s.io/kustomize/k8sdeps/transformer" "sigs.k8s.io/kustomize/k8sdeps/transformer"
"sigs.k8s.io/kustomize/pkg/internal/loadertest" "sigs.k8s.io/kustomize/pkg/internal/loadertest"
"sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/resource"
@@ -51,12 +52,18 @@ func NewKustTestHarness(t *testing.T, path string) *KustTestHarness {
func NewKustTestHarnessWithPluginConfig( func NewKustTestHarnessWithPluginConfig(
t *testing.T, path string, t *testing.T, path string,
pc *types.PluginConfig) *KustTestHarness { pc *types.PluginConfig) *KustTestHarness {
return NewKustTestHarnessFull(t, path, loader.RestrictionRootOnly, pc)
}
func NewKustTestHarnessFull(
t *testing.T, path string,
lr loader.LoadRestrictorFunc, pc *types.PluginConfig) *KustTestHarness {
return &KustTestHarness{ return &KustTestHarness{
t: t, t: t,
rf: resmap.NewFactory(resource.NewFactory( rf: resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryWithGeneratorArgs( kunstruct.NewKunstructuredFactoryWithGeneratorArgs(
&types.GeneratorMetaArgs{PluginConfig: pc}))), &types.GeneratorMetaArgs{PluginConfig: pc}))),
ldr: loadertest.NewFakeLoader(path), ldr: loadertest.NewFakeLoaderWithRestrictor(lr, path),
pc: pc} pc: pc}
} }