-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3258 from jedevc/sbom-filelist
Supplement generated SBOMs with layer information post-build
- Loading branch information
Showing
49 changed files
with
4,346 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package cache | ||
|
||
import ( | ||
"archive/tar" | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"path" | ||
"sort" | ||
|
||
cdcompression "github.com/containerd/containerd/archive/compression" | ||
"github.com/moby/buildkit/session" | ||
) | ||
|
||
const keyFileList = "filelist" | ||
|
||
// FileList returns an ordered list of files present in the cache record that were | ||
// changed compared to the parent. The paths of the files are in same format as they | ||
// are in the tar stream (AUFS whiteout format). If the reference does not have a | ||
// a blob associated with it, the list is empty. | ||
func (sr *immutableRef) FileList(ctx context.Context, s session.Group) ([]string, error) { | ||
res, err := g.Do(ctx, fmt.Sprintf("filelist-%s", sr.ID()), func(ctx context.Context) (interface{}, error) { | ||
dt, err := sr.GetExternal(keyFileList) | ||
if err == nil && dt != nil { | ||
var files []string | ||
if err := json.Unmarshal(dt, &files); err != nil { | ||
return nil, err | ||
} | ||
return files, nil | ||
} | ||
|
||
if sr.getBlob() == "" { | ||
return nil, nil | ||
} | ||
|
||
// lazy blobs need to be pulled first | ||
if err := sr.Extract(ctx, s); err != nil { | ||
return nil, err | ||
} | ||
|
||
desc, err := sr.ociDesc(ctx, sr.descHandlers, false) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
ra, err := sr.cm.ContentStore.ReaderAt(ctx, desc) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
r, err := cdcompression.DecompressStream(io.NewSectionReader(ra, 0, ra.Size())) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer r.Close() | ||
|
||
var files []string | ||
|
||
rdr := tar.NewReader(r) | ||
for { | ||
hdr, err := rdr.Next() | ||
if err == io.EOF { | ||
break | ||
} | ||
if err != nil { | ||
return nil, err | ||
} | ||
name := path.Clean(hdr.Name) | ||
files = append(files, name) | ||
} | ||
sort.Strings(files) | ||
|
||
dt, err = json.Marshal(files) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if err := sr.SetExternal(keyFileList, dt); err != nil { | ||
return nil, err | ||
} | ||
return files, nil | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if res == nil { | ||
return nil, nil | ||
} | ||
return res.([]string), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package attestation | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"os" | ||
|
||
"github.com/containerd/continuity/fs" | ||
intoto "github.com/in-toto/in-toto-golang/in_toto" | ||
"github.com/moby/buildkit/cache" | ||
gatewaypb "github.com/moby/buildkit/frontend/gateway/pb" | ||
"github.com/moby/buildkit/session" | ||
"github.com/moby/buildkit/snapshot" | ||
"github.com/moby/buildkit/solver/result" | ||
"github.com/pkg/errors" | ||
"golang.org/x/sync/errgroup" | ||
) | ||
|
||
// ReadAll reads the content of an attestation. | ||
func ReadAll(ctx context.Context, s session.Group, refs map[string]cache.ImmutableRef, att result.Attestation) ([]byte, error) { | ||
var content []byte | ||
if att.ContentFunc != nil { | ||
data, err := att.ContentFunc() | ||
if err != nil { | ||
return nil, err | ||
} | ||
content = data | ||
} else { | ||
if refs == nil { | ||
return nil, errors.Errorf("no refs map provided to lookup attestation keys") | ||
} | ||
ref, ok := refs[att.Ref] | ||
if !ok { | ||
return nil, errors.Errorf("key %s not found in refs map", att.Ref) | ||
} | ||
mount, err := ref.Mount(ctx, true, s) | ||
if err != nil { | ||
return nil, err | ||
} | ||
lm := snapshot.LocalMounter(mount) | ||
src, err := lm.Mount() | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer lm.Unmount() | ||
|
||
p, err := fs.RootPath(src, att.Path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
content, err = os.ReadFile(p) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "cannot read in-toto attestation") | ||
} | ||
} | ||
if len(content) == 0 { | ||
content = nil | ||
} | ||
return content, nil | ||
} | ||
|
||
// MakeInTotoStatements iterates over all provided result attestations and | ||
// generates intoto attestation statements. | ||
func MakeInTotoStatements(ctx context.Context, s session.Group, refs map[string]cache.ImmutableRef, attestations []result.Attestation, defaultSubjects []intoto.Subject) ([]intoto.Statement, error) { | ||
eg, ctx := errgroup.WithContext(ctx) | ||
statements := make([]intoto.Statement, len(attestations)) | ||
|
||
for i, att := range attestations { | ||
i, att := i, att | ||
eg.Go(func() error { | ||
content, err := ReadAll(ctx, s, refs, att) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
switch att.Kind { | ||
case gatewaypb.AttestationKindInToto: | ||
stmt, err := makeInTotoStatement(ctx, content, att, defaultSubjects) | ||
if err != nil { | ||
return err | ||
} | ||
statements[i] = *stmt | ||
case gatewaypb.AttestationKindBundle: | ||
return errors.New("bundle attestation kind must be un-bundled first") | ||
} | ||
return nil | ||
}) | ||
} | ||
if err := eg.Wait(); err != nil { | ||
return nil, err | ||
} | ||
return statements, nil | ||
} | ||
|
||
func makeInTotoStatement(ctx context.Context, content []byte, attestation result.Attestation, defaultSubjects []intoto.Subject) (*intoto.Statement, error) { | ||
if len(attestation.InToto.Subjects) == 0 { | ||
attestation.InToto.Subjects = []result.InTotoSubject{{ | ||
Kind: gatewaypb.InTotoSubjectKindSelf, | ||
}} | ||
} | ||
subjects := []intoto.Subject{} | ||
for _, subject := range attestation.InToto.Subjects { | ||
subjectName := "_" | ||
if subject.Name != "" { | ||
subjectName = subject.Name | ||
} | ||
|
||
switch subject.Kind { | ||
case gatewaypb.InTotoSubjectKindSelf: | ||
for _, defaultSubject := range defaultSubjects { | ||
subjectNames := []string{} | ||
subjectNames = append(subjectNames, defaultSubject.Name) | ||
if subjectName != "_" { | ||
subjectNames = append(subjectNames, subjectName) | ||
} | ||
|
||
for _, name := range subjectNames { | ||
subjects = append(subjects, intoto.Subject{ | ||
Name: name, | ||
Digest: defaultSubject.Digest, | ||
}) | ||
} | ||
} | ||
case gatewaypb.InTotoSubjectKindRaw: | ||
subjects = append(subjects, intoto.Subject{ | ||
Name: subjectName, | ||
Digest: result.ToDigestMap(subject.Digest...), | ||
}) | ||
default: | ||
return nil, errors.Errorf("unknown attestation subject type %T", subject) | ||
} | ||
} | ||
|
||
stmt := intoto.Statement{ | ||
StatementHeader: intoto.StatementHeader{ | ||
Type: intoto.StatementInTotoV01, | ||
PredicateType: attestation.InToto.PredicateType, | ||
Subject: subjects, | ||
}, | ||
Predicate: json.RawMessage(content), | ||
} | ||
return &stmt, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.