bake: restrict target name

This fix adds a restriction `[a-zA-Z0-9_-]+`
for target name. This is pretty much the same as the
container name restriction in moby.

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2022-01-26 10:29:17 +01:00
parent 11b771c789
commit c74b2fe7a4
No known key found for this signature in database
GPG Key ID: 3248E46B6BB8C7F7
6 changed files with 150 additions and 7 deletions

View File

@ -22,8 +22,13 @@ import (
"github.com/pkg/errors"
)
var httpPrefix = regexp.MustCompile(`^https?://`)
var gitURLPathWithFragmentSuffix = regexp.MustCompile(`\.git(?:#.+)?$`)
var (
httpPrefix = regexp.MustCompile(`^https?://`)
gitURLPathWithFragmentSuffix = regexp.MustCompile(`\.git(?:#.+)?$`)
validTargetNameChars = `[a-zA-Z0-9_-]+`
targetNamePattern = regexp.MustCompile(`^` + validTargetNameChars + `$`)
)
type File struct {
Name string
@ -176,8 +181,9 @@ func ParseFiles(files []File, defaults map[string]string) (_ *Config, err error)
if len(fs) > 0 {
if err := hclparser.Parse(hcl.MergeFiles(fs), hclparser.Opt{
LookupVar: os.LookupEnv,
Vars: defaults,
LookupVar: os.LookupEnv,
Vars: defaults,
ValidateLabel: validateTargetName,
}, &c); err.HasErrors() {
return nil, err
}
@ -798,3 +804,10 @@ func parseOutputType(str string) string {
}
return ""
}
func validateTargetName(name string) error {
if !targetNamePattern.MatchString(name) {
return errors.Errorf("only %q are allowed", validTargetNameChars)
}
return nil
}

View File

@ -788,3 +788,58 @@ group "default" {
})
}
}
func TestTargetName(t *testing.T) {
ctx := context.TODO()
cases := []struct {
target string
wantErr bool
}{
{
target: "a",
wantErr: false,
},
{
target: "abc",
wantErr: false,
},
{
target: "a/b",
wantErr: true,
},
{
target: "a.b",
wantErr: true,
},
{
target: "_a",
wantErr: false,
},
{
target: "a_b",
wantErr: false,
},
{
target: "AbC",
wantErr: false,
},
{
target: "AbC-0123",
wantErr: false,
},
}
for _, tt := range cases {
tt := tt
t.Run(tt.target, func(t *testing.T) {
_, _, err := ReadTargets(ctx, []File{{
Name: "docker-bake.hcl",
Data: []byte(`target "` + tt.target + `" {}`),
}}, []string{tt.target}, nil, nil)
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}

View File

@ -8,6 +8,7 @@ import (
"github.com/compose-spec/compose-go/loader"
compose "github.com/compose-spec/compose-go/types"
"github.com/pkg/errors"
)
func parseCompose(dt []byte) (*compose.Project, error) {
@ -59,6 +60,10 @@ func ParseCompose(dt []byte) (*Config, error) {
continue
}
if err = validateTargetName(s.Name); err != nil {
return nil, errors.Wrapf(err, "invalid service name %q", s.Name)
}
var contextPathP *string
if s.Build.Context != "" {
contextPath := s.Build.Context

View File

@ -314,3 +314,55 @@ func newBool(val bool) *bool {
b := val
return &b
}
func TestServiceName(t *testing.T) {
cases := []struct {
svc string
wantErr bool
}{
{
svc: "a",
wantErr: false,
},
{
svc: "abc",
wantErr: false,
},
{
svc: "a.b",
wantErr: true,
},
{
svc: "_a",
wantErr: false,
},
{
svc: "a_b",
wantErr: false,
},
{
svc: "AbC",
wantErr: false,
},
{
svc: "AbC-0123",
wantErr: false,
},
}
for _, tt := range cases {
tt := tt
t.Run(tt.svc, func(t *testing.T) {
_, err := ParseCompose([]byte(`
services:
` + tt.svc + `:
build:
context: .
`))
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}

View File

@ -3,7 +3,7 @@ package bake
import (
"strings"
hcl "github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclparse"
"github.com/moby/buildkit/solver/errdefs"
"github.com/moby/buildkit/solver/pb"

View File

@ -16,8 +16,9 @@ import (
)
type Opt struct {
LookupVar func(string) (string, bool)
Vars map[string]string
LookupVar func(string) (string, bool)
Vars map[string]string
ValidateLabel func(string) error
}
type variable struct {
@ -262,6 +263,12 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
}
}
if opt.ValidateLabel == nil {
opt.ValidateLabel = func(string) error {
return nil
}
}
p := &parser{
opt: opt,
@ -446,6 +453,17 @@ func Parse(b hcl.Body, opt Opt, val interface{}) hcl.Diagnostics {
continue
}
if err := opt.ValidateLabel(b.Labels[0]); err != nil {
return hcl.Diagnostics{
&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid name",
Detail: err.Error(),
Subject: &b.LabelRanges[0],
},
}
}
lblIndex := setLabel(vv, b.Labels[0])
oldValue, exists := t.values[b.Labels[0]]