Repository: docker/buildx

Issue:
`buildx ls --format=json` missing "selected" field
### Contributing guidelines

- [x] I've read the [contributing guidelines](https://github.com/docker/buildx/blob/master/.github/CONTRIBUTING.md) and wholeheartedly agree

### I've found a bug and checked that ...

- [x] ... the documentation does not mention anything about my problem
- [x] ... there are no open or closed issues that are related to my problem

### Description

In cli output of `docker buildx ls` an asterisk (*) next to a builder name indicates the selected builder.
In a json output, `docker buildx ls --format=json`, there is no such field, and there is no way to determine the selected one.

### Expected behaviour

Json output has a field indicating if a builder is a selected one (see line 3).
```
{
  "Name": "default",
  "Selected": true,
  "Driver": "docker",
  "LastActivity": "2025-01-01T00:00:00Z",
  "Dynamic": false,
  "Nodes": [ ... ]
}
```

### Actual behaviour

Json output does not have a "Selected" field in any way.
```
{
  "Name": "default",
  "Driver": "docker",
  "LastActivity": "2025-01-01T00:00:00Z",
  "Dynamic": false,
  "Nodes": [ ... ]
}
```

### Buildx version

github.com/docker/buildx v0.23.0 28c90ea

### Docker info

```text

```

### Builders list

```text
NAME/NODE        DRIVER/ENDPOINT                   STATUS    BUILDKIT   PLATFORMS
multiarch        docker-container
 \_ multiarch0    \_ ssh://user@192.168.1.1        running   v0.20.2    linux/amd64 (+2), linux/386
 \_ multiarch1    \_ unix:///var/run/docker.sock   running   v0.20.2    linux/arm64
default*         docker
 \_ default       \_ default                       running   v0.21.0    linux/arm64
```

### Configuration

```dockerfile
FROM scratch
```

### Build logs

```text

```

### Additional info

_No response_

Discussion:

Solution patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index cf3d1996..1a7bb86e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -36,8 +36,8 @@ env:
   TEST_CACHE_SCOPE: "test"
   TESTFLAGS: "-v --parallel=6 --timeout=30m"
   GOTESTSUM_FORMAT: "standard-verbose"
-  GO_VERSION: "1.23"
-  GOTESTSUM_VERSION: "v1.9.0"  # same as one in Dockerfile
+  GO_VERSION: "1.24"
+  GOTESTSUM_VERSION: "v1.12.0"  # same as one in Dockerfile
 
 jobs:
   test-integration:
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 5da47e2e..4e58b499 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -17,7 +17,7 @@ on:
   pull_request:
 
 env:
-  GO_VERSION: "1.23"
+  GO_VERSION: "1.24"
 
 jobs:
   codeql:
diff --git a/.golangci.yml b/.golangci.yml
index 05dca7f2..900134f4 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,17 +1,16 @@
+version: "2"
+
 run:
-  timeout: 30m
   modules-download-mode: vendor
 
 linters:
+  default: none
   enable:
     - bodyclose
     - depguard
     - forbidigo
     - gocritic
-    - gofmt
-    - goimports
     - gosec
-    - gosimple
     - govet
     - ineffassign
     - makezero
@@ -21,99 +20,101 @@ linters:
     - revive
     - staticcheck
     - testifylint
-    - typecheck
     - unused
     - whitespace
-  disable-all: true
-
-linters-settings:
-  gocritic:
-    disabled-checks:
-      - "ifElseChain"
-      - "assignOp"
-      - "appendAssign"
-      - "singleCaseSwitch"
-      - "exitAfterDefer" # FIXME
-  importas:
-    alias:
-      # Enforce alias to prevent it accidentally being used instead of
-      # buildkit errdefs package (or vice-versa).
-      - pkg: "github.com/containerd/errdefs"
-        alias: "cerrdefs"
-      # Use a consistent alias to prevent confusion with "github.com/moby/buildkit/client"
-      - pkg: "github.com/docker/docker/client"
-        alias: "dockerclient"
-      - pkg: "github.com/opencontainers/image-spec/specs-go/v1"
-        alias: "ocispecs"
-      - pkg: "github.com/opencontainers/go-digest"
-        alias: "digest"
-  govet:
-    enable:
-      - nilness
-      - unusedwrite
-  # enable-all: true
-  # disable:
-  #   - fieldalignment
-  #   - shadow
-  depguard:
+  settings:
+    depguard:
+      rules:
+        main:
+          deny:
+            - pkg: "github.com/containerd/containerd/errdefs"
+              desc: The containerd errdefs package was migrated to a separate module. Use github.com/containerd/errdefs instead.
+            - pkg: "github.com/containerd/containerd/log"
+              desc: The containerd log package was migrated to a separate module. Use github.com/containerd/log instead.
+            - pkg: "github.com/containerd/containerd/platforms"
+              desc: The containerd platforms package was migrated to a separate module. Use github.com/containerd/platforms instead.
+            - pkg: "io/ioutil"
+              desc: The io/ioutil package has been deprecated.
+    forbidigo:
+      forbid:
+        - pattern: ^context\.WithCancel(# use context\.WithCancelCause instead)?$
+        - pattern: ^context\.WithDeadline(# use context\.WithDeadline instead)?$
+        - pattern: ^context\.WithTimeout(# use context\.WithTimeoutCause instead)?$
+        - pattern: ^ctx\.Err(# use context\.Cause instead)?$
+        - pattern: ^fmt\.Errorf(# use errors\.Errorf instead)?$
+        - pattern: ^platforms\.DefaultString(# use platforms\.Format(platforms\.DefaultSpec()) instead\.)?$
+    gocritic:
+      disabled-checks:
+        - "ifElseChain"
+        - "assignOp"
+        - "appendAssign"
+        - "singleCaseSwitch"
+        - "exitAfterDefer" # FIXME
+    gosec:
+      excludes:
+        - G204
+        - G402
+        - G115
+      config:
+        G306: "0644"
+    govet:
+      enable:
+        - nilness
+        - unusedwrite
+    importas:
+      alias:
+        - pkg: "github.com/containerd/errdefs"
+          alias: "cerrdefs"
+        - pkg: "github.com/docker/docker/client"
+          alias: "dockerclient"
+        - pkg: "github.com/opencontainers/image-spec/specs-go/v1"
+          alias: "ocispecs"
+        - pkg: "github.com/opencontainers/go-digest"
+          alias: "digest"
+    testifylint:
+      disable:
+        - empty
+        - bool-compare
+        - len
+        - negative-positive
+  exclusions:
+    generated: lax
+    presets:
+      - comments
+      - common-false-positives
+      - legacy
+      - std-error-handling
     rules:
-      main:
-        deny:
-          - pkg: "github.com/containerd/containerd/errdefs"
-            desc: The containerd errdefs package was migrated to a separate module. Use github.com/containerd/errdefs instead.
-          - pkg: "github.com/containerd/containerd/log"
-            desc: The containerd log package was migrated to a separate module. Use github.com/containerd/log instead.
-          - pkg: "github.com/containerd/containerd/platforms"
-            desc: The containerd platforms package was migrated to a separate module. Use github.com/containerd/platforms instead.
-          - pkg: "io/ioutil"
-            desc: The io/ioutil package has been deprecated.
-  forbidigo:
-    forbid:
-      - '^context\.WithCancel(# use context\.WithCancelCause instead)?$'
-      - '^context\.WithDeadline(# use context\.WithDeadline instead)?$'
-      - '^context\.WithTimeout(# use context\.WithTimeoutCause instead)?$'
-      - '^ctx\.Err(# use context\.Cause instead)?$'
-      - '^fmt\.Errorf(# use errors\.Errorf instead)?$'
-      - '^platforms\.DefaultString(# use platforms\.Format(platforms\.DefaultSpec()) instead\.)?$'
-  gosec:
-    excludes:
-      - G204  # Audit use of command execution
-      - G402  # TLS MinVersion too low
-      - G115  # integer overflow conversion (TODO: verify these)
-    config:
-      G306: "0644"
-  testifylint:
-    disable:
-      # disable rules that reduce the test condition
-      - "empty"
-      - "bool-compare"
-      - "len"
-      - "negative-positive"
+      - linters:
+          - revive
+        text: stutters
+      - linters:
+          - revive
+        text: empty-block
+      - linters:
+          - revive
+        text: superfluous-else
+      - linters:
+          - revive
+        text: unused-parameter
+      - linters:
+          - revive
+        text: redefines-builtin-id
+      - linters:
+          - revive
+        text: if-return
+    paths:
+      - .*\.pb\.go$
 
+formatters:
+  enable:
+    - gofmt
+    - goimports
+  exclusions:
+    generated: lax
+    paths:
+      - .*\.pb\.go$
 
 issues:
-  exclude-files:
-    - ".*\\.pb\\.go$"
-  exclude-rules:
-    - linters:
-        - revive
-      text: "stutters"
-    - linters:
-        - revive
-      text: "empty-block"
-    - linters:
-        - revive
-      text: "superfluous-else"
-    - linters:
-        - revive
-      text: "unused-parameter"
-    - linters:
-        - revive
-      text: "redefines-builtin-id"
-    - linters:
-        - revive
-      text: "if-return"
-
-  # show all
   max-issues-per-linter: 0
   max-same-issues: 0
diff --git a/Dockerfile b/Dockerfile
index 71b726c5..e8878dd7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
 # syntax=docker/dockerfile:1
 
-ARG GO_VERSION=1.23
+ARG GO_VERSION=1.24
 ARG ALPINE_VERSION=3.21
 ARG XX_VERSION=1.6.1
 
diff --git a/bake/bake.go b/bake/bake.go
index fd7f901b..ad626ee6 100644
--- a/bake/bake.go
+++ b/bake/bake.go
@@ -483,8 +483,7 @@ func (c Config) expandTargets(pattern string) ([]string, error) {
 func (c Config) loadLinks(name string, t *Target, m map[string]*Target, o map[string]map[string]Override, visited []string, ent *EntitlementConf) error {
 	visited = append(visited, name)
 	for _, v := range t.Contexts {
-		if strings.HasPrefix(v, "target:") {
-			target := strings.TrimPrefix(v, "target:")
+		if target, ok := strings.CutPrefix(v, "target:"); ok {
 			if target == name {
 				return errors.Errorf("target %s cannot link to itself", target)
 			}
@@ -1275,8 +1274,8 @@ func collectLocalPaths(t build.Inputs) []string {
 		if v, ok := isLocalPath(t.DockerfilePath); ok {
 			out = append(out, v)
 		}
-	} else if strings.HasPrefix(t.ContextPath, "cwd://") {
-		out = append(out, strings.TrimPrefix(t.ContextPath, "cwd://"))
+	} else if v, ok := strings.CutPrefix(t.ContextPath, "cwd://"); ok {
+		out = append(out, v)
 	}
 	for _, v := range t.NamedContexts {
 		if v.State != nil {
@@ -1328,11 +1327,11 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
 		bi.DockerfileInline = *t.DockerfileInline
 	}
 	updateContext(&bi, inp)
-	if strings.HasPrefix(bi.DockerfilePath, "cwd://") {
+	if v, ok := strings.CutPrefix(bi.DockerfilePath, "cwd://"); ok {
 		// If Dockerfile is local for a remote invocation, we first check if
 		// it's not outside the working directory and then resolve it to an
 		// absolute path.
-		bi.DockerfilePath = path.Clean(strings.TrimPrefix(bi.DockerfilePath, "cwd://"))
+		bi.DockerfilePath = path.Clean(v)
 		var err error
 		bi.DockerfilePath, err = filepath.Abs(bi.DockerfilePath)
 		if err != nil {
@@ -1357,15 +1356,15 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
 			return nil, errors.Errorf("reading a dockerfile for a remote build invocation is currently not supported")
 		}
 	}
-	if strings.HasPrefix(bi.ContextPath, "cwd://") {
-		bi.ContextPath = path.Clean(strings.TrimPrefix(bi.ContextPath, "cwd://"))
+	if v, ok := strings.CutPrefix(bi.ContextPath, "cwd://"); ok {
+		bi.ContextPath = path.Clean(v)
 	}
 	if !build.IsRemoteURL(bi.ContextPath) && bi.ContextState == nil && !filepath.IsAbs(bi.DockerfilePath) {
 		bi.DockerfilePath = filepath.Join(bi.ContextPath, bi.DockerfilePath)
 	}
 	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 v, ok := strings.CutPrefix(v.Path, "cwd://"); ok {
+			bi.NamedContexts[k] = build.NamedContext{Path: path.Clean(v)}
 		}
 	}
 
diff --git a/bake/compose.go b/bake/compose.go
index 931fec36..1ca046d0 100644
--- a/bake/compose.go
+++ b/bake/compose.go
@@ -62,7 +62,6 @@ func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Conf
 		g := &Group{Name: "default"}
 
 		for _, s := range cfg.Services {
-			s := s
 			if s.Build == nil {
 				continue
 			}
@@ -144,7 +143,6 @@ func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Conf
 			// compose does not support nil values for labels
 			labels := map[string]*string{}
 			for k, v := range s.Build.Labels {
-				v := v
 				labels[k] = &v
 			}
 
diff --git a/bake/hclparser/hclparser.go b/bake/hclparser/hclparser.go
index 16ffc454..d132e966 100644
--- a/bake/hclparser/hclparser.go
+++ b/bake/hclparser/hclparser.go
@@ -781,7 +781,6 @@ func Parse(b hcl.Body, opt Opt, val any) (*ParseMeta, hcl.Diagnostics) {
 	}
 
 	for _, a := range content.Attributes {
-		a := a
 		return nil, hcl.Diagnostics{
 			&hcl.Diagnostic{
 				Severity: hcl.DiagError,
@@ -834,7 +833,6 @@ func Parse(b hcl.Body, opt Opt, val any) (*ParseMeta, hcl.Diagnostics) {
 				context = subject
 			} else {
 				for _, block := range blocks.Blocks {
-					block := block
 					if block.Type == "function" && len(block.Labels) == 1 && block.Labels[0] == k {
 						subject = block.LabelRanges[0].Ptr()
 						context = block.DefRange.Ptr()
@@ -903,7 +901,6 @@ func Parse(b hcl.Body, opt Opt, val any) (*ParseMeta, hcl.Diagnostics) {
 
 	diags = hcl.Diagnostics{}
 	for _, b := range content.Blocks {
-		b := b
 		v := reflect.ValueOf(val)
 
 		err := p.resolveBlock(b, nil)
@@ -936,7 +933,7 @@ func Parse(b hcl.Body, opt Opt, val any) (*ParseMeta, hcl.Diagnostics) {
 				}
 			}
 			if exists {
-				if m := oldValue.Value.MethodByName("Merge"); m.IsValid() {
+				if m := oldValue.MethodByName("Merge"); m.IsValid() {
 					m.Call([]reflect.Value{vv})
 				} else {
 					v.Elem().Field(t.idx).Index(oldValue.idx).Set(vv)
diff --git a/bake/hclparser/stdlib.go b/bake/hclparser/stdlib.go
index df04bb8a..d8ef0004 100644
--- a/bake/hclparser/stdlib.go
+++ b/bake/hclparser/stdlib.go
@@ -144,7 +144,7 @@ func indexOfFunc() function.Function {
 		},
 		Type: function.StaticReturnType(cty.Number),
 		Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
-			if !(args[0].Type().IsListType() || args[0].Type().IsTupleType()) {
+			if !args[0].Type().IsListType() && !args[0].Type().IsTupleType() {
 				return cty.NilVal, errors.New("argument must be a list or tuple")
 			}
 
diff --git a/build/build.go b/build/build.go
index 0414b350..0f8fca6d 100644
--- a/build/build.go
+++ b/build/build.go
@@ -44,7 +44,7 @@ import (
 	"github.com/moby/buildkit/util/progress/progresswriter"
 	"github.com/moby/buildkit/util/tracing"
 	"github.com/opencontainers/go-digest"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"github.com/tonistiigi/fsutil"
@@ -76,7 +76,7 @@ type Options struct {
 	NetworkMode                string
 	NoCache                    bool
 	NoCacheFilter              []string
-	Platforms                  []specs.Platform
+	Platforms                  []ocispecs.Platform
 	Pull                       bool
 	SecretSpecs                []*controllerapi.Secret
 	SSHSpecs                   []*controllerapi.SSH
@@ -383,7 +383,6 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[
 						wg.Add(1)
 						sharedSessionsWG[node.Name] = wg
 						for _, s := range sessions {
-							s := s
 							eg.Go(func() error {
 								return s.Run(baseCtx, c.Dialer())
 							})
@@ -600,7 +599,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[
 
 				if pushNames != "" {
 					err := progress.Write(pw, fmt.Sprintf("merging manifest list %s", pushNames), func() error {
-						descs := make([]specs.Descriptor, 0, len(res))
+						descs := make([]ocispecs.Descriptor, 0, len(res))
 
 						for _, r := range res {
 							s, ok := r.ExporterResponse[exptypes.ExporterImageDescriptorKey]
@@ -609,7 +608,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[
 								if err != nil {
 									return err
 								}
-								var desc specs.Descriptor
+								var desc ocispecs.Descriptor
 								if err := json.Unmarshal(dt, &desc); err != nil {
 									return errors.Wrapf(err, "failed to unmarshal descriptor %s", s)
 								}
@@ -622,7 +621,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[
 							// mediatype value in the Accept header does not seem to matter.
 							s, ok = r.ExporterResponse[exptypes.ExporterImageDigestKey]
 							if ok {
-								descs = append(descs, specs.Descriptor{
+								descs = append(descs, ocispecs.Descriptor{
 									Digest:    digest.Digest(s),
 									MediaType: images.MediaTypeDockerSchema2ManifestList,
 									Size:      -1,
diff --git a/build/dial.go b/build/dial.go
index b842419a..571d3c1e 100644
--- a/build/dial.go
+++ b/build/dial.go
@@ -9,11 +9,11 @@ import (
 	"github.com/containerd/platforms"
 	"github.com/docker/buildx/builder"
 	"github.com/docker/buildx/util/progress"
-	v1 "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
-func Dial(ctx context.Context, nodes []builder.Node, pw progress.Writer, platform *v1.Platform) (net.Conn, error) {
+func Dial(ctx context.Context, nodes []builder.Node, pw progress.Writer, platform *ocispecs.Platform) (net.Conn, error) {
 	nodes, err := filterAvailableNodes(nodes)
 	if err != nil {
 		return nil, err
@@ -23,9 +23,9 @@ func Dial(ctx context.Context, nodes []builder.Node, pw progress.Writer, platfor
 		return nil, errors.New("no nodes available")
 	}
 
-	var pls []v1.Platform
+	var pls []ocispecs.Platform
 	if platform != nil {
-		pls = []v1.Platform{*platform}
+		pls = []ocispecs.Platform{*platform}
 	}
 
 	opts := map[string]Options{"default": {Platforms: pls}}
diff --git a/build/driver.go b/build/driver.go
index eaae1411..6eab6db8 100644
--- a/build/driver.go
+++ b/build/driver.go
@@ -14,7 +14,7 @@ import (
 	gateway "github.com/moby/buildkit/frontend/gateway/client"
 	"github.com/moby/buildkit/util/flightcontrol"
 	"github.com/moby/buildkit/util/tracing"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"go.opentelemetry.io/otel/trace"
 	"golang.org/x/sync/errgroup"
@@ -23,7 +23,7 @@ import (
 type resolvedNode struct {
 	resolver    *nodeResolver
 	driverIndex int
-	platforms   []specs.Platform
+	platforms   []ocispecs.Platform
 }
 
 func (dp resolvedNode) Node() builder.Node {
@@ -46,7 +46,7 @@ func (dp resolvedNode) BuildOpts(ctx context.Context) (gateway.BuildOpts, error)
 	return opts[0], nil
 }
 
-type matchMaker func(specs.Platform) platforms.MatchComparer
+type matchMaker func(ocispecs.Platform) platforms.MatchComparer
 
 type cachedGroup[T any] struct {
 	g       flightcontrol.Group[T]
@@ -112,7 +112,7 @@ func (r *nodeResolver) Resolve(ctx context.Context, opt map[string]Options, pw p
 			return nil, err
 		}
 		eg, egCtx := errgroup.WithContext(ctx)
-		workers := make([][]specs.Platform, len(clients))
+		workers := make([][]ocispecs.Platform, len(clients))
 		for i, c := range clients {
 			i, c := i, c
 			if c == nil {
@@ -124,7 +124,7 @@ func (r *nodeResolver) Resolve(ctx context.Context, opt map[string]Options, pw p
 					return errors.Wrap(err, "listing workers")
 				}
 
-				ps := make(map[string]specs.Platform, len(ww))
+				ps := make(map[string]ocispecs.Platform, len(ww))
 				for _, w := range ww {
 					for _, p := range w.Platforms {
 						pk := platforms.Format(platforms.Normalize(p))
@@ -145,7 +145,7 @@ func (r *nodeResolver) Resolve(ctx context.Context, opt map[string]Options, pw p
 		// (this time we don't care about imperfect matches)
 		nodes = map[string][]*resolvedNode{}
 		for k, opt := range opt {
-			node, _, err := r.resolve(ctx, opt.Platforms, pw, platforms.Only, func(idx int, n builder.Node) []specs.Platform {
+			node, _, err := r.resolve(ctx, opt.Platforms, pw, platforms.Only, func(idx int, n builder.Node) []ocispecs.Platform {
 				return workers[idx]
 			})
 			if err != nil {
@@ -173,7 +173,7 @@ func (r *nodeResolver) Resolve(ctx context.Context, opt map[string]Options, pw p
 	return nodes, nil
 }
 
-func (r *nodeResolver) resolve(ctx context.Context, ps []specs.Platform, pw progress.Writer, matcher matchMaker, additional func(idx int, n builder.Node) []specs.Platform) ([]*resolvedNode, bool, error) {
+func (r *nodeResolver) resolve(ctx context.Context, ps []ocispecs.Platform, pw progress.Writer, matcher matchMaker, additional func(idx int, n builder.Node) []ocispecs.Platform) ([]*resolvedNode, bool, error) {
 	if len(r.nodes) == 0 {
 		return nil, true, nil
 	}
@@ -203,7 +203,7 @@ func (r *nodeResolver) resolve(ctx context.Context, ps []specs.Platform, pw prog
 				driverIndex: idx,
 			}
 			if len(ps) > 0 {
-				node.platforms = []specs.Platform{ps[i]}
+				node.platforms = []ocispecs.Platform{ps[i]}
 			}
 			nodes = append(nodes, node)
 		}
@@ -216,9 +216,9 @@ func (r *nodeResolver) resolve(ctx context.Context, ps []specs.Platform, pw prog
 	return nodes, perfect, nil
 }
 
-func (r *nodeResolver) get(p specs.Platform, matcher matchMaker, additionalPlatforms func(int, builder.Node) []specs.Platform) int {
+func (r *nodeResolver) get(p ocispecs.Platform, matcher matchMaker, additionalPlatforms func(int, builder.Node) []ocispecs.Platform) int {
 	best := -1
-	bestPlatform := specs.Platform{}
+	bestPlatform := ocispecs.Platform{}
 	for i, node := range r.nodes {
 		platforms := node.Platforms
 		if additionalPlatforms != nil {
diff --git a/build/git.go b/build/git.go
index 4672860c..de30c510 100644
--- a/build/git.go
+++ b/build/git.go
@@ -12,7 +12,7 @@ import (
 	"github.com/docker/buildx/util/gitutil"
 	"github.com/docker/buildx/util/osutil"
 	"github.com/moby/buildkit/client"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
@@ -96,7 +96,7 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) (
 			sha += "-dirty"
 		}
 		if setGitLabels {
-			res["label:"+specs.AnnotationRevision] = sha
+			res["label:"+ocispecs.AnnotationRevision] = sha
 		}
 		if setGitInfo {
 			res["vcs:revision"] = sha
@@ -105,7 +105,7 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) (
 
 	if rurl, err := gitc.RemoteURL(); err == nil && rurl != "" {
 		if setGitLabels {
-			res["label:"+specs.AnnotationSource] = rurl
+			res["label:"+ocispecs.AnnotationSource] = rurl
 		}
 		if setGitInfo {
 			res["vcs:source"] = rurl
diff --git a/build/opt.go b/build/opt.go
index 74fcdb38..a1014022 100644
--- a/build/opt.go
+++ b/build/opt.go
@@ -394,7 +394,7 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp *Inputs, pw pro
 		if err != nil && err != io.EOF {
 			return nil, errors.Wrap(err, "failed to peek context header from STDIN")
 		}
-		if !(err == io.EOF && len(magic) == 0) {
+		if err != io.EOF || len(magic) != 0 {
 			if isArchive(magic) {
 				// stdin is context
 				up := uploadprovider.New()
@@ -503,8 +503,7 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp *Inputs, pw pro
 		}
 
 		// handle OCI layout
-		if strings.HasPrefix(v.Path, "oci-layout://") {
-			localPath := strings.TrimPrefix(v.Path, "oci-layout://")
+		if localPath, ok := strings.CutPrefix(v.Path, "oci-layout://"); ok {
 			localPath, dig, hasDigest := strings.Cut(localPath, "@")
 			localPath, tag, hasTag := strings.Cut(localPath, ":")
 			if !hasTag {
diff --git a/build/provenance.go b/build/provenance.go
index b6cca56f..b355f8e5 100644
--- a/build/provenance.go
+++ b/build/provenance.go
@@ -92,7 +92,6 @@ func fetchProvenance(ctx context.Context, c *client.Client, ref string, mode con
 			})
 		} else if ev.Record.Results != nil {
 			for platform, res := range ev.Record.Results {
-				platform := platform
 				desc := lookupProvenance(res)
 				if desc == nil {
 					continue
diff --git a/build/result.go b/build/result.go
index cb38fdcf..904907ce 100644
--- a/build/result.go
+++ b/build/result.go
@@ -14,7 +14,7 @@ import (
 	"github.com/moby/buildkit/solver/errdefs"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/solver/result"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/sync/errgroup"
@@ -354,9 +354,9 @@ func containerConfigFromResult(res *gateway.Result, cfg *controllerapi.InvokeCon
 
 func populateProcessConfigFromResult(req *gateway.StartRequest, res *gateway.Result, cfg *controllerapi.InvokeConfig) error {
 	imgData := res.Metadata[exptypes.ExporterImageConfigKey]
-	var img *specs.Image
+	var img *ocispecs.Image
 	if len(imgData) > 0 {
-		img = &specs.Image{}
+		img = &ocispecs.Image{}
 		if err := json.Unmarshal(imgData, img); err != nil {
 			return err
 		}
@@ -410,9 +410,9 @@ func containerConfigFromError(solveErr *errdefs.SolveError, cfg *controllerapi.I
 	}
 	var mounts []gateway.Mount
 	for i, mnt := range exec.Mounts {
-		rid := solveErr.Solve.MountIDs[i]
+		rid := solveErr.MountIDs[i]
 		if cfg.Initial {
-			rid = solveErr.Solve.InputIDs[i]
+			rid = solveErr.InputIDs[i]
 		}
 		mounts = append(mounts, gateway.Mount{
 			Selector:  mnt.Selector,
@@ -477,7 +477,7 @@ func execOpFromError(solveErr *errdefs.SolveError) (*pb.ExecOp, error) {
 	if solveErr == nil {
 		return nil, errors.Errorf("no error is available")
 	}
-	switch op := solveErr.Solve.Op.GetOp().(type) {
+	switch op := solveErr.Op.GetOp().(type) {
 	case *pb.Op_Exec:
 		return op.Exec, nil
 	default:
diff --git a/builder/builder.go b/builder/builder.go
index d82af210..d26c4237 100644
--- a/builder/builder.go
+++ b/builder/builder.go
@@ -122,7 +122,7 @@ func New(dockerCli command.Cli, opts ...Option) (_ *Builder, err error) {
 
 // Validate validates builder context
 func (b *Builder) Validate() error {
-	if b.NodeGroup != nil && b.NodeGroup.DockerContext {
+	if b.NodeGroup != nil && b.DockerContext {
 		list, err := b.opts.dockerCli.ContextStore().List()
 		if err != nil {
 			return err
@@ -144,7 +144,7 @@ func (b *Builder) ContextName() string {
 		return ""
 	}
 	for _, cb := range ctxbuilders {
-		if b.NodeGroup.Driver == "docker" && len(b.NodeGroup.Nodes) == 1 && b.NodeGroup.Nodes[0].Endpoint == cb.Name {
+		if b.Driver == "docker" && len(b.NodeGroup.Nodes) == 1 && b.NodeGroup.Nodes[0].Endpoint == cb.Name {
 			return cb.Name
 		}
 	}
@@ -254,7 +254,7 @@ func (b *Builder) Factory(ctx context.Context, dialMeta map[string][]string) (_
 			if err != nil {
 				return
 			}
-			b.Driver = b.driverFactory.Factory.Name()
+			b.Driver = b.driverFactory.Name()
 		}
 	})
 	return b.driverFactory.Factory, err
@@ -309,7 +309,7 @@ func GetBuilders(dockerCli command.Cli, txn *store.Txn) ([]*Builder, error) {
 			return nil, err
 		}
 		builders[i] = b
-		seen[b.NodeGroup.Name] = struct{}{}
+		seen[b.Name] = struct{}{}
 	}
 
 	for _, c := range contexts {
@@ -524,7 +524,7 @@ func Create(ctx context.Context, txn *store.Txn, dockerCli command.Cli, opts Cre
 	}
 
 	cancelCtx, cancel := context.WithCancelCause(ctx)
-	timeoutCtx, _ := context.WithTimeoutCause(cancelCtx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet,lostcancel // no need to manually cancel this context as we already rely on parent
+	timeoutCtx, _ := context.WithTimeoutCause(cancelCtx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet // no need to manually cancel this context as we already rely on parent
 	defer func() { cancel(errors.WithStack(context.Canceled)) }()
 
 	nodes, err := b.LoadNodes(timeoutCtx, WithData())
diff --git a/builder/node.go b/builder/node.go
index b582503b..b1bccbf7 100644
--- a/builder/node.go
+++ b/builder/node.go
@@ -183,7 +183,7 @@ func (b *Builder) LoadNodes(ctx context.Context, opts ...LoadNodesOption) (_ []N
 			// not append (remove the static nodes in the store)
 			b.NodeGroup.Nodes = dynamicNodes
 			b.nodes = nodes
-			b.NodeGroup.Dynamic = true
+			b.Dynamic = true
 		}
 	}
 
diff --git a/commands/bake.go b/commands/bake.go
index 49a23c67..e9636e2f 100644
--- a/commands/bake.go
+++ b/commands/bake.go
@@ -136,7 +136,7 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
 
 	// instance only needed for reading remote bake files or building
 	var driverType string
-	if url != "" || !(in.print || in.list != "") {
+	if url != "" || (!in.print && in.list == "") {
 		b, err := builder.New(dockerCli,
 			builder.WithName(in.builder),
 			builder.WithContextPathHash(contextPathHash),
@@ -559,8 +559,7 @@ func readBakeFiles(ctx context.Context, nodes []builder.Node, url string, names
 	var rnames []string // remote
 	var anames []string // both
 	for _, v := range names {
-		if strings.HasPrefix(v, "cwd://") {
-			tname := strings.TrimPrefix(v, "cwd://")
+		if tname, ok := strings.CutPrefix(v, "cwd://"); ok {
 			lnames = append(lnames, tname)
 			anames = append(anames, tname)
 		} else {
diff --git a/commands/dial_stdio.go b/commands/dial_stdio.go
index 42c0e365..92024955 100644
--- a/commands/dial_stdio.go
+++ b/commands/dial_stdio.go
@@ -12,7 +12,7 @@ import (
 	"github.com/docker/cli/cli/command"
 	"github.com/moby/buildkit/util/appcontext"
 	"github.com/moby/buildkit/util/progress/progressui"
-	v1 "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 	"golang.org/x/sync/errgroup"
@@ -49,7 +49,7 @@ func runDialStdio(dockerCli command.Cli, opts stdioOptions) error {
 		return err
 	}
 
-	var p *v1.Platform
+	var p *ocispecs.Platform
 	if opts.platform != "" {
 		pp, err := platforms.Parse(opts.platform)
 		if err != nil {
diff --git a/commands/history/export.go b/commands/history/export.go
index c0c0f68d..af8149a7 100644
--- a/commands/history/export.go
+++ b/commands/history/export.go
@@ -20,10 +20,11 @@ import (
 )
 
 type exportOptions struct {
-	builder string
-	refs    []string
-	output  string
-	all     bool
+	builder  string
+	refs     []string
+	output   string
+	all      bool
+	finalize bool
 }
 
 func runExport(ctx context.Context, dockerCli command.Cli, opts exportOptions) error {
@@ -62,6 +63,26 @@ func runExport(ctx context.Context, dockerCli command.Cli, opts exportOptions) e
 			return errors.Errorf("no record found for ref %q", ref)
 		}
 
+		if opts.finalize {
+			var finalized bool
+			for _, rec := range recs {
+				if rec.Trace == nil {
+					finalized = true
+					if err := finalizeRecord(ctx, rec.Ref, nodes); err != nil {
+						return err
+					}
+				}
+			}
+			if finalized {
+				recs, err = queryRecords(ctx, ref, nodes, &queryOptions{
+					CompletedOnly: true,
+				})
+				if err != nil {
+					return err
+				}
+			}
+		}
+
 		if ref == "" {
 			slices.SortFunc(recs, func(a, b historyRecord) int {
 				return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
@@ -139,8 +160,8 @@ func exportCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
 	var options exportOptions
 
 	cmd := &cobra.Command{
-		Use:   "export [OPTIONS] [REF]",
-		Short: "Export a build into Docker Desktop bundle",
+		Use:   "export [OPTIONS] [REF...]",
+		Short: "Export build records into Docker Desktop bundle",
 		RunE: func(cmd *cobra.Command, args []string) error {
 			if options.all && len(args) > 0 {
 				return errors.New("cannot specify refs when using --all")
@@ -154,7 +175,8 @@ func exportCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
 
 	flags := cmd.Flags()
 	flags.StringVarP(&options.output, "output", "o", "", "Output file path")
-	flags.BoolVar(&options.all, "all", false, "Export all records for the builder")
+	flags.BoolVar(&options.all, "all", false, "Export all build records for the builder")
+	flags.BoolVar(&options.finalize, "finalize", false, "Ensure build records are finalized before exporting")
 
 	return cmd
 }
diff --git a/commands/history/import.go b/commands/history/import.go
index afd95608..ff43d6d8 100644
--- a/commands/history/import.go
+++ b/commands/history/import.go
@@ -119,8 +119,8 @@ func importCmd(dockerCli command.Cli, _ RootOptions) *cobra.Command {
 	var options importOptions
 
 	cmd := &cobra.Command{
-		Use:   "import [OPTIONS] < bundle.dockerbuild",
-		Short: "Import a build into Docker Desktop",
+		Use:   "import [OPTIONS] -",
+		Short: "Import build records into Docker Desktop",
 		Args:  cobra.NoArgs,
 		RunE: func(cmd *cobra.Command, args []string) error {
 			return runImport(cmd.Context(), dockerCli, options)
diff --git a/commands/history/inspect.go b/commands/history/inspect.go
index 0704e2f6..6fd2a252 100644
--- a/commands/history/inspect.go
+++ b/commands/history/inspect.go
@@ -335,9 +335,9 @@ workers0:
 			out.Error.Sources = errsources.Bytes()
 			var ve *errdefs.VertexError
 			if errors.As(retErr, &ve) {
-				dgst, err := digest.Parse(ve.Vertex.Digest)
+				dgst, err := digest.Parse(ve.Digest)
 				if err != nil {
-					return errors.Wrapf(err, "failed to parse vertex digest %s", ve.Vertex.Digest)
+					return errors.Wrapf(err, "failed to parse vertex digest %s", ve.Digest)
 				}
 				name, logs, err := loadVertexLogs(ctx, c, rec.Ref, dgst, 16)
 				if err != nil {
@@ -525,9 +525,10 @@ workers0:
 	}
 	fmt.Fprintf(tw, "Duration:\t%s%s\n", formatDuration(out.Duration), statusStr)
 
-	if out.Status == statusError {
+	switch out.Status {
+	case statusError:
 		fmt.Fprintf(tw, "Error:\t%s %s\n", codes.Code(rec.Error.Code).String(), rec.Error.Message)
-	} else if out.Status == statusCanceled {
+	case statusCanceled:
 		fmt.Fprintf(tw, "Status:\tCanceled\n")
 	}
 
@@ -648,7 +649,7 @@ func inspectCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
 
 	cmd := &cobra.Command{
 		Use:   "inspect [OPTIONS] [REF]",
-		Short: "Inspect a build",
+		Short: "Inspect a build record",
 		Args:  cobra.MaximumNArgs(1),
 		RunE: func(cmd *cobra.Command, args []string) error {
 			if len(args) > 0 {
@@ -868,9 +869,9 @@ func printTable(w io.Writer, kvs []keyValueOutput, title string) {
 func readKeyValues(attrs map[string]string, prefix string) []keyValueOutput {
 	var out []keyValueOutput
 	for k, v := range attrs {
-		if strings.HasPrefix(k, prefix) {
+		if name, ok := strings.CutPrefix(k, prefix); ok {
 			out = append(out, keyValueOutput{
-				Name:  strings.TrimPrefix(k, prefix),
+				Name:  name,
 				Value: v,
 			})
 		}
diff --git a/commands/history/inspect_attachment.go b/commands/history/inspect_attachment.go
index 71f7ec7a..8fb01191 100644
--- a/commands/history/inspect_attachment.go
+++ b/commands/history/inspect_attachment.go
@@ -113,7 +113,7 @@ func attachmentCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
 
 	cmd := &cobra.Command{
 		Use:   "attachment [OPTIONS] REF [DIGEST]",
-		Short: "Inspect a build attachment",
+		Short: "Inspect a build record attachment",
 		Args:  cobra.RangeArgs(1, 2),
 		RunE: func(cmd *cobra.Command, args []string) error {
 			if len(args) > 0 {
diff --git a/commands/history/logs.go b/commands/history/logs.go
index bd58ba9e..458ee384 100644
--- a/commands/history/logs.go
+++ b/commands/history/logs.go
@@ -63,7 +63,7 @@ func runLogs(ctx context.Context, dockerCli command.Cli, opts logsOptions) error
 		return err
 	}
 
-	var mode progressui.DisplayMode = progressui.DisplayMode(opts.progress)
+	mode := progressui.DisplayMode(opts.progress)
 	if mode == progressui.AutoMode {
 		mode = progressui.PlainMode
 	}
@@ -98,7 +98,7 @@ func logsCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
 
 	cmd := &cobra.Command{
 		Use:   "logs [OPTIONS] [REF]",
-		Short: "Print the logs of a build",
+		Short: "Print the logs of a build record",
 		Args:  cobra.MaximumNArgs(1),
 		RunE: func(cmd *cobra.Command, args []string) error {
 			if len(args) > 0 {
diff --git a/commands/history/ls.go b/commands/history/ls.go
index c902a343..f6135164 100644
--- a/commands/history/ls.go
+++ b/commands/history/ls.go
@@ -107,7 +107,7 @@ func lsCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
 	var options lsOptions
 
 	cmd := &cobra.Command{
-		Use:   "ls",
+		Use:   "ls [OPTIONS]",
 		Short: "List build records",
 		Args:  cli.NoArgs,
 		RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/commands/history/open.go b/commands/history/open.go
index 8bab4b8f..aa047b29 100644
--- a/commands/history/open.go
+++ b/commands/history/open.go
@@ -57,7 +57,7 @@ func openCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
 
 	cmd := &cobra.Command{
 		Use:   "open [OPTIONS] [REF]",
-		Short: "Open a build in Docker Desktop",
+		Short: "Open a build record in Docker Desktop",
 		Args:  cobra.MaximumNArgs(1),
 		RunE: func(cmd *cobra.Command, args []string) error {
 			if len(args) > 0 {
diff --git a/commands/history/rm.go b/commands/history/rm.go
index 596fd567..4f5338d9 100644
--- a/commands/history/rm.go
+++ b/commands/history/rm.go
@@ -43,7 +43,6 @@ func runRm(ctx context.Context, dockerCli command.Cli, opts rmOptions) error {
 
 	eg, ctx := errgroup.WithContext(ctx)
 	for i, node := range nodes {
-		node := node
 		eg.Go(func() error {
 			if node.Driver == nil {
 				return nil
diff --git a/commands/history/trace.go b/commands/history/trace.go
index d1e04ad0..b841ce35 100644
--- a/commands/history/trace.go
+++ b/commands/history/trace.go
@@ -17,7 +17,6 @@ import (
 	"github.com/docker/buildx/util/otelutil"
 	"github.com/docker/buildx/util/otelutil/jaeger"
 	"github.com/docker/cli/cli/command"
-	controlapi "github.com/moby/buildkit/api/services/control"
 	"github.com/opencontainers/go-digest"
 	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/browser"
@@ -57,14 +56,7 @@ func loadTrace(ctx context.Context, ref string, nodes []builder.Node) (string, [
 		// build is complete but no trace yet. try to finalize the trace
 		time.Sleep(1 * time.Second) // give some extra time for last parts of trace to be written
 
-		c, err := rec.node.Driver.Client(ctx)
-		if err != nil {
-			return "", nil, err
-		}
-		_, err = c.ControlClient().UpdateBuildHistory(ctx, &controlapi.UpdateBuildHistoryRequest{
-			Ref:      rec.Ref,
-			Finalize: true,
-		})
+		err := finalizeRecord(ctx, rec.Ref, []builder.Node{*rec.node})
 		if err != nil {
 			return "", nil, err
 		}
@@ -222,7 +214,7 @@ func traceCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
 
 	flags := cmd.Flags()
 	flags.StringVar(&options.addr, "addr", "127.0.0.1:0", "Address to bind the UI server")
-	flags.StringVar(&options.compare, "compare", "", "Compare with another build reference")
+	flags.StringVar(&options.compare, "compare", "", "Compare with another build record")
 
 	return cmd
 }
diff --git a/commands/history/utils.go b/commands/history/utils.go
index 95c8702e..825ca5e2 100644
--- a/commands/history/utils.go
+++ b/commands/history/utils.go
@@ -139,7 +139,6 @@ func queryRecords(ctx context.Context, ref string, nodes []builder.Node, opts *q
 
 	eg, ctx := errgroup.WithContext(ctx)
 	for _, node := range nodes {
-		node := node
 		eg.Go(func() error {
 			if node.Driver == nil {
 				return nil
@@ -248,6 +247,28 @@ func queryRecords(ctx context.Context, ref string, nodes []builder.Node, opts *q
 	return out, nil
 }
 
+func finalizeRecord(ctx context.Context, ref string, nodes []builder.Node) error {
+	eg, ctx := errgroup.WithContext(ctx)
+	for _, node := range nodes {
+		node := node
+		eg.Go(func() error {
+			if node.Driver == nil {
+				return nil
+			}
+			c, err := node.Driver.Client(ctx)
+			if err != nil {
+				return err
+			}
+			_, err = c.ControlClient().UpdateBuildHistory(ctx, &controlapi.UpdateBuildHistoryRequest{
+				Ref:      ref,
+				Finalize: true,
+			})
+			return err
+		})
+	}
+	return eg.Wait()
+}
+
 func formatDuration(d time.Duration) string {
 	if d < time.Minute {
 		return fmt.Sprintf("%.1fs", d.Seconds())
diff --git a/commands/imagetools/create.go b/commands/imagetools/create.go
index fee838c6..fc2ad066 100644
--- a/commands/imagetools/create.go
+++ b/commands/imagetools/create.go
@@ -16,7 +16,7 @@ import (
 	"github.com/docker/cli/cli/command"
 	"github.com/moby/buildkit/util/progress/progressui"
 	"github.com/opencontainers/go-digest"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 	"golang.org/x/sync/errgroup"
@@ -184,7 +184,6 @@ func runCreate(ctx context.Context, dockerCli command.Cli, in createOptions, arg
 	pw := progress.WithPrefix(printer, "internal", true)
 
 	for _, t := range tags {
-		t := t
 		eg.Go(func() error {
 			return progress.Wrap(fmt.Sprintf("pushing %s", t.String()), pw.Write, func(sub progress.SubLogger) error {
 				eg2, _ := errgroup.WithContext(ctx)
@@ -246,7 +245,7 @@ func parseSource(in string) (*imagetools.Source, error) {
 	dgst, err := digest.Parse(in)
 	if err == nil {
 		return &imagetools.Source{
-			Desc: ocispec.Descriptor{
+			Desc: ocispecs.Descriptor{
 				Digest: dgst,
 			},
 		}, nil
@@ -274,7 +273,7 @@ func createCmd(dockerCli command.Cli, opts RootOptions) *cobra.Command {
 	var options createOptions
 
 	cmd := &cobra.Command{
-		Use:   "create [OPTIONS] [SOURCE] [SOURCE...]",
+		Use:   "create [OPTIONS] [SOURCE...]",
 		Short: "Create a new image based on source images",
 		RunE: func(cmd *cobra.Command, args []string) error {
 			options.builder = *opts.Builder
@@ -295,9 +294,9 @@ func createCmd(dockerCli command.Cli, opts RootOptions) *cobra.Command {
 	return cmd
 }
 
-func mergeDesc(d1, d2 ocispec.Descriptor) (ocispec.Descriptor, error) {
+func mergeDesc(d1, d2 ocispecs.Descriptor) (ocispecs.Descriptor, error) {
 	if d2.Size != 0 && d1.Size != d2.Size {
-		return ocispec.Descriptor{}, errors.Errorf("invalid size mismatch for %s, %d != %d", d1.Digest, d2.Size, d1.Size)
+		return ocispecs.Descriptor{}, errors.Errorf("invalid size mismatch for %s, %d != %d", d1.Digest, d2.Size, d1.Size)
 	}
 	if d2.MediaType != "" {
 		d1.MediaType = d2.MediaType
diff --git a/commands/inspect.go b/commands/inspect.go
index eeae99ea..06c0da4e 100644
--- a/commands/inspect.go
+++ b/commands/inspect.go
@@ -36,7 +36,7 @@ func runInspect(ctx context.Context, dockerCli command.Cli, in inspectOptions) e
 	}
 
 	timeoutCtx, cancel := context.WithCancelCause(ctx)
-	timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet,lostcancel // no need to manually cancel this context as we already rely on parent
+	timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet // no need to manually cancel this context as we already rely on parent
 	defer func() { cancel(errors.WithStack(context.Canceled)) }()
 
 	nodes, err := b.LoadNodes(timeoutCtx, builder.WithData())
@@ -54,8 +54,8 @@ func runInspect(ctx context.Context, dockerCli command.Cli, in inspectOptions) e
 	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
 	fmt.Fprintf(w, "Name:\t%s\n", b.Name)
 	fmt.Fprintf(w, "Driver:\t%s\n", b.Driver)
-	if !b.NodeGroup.LastActivity.IsZero() {
-		fmt.Fprintf(w, "Last Activity:\t%v\n", b.NodeGroup.LastActivity)
+	if !b.LastActivity.IsZero() {
+		fmt.Fprintf(w, "Last Activity:\t%v\n", b.LastActivity)
 	}
 
 	if err != nil {
diff --git a/commands/ls.go b/commands/ls.go
index 8c247679..cf57d4c6 100644
--- a/commands/ls.go
+++ b/commands/ls.go
@@ -60,7 +60,7 @@ func runLs(ctx context.Context, dockerCli command.Cli, in lsOptions) error {
 	}
 
 	timeoutCtx, cancel := context.WithCancelCause(ctx)
-	timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet,lostcancel // no need to manually cancel this context as we already rely on parent
+	timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet // no need to manually cancel this context as we already rely on parent
 	defer func() { cancel(errors.WithStack(context.Canceled)) }()
 
 	eg, _ := errgroup.WithContext(timeoutCtx)
@@ -213,7 +213,17 @@ type lsContext struct {
 }
 
 func (c *lsContext) MarshalJSON() ([]byte, error) {
-	return json.Marshal(c.Builder)
+	// can't marshal c.Builder directly because Builder type has custom MarshalJSON
+	dt, err := json.Marshal(c.Builder.Builder)
+	if err != nil {
+		return nil, err
+	}
+	var m map[string]any
+	if err := json.Unmarshal(dt, &m); err != nil {
+		return nil, err
+	}
+	m["Current"] = c.Builder.Current
+	return json.Marshal(m)
 }
 
 func (c *lsContext) Name() string {
diff --git a/commands/rm.go b/commands/rm.go
index cabbe9aa..712ed456 100644
--- a/commands/rm.go
+++ b/commands/rm.go
@@ -99,7 +99,7 @@ func rmCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
 	var options rmOptions
 
 	cmd := &cobra.Command{
-		Use:   "rm [OPTIONS] [NAME] [NAME...]",
+		Use:   "rm [OPTIONS] [NAME...]",
 		Short: "Remove one or more builder instances",
 		RunE: func(cmd *cobra.Command, args []string) error {
 			options.builders = []string{rootOpts.builder}
@@ -151,7 +151,7 @@ func rmAllInactive(ctx context.Context, txn *store.Txn, dockerCli command.Cli, i
 	}
 
 	timeoutCtx, cancel := context.WithCancelCause(ctx)
-	timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet,lostcancel // no need to manually cancel this context as we already rely on parent
+	timeoutCtx, _ = context.WithTimeoutCause(timeoutCtx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet // no need to manually cancel this context as we already rely on parent
 	defer func() { cancel(errors.WithStack(context.Canceled)) }()
 
 	eg, _ := errgroup.WithContext(timeoutCtx)
diff --git a/controller/build/options.go b/controller/build/options.go
index dba752b9..817f4836 100644
--- a/controller/build/options.go
+++ b/controller/build/options.go
@@ -70,9 +70,8 @@ func ResolveOptionPaths(options *Options) (_ *Options, err error) {
 	for k, v := range options.NamedContexts {
 		if isRemoteURL(v) || strings.HasPrefix(v, "docker-image://") {
 			// url prefix, this is a remote path
-		} else if strings.HasPrefix(v, "oci-layout://") {
+		} else if p, ok := strings.CutPrefix(v, "oci-layout://"); ok {
 			// oci layout prefix, this is a local path
-			p := strings.TrimPrefix(v, "oci-layout://")
 			p, err = filepath.Abs(p)
 			if err != nil {
 				return nil, err
diff --git a/docker-bake.hcl b/docker-bake.hcl
index a65973fa..a3576c73 100644
--- a/docker-bake.hcl
+++ b/docker-bake.hcl
@@ -38,6 +38,9 @@ target "lint" {
   inherits = ["_common"]
   dockerfile = "./hack/dockerfiles/lint.Dockerfile"
   output = ["type=cacheonly"]
+  args = {
+    GOLANGCI_FROM_SOURCE = "true"
+  }
   platforms = GOLANGCI_LINT_MULTIPLATFORM != "" ? [
     "darwin/amd64",
     "darwin/arm64",
diff --git a/docs/reference/buildx_dial-stdio.md b/docs/reference/buildx_dial-stdio.md
index 7fdc84ec..b7c0a290 100644
--- a/docs/reference/buildx_dial-stdio.md
+++ b/docs/reference/buildx_dial-stdio.md
@@ -1,5 +1,9 @@
 # docker buildx dial-stdio
 
+```text
+docker buildx dial-stdio [OPTIONS] < in.fifo > out.fifo &
+```
+
 <!---MARKER_GEN_START-->
 Proxy current stdio streams to builder instance
 
@@ -17,13 +21,15 @@ Proxy current stdio streams to builder instance
 
 ## Description
 
-dial-stdio uses the stdin and stdout streams of the command to proxy to the configured builder instance.
-It is not intended to be used by humans, but rather by other tools that want to interact with the builder instance via BuildKit API.
+dial-stdio uses the stdin and stdout streams of the command to proxy to the
+configured builder instance. It is not intended to be used by humans, but
+rather by other tools that want to interact with the builder instance via
+BuildKit API.
 
 ## Examples
 
 Example go program that uses the dial-stdio command wire up a buildkit client.
-This is for example use only and may not be suitable for production use.
+This is, for example, use only and may not be suitable for production use.
 
 ```go
 client.New(ctx, "", client.WithContextDialer(func(context.Context, string) (net.Conn, error) {
@@ -45,4 +51,4 @@ client.New(ctx, "", client.WithContextDialer(func(context.Context, string) (net.
 
     return c2
 }))
-```
\ No newline at end of file
+```
diff --git a/docs/reference/buildx_du.md b/docs/reference/buildx_du.md
index 684f717a..29878272 100644
--- a/docs/reference/buildx_du.md
+++ b/docs/reference/buildx_du.md
@@ -1,7 +1,7 @@
 # buildx du
 
 ```text
-docker buildx du
+docker buildx du [OPTIONS]
 ```
 
 <!---MARKER_GEN_START-->
diff --git a/docs/reference/buildx_history.md b/docs/reference/buildx_history.md
index ef0cf8b1..c7f3d064 100644
--- a/docs/reference/buildx_history.md
+++ b/docs/reference/buildx_history.md
@@ -1,20 +1,24 @@
 # docker buildx history
 
+```text
+docker buildx history [OPTIONS] COMMAND
+```
+
 <!---MARKER_GEN_START-->
 Commands to work on build records
 
 ### Subcommands
 
-| Name                                   | Description                                    |
-|:---------------------------------------|:-----------------------------------------------|
-| [`export`](buildx_history_export.md)   | Export a build into Docker Desktop bundle      |
-| [`import`](buildx_history_import.md)   | Import a build into Docker Desktop             |
-| [`inspect`](buildx_history_inspect.md) | Inspect a build                                |
-| [`logs`](buildx_history_logs.md)       | Print the logs of a build                      |
-| [`ls`](buildx_history_ls.md)           | List build records                             |
-| [`open`](buildx_history_open.md)       | Open a build in Docker Desktop                 |
-| [`rm`](buildx_history_rm.md)           | Remove build records                           |
-| [`trace`](buildx_history_trace.md)     | Show the OpenTelemetry trace of a build record |
+| Name                                   | Description                                     |
+|:---------------------------------------|:------------------------------------------------|
+| [`export`](buildx_history_export.md)   | Export build records into Docker Desktop bundle |
+| [`import`](buildx_history_import.md)   | Import build records into Docker Desktop        |
+| [`inspect`](buildx_history_inspect.md) | Inspect a build record                          |
+| [`logs`](buildx_history_logs.md)       | Print the logs of a build record                |
+| [`ls`](buildx_history_ls.md)           | List build records                              |
+| [`open`](buildx_history_open.md)       | Open a build record in Docker Desktop           |
+| [`rm`](buildx_history_rm.md)           | Remove build records                            |
+| [`trace`](buildx_history_trace.md)     | Show the OpenTelemetry trace of a build record  |
 
 
 ### Options
diff --git a/docs/reference/buildx_history_export.md b/docs/reference/buildx_history_export.md
index ab8a1ff8..edb99ee8 100644
--- a/docs/reference/buildx_history_export.md
+++ b/docs/reference/buildx_history_export.md
@@ -1,16 +1,17 @@
 # docker buildx history export
 
 <!---MARKER_GEN_START-->
-Export a build into Docker Desktop bundle
+Export build records into Docker Desktop bundle
 
 ### Options
 
-| Name                                   | Type     | Default | Description                              |
-|:---------------------------------------|:---------|:--------|:-----------------------------------------|
-| [`--all`](#all)                        | `bool`   |         | Export all records for the builder       |
-| [`--builder`](#builder)                | `string` |         | Override the configured builder instance |
-| [`-D`](#debug), [`--debug`](#debug)    | `bool`   |         | Enable debug logging                     |
-| [`-o`](#output), [`--output`](#output) | `string` |         | Output file path                         |
+| Name                                   | Type     | Default | Description                                         |
+|:---------------------------------------|:---------|:--------|:----------------------------------------------------|
+| [`--all`](#all)                        | `bool`   |         | Export all build records for the builder            |
+| [`--builder`](#builder)                | `string` |         | Override the configured builder instance            |
+| [`-D`](#debug), [`--debug`](#debug)    | `bool`   |         | Enable debug logging                                |
+| [`--finalize`](#finalize)              | `bool`   |         | Ensure build records are finalized before exporting |
+| [`-o`](#output), [`--output`](#output) | `string` |         | Output file path                                    |
 
 
 <!---MARKER_GEN_END-->
@@ -23,59 +24,67 @@ Desktop or shared across environments.
 
 ## Examples
 
-### <a name="output"></a> Export a single build to a custom file (--output)
+### <a name="all"></a> Export all build records to a file (--all)
+
+Use the `--all` flag and redirect the output:
 
 ```console
-docker buildx history export qu2gsuo8ejqrwdfii23xkkckt --output mybuild.dockerbuild
+docker buildx history export --all > all-builds.dockerbuild
 ```
 
-You can find build IDs by running:
+Or use the `--output` flag:
 
 ```console
-docker buildx history ls
+docker buildx history export --all -o all-builds.dockerbuild
 ```
 
-### <a name="o"></a> Export multiple builds to individual `.dockerbuild` files (-o)
-
-To export two builds to separate files:
+### <a name="builder"></a> Use a specific builder instance (--builder)
 
 ```console
-# Using build IDs
-docker buildx history export qu2gsuo8ejqrwdfii23xkkckt qsiifiuf1ad9pa9qvppc0z1l3 -o multi.dockerbuild
-
-# Or using relative offsets
-docker buildx history export ^1 ^2 -o multi.dockerbuild
+docker buildx history export --builder builder0 ^1 -o builder0-build.dockerbuild
 ```
 
-Or use shell redirection:
+### <a name="debug"></a> Enable debug logging (--debug)
 
 ```console
-docker buildx history export ^1 > mybuild.dockerbuild
-docker buildx history export ^2 > backend-build.dockerbuild
+docker buildx history export --debug qu2gsuo8ejqrwdfii23xkkckt -o debug-build.dockerbuild
 ```
 
-### <a name="all"></a> Export all build records to a file (--all)
+### <a name="finalize"></a> Ensure build records are finalized before exporting (--finalize)
 
-Use the `--all` flag and redirect the output:
+Clients can report their own traces concurrently, and not all traces may be
+saved yet by the time of the export. Use the `--finalize` flag to ensure all
+traces are finalized before exporting.
 
 ```console
-docker buildx history export --all > all-builds.dockerbuild
+docker buildx history export --finalize qu2gsuo8ejqrwdfii23xkkckt -o finalized-build.dockerbuild
 ```
 
-Or use the `--output` flag:
+### <a name="output"></a> Export a single build to a custom file (--output)
 
 ```console
-docker buildx history export --all -o all-builds.dockerbuild
+docker buildx history export qu2gsuo8ejqrwdfii23xkkckt --output mybuild.dockerbuild
 ```
 
-### <a name="builder"></a> Use a specific builder instance (--builder)
+You can find build IDs by running:
 
 ```console
-docker buildx history export --builder builder0 ^1 -o builder0-build.dockerbuild
+docker buildx history ls
 ```
 
-### <a name="debug"></a> Enable debug logging (--debug)
+To export two builds to separate files:
 
 ```console
-docker buildx history export --debug qu2gsuo8ejqrwdfii23xkkckt -o debug-build.dockerbuild
-```
\ No newline at end of file
+# Using build IDs
+docker buildx history export qu2gsuo8ejqrwdfii23xkkckt qsiifiuf1ad9pa9qvppc0z1l3 -o multi.dockerbuild
+
+# Or using relative offsets
+docker buildx history export ^1 ^2 -o multi.dockerbuild
+```
+
+Or use shell redirection:
+
+```console
+docker buildx history export ^1 > mybuild.dockerbuild
+docker buildx history export ^2 > backend-build.dockerbuild
+```
diff --git a/docs/reference/buildx_history_import.md b/docs/reference/buildx_history_import.md
index cc145ea0..1d2c06d0 100644
--- a/docs/reference/buildx_history_import.md
+++ b/docs/reference/buildx_history_import.md
@@ -1,7 +1,11 @@
 # docker buildx history import
 
+```text
+docker buildx history import [OPTIONS] -
+```
+
 <!---MARKER_GEN_START-->
-Import a build into Docker Desktop
+Import build records into Docker Desktop
 
 ### Options
 
diff --git a/docs/reference/buildx_history_inspect.md b/docs/reference/buildx_history_inspect.md
index 942e1a3f..dcc20280 100644
--- a/docs/reference/buildx_history_inspect.md
+++ b/docs/reference/buildx_history_inspect.md
@@ -1,13 +1,17 @@
 # docker buildx history inspect
 
+```text
+docker buildx history inspect [OPTIONS] [REF|COMMAND]
+```
+
 <!---MARKER_GEN_START-->
-Inspect a build
+Inspect a build record
 
 ### Subcommands
 
-| Name                                                 | Description                |
-|:-----------------------------------------------------|:---------------------------|
-| [`attachment`](buildx_history_inspect_attachment.md) | Inspect a build attachment |
+| Name                                                 | Description                       |
+|:-----------------------------------------------------|:----------------------------------|
+| [`attachment`](buildx_history_inspect_attachment.md) | Inspect a build record attachment |
 
 
 ### Options
@@ -74,7 +78,7 @@ docker buildx history inspect ^1
 The formatting options (`--format`) pretty-prints the output to `pretty` (default),
 `json` or using a Go template.
 
-**Pretty output**
+#### Pretty output
 
 ```console
 $ docker buildx history inspect
@@ -105,7 +109,8 @@ sha256:217329d2af959d4f02e3a96dcbe62bf100cab1feb8006a047ddfe51a5397f7e3
 
 Print build logs: docker buildx history logs g9808bwrjrlkbhdamxklx660b
 ```
-**JSON output**
+
+#### JSON output
 
 ```console
 $ docker buildx history inspect --format json
@@ -160,7 +165,7 @@ $ docker buildx history inspect --format json
 }
 ```
 
-**Go template output**
+#### Go template output
 
 ```console
 $ docker buildx history inspect --format "{{.Name}}: {{.VCSRepository}} ({{.VCSRevision}})"
diff --git a/docs/reference/buildx_history_inspect_attachment.md b/docs/reference/buildx_history_inspect_attachment.md
index 6014e924..d4a4deb4 100644
--- a/docs/reference/buildx_history_inspect_attachment.md
+++ b/docs/reference/buildx_history_inspect_attachment.md
@@ -1,7 +1,11 @@
 # docker buildx history inspect attachment
 
+```text
+docker buildx history inspect attachment [OPTIONS] REF [DIGEST]
+```
+
 <!---MARKER_GEN_START-->
-Inspect a build attachment
+Inspect a build record attachment
 
 ### Options
 
diff --git a/docs/reference/buildx_history_logs.md b/docs/reference/buildx_history_logs.md
index 212b43cc..4f27c19b 100644
--- a/docs/reference/buildx_history_logs.md
+++ b/docs/reference/buildx_history_logs.md
@@ -1,7 +1,11 @@
 # docker buildx history logs
 
+```text
+docker buildx history logs [OPTIONS] [REF]
+```
+
 <!---MARKER_GEN_START-->
-Print the logs of a build
+Print the logs of a build record
 
 ### Options
 
diff --git a/docs/reference/buildx_history_ls.md b/docs/reference/buildx_history_ls.md
index 88a7ce34..9f27d238 100644
--- a/docs/reference/buildx_history_ls.md
+++ b/docs/reference/buildx_history_ls.md
@@ -1,5 +1,9 @@
 # docker buildx history ls
 
+```text
+docker buildx history ls [OPTIONS]
+```
+
 <!---MARKER_GEN_START-->
 List build records
 
@@ -45,10 +49,10 @@ docker buildx history ls --filter status=error
 
 You can filter the list using the `--filter` flag. Supported filters include:
 
-| Filter | Supported comparisons | Example |
-|:-------|:----------------------|:--------|
-| `ref`, `repository`, `status` | Support `=` and `!=` comparisons | `--filter status!=success` |
-| `startedAt`, `completedAt`, `duration` | Support `<` and `>` comparisons with time values | `--filter duration>30s` |
+| Filter                                 | Supported comparisons                            | Example                    |
+|:---------------------------------------|:-------------------------------------------------|:---------------------------|
+| `ref`, `repository`, `status`          | Support `=` and `!=` comparisons                 | `--filter status!=success` |
+| `startedAt`, `completedAt`, `duration` | Support `<` and `>` comparisons with time values | `--filter duration>30s`    |
 
 You can combine multiple filters by repeating the `--filter` flag:
 
@@ -70,7 +74,7 @@ docker buildx history ls --no-trunc
 
 ### <a name="format"></a> Format output (--format)
 
-**JSON output**
+#### JSON output
 
 ```console
 $ docker buildx history ls --format json
@@ -92,7 +96,7 @@ $ docker buildx history ls --format json
 ]
 ```
 
-**Go template output**
+#### Go template output
 
 ```console
 $ docker buildx history ls --format '{{.Name}} - {{.Duration}}'
diff --git a/docs/reference/buildx_history_open.md b/docs/reference/buildx_history_open.md
index e0817b41..0dc19702 100644
--- a/docs/reference/buildx_history_open.md
+++ b/docs/reference/buildx_history_open.md
@@ -1,7 +1,11 @@
 # docker buildx history open
 
+```text
+docker buildx history open [OPTIONS] [REF]
+```
+
 <!---MARKER_GEN_START-->
-Open a build in Docker Desktop
+Open a build record in Docker Desktop
 
 ### Options
 
diff --git a/docs/reference/buildx_history_rm.md b/docs/reference/buildx_history_rm.md
index dedf1a0c..deb922f9 100644
--- a/docs/reference/buildx_history_rm.md
+++ b/docs/reference/buildx_history_rm.md
@@ -1,5 +1,9 @@
 # docker buildx history rm
 
+```text
+docker buildx history rm [OPTIONS] [REF...]
+```
+
 <!---MARKER_GEN_START-->
 Remove build records
 
@@ -7,7 +11,7 @@ Remove build records
 
 | Name            | Type     | Default | Description                              |
 |:----------------|:---------|:--------|:-----------------------------------------|
-| `--all`         | `bool`   |         | Remove all build records                 |
+| [`--all`](#all) | `bool`   |         | Remove all build records                 |
 | `--builder`     | `string` |         | Override the configured builder instance |
 | `-D`, `--debug` | `bool`   |         | Enable debug logging                     |
 
@@ -42,7 +46,7 @@ docker buildx history rm qu2gsuo8ejqrwdfii23xkkckt qsiifiuf1ad9pa9qvppc0z1l3
 docker buildx history rm ^1 ^2
 ```
 
-### Remove all build records from the current builder
+### <a name="all"></a> Remove all build records from the current builder (--all)
 
 ```console
 docker buildx history rm --all
diff --git a/docs/reference/buildx_history_trace.md b/docs/reference/buildx_history_trace.md
index 2b448145..4b7f4dac 100644
--- a/docs/reference/buildx_history_trace.md
+++ b/docs/reference/buildx_history_trace.md
@@ -1,5 +1,9 @@
 # docker buildx history trace
 
+```text
+docker buildx history trace [OPTIONS] [REF]
+```
+
 <!---MARKER_GEN_START-->
 Show the OpenTelemetry trace of a build record
 
@@ -9,7 +13,7 @@ Show the OpenTelemetry trace of a build record
 |:------------------------|:---------|:--------------|:-----------------------------------------|
 | [`--addr`](#addr)       | `string` | `127.0.0.1:0` | Address to bind the UI server            |
 | `--builder`             | `string` |               | Override the configured builder instance |
-| [`--compare`](#compare) | `string` |               | Compare with another build reference     |
+| [`--compare`](#compare) | `string` |               | Compare with another build record        |
 | `-D`, `--debug`         | `bool`   |               | Enable debug logging                     |
 
 
diff --git a/docs/reference/buildx_imagetools_create.md b/docs/reference/buildx_imagetools_create.md
index d937d5d7..4e74b03a 100644
--- a/docs/reference/buildx_imagetools_create.md
+++ b/docs/reference/buildx_imagetools_create.md
@@ -1,7 +1,7 @@
 # buildx imagetools create
 
 ```text
-docker buildx imagetools create [OPTIONS] [SOURCE] [SOURCE...]
+docker buildx imagetools create [OPTIONS] [SOURCE...]
 ```
 
 <!---MARKER_GEN_START-->
diff --git a/docs/reference/buildx_ls.md b/docs/reference/buildx_ls.md
index 63f442f2..1b0d89a0 100644
--- a/docs/reference/buildx_ls.md
+++ b/docs/reference/buildx_ls.md
@@ -1,7 +1,7 @@
 # buildx ls
 
 ```text
-docker buildx ls
+docker buildx ls [OPTIONS]
 ```
 
 <!---MARKER_GEN_START-->
diff --git a/docs/reference/buildx_prune.md b/docs/reference/buildx_prune.md
index e86b3021..f23385ab 100644
--- a/docs/reference/buildx_prune.md
+++ b/docs/reference/buildx_prune.md
@@ -1,7 +1,7 @@
 # buildx prune
 
 ```text
-docker buildx prune
+docker buildx prune [OPTIONS]
 ```
 
 <!---MARKER_GEN_START-->
diff --git a/docs/reference/buildx_rm.md b/docs/reference/buildx_rm.md
index bcb856e7..996bacd5 100644
--- a/docs/reference/buildx_rm.md
+++ b/docs/reference/buildx_rm.md
@@ -1,7 +1,7 @@
 # buildx rm
 
 ```text
-docker buildx rm [OPTIONS] [NAME] [NAME...]
+docker buildx rm [OPTIONS] [NAME...]
 ```
 
 <!---MARKER_GEN_START-->
diff --git a/docs/reference/buildx_stop.md b/docs/reference/buildx_stop.md
index dcf0430a..6493f855 100644
--- a/docs/reference/buildx_stop.md
+++ b/docs/reference/buildx_stop.md
@@ -1,6 +1,6 @@
 # buildx stop
 
-```
+```text
 docker buildx stop [NAME]
 ```
 
diff --git a/docs/reference/buildx_use.md b/docs/reference/buildx_use.md
index 6cd1652f..bf8bb97f 100644
--- a/docs/reference/buildx_use.md
+++ b/docs/reference/buildx_use.md
@@ -1,6 +1,6 @@
 # buildx use
 
-```
+```text
 docker buildx use [OPTIONS] NAME
 ```
 
diff --git a/driver/docker-container/driver.go b/driver/docker-container/driver.go
index cfcdf67c..fc964dd9 100644
--- a/driver/docker-container/driver.go
+++ b/driver/docker-container/driver.go
@@ -138,28 +138,28 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
 			hc.NetworkMode = container.NetworkMode(d.netMode)
 		}
 		if d.memory != 0 {
-			hc.Resources.Memory = int64(d.memory)
+			hc.Memory = int64(d.memory)
 		}
 		if d.memorySwap != 0 {
-			hc.Resources.MemorySwap = int64(d.memorySwap)
+			hc.MemorySwap = int64(d.memorySwap)
 		}
 		if d.cpuQuota != 0 {
-			hc.Resources.CPUQuota = d.cpuQuota
+			hc.CPUQuota = d.cpuQuota
 		}
 		if d.cpuPeriod != 0 {
-			hc.Resources.CPUPeriod = d.cpuPeriod
+			hc.CPUPeriod = d.cpuPeriod
 		}
 		if d.cpuShares != 0 {
-			hc.Resources.CPUShares = d.cpuShares
+			hc.CPUShares = d.cpuShares
 		}
 		if d.cpusetCpus != "" {
-			hc.Resources.CpusetCpus = d.cpusetCpus
+			hc.CpusetCpus = d.cpusetCpus
 		}
 		if d.cpusetMems != "" {
-			hc.Resources.CpusetMems = d.cpusetMems
+			hc.CpusetMems = d.cpusetMems
 		}
 		if len(d.gpus) > 0 && d.hasGPUCapability(ctx, cfg.Image, d.gpus) {
-			hc.Resources.DeviceRequests = d.gpus
+			hc.DeviceRequests = d.gpus
 		}
 		if info, err := d.DockerAPI.Info(ctx); err == nil {
 			if info.CgroupDriver == "cgroupfs" {
@@ -187,7 +187,7 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
 			return err
 		}
 		if err == nil {
-			if err := d.copyToContainer(ctx, d.InitConfig.Files); err != nil {
+			if err := d.copyToContainer(ctx, d.Files); err != nil {
 				return err
 			}
 			if err := d.start(ctx); err != nil {
diff --git a/driver/kubernetes/manifest/manifest.go b/driver/kubernetes/manifest/manifest.go
index 1137badb..dfc51bbd 100644
--- a/driver/kubernetes/manifest/manifest.go
+++ b/driver/kubernetes/manifest/manifest.go
@@ -6,7 +6,7 @@ import (
 	"strings"
 
 	"github.com/docker/buildx/util/platformutil"
-	v1 "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
@@ -43,7 +43,7 @@ type DeploymentOpt struct {
 	LimitsCPU                string
 	LimitsMemory             string
 	LimitsEphemeralStorage   string
-	Platforms                []v1.Platform
+	Platforms                []ocispecs.Platform
 }
 
 const (
@@ -260,10 +260,10 @@ func toRootless(d *appsv1.Deployment) error {
 			Type: corev1.SeccompProfileTypeUnconfined,
 		},
 	}
-	if d.Spec.Template.ObjectMeta.Annotations == nil {
-		d.Spec.Template.ObjectMeta.Annotations = make(map[string]string, 1)
+	if d.Spec.Template.Annotations == nil {
+		d.Spec.Template.Annotations = make(map[string]string, 1)
 	}
-	d.Spec.Template.ObjectMeta.Annotations["container.apparmor.security.beta.kubernetes.io/"+containerName] = "unconfined"
+	d.Spec.Template.Annotations["container.apparmor.security.beta.kubernetes.io/"+containerName] = "unconfined"
 
 	// Dockerfile has `VOLUME /home/user/.local/share/buildkit` by default too,
 	// but the default VOLUME does not work with rootless on Google's Container-Optimized OS
diff --git a/driver/manager.go b/driver/manager.go
index 400a0cdd..fcc94c72 100644
--- a/driver/manager.go
+++ b/driver/manager.go
@@ -9,7 +9,7 @@ import (
 	dockerclient "github.com/docker/docker/client"
 	"github.com/moby/buildkit/client"
 	"github.com/moby/buildkit/util/tracing/delegated"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
@@ -35,7 +35,7 @@ type InitConfig struct {
 	Files           map[string][]byte
 	DriverOpts      map[string]string
 	Auth            Auth
-	Platforms       []specs.Platform
+	Platforms       []ocispecs.Platform
 	ContextPathHash string
 	DialMeta        map[string][]string
 }
diff --git a/driver/remote/driver.go b/driver/remote/driver.go
index 22145dd6..495a487e 100644
--- a/driver/remote/driver.go
+++ b/driver/remote/driver.go
@@ -48,7 +48,7 @@ func (d *Driver) Bootstrap(ctx context.Context, l progress.Logger) error {
 	}
 	return progress.Wrap("[internal] waiting for connection", l, func(_ progress.SubLogger) error {
 		cancelCtx, cancel := context.WithCancelCause(ctx)
-		ctx, _ := context.WithTimeoutCause(cancelCtx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet,lostcancel // no need to manually cancel this context as we already rely on parent
+		ctx, _ := context.WithTimeoutCause(cancelCtx, 20*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet // no need to manually cancel this context as we already rely on parent
 		defer func() { cancel(errors.WithStack(context.Canceled)) }()
 		return c.Wait(ctx)
 	})
@@ -101,7 +101,7 @@ func (d *Driver) Client(ctx context.Context, opts ...client.ClientOpt) (*client.
 }
 
 func (d *Driver) Dial(ctx context.Context) (net.Conn, error) {
-	addr := d.InitConfig.EndpointAddr
+	addr := d.EndpointAddr
 	ch, err := connhelper.GetConnectionHelper(addr)
 	if err != nil {
 		return nil, err
@@ -112,7 +112,7 @@ func (d *Driver) Dial(ctx context.Context) (net.Conn, error) {
 
 	network, addr, ok := strings.Cut(addr, "://")
 	if !ok {
-		return nil, errors.Errorf("invalid endpoint address: %s", d.InitConfig.EndpointAddr)
+		return nil, errors.Errorf("invalid endpoint address: %s", d.EndpointAddr)
 	}
 
 	conn, err := util.DialContext(ctx, network, addr)
diff --git a/hack/dockerfiles/docs.Dockerfile b/hack/dockerfiles/docs.Dockerfile
index 2c18b12c..2e3400ec 100644
--- a/hack/dockerfiles/docs.Dockerfile
+++ b/hack/dockerfiles/docs.Dockerfile
@@ -1,6 +1,6 @@
 # syntax=docker/dockerfile:1
 
-ARG GO_VERSION=1.23
+ARG GO_VERSION=1.24
 ARG ALPINE_VERSION=3.21
 
 ARG FORMATS=md,yaml
diff --git a/hack/dockerfiles/generated-files.Dockerfile b/hack/dockerfiles/generated-files.Dockerfile
index a7b406c1..99149bff 100644
--- a/hack/dockerfiles/generated-files.Dockerfile
+++ b/hack/dockerfiles/generated-files.Dockerfile
@@ -5,7 +5,7 @@
 # Copyright The Buildx Authors.
 # Licensed under the Apache License, Version 2.0
 
-ARG GO_VERSION=1.23
+ARG GO_VERSION=1.24
 ARG PROTOC_VERSION=3.11.4
 ARG PROTOC_GOOGLEAPIS_VERSION=2af421884dd468d565137215c946ebe4e245ae26
 
diff --git a/hack/dockerfiles/govulncheck.Dockerfile b/hack/dockerfiles/govulncheck.Dockerfile
index 3b955b10..1f1cd84e 100644
--- a/hack/dockerfiles/govulncheck.Dockerfile
+++ b/hack/dockerfiles/govulncheck.Dockerfile
@@ -1,6 +1,6 @@
 # syntax=docker/dockerfile:1
 
-ARG GO_VERSION=1.23
+ARG GO_VERSION=1.24
 ARG ALPINE_VERSION=3.21
 
 ARG GOVULNCHECK_VERSION=v1.1.3
diff --git a/hack/dockerfiles/lint.Dockerfile b/hack/dockerfiles/lint.Dockerfile
index 37c64ac6..1ce48dff 100644
--- a/hack/dockerfiles/lint.Dockerfile
+++ b/hack/dockerfiles/lint.Dockerfile
@@ -1,24 +1,38 @@
 # syntax=docker/dockerfile:1
 
-ARG GO_VERSION=1.23
+ARG GO_VERSION=1.24
 ARG ALPINE_VERSION=3.21
 ARG XX_VERSION=1.6.1
 
-ARG GOLANGCI_LINT_VERSION=1.62.0
-# v0.31 requires go1.24
-ARG GOPLS_VERSION=v0.30.0
-# disabled: deprecated unusedvariable simplifyrange
-ARG GOPLS_ANALYZERS="embeddirective fillreturns hostport infertypeargs modernize nonewvars noresultvalues simplifycompositelit simplifyslice unusedparams yield"
+ARG GOLANGCI_LINT_VERSION=v2.1.5
+ARG GOLANGCI_FROM_SOURCE=false
+ARG GOPLS_VERSION=v0.33.0
+# GOPLS_ANALYZERS defines gopls analyzers to be run. disabled by default: deprecated simplifyrange unusedfunc unusedvariable
+ARG GOPLS_ANALYZERS="embeddirective fillreturns infertypeargs maprange modernize nonewvars noresultvalues simplifycompositelit simplifyslice unusedparams yield"
 
 FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
 
-FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS golang-base
+FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base
 RUN apk add --no-cache git gcc musl-dev
 
-FROM golang-base AS lint-base
+FROM base AS golangci-build
+WORKDIR /src
+ARG GOLANGCI_LINT_VERSION
+ADD https://github.com/golangci/golangci-lint.git#${GOLANGCI_LINT_VERSION} .
+RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/ go mod download
+RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/ mkdir -p out && go build -o /out/golangci-lint ./cmd/golangci-lint
+
+FROM scratch AS golangci-binary-false
+FROM scratch AS golangci-binary-true
+COPY --from=golangci-build /out/golangci-lint golangci-lint
+FROM golangci-binary-${GOLANGCI_FROM_SOURCE} AS golangci-binary
+
+FROM base AS lint-base
 ENV GOFLAGS="-buildvcs=false"
 ARG GOLANGCI_LINT_VERSION
-RUN wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v${GOLANGCI_LINT_VERSION}
+ARG GOLANGCI_FROM_SOURCE
+COPY --link --from=golangci-binary / /usr/bin/
+RUN [ "${GOLANGCI_FROM_SOURCE}" = "true" ] && exit 0; wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s ${GOLANGCI_LINT_VERSION}
 COPY --link --from=xx / /
 WORKDIR /go/src/github.com/docker/buildx
 ARG TARGETPLATFORM
@@ -33,7 +47,7 @@ FROM lint-base AS validate-golangci
 RUN --mount=target=/go/src/github.com/docker/buildx \
   golangci-lint config verify
 
-FROM golang-base AS gopls
+FROM base AS gopls
 RUN apk add --no-cache git
 ARG GOPLS_VERSION
 WORKDIR /src
@@ -61,7 +75,7 @@ eot
   done
 EOF
 
-FROM golang-base AS gopls-analyze
+FROM base AS gopls-analyze
 COPY --link --from=xx / /
 ARG GOPLS_ANALYZERS
 ARG TARGETNAME
diff --git a/hack/dockerfiles/vendor.Dockerfile b/hack/dockerfiles/vendor.Dockerfile
index 1dac1c37..341f64ac 100644
--- a/hack/dockerfiles/vendor.Dockerfile
+++ b/hack/dockerfiles/vendor.Dockerfile
@@ -1,6 +1,6 @@
 # syntax=docker/dockerfile:1
 
-ARG GO_VERSION=1.23
+ARG GO_VERSION=1.24
 ARG ALPINE_VERSION=3.21
 
 ARG MODOUTDATED_VERSION=v0.9.0
diff --git a/store/nodegroup.go b/store/nodegroup.go
index 9d986d17..8c78acc1 100644
--- a/store/nodegroup.go
+++ b/store/nodegroup.go
@@ -9,7 +9,7 @@ import (
 	"github.com/containerd/platforms"
 	"github.com/docker/buildx/util/confutil"
 	"github.com/docker/buildx/util/platformutil"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 )
@@ -28,7 +28,7 @@ type NodeGroup struct {
 type Node struct {
 	Name           string
 	Endpoint       string
-	Platforms      []specs.Platform
+	Platforms      []ocispecs.Platform
 	DriverOpts     map[string]string
 	BuildkitdFlags []string `json:"Flags"` // keep the field name for backward compatibility
 
@@ -141,7 +141,7 @@ func (ng *NodeGroup) Copy() *NodeGroup {
 }
 
 func (n *Node) Copy() *Node {
-	platforms := []specs.Platform{}
+	platforms := []ocispecs.Platform{}
 	copy(platforms, n.Platforms)
 	buildkitdFlags := []string{}
 	copy(buildkitdFlags, n.BuildkitdFlags)
@@ -210,8 +210,8 @@ func (ng *NodeGroup) nextNodeName() string {
 	}
 }
 
-func filterPlatforms(in []specs.Platform, m map[string]struct{}) []specs.Platform {
-	out := make([]specs.Platform, 0, len(in))
+func filterPlatforms(in []ocispecs.Platform, m map[string]struct{}) []ocispecs.Platform {
+	out := make([]ocispecs.Platform, 0, len(in))
 	for _, p := range in {
 		if _, ok := m[platforms.Format(p)]; !ok {
 			out = append(out, p)
diff --git a/util/dockerutil/progress.go b/util/dockerutil/progress.go
index 608c9c2a..10f20f7c 100644
--- a/util/dockerutil/progress.go
+++ b/util/dockerutil/progress.go
@@ -17,7 +17,6 @@ func fromReader(l progress.SubLogger, rc io.ReadCloser) error {
 
 	defer func() {
 		for _, st := range started {
-			st := st
 			if st.Completed == nil {
 				now := time.Now()
 				st.Completed = &now
diff --git a/util/imagetools/create.go b/util/imagetools/create.go
index 9b1ca6b4..91afce35 100644
--- a/util/imagetools/create.go
+++ b/util/imagetools/create.go
@@ -18,17 +18,17 @@ import (
 	"github.com/moby/buildkit/util/contentutil"
 	"github.com/opencontainers/go-digest"
 	"github.com/opencontainers/image-spec/specs-go"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"golang.org/x/sync/errgroup"
 )
 
 type Source struct {
-	Desc ocispec.Descriptor
+	Desc ocispecs.Descriptor
 	Ref  reference.Named
 }
 
-func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[exptypes.AnnotationKey]string, preferIndex bool) ([]byte, ocispec.Descriptor, error) {
+func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[exptypes.AnnotationKey]string, preferIndex bool) ([]byte, ocispecs.Descriptor, error) {
 	eg, ctx := errgroup.WithContext(ctx)
 
 	dts := make([][]byte, len(srcs))
@@ -52,10 +52,10 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[exptypes
 				mt := srcs[i].Desc.MediaType
 
 				switch mt {
-				case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+				case images.MediaTypeDockerSchema2Manifest, ocispecs.MediaTypeImageManifest:
 					p := srcs[i].Desc.Platform
 					if srcs[i].Desc.Platform == nil {
-						p = &ocispec.Platform{}
+						p = &ocispecs.Platform{}
 					}
 					if p.OS == "" || p.Architecture == "" {
 						if err := r.loadPlatform(ctx, p, srcs[i].Ref.String(), dt); err != nil {
@@ -73,7 +73,7 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[exptypes
 	}
 
 	if err := eg.Wait(); err != nil {
-		return nil, ocispec.Descriptor{}, err
+		return nil, ocispecs.Descriptor{}, err
 	}
 
 	// on single source, return original bytes
@@ -82,7 +82,7 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[exptypes
 		// if the source is already an image index or manifest list, there is no need to consider the value
 		// of preferIndex since if set to true then the source is already in the preferred format, and if false
 		// it doesn't matter since we're not going to split it into separate manifests
-		case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+		case images.MediaTypeDockerSchema2ManifestList, ocispecs.MediaTypeImageIndex:
 			return dts[0], srcs[0].Desc, nil
 		default:
 			if !preferIndex {
@@ -92,9 +92,9 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[exptypes
 	}
 
 	m := map[digest.Digest]int{}
-	newDescs := make([]ocispec.Descriptor, 0, len(srcs))
+	newDescs := make([]ocispecs.Descriptor, 0, len(srcs))
 
-	addDesc := func(d ocispec.Descriptor) {
+	addDesc := func(d ocispecs.Descriptor) {
 		idx, ok := m[d.Digest]
 		if ok {
 			old := newDescs[idx]
@@ -117,10 +117,10 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[exptypes
 
 	for i, src := range srcs {
 		switch src.Desc.MediaType {
-		case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
-			var mfst ocispec.Index
+		case images.MediaTypeDockerSchema2ManifestList, ocispecs.MediaTypeImageIndex:
+			var mfst ocispecs.Index
 			if err := json.Unmarshal(dts[i], &mfst); err != nil {
-				return nil, ocispec.Descriptor{}, errors.WithStack(err)
+				return nil, ocispecs.Descriptor{}, errors.WithStack(err)
 			}
 			for _, d := range mfst.Manifests {
 				addDesc(d)
@@ -143,12 +143,12 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[exptypes
 		mt = images.MediaTypeDockerSchema2ManifestList
 	} else {
 		// otherwise, use OCI index
-		mt = ocispec.MediaTypeImageIndex
+		mt = ocispecs.MediaTypeImageIndex
 	}
 
 	// annotations are only allowed on OCI indexes
 	indexAnnotation := make(map[string]string)
-	if mt == ocispec.MediaTypeImageIndex {
+	if mt == ocispecs.MediaTypeImageIndex {
 		for k, v := range ann {
 			switch k.Type {
 			case exptypes.AnnotationIndex:
@@ -163,14 +163,14 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[exptypes
 					}
 				}
 			case exptypes.AnnotationManifest, "":
-				return nil, ocispec.Descriptor{}, errors.Errorf("%q annotations are not supported yet", k.Type)
+				return nil, ocispecs.Descriptor{}, errors.Errorf("%q annotations are not supported yet", k.Type)
 			case exptypes.AnnotationIndexDescriptor:
-				return nil, ocispec.Descriptor{}, errors.Errorf("%q annotations are invalid while creating an image", k.Type)
+				return nil, ocispecs.Descriptor{}, errors.Errorf("%q annotations are invalid while creating an image", k.Type)
 			}
 		}
 	}
 
-	idxBytes, err := json.MarshalIndent(ocispec.Index{
+	idxBytes, err := json.MarshalIndent(ocispecs.Index{
 		MediaType: mt,
 		Versioned: specs.Versioned{
 			SchemaVersion: 2,
@@ -179,17 +179,17 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[exptypes
 		Annotations: indexAnnotation,
 	}, "", "  ")
 	if err != nil {
-		return nil, ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal index")
+		return nil, ocispecs.Descriptor{}, errors.Wrap(err, "failed to marshal index")
 	}
 
-	return idxBytes, ocispec.Descriptor{
+	return idxBytes, ocispecs.Descriptor{
 		MediaType: mt,
 		Size:      int64(len(idxBytes)),
 		Digest:    digest.FromBytes(idxBytes),
 	}, nil
 }
 
-func (r *Resolver) Push(ctx context.Context, ref reference.Named, desc ocispec.Descriptor, dt []byte) error {
+func (r *Resolver) Push(ctx context.Context, ref reference.Named, desc ocispecs.Descriptor, dt []byte) error {
 	ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.in-toto+json", "intoto")
 
 	fullRef, err := reference.WithDigest(reference.TagNameOnly(ref), desc.Digest)
@@ -252,8 +252,8 @@ func (r *Resolver) Copy(ctx context.Context, src *Source, dest reference.Named)
 	return nil
 }
 
-func (r *Resolver) loadPlatform(ctx context.Context, p2 *ocispec.Platform, in string, dt []byte) error {
-	var manifest ocispec.Manifest
+func (r *Resolver) loadPlatform(ctx context.Context, p2 *ocispecs.Platform, in string, dt []byte) error {
+	var manifest ocispecs.Manifest
 	if err := json.Unmarshal(dt, &manifest); err != nil {
 		return errors.WithStack(err)
 	}
@@ -263,7 +263,7 @@ func (r *Resolver) loadPlatform(ctx context.Context, p2 *ocispec.Platform, in st
 		return err
 	}
 
-	var p ocispec.Platform
+	var p ocispecs.Platform
 	if err := json.Unmarshal(dt, &p); err != nil {
 		return errors.WithStack(err)
 	}
diff --git a/util/imagetools/inspect.go b/util/imagetools/inspect.go
index 8af09c48..28f86f5b 100644
--- a/util/imagetools/inspect.go
+++ b/util/imagetools/inspect.go
@@ -16,7 +16,7 @@ import (
 	clitypes "github.com/docker/cli/cli/config/types"
 	"github.com/moby/buildkit/util/contentutil"
 	"github.com/moby/buildkit/util/tracing"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/sirupsen/logrus"
 )
 
@@ -59,7 +59,7 @@ func (r *Resolver) resolver() remotes.Resolver {
 	})
 }
 
-func (r *Resolver) Resolve(ctx context.Context, in string) (string, ocispec.Descriptor, error) {
+func (r *Resolver) Resolve(ctx context.Context, in string) (string, ocispecs.Descriptor, error) {
 	// discard containerd logger to avoid printing unnecessary info during image reference resolution.
 	// https://github.com/containerd/containerd/blob/1a88cf5242445657258e0c744def5017d7cfb492/remotes/docker/resolver.go#L288
 	logger := logrus.New()
@@ -68,31 +68,31 @@ func (r *Resolver) Resolve(ctx context.Context, in string) (string, ocispec.Desc
 
 	ref, err := parseRef(in)
 	if err != nil {
-		return "", ocispec.Descriptor{}, err
+		return "", ocispecs.Descriptor{}, err
 	}
 
 	in, desc, err := r.resolver().Resolve(ctx, ref.String())
 	if err != nil {
-		return "", ocispec.Descriptor{}, err
+		return "", ocispecs.Descriptor{}, err
 	}
 
 	return in, desc, nil
 }
 
-func (r *Resolver) Get(ctx context.Context, in string) ([]byte, ocispec.Descriptor, error) {
+func (r *Resolver) Get(ctx context.Context, in string) ([]byte, ocispecs.Descriptor, error) {
 	in, desc, err := r.Resolve(ctx, in)
 	if err != nil {
-		return nil, ocispec.Descriptor{}, err
+		return nil, ocispecs.Descriptor{}, err
 	}
 
 	dt, err := r.GetDescriptor(ctx, in, desc)
 	if err != nil {
-		return nil, ocispec.Descriptor{}, err
+		return nil, ocispecs.Descriptor{}, err
 	}
 	return dt, desc, nil
 }
 
-func (r *Resolver) GetDescriptor(ctx context.Context, in string, desc ocispec.Descriptor) ([]byte, error) {
+func (r *Resolver) GetDescriptor(ctx context.Context, in string, desc ocispecs.Descriptor) ([]byte, error) {
 	fetcher, err := r.resolver().Fetcher(ctx, in)
 	if err != nil {
 		return nil, err
diff --git a/util/imagetools/loader.go b/util/imagetools/loader.go
index eaba4d11..3650bcaf 100644
--- a/util/imagetools/loader.go
+++ b/util/imagetools/loader.go
@@ -20,7 +20,7 @@ import (
 	intoto "github.com/in-toto/in-toto-golang/in_toto"
 	"github.com/moby/buildkit/util/contentutil"
 	"github.com/opencontainers/go-digest"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"golang.org/x/sync/errgroup"
 )
@@ -49,17 +49,17 @@ type loader struct {
 }
 
 type manifest struct {
-	desc     ocispec.Descriptor
-	manifest ocispec.Manifest
+	desc     ocispecs.Descriptor
+	manifest ocispecs.Manifest
 }
 
 type index struct {
-	desc  ocispec.Descriptor
-	index ocispec.Index
+	desc  ocispecs.Descriptor
+	index ocispecs.Index
 }
 
 type asset struct {
-	config     *ocispec.Image
+	config     *ocispecs.Image
 	sbom       *sbomStub
 	provenance *provenanceStub
 
@@ -153,15 +153,15 @@ func (l *loader) Load(ctx context.Context, ref string) (*result, error) {
 	return r, nil
 }
 
-func (l *loader) fetch(ctx context.Context, fetcher remotes.Fetcher, desc ocispec.Descriptor, r *result) error {
+func (l *loader) fetch(ctx context.Context, fetcher remotes.Fetcher, desc ocispecs.Descriptor, r *result) error {
 	_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, desc)
 	if err != nil {
 		return err
 	}
 
 	switch desc.MediaType {
-	case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
-		var mfst ocispec.Manifest
+	case images.MediaTypeDockerSchema2Manifest, ocispecs.MediaTypeImageManifest:
+		var mfst ocispecs.Manifest
 		dt, err := content.ReadBlob(ctx, l.cache, desc)
 		if err != nil {
 			return err
@@ -205,8 +205,8 @@ func (l *loader) fetch(ctx context.Context, fetcher remotes.Fetcher, desc ocispe
 			r.images[platforms.Format(platforms.Normalize(*p))] = desc.Digest
 			r.mu.Unlock()
 		}
-	case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
-		var idx ocispec.Index
+	case images.MediaTypeDockerSchema2ManifestList, ocispecs.MediaTypeImageIndex:
+		var idx ocispecs.Index
 		dt, err := content.ReadBlob(ctx, l.cache, desc)
 		if err != nil {
 			return err
@@ -225,7 +225,6 @@ func (l *loader) fetch(ctx context.Context, fetcher remotes.Fetcher, desc ocispe
 
 		eg, ctx := errgroup.WithContext(ctx)
 		for _, d := range idx.Manifests {
-			d := d
 			eg.Go(func() error {
 				return l.fetch(ctx, fetcher, d, r)
 			})
@@ -239,7 +238,7 @@ func (l *loader) fetch(ctx context.Context, fetcher remotes.Fetcher, desc ocispe
 	return nil
 }
 
-func (l *loader) readPlatformFromConfig(ctx context.Context, fetcher remotes.Fetcher, desc ocispec.Descriptor) (*ocispec.Platform, error) {
+func (l *loader) readPlatformFromConfig(ctx context.Context, fetcher remotes.Fetcher, desc ocispecs.Descriptor) (*ocispecs.Platform, error) {
 	_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, desc)
 	if err != nil {
 		return nil, err
@@ -250,19 +249,19 @@ func (l *loader) readPlatformFromConfig(ctx context.Context, fetcher remotes.Fet
 		return nil, err
 	}
 
-	var config ocispec.Image
+	var config ocispecs.Image
 	if err := json.Unmarshal(dt, &config); err != nil {
 		return nil, err
 	}
 
-	return &ocispec.Platform{
+	return &ocispecs.Platform{
 		OS:           config.OS,
 		Architecture: config.Architecture,
 		Variant:      config.Variant,
 	}, nil
 }
 
-func (l *loader) scanConfig(ctx context.Context, fetcher remotes.Fetcher, desc ocispec.Descriptor, as *asset) error {
+func (l *loader) scanConfig(ctx context.Context, fetcher remotes.Fetcher, desc ocispecs.Descriptor, as *asset) error {
 	_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, desc)
 	if err != nil {
 		return err
@@ -374,11 +373,11 @@ func (l *loader) scanProvenance(ctx context.Context, fetcher remotes.Fetcher, r
 	return nil
 }
 
-func (r *result) Configs() map[string]*ocispec.Image {
+func (r *result) Configs() map[string]*ocispecs.Image {
 	if len(r.assets) == 0 {
 		return nil
 	}
-	res := make(map[string]*ocispec.Image)
+	res := make(map[string]*ocispecs.Image)
 	for p, a := range r.assets {
 		if a.config == nil {
 			continue
diff --git a/util/imagetools/printers.go b/util/imagetools/printers.go
index ab6fef1b..2d3e795a 100644
--- a/util/imagetools/printers.go
+++ b/util/imagetools/printers.go
@@ -114,7 +114,7 @@ func (p *Printer) Print(raw bool, out io.Writer) error {
 			Manifests     []ocispecs.Descriptor `json:"manifests"`
 			Annotations   map[string]string     `json:"annotations,omitempty"`
 		}{
-			SchemaVersion: p.index.Versioned.SchemaVersion,
+			SchemaVersion: p.index.SchemaVersion,
 			MediaType:     p.index.MediaType,
 			Digest:        p.manifest.Digest,
 			Size:          p.manifest.Size,
diff --git a/util/platformutil/parse.go b/util/platformutil/parse.go
index 608fb3ee..b95855ff 100644
--- a/util/platformutil/parse.go
+++ b/util/platformutil/parse.go
@@ -4,14 +4,14 @@ import (
 	"strings"
 
 	"github.com/containerd/platforms"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
-func Parse(platformsStr []string) ([]specs.Platform, error) {
+func Parse(platformsStr []string) ([]ocispecs.Platform, error) {
 	if len(platformsStr) == 0 {
 		return nil, nil
 	}
-	out := make([]specs.Platform, 0, len(platformsStr))
+	out := make([]ocispecs.Platform, 0, len(platformsStr))
 	for _, s := range platformsStr {
 		parts := strings.Split(s, ",")
 		if len(parts) > 1 {
@@ -31,16 +31,16 @@ func Parse(platformsStr []string) ([]specs.Platform, error) {
 	return out, nil
 }
 
-func parse(in string) (specs.Platform, error) {
+func parse(in string) (ocispecs.Platform, error) {
 	if strings.EqualFold(in, "local") {
 		return platforms.DefaultSpec(), nil
 	}
 	return platforms.Parse(in)
 }
 
-func Dedupe(in []specs.Platform) []specs.Platform {
+func Dedupe(in []ocispecs.Platform) []ocispecs.Platform {
 	m := map[string]struct{}{}
-	out := make([]specs.Platform, 0, len(in))
+	out := make([]ocispecs.Platform, 0, len(in))
 	for _, p := range in {
 		p := platforms.Normalize(p)
 		key := platforms.Format(p)
@@ -53,7 +53,7 @@ func Dedupe(in []specs.Platform) []specs.Platform {
 	return out
 }
 
-func FormatInGroups(gg ...[]specs.Platform) []string {
+func FormatInGroups(gg ...[]ocispecs.Platform) []string {
 	m := map[string]struct{}{}
 	out := make([]string, 0, len(gg))
 	for i, g := range gg {
@@ -74,7 +74,7 @@ func FormatInGroups(gg ...[]specs.Platform) []string {
 	return out
 }
 
-func Format(in []specs.Platform) []string {
+func Format(in []ocispecs.Platform) []string {
 	if len(in) == 0 {
 		return nil
 	}



Test patch:
diff --git a/bake/bake_test.go b/bake/bake_test.go
index 40ff01bd..482b83ad 100644
--- a/bake/bake_test.go
+++ b/bake/bake_test.go
@@ -1381,7 +1381,6 @@ target "d" {
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			m, g, err := ReadTargets(ctx, []File{f}, []string{"d"}, tt.overrides, nil, &EntitlementConf{})
 			require.NoError(t, err)
@@ -1454,7 +1453,6 @@ group "default" {
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			m, g, err := ReadTargets(ctx, []File{f}, []string{"default"}, tt.overrides, nil, &EntitlementConf{})
 			require.NoError(t, err)
@@ -1509,7 +1507,6 @@ func TestTargetName(t *testing.T) {
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(tt.target, func(t *testing.T) {
 			_, _, err := ReadTargets(ctx, []File{{
 				Name: "docker-bake.hcl",
@@ -1600,7 +1597,6 @@ target "f" {
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(strings.Join(tt.names, "+"), func(t *testing.T) {
 			m, g, err := ReadTargets(ctx, []File{f}, tt.names, nil, nil, &EntitlementConf{})
 			require.NoError(t, err)
diff --git a/bake/compose_test.go b/bake/compose_test.go
index 7619fc7a..e19ff138 100644
--- a/bake/compose_test.go
+++ b/bake/compose_test.go
@@ -518,7 +518,6 @@ func TestServiceName(t *testing.T) {
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(tt.svc, func(t *testing.T) {
 			_, err := ParseCompose([]composetypes.ConfigFile{{Content: []byte(`
 services:
@@ -589,7 +588,6 @@ services:
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			_, err := ParseCompose([]composetypes.ConfigFile{{Content: tt.dt}}, nil)
 			if tt.wantErr {
@@ -665,7 +663,6 @@ target "default" {
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			isCompose, err := validateComposeFile(tt.dt, tt.fn)
 			assert.Equal(t, tt.isCompose, isCompose)
diff --git a/build/driver_test.go b/build/driver_test.go
index a65ba97d..1fbfeb42 100644
--- a/build/driver_test.go
+++ b/build/driver_test.go
@@ -7,41 +7,41 @@ import (
 
 	"github.com/containerd/platforms"
 	"github.com/docker/buildx/builder"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/stretchr/testify/require"
 )
 
 func TestFindDriverSanity(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.DefaultSpec()},
 	})
 
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.DefaultSpec()}, nil, platforms.OnlyStrict, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.DefaultSpec()}, nil, platforms.OnlyStrict, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
 	require.Equal(t, 0, res[0].driverIndex)
 	require.Equal(t, "aaa", res[0].Node().Builder)
-	require.Equal(t, []specs.Platform{platforms.DefaultSpec()}, res[0].platforms)
+	require.Equal(t, []ocispecs.Platform{platforms.DefaultSpec()}, res[0].platforms)
 }
 
 func TestFindDriverEmpty(t *testing.T) {
 	r := makeTestResolver(nil)
 
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.DefaultSpec()}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.DefaultSpec()}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Nil(t, res)
 }
 
 func TestFindDriverWeirdName(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64")},
 		"bbb": {platforms.MustParse("linux/foobar")},
 	})
 
 	// find first platform
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/foobar")}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/foobar")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
@@ -50,11 +50,11 @@ func TestFindDriverWeirdName(t *testing.T) {
 }
 
 func TestFindDriverUnknown(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64")},
 	})
 
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.False(t, perfect)
 	require.Len(t, res, 1)
@@ -63,13 +63,13 @@ func TestFindDriverUnknown(t *testing.T) {
 }
 
 func TestSelectNodeSinglePlatform(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64")},
 		"bbb": {platforms.MustParse("linux/riscv64")},
 	})
 
 	// find first platform
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/amd64")}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/amd64")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
@@ -77,7 +77,7 @@ func TestSelectNodeSinglePlatform(t *testing.T) {
 	require.Equal(t, "aaa", res[0].Node().Builder)
 
 	// find second platform
-	res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
+	res, perfect, err = r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
@@ -85,7 +85,7 @@ func TestSelectNodeSinglePlatform(t *testing.T) {
 	require.Equal(t, "bbb", res[0].Node().Builder)
 
 	// find an unknown platform, should match the first driver
-	res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/s390x")}, nil, platforms.Only, nil)
+	res, perfect, err = r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/s390x")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.False(t, perfect)
 	require.Len(t, res, 1)
@@ -94,26 +94,26 @@ func TestSelectNodeSinglePlatform(t *testing.T) {
 }
 
 func TestSelectNodeMultiPlatform(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64"), platforms.MustParse("linux/arm64")},
 		"bbb": {platforms.MustParse("linux/riscv64")},
 	})
 
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/amd64")}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/amd64")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
 	require.Equal(t, 0, res[0].driverIndex)
 	require.Equal(t, "aaa", res[0].Node().Builder)
 
-	res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm64")}, nil, platforms.Only, nil)
+	res, perfect, err = r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm64")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
 	require.Equal(t, 0, res[0].driverIndex)
 	require.Equal(t, "aaa", res[0].Node().Builder)
 
-	res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
+	res, perfect, err = r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
@@ -122,27 +122,27 @@ func TestSelectNodeMultiPlatform(t *testing.T) {
 }
 
 func TestSelectNodeNonStrict(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64")},
 		"bbb": {platforms.MustParse("linux/arm64")},
 	})
 
 	// arm64 should match itself
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm64")}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm64")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
 	require.Equal(t, "bbb", res[0].Node().Builder)
 
 	// arm64 may support arm/v8
-	res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
+	res, perfect, err = r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
 	require.Equal(t, "bbb", res[0].Node().Builder)
 
 	// arm64 may support arm/v7
-	res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
+	res, perfect, err = r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
@@ -150,19 +150,19 @@ func TestSelectNodeNonStrict(t *testing.T) {
 }
 
 func TestSelectNodeNonStrictARM(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64")},
 		"bbb": {platforms.MustParse("linux/arm64")},
 		"ccc": {platforms.MustParse("linux/arm/v8")},
 	})
 
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
 	require.Equal(t, "ccc", res[0].Node().Builder)
 
-	res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
+	res, perfect, err = r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
@@ -170,20 +170,20 @@ func TestSelectNodeNonStrictARM(t *testing.T) {
 }
 
 func TestSelectNodeNonStrictLower(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64")},
 		"bbb": {platforms.MustParse("linux/arm/v7")},
 	})
 
 	// v8 can't be built on v7 (so we should select the default)...
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm/v8")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.False(t, perfect)
 	require.Len(t, res, 1)
 	require.Equal(t, "aaa", res[0].Node().Builder)
 
 	// ...but v6 can be built on v8
-	res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v6")}, nil, platforms.Only, nil)
+	res, perfect, err = r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm/v6")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
@@ -191,13 +191,13 @@ func TestSelectNodeNonStrictLower(t *testing.T) {
 }
 
 func TestSelectNodePreferStart(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64")},
 		"bbb": {platforms.MustParse("linux/riscv64")},
 		"ccc": {platforms.MustParse("linux/riscv64")},
 	})
 
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/riscv64")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
@@ -205,12 +205,12 @@ func TestSelectNodePreferStart(t *testing.T) {
 }
 
 func TestSelectNodePreferExact(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/arm/v8")},
 		"bbb": {platforms.MustParse("linux/arm/v7")},
 	})
 
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
@@ -218,12 +218,12 @@ func TestSelectNodePreferExact(t *testing.T) {
 }
 
 func TestSelectNodeNoPlatform(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/foobar")},
 		"bbb": {platforms.DefaultSpec()},
 	})
 
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
@@ -232,20 +232,20 @@ func TestSelectNodeNoPlatform(t *testing.T) {
 }
 
 func TestSelectNodeAdditionalPlatforms(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64")},
 		"bbb": {platforms.MustParse("linux/arm/v8")},
 	})
 
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, nil)
 	require.NoError(t, err)
 	require.True(t, perfect)
 	require.Len(t, res, 1)
 	require.Equal(t, "bbb", res[0].Node().Builder)
 
-	res, perfect, err = r.resolve(context.TODO(), []specs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, func(idx int, n builder.Node) []specs.Platform {
+	res, perfect, err = r.resolve(context.TODO(), []ocispecs.Platform{platforms.MustParse("linux/arm/v7")}, nil, platforms.Only, func(idx int, n builder.Node) []ocispecs.Platform {
 		if n.Builder == "aaa" {
-			return []specs.Platform{platforms.MustParse("linux/arm/v7")}
+			return []ocispecs.Platform{platforms.MustParse("linux/arm/v7")}
 		}
 		return nil
 	})
@@ -256,12 +256,12 @@ func TestSelectNodeAdditionalPlatforms(t *testing.T) {
 }
 
 func TestSplitNodeMultiPlatform(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64"), platforms.MustParse("linux/arm64")},
 		"bbb": {platforms.MustParse("linux/riscv64")},
 	})
 
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{
 		platforms.MustParse("linux/amd64"),
 		platforms.MustParse("linux/arm64"),
 	}, nil, platforms.Only, nil)
@@ -270,7 +270,7 @@ func TestSplitNodeMultiPlatform(t *testing.T) {
 	require.Len(t, res, 1)
 	require.Equal(t, "aaa", res[0].Node().Builder)
 
-	res, perfect, err = r.resolve(context.TODO(), []specs.Platform{
+	res, perfect, err = r.resolve(context.TODO(), []ocispecs.Platform{
 		platforms.MustParse("linux/amd64"),
 		platforms.MustParse("linux/riscv64"),
 	}, nil, platforms.Only, nil)
@@ -282,14 +282,14 @@ func TestSplitNodeMultiPlatform(t *testing.T) {
 }
 
 func TestSplitNodeMultiPlatformNoUnify(t *testing.T) {
-	r := makeTestResolver(map[string][]specs.Platform{
+	r := makeTestResolver(map[string][]ocispecs.Platform{
 		"aaa": {platforms.MustParse("linux/amd64")},
 		"bbb": {platforms.MustParse("linux/amd64"), platforms.MustParse("linux/riscv64")},
 	})
 
 	// the "best" choice would be the node with both platforms, but we're using
 	// a naive algorithm that doesn't try to unify the platforms
-	res, perfect, err := r.resolve(context.TODO(), []specs.Platform{
+	res, perfect, err := r.resolve(context.TODO(), []ocispecs.Platform{
 		platforms.MustParse("linux/amd64"),
 		platforms.MustParse("linux/riscv64"),
 	}, nil, platforms.Only, nil)
@@ -300,7 +300,7 @@ func TestSplitNodeMultiPlatformNoUnify(t *testing.T) {
 	require.Equal(t, "bbb", res[1].Node().Builder)
 }
 
-func makeTestResolver(nodes map[string][]specs.Platform) *nodeResolver {
+func makeTestResolver(nodes map[string][]ocispecs.Platform) *nodeResolver {
 	var ns []builder.Node
 	for name, platforms := range nodes {
 		ns = append(ns, builder.Node{
diff --git a/build/git_test.go b/build/git_test.go
index 1da16fb2..5b33049d 100644
--- a/build/git_test.go
+++ b/build/git_test.go
@@ -11,7 +11,7 @@ import (
 	"github.com/docker/buildx/util/gitutil"
 	"github.com/docker/buildx/util/gitutil/gittestutil"
 	"github.com/moby/buildkit/client"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
@@ -91,8 +91,8 @@ func TestGetGitAttributes(t *testing.T) {
 			envGitInfo:   "false",
 			expected: []string{
 				"label:" + DockerfileLabel,
-				"label:" + specs.AnnotationRevision,
-				"label:" + specs.AnnotationSource,
+				"label:" + ocispecs.AnnotationRevision,
+				"label:" + ocispecs.AnnotationSource,
 			},
 		},
 		{
@@ -101,15 +101,14 @@ func TestGetGitAttributes(t *testing.T) {
 			envGitInfo:   "",
 			expected: []string{
 				"label:" + DockerfileLabel,
-				"label:" + specs.AnnotationRevision,
-				"label:" + specs.AnnotationSource,
+				"label:" + ocispecs.AnnotationRevision,
+				"label:" + ocispecs.AnnotationSource,
 				"vcs:revision",
 				"vcs:source",
 			},
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			setupTest(t)
 			if tt.envGitLabels != "" {
@@ -125,9 +124,10 @@ func TestGetGitAttributes(t *testing.T) {
 			for _, e := range tt.expected {
 				assert.Contains(t, so.FrontendAttrs, e)
 				assert.NotEmpty(t, so.FrontendAttrs[e])
-				if e == "label:"+DockerfileLabel {
+				switch e {
+				case "label:" + DockerfileLabel:
 					assert.Equal(t, "Dockerfile", so.FrontendAttrs[e])
-				} else if e == "label:"+specs.AnnotationSource || e == "vcs:source" {
+				case "label:" + ocispecs.AnnotationSource, "vcs:source":
 					assert.Equal(t, "git@github.com:docker/buildx.git", so.FrontendAttrs[e])
 				}
 			}
@@ -155,10 +155,10 @@ func TestGetGitAttributesDirty(t *testing.T) {
 
 	assert.Contains(t, so.FrontendAttrs, "label:"+DockerfileLabel)
 	assert.Equal(t, "Dockerfile", so.FrontendAttrs["label:"+DockerfileLabel])
-	assert.Contains(t, so.FrontendAttrs, "label:"+specs.AnnotationSource)
-	assert.Equal(t, "git@github.com:docker/buildx.git", so.FrontendAttrs["label:"+specs.AnnotationSource])
-	assert.Contains(t, so.FrontendAttrs, "label:"+specs.AnnotationRevision)
-	assert.True(t, strings.HasSuffix(so.FrontendAttrs["label:"+specs.AnnotationRevision], "-dirty"))
+	assert.Contains(t, so.FrontendAttrs, "label:"+ocispecs.AnnotationSource)
+	assert.Equal(t, "git@github.com:docker/buildx.git", so.FrontendAttrs["label:"+ocispecs.AnnotationSource])
+	assert.Contains(t, so.FrontendAttrs, "label:"+ocispecs.AnnotationRevision)
+	assert.True(t, strings.HasSuffix(so.FrontendAttrs["label:"+ocispecs.AnnotationRevision], "-dirty"))
 
 	assert.Contains(t, so.FrontendAttrs, "vcs:source")
 	assert.Equal(t, "git@github.com:docker/buildx.git", so.FrontendAttrs["vcs:source"])
diff --git a/build/utils_test.go b/build/utils_test.go
index f12eda3a..02b597b9 100644
--- a/build/utils_test.go
+++ b/build/utils_test.go
@@ -130,7 +130,6 @@ func TestToBuildkitExtraHosts(t *testing.T) {
 	}
 
 	for _, tc := range tests {
-		tc := tc
 		if tc.expectedOut == "" {
 			tc.expectedOut = strings.Join(tc.input, ",")
 		}
diff --git a/builder/builder_test.go b/builder/builder_test.go
index 59ab5da8..6c308068 100644
--- a/builder/builder_test.go
+++ b/builder/builder_test.go
@@ -190,7 +190,6 @@ foo = "bar"
 		},
 	}
 	for _, tt := range testCases {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			flags, err := parseBuildkitdFlags(tt.flags, tt.driver, tt.driverOpts, tt.buildkitdConfigFile)
 			if tt.wantErr {
diff --git a/commands/ls_test.go b/commands/ls_test.go
index a428213a..cdfee843 100644
--- a/commands/ls_test.go
+++ b/commands/ls_test.go
@@ -164,7 +164,6 @@ func TestTruncPlatforms(t *testing.T) {
 		},
 	}
 	for _, tt := range tests {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			tpfs := truncPlatforms(tt.platforms, tt.max)
 			assert.Equal(t, tt.expectedList, tpfs.List())
diff --git a/controller/build/options_test.go b/controller/build/options_test.go
index 548351d0..aa814e78 100644
--- a/controller/build/options_test.go
+++ b/controller/build/options_test.go
@@ -240,7 +240,6 @@ func TestResolvePaths(t *testing.T) {
 		},
 	}
 	for _, tt := range tests {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			got, err := ResolveOptionPaths(tt.options)
 			require.NoError(t, err)
diff --git a/driver/docker/version_test.go b/driver/docker/version_test.go
index 03b2c6a6..c342ba86 100644
--- a/driver/docker/version_test.go
+++ b/driver/docker/version_test.go
@@ -9,7 +9,6 @@ import (
 
 func TestConstraint(t *testing.T) {
 	for _, tt := range mobyBuildkitVersions {
-		tt := tt
 		t.Run(tt.MobyVersionConstraint, func(t *testing.T) {
 			_, err := semver.NewConstraint(tt.MobyVersionConstraint)
 			require.NoError(t, err)
@@ -121,7 +120,6 @@ func TestResolveBuildKitVersion(t *testing.T) {
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(tt.mobyVersion, func(t *testing.T) {
 			bkVersion, err := resolveBuildKitVersion(tt.mobyVersion)
 			if tt.err {
diff --git a/tests/history.go b/tests/history.go
new file mode 100644
index 00000000..6ced64cf
--- /dev/null
+++ b/tests/history.go
@@ -0,0 +1,141 @@
+package tests
+
+import (
+	"encoding/json"
+	"os"
+	"path"
+	"path/filepath"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/moby/buildkit/util/testutil/integration"
+	"github.com/stretchr/testify/require"
+)
+
+var historyTests = []func(t *testing.T, sb integration.Sandbox){
+	testHistoryExport,
+	testHistoryExportFinalize,
+	testHistoryInspect,
+	testHistoryLs,
+	testHistoryRm,
+}
+
+func testHistoryExport(t *testing.T, sb integration.Sandbox) {
+	ref := buildTestProject(t, sb)
+	require.NotEmpty(t, ref.Ref)
+
+	outFile := path.Join(t.TempDir(), "export.dockerbuild")
+	cmd := buildxCmd(sb, withArgs("history", "export", ref.Ref, "--output", outFile))
+	out, err := cmd.Output()
+	require.NoError(t, err, string(out))
+	require.FileExists(t, outFile)
+}
+
+func testHistoryExportFinalize(t *testing.T, sb integration.Sandbox) {
+	ref := buildTestProject(t, sb)
+	require.NotEmpty(t, ref.Ref)
+
+	outFile := path.Join(t.TempDir(), "export.dockerbuild")
+	cmd := buildxCmd(sb, withArgs("history", "export", ref.Ref, "--finalize", "--output", outFile))
+	out, err := cmd.Output()
+	require.NoError(t, err, string(out))
+	require.FileExists(t, outFile)
+}
+
+func testHistoryInspect(t *testing.T, sb integration.Sandbox) {
+	ref := buildTestProject(t, sb)
+	require.NotEmpty(t, ref.Ref)
+
+	cmd := buildxCmd(sb, withArgs("history", "inspect", ref.Ref, "--format=json"))
+	out, err := cmd.Output()
+	require.NoError(t, err, string(out))
+
+	type recT struct {
+		Name              string
+		Ref               string
+		Context           string
+		Dockerfile        string
+		StartedAt         *time.Time
+		CompletedAt       *time.Time
+		Duration          time.Duration
+		Status            string
+		NumCompletedSteps int32
+		NumTotalSteps     int32
+		NumCachedSteps    int32
+	}
+	var rec recT
+	err = json.Unmarshal(out, &rec)
+	require.NoError(t, err)
+	require.Equal(t, ref.Ref, rec.Ref)
+	require.NotEmpty(t, rec.Name)
+}
+
+func testHistoryLs(t *testing.T, sb integration.Sandbox) {
+	ref := buildTestProject(t, sb)
+	require.NotEmpty(t, ref.Ref)
+
+	cmd := buildxCmd(sb, withArgs("history", "ls", "--filter=ref="+ref.Ref, "--format=json"))
+	out, err := cmd.Output()
+	require.NoError(t, err, string(out))
+
+	type recT struct {
+		Ref            string     `json:"ref"`
+		Name           string     `json:"name"`
+		Status         string     `json:"status"`
+		CreatedAt      *time.Time `json:"created_at"`
+		CompletedAt    *time.Time `json:"completed_at"`
+		TotalSteps     int32      `json:"total_steps"`
+		CompletedSteps int32      `json:"completed_steps"`
+		CachedSteps    int32      `json:"cached_steps"`
+	}
+	var rec recT
+	err = json.Unmarshal(out, &rec)
+	require.NoError(t, err)
+	require.Equal(t, ref.String(), rec.Ref)
+	require.NotEmpty(t, rec.Name)
+}
+
+func testHistoryRm(t *testing.T, sb integration.Sandbox) {
+	ref := buildTestProject(t, sb)
+	require.NotEmpty(t, ref.Ref)
+
+	cmd := buildxCmd(sb, withArgs("history", "rm", ref.Ref))
+	out, err := cmd.Output()
+	require.NoError(t, err, string(out))
+}
+
+type buildRef struct {
+	Builder string
+	Node    string
+	Ref     string
+}
+
+func (b buildRef) String() string {
+	return b.Builder + "/" + b.Node + "/" + b.Ref
+}
+
+func buildTestProject(t *testing.T, sb integration.Sandbox) buildRef {
+	dir := createTestProject(t)
+	out, err := buildCmd(sb, withArgs("--metadata-file", filepath.Join(dir, "md.json"), dir))
+	require.NoError(t, err, string(out))
+
+	dt, err := os.ReadFile(filepath.Join(dir, "md.json"))
+	require.NoError(t, err)
+
+	type mdT struct {
+		BuildRef string `json:"buildx.build.ref"`
+	}
+	var md mdT
+	err = json.Unmarshal(dt, &md)
+	require.NoError(t, err)
+
+	refParts := strings.Split(md.BuildRef, "/")
+	require.Len(t, refParts, 3)
+
+	return buildRef{
+		Builder: refParts[0],
+		Node:    refParts[1],
+		Ref:     refParts[2],
+	}
+}
diff --git a/tests/integration_test.go b/tests/integration_test.go
index 9cd76c7c..3884ca68 100644
--- a/tests/integration_test.go
+++ b/tests/integration_test.go
@@ -24,6 +24,7 @@ func TestIntegration(t *testing.T) {
 	tests = append(tests, commonTests...)
 	tests = append(tests, buildTests...)
 	tests = append(tests, bakeTests...)
+	tests = append(tests, historyTests...)
 	tests = append(tests, inspectTests...)
 	tests = append(tests, lsTests...)
 	tests = append(tests, imagetoolsTests...)
diff --git a/tests/ls.go b/tests/ls.go
index 23ad60d1..5898c7fb 100644
--- a/tests/ls.go
+++ b/tests/ls.go
@@ -36,7 +36,6 @@ func testLs(t *testing.T, sb integration.Sandbox) {
 
 	sbDriver, _, _ := driverName(sb.Name())
 	for _, tt := range tests {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			out, err := lsCmd(sb, withArgs(tt.args...))
 			require.NoError(t, err, out)
diff --git a/util/confutil/config_unix_test.go b/util/confutil/config_unix_test.go
index 2d217b4f..32bf3649 100644
--- a/util/confutil/config_unix_test.go
+++ b/util/confutil/config_unix_test.go
@@ -49,7 +49,6 @@ func TestIsSubPath(t *testing.T) {
 		},
 	}
 	for _, tt := range tests {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			ok, err := isSubPath(tt.basePath, tt.subPath)
 			require.NoError(t, err)
diff --git a/util/gitutil/credentials_test.go b/util/gitutil/credentials_test.go
index a2b7f529..7225f8dc 100644
--- a/util/gitutil/credentials_test.go
+++ b/util/gitutil/credentials_test.go
@@ -35,7 +35,6 @@ func TestStripCredentials(t *testing.T) {
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			if g, w := stripCredentials(tt.url), tt.want; g != w {
 				t.Fatalf("got: %q\nwant: %q", g, w)
diff --git a/util/gitutil/gitutil_test.go b/util/gitutil/gitutil_test.go
index cb3936fe..4eb09ba5 100644
--- a/util/gitutil/gitutil_test.go
+++ b/util/gitutil/gitutil_test.go
@@ -200,7 +200,6 @@ func TestGitRemoteURL(t *testing.T) {
 		},
 	}
 	for _, tt := range cases {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			gittestutil.Mktmp(t)
 			c, err := gitutil.New()
diff --git a/util/imagetools/imagetools_helpers_test.go b/util/imagetools/imagetools_helpers_test.go
index 925b9e70..8ac639c1 100644
--- a/util/imagetools/imagetools_helpers_test.go
+++ b/util/imagetools/imagetools_helpers_test.go
@@ -12,8 +12,7 @@ import (
 	intoto "github.com/in-toto/in-toto-golang/in_toto"
 	slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
 	"github.com/opencontainers/go-digest"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
-	v1 "github.com/opencontainers/image-spec/specs-go/v1"
+	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 type attestationType int
@@ -35,12 +34,12 @@ type mockResolver struct {
 var manifests = make(map[digest.Digest]manifest)
 var indexes = make(map[digest.Digest]index)
 
-func (f mockFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) {
+func (f mockFetcher) Fetch(ctx context.Context, desc ocispecs.Descriptor) (io.ReadCloser, error) {
 	switch desc.MediaType {
-	case ocispec.MediaTypeImageIndex:
+	case ocispecs.MediaTypeImageIndex:
 		reader := io.NopCloser(strings.NewReader(indexes[desc.Digest].desc.Annotations["test_content"]))
 		return reader, nil
-	case ocispec.MediaTypeImageManifest:
+	case ocispecs.MediaTypeImageManifest:
 		reader := io.NopCloser(strings.NewReader(manifests[desc.Digest].desc.Annotations["test_content"]))
 		return reader, nil
 	default:
@@ -49,7 +48,7 @@ func (f mockFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.Rea
 	}
 }
 
-func (r mockResolver) Resolve(ctx context.Context, ref string) (name string, desc ocispec.Descriptor, err error) {
+func (r mockResolver) Resolve(ctx context.Context, ref string) (name string, desc ocispecs.Descriptor, err error) {
 	d := digest.Digest(strings.ReplaceAll(ref, "docker.io/library/test@", ""))
 	return string(d), indexes[d].desc, nil
 }
@@ -77,8 +76,8 @@ func getImageNoAttestation() *result {
 func getImageWithAttestation(t attestationType) *result {
 	manifestList := getBaseManifests()
 
-	objManifest := ocispec.Manifest{
-		MediaType: v1.MediaTypeImageManifest,
+	objManifest := ocispecs.Manifest{
+		MediaType: ocispecs.MediaTypeImageManifest,
 		Layers:    getAttestationLayers(t),
 		Annotations: map[string]string{
 			"platform": "linux/amd64",
@@ -89,8 +88,8 @@ func getImageWithAttestation(t attestationType) *result {
 	d := digest.FromString(jsonString)
 
 	manifestList[d] = manifest{
-		desc: ocispec.Descriptor{
-			MediaType: v1.MediaTypeImageManifest,
+		desc: ocispecs.Descriptor{
+			MediaType: ocispecs.MediaTypeImageManifest,
 			Digest:    d,
 			Size:      int64(len(jsonString)),
 			Annotations: map[string]string{
@@ -98,7 +97,7 @@ func getImageWithAttestation(t attestationType) *result {
 				"vnd.docker.reference.type":   "attestation-manifest",
 				"test_content":                jsonString,
 			},
-			Platform: &v1.Platform{
+			Platform: &ocispecs.Platform{
 				Architecture: "unknown",
 				OS:           "unknown",
 			},
@@ -106,8 +105,8 @@ func getImageWithAttestation(t attestationType) *result {
 		manifest: objManifest,
 	}
 
-	objManifest = ocispec.Manifest{
-		MediaType: v1.MediaTypeImageManifest,
+	objManifest = ocispecs.Manifest{
+		MediaType: ocispecs.MediaTypeImageManifest,
 		Layers:    getAttestationLayers(t),
 		Annotations: map[string]string{
 			"platform": "linux/arm64",
@@ -117,8 +116,8 @@ func getImageWithAttestation(t attestationType) *result {
 	jsonString = string(jsonContent)
 	d = digest.FromString(jsonString)
 	manifestList[d] = manifest{
-		desc: ocispec.Descriptor{
-			MediaType: v1.MediaTypeImageManifest,
+		desc: ocispecs.Descriptor{
+			MediaType: ocispecs.MediaTypeImageManifest,
 			Digest:    d,
 			Size:      int64(len(jsonString)),
 			Annotations: map[string]string{
@@ -126,7 +125,7 @@ func getImageWithAttestation(t attestationType) *result {
 				"vnd.docker.reference.type":   "attestation-manifest",
 				"test_content":                jsonString,
 			},
-			Platform: &v1.Platform{
+			Platform: &ocispecs.Platform{
 				Architecture: "unknown",
 				OS:           "unknown",
 			},
@@ -148,13 +147,13 @@ func getImageFromManifests(manifests map[digest.Digest]manifest) *result {
 	r.images["linux/amd64"] = getManifestDigestForArch(manifests, "linux", "amd64")
 	r.images["linux/arm64"] = getManifestDigestForArch(manifests, "linux", "arm64")
 
-	manifestsDesc := []v1.Descriptor{}
+	manifestsDesc := []ocispecs.Descriptor{}
 	for _, val := range manifests {
 		manifestsDesc = append(manifestsDesc, val.desc)
 	}
 
-	objIndex := v1.Index{
-		MediaType: v1.MediaTypeImageIndex,
+	objIndex := ocispecs.Index{
+		MediaType: ocispecs.MediaTypeImageIndex,
 		Manifests: manifestsDesc,
 	}
 	jsonContent, _ := json.Marshal(objIndex)
@@ -163,8 +162,8 @@ func getImageFromManifests(manifests map[digest.Digest]manifest) *result {
 
 	if _, ok := indexes[d]; !ok {
 		indexes[d] = index{
-			desc: ocispec.Descriptor{
-				MediaType: v1.MediaTypeImageIndex,
+			desc: ocispecs.Descriptor{
+				MediaType: ocispecs.MediaTypeImageIndex,
 				Digest:    d,
 				Size:      int64(len(jsonString)),
 				Annotations: map[string]string{
@@ -193,12 +192,12 @@ func getBaseManifests() map[digest.Digest]manifest {
 	if len(manifests) == 0 {
 		config := getConfig()
 		content := "amd64-content"
-		objManifest := ocispec.Manifest{
-			MediaType: v1.MediaTypeImageManifest,
+		objManifest := ocispecs.Manifest{
+			MediaType: ocispecs.MediaTypeImageManifest,
 			Config:    config,
-			Layers: []v1.Descriptor{
+			Layers: []ocispecs.Descriptor{
 				{
-					MediaType: v1.MediaTypeImageLayerGzip,
+					MediaType: ocispecs.MediaTypeImageLayerGzip,
 					Digest:    digest.FromString(content),
 					Size:      int64(len(content)),
 				},
@@ -209,11 +208,11 @@ func getBaseManifests() map[digest.Digest]manifest {
 		d := digest.FromString(jsonString)
 
 		manifests[d] = manifest{
-			desc: ocispec.Descriptor{
-				MediaType: v1.MediaTypeImageManifest,
+			desc: ocispecs.Descriptor{
+				MediaType: ocispecs.MediaTypeImageManifest,
 				Digest:    d,
 				Size:      int64(len(jsonString)),
-				Platform: &v1.Platform{
+				Platform: &ocispecs.Platform{
 					Architecture: "amd64",
 					OS:           "linux",
 				},
@@ -225,12 +224,12 @@ func getBaseManifests() map[digest.Digest]manifest {
 		}
 
 		content = "arm64-content"
-		objManifest = ocispec.Manifest{
-			MediaType: v1.MediaTypeImageManifest,
+		objManifest = ocispecs.Manifest{
+			MediaType: ocispecs.MediaTypeImageManifest,
 			Config:    config,
-			Layers: []v1.Descriptor{
+			Layers: []ocispecs.Descriptor{
 				{
-					MediaType: v1.MediaTypeImageLayerGzip,
+					MediaType: ocispecs.MediaTypeImageLayerGzip,
 					Digest:    digest.FromString(content),
 					Size:      int64(len(content)),
 				},
@@ -241,11 +240,11 @@ func getBaseManifests() map[digest.Digest]manifest {
 		d = digest.FromString(jsonString)
 
 		manifests[d] = manifest{
-			desc: ocispec.Descriptor{
-				MediaType: v1.MediaTypeImageManifest,
+			desc: ocispecs.Descriptor{
+				MediaType: ocispecs.MediaTypeImageManifest,
 				Digest:    d,
 				Size:      int64(len(jsonString)),
-				Platform: &v1.Platform{
+				Platform: &ocispecs.Platform{
 					Architecture: "arm64",
 					OS:           "linux",
 				},
@@ -260,8 +259,8 @@ func getBaseManifests() map[digest.Digest]manifest {
 	return manifests
 }
 
-func getConfig() v1.Descriptor {
-	config := v1.ImageConfig{
+func getConfig() ocispecs.Descriptor {
+	config := ocispecs.ImageConfig{
 		Env: []string{
 			"config",
 		},
@@ -270,8 +269,8 @@ func getConfig() v1.Descriptor {
 	jsonString := string(jsonContent)
 	d := digest.FromString(jsonString)
 
-	return v1.Descriptor{
-		MediaType: ocispec.MediaTypeImageConfig,
+	return ocispecs.Descriptor{
+		MediaType: ocispecs.MediaTypeImageConfig,
 		Digest:    d,
 		Size:      int64(len(jsonString)),
 		Annotations: map[string]string{
@@ -280,11 +279,11 @@ func getConfig() v1.Descriptor {
 	}
 }
 
-func getAttestationLayers(t attestationType) []v1.Descriptor {
-	layers := []v1.Descriptor{}
+func getAttestationLayers(t attestationType) []ocispecs.Descriptor {
+	layers := []ocispecs.Descriptor{}
 
 	if t == plainSpdx || t == plainSpdxAndDSSEEmbed {
-		layers = append(layers, v1.Descriptor{
+		layers = append(layers, ocispecs.Descriptor{
 			MediaType: inTotoGenericMime,
 			Digest:    digest.FromString(attestationContent),
 			Size:      int64(len(attestationContent)),
@@ -293,7 +292,7 @@ func getAttestationLayers(t attestationType) []v1.Descriptor {
 				"test_content":              attestationContent,
 			},
 		})
-		layers = append(layers, v1.Descriptor{
+		layers = append(layers, ocispecs.Descriptor{
 			MediaType: inTotoGenericMime,
 			Digest:    digest.FromString(provenanceContent),
 			Size:      int64(len(provenanceContent)),
@@ -307,7 +306,7 @@ func getAttestationLayers(t attestationType) []v1.Descriptor {
 	if t == dsseEmbeded || t == plainSpdxAndDSSEEmbed {
 		dsseAttestation := fmt.Sprintf("{\"payload\":\"%s\"}", base64.StdEncoding.EncodeToString([]byte(attestationContent)))
 		dsseProvenance := fmt.Sprintf("{\"payload\":\"%s\"}", base64.StdEncoding.EncodeToString([]byte(provenanceContent)))
-		layers = append(layers, v1.Descriptor{
+		layers = append(layers, ocispecs.Descriptor{
 			MediaType: inTotoSPDXDSSEMime,
 			Digest:    digest.FromString(dsseAttestation),
 			Size:      int64(len(dsseAttestation)),
@@ -316,7 +315,7 @@ func getAttestationLayers(t attestationType) []v1.Descriptor {
 				"test_content":              dsseAttestation,
 			},
 		})
-		layers = append(layers, v1.Descriptor{
+		layers = append(layers, ocispecs.Descriptor{
 			MediaType: inTotoProvenanceDSSEMime,
 			Digest:    digest.FromString(dsseProvenance),
 			Size:      int64(len(dsseProvenance)),
diff --git a/util/otelutil/span_test.go b/util/otelutil/span_test.go
index fb52d109..b4b50005 100644
--- a/util/otelutil/span_test.go
+++ b/util/otelutil/span_test.go
@@ -145,7 +145,6 @@ func TestAsAttributeKeyValue(t *testing.T) {
 		},
 	}
 	for _, tt := range tests {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			kv := keyValue{
 				Key:   "key",