mirror of
https://github.com/moby/buildkit.git
synced 2026-11-06 05:16:45 +00:00
solver: add compatibility-version support
Add solve-wide compatibility-version support for image and oci exports, with historical goldens and release compatibility tests. Backfill version 10 for v0.13-v0.14 git artifact behavior, keep version 20 as current, and reject unsupported zstd on v10. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
60 files changed
+2299
-57
No files matched your search
@@ -0,0 +1,94 @@
|
||||
name: compatibility-releases
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'v[0-9]+.[0-9]+'
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.26"
|
||||
|
||||
jobs:
|
||||
compatibility:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- release: v0.13.0
|
||||
expected-compatibility-version: "10"
|
||||
- release: v0.14.0
|
||||
expected-compatibility-version: "10"
|
||||
- release: v0.15.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.16.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.17.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.18.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.19.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.20.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.21.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.22.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.23.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.24.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.25.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.26.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.27.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.28.0
|
||||
expected-compatibility-version: "20"
|
||||
- release: v0.29.0
|
||||
expected-compatibility-version: "20"
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||
with:
|
||||
platforms: arm64
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: "${{ env.GO_VERSION }}"
|
||||
cache: true
|
||||
-
|
||||
name: Prepare release binaries
|
||||
run: |
|
||||
mkdir -p .tmp/compat-bin
|
||||
docker pull "moby/buildkit:${{ matrix.release }}"
|
||||
cid=$(docker create "moby/buildkit:${{ matrix.release }}")
|
||||
trap 'docker rm -f "$cid" >/dev/null 2>&1 || true' EXIT
|
||||
docker cp "$cid:/usr/bin/buildkitd" .tmp/compat-bin/buildkitd
|
||||
docker cp "$cid:/usr/bin/buildctl" .tmp/compat-bin/buildctl
|
||||
chmod +x .tmp/compat-bin/buildkitd .tmp/compat-bin/buildctl
|
||||
docker rm -f "$cid"
|
||||
trap - EXIT
|
||||
echo "$PWD/.tmp/compat-bin" >> "$GITHUB_PATH"
|
||||
-
|
||||
name: Test compatibility integration
|
||||
env:
|
||||
BUILDKIT_TEST_EXPECTED_COMPATIBILITY_VERSION: ${{ matrix.expected-compatibility-version }}
|
||||
run: |
|
||||
go test ./client -run '^TestCompatibilityIntegration/Test(Image|OCI)ExporterCompatibilityVersion$' -count=1 -v
|
||||
@@ -409,6 +409,7 @@ type SolveRequest struct {
|
||||
Exporters []*Exporter `protobuf:"bytes,13,rep,name=Exporters,proto3" json:"Exporters,omitempty"`
|
||||
EnableSessionExporter bool `protobuf:"varint,14,opt,name=EnableSessionExporter,proto3" json:"EnableSessionExporter,omitempty"`
|
||||
SourcePolicySession string `protobuf:"bytes,15,opt,name=SourcePolicySession,proto3" json:"SourcePolicySession,omitempty"`
|
||||
CompatibilityVersion int64 `protobuf:"varint,16,opt,name=CompatibilityVersion,proto3" json:"CompatibilityVersion,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -548,6 +549,13 @@ func (x *SolveRequest) GetSourcePolicySession() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SolveRequest) GetCompatibilityVersion() int64 {
|
||||
if x != nil {
|
||||
return x.CompatibilityVersion
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type CacheOptions struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// ExportRefDeprecated is deprecated in favor or the new Exports since BuildKit v0.4.0.
|
||||
@@ -2058,7 +2066,7 @@ const file_github_com_moby_buildkit_api_services_control_control_proto_rawDesc =
|
||||
" \x01(\tR\n" +
|
||||
"RecordType\x12\x16\n" +
|
||||
"\x06Shared\x18\v \x01(\bR\x06Shared\x12\x18\n" +
|
||||
"\aParents\x18\f \x03(\tR\aParents\"\xa6\b\n" +
|
||||
"\aParents\x18\f \x03(\tR\aParents\"\xda\b\n" +
|
||||
"\fSolveRequest\x12\x10\n" +
|
||||
"\x03Ref\x18\x01 \x01(\tR\x03Ref\x12.\n" +
|
||||
"\n" +
|
||||
@@ -2077,7 +2085,8 @@ const file_github_com_moby_buildkit_api_services_control_control_proto_rawDesc =
|
||||
"\fSourcePolicy\x18\f \x01(\v2%.moby.buildkit.v1.sourcepolicy.PolicyR\fSourcePolicy\x128\n" +
|
||||
"\tExporters\x18\r \x03(\v2\x1a.moby.buildkit.v1.ExporterR\tExporters\x124\n" +
|
||||
"\x15EnableSessionExporter\x18\x0e \x01(\bR\x15EnableSessionExporter\x120\n" +
|
||||
"\x13SourcePolicySession\x18\x0f \x01(\tR\x13SourcePolicySession\x1aJ\n" +
|
||||
"\x13SourcePolicySession\x18\x0f \x01(\tR\x13SourcePolicySession\x122\n" +
|
||||
"\x14CompatibilityVersion\x18\x10 \x01(\x03R\x14CompatibilityVersion\x1aJ\n" +
|
||||
"\x1cExporterAttrsDeprecatedEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a@\n" +
|
||||
|
||||
@@ -77,6 +77,7 @@ message SolveRequest {
|
||||
repeated Exporter Exporters = 13;
|
||||
bool EnableSessionExporter = 14;
|
||||
string SourcePolicySession = 15;
|
||||
int64 CompatibilityVersion = 16;
|
||||
}
|
||||
|
||||
message CacheOptions {
|
||||
|
||||
@@ -143,6 +143,7 @@ func (m *SolveRequest) CloneVT() *SolveRequest {
|
||||
r.SourcePolicy = m.SourcePolicy.CloneVT()
|
||||
r.EnableSessionExporter = m.EnableSessionExporter
|
||||
r.SourcePolicySession = m.SourcePolicySession
|
||||
r.CompatibilityVersion = m.CompatibilityVersion
|
||||
if rhs := m.ExporterAttrsDeprecated; rhs != nil {
|
||||
tmpContainer := make(map[string]string, len(rhs))
|
||||
for k, v := range rhs {
|
||||
@@ -1043,6 +1044,9 @@ func (this *SolveRequest) EqualVT(that *SolveRequest) bool {
|
||||
if this.SourcePolicySession != that.SourcePolicySession {
|
||||
return false
|
||||
}
|
||||
if this.CompatibilityVersion != that.CompatibilityVersion {
|
||||
return false
|
||||
}
|
||||
return string(this.unknownFields) == string(that.unknownFields)
|
||||
}
|
||||
|
||||
@@ -2249,6 +2253,13 @@ func (m *SolveRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if m.CompatibilityVersion != 0 {
|
||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.CompatibilityVersion))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0x80
|
||||
}
|
||||
if len(m.SourcePolicySession) > 0 {
|
||||
i -= len(m.SourcePolicySession)
|
||||
copy(dAtA[i:], m.SourcePolicySession)
|
||||
@@ -4174,6 +4185,9 @@ func (m *SolveRequest) SizeVT() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
|
||||
}
|
||||
if m.CompatibilityVersion != 0 {
|
||||
n += 2 + protohelpers.SizeOfVarint(uint64(m.CompatibilityVersion))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
@@ -6326,6 +6340,25 @@ func (m *SolveRequest) UnmarshalVT(dAtA []byte) error {
|
||||
}
|
||||
m.SourcePolicySession = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 16:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field CompatibilityVersion", wireType)
|
||||
}
|
||||
m.CompatibilityVersion = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return protohelpers.ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.CompatibilityVersion |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
|
||||
|
||||
@@ -211,6 +211,8 @@ var allTests = []func(t *testing.T, sb integration.Sandbox){
|
||||
testExportAnnotationsMediaTypes,
|
||||
testExportAttestationsOCIArtifact,
|
||||
testExportAttestationsImageManifest,
|
||||
testImageExporterCompatibilityVersion,
|
||||
testOCIExporterCompatibilityVersion,
|
||||
testExportedImageLabels,
|
||||
testAttestationDefaultSubject,
|
||||
testSourceDateEpochLayerTimestamps,
|
||||
|
||||
@@ -0,0 +1,879 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
stderrors "errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/v2/core/content"
|
||||
"github.com/containerd/containerd/v2/core/images"
|
||||
"github.com/containerd/platforms"
|
||||
intoto "github.com/in-toto/in-toto-golang/in_toto"
|
||||
"github.com/moby/buildkit/client/llb"
|
||||
"github.com/moby/buildkit/client/llb/sourceresolver"
|
||||
"github.com/moby/buildkit/exporter/containerimage/exptypes"
|
||||
gateway "github.com/moby/buildkit/frontend/gateway/client"
|
||||
solvererrdefs "github.com/moby/buildkit/solver/errdefs"
|
||||
"github.com/moby/buildkit/solver/llbsolver/compat"
|
||||
provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types"
|
||||
"github.com/moby/buildkit/util/contentutil"
|
||||
"github.com/moby/buildkit/util/grpcerrors"
|
||||
"github.com/moby/buildkit/util/testutil/httpserver"
|
||||
"github.com/moby/buildkit/util/testutil/integration"
|
||||
"github.com/moby/buildkit/util/testutil/workers"
|
||||
policyimage "github.com/moby/policy-helpers/image"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/pmezard/go-difflib/difflib"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const compatibilityUpdateEnv = "BUILDKIT_UPDATE_COMPAT_GOLDENS"
|
||||
const compatibilityExpectedVersionEnv = "BUILDKIT_TEST_EXPECTED_COMPATIBILITY_VERSION"
|
||||
const compatibilityEpoch = "1445412480"
|
||||
const compatibilityPlatformString = "linux/arm64"
|
||||
const compatibilityBusyboxMirrorRef = "busybox_arm64:latest"
|
||||
const compatibilityBusyboxImageRef = "docker.io/library/" + compatibilityBusyboxMirrorRef
|
||||
|
||||
//go:embed testdata/compatibility
|
||||
var compatibilityGoldens embed.FS
|
||||
|
||||
type compatibilityLayerExpectation struct {
|
||||
MediaType string
|
||||
Digest string
|
||||
}
|
||||
|
||||
type compatibilityCase struct {
|
||||
Name string
|
||||
Attrs map[string]string
|
||||
TouchExecOutputs bool
|
||||
}
|
||||
|
||||
type compatibilityActual struct {
|
||||
ManifestDigest string
|
||||
ConfigDigest string
|
||||
Layers []compatibilityLayerExpectation
|
||||
ManifestBytes []byte
|
||||
ConfigBytes []byte
|
||||
ManifestJSON string
|
||||
ConfigJSON string
|
||||
}
|
||||
|
||||
var compatibilityCases = []compatibilityCase{
|
||||
{
|
||||
Name: "default-gzip",
|
||||
Attrs: map[string]string{
|
||||
"source-date-epoch": compatibilityEpoch,
|
||||
"rewrite-timestamp": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "gzip-level-0",
|
||||
Attrs: map[string]string{
|
||||
"compression": "gzip",
|
||||
"compression-level": "0",
|
||||
"force-compression": "true",
|
||||
"source-date-epoch": compatibilityEpoch,
|
||||
"rewrite-timestamp": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "gzip-level-9",
|
||||
Attrs: map[string]string{
|
||||
"compression": "gzip",
|
||||
"compression-level": "9",
|
||||
"force-compression": "true",
|
||||
"source-date-epoch": compatibilityEpoch,
|
||||
"rewrite-timestamp": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "uncompressed",
|
||||
Attrs: map[string]string{
|
||||
"compression": "uncompressed",
|
||||
"force-compression": "true",
|
||||
"source-date-epoch": compatibilityEpoch,
|
||||
"rewrite-timestamp": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "zstd-oci-types",
|
||||
Attrs: map[string]string{
|
||||
"compression": "zstd",
|
||||
"compression-level": "12",
|
||||
"force-compression": "true",
|
||||
"oci-mediatypes": "true",
|
||||
"source-date-epoch": compatibilityEpoch,
|
||||
"rewrite-timestamp": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "manifest-annotation",
|
||||
Attrs: map[string]string{
|
||||
"annotation-manifest.org.opencontainers.image.title": "compatibility-test",
|
||||
"source-date-epoch": compatibilityEpoch,
|
||||
"rewrite-timestamp": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "oci-mediatypes",
|
||||
Attrs: map[string]string{
|
||||
"oci-mediatypes": "true",
|
||||
"force-compression": "true",
|
||||
"source-date-epoch": compatibilityEpoch,
|
||||
"rewrite-timestamp": "true",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestCompatibilityIntegration(t *testing.T) {
|
||||
integration.SkipOnPlatform(t, "windows")
|
||||
mirrors := integration.WithMirroredImages(map[string]string{
|
||||
"library/" + compatibilityBusyboxMirrorRef: "docker.io/arm64v8/busybox:latest@sha256:1fa89c01cd0473cedbd1a470abb8c139eeb80920edf1bc55de87851bfb63ea11",
|
||||
})
|
||||
integration.Run(t, integration.TestFuncs(
|
||||
testImageExporterCompatibilityVersion,
|
||||
testOCIExporterCompatibilityVersion,
|
||||
testImageExporterCompatibilityVersionProvenance,
|
||||
), mirrors)
|
||||
}
|
||||
|
||||
func testImageExporterCompatibilityVersion(t *testing.T, sb integration.Sandbox) {
|
||||
workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance, workers.FeatureSourceDateEpoch)
|
||||
requiresLinux(t)
|
||||
|
||||
ctx := sb.Context()
|
||||
c, err := New(ctx, sb.Address())
|
||||
require.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
platform := compatibilityPlatform(t)
|
||||
registry, err := sb.NewRegistry()
|
||||
if errors.Is(err, integration.ErrRequirements) {
|
||||
t.Skip(err.Error())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
baseRef, baseConfig := createCompatibilityBaseImage(ctx, t, c, registry, platform)
|
||||
|
||||
expectedSet := compatibilityExpectedVersionIsSet()
|
||||
for _, version := range compatibilityVersionsUnderTest(t) {
|
||||
ensurePruneAll(t, c, sb)
|
||||
for _, tc := range compatibilityCases {
|
||||
t.Run(fmt.Sprintf("image/%s/%s", tc.Name, compatibilityRunName(version, expectedSet)), func(t *testing.T) {
|
||||
def := createCompatibilityDefinition(t, sb, baseRef, platform, tc)
|
||||
actual, err := exportCompatibilityImageCase(ctx, t, c, def, registry, tc, version, expectedSet, baseConfig)
|
||||
assertCompatibilityCaseResult(t, ExporterImage, tc, version, expectedSet, actual, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testOCIExporterCompatibilityVersion(t *testing.T, sb integration.Sandbox) {
|
||||
workers.CheckFeatureCompat(t, sb, workers.FeatureOCIExporter, workers.FeatureProvenance, workers.FeatureSourceDateEpoch)
|
||||
requiresLinux(t)
|
||||
|
||||
ctx := sb.Context()
|
||||
c, err := New(ctx, sb.Address())
|
||||
require.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
platform := compatibilityPlatform(t)
|
||||
registry, err := sb.NewRegistry()
|
||||
if errors.Is(err, integration.ErrRequirements) {
|
||||
t.Skip(err.Error())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
baseRef, baseConfig := createCompatibilityBaseImage(ctx, t, c, registry, platform)
|
||||
|
||||
expectedSet := compatibilityExpectedVersionIsSet()
|
||||
for _, version := range compatibilityVersionsUnderTest(t) {
|
||||
ensurePruneAll(t, c, sb)
|
||||
for _, tc := range compatibilityCases {
|
||||
t.Run(fmt.Sprintf("oci/%s/%s", tc.Name, compatibilityRunName(version, expectedSet)), func(t *testing.T) {
|
||||
def := createCompatibilityDefinition(t, sb, baseRef, platform, tc)
|
||||
actual, err := exportCompatibilityOCICase(ctx, t, c, def, tc, version, expectedSet, baseConfig)
|
||||
assertCompatibilityCaseResult(t, ExporterOCI, tc, version, expectedSet, actual, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testImageExporterCompatibilityVersionProvenance(t *testing.T, sb integration.Sandbox) {
|
||||
workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush, workers.FeatureProvenance, workers.FeatureSourceDateEpoch)
|
||||
requiresLinux(t)
|
||||
|
||||
if compatibilityExpectedVersionIsSet() {
|
||||
t.Skip("provenance compatibility assertion requires explicit compatibility-version request")
|
||||
}
|
||||
|
||||
ctx := sb.Context()
|
||||
c, err := New(ctx, sb.Address())
|
||||
require.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
platform := compatibilityPlatform(t)
|
||||
registry, err := sb.NewRegistry()
|
||||
if errors.Is(err, integration.ErrRequirements) {
|
||||
t.Skip(err.Error())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
baseRef, baseConfig := createCompatibilityBaseImage(ctx, t, c, registry, platform)
|
||||
ensurePruneAll(t, c, sb)
|
||||
|
||||
var tc compatibilityCase
|
||||
for _, candidate := range compatibilityCases {
|
||||
if candidate.Name == "default-gzip" {
|
||||
tc = candidate
|
||||
break
|
||||
}
|
||||
}
|
||||
require.NotEmpty(t, tc.Name)
|
||||
|
||||
def := createCompatibilityDefinition(t, sb, baseRef, platform, tc)
|
||||
target := fmt.Sprintf("%s/buildkit/compatibility-provenance-v10:latest", registry)
|
||||
attrs := cloneStringMap(tc.Attrs)
|
||||
attrs["name"] = target
|
||||
attrs["push"] = "true"
|
||||
attrs[exptypes.ExporterImageConfigKey] = string(baseConfig)
|
||||
|
||||
_, err = c.Solve(ctx, def, SolveOpt{
|
||||
CompatibilityVersion: compat.CompatibilityVersion013,
|
||||
FrontendAttrs: map[string]string{
|
||||
"attest:provenance": "mode=max,version=v1",
|
||||
},
|
||||
Exports: []ExportEntry{{
|
||||
Type: ExporterImage,
|
||||
Attrs: attrs,
|
||||
}},
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
pr, err := readImageCompatibilityProvenance(ctx, target)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, compat.CompatibilityVersion013, pr.BuildDefinition.ExternalParameters.Request.CompatibilityVersion)
|
||||
}
|
||||
|
||||
func compatibilityVersionsUnderTest(t *testing.T) []int {
|
||||
t.Helper()
|
||||
|
||||
versionStr := os.Getenv(compatibilityExpectedVersionEnv)
|
||||
if versionStr == "" {
|
||||
return compat.SupportedCompatibilityVersions()
|
||||
}
|
||||
|
||||
version, err := strconv.Atoi(versionStr)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, compat.ValidateCompatibilityVersion(version))
|
||||
return []int{version}
|
||||
}
|
||||
|
||||
func compatibilityExpectedVersionIsSet() bool {
|
||||
return os.Getenv(compatibilityExpectedVersionEnv) != ""
|
||||
}
|
||||
|
||||
func compatibilityRunName(version int, expectedSet bool) string {
|
||||
if expectedSet {
|
||||
return "default"
|
||||
}
|
||||
return "v" + strconv.Itoa(version)
|
||||
}
|
||||
|
||||
func createCompatibilityBaseImage(ctx context.Context, t *testing.T, c *Client, registry string, platform ocispecs.Platform) (string, []byte) {
|
||||
t.Helper()
|
||||
|
||||
baseRef := fmt.Sprintf("%s/buildkit/compatibility-base:latest", registry)
|
||||
_, err := c.Build(ctx, SolveOpt{
|
||||
Exports: []ExportEntry{{
|
||||
Type: ExporterImage,
|
||||
Attrs: map[string]string{
|
||||
"name": baseRef,
|
||||
"push": "true",
|
||||
"store": "false",
|
||||
},
|
||||
}},
|
||||
}, "", func(ctx context.Context, gw gateway.Client) (*gateway.Result, error) {
|
||||
baseConfig, err := resolveCompatibilityImageConfig(ctx, gw, platform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base, err := llb.Image(compatibilityBusyboxImageRef, llb.Platform(platform)).WithImageConfig(baseConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base = base.File(
|
||||
llb.Mkdir("/base", 0o755, llb.WithParents(true)).
|
||||
Mkfile("/base/base.txt", 0o644, []byte("compatibility base\n")),
|
||||
)
|
||||
|
||||
def, err := base.Marshal(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := gw.Solve(ctx, gateway.SolveRequest{
|
||||
Definition: def.ToPB(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ref, err := r.SingleRef()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := gateway.NewResult()
|
||||
res.SetRef(ref)
|
||||
res.AddMeta(exptypes.ExporterImageConfigKey, baseConfig)
|
||||
return res, nil
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
desc, provider, err := contentutil.ProviderFromRef(baseRef)
|
||||
require.NoError(t, err)
|
||||
actual := readCompatibilityActualFromProvider(ctx, t, provider, desc)
|
||||
|
||||
return baseRef, actual.ConfigBytes
|
||||
}
|
||||
|
||||
func resolveCompatibilityImageConfig(ctx context.Context, gw gateway.Client, platform ocispecs.Platform) ([]byte, error) {
|
||||
_, _, baseConfig, err := gw.ResolveImageConfig(ctx, compatibilityBusyboxImageRef, sourceresolver.Opt{
|
||||
ImageOpt: &sourceresolver.ResolveImageOpt{
|
||||
Platform: &platform,
|
||||
},
|
||||
})
|
||||
return baseConfig, err
|
||||
}
|
||||
|
||||
func createCompatibilityDefinition(t *testing.T, sb integration.Sandbox, baseRef string, platform ocispecs.Platform, tc compatibilityCase) *llb.Definition {
|
||||
t.Helper()
|
||||
|
||||
httpModTime := time.Date(2021, time.January, 2, 3, 4, 5, 0, time.UTC)
|
||||
httpSrv := httpserver.NewTestServer(map[string]*httpserver.Response{
|
||||
"/artifact.txt": {
|
||||
Content: []byte("http fixture\n"),
|
||||
LastModified: &httpModTime,
|
||||
},
|
||||
})
|
||||
t.Cleanup(httpSrv.Close)
|
||||
|
||||
gitDir := t.TempDir()
|
||||
err := runInDirEnv(gitDir, []string{
|
||||
"GIT_AUTHOR_DATE=2020-01-02T03:04:05Z",
|
||||
"GIT_COMMITTER_DATE=2020-01-02T03:04:05Z",
|
||||
}, []string{
|
||||
"git init",
|
||||
"git config --local user.email test@example.com",
|
||||
"git config --local user.name test",
|
||||
"git checkout -b main",
|
||||
"mkdir -p sub",
|
||||
"printf 'git fixture\\n' > git.txt",
|
||||
"printf 'nested fixture\\n' > sub/nested.txt",
|
||||
"git add .",
|
||||
"git commit -m fixture",
|
||||
"git update-server-info",
|
||||
}...)
|
||||
require.NoError(t, err)
|
||||
|
||||
gitSrv := httptest.NewServer(http.FileServer(http.Dir(filepath.Clean(gitDir))))
|
||||
t.Cleanup(gitSrv.Close)
|
||||
|
||||
httpState := llb.HTTP(httpSrv.URL+"/artifact.txt", llb.Filename("artifact.txt"))
|
||||
gitState := llb.Git(gitSrv.URL+"/.git", "", llb.GitRef("main"))
|
||||
|
||||
st := llb.Image(baseRef, llb.Platform(platform)).File(
|
||||
llb.Mkdir("/inputs/git", 0o755, llb.WithParents(true)).
|
||||
Mkfile("/inputs/llb.txt", 0o644, []byte("llb fixture\n")).
|
||||
Copy(httpState, "/artifact.txt", "/inputs/http.txt").
|
||||
Copy(gitState, "/git.txt", "/inputs/git/git.txt").
|
||||
Copy(gitState, "/sub/nested.txt", "/inputs/git/nested.txt"),
|
||||
)
|
||||
|
||||
execScript := `sh -eux -c '
|
||||
mkdir -p /foo/bar/generated/deeper
|
||||
echo exec-fixture > /foo/bar/generated/exec.txt
|
||||
echo nested-exec > /foo/bar/generated/deeper/nested.txt
|
||||
`
|
||||
if tc.TouchExecOutputs {
|
||||
execScript += `touch -t 201903040506.07 /foo/bar/generated /foo/bar/generated/deeper
|
||||
touch -t 201903040506.07 /foo/bar/generated/exec.txt /foo/bar/generated/deeper/nested.txt
|
||||
`
|
||||
}
|
||||
execScript += `'`
|
||||
|
||||
run := st.Run(
|
||||
llb.Shlex(execScript),
|
||||
llb.AddMount("/foo/bar", llb.Scratch()),
|
||||
)
|
||||
|
||||
def, err := run.Root().Marshal(sb.Context())
|
||||
require.NoError(t, err)
|
||||
return def
|
||||
}
|
||||
|
||||
func exportCompatibilityImageCase(ctx context.Context, t *testing.T, c *Client, def *llb.Definition, registry string, tc compatibilityCase, version int, expectedSet bool, baseConfig []byte) (compatibilityActual, error) {
|
||||
t.Helper()
|
||||
|
||||
target := fmt.Sprintf("%s/buildkit/compatibility-%s:%s", registry, sanitizeCompatibilityName(tc.Name), compatibilityRunName(version, expectedSet))
|
||||
attrs := cloneStringMap(tc.Attrs)
|
||||
attrs["name"] = target
|
||||
attrs["push"] = "true"
|
||||
attrs[exptypes.ExporterImageConfigKey] = string(baseConfig)
|
||||
|
||||
opt := SolveOpt{
|
||||
FrontendAttrs: map[string]string{
|
||||
"attest:provenance": "mode=max,version=v1",
|
||||
},
|
||||
Exports: []ExportEntry{{
|
||||
Type: ExporterImage,
|
||||
Attrs: attrs,
|
||||
}},
|
||||
}
|
||||
if !expectedSet {
|
||||
opt.CompatibilityVersion = version
|
||||
}
|
||||
_, err := c.Solve(ctx, def, opt, nil)
|
||||
if err != nil {
|
||||
return compatibilityActual{}, err
|
||||
}
|
||||
|
||||
desc, provider, err := contentutil.ProviderFromRef(target)
|
||||
if err != nil {
|
||||
return compatibilityActual{}, err
|
||||
}
|
||||
return readCompatibilityActualFromProvider(ctx, t, provider, desc), nil
|
||||
}
|
||||
|
||||
func exportCompatibilityOCICase(ctx context.Context, t *testing.T, c *Client, def *llb.Definition, tc compatibilityCase, version int, expectedSet bool, baseConfig []byte) (compatibilityActual, error) {
|
||||
t.Helper()
|
||||
|
||||
dir := t.TempDir()
|
||||
attrs := cloneStringMap(tc.Attrs)
|
||||
attrs["tar"] = "false"
|
||||
attrs[exptypes.ExporterImageConfigKey] = string(baseConfig)
|
||||
|
||||
opt := SolveOpt{
|
||||
FrontendAttrs: map[string]string{
|
||||
"attest:provenance": "mode=max,version=v1",
|
||||
},
|
||||
Exports: []ExportEntry{{
|
||||
Type: ExporterOCI,
|
||||
OutputDir: dir,
|
||||
Attrs: attrs,
|
||||
}},
|
||||
}
|
||||
if !expectedSet {
|
||||
opt.CompatibilityVersion = version
|
||||
}
|
||||
_, err := c.Solve(ctx, def, opt, nil)
|
||||
if err != nil {
|
||||
return compatibilityActual{}, err
|
||||
}
|
||||
|
||||
indexDT, err := os.ReadFile(filepath.Join(dir, ocispecs.ImageIndexFile))
|
||||
require.NoError(t, err)
|
||||
|
||||
var index ocispecs.Index
|
||||
require.NoError(t, json.Unmarshal(indexDT, &index))
|
||||
|
||||
for _, desc := range index.Manifests {
|
||||
if desc.Digest == "" {
|
||||
continue
|
||||
}
|
||||
if desc.Platform != nil && desc.Platform.OS == "unknown" && desc.Platform.Architecture == "unknown" {
|
||||
continue
|
||||
}
|
||||
manifestDT, err := os.ReadFile(filepath.Join(dir, ocispecs.ImageBlobsDir, desc.Digest.Algorithm().String(), desc.Digest.Encoded()))
|
||||
require.NoError(t, err)
|
||||
|
||||
var manifest ocispecs.Manifest
|
||||
require.NoError(t, json.Unmarshal(manifestDT, &manifest))
|
||||
if manifest.Config.Digest == "" {
|
||||
continue
|
||||
}
|
||||
if isCompatibilityAttestationManifest(manifest) {
|
||||
continue
|
||||
}
|
||||
|
||||
configDT, err := os.ReadFile(filepath.Join(dir, ocispecs.ImageBlobsDir, manifest.Config.Digest.Algorithm().String(), manifest.Config.Digest.Encoded()))
|
||||
require.NoError(t, err)
|
||||
|
||||
return compatibilityActualFromBytes(manifestDT, configDT, manifest.Layers), nil
|
||||
}
|
||||
|
||||
blobPaths, err := filepath.Glob(filepath.Join(dir, ocispecs.ImageBlobsDir, "*", "*"))
|
||||
require.NoError(t, err)
|
||||
sort.Strings(blobPaths)
|
||||
for _, blobPath := range blobPaths {
|
||||
manifestDT, err := os.ReadFile(blobPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
var manifest ocispecs.Manifest
|
||||
if err := json.Unmarshal(manifestDT, &manifest); err != nil {
|
||||
continue
|
||||
}
|
||||
if manifest.Config.Digest == "" {
|
||||
continue
|
||||
}
|
||||
if isCompatibilityAttestationManifest(manifest) {
|
||||
continue
|
||||
}
|
||||
|
||||
configDT, err := os.ReadFile(filepath.Join(dir, ocispecs.ImageBlobsDir, manifest.Config.Digest.Algorithm().String(), manifest.Config.Digest.Encoded()))
|
||||
require.NoError(t, err)
|
||||
|
||||
return compatibilityActualFromBytes(manifestDT, configDT, manifest.Layers), nil
|
||||
}
|
||||
|
||||
t.Fatalf("missing platform manifest\nindex json:\n%s", normalizeJSON(indexDT))
|
||||
return compatibilityActual{}, nil
|
||||
}
|
||||
|
||||
func compatibilityActualFromBytes(manifestDT, configDT []byte, layers []ocispecs.Descriptor) compatibilityActual {
|
||||
out := compatibilityActual{
|
||||
ManifestDigest: digest.FromBytes(manifestDT).String(),
|
||||
ConfigDigest: digest.FromBytes(configDT).String(),
|
||||
ManifestBytes: append([]byte(nil), manifestDT...),
|
||||
ConfigBytes: append([]byte(nil), configDT...),
|
||||
ManifestJSON: normalizeJSON(manifestDT),
|
||||
ConfigJSON: normalizeJSON(configDT),
|
||||
Layers: make([]compatibilityLayerExpectation, len(layers)),
|
||||
}
|
||||
for i, layer := range layers {
|
||||
out.Layers[i] = compatibilityLayerExpectation{
|
||||
MediaType: layer.MediaType,
|
||||
Digest: layer.Digest.String(),
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func isCompatibilityAttestationManifest(manifest ocispecs.Manifest) bool {
|
||||
if len(manifest.Layers) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, layer := range manifest.Layers {
|
||||
if layer.MediaType != "application/vnd.in-toto+json" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func readCompatibilityActualFromProvider(ctx context.Context, t *testing.T, provider content.Provider, desc ocispecs.Descriptor) compatibilityActual {
|
||||
t.Helper()
|
||||
|
||||
if images.IsIndexType(desc.MediaType) {
|
||||
indexDT, err := content.ReadBlob(ctx, provider, desc)
|
||||
require.NoError(t, err)
|
||||
|
||||
var index ocispecs.Index
|
||||
require.NoError(t, json.Unmarshal(indexDT, &index))
|
||||
|
||||
platform := compatibilityPlatform(t)
|
||||
matcher := platforms.Only(platform)
|
||||
for _, manifestDesc := range index.Manifests {
|
||||
if manifestDesc.Platform == nil || !matcher.Match(*manifestDesc.Platform) {
|
||||
continue
|
||||
}
|
||||
return readCompatibilityActualFromProvider(ctx, t, provider, manifestDesc)
|
||||
}
|
||||
|
||||
require.FailNow(t, "missing platform manifest in image index")
|
||||
}
|
||||
|
||||
manifestDT, err := content.ReadBlob(ctx, provider, desc)
|
||||
require.NoError(t, err)
|
||||
|
||||
var manifest ocispecs.Manifest
|
||||
require.NoError(t, json.Unmarshal(manifestDT, &manifest))
|
||||
require.True(t, images.IsManifestType(manifest.MediaType), "unexpected manifest media type %s", manifest.MediaType)
|
||||
|
||||
configDT, err := content.ReadBlob(ctx, provider, manifest.Config)
|
||||
require.NoError(t, err)
|
||||
|
||||
return compatibilityActualFromBytes(manifestDT, configDT, manifest.Layers)
|
||||
}
|
||||
|
||||
func readImageCompatibilityProvenance(ctx context.Context, ref string) (*provenancetypes.ProvenancePredicateSLSA1, error) {
|
||||
desc, provider, err := contentutil.ProviderFromRef(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
indexDT, err := content.ReadBlob(ctx, provider, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var index ocispecs.Index
|
||||
if err := json.Unmarshal(indexDT, &index); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, manifestDesc := range index.Manifests {
|
||||
manifestDT, err := content.ReadBlob(ctx, provider, manifestDesc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var manifest ocispecs.Manifest
|
||||
if err := json.Unmarshal(manifestDT, &manifest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isCompatibilityAttestationManifest(manifest) {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, layer := range manifest.Layers {
|
||||
if layer.Annotations["in-toto.io/predicate-type"] != policyimage.SLSAProvenancePredicateType1 {
|
||||
continue
|
||||
}
|
||||
|
||||
stmtDT, err := content.ReadBlob(ctx, provider, layer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var stmt struct {
|
||||
intoto.StatementHeader
|
||||
Predicate json.RawMessage `json:"predicate"`
|
||||
}
|
||||
if err := json.Unmarshal(stmtDT, &stmt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pr provenancetypes.ProvenancePredicateSLSA1
|
||||
if err := json.Unmarshal(stmt.Predicate, &pr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pr, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("missing SLSA provenance attestation")
|
||||
}
|
||||
|
||||
func assertCompatibilityCase(t *testing.T, exporterType string, tc compatibilityCase, version int, actual compatibilityActual) {
|
||||
t.Helper()
|
||||
|
||||
if os.Getenv(compatibilityUpdateEnv) != "" {
|
||||
writeCompatibilityGoldens(t, tc.Name, version, actual)
|
||||
t.Logf("compatibility expectation %s/%s/v%d manifest=%q config=%q layers=%s",
|
||||
exporterType, tc.Name, version, actual.ManifestDigest, actual.ConfigDigest, formatLayerExpectations(actual.Layers))
|
||||
return
|
||||
}
|
||||
|
||||
expectedManifestJSON, err := compatibilityGoldens.ReadFile(goldenPath(tc.Name, version, "manifest.json"))
|
||||
require.NoError(t, err)
|
||||
expectedConfigJSON, err := compatibilityGoldens.ReadFile(goldenPath(tc.Name, version, "config.json"))
|
||||
require.NoError(t, err)
|
||||
|
||||
exp, err := compatibilityExpectationFromGoldens(expectedManifestJSON, expectedConfigJSON)
|
||||
require.NoError(t, err)
|
||||
|
||||
manifestDiff := ""
|
||||
if normalizeJSON(expectedManifestJSON) != actual.ManifestJSON {
|
||||
manifestDiff = unifiedDiff("golden-manifest", normalizeJSON(expectedManifestJSON), actual.ManifestJSON)
|
||||
}
|
||||
configDiff := ""
|
||||
if normalizeJSON(expectedConfigJSON) != actual.ConfigJSON {
|
||||
configDiff = unifiedDiff("golden-config", normalizeJSON(expectedConfigJSON), actual.ConfigJSON)
|
||||
}
|
||||
|
||||
if exp.ManifestDigest != actual.ManifestDigest ||
|
||||
exp.ConfigDigest != actual.ConfigDigest ||
|
||||
!equalLayerExpectations(exp.Layers, actual.Layers) ||
|
||||
manifestDiff != "" ||
|
||||
configDiff != "" {
|
||||
t.Fatalf("%s", formatCompatibilityDebug(exporterType, tc.Name, version, tc.Attrs, exp, actual, manifestDiff, configDiff))
|
||||
}
|
||||
}
|
||||
|
||||
func assertCompatibilityCaseResult(t *testing.T, exporterType string, tc compatibilityCase, version int, expectedSet bool, actual compatibilityActual, err error) {
|
||||
t.Helper()
|
||||
|
||||
if compatibilityCaseExpectedUnsupported(tc, version, expectedSet) {
|
||||
require.Error(t, err)
|
||||
err = grpcerrors.FromGRPC(err)
|
||||
var unsupported *solvererrdefs.UnsupportedCompatibilityFeatureError
|
||||
expectedFeature := fmt.Sprintf("%s exporter compression=zstd", exporterType)
|
||||
if stderrors.As(err, &unsupported) {
|
||||
require.Equal(t, int64(version), unsupported.Version)
|
||||
require.Equal(t, expectedFeature, unsupported.Feature)
|
||||
return
|
||||
}
|
||||
require.ErrorContains(t, err, fmt.Sprintf("unsupported compatibility-version %d feature %s", version, expectedFeature))
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
assertCompatibilityCase(t, exporterType, tc, version, actual)
|
||||
}
|
||||
|
||||
func compatibilityCaseExpectedUnsupported(tc compatibilityCase, version int, expectedSet bool) bool {
|
||||
return !expectedSet && version == compat.CompatibilityVersion013 && tc.Attrs["compression"] == "zstd"
|
||||
}
|
||||
|
||||
func compatibilityExpectationFromGoldens(manifestDT, configDT []byte) (compatibilityActual, error) {
|
||||
var manifest ocispecs.Manifest
|
||||
if err := json.Unmarshal(manifestDT, &manifest); err != nil {
|
||||
return compatibilityActual{}, err
|
||||
}
|
||||
return compatibilityActualFromBytes(manifestDT, configDT, manifest.Layers), nil
|
||||
}
|
||||
|
||||
func writeCompatibilityGoldens(t *testing.T, caseName string, version int, actual compatibilityActual) {
|
||||
t.Helper()
|
||||
|
||||
_, currentFile, _, ok := runtime.Caller(0)
|
||||
require.True(t, ok)
|
||||
|
||||
baseDir := filepath.Dir(currentFile)
|
||||
manifestPath := filepath.Join(baseDir, "testdata", "compatibility", caseName, fmt.Sprintf("v%d", version), "manifest.json")
|
||||
configPath := filepath.Join(baseDir, "testdata", "compatibility", caseName, fmt.Sprintf("v%d", version), "config.json")
|
||||
require.NoError(t, os.MkdirAll(filepath.Dir(manifestPath), 0o755))
|
||||
require.NoError(t, os.WriteFile(manifestPath, actual.ManifestBytes, 0o644))
|
||||
require.NoError(t, os.WriteFile(configPath, actual.ConfigBytes, 0o644))
|
||||
}
|
||||
|
||||
func goldenPath(caseName string, version int, file string) string {
|
||||
return filepath.ToSlash(filepath.Join("testdata", "compatibility", caseName, fmt.Sprintf("v%d", version), file))
|
||||
}
|
||||
|
||||
func formatCompatibilityDebug(exporterType, caseName string, version int, attrs map[string]string, exp compatibilityActual, actual compatibilityActual, manifestDiff, configDiff string) string {
|
||||
var b strings.Builder
|
||||
fmt.Fprintf(&b, "compatibility regression mismatch\n")
|
||||
fmt.Fprintf(&b, "case: %s\n", caseName)
|
||||
fmt.Fprintf(&b, "exporter: %s\n", exporterType)
|
||||
fmt.Fprintf(&b, "compatibility-version: %d\n", version)
|
||||
fmt.Fprintf(&b, "attrs:\n")
|
||||
|
||||
keys := make([]string, 0, len(attrs))
|
||||
for k := range attrs {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
fmt.Fprintf(&b, " %s=%s\n", k, attrs[k])
|
||||
}
|
||||
|
||||
fmt.Fprintf(&b, "\nexpected:\n")
|
||||
fmt.Fprintf(&b, " manifest=%s\n", exp.ManifestDigest)
|
||||
fmt.Fprintf(&b, " config=%s\n", exp.ConfigDigest)
|
||||
for i, layer := range exp.Layers {
|
||||
fmt.Fprintf(&b, " layer[%d]=%s %s\n", i, layer.MediaType, layer.Digest)
|
||||
}
|
||||
|
||||
fmt.Fprintf(&b, "\nactual:\n")
|
||||
fmt.Fprintf(&b, " manifest=%s\n", actual.ManifestDigest)
|
||||
fmt.Fprintf(&b, " config=%s\n", actual.ConfigDigest)
|
||||
for i, layer := range actual.Layers {
|
||||
fmt.Fprintf(&b, " layer[%d]=%s %s\n", i, layer.MediaType, layer.Digest)
|
||||
}
|
||||
|
||||
if manifestDiff != "" {
|
||||
fmt.Fprintf(&b, "\nmanifest diff:\n%s\n", manifestDiff)
|
||||
}
|
||||
if configDiff != "" {
|
||||
fmt.Fprintf(&b, "\nconfig diff:\n%s\n", configDiff)
|
||||
}
|
||||
|
||||
fmt.Fprintf(&b, "\nmanifest json:\n%s\n", actual.ManifestJSON)
|
||||
fmt.Fprintf(&b, "\nconfig json:\n%s\n", actual.ConfigJSON)
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func unifiedDiff(name, expected, actual string) string {
|
||||
diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
|
||||
A: difflib.SplitLines(expected),
|
||||
B: difflib.SplitLines(actual),
|
||||
FromFile: name + ".golden",
|
||||
ToFile: name + ".actual",
|
||||
Context: 3,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Sprintf("failed to render diff: %v", err)
|
||||
}
|
||||
return diff
|
||||
}
|
||||
|
||||
func normalizeJSON(dt []byte) string {
|
||||
var v any
|
||||
if err := json.Unmarshal(dt, &v); err != nil {
|
||||
return string(dt)
|
||||
}
|
||||
out, err := json.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
return string(dt)
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func equalLayerExpectations(a, b []compatibilityLayerExpectation) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func formatLayerExpectations(layers []compatibilityLayerExpectation) string {
|
||||
parts := make([]string, len(layers))
|
||||
for i, layer := range layers {
|
||||
parts[i] = fmt.Sprintf("{MediaType:%q,Digest:%q}", layer.MediaType, layer.Digest)
|
||||
}
|
||||
return "[" + strings.Join(parts, ", ") + "]"
|
||||
}
|
||||
|
||||
func cloneStringMap(in map[string]string) map[string]string {
|
||||
if len(in) == 0 {
|
||||
return map[string]string{}
|
||||
}
|
||||
out := make(map[string]string, len(in))
|
||||
maps.Copy(out, in)
|
||||
return out
|
||||
}
|
||||
|
||||
func sanitizeCompatibilityName(name string) string {
|
||||
var b strings.Builder
|
||||
b.Grow(len(name))
|
||||
for _, r := range name {
|
||||
switch {
|
||||
case r >= 'a' && r <= 'z':
|
||||
b.WriteRune(r)
|
||||
case r >= 'A' && r <= 'Z':
|
||||
b.WriteRune(r + ('a' - 'A'))
|
||||
case r >= '0' && r <= '9':
|
||||
b.WriteRune(r)
|
||||
case r == '.', r == '-', r == '_':
|
||||
b.WriteRune(r)
|
||||
default:
|
||||
b.WriteByte('-')
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func compatibilityPlatform(t *testing.T) ocispecs.Platform {
|
||||
t.Helper()
|
||||
return platforms.Normalize(platforms.MustParse(compatibilityPlatformString))
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
|
||||
type SolveOpt struct {
|
||||
Exports []ExportEntry
|
||||
CompatibilityVersion int
|
||||
EnableSessionExporter bool
|
||||
LocalDirs map[string]string // Deprecated: use LocalMounts
|
||||
LocalMounts map[string]fsutil.FS
|
||||
@@ -311,6 +312,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
|
||||
Cache: &cacheOpt.options,
|
||||
Entitlements: slices.Clone(opt.AllowedEntitlements),
|
||||
Internal: opt.Internal,
|
||||
CompatibilityVersion: int64(opt.CompatibilityVersion),
|
||||
SourcePolicy: opt.SourcePolicy,
|
||||
}
|
||||
if opt.SourcePolicyProvider != nil {
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
Compatibility regression goldens live under:
|
||||
|
||||
testdata/compatibility/<case>/v<compat-version>/{manifest,config}.json
|
||||
|
||||
Use BUILDKIT_UPDATE_COMPAT_GOLDENS=1 to regenerate them against the current daemon.
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:78260322e6ea253e5f3f675b3140ebe95ae8fc7e0ac2b1b3b88f1c8fc83525ce","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:3626b1d102dacca93b04a986b5c02d362209d18f05234437caa42e05e40db631",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:7a93c5cd268d789b9f3f4395657e8114c377144d0e8532e3082cb310538204e4",
|
||||
"size": 1916567,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:bddce71fda3dfcd6e87ef6d19383da8d6387ccb6ef9b1469fedd54b1187f5f20",
|
||||
"size": 151,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:9f55dc33cc1a8a650ec0b977d23e9ae2be65954f129f70fe44d766a52c61885b",
|
||||
"size": 247,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:f83d05f639a6555fc9c7f62b19ef2a75561e6934f05505d341cb21b6632e129f",
|
||||
"size": 108,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:9228085939d1444bd500ac8a4f8ee9d39fed1e5905da0968ffed61887ab41042","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:75c490263aada3f00b91cdd6f31d69098f2a27fb6c4a856dc9099a66cc84f96d",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:7a93c5cd268d789b9f3f4395657e8114c377144d0e8532e3082cb310538204e4",
|
||||
"size": 1916567,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:bddce71fda3dfcd6e87ef6d19383da8d6387ccb6ef9b1469fedd54b1187f5f20",
|
||||
"size": 151,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:3096f0079befb9bacfab7003f9de4604477e81ef1cd0d4bb9f967db5aba7bebc",
|
||||
"size": 242,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:f83d05f639a6555fc9c7f62b19ef2a75561e6934f05505d341cb21b6632e129f",
|
||||
"size": 108,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:78260322e6ea253e5f3f675b3140ebe95ae8fc7e0ac2b1b3b88f1c8fc83525ce","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:3626b1d102dacca93b04a986b5c02d362209d18f05234437caa42e05e40db631",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:9304bdcb5b86d518cf2128a070efb679fff088ce59d27072e9543f9836f78359",
|
||||
"size": 4272993,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:e67548f577b3eb6e6726c769a9ec3a2a46ad53f009f15d6e2e8bb797ee9e1f3a",
|
||||
"size": 2588,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:32b77f982cd1e1e83523fc65841d82dd0d925872e3dee6bd508ff81b157864c9",
|
||||
"size": 6172,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:bf943002b85c24847b4e0b6329ea308c705cffba71423e99d878204e7d2c79fa",
|
||||
"size": 2076,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:9228085939d1444bd500ac8a4f8ee9d39fed1e5905da0968ffed61887ab41042","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:75c490263aada3f00b91cdd6f31d69098f2a27fb6c4a856dc9099a66cc84f96d",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:9304bdcb5b86d518cf2128a070efb679fff088ce59d27072e9543f9836f78359",
|
||||
"size": 4272993,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:e67548f577b3eb6e6726c769a9ec3a2a46ad53f009f15d6e2e8bb797ee9e1f3a",
|
||||
"size": 2588,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:5c3240cc0bcdc46a4ff085359eba4d0ffe7e5e161c5f376e79f2264719041668",
|
||||
"size": 6172,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:bf943002b85c24847b4e0b6329ea308c705cffba71423e99d878204e7d2c79fa",
|
||||
"size": 2076,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:78260322e6ea253e5f3f675b3140ebe95ae8fc7e0ac2b1b3b88f1c8fc83525ce","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:3626b1d102dacca93b04a986b5c02d362209d18f05234437caa42e05e40db631",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:a130f54140e9b3f76dc2c2261eaa8500e5be39f942067e7a8ebdd3463795d1bc",
|
||||
"size": 1913990,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:6c24a150ead6b26912038d3a007cdd5de329ab9a9239ed948efee6381c60af3e",
|
||||
"size": 143,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:640c55a12b945452255a4cee6c2c084bc3b29f2f5b802eb0b42a4245f489ae23",
|
||||
"size": 232,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:4b65c30ca18f35f78dac1590302407fd5ae94fb24e5b69231b1e991342a1070c",
|
||||
"size": 107,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:9228085939d1444bd500ac8a4f8ee9d39fed1e5905da0968ffed61887ab41042","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:75c490263aada3f00b91cdd6f31d69098f2a27fb6c4a856dc9099a66cc84f96d",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:a130f54140e9b3f76dc2c2261eaa8500e5be39f942067e7a8ebdd3463795d1bc",
|
||||
"size": 1913990,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:6c24a150ead6b26912038d3a007cdd5de329ab9a9239ed948efee6381c60af3e",
|
||||
"size": 143,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:ba67dd0bb35371d02be3b950c6d617e1f22f55861fc5a7d0d354c8fbb2f77b56",
|
||||
"size": 228,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:4b65c30ca18f35f78dac1590302407fd5ae94fb24e5b69231b1e991342a1070c",
|
||||
"size": 107,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:78260322e6ea253e5f3f675b3140ebe95ae8fc7e0ac2b1b3b88f1c8fc83525ce","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:3626b1d102dacca93b04a986b5c02d362209d18f05234437caa42e05e40db631",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:7a93c5cd268d789b9f3f4395657e8114c377144d0e8532e3082cb310538204e4",
|
||||
"size": 1916567,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:bddce71fda3dfcd6e87ef6d19383da8d6387ccb6ef9b1469fedd54b1187f5f20",
|
||||
"size": 151,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:9f55dc33cc1a8a650ec0b977d23e9ae2be65954f129f70fe44d766a52c61885b",
|
||||
"size": 247,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:f83d05f639a6555fc9c7f62b19ef2a75561e6934f05505d341cb21b6632e129f",
|
||||
"size": 108,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"org.opencontainers.image.title": "compatibility-test"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:9228085939d1444bd500ac8a4f8ee9d39fed1e5905da0968ffed61887ab41042","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:75c490263aada3f00b91cdd6f31d69098f2a27fb6c4a856dc9099a66cc84f96d",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:7a93c5cd268d789b9f3f4395657e8114c377144d0e8532e3082cb310538204e4",
|
||||
"size": 1916567,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:bddce71fda3dfcd6e87ef6d19383da8d6387ccb6ef9b1469fedd54b1187f5f20",
|
||||
"size": 151,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:3096f0079befb9bacfab7003f9de4604477e81ef1cd0d4bb9f967db5aba7bebc",
|
||||
"size": 242,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:f83d05f639a6555fc9c7f62b19ef2a75561e6934f05505d341cb21b6632e129f",
|
||||
"size": 108,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"org.opencontainers.image.title": "compatibility-test"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:78260322e6ea253e5f3f675b3140ebe95ae8fc7e0ac2b1b3b88f1c8fc83525ce","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:3626b1d102dacca93b04a986b5c02d362209d18f05234437caa42e05e40db631",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:7a93c5cd268d789b9f3f4395657e8114c377144d0e8532e3082cb310538204e4",
|
||||
"size": 1916567,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:bddce71fda3dfcd6e87ef6d19383da8d6387ccb6ef9b1469fedd54b1187f5f20",
|
||||
"size": 151,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:9f55dc33cc1a8a650ec0b977d23e9ae2be65954f129f70fe44d766a52c61885b",
|
||||
"size": 247,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:f83d05f639a6555fc9c7f62b19ef2a75561e6934f05505d341cb21b6632e129f",
|
||||
"size": 108,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:9228085939d1444bd500ac8a4f8ee9d39fed1e5905da0968ffed61887ab41042","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:75c490263aada3f00b91cdd6f31d69098f2a27fb6c4a856dc9099a66cc84f96d",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:7a93c5cd268d789b9f3f4395657e8114c377144d0e8532e3082cb310538204e4",
|
||||
"size": 1916567,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:bddce71fda3dfcd6e87ef6d19383da8d6387ccb6ef9b1469fedd54b1187f5f20",
|
||||
"size": 151,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:3096f0079befb9bacfab7003f9de4604477e81ef1cd0d4bb9f967db5aba7bebc",
|
||||
"size": 242,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "sha256:f83d05f639a6555fc9c7f62b19ef2a75561e6934f05505d341cb21b6632e129f",
|
||||
"size": 108,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:78260322e6ea253e5f3f675b3140ebe95ae8fc7e0ac2b1b3b88f1c8fc83525ce","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:3626b1d102dacca93b04a986b5c02d362209d18f05234437caa42e05e40db631",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar",
|
||||
"digest": "sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01",
|
||||
"size": 4272640,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar",
|
||||
"digest": "sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837",
|
||||
"size": 2560,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar",
|
||||
"digest": "sha256:78260322e6ea253e5f3f675b3140ebe95ae8fc7e0ac2b1b3b88f1c8fc83525ce",
|
||||
"size": 6144,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar",
|
||||
"digest": "sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245",
|
||||
"size": 2048,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:9228085939d1444bd500ac8a4f8ee9d39fed1e5905da0968ffed61887ab41042","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:75c490263aada3f00b91cdd6f31d69098f2a27fb6c4a856dc9099a66cc84f96d",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar",
|
||||
"digest": "sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01",
|
||||
"size": 4272640,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar",
|
||||
"digest": "sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837",
|
||||
"size": 2560,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar",
|
||||
"digest": "sha256:9228085939d1444bd500ac8a4f8ee9d39fed1e5905da0968ffed61887ab41042",
|
||||
"size": 6144,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar",
|
||||
"digest": "sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245",
|
||||
"size": 2048,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/"},"created":"2015-10-21T07:28:00Z","history":[{"created":"2015-10-21T07:28:00Z","created_by":"created by buildkit","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"created by buildkit","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:78260322e6ea253e5f3f675b3140ebe95ae8fc7e0ac2b1b3b88f1c8fc83525ce","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]}}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:7d82822310244d958c0ba8f7ca7a1a6d05951014a94cddb428db890901a7acd8",
|
||||
"size": 1261
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+zstd",
|
||||
"digest": "sha256:afe006c96b8cc4b555093d5e3c5fed66c350a823f80aee0e832e4b493c990227",
|
||||
"size": 1792005,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+zstd",
|
||||
"digest": "sha256:1f844c50d06d6ce3ae52b9612df9432067c8c7f63d924de3edfaba224aa8067e",
|
||||
"size": 146,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+zstd",
|
||||
"digest": "sha256:d63f0b6201a917c58923b4e58cec8b46a08e9d6eae282e8432e73ccaa848e735",
|
||||
"size": 237,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+zstd",
|
||||
"digest": "sha256:8f28c1c2fe14efe5969fbec33c3d3877cc09bbeeaa0000a1772691e6bca025bc",
|
||||
"size": 95,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"architecture":"arm64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"85aa09f514bed8dee7af8bcf0074cf4fe6afecad73abb6c86164cfb7b074c4de","container_config":{"Hostname":"85aa09f514be","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"sh\"]"],"Image":"sha256:c3c0c88516c12e4bdff32a3505c8447db711ec0c71682e589b2a5b4e2db9e53f","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2015-10-21T07:28:00Z","docker_version":"20.10.23","history":[{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) ADD file:970f2985156276493000001a07e8417815afcd3a621bf5009ddb87e06eab1514 in / "},{"created":"2015-10-21T07:28:00Z","created_by":"/bin/sh -c #(nop) CMD [\"sh\"]","empty_layer":true},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /base, mkfile /base/base.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mkdir /inputs/git, mkfile /inputs/llb.txt, copy /artifact.txt /inputs/http.txt, copy /git.txt /inputs/git/git.txt, copy /sub/nested.txt /inputs/git/nested.txt","comment":"buildkit.exporter.image.v0"},{"created":"2015-10-21T07:28:00Z","created_by":"mount / from exec sh -eux -c \nmkdir -p /foo/bar/generated/deeper\necho exec-fixture \u003e /foo/bar/generated/exec.txt\necho nested-exec \u003e /foo/bar/generated/deeper/nested.txt\n","comment":"buildkit.exporter.image.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:a58dbf63860196622d60b97bf39c2cbba3e86039b8a196265389376e95edcf01","sha256:3836403461af46e9486f5f7086a1d6649828a215e357db42b18ed55d55315837","sha256:9228085939d1444bd500ac8a4f8ee9d39fed1e5905da0968ffed61887ab41042","sha256:6463152b9770f67aa00a13fca70749b2eda9cfabdc6fce35ad78d0d73dcc4245"]},"variant":"v8"}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": "sha256:75c490263aada3f00b91cdd6f31d69098f2a27fb6c4a856dc9099a66cc84f96d",
|
||||
"size": 2309
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+zstd",
|
||||
"digest": "sha256:afe006c96b8cc4b555093d5e3c5fed66c350a823f80aee0e832e4b493c990227",
|
||||
"size": 1792005,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+zstd",
|
||||
"digest": "sha256:1f844c50d06d6ce3ae52b9612df9432067c8c7f63d924de3edfaba224aa8067e",
|
||||
"size": 146,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+zstd",
|
||||
"digest": "sha256:cdd742478917b2382493c0c3ccf484ffa94833015e81b7b084c608bb8405affa",
|
||||
"size": 232,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+zstd",
|
||||
"digest": "sha256:8f28c1c2fe14efe5969fbec33c3d3877cc09bbeeaa0000a1772691e6bca025bc",
|
||||
"size": 95,
|
||||
"annotations": {
|
||||
"buildkit/rewritten-timestamp": "1445412480"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+10
-1
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/moby/buildkit/solver/bboltcachestorage"
|
||||
"github.com/moby/buildkit/solver/llbsolver"
|
||||
"github.com/moby/buildkit/solver/llbsolver/cdidevices"
|
||||
"github.com/moby/buildkit/solver/llbsolver/compat"
|
||||
"github.com/moby/buildkit/solver/llbsolver/history"
|
||||
"github.com/moby/buildkit/solver/llbsolver/proc"
|
||||
provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types"
|
||||
@@ -389,6 +390,14 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
|
||||
}
|
||||
translateLegacySolveRequest(req)
|
||||
|
||||
compatibilityVersion := int(req.CompatibilityVersion)
|
||||
if compatibilityVersion == 0 {
|
||||
compatibilityVersion = compat.CompatibilityVersionCurrent
|
||||
}
|
||||
if err := compat.ValidateCompatibilityVersion(compatibilityVersion); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
time.AfterFunc(time.Second, c.throttledGC)
|
||||
}()
|
||||
@@ -538,7 +547,7 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
|
||||
FrontendOpt: req.FrontendAttrs,
|
||||
FrontendInputs: req.FrontendInputs,
|
||||
CacheImports: cacheImports,
|
||||
}, llbsolver.ExporterRequest{
|
||||
}, compatibilityVersion, llbsolver.ExporterRequest{
|
||||
Exporters: expis,
|
||||
CacheExporters: cacheExporters,
|
||||
EnableSessionExporter: req.EnableSessionExporter,
|
||||
|
||||
@@ -73,3 +73,38 @@ See [v0.12 documentation](https://github.com/moby/buildkit/blob/v0.12/docs/build
|
||||
in BuildKit v0.12 and v0.11.
|
||||
|
||||
See also the [documentation](/frontend/dockerfile/docs/reference.md#buildkit-built-in-build-args) of the Dockerfile frontend.
|
||||
|
||||
## `compatibility-version`
|
||||
|
||||
`compatibility-version` pins digest-affecting image assembly behavior for the `image` and `oci` exporters.
|
||||
|
||||
BuildKit currently supports these values:
|
||||
|
||||
- `10` for the `v0.13.0` and `v0.14.0` historical path
|
||||
- `20` for the `v0.15.0+` path and current behavior
|
||||
|
||||
### `20`
|
||||
|
||||
`20` is the current compatibility version.
|
||||
|
||||
It matches released BuildKit output from `v0.15.0` and newer for the compatibility test matrix in `client/compatibility_test.go`.
|
||||
|
||||
### `10`
|
||||
|
||||
`10` represents the `v0.13.0` and `v0.14.0` historical path.
|
||||
|
||||
Compared to `20`, `10` differs in two ways:
|
||||
|
||||
- in the git-backed copied-content layer, non-executable regular files from the `git` source are stored as mode `0666` instead of `0644`
|
||||
- `compression=zstd` produces different historical artifacts
|
||||
|
||||
The git-backed layer boundary was introduced by commit `6493fd064ceece1d29f3e61aa73a531502f4795c` ("git: ensure exec option is propagated to child git clis").
|
||||
|
||||
The old pre-`v0.15.0` zstd artifacts crossed two independent historical changes:
|
||||
|
||||
1. `a2a440feb58388e6873082900a5c0b35746b18f3` ("vendor: update klauspost/compress to v1.17.9")
|
||||
2. `6493fd064ceece1d29f3e61aa73a531502f4795c` ("git: ensure exec option is propagated to child git clis")
|
||||
|
||||
The first changed zstd-compressed layer bytes. The second changed the git-backed copied-content layer metadata described above.
|
||||
|
||||
Because the currently supported historical backfill for `10` only covers the git-backed artifact difference, BuildKit currently rejects `compression=zstd` with `compatibility-version=10` instead of claiming full reproduction of the old zstd output.
|
||||
@@ -246,7 +246,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source
|
||||
}
|
||||
}()
|
||||
|
||||
desc, err := e.opt.ImageWriter.Commit(ctx, src, buildInfo.SessionID, buildInfo.InlineCache, &opts)
|
||||
desc, err := e.opt.ImageWriter.Commit(ctx, src, buildInfo.SessionID, buildInfo.InlineCache, &opts, buildInfo.CompatibilityVersion, e.Type())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import (
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/snapshot"
|
||||
"github.com/moby/buildkit/solver"
|
||||
solvererrdefs "github.com/moby/buildkit/solver/errdefs"
|
||||
"github.com/moby/buildkit/solver/llbsolver/compat"
|
||||
"github.com/moby/buildkit/solver/result"
|
||||
attestationTypes "github.com/moby/buildkit/util/attestation"
|
||||
"github.com/moby/buildkit/util/bklog"
|
||||
@@ -63,10 +65,14 @@ type ImageWriter struct {
|
||||
opt WriterOpt
|
||||
}
|
||||
|
||||
func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, sessionID string, inlineCache exptypes.InlineCache, opts *ImageCommitOpts) (*ocispecs.Descriptor, error) {
|
||||
func (ic *ImageWriter) Commit(ctx context.Context, inp *exporter.Source, sessionID string, inlineCache exptypes.InlineCache, opts *ImageCommitOpts, compatibilityVersion int, exporterType string) (*ocispecs.Descriptor, error) {
|
||||
if _, ok := inp.Metadata[exptypes.ExporterPlatformsKey]; len(inp.Refs) > 0 && !ok {
|
||||
return nil, errors.Errorf("unable to export multiple refs, missing platforms mapping")
|
||||
}
|
||||
if compatibilityVersion == compat.CompatibilityVersion013 && opts.RefCfg.Compression.Type == compression.Zstd {
|
||||
feature := fmt.Sprintf("%s exporter compression=%s", exporterType, opts.RefCfg.Compression.Type.String())
|
||||
return nil, solvererrdefs.NewUnsupportedCompatibilityFeatureError(compatibilityVersion, feature)
|
||||
}
|
||||
|
||||
isMap := len(inp.Refs) > 0
|
||||
|
||||
|
||||
@@ -50,9 +50,10 @@ type ExporterInstance interface {
|
||||
}
|
||||
|
||||
type ExportBuildInfo struct {
|
||||
Ref string
|
||||
InlineCache exptypes.InlineCache
|
||||
SessionID string
|
||||
Ref string
|
||||
InlineCache exptypes.InlineCache
|
||||
SessionID string
|
||||
CompatibilityVersion int
|
||||
}
|
||||
|
||||
type DescriptorReference interface {
|
||||
|
||||
@@ -159,7 +159,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source
|
||||
}
|
||||
}()
|
||||
|
||||
desc, err := e.opt.ImageWriter.Commit(ctx, src, buildInfo.SessionID, buildInfo.InlineCache, &opts)
|
||||
desc, err := e.opt.ImageWriter.Commit(ctx, src, buildInfo.SessionID, buildInfo.InlineCache, &opts, buildInfo.CompatibilityVersion, e.Type())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/profile v1.7.0
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/prometheus/procfs v0.17.0
|
||||
github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b
|
||||
@@ -203,7 +204,6 @@ require (
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20251114084447-edf4cb3d2116 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.66.1 // indirect
|
||||
github.com/prometheus/otlptranslator v0.0.2 // indirect
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package errdefs
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
|
||||
"github.com/containerd/typeurl/v2"
|
||||
"github.com/moby/buildkit/util/grpcerrors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
typeurl.Register((*CompatibilityFeature)(nil), "github.com/moby/buildkit", "errdefs.CompatibilityFeature+json")
|
||||
}
|
||||
|
||||
type UnsupportedCompatibilityFeatureError struct {
|
||||
*CompatibilityFeature
|
||||
error
|
||||
}
|
||||
|
||||
func (e *UnsupportedCompatibilityFeatureError) Error() string {
|
||||
msg := fmt.Sprintf("unsupported compatibility-version %d feature %s", e.Version, e.Feature)
|
||||
if e.error != nil {
|
||||
msg += ": " + e.error.Error()
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func (e *UnsupportedCompatibilityFeatureError) Unwrap() error {
|
||||
return e.error
|
||||
}
|
||||
|
||||
func (e *UnsupportedCompatibilityFeatureError) ToProto() grpcerrors.TypedErrorProto {
|
||||
return e.CompatibilityFeature
|
||||
}
|
||||
|
||||
func NewUnsupportedCompatibilityFeatureError(version int, feature string) error {
|
||||
return &UnsupportedCompatibilityFeatureError{
|
||||
CompatibilityFeature: &CompatibilityFeature{Version: int64(version), Feature: feature},
|
||||
}
|
||||
}
|
||||
|
||||
func (v *CompatibilityFeature) WrapError(err error) error {
|
||||
return &UnsupportedCompatibilityFeatureError{error: err, CompatibilityFeature: v}
|
||||
}
|
||||
@@ -214,6 +214,58 @@ func (x *FrontendCap) GetName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type CompatibilityFeature struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
|
||||
Feature string `protobuf:"bytes,2,opt,name=feature,proto3" json:"feature,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *CompatibilityFeature) Reset() {
|
||||
*x = CompatibilityFeature{}
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *CompatibilityFeature) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CompatibilityFeature) ProtoMessage() {}
|
||||
|
||||
func (x *CompatibilityFeature) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CompatibilityFeature.ProtoReflect.Descriptor instead.
|
||||
func (*CompatibilityFeature) Descriptor() ([]byte, []int) {
|
||||
return file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *CompatibilityFeature) GetVersion() int64 {
|
||||
if x != nil {
|
||||
return x.Version
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *CompatibilityFeature) GetFeature() string {
|
||||
if x != nil {
|
||||
return x.Feature
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Subrequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
@@ -223,7 +275,7 @@ type Subrequest struct {
|
||||
|
||||
func (x *Subrequest) Reset() {
|
||||
*x = Subrequest{}
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[4]
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -235,7 +287,7 @@ func (x *Subrequest) String() string {
|
||||
func (*Subrequest) ProtoMessage() {}
|
||||
|
||||
func (x *Subrequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[4]
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[5]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -248,7 +300,7 @@ func (x *Subrequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Subrequest.ProtoReflect.Descriptor instead.
|
||||
func (*Subrequest) Descriptor() ([]byte, []int) {
|
||||
return file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescGZIP(), []int{4}
|
||||
return file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *Subrequest) GetName() string {
|
||||
@@ -275,7 +327,7 @@ type Solve struct {
|
||||
|
||||
func (x *Solve) Reset() {
|
||||
*x = Solve{}
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[5]
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -287,7 +339,7 @@ func (x *Solve) String() string {
|
||||
func (*Solve) ProtoMessage() {}
|
||||
|
||||
func (x *Solve) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[5]
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[6]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -300,7 +352,7 @@ func (x *Solve) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Solve.ProtoReflect.Descriptor instead.
|
||||
func (*Solve) Descriptor() ([]byte, []int) {
|
||||
return file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescGZIP(), []int{5}
|
||||
return file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *Solve) GetInputIDs() []string {
|
||||
@@ -382,7 +434,7 @@ type FileAction struct {
|
||||
|
||||
func (x *FileAction) Reset() {
|
||||
*x = FileAction{}
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[6]
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -394,7 +446,7 @@ func (x *FileAction) String() string {
|
||||
func (*FileAction) ProtoMessage() {}
|
||||
|
||||
func (x *FileAction) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[6]
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[7]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -407,7 +459,7 @@ func (x *FileAction) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use FileAction.ProtoReflect.Descriptor instead.
|
||||
func (*FileAction) Descriptor() ([]byte, []int) {
|
||||
return file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescGZIP(), []int{6}
|
||||
return file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *FileAction) GetIndex() int64 {
|
||||
@@ -427,7 +479,7 @@ type ContentCache struct {
|
||||
|
||||
func (x *ContentCache) Reset() {
|
||||
*x = ContentCache{}
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[7]
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -439,7 +491,7 @@ func (x *ContentCache) String() string {
|
||||
func (*ContentCache) ProtoMessage() {}
|
||||
|
||||
func (x *ContentCache) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[7]
|
||||
mi := &file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -452,7 +504,7 @@ func (x *ContentCache) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ContentCache.ProtoReflect.Descriptor instead.
|
||||
func (*ContentCache) Descriptor() ([]byte, []int) {
|
||||
return file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescGZIP(), []int{7}
|
||||
return file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *ContentCache) GetIndex() int64 {
|
||||
@@ -476,7 +528,10 @@ const file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDesc = "" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\x12\x16\n" +
|
||||
"\x06source\x18\x02 \x01(\tR\x06source\"!\n" +
|
||||
"\vFrontendCap\x12\x12\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\" \n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\"J\n" +
|
||||
"\x14CompatibilityFeature\x12\x18\n" +
|
||||
"\aversion\x18\x01 \x01(\x03R\aversion\x12\x18\n" +
|
||||
"\afeature\x18\x02 \x01(\tR\afeature\" \n" +
|
||||
"\n" +
|
||||
"Subrequest\x12\x12\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\"\xbf\x02\n" +
|
||||
@@ -509,28 +564,29 @@ func file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescGZIP() []
|
||||
return file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
||||
var file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_goTypes = []any{
|
||||
(*Vertex)(nil), // 0: errdefs.Vertex
|
||||
(*Source)(nil), // 1: errdefs.Source
|
||||
(*Frontend)(nil), // 2: errdefs.Frontend
|
||||
(*FrontendCap)(nil), // 3: errdefs.FrontendCap
|
||||
(*Subrequest)(nil), // 4: errdefs.Subrequest
|
||||
(*Solve)(nil), // 5: errdefs.Solve
|
||||
(*FileAction)(nil), // 6: errdefs.FileAction
|
||||
(*ContentCache)(nil), // 7: errdefs.ContentCache
|
||||
nil, // 8: errdefs.Solve.DescriptionEntry
|
||||
(*pb.SourceInfo)(nil), // 9: pb.SourceInfo
|
||||
(*pb.Range)(nil), // 10: pb.Range
|
||||
(*pb.Op)(nil), // 11: pb.Op
|
||||
(*Vertex)(nil), // 0: errdefs.Vertex
|
||||
(*Source)(nil), // 1: errdefs.Source
|
||||
(*Frontend)(nil), // 2: errdefs.Frontend
|
||||
(*FrontendCap)(nil), // 3: errdefs.FrontendCap
|
||||
(*CompatibilityFeature)(nil), // 4: errdefs.CompatibilityFeature
|
||||
(*Subrequest)(nil), // 5: errdefs.Subrequest
|
||||
(*Solve)(nil), // 6: errdefs.Solve
|
||||
(*FileAction)(nil), // 7: errdefs.FileAction
|
||||
(*ContentCache)(nil), // 8: errdefs.ContentCache
|
||||
nil, // 9: errdefs.Solve.DescriptionEntry
|
||||
(*pb.SourceInfo)(nil), // 10: pb.SourceInfo
|
||||
(*pb.Range)(nil), // 11: pb.Range
|
||||
(*pb.Op)(nil), // 12: pb.Op
|
||||
}
|
||||
var file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_depIdxs = []int32{
|
||||
9, // 0: errdefs.Source.info:type_name -> pb.SourceInfo
|
||||
10, // 1: errdefs.Source.ranges:type_name -> pb.Range
|
||||
11, // 2: errdefs.Solve.op:type_name -> pb.Op
|
||||
6, // 3: errdefs.Solve.file:type_name -> errdefs.FileAction
|
||||
7, // 4: errdefs.Solve.cache:type_name -> errdefs.ContentCache
|
||||
8, // 5: errdefs.Solve.description:type_name -> errdefs.Solve.DescriptionEntry
|
||||
10, // 0: errdefs.Source.info:type_name -> pb.SourceInfo
|
||||
11, // 1: errdefs.Source.ranges:type_name -> pb.Range
|
||||
12, // 2: errdefs.Solve.op:type_name -> pb.Op
|
||||
7, // 3: errdefs.Solve.file:type_name -> errdefs.FileAction
|
||||
8, // 4: errdefs.Solve.cache:type_name -> errdefs.ContentCache
|
||||
9, // 5: errdefs.Solve.description:type_name -> errdefs.Solve.DescriptionEntry
|
||||
6, // [6:6] is the sub-list for method output_type
|
||||
6, // [6:6] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
@@ -543,7 +599,7 @@ func file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_init() {
|
||||
if File_github_com_moby_buildkit_solver_errdefs_errdefs_proto != nil {
|
||||
return
|
||||
}
|
||||
file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[5].OneofWrappers = []any{
|
||||
file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_msgTypes[6].OneofWrappers = []any{
|
||||
(*Solve_File)(nil),
|
||||
(*Solve_Cache)(nil),
|
||||
}
|
||||
@@ -553,7 +609,7 @@ func file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDesc), len(file_github_com_moby_buildkit_solver_errdefs_errdefs_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 9,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -24,6 +24,11 @@ message FrontendCap {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message CompatibilityFeature {
|
||||
int64 version = 1;
|
||||
string feature = 2;
|
||||
}
|
||||
|
||||
message Subrequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
@@ -96,6 +96,24 @@ func (m *FrontendCap) CloneMessageVT() proto.Message {
|
||||
return m.CloneVT()
|
||||
}
|
||||
|
||||
func (m *CompatibilityFeature) CloneVT() *CompatibilityFeature {
|
||||
if m == nil {
|
||||
return (*CompatibilityFeature)(nil)
|
||||
}
|
||||
r := new(CompatibilityFeature)
|
||||
r.Version = m.Version
|
||||
r.Feature = m.Feature
|
||||
if len(m.unknownFields) > 0 {
|
||||
r.unknownFields = make([]byte, len(m.unknownFields))
|
||||
copy(r.unknownFields, m.unknownFields)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (m *CompatibilityFeature) CloneMessageVT() proto.Message {
|
||||
return m.CloneVT()
|
||||
}
|
||||
|
||||
func (m *Subrequest) CloneVT() *Subrequest {
|
||||
if m == nil {
|
||||
return (*Subrequest)(nil)
|
||||
@@ -298,6 +316,28 @@ func (this *FrontendCap) EqualMessageVT(thatMsg proto.Message) bool {
|
||||
}
|
||||
return this.EqualVT(that)
|
||||
}
|
||||
func (this *CompatibilityFeature) EqualVT(that *CompatibilityFeature) bool {
|
||||
if this == that {
|
||||
return true
|
||||
} else if this == nil || that == nil {
|
||||
return false
|
||||
}
|
||||
if this.Version != that.Version {
|
||||
return false
|
||||
}
|
||||
if this.Feature != that.Feature {
|
||||
return false
|
||||
}
|
||||
return string(this.unknownFields) == string(that.unknownFields)
|
||||
}
|
||||
|
||||
func (this *CompatibilityFeature) EqualMessageVT(thatMsg proto.Message) bool {
|
||||
that, ok := thatMsg.(*CompatibilityFeature)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return this.EqualVT(that)
|
||||
}
|
||||
func (this *Subrequest) EqualVT(that *Subrequest) bool {
|
||||
if this == that {
|
||||
return true
|
||||
@@ -646,6 +686,51 @@ func (m *FrontendCap) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *CompatibilityFeature) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *CompatibilityFeature) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *CompatibilityFeature) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.Feature) > 0 {
|
||||
i -= len(m.Feature)
|
||||
copy(dAtA[i:], m.Feature)
|
||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Feature)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if m.Version != 0 {
|
||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Version))
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *Subrequest) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
@@ -963,6 +1048,23 @@ func (m *FrontendCap) SizeVT() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *CompatibilityFeature) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.Version != 0 {
|
||||
n += 1 + protohelpers.SizeOfVarint(uint64(m.Version))
|
||||
}
|
||||
l = len(m.Feature)
|
||||
if l > 0 {
|
||||
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *Subrequest) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@@ -1470,6 +1572,108 @@ func (m *FrontendCap) UnmarshalVT(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *CompatibilityFeature) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return protohelpers.ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: CompatibilityFeature: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: CompatibilityFeature: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType)
|
||||
}
|
||||
m.Version = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return protohelpers.ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Version |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Feature", 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.Feature = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return protohelpers.ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Subrequest) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/moby/buildkit/identity"
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/solver/errdefs"
|
||||
"github.com/moby/buildkit/solver/llbsolver/compat"
|
||||
"github.com/moby/buildkit/util/bklog"
|
||||
"github.com/moby/buildkit/util/bkmaps"
|
||||
"github.com/moby/buildkit/util/flightcontrol"
|
||||
@@ -90,6 +91,34 @@ func (s *state) ResolverCache() ResolverCache {
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *state) CompatibilityVersion() (int, error) {
|
||||
s.mu.Lock()
|
||||
jobs := make([]*Job, 0, len(s.jobs))
|
||||
for j := range s.jobs {
|
||||
jobs = append(jobs, j)
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
version := 0
|
||||
for _, j := range jobs {
|
||||
v, err := j.CompatibilityVersion()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if version == 0 {
|
||||
version = v
|
||||
continue
|
||||
}
|
||||
if version != v {
|
||||
return 0, errors.Errorf("conflicting compatibility versions in shared solve state: %d != %d", version, v)
|
||||
}
|
||||
}
|
||||
if version == 0 {
|
||||
return compat.CompatibilityVersionCurrent, nil
|
||||
}
|
||||
return version, nil
|
||||
}
|
||||
|
||||
func (s *state) Lock(key any) (values []any, release func(any) error, err error) {
|
||||
var rcs []ResolverCache
|
||||
s.mu.Lock()
|
||||
@@ -865,6 +894,21 @@ func (j *Job) UniqueID() string {
|
||||
return j.uniqueID
|
||||
}
|
||||
|
||||
func (j *Job) CompatibilityVersion() (int, error) {
|
||||
version := compat.CompatibilityVersionCurrent
|
||||
if err := j.EachValue(context.TODO(), compat.JobValueKey, func(v any) error {
|
||||
parsed, ok := v.(int)
|
||||
if !ok {
|
||||
return errors.Errorf("invalid compatibility version %T", v)
|
||||
}
|
||||
version = parsed
|
||||
return nil
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return version, nil
|
||||
}
|
||||
|
||||
func (j *Job) InContext(ctx context.Context, f func(context.Context, JobContext) error) error {
|
||||
return f(progress.WithProgress(ctx, j.pw), j)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package compat
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
CompatibilityVersion013 = 10
|
||||
CompatibilityVersion015 = 20
|
||||
CompatibilityVersionCurrent = CompatibilityVersion015
|
||||
)
|
||||
|
||||
// JobValueKey is the key used to store the compatibility version on a solver
|
||||
// job via Job.SetValue/EachValue.
|
||||
const JobValueKey = "llb.compatibilityversion"
|
||||
|
||||
var supportedCompatibilityVersions = []int{
|
||||
CompatibilityVersion013,
|
||||
CompatibilityVersion015,
|
||||
}
|
||||
|
||||
func SupportedCompatibilityVersions() []int {
|
||||
return slices.Clone(supportedCompatibilityVersions)
|
||||
}
|
||||
|
||||
func ValidateCompatibilityVersion(version int) error {
|
||||
if slices.Contains(supportedCompatibilityVersions, version) {
|
||||
return nil
|
||||
}
|
||||
if version > CompatibilityVersionCurrent {
|
||||
return errors.Errorf("unsupported compatibility-version %d: upgrade buildkit (max supported: %d)", version, CompatibilityVersionCurrent)
|
||||
}
|
||||
return errors.Errorf("unsupported compatibility-version %d (supported: %v)", version, supportedCompatibilityVersions)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package compat
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSupportedCompatibilityVersions(t *testing.T) {
|
||||
require.Equal(t, []int{10, 20}, SupportedCompatibilityVersions())
|
||||
require.Equal(t, 20, CompatibilityVersionCurrent)
|
||||
}
|
||||
|
||||
func TestValidateCompatibilityVersion(t *testing.T) {
|
||||
require.NoError(t, ValidateCompatibilityVersion(CompatibilityVersion013))
|
||||
require.NoError(t, ValidateCompatibilityVersion(CompatibilityVersionCurrent))
|
||||
require.ErrorContains(t, ValidateCompatibilityVersion(11), "unsupported compatibility-version 11")
|
||||
require.ErrorContains(t, ValidateCompatibilityVersion(30), "upgrade buildkit")
|
||||
}
|
||||
@@ -188,11 +188,16 @@ func (s *Solver) runExporters(ctx context.Context, ref string, exporters []expor
|
||||
defer inlineCacheMu.Unlock()
|
||||
return runInlineCacheExporter(ctx, exp, inlineCacheExporter, job, cached)
|
||||
})
|
||||
compatibilityVersion, err := job.CompatibilityVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, finalize, desc, expErr := exp.Export(ctx, inp, exporter.ExportBuildInfo{
|
||||
Ref: ref,
|
||||
SessionID: job.SessionID,
|
||||
InlineCache: inlineCache,
|
||||
Ref: ref,
|
||||
SessionID: job.SessionID,
|
||||
InlineCache: inlineCache,
|
||||
CompatibilityVersion: compatibilityVersion,
|
||||
})
|
||||
resps[i], finalizeFuncs[i], descs[i] = resp, finalize, desc
|
||||
if expErr != nil {
|
||||
|
||||
@@ -311,3 +311,7 @@ func (j *jobCtx) Cleanup(f func() error) error {
|
||||
func (j *jobCtx) ResolverCache() solver.ResolverCache {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *jobCtx) CompatibilityVersion() (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
@@ -71,7 +71,6 @@ func ProvenanceProcessor(slsaVersion provenancetypes.ProvenanceSLSA, attrs map[s
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.MarshalIndent(pr, "", " ")
|
||||
},
|
||||
})
|
||||
|
||||
@@ -506,6 +506,12 @@ func (p *ProvenanceCreator) Predicate(ctx context.Context) (any, error) {
|
||||
p.pr.RunDetails.Metadata.BuildKitMetadata.SysUsage = sysSamples
|
||||
}
|
||||
|
||||
compatibilityVersion, err := p.j.CompatibilityVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.pr.BuildDefinition.ExternalParameters.Request.CompatibilityVersion = compatibilityVersion
|
||||
|
||||
if p.slsaVersion == provenancetypes.ProvenanceSLSA02 {
|
||||
return p.pr.ConvertToSLSA02(), nil
|
||||
}
|
||||
|
||||
@@ -172,12 +172,12 @@ type ProvenanceMetadataSLSA1 struct {
|
||||
}
|
||||
|
||||
type Parameters struct {
|
||||
Frontend string `json:"frontend,omitempty"`
|
||||
Args map[string]string `json:"args,omitempty"`
|
||||
Secrets []*Secret `json:"secrets,omitempty"`
|
||||
SSH []*SSH `json:"ssh,omitempty"`
|
||||
Locals []*LocalSource `json:"locals,omitempty"`
|
||||
// TODO: select export attributes
|
||||
Frontend string `json:"frontend,omitempty"`
|
||||
Args map[string]string `json:"args,omitempty"`
|
||||
Secrets []*Secret `json:"secrets,omitempty"`
|
||||
SSH []*SSH `json:"ssh,omitempty"`
|
||||
Locals []*LocalSource `json:"locals,omitempty"`
|
||||
CompatibilityVersion int `json:"compatibilityVersion,omitempty"`
|
||||
// TODO: frontend inputs
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/moby/buildkit/identity"
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/solver"
|
||||
"github.com/moby/buildkit/solver/llbsolver/compat"
|
||||
"github.com/moby/buildkit/solver/llbsolver/history"
|
||||
"github.com/moby/buildkit/solver/result"
|
||||
spb "github.com/moby/buildkit/sourcepolicy/pb"
|
||||
@@ -153,7 +154,7 @@ func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge {
|
||||
return s.bridge(b)
|
||||
}
|
||||
|
||||
func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req frontend.SolveRequest, exp ExporterRequest, ent []entitlements.Entitlement, post []Processor, internal bool, srcPol *spb.Policy, policySession string) (_ *client.SolveResponse, err error) {
|
||||
func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req frontend.SolveRequest, compatibilityVersion int, exp ExporterRequest, ent []entitlements.Entitlement, post []Processor, internal bool, srcPol *spb.Policy, policySession string) (_ *client.SolveResponse, err error) {
|
||||
hasNamedDockerfileContext := false
|
||||
for k := range req.FrontendOpt {
|
||||
if k == "context:dockerfile.v0" || strings.HasPrefix(k, "context:dockerfile.v0::") {
|
||||
@@ -216,6 +217,10 @@ func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req fro
|
||||
if policySession != "" {
|
||||
j.SetValue(keySourcePolicySession, policySession)
|
||||
}
|
||||
if compatibilityVersion == 0 {
|
||||
compatibilityVersion = compat.CompatibilityVersionCurrent
|
||||
}
|
||||
j.SetValue(compat.JobValueKey, compatibilityVersion)
|
||||
|
||||
j.SessionID = sessionID
|
||||
|
||||
|
||||
@@ -184,6 +184,8 @@ type JobContext interface {
|
||||
// ResolverCache returns object for memorizing/synchronizing remote resolving decisions during the job.
|
||||
// Steps from same build job will share the same resolver cache.
|
||||
ResolverCache() ResolverCache
|
||||
// CompatibilityVersion returns the solve-wide compatibility version for the current job.
|
||||
CompatibilityVersion() (int, error)
|
||||
}
|
||||
|
||||
type ResolverCache interface {
|
||||
|
||||
+44
-2
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/moby/buildkit/session/sshforward"
|
||||
"github.com/moby/buildkit/snapshot"
|
||||
"github.com/moby/buildkit/solver"
|
||||
"github.com/moby/buildkit/solver/llbsolver/compat"
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
"github.com/moby/buildkit/source"
|
||||
srctypes "github.com/moby/buildkit/source/types"
|
||||
@@ -789,6 +790,14 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, jobCtx solver.JobConte
|
||||
g = jobCtx.Session()
|
||||
}
|
||||
gs.getAuthToken(ctx, g)
|
||||
compatibilityVersion := 0
|
||||
if jobCtx != nil {
|
||||
var err error
|
||||
compatibilityVersion, err = jobCtx.CompatibilityVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
snapshotKey := cacheKey + ":" + gs.src.Subdir
|
||||
gs.locker.Lock(snapshotKey)
|
||||
@@ -808,7 +817,7 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, jobCtx solver.JobConte
|
||||
}
|
||||
defer repo.Release()
|
||||
|
||||
ref, err := gs.checkout(ctx, repo, g)
|
||||
ref, err := gs.checkout(ctx, repo, g, compatibilityVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -975,7 +984,7 @@ func (gs *gitSourceHandler) tryRemoteFetch(ctx context.Context, g session.Group,
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func (gs *gitSourceHandler) checkout(ctx context.Context, repo *gitRepo, g session.Group) (_ cache.ImmutableRef, retErr error) {
|
||||
func (gs *gitSourceHandler) checkout(ctx context.Context, repo *gitRepo, g session.Group, compatibilityVersion int) (_ cache.ImmutableRef, retErr error) {
|
||||
ref := gs.src.Ref
|
||||
checkoutRef, err := gs.cache.New(ctx, nil, g, cache.WithRecordType(client.UsageRecordTypeGitCheckout), cache.WithDescription(fmt.Sprintf("git snapshot for %s#%s", urlutil.RedactCredentials(gs.src.Remote), ref)))
|
||||
if err != nil {
|
||||
@@ -1138,6 +1147,12 @@ func (gs *gitSourceHandler) checkout(ctx context.Context, repo *gitRepo, g sessi
|
||||
}
|
||||
}
|
||||
|
||||
if compatibilityVersion == compat.CompatibilityVersion013 {
|
||||
if err := resetCompatibility014FileModes(checkoutDir); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to normalize compatibility file modes for %s", urlutil.RedactCredentials(gs.src.Remote))
|
||||
}
|
||||
}
|
||||
|
||||
if gs.src.MTime == "commit" {
|
||||
commitTime, err := getCommitTime(ctx, git, ref)
|
||||
if err != nil {
|
||||
@@ -1220,6 +1235,33 @@ func resetSnapshotMtimes(dir string, t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// resetCompatibility014FileModes restores the pre-v0.15 git checkout file
|
||||
// mode for non-executable regular files, which were stored with group/other
|
||||
// write bits set before the exec-option propagation fix. Executable files are
|
||||
// left untouched: their pre-v0.15 behavior is not covered by the current
|
||||
// compatibility matrix, and blindly adding write bits to 0o755 would be a
|
||||
// guess.
|
||||
func resetCompatibility014FileModes(dir string) error {
|
||||
return filepath.WalkDir(dir, func(p string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() || d.Type()&os.ModeSymlink != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mode := info.Mode()
|
||||
if !mode.IsRegular() || mode&0o111 != 0 {
|
||||
return nil
|
||||
}
|
||||
return os.Chmod(p, mode|0o222)
|
||||
})
|
||||
}
|
||||
|
||||
type wouldClobberExistingTagError struct {
|
||||
error
|
||||
}
|
||||
|
||||
@@ -27,8 +27,11 @@ import (
|
||||
"github.com/moby/buildkit/cache"
|
||||
"github.com/moby/buildkit/cache/metadata"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/snapshot"
|
||||
containerdsnapshot "github.com/moby/buildkit/snapshot/containerd"
|
||||
"github.com/moby/buildkit/solver"
|
||||
"github.com/moby/buildkit/solver/llbsolver/compat"
|
||||
"github.com/moby/buildkit/util/gitutil"
|
||||
"github.com/moby/buildkit/util/gitutil/gitobject"
|
||||
"github.com/moby/buildkit/util/gitutil/gitsign"
|
||||
@@ -2188,6 +2191,54 @@ func setupGitSource(t *testing.T, tmpdir string) *Source {
|
||||
return gs
|
||||
}
|
||||
|
||||
type testJobContext struct {
|
||||
compatibilityVersion int
|
||||
}
|
||||
|
||||
func (j testJobContext) Session() session.Group {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j testJobContext) Cleanup(func() error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j testJobContext) ResolverCache() solver.ResolverCache {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j testJobContext) CompatibilityVersion() (int, error) {
|
||||
return j.compatibilityVersion, nil
|
||||
}
|
||||
|
||||
func gitSnapshotMode(ctx context.Context, t *testing.T, gs *Source, id *GitIdentifier, jobCtx solver.JobContext) os.FileMode {
|
||||
t.Helper()
|
||||
|
||||
g, err := gs.Resolve(ctx, id, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, _, done, err := g.CacheKey(ctx, jobCtx, 0)
|
||||
require.NoError(t, err)
|
||||
require.True(t, done)
|
||||
|
||||
ref, err := g.Snapshot(ctx, jobCtx)
|
||||
require.NoError(t, err)
|
||||
defer ref.Release(context.TODO())
|
||||
|
||||
mount, err := ref.Mount(ctx, true, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
lm := snapshot.LocalMounter(mount)
|
||||
dir, err := lm.Mount()
|
||||
require.NoError(t, err)
|
||||
defer lm.Unmount()
|
||||
|
||||
st, err := os.Lstat(filepath.Join(dir, "def"))
|
||||
require.NoError(t, err)
|
||||
|
||||
return st.Mode() & os.ModePerm
|
||||
}
|
||||
|
||||
type gitRepoFixture struct {
|
||||
mainPath, subPath string // Filesystem paths to the respective repos
|
||||
mainURL, subURL string // HTTP URLs for the respective repos
|
||||
@@ -2497,6 +2548,25 @@ func TestCommitTimeMtimesKeepGitDirSHA256(t *testing.T) {
|
||||
testCommitTimeMtimes(t, "sha256", true)
|
||||
}
|
||||
|
||||
func TestCompatibility014FileModes(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Depends on unimplemented containerd bind-mount support on Windows")
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
ctx := logProgressStreams(context.Background(), t)
|
||||
|
||||
gs := setupGitSource(t, t.TempDir())
|
||||
repo := setupGitRepo(t, "sha1")
|
||||
id := &GitIdentifier{Remote: repo.mainURL, Ref: "master"}
|
||||
|
||||
currentMode := gitSnapshotMode(ctx, t, gs, id, testJobContext{compatibilityVersion: compat.CompatibilityVersionCurrent})
|
||||
compat013Mode := gitSnapshotMode(ctx, t, gs, id, testJobContext{compatibilityVersion: compat.CompatibilityVersion013})
|
||||
|
||||
require.Equal(t, os.FileMode(0o644), currentMode)
|
||||
require.Equal(t, os.FileMode(0o666), compat013Mode)
|
||||
}
|
||||
|
||||
func testCommitTimeMtimes(t *testing.T, format string, keepGitDir bool) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Depends on unimplemented containerd bind-mount support on Windows")
|
||||
|
||||
@@ -599,6 +599,10 @@ func (s *simpleJobContext) ResolverCache() solver.ResolverCache {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *simpleJobContext) CompatibilityVersion() (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func readSignFixture(t *testing.T, fixturesPath, name string) []byte {
|
||||
t.Helper()
|
||||
p := filepath.Join(fixturesPath, name)
|
||||
|
||||
Reference in new issue
Block a user