Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 87 additions & 1 deletion bake/bake.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
"sort"
"strconv"
Expand Down Expand Up @@ -715,6 +716,21 @@ func updateContext(t *build.Inputs, inp *Input) {
if inp == nil || inp.State == nil {
return
}

for k, v := range t.NamedContexts {
if v.Path == "." {
t.NamedContexts[k] = build.NamedContext{Path: inp.URL}
}
if strings.HasPrefix(v.Path, "cwd://") || strings.HasPrefix(v.Path, "target:") || strings.HasPrefix(v.Path, "docker-image:") {
continue
}
if IsRemoteURL(v.Path) {
continue
}
st := llb.Scratch().File(llb.Copy(*inp.State, v.Path, "/"), llb.WithCustomNamef("set context %s to %s", k, v.Path))
t.NamedContexts[k] = build.NamedContext{State: &st}
}

if t.ContextPath == "." {
t.ContextPath = inp.URL
return
Expand All @@ -729,6 +745,59 @@ func updateContext(t *build.Inputs, inp *Input) {
t.ContextState = &st
}

// validateContextsEntitlements is a basic check to ensure contexts do not
// escape local directories when loaded from remote sources. This is to be
// replaced with proper entitlements support in the future.
func validateContextsEntitlements(t build.Inputs, inp *Input) error {
if inp == nil || inp.State == nil {
return nil
}
if v, ok := os.LookupEnv("BAKE_ALLOW_REMOTE_FS_ACCESS"); ok {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@crazy-max I think in our github actions we can define this by default as the whole system is in a vm anyway.

Copy link
Member

@crazy-max crazy-max Feb 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On GHA they could include /home/runner/.docker which contains auth token in config.json if login step has been done in a previous step.

if vv, _ := strconv.ParseBool(v); vv {
return nil
}
}
if t.ContextState == nil {
if err := checkPath(t.ContextPath); err != nil {
return err
}
}
for _, v := range t.NamedContexts {
if v.State != nil {
continue
}
if err := checkPath(v.Path); err != nil {
return err
}
}
return nil
}

func checkPath(p string) error {
if IsRemoteURL(p) || strings.HasPrefix(p, "target:") || strings.HasPrefix(p, "docker-image:") {
return nil
}
p, err := filepath.EvalSymlinks(p)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
wd, err := os.Getwd()
if err != nil {
return err
}
rel, err := filepath.Rel(wd, p)
if err != nil {
return err
}
if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
return errors.Errorf("path %s is outside of the working directory, please set BAKE_ALLOW_REMOTE_FS_ACCESS=1", p)
}
return nil
}

func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
if v := t.Context; v != nil && *v == "-" {
return nil, errors.Errorf("context from stdin not allowed in bake")
Expand Down Expand Up @@ -769,7 +838,7 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
bi := build.Inputs{
ContextPath: contextPath,
DockerfilePath: dockerfilePath,
NamedContexts: t.Contexts,
NamedContexts: toNamedContexts(t.Contexts),
}
if t.DockerfileInline != nil {
bi.DockerfileInline = *t.DockerfileInline
Expand All @@ -778,6 +847,15 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
if strings.HasPrefix(bi.ContextPath, "cwd://") {
bi.ContextPath = path.Clean(strings.TrimPrefix(bi.ContextPath, "cwd://"))
}
for k, v := range bi.NamedContexts {
if strings.HasPrefix(v.Path, "cwd://") {
bi.NamedContexts[k] = build.NamedContext{Path: path.Clean(strings.TrimPrefix(v.Path, "cwd://"))}
}
}

if err := validateContextsEntitlements(bi, inp); err != nil {
return nil, err
}

t.Context = &bi.ContextPath

Expand Down Expand Up @@ -903,3 +981,11 @@ func sliceEqual(s1, s2 []string) bool {
}
return true
}

func toNamedContexts(m map[string]string) map[string]build.NamedContext {
m2 := make(map[string]build.NamedContext, len(m))
for k, v := range m {
m2[k] = build.NamedContext{Path: v}
}
return m2
}
12 changes: 6 additions & 6 deletions bake/bake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,8 @@ func TestReadContexts(t *testing.T) {
ctxs := bo["app"].Inputs.NamedContexts
require.Equal(t, 2, len(ctxs))

require.Equal(t, "baz", ctxs["foo"])
require.Equal(t, "def", ctxs["abc"])
require.Equal(t, "baz", ctxs["foo"].Path)
require.Equal(t, "def", ctxs["abc"].Path)

m, _, err = ReadTargets(ctx, []File{fp}, []string{"app"}, []string{"app.contexts.foo=bay", "base.contexts.ghi=jkl"}, nil)
require.NoError(t, err)
Expand All @@ -402,9 +402,9 @@ func TestReadContexts(t *testing.T) {
ctxs = bo["app"].Inputs.NamedContexts
require.Equal(t, 3, len(ctxs))

require.Equal(t, "bay", ctxs["foo"])
require.Equal(t, "def", ctxs["abc"])
require.Equal(t, "jkl", ctxs["ghi"])
require.Equal(t, "bay", ctxs["foo"].Path)
require.Equal(t, "def", ctxs["abc"].Path)
require.Equal(t, "jkl", ctxs["ghi"].Path)

// test resetting base values
m, _, err = ReadTargets(ctx, []File{fp}, []string{"app"}, []string{"app.contexts.foo="}, nil)
Expand All @@ -419,7 +419,7 @@ func TestReadContexts(t *testing.T) {

ctxs = bo["app"].Inputs.NamedContexts
require.Equal(t, 1, len(ctxs))
require.Equal(t, "def", ctxs["abc"])
require.Equal(t, "def", ctxs["abc"].Path)
}

func TestReadContextFromTargetUnknown(t *testing.T) {
Expand Down
24 changes: 19 additions & 5 deletions build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,12 @@ type Inputs struct {
InStream io.Reader
ContextState *llb.State
DockerfileInline string
NamedContexts map[string]string
NamedContexts map[string]NamedContext
}

type NamedContext struct {
Path string
State *llb.State
}

type DriverInfo struct {
Expand Down Expand Up @@ -1160,11 +1165,20 @@ func LoadInputs(ctx context.Context, d driver.Driver, inp Inputs, pw progress.Wr

for k, v := range inp.NamedContexts {
target.FrontendAttrs["frontend.caps"] = "moby.buildkit.frontend.contexts+forward"
if urlutil.IsGitURL(v) || urlutil.IsURL(v) || strings.HasPrefix(v, "docker-image://") || strings.HasPrefix(v, "target:") {
target.FrontendAttrs["context:"+k] = v
if v.State != nil {
target.FrontendAttrs["context:"+k] = "input:" + k
if target.FrontendInputs == nil {
target.FrontendInputs = make(map[string]llb.State)
}
target.FrontendInputs[k] = *v.State
continue
}

if urlutil.IsGitURL(v.Path) || urlutil.IsURL(v.Path) || strings.HasPrefix(v.Path, "docker-image://") || strings.HasPrefix(v.Path, "target:") {
target.FrontendAttrs["context:"+k] = v.Path
continue
}
st, err := os.Stat(v)
st, err := os.Stat(v.Path)
if err != nil {
return nil, errors.Wrapf(err, "failed to get build context %v", k)
}
Expand All @@ -1175,7 +1189,7 @@ func LoadInputs(ctx context.Context, d driver.Driver, inp Inputs, pw progress.Wr
if k == "context" || k == "dockerfile" {
localName = "_" + k // underscore to avoid collisions
}
target.LocalDirs[localName] = v
target.LocalDirs[localName] = v.Path
target.FrontendAttrs["context:"+k] = "local:" + localName
}

Expand Down
6 changes: 3 additions & 3 deletions commands/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,11 +480,11 @@ func listToMap(values []string, defaultEnv bool) map[string]string {
return result
}

func parseContextNames(values []string) (map[string]string, error) {
func parseContextNames(values []string) (map[string]build.NamedContext, error) {
if len(values) == 0 {
return nil, nil
}
result := make(map[string]string, len(values))
result := make(map[string]build.NamedContext, len(values))
for _, value := range values {
kv := strings.SplitN(value, "=", 2)
if len(kv) != 2 {
Expand All @@ -495,7 +495,7 @@ func parseContextNames(values []string) (map[string]string, error) {
return nil, errors.Wrapf(err, "invalid context name %s", kv[0])
}
name := strings.TrimSuffix(reference.FamiliarString(named), ":latest")
result[name] = kv[1]
result[name] = build.NamedContext{Path: kv[1]}
}
return result, nil
}
Expand Down