mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 00:47:48 +08:00
Merge pull request #2945 from tonistiigi/v0.20.1-cherry-picks
[v0.20.1] cherry picks
This commit is contained in:
commit
245093b99a
2
.github/workflows/docs-upstream.yml
vendored
2
.github/workflows/docs-upstream.yml
vendored
@ -65,7 +65,7 @@ jobs:
|
|||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
validate:
|
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:
|
needs:
|
||||||
- docs-yaml
|
- docs-yaml
|
||||||
with:
|
with:
|
||||||
|
39
bake/bake.go
39
bake/bake.go
@ -29,7 +29,6 @@ import (
|
|||||||
"github.com/moby/buildkit/session/auth/authprovider"
|
"github.com/moby/buildkit/session/auth/authprovider"
|
||||||
"github.com/moby/buildkit/util/entitlements"
|
"github.com/moby/buildkit/util/entitlements"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/tonistiigi/go-csvvalue"
|
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
"github.com/zclconf/go-cty/cty/convert"
|
"github.com/zclconf/go-cty/cty/convert"
|
||||||
)
|
)
|
||||||
@ -900,7 +899,7 @@ func (t *Target) AddOverrides(overrides map[string]Override, ent *EntitlementCon
|
|||||||
case "tags":
|
case "tags":
|
||||||
t.Tags = o.ArrValue
|
t.Tags = o.ArrValue
|
||||||
case "cache-from":
|
case "cache-from":
|
||||||
cacheFrom, err := parseCacheArrValues(o.ArrValue)
|
cacheFrom, err := buildflags.ParseCacheEntry(o.ArrValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -913,7 +912,7 @@ func (t *Target) AddOverrides(overrides map[string]Override, ent *EntitlementCon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "cache-to":
|
case "cache-to":
|
||||||
cacheTo, err := parseCacheArrValues(o.ArrValue)
|
cacheTo, err := buildflags.ParseCacheEntry(o.ArrValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1585,37 +1584,3 @@ func parseArrValue[T any, PT arrValue[T]](s []string) ([]*T, error) {
|
|||||||
}
|
}
|
||||||
return outputs, nil
|
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
|
|
||||||
}
|
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/buildx/util/buildflags"
|
||||||
"github.com/moby/buildkit/util/entitlements"
|
"github.com/moby/buildkit/util/entitlements"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -1759,6 +1760,27 @@ func TestAnnotations(t *testing.T) {
|
|||||||
require.Equal(t, "bar", bo["app"].Exports[0].Attrs["annotation-manifest[linux/amd64].foo"])
|
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) {
|
func TestHCLEntitlements(t *testing.T) {
|
||||||
fp := File{
|
fp := File{
|
||||||
Name: "docker-bake.hcl",
|
Name: "docker-bake.hcl",
|
||||||
|
@ -145,12 +145,12 @@ func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Conf
|
|||||||
labels[k] = &v
|
labels[k] = &v
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheFrom, err := parseCacheArrValues(s.Build.CacheFrom)
|
cacheFrom, err := buildflags.ParseCacheEntry(s.Build.CacheFrom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheTo, err := parseCacheArrValues(s.Build.CacheTo)
|
cacheTo, err := buildflags.ParseCacheEntry(s.Build.CacheTo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -349,14 +349,14 @@ func (t *Target) composeExtTarget(exts map[string]interface{}) error {
|
|||||||
t.Tags = dedupSlice(append(t.Tags, xb.Tags...))
|
t.Tags = dedupSlice(append(t.Tags, xb.Tags...))
|
||||||
}
|
}
|
||||||
if len(xb.CacheFrom) > 0 {
|
if len(xb.CacheFrom) > 0 {
|
||||||
cacheFrom, err := parseCacheArrValues(xb.CacheFrom)
|
cacheFrom, err := buildflags.ParseCacheEntry(xb.CacheFrom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
t.CacheFrom = t.CacheFrom.Merge(cacheFrom)
|
t.CacheFrom = t.CacheFrom.Merge(cacheFrom)
|
||||||
}
|
}
|
||||||
if len(xb.CacheTo) > 0 {
|
if len(xb.CacheTo) > 0 {
|
||||||
cacheTo, err := parseCacheArrValues(xb.CacheTo)
|
cacheTo, err := buildflags.ParseCacheEntry(xb.CacheTo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
opts.CacheTo, err = buildflags.ParseCacheEntry(o.cacheTo)
|
opts.CacheFrom = cacheFrom.ToPB()
|
||||||
|
|
||||||
|
cacheTo, err := buildflags.ParseCacheEntry(o.cacheTo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
opts.CacheTo = cacheTo.ToPB()
|
||||||
|
|
||||||
opts.Secrets, err = buildflags.ParseSecretSpecs(o.secrets)
|
opts.Secrets, err = buildflags.ParseSecretSpecs(o.secrets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -221,8 +221,10 @@ The following table shows the complete list of attributes that you can assign to
|
|||||||
| [`attest`](#targetattest) | List | Build attestations |
|
| [`attest`](#targetattest) | List | Build attestations |
|
||||||
| [`cache-from`](#targetcache-from) | List | External cache sources |
|
| [`cache-from`](#targetcache-from) | List | External cache sources |
|
||||||
| [`cache-to`](#targetcache-to) | List | External cache destinations |
|
| [`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 |
|
| [`context`](#targetcontext) | String | Set of files located in the specified path or URL |
|
||||||
| [`contexts`](#targetcontexts) | Map | Additional build contexts |
|
| [`contexts`](#targetcontexts) | Map | Additional build contexts |
|
||||||
|
| [`description`](#targetdescription) | String | Description of a target |
|
||||||
| [`dockerfile-inline`](#targetdockerfile-inline) | String | Inline Dockerfile string |
|
| [`dockerfile-inline`](#targetdockerfile-inline) | String | Inline Dockerfile string |
|
||||||
| [`dockerfile`](#targetdockerfile) | String | Dockerfile location |
|
| [`dockerfile`](#targetdockerfile) | String | Dockerfile location |
|
||||||
| [`inherits`](#targetinherits) | List | Inherit attributes from other targets |
|
| [`inherits`](#targetinherits) | List | Inherit attributes from other targets |
|
||||||
@ -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
|
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).
|
[`docker buildx build --call`](https://docs.docker.com/reference/cli/docker/buildx/build/#call).
|
||||||
|
|
||||||
@ -481,6 +490,25 @@ FROM baseapp
|
|||||||
RUN echo "Hello world"
|
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`
|
### `target.dockerfile-inline`
|
||||||
|
|
||||||
Uses the string value as an inline Dockerfile for the build target.
|
Uses the string value as an inline Dockerfile for the build target.
|
||||||
|
@ -15,7 +15,7 @@ Build from a file
|
|||||||
|
|
||||||
| Name | Type | Default | Description |
|
| 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 |
|
| [`--builder`](#builder) | `string` | | Override the configured builder instance |
|
||||||
| [`--call`](#call) | `string` | `build` | Set method for evaluating build (`check`, `outline`, `targets`) |
|
| [`--call`](#call) | `string` | `build` | Set method for evaluating build (`check`, `outline`, `targets`) |
|
||||||
| [`--check`](#check) | `bool` | | Shorthand for `--call=check` |
|
| [`--check`](#check) | `bool` | | Shorthand for `--call=check` |
|
||||||
@ -51,6 +51,80 @@ guide for introduction to writing bake files.
|
|||||||
|
|
||||||
## Examples
|
## 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)
|
### <a name="builder"></a> Override the configured builder instance (--builder)
|
||||||
|
|
||||||
Same as [`buildx --builder`](buildx.md#builder).
|
Same as [`buildx --builder`](buildx.md#builder).
|
||||||
|
@ -167,20 +167,37 @@ func (e *CacheOptionsEntry) validate(gv interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseCacheEntry(in []string) ([]*controllerapi.CacheOptionsEntry, error) {
|
func ParseCacheEntry(in []string) (CacheOptions, error) {
|
||||||
if len(in) == 0 {
|
if len(in) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := make(CacheOptions, 0, len(in))
|
opts := make(CacheOptions, 0, len(in))
|
||||||
for _, in := range 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
|
var out CacheOptionsEntry
|
||||||
if err := out.UnmarshalText([]byte(in)); err != nil {
|
if err := out.UnmarshalText([]byte(in)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
opts = append(opts, &out)
|
opts = append(opts, &out)
|
||||||
}
|
}
|
||||||
return opts.ToPB(), nil
|
return opts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addGithubToken(ci *controllerapi.CacheOptionsEntry) {
|
func addGithubToken(ci *controllerapi.CacheOptionsEntry) {
|
||||||
|
@ -30,6 +30,16 @@ func (o *CacheOptions) fromCtyValue(in cty.Value, p cty.Path) error {
|
|||||||
continue
|
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{}
|
entry := &CacheOptionsEntry{}
|
||||||
if err := entry.FromCtyValue(value, p); err != nil {
|
if err := entry.FromCtyValue(value, p); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -52,13 +62,6 @@ func (o CacheOptions) ToCtyValue() cty.Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *CacheOptionsEntry) FromCtyValue(in cty.Value, p cty.Path) error {
|
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))
|
conv, err := convert.Convert(in, cty.Map(cty.String))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -37,7 +37,7 @@ func TestCacheOptions_DerivedVars(t *testing.T) {
|
|||||||
"session_token": "not_a_mitm_attack",
|
"session_token": "not_a_mitm_attack",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, cacheFrom)
|
}, cacheFrom.ToPB())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCacheOptions(t *testing.T) {
|
func TestCacheOptions(t *testing.T) {
|
||||||
@ -109,3 +109,12 @@ func TestCacheOptions(t *testing.T) {
|
|||||||
require.True(t, result.True())
|
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)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user