version: expose Dockerfile frontend version

Expose the builtin Dockerfile frontend version in BuildKit version
APIs and buildctl debug output.

Move Dockerfile version logic into frontend/dockerfile/version and
validate that the builtin version constant matches release tags.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi committed 2026-05-06 10:42:32 -07:00
1 parent b3fe2874cb
commit 1890989989
15 files changed
+139 -63

No files matched your search

+17 -8
View File
@@ -192,12 +192,13 @@ func (x *GCPolicy) GetMinFreeSpace() int64 {
}
type BuildkitVersion struct {
state protoimpl.MessageState `protogen:"open.v1"`
Package string `protobuf:"bytes,1,opt,name=package,proto3" json:"package,omitempty"`
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Package string `protobuf:"bytes,1,opt,name=package,proto3" json:"package,omitempty"`
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"`
DockerfileVersion string `protobuf:"bytes,4,opt,name=dockerfileVersion,proto3" json:"dockerfileVersion,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuildkitVersion) Reset() {
@@ -251,6 +252,13 @@ func (x *BuildkitVersion) GetRevision() string {
return ""
}
func (x *BuildkitVersion) GetDockerfileVersion() string {
if x != nil {
return x.DockerfileVersion
}
return ""
}
type CDIDevice struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
@@ -342,11 +350,12 @@ const file_github_com_moby_buildkit_api_types_worker_proto_rawDesc = "" +
"\afilters\x18\x04 \x03(\tR\afilters\x12$\n" +
"\rreservedSpace\x18\x03 \x01(\x03R\rreservedSpace\x12\"\n" +
"\fmaxUsedSpace\x18\x05 \x01(\x03R\fmaxUsedSpace\x12\"\n" +
"\fminFreeSpace\x18\x06 \x01(\x03R\fminFreeSpace\"a\n" +
"\fminFreeSpace\x18\x06 \x01(\x03R\fminFreeSpace\"\x8f\x01\n" +
"\x0fBuildkitVersion\x12\x18\n" +
"\apackage\x18\x01 \x01(\tR\apackage\x12\x18\n" +
"\aversion\x18\x02 \x01(\tR\aversion\x12\x1a\n" +
"\brevision\x18\x03 \x01(\tR\brevision\"\xef\x01\n" +
"\brevision\x18\x03 \x01(\tR\brevision\x12,\n" +
"\x11dockerfileVersion\x18\x04 \x01(\tR\x11dockerfileVersion\"\xef\x01\n" +
"\tCDIDevice\x12\x12\n" +
"\x04Name\x18\x01 \x01(\tR\x04Name\x12\x1c\n" +
"\tAutoAllow\x18\x02 \x01(\bR\tAutoAllow\x12T\n" +
+2 -1
View File
@@ -30,6 +30,7 @@ message BuildkitVersion {
string package = 1;
string version = 2;
string revision = 3;
string dockerfileVersion = 4;
}
message CDIDevice {
@@ -37,4 +38,4 @@ message CDIDevice {
bool AutoAllow = 2;
map<string, string> Annotations = 3;
bool OnDemand = 4;
}
}
+47
View File
@@ -100,6 +100,7 @@ func (m *BuildkitVersion) CloneVT() *BuildkitVersion {
r.Package = m.Package
r.Version = m.Version
r.Revision = m.Revision
r.DockerfileVersion = m.DockerfileVersion
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields)
@@ -277,6 +278,9 @@ func (this *BuildkitVersion) EqualVT(that *BuildkitVersion) bool {
if this.Revision != that.Revision {
return false
}
if this.DockerfileVersion != that.DockerfileVersion {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
@@ -531,6 +535,13 @@ func (m *BuildkitVersion) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.DockerfileVersion) > 0 {
i -= len(m.DockerfileVersion)
copy(dAtA[i:], m.DockerfileVersion)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DockerfileVersion)))
i--
dAtA[i] = 0x22
}
if len(m.Revision) > 0 {
i -= len(m.Revision)
copy(dAtA[i:], m.Revision)
@@ -727,6 +738,10 @@ func (m *BuildkitVersion) SizeVT() (n int) {
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.DockerfileVersion)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
@@ -1411,6 +1426,38 @@ func (m *BuildkitVersion) UnmarshalVT(dAtA []byte) error {
}
m.Revision = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field DockerfileVersion", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.DockerfileVersion = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
+8 -6
View File
@@ -13,9 +13,10 @@ type Info struct {
}
type BuildkitVersion struct {
Package string `json:"package"`
Version string `json:"version"`
Revision string `json:"revision"`
Package string `json:"package"`
Version string `json:"version"`
Revision string `json:"revision"`
DockerfileVersion string `json:"dockerfileVersion,omitempty"`
}
type CDIDevice struct {
@@ -40,9 +41,10 @@ func fromAPIBuildkitVersion(in *apitypes.BuildkitVersion) BuildkitVersion {
return BuildkitVersion{}
}
return BuildkitVersion{
Package: in.Package,
Version: in.Version,
Revision: in.Revision,
Package: in.Package,
Version: in.Version,
Revision: in.Revision,
DockerfileVersion: in.DockerfileVersion,
}
}
+3
View File
@@ -44,5 +44,8 @@ func info(clicontext *cli.Context) error {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
_, _ = fmt.Fprintf(w, "BuildKit:\t%s %s %s\n", res.BuildkitVersion.Package, res.BuildkitVersion.Version, res.BuildkitVersion.Revision)
if res.BuildkitVersion.DockerfileVersion != "" {
_, _ = fmt.Fprintf(w, "Dockerfile:\t%s\n", res.BuildkitVersion.DockerfileVersion)
}
return w.Flush()
}
+3
View File
@@ -78,6 +78,9 @@ func printWorkersVerbose(tw *tabwriter.Writer, winfo []*client.WorkerInfo) {
fmt.Fprintf(tw, "ID:\t%s\n", wi.ID)
fmt.Fprintf(tw, "Platforms:\t%s\n", joinPlatforms(wi.Platforms))
fmt.Fprintf(tw, "BuildKit:\t%s %s %s\n", wi.BuildkitVersion.Package, wi.BuildkitVersion.Version, wi.BuildkitVersion.Revision)
if wi.BuildkitVersion.DockerfileVersion != "" {
fmt.Fprintf(tw, "Dockerfile:\t%s\n", wi.BuildkitVersion.DockerfileVersion)
}
fmt.Fprintf(tw, "Labels:\n")
for _, k := range sortedKeys(wi.Labels) {
v := wi.Labels[k]
+6 -1
View File
@@ -35,6 +35,7 @@ import (
"github.com/moby/buildkit/executor/oci"
"github.com/moby/buildkit/frontend"
dockerfile "github.com/moby/buildkit/frontend/dockerfile/builder"
dockerfileversion "github.com/moby/buildkit/frontend/dockerfile/version"
"github.com/moby/buildkit/frontend/gateway"
"github.com/moby/buildkit/frontend/gateway/forwarder"
"github.com/moby/buildkit/session"
@@ -986,11 +987,15 @@ func getGCPolicy(cfg config.GCConfig, root string) []client.PruneInfo {
}
func getBuildkitVersion() client.BuildkitVersion {
return client.BuildkitVersion{
buildkitVersion := client.BuildkitVersion{
Package: version.Package,
Version: version.Version,
Revision: version.Revision,
}
if dockerfileVersion := dockerfileversion.Version(); dockerfileVersion != "" {
buildkitVersion.DockerfileVersion = dockerfileVersion
}
return buildkitVersion
}
func getDNSConfig(cfg *config.DNSConfig) *oci.DNSConfig {
+14 -8
View File
@@ -27,6 +27,7 @@ import (
"github.com/moby/buildkit/exporter/util/epoch"
"github.com/moby/buildkit/frontend"
"github.com/moby/buildkit/frontend/attestations"
dockerfileversion "github.com/moby/buildkit/frontend/dockerfile/version"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/grpchijack"
containerdsnapshot "github.com/moby/buildkit/snapshot/containerd"
@@ -630,12 +631,16 @@ func (c *Controller) ListWorkers(ctx context.Context, r *controlapi.ListWorkersR
}
func (c *Controller) Info(ctx context.Context, r *controlapi.InfoRequest) (*controlapi.InfoResponse, error) {
buildkitVersion := toPBBuildkitVersion(client.BuildkitVersion{
Package: version.Package,
Version: version.Version,
Revision: version.Revision,
})
if dockerfileVersion := dockerfileversion.Version(); dockerfileVersion != "" {
buildkitVersion.DockerfileVersion = dockerfileVersion
}
return &controlapi.InfoResponse{
BuildkitVersion: &apitypes.BuildkitVersion{
Package: version.Package,
Version: version.Version,
Revision: version.Revision,
},
BuildkitVersion: buildkitVersion,
}, nil
}
@@ -716,9 +721,10 @@ func toPBGCPolicy(in []client.PruneInfo) []*apitypes.GCPolicy {
func toPBBuildkitVersion(in client.BuildkitVersion) *apitypes.BuildkitVersion {
return &apitypes.BuildkitVersion{
Package: in.Package,
Version: in.Version,
Revision: in.Revision,
Package: in.Package,
Version: in.Version,
Revision: in.Revision,
DockerfileVersion: in.DockerfileVersion,
}
}
-3
View File
@@ -1,3 +0,0 @@
package builder
const Version = "1.24"
@@ -25,24 +25,26 @@ RUN --mount=target=. <<EOT
fi
if [ "$CHANNEL" = "mainline" ]; then
VERSION=$(git describe --always --tags --match "dockerfile/[0-9]*")
EXACT_TAG=$(git describe --exact-match --tags --match "dockerfile/[0-9]*" 2>/dev/null || true)
else
VERSION=$(git describe --always --tags --match "dockerfile/[0-9]*-$CHANNEL")
EXACT_TAG=$(git describe --exact-match --tags --match "dockerfile/[0-9]*-$CHANNEL" 2>/dev/null || true)
fi
BUILTIN_VERSION=$(sed -n 's/^const Version = "\\(.*\\)"$/\\1/p' ./frontend/dockerfile/builder/version.go)
BUILTIN_VERSION=$(sed -n 's/^const version = "\(.*\)"$/\1/p' ./frontend/dockerfile/version/version.go)
case "$BUILTIN_VERSION" in
*.*.*) EXPECTED_VERSION="$BUILTIN_VERSION" ;;
*.*) EXPECTED_VERSION="$BUILTIN_VERSION.0" ;;
*)
echo "invalid frontend/dockerfile/builder/version.go version: $BUILTIN_VERSION"
echo "invalid frontend/dockerfile/version/version.go version: $BUILTIN_VERSION"
exit 1
;;
esac
case "$VERSION" in
case "$EXACT_TAG" in
dockerfile/*)
ACTUAL_VERSION=${VERSION#dockerfile/}
ACTUAL_VERSION=${EXACT_TAG#dockerfile/}
ACTUAL_VERSION=${ACTUAL_VERSION%%-*}
if [ "$ACTUAL_VERSION" != "$EXPECTED_VERSION" ]; then
echo "frontend/dockerfile/builder/version.go version $BUILTIN_VERSION does not match external frontend version $VERSION"
echo "frontend/dockerfile/version/version.go version $BUILTIN_VERSION does not match external frontend version $EXACT_TAG"
exit 1
fi
;;
@@ -27,7 +27,6 @@ import (
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/exporter/containerimage/exptypes"
dockerfilebuilder "github.com/moby/buildkit/frontend/dockerfile/builder"
"github.com/moby/buildkit/frontend/dockerui"
gateway "github.com/moby/buildkit/frontend/gateway/client"
"github.com/moby/buildkit/identity"
@@ -70,6 +69,13 @@ func init() {
allTests = append(allTests, provenanceTests...)
}
func daemonDockerfileVersion(ctx context.Context, t *testing.T, c *client.Client) string {
info, err := c.Info(ctx)
require.NoError(t, err)
require.NotEmpty(t, info.BuildkitVersion.DockerfileVersion)
return info.BuildkitVersion.DockerfileVersion
}
func testProvenanceAttestation(t *testing.T, sb integration.Sandbox) {
workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance)
ctx := sb.Context()
@@ -191,10 +197,7 @@ RUN echo ok> /foo
if isDockerd {
expCustom = provenancetypes.ProvenanceCustomEnv{}
}
expectedDockerfileVersionPrefix := dockerfilebuilder.Version
if strings.Count(expectedDockerfileVersionPrefix, ".") == 1 {
expectedDockerfileVersionPrefix += ".0"
}
expectedDockerfileVersion := daemonDockerfileVersion(ctx, t, c)
if slsaVersion == "" || slsaVersion == "v1" {
type stmtT struct {
@@ -285,7 +288,7 @@ RUN echo ok> /foo
if isClient || isGateway {
require.Empty(t, pred.BuildDefinition.InternalParameters.DockerfileVersion)
} else {
require.True(t, strings.HasPrefix(pred.BuildDefinition.InternalParameters.DockerfileVersion, expectedDockerfileVersionPrefix))
require.Equal(t, expectedDockerfileVersion, pred.BuildDefinition.InternalParameters.DockerfileVersion)
}
require.False(t, pred.RunDetails.Metadata.Completeness.ResolvedDependencies)
@@ -359,7 +362,7 @@ RUN echo ok> /foo
if isClient || isGateway {
require.Empty(t, pred.Invocation.Environment.DockerfileVersion)
} else {
require.True(t, strings.HasPrefix(pred.Invocation.Environment.DockerfileVersion, expectedDockerfileVersionPrefix))
require.Equal(t, expectedDockerfileVersion, pred.Invocation.Environment.DockerfileVersion)
}
expectedBaseImage := integration.UnixOrWindows("busybox", "nanoserver")
@@ -531,10 +534,7 @@ COPY myapp.Dockerfile /
_, isClient := f.(*clientFrontend)
_, isGateway := f.(*gatewayFrontend)
expectedDockerfileVersionPrefix := dockerfilebuilder.Version
if strings.Count(expectedDockerfileVersionPrefix, ".") == 1 {
expectedDockerfileVersionPrefix += ".0"
}
expectedDockerfileVersion := daemonDockerfileVersion(ctx, t, c)
if slsaVersion == "" || slsaVersion == "v1" {
require.Equal(t, "https://slsa.dev/provenance/v1", attest.PredicateType) // intentionally not const
@@ -558,7 +558,7 @@ COPY myapp.Dockerfile /
if isGateway {
require.Empty(t, pred.BuildDefinition.InternalParameters.DockerfileVersion)
} else {
require.True(t, strings.HasPrefix(pred.BuildDefinition.InternalParameters.DockerfileVersion, expectedDockerfileVersionPrefix))
require.Equal(t, expectedDockerfileVersion, pred.BuildDefinition.InternalParameters.DockerfileVersion)
}
}
@@ -619,7 +619,7 @@ COPY myapp.Dockerfile /
if isGateway {
require.Empty(t, pred.Invocation.Environment.DockerfileVersion)
} else {
require.True(t, strings.HasPrefix(pred.Invocation.Environment.DockerfileVersion, expectedDockerfileVersionPrefix))
require.Equal(t, expectedDockerfileVersion, pred.Invocation.Environment.DockerfileVersion)
}
}
@@ -1071,11 +1071,7 @@ COPY --from=base C:\out C:\Files
pred := stmt.Predicate
require.Equal(t, "dockerfile.v0", pred.BuildDefinition.ExternalParameters.Request.Frontend)
expectedDockerfileVersionPrefix := dockerfilebuilder.Version
if strings.Count(expectedDockerfileVersionPrefix, ".") == 1 {
expectedDockerfileVersionPrefix += ".0"
}
require.True(t, strings.HasPrefix(pred.BuildDefinition.InternalParameters.DockerfileVersion, expectedDockerfileVersionPrefix))
require.Equal(t, daemonDockerfileVersion(ctx, t, c), pred.BuildDefinition.InternalParameters.DockerfileVersion)
require.NotContains(t, pred.BuildDefinition.ExternalParameters.Request.Args, "source")
require.Equal(t, 2, len(pred.BuildDefinition.ExternalParameters.Request.Locals), "%+v", pred.BuildDefinition.ExternalParameters.Request.Locals)
@@ -1,19 +1,22 @@
package llbsolver
package version
import (
"strings"
dockerfilebuilder "github.com/moby/buildkit/frontend/dockerfile/builder"
"github.com/moby/buildkit/version"
buildkitversion "github.com/moby/buildkit/version"
"github.com/pkg/errors"
"golang.org/x/mod/semver"
)
func builtinDockerfileVersion() (string, error) {
return normalizeBuiltinDockerfileVersion(dockerfilebuilder.Version, version.Version)
func Version() string {
v, err := normalizeDockerfileVersion(version, buildkitversion.Version)
if err != nil {
return ""
}
return v
}
func normalizeBuiltinDockerfileVersion(v, buildkitVersion string) (string, error) {
func normalizeDockerfileVersion(v, buildkitVersion string) (string, error) {
v = strings.TrimSpace(v)
parts := strings.Split(v, ".")
if len(parts) != 2 && len(parts) != 3 {
@@ -1,4 +1,4 @@
package llbsolver
package version
import (
"testing"
@@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/require"
)
func TestBuiltinDockerfileVersion(t *testing.T) {
func TestNormalizeDockerfileVersion(t *testing.T) {
for _, tc := range []struct {
name string
dockerfileVer string
@@ -25,7 +25,7 @@ func TestBuiltinDockerfileVersion(t *testing.T) {
{name: "invalid dockerfile suffix", dockerfileVer: "1.24.x", buildkitVersion: "v0.29.0", wantErr: true},
} {
t.Run(tc.name, func(t *testing.T) {
got, err := normalizeBuiltinDockerfileVersion(tc.dockerfileVer, tc.buildkitVersion)
got, err := normalizeDockerfileVersion(tc.dockerfileVer, tc.buildkitVersion)
if tc.wantErr {
require.Error(t, err)
return
+3
View File
@@ -0,0 +1,3 @@
package version
const version = "1.24"
+3 -4
View File
@@ -17,6 +17,7 @@ import (
"github.com/moby/buildkit/exporter/containerimage"
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/frontend"
dockerfileversion "github.com/moby/buildkit/frontend/dockerfile/version"
"github.com/moby/buildkit/solver"
"github.com/moby/buildkit/solver/errdefs"
"github.com/moby/buildkit/solver/llbsolver/ops"
@@ -466,11 +467,9 @@ func NewProvenanceCreator(ctx context.Context, slsaVersion provenancetypes.Prove
pr.BuildDefinition.InternalParameters.ProvenanceCustomEnv = customEnv
if pr.BuildDefinition.ExternalParameters.Request.Frontend == "dockerfile.v0" {
dockerfileVersion, err := builtinDockerfileVersion()
if err != nil {
return nil, err
if dockerfileVersion := dockerfileversion.Version(); dockerfileVersion != "" {
pr.BuildDefinition.InternalParameters.DockerfileVersion = dockerfileVersion
}
pr.BuildDefinition.InternalParameters.DockerfileVersion = dockerfileVersion
}
pc := &ProvenanceCreator{