Skip to content

Commit

Permalink
Merge pull request #3240 from tonistiigi/attestations-provenance
Browse files Browse the repository at this point in the history
Support for provenance attestations
  • Loading branch information
tonistiigi authored Nov 16, 2022
2 parents 8270cab + fb917b9 commit abae584
Show file tree
Hide file tree
Showing 79 changed files with 5,961 additions and 1,378 deletions.
4 changes: 2 additions & 2 deletions cache/remotecache/v1/chains.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func (c *item) removeLink(src *item) bool {
return found
}

func (c *item) AddResult(createdAt time.Time, result *solver.Remote) {
func (c *item) AddResult(_ digest.Digest, _ int, createdAt time.Time, result *solver.Remote) {
c.resultTime = createdAt
c.result = result
}
Expand Down Expand Up @@ -214,7 +214,7 @@ func (c *item) walkAllResults(fn func(i *item) error, visited map[*item]struct{}
type nopRecord struct {
}

func (c *nopRecord) AddResult(createdAt time.Time, result *solver.Remote) {
func (c *nopRecord) AddResult(_ digest.Digest, _ int, createdAt time.Time, result *solver.Remote) {
}

func (c *nopRecord) LinkFrom(rec solver.CacheExporterRecord, index int, selector string) {
Expand Down
2 changes: 1 addition & 1 deletion cache/remotecache/v1/chains_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestSimpleMarshal(t *testing.T) {
Digest: dgst("d1"),
}},
}
baz.AddResult(time.Now(), r0)
baz.AddResult("", 0, time.Now(), r0)
}

addRecords()
Expand Down
4 changes: 2 additions & 2 deletions cache/remotecache/v1/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func parseRecord(cc CacheConfig, idx int, provider DescriptorProvider, t solver.
return nil, err
}
if remote != nil {
r.AddResult(res.CreatedAt, remote)
r.AddResult("", 0, res.CreatedAt, remote)
}
}

Expand All @@ -86,7 +86,7 @@ func parseRecord(cc CacheConfig, idx int, provider DescriptorProvider, t solver.
}
if remote != nil {
remote.Provider = mp
r.AddResult(res.CreatedAt, remote)
r.AddResult("", 0, res.CreatedAt, remote)
}
}

Expand Down
63 changes: 0 additions & 63 deletions client/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package client
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"os"
Expand All @@ -16,7 +14,6 @@ import (
"time"

"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/frontend/gateway/client"
gatewayapi "github.com/moby/buildkit/frontend/gateway/pb"
"github.com/moby/buildkit/identity"
Expand All @@ -25,7 +22,6 @@ import (
"github.com/moby/buildkit/session/sshforward/sshprovider"
"github.com/moby/buildkit/solver/errdefs"
"github.com/moby/buildkit/solver/pb"
binfotypes "github.com/moby/buildkit/util/buildinfo/types"
"github.com/moby/buildkit/util/entitlements"
utilsystem "github.com/moby/buildkit/util/system"
"github.com/moby/buildkit/util/testutil/echoserver"
Expand Down Expand Up @@ -58,7 +54,6 @@ func TestClientGatewayIntegration(t *testing.T) {
testClientGatewayContainerExtraHosts,
testClientGatewayContainerSignal,
testWarnings,
testClientGatewayFrontendAttrs,
testClientGatewayNilResult,
testClientGatewayEmptyImageExec,
), integration.WithMirroredImages(integration.OfficialImages("busybox:latest")))
Expand Down Expand Up @@ -1995,64 +1990,6 @@ func testClientGatewayContainerSignal(t *testing.T, sb integration.Sandbox) {
checkAllReleasable(t, c, sb, true)
}

// moby/buildkit#2476
func testClientGatewayFrontendAttrs(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
c, err := New(sb.Context(), sb.Address())
require.NoError(t, err)
defer c.Close()

fooattrval := "bar"
bazattrval := "fuu"

b := func(ctx context.Context, c client.Client) (*client.Result, error) {
st := llb.Image("busybox:latest").Run(
llb.ReadonlyRootFS(),
llb.Args([]string{"/bin/sh", "-c", `echo hello`}),
)
def, err := st.Marshal(sb.Context())
if err != nil {
return nil, err
}
res, err := c.Solve(ctx, client.SolveRequest{
Definition: def.ToPB(),
FrontendOpt: map[string]string{
"build-arg:foo": fooattrval,
},
})
require.NoError(t, err)
require.Contains(t, res.Metadata, exptypes.ExporterBuildInfo)

var bi binfotypes.BuildInfo
require.NoError(t, json.Unmarshal(res.Metadata[exptypes.ExporterBuildInfo], &bi))
require.Contains(t, bi.Attrs, "build-arg:foo")
bi.Attrs["build-arg:baz"] = &bazattrval

bmbi, err := json.Marshal(bi)
require.NoError(t, err)

res.AddMeta(exptypes.ExporterBuildInfo, bmbi)
return res, err
}

res, err := c.Build(sb.Context(), SolveOpt{}, "", b, nil)
require.NoError(t, err)

require.Contains(t, res.ExporterResponse, exptypes.ExporterBuildInfo)
decbi, err := base64.StdEncoding.DecodeString(res.ExporterResponse[exptypes.ExporterBuildInfo])
require.NoError(t, err)

var bi binfotypes.BuildInfo
require.NoError(t, json.Unmarshal(decbi, &bi))

require.Contains(t, bi.Attrs, "build-arg:foo")
require.Equal(t, &fooattrval, bi.Attrs["build-arg:foo"])
require.Contains(t, bi.Attrs, "build-arg:baz")
require.Equal(t, &bazattrval, bi.Attrs["build-arg:baz"])

checkAllReleasable(t, c, sb, true)
}

func testClientGatewayNilResult(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
c, err := New(sb.Context(), sb.Address())
Expand Down
90 changes: 30 additions & 60 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6199,8 +6199,7 @@ func testBuildInfoExporter(t *testing.T, sb integration.Sandbox) {
return nil, err
}
return c.Solve(ctx, gateway.SolveRequest{
Definition: def.ToPB(),
FrontendOpt: map[string]string{"build-arg:foo": "bar"},
Definition: def.ToPB(),
})
}

Expand Down Expand Up @@ -6233,8 +6232,6 @@ func testBuildInfoExporter(t *testing.T, sb integration.Sandbox) {
err = json.Unmarshal(decbi, &exbi)
require.NoError(t, err)

attrval := "bar"
require.Equal(t, exbi.Attrs, map[string]*string{"build-arg:foo": &attrval})
require.Equal(t, len(exbi.Sources), 1)
require.Equal(t, exbi.Sources[0].Type, binfotypes.SourceTypeDockerImage)
require.Equal(t, exbi.Sources[0].Ref, "docker.io/library/busybox:latest")
Expand Down Expand Up @@ -6271,66 +6268,42 @@ func testBuildInfoInline(t *testing.T, sb integration.Sandbox) {

ctx := namespaces.WithNamespace(sb.Context(), "buildkit")

for _, tt := range []struct {
name string
buildAttrs bool
}{{
"attrsEnabled",
true,
}, {
"attrsDisabled",
false,
}} {
t.Run(tt.name, func(t *testing.T) {
target := registry + "/buildkit/test-buildinfo:latest"

_, err = c.Solve(sb.Context(), def, SolveOpt{
Exports: []ExportEntry{
{
Type: ExporterImage,
Attrs: map[string]string{
"name": target,
"push": "true",
"buildinfo-attrs": strconv.FormatBool(tt.buildAttrs),
},
},
},
FrontendAttrs: map[string]string{
"build-arg:foo": "bar",
target := registry + "/buildkit/test-buildinfo:latest"

_, err = c.Solve(sb.Context(), def, SolveOpt{
Exports: []ExportEntry{
{
Type: ExporterImage,
Attrs: map[string]string{
"name": target,
"push": "true",
},
}, nil)
require.NoError(t, err)
},
},
}, nil)
require.NoError(t, err)

img, err := client.GetImage(ctx, target)
require.NoError(t, err)
img, err := client.GetImage(ctx, target)
require.NoError(t, err)

desc, err := img.Config(ctx)
require.NoError(t, err)
desc, err := img.Config(ctx)
require.NoError(t, err)

dt, err := content.ReadBlob(ctx, img.ContentStore(), desc)
require.NoError(t, err)
dt, err := content.ReadBlob(ctx, img.ContentStore(), desc)
require.NoError(t, err)

var config binfotypes.ImageConfig
require.NoError(t, json.Unmarshal(dt, &config))
var config binfotypes.ImageConfig
require.NoError(t, json.Unmarshal(dt, &config))

dec, err := base64.StdEncoding.DecodeString(config.BuildInfo)
require.NoError(t, err)
dec, err := base64.StdEncoding.DecodeString(config.BuildInfo)
require.NoError(t, err)

var bi binfotypes.BuildInfo
require.NoError(t, json.Unmarshal(dec, &bi))
var bi binfotypes.BuildInfo
require.NoError(t, json.Unmarshal(dec, &bi))

if tt.buildAttrs {
attrval := "bar"
require.Contains(t, bi.Attrs, "build-arg:foo")
require.Equal(t, bi.Attrs["build-arg:foo"], &attrval)
} else {
require.NotContains(t, bi.Attrs, "build-arg:foo")
}
require.Equal(t, len(bi.Sources), 1)
require.Equal(t, bi.Sources[0].Type, binfotypes.SourceTypeDockerImage)
require.Equal(t, bi.Sources[0].Ref, "docker.io/library/busybox:latest")
})
}
require.Equal(t, len(bi.Sources), 1)
require.Equal(t, bi.Sources[0].Type, binfotypes.SourceTypeDockerImage)
require.Equal(t, bi.Sources[0].Ref, "docker.io/library/busybox:latest")
}

func testBuildInfoNoExport(t *testing.T, sb integration.Sandbox) {
Expand All @@ -6348,8 +6321,7 @@ func testBuildInfoNoExport(t *testing.T, sb integration.Sandbox) {
return nil, err
}
return c.Solve(ctx, gateway.SolveRequest{
Definition: def.ToPB(),
FrontendOpt: map[string]string{"build-arg:foo": "bar"},
Definition: def.ToPB(),
})
}

Expand All @@ -6364,8 +6336,6 @@ func testBuildInfoNoExport(t *testing.T, sb integration.Sandbox) {
err = json.Unmarshal(decbi, &exbi)
require.NoError(t, err)

attrval := "bar"
require.Equal(t, exbi.Attrs, map[string]*string{"build-arg:foo": &attrval})
require.Equal(t, len(exbi.Sources), 1)
require.Equal(t, exbi.Sources[0].Type, binfotypes.SourceTypeDockerImage)
require.Equal(t, exbi.Sources[0].Ref, "docker.io/library/busybox:latest")
Expand Down
15 changes: 14 additions & 1 deletion cmd/buildctl/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,13 +277,26 @@ func buildAction(clicontext *cli.Context) error {
close(w.Status())
}
}()

solveAttr := map[string]string{}
frontendAttr := map[string]string{}
for k, v := range solveOpt.FrontendAttrs {
if strings.HasPrefix(k, "attest:") || strings.HasPrefix(k, "build-arg:BUILDKIT_ATTEST_") {
frontendAttr[k] = v
} else {
solveAttr[k] = v
}
}

sreq := gateway.SolveRequest{
Frontend: solveOpt.Frontend,
FrontendOpt: solveOpt.FrontendAttrs,
FrontendOpt: solveAttr,
}
if def != nil {
sreq.Definition = def.ToPB()
}
solveOpt.Frontend = ""
solveOpt.FrontendAttrs = frontendAttr

resp, err := c.Build(ctx, solveOpt, "buildctl", func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
_, isSubRequest := sreq.FrontendOpt["requestid"]
Expand Down
11 changes: 10 additions & 1 deletion control/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,11 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
}

var procs []llbsolver.Processor

if len(attests) > 0 {
procs = append(procs, proc.ForceRefsProcessor)
}

if attrs, ok := attests["sbom"]; ok {
src := attrs["generator"]
if src == "" {
Expand All @@ -340,7 +345,11 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
return nil, errors.Wrapf(err, "failed to parse sbom generator %s", src)
}
ref = reference.TagNameOnly(ref)
procs = append(procs, proc.ForceRefsProcessor, proc.SBOMProcessor(ref.String()))
procs = append(procs, proc.SBOMProcessor(ref.String()))
}

if attrs, ok := attests["provenance"]; ok {
procs = append(procs, proc.ProvenanceProcessor(attrs))
}

resp, err := c.solver.Solve(ctx, req.Ref, req.Session, frontend.SolveRequest{
Expand Down
7 changes: 1 addition & 6 deletions examples/dockerfile2llb/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func xmain() error {

caps := pb.Caps.CapSet(pb.Caps.All())

state, img, bi, err := dockerfile2llb.Dockerfile2LLB(appcontext.Context(), df, dockerfile2llb.ConvertOpt{
state, img, err := dockerfile2llb.Dockerfile2LLB(appcontext.Context(), df, dockerfile2llb.ConvertOpt{
MetaResolver: imagemetaresolver.Default(),
Target: opt.target,
LLBCaps: &caps,
Expand All @@ -62,11 +62,6 @@ func xmain() error {
return err
}
}
if opt.partialMetadataFile != "" {
if err := writeJSON(opt.partialMetadataFile, bi); err != nil {
return err
}
}
return nil
}

Expand Down
Loading

0 comments on commit abae584

Please sign in to comment.