Skip to content

Commit

Permalink
Merge pull request #2945 from tonistiigi/v0.20.1-cherry-picks
Browse files Browse the repository at this point in the history
[v0.20.1] cherry picks
  • Loading branch information
tonistiigi authored Jan 22, 2025
2 parents bd7090b + e2ed15f commit 245093b
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 55 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/docs-upstream.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
retention-days: 1

validate:
uses: docker/docs/.github/workflows/validate-upstream.yml@6b73b05acb21edf7995cc5b3c6672d8e314cee7a # pin for artifact v4 support: https://github.com/docker/docs/pull/19220
uses: docker/docs/.github/workflows/validate-upstream.yml@main
needs:
- docs-yaml
with:
Expand Down
39 changes: 2 additions & 37 deletions bake/bake.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"github.com/moby/buildkit/session/auth/authprovider"
"github.com/moby/buildkit/util/entitlements"
"github.com/pkg/errors"
"github.com/tonistiigi/go-csvvalue"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
)
Expand Down Expand Up @@ -900,7 +899,7 @@ func (t *Target) AddOverrides(overrides map[string]Override, ent *EntitlementCon
case "tags":
t.Tags = o.ArrValue
case "cache-from":
cacheFrom, err := parseCacheArrValues(o.ArrValue)
cacheFrom, err := buildflags.ParseCacheEntry(o.ArrValue)
if err != nil {
return err
}
Expand All @@ -913,7 +912,7 @@ func (t *Target) AddOverrides(overrides map[string]Override, ent *EntitlementCon
}
}
case "cache-to":
cacheTo, err := parseCacheArrValues(o.ArrValue)
cacheTo, err := buildflags.ParseCacheEntry(o.ArrValue)
if err != nil {
return err
}
Expand Down Expand Up @@ -1585,37 +1584,3 @@ func parseArrValue[T any, PT arrValue[T]](s []string) ([]*T, error) {
}
return outputs, nil
}

func parseCacheArrValues(s []string) (buildflags.CacheOptions, error) {
var outs buildflags.CacheOptions
for _, in := range s {
if in == "" {
continue
}

if !strings.Contains(in, "=") {
// This is ref only format. Each field in the CSV is its own entry.
fields, err := csvvalue.Fields(in, nil)
if err != nil {
return nil, err
}

for _, field := range fields {
out := buildflags.CacheOptionsEntry{}
if err := out.UnmarshalText([]byte(field)); err != nil {
return nil, err
}
outs = append(outs, &out)
}
continue
}

// Normal entry.
out := buildflags.CacheOptionsEntry{}
if err := out.UnmarshalText([]byte(in)); err != nil {
return nil, err
}
outs = append(outs, &out)
}
return outs, nil
}
22 changes: 22 additions & 0 deletions bake/bake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"testing"

"github.com/docker/buildx/util/buildflags"
"github.com/moby/buildkit/util/entitlements"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -1759,6 +1760,27 @@ func TestAnnotations(t *testing.T) {
require.Equal(t, "bar", bo["app"].Exports[0].Attrs["annotation-manifest[linux/amd64].foo"])
}

func TestRefOnlyCacheOptions(t *testing.T) {
fp := File{
Name: "docker-bake.hcl",
Data: []byte(
`target "app" {
output = ["type=image,name=foo"]
cache-from = ["ref1,ref2"]
}`),
}
ctx := context.TODO()
m, _, err := ReadTargets(ctx, []File{fp}, []string{"app"}, nil, nil, &EntitlementConf{})
require.NoError(t, err)

require.Len(t, m, 1)
require.Contains(t, m, "app")
require.Equal(t, buildflags.CacheOptions{
{Type: "registry", Attrs: map[string]string{"ref": "ref1"}},
{Type: "registry", Attrs: map[string]string{"ref": "ref2"}},
}, m["app"].CacheFrom)
}

func TestHCLEntitlements(t *testing.T) {
fp := File{
Name: "docker-bake.hcl",
Expand Down
8 changes: 4 additions & 4 deletions bake/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,12 @@ func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Conf
labels[k] = &v
}

cacheFrom, err := parseCacheArrValues(s.Build.CacheFrom)
cacheFrom, err := buildflags.ParseCacheEntry(s.Build.CacheFrom)
if err != nil {
return nil, err
}

cacheTo, err := parseCacheArrValues(s.Build.CacheTo)
cacheTo, err := buildflags.ParseCacheEntry(s.Build.CacheTo)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -349,14 +349,14 @@ func (t *Target) composeExtTarget(exts map[string]interface{}) error {
t.Tags = dedupSlice(append(t.Tags, xb.Tags...))
}
if len(xb.CacheFrom) > 0 {
cacheFrom, err := parseCacheArrValues(xb.CacheFrom)
cacheFrom, err := buildflags.ParseCacheEntry(xb.CacheFrom)
if err != nil {
return err
}
t.CacheFrom = t.CacheFrom.Merge(cacheFrom)
}
if len(xb.CacheTo) > 0 {
cacheTo, err := parseCacheArrValues(xb.CacheTo)
cacheTo, err := buildflags.ParseCacheEntry(xb.CacheTo)
if err != nil {
return err
}
Expand Down
7 changes: 5 additions & 2 deletions commands/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,17 @@ func (o *buildOptions) toControllerOptions() (*controllerapi.BuildOptions, error
}
}

opts.CacheFrom, err = buildflags.ParseCacheEntry(o.cacheFrom)
cacheFrom, err := buildflags.ParseCacheEntry(o.cacheFrom)
if err != nil {
return nil, err
}
opts.CacheTo, err = buildflags.ParseCacheEntry(o.cacheTo)
opts.CacheFrom = cacheFrom.ToPB()

cacheTo, err := buildflags.ParseCacheEntry(o.cacheTo)
if err != nil {
return nil, err
}
opts.CacheTo = cacheTo.ToPB()

opts.Secrets, err = buildflags.ParseSecretSpecs(o.secrets)
if err != nil {
Expand Down
28 changes: 28 additions & 0 deletions docs/bake-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,10 @@ The following table shows the complete list of attributes that you can assign to
| [`attest`](#targetattest) | List | Build attestations |
| [`cache-from`](#targetcache-from) | List | External cache sources |
| [`cache-to`](#targetcache-to) | List | External cache destinations |
| [`call`](#targetcall) | String | Specify the frontend method to call for the target. |
| [`context`](#targetcontext) | String | Set of files located in the specified path or URL |
| [`contexts`](#targetcontexts) | Map | Additional build contexts |
| [`description`](#targetdescription) | String | Description of a target |
| [`dockerfile-inline`](#targetdockerfile-inline) | String | Inline Dockerfile string |
| [`dockerfile`](#targetdockerfile) | String | Dockerfile location |
| [`inherits`](#targetinherits) | List | Inherit attributes from other targets |
Expand Down Expand Up @@ -371,6 +373,13 @@ target "app" {
}
```

Supported values are:

- `build` builds the target (default)
- `check`: evaluates [build checks](https://docs.docker.com/build/checks/) for the target
- `outline`: displays the target's build arguments and their default values if available
- `targets`: lists all Bake targets in the loaded definition, along with its [description](#targetdescription).

For more information about frontend methods, refer to the CLI reference for
[`docker buildx build --call`](https://docs.docker.com/reference/cli/docker/buildx/build/#call).

Expand Down Expand Up @@ -481,6 +490,25 @@ FROM baseapp
RUN echo "Hello world"
```

### `target.description`

Defines a human-readable description for the target, clarifying its purpose or
functionality.

```hcl
target "lint" {
description = "Runs golangci-lint to detect style errors"
args = {
GOLANGCI_LINT_VERSION = null
}
dockerfile = "lint.Dockerfile"
}
```

This attribute is useful when combined with the `docker buildx bake --list=targets`
option, providing a more informative output when listing the available build
targets in a Bake file.

### `target.dockerfile-inline`

Uses the string value as an inline Dockerfile for the build target.
Expand Down
76 changes: 75 additions & 1 deletion docs/reference/buildx_bake.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Build from a file

| Name | Type | Default | Description |
|:------------------------------------|:--------------|:--------|:-------------------------------------------------------------------------------------------------------------|
| `--allow` | `stringArray` | | Allow build to access specified resources |
| [`--allow`](#allow) | `stringArray` | | Allow build to access specified resources |
| [`--builder`](#builder) | `string` | | Override the configured builder instance |
| [`--call`](#call) | `string` | `build` | Set method for evaluating build (`check`, `outline`, `targets`) |
| [`--check`](#check) | `bool` | | Shorthand for `--call=check` |
Expand Down Expand Up @@ -51,6 +51,80 @@ guide for introduction to writing bake files.
## Examples

### <a name="allow"></a> Allow extra privileged entitlement (--allow)

```text
--allow=ENTITLEMENT[=VALUE]
```

Entitlements are designed to provide controlled access to privileged
operations. By default, Buildx and BuildKit operates with restricted
permissions to protect users and their systems from unintended side effects or
security risks. The `--allow` flag explicitly grants access to additional
entitlements, making it clear when a build or bake operation requires elevated
privileges.

In addition to BuildKit's `network.host` and `security.insecure` entitlements
(see [`docker buildx build --allow`](https://docs.docker.com/reference/cli/docker/buildx/build/#allow),
Bake supports file system entitlements that grant granular control over file
system access. These are particularly useful when working with builds that need
access to files outside the default working directory.

Bake supports the following filesystem entitlements:

- `--allow fs=<path|*>` - Grant read and write access to files outside of the
working directory.
- `--allow fs.read=<path|*>` - Grant read access to files outside of the
working directory.
- `--allow fs.write=<path|*>` - Grant write access to files outside of the
working directory.

The `fs` entitlements take a path value (relative or absolute) to a directory
on the filesystem. Alternatively, you can pass a wildcard (`*`) to allow Bake
to access the entire filesystem.

### Example: fs.read

Given the following Bake configuration, Bake would need to access the parent
directory, relative to the Bake file.

```hcl
target "app" {
context = "../src"
}
```

Assuming `docker buildx bake app` is executed in the same directory as the
`docker-bake.hcl` file, you would need to explicitly allow Bake to read from
the `../src` directory. In this case, the following invocations all work:

```console
$ docker buildx bake --allow fs.read=* app
$ docker buildx bake --allow fs.read=../src app
$ docker buildx bake --allow fs=* app
```

### Example: fs.write

The following `docker-bake.hcl` file requires write access to the `/tmp`
directory.

```hcl
target "app" {
output = "/tmp"
}
```

Assuming `docker buildx bake app` is executed outside of the `/tmp` directory,
you would need to allow the `fs.write` entitlement, either by specifying the
path or using a wildcard:

```console
$ docker buildx bake --allow fs=/tmp app
$ docker buildx bake --allow fs.write=/tmp app
$ docker buildx bake --allow fs.write=* app
```

### <a name="builder"></a> Override the configured builder instance (--builder)

Same as [`buildx --builder`](buildx.md#builder).
Expand Down
21 changes: 19 additions & 2 deletions util/buildflags/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,20 +167,37 @@ func (e *CacheOptionsEntry) validate(gv interface{}) error {
return nil
}

func ParseCacheEntry(in []string) ([]*controllerapi.CacheOptionsEntry, error) {
func ParseCacheEntry(in []string) (CacheOptions, error) {
if len(in) == 0 {
return nil, nil
}

opts := make(CacheOptions, 0, len(in))
for _, in := range in {
if !strings.Contains(in, "=") {
// This is ref only format. Each field in the CSV is its own entry.
fields, err := csvvalue.Fields(in, nil)
if err != nil {
return nil, err
}

for _, field := range fields {
opt := CacheOptionsEntry{}
if err := opt.UnmarshalText([]byte(field)); err != nil {
return nil, err
}
opts = append(opts, &opt)
}
continue
}

var out CacheOptionsEntry
if err := out.UnmarshalText([]byte(in)); err != nil {
return nil, err
}
opts = append(opts, &out)
}
return opts.ToPB(), nil
return opts, nil
}

func addGithubToken(ci *controllerapi.CacheOptionsEntry) {
Expand Down
17 changes: 10 additions & 7 deletions util/buildflags/cache_cty.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ func (o *CacheOptions) fromCtyValue(in cty.Value, p cty.Path) error {
continue
}

// Special handling for a string type to handle ref only format.
if value.Type() == cty.String {
entries, err := ParseCacheEntry([]string{value.AsString()})
if err != nil {
return err
}
*o = append(*o, entries...)
continue
}

entry := &CacheOptionsEntry{}
if err := entry.FromCtyValue(value, p); err != nil {
return err
Expand All @@ -52,13 +62,6 @@ func (o CacheOptions) ToCtyValue() cty.Value {
}

func (o *CacheOptionsEntry) FromCtyValue(in cty.Value, p cty.Path) error {
if in.Type() == cty.String {
if err := o.UnmarshalText([]byte(in.AsString())); err != nil {
return p.NewError(err)
}
return nil
}

conv, err := convert.Convert(in, cty.Map(cty.String))
if err != nil {
return err
Expand Down
11 changes: 10 additions & 1 deletion util/buildflags/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestCacheOptions_DerivedVars(t *testing.T) {
"session_token": "not_a_mitm_attack",
},
},
}, cacheFrom)
}, cacheFrom.ToPB())
}

func TestCacheOptions(t *testing.T) {
Expand Down Expand Up @@ -109,3 +109,12 @@ func TestCacheOptions(t *testing.T) {
require.True(t, result.True())
})
}

func TestCacheOptions_RefOnlyFormat(t *testing.T) {
opts, err := ParseCacheEntry([]string{"ref1", "ref2"})
require.NoError(t, err)
require.Equal(t, CacheOptions{
{Type: "registry", Attrs: map[string]string{"ref": "ref1"}},
{Type: "registry", Attrs: map[string]string{"ref": "ref2"}},
}, opts)
}

0 comments on commit 245093b

Please sign in to comment.