Skip to content

Commit

Permalink
Merge pull request #3342 from jedevc/attestation-metadata
Browse files Browse the repository at this point in the history
Introduce attestation metadata
  • Loading branch information
jedevc authored Dec 7, 2022
2 parents 9bf3605 + 8e107a6 commit d32cb4a
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 12 deletions.
45 changes: 45 additions & 0 deletions exporter/attestation/filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package attestation

import (
"bytes"

"github.com/moby/buildkit/solver/result"
)

func Filter(attestations []result.Attestation, include map[string][]byte, exclude map[string][]byte) []result.Attestation {
if len(include) == 0 && len(exclude) == 0 {
return attestations
}

result := []result.Attestation{}
for _, att := range attestations {
meta := att.Metadata
if meta == nil {
meta = map[string][]byte{}
}

match := true
for k, v := range include {
if !bytes.Equal(meta[k], v) {
match = false
break
}
}
if !match {
continue
}

for k, v := range exclude {
if bytes.Equal(meta[k], v) {
match = false
break
}
}
if !match {
continue
}

result = append(result, att)
}
return result
}
4 changes: 4 additions & 0 deletions exporter/local/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io/fs"
"os"
"path"
"strconv"
"time"

"github.com/docker/docker/pkg/idtools"
Expand Down Expand Up @@ -87,6 +88,9 @@ func CreateFS(ctx context.Context, sessionID string, k string, ref cache.Immutab
}

outputFS := fsutil.NewFS(src, walkOpt)
attestations = attestation.Filter(attestations, nil, map[string][]byte{
result.AttestationInlineOnlyKey: []byte(strconv.FormatBool(true)),
})
attestations, err = attestation.Unbundle(ctx, session.NewGroup(sessionID), refs, attestations)
if err != nil {
return nil, nil, err
Expand Down
3 changes: 3 additions & 0 deletions frontend/attestations/sbom/sbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ func CreateSBOMScanner(ctx context.Context, resolver llb.ImageMetaResolver, scan
stsbom := runscan.AddMount(outDir, llb.Scratch())
return result.Attestation{
Kind: gatewaypb.AttestationKindBundle,
Metadata: map[string][]byte{
result.AttestationReasonKey: result.AttestationReasonSBOM,
},
InToto: result.InTotoAttestation{
PredicateType: intoto.PredicateSPDX,
},
Expand Down
20 changes: 13 additions & 7 deletions frontend/dockerfile/dockerfile_provenance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,18 @@ RUN echo "ok" > /foo
)
require.NoError(t, err)

for _, mode := range []string{"min", "max"} {
for _, mode := range []string{"", "min", "max"} {
t.Run(mode, func(t *testing.T) {
target := registry + "/buildkit/testwithprovenance:" + mode
var target string
if target == "" {
target = registry + "/buildkit/testwithprovenance:none"
} else {
target = registry + "/buildkit/testwithprovenance:" + mode
}

provReq := ""
if mode == "max" {
provReq = "mode=max"
if mode != "" {
provReq = "mode=" + mode
}
_, err = f.Solve(sb.Context(), c, client.SolveOpt{
LocalDirs: map[string]string{
Expand Down Expand Up @@ -130,7 +136,7 @@ RUN echo "ok" > /foo
} else if isGateway {
require.Equal(t, "gateway.v0", pred.Invocation.Parameters.Frontend)

if mode == "max" {
if mode == "max" || mode == "" {
require.Equal(t, 3, len(args), "%v", args)
require.True(t, pred.Metadata.Completeness.Parameters)

Expand All @@ -145,7 +151,7 @@ RUN echo "ok" > /foo
} else {
require.Equal(t, "dockerfile.v0", pred.Invocation.Parameters.Frontend)

if mode == "max" {
if mode == "max" || mode == "" {
require.Equal(t, 2, len(args))
require.True(t, pred.Metadata.Completeness.Parameters)

Expand Down Expand Up @@ -194,7 +200,7 @@ RUN echo "ok" > /foo
require.False(t, pred.Metadata.Reproducible)
require.False(t, pred.Metadata.Completeness.Hermetic)

if mode == "max" {
if mode == "max" || mode == "" {
require.Equal(t, 2, len(pred.Metadata.BuildKitMetadata.Layers))
require.NotNil(t, pred.Metadata.BuildKitMetadata.Source)
require.Equal(t, "Dockerfile", pred.Metadata.BuildKitMetadata.Source.Infos[0].Filename)
Expand Down
20 changes: 15 additions & 5 deletions solver/llbsolver/proc/provenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,9 @@ func ProvenanceProcessor(attrs map[string]string) llbsolver.Processor {
reproducible = b
}

var mode string
mode := "max"
if v, ok := attrs["mode"]; ok {
switch v {
case "disabled", "none":
return res, nil
case "full":
mode = "max"
case "max", "min":
Expand All @@ -68,6 +66,11 @@ func ProvenanceProcessor(attrs map[string]string) llbsolver.Processor {
}
}

var inlineOnly bool
if v, err := strconv.ParseBool(attrs["inline-only"]); v && err == nil {
inlineOnly = true
}

for _, p := range ps.Platforms {
cp, ok := res.Provenance.Refs[p.ID]
if !ok {
Expand All @@ -87,7 +90,8 @@ func ProvenanceProcessor(attrs map[string]string) llbsolver.Processor {

var addLayers func() error

if mode != "max" {
switch mode {
case "min":
args := make(map[string]string)
for k, v := range pr.Invocation.Parameters.Args {
if strings.HasPrefix(k, "build-arg:") || strings.HasPrefix(k, "label:") {
Expand All @@ -99,7 +103,7 @@ func ProvenanceProcessor(attrs map[string]string) llbsolver.Processor {
pr.Invocation.Parameters.Args = args
pr.Invocation.Parameters.Secrets = nil
pr.Invocation.Parameters.SSH = nil
} else {
case "max":
dgsts, err := provenance.AddBuildConfig(ctx, pr, res.Refs[p.ID])
if err != nil {
return nil, err
Expand Down Expand Up @@ -141,10 +145,16 @@ func ProvenanceProcessor(attrs map[string]string) llbsolver.Processor {

return nil
}
default:
return nil, errors.Errorf("invalid mode %q", mode)
}

res.AddAttestation(p.ID, result.Attestation{
Kind: gatewaypb.AttestationKindInToto,
Metadata: map[string][]byte{
result.AttestationReasonKey: result.AttestationReasonProvenance,
result.AttestationInlineOnlyKey: []byte(strconv.FormatBool(inlineOnly)),
},
InToto: result.InTotoAttestation{
PredicateType: slsa.PredicateSLSAProvenance,
},
Expand Down
12 changes: 12 additions & 0 deletions solver/result/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,21 @@ import (
digest "github.com/opencontainers/go-digest"
)

const (
AttestationReasonKey = "reason"
AttestationInlineOnlyKey = "inline-only"
)

var (
AttestationReasonSBOM = []byte("sbom")
AttestationReasonProvenance = []byte("provenance")
)

type Attestation struct {
Kind pb.AttestationKind

Metadata map[string][]byte

Ref string
Path string
ContentFunc func() ([]byte, error)
Expand Down

0 comments on commit d32cb4a

Please sign in to comment.