mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 00:47:48 +08:00
Merge pull request #2194 from LaurentGoderre/sbom-dsse
Add support for DSSE envelope for attestation in imagetools
This commit is contained in:
commit
e273a53c88
@ -4,7 +4,9 @@ package imagetools
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -21,6 +23,12 @@ import (
|
|||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
inTotoGenericMime = "application/vnd.in-toto+json"
|
||||||
|
inTotoSPDXDSSEMime = "application/vnd.in-toto.spdx+dsse"
|
||||||
|
inTotoProvenanceDSSEMime = "application/vnd.in-toto.provenance+dsse"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
annotationReferences = []string{
|
annotationReferences = []string{
|
||||||
"com.docker.reference.digest",
|
"com.docker.reference.digest",
|
||||||
@ -274,7 +282,7 @@ type sbomStub struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *loader) scanSBOM(ctx context.Context, fetcher remotes.Fetcher, r *result, refs []digest.Digest, as *asset) error {
|
func (l *loader) scanSBOM(ctx context.Context, fetcher remotes.Fetcher, r *result, refs []digest.Digest, as *asset) error {
|
||||||
ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.in-toto+json", "intoto")
|
ctx = withIntotoMediaTypes(ctx)
|
||||||
as.deferredSbom = func() (*sbomStub, error) {
|
as.deferredSbom = func() (*sbomStub, error) {
|
||||||
var sbom *sbomStub
|
var sbom *sbomStub
|
||||||
for _, dgst := range refs {
|
for _, dgst := range refs {
|
||||||
@ -283,7 +291,8 @@ func (l *loader) scanSBOM(ctx context.Context, fetcher remotes.Fetcher, r *resul
|
|||||||
return nil, errors.Errorf("referenced image %s not found", dgst)
|
return nil, errors.Errorf("referenced image %s not found", dgst)
|
||||||
}
|
}
|
||||||
for _, layer := range mfst.manifest.Layers {
|
for _, layer := range mfst.manifest.Layers {
|
||||||
if layer.MediaType == "application/vnd.in-toto+json" && layer.Annotations["in-toto.io/predicate-type"] == "https://spdx.dev/Document" {
|
if (layer.MediaType == inTotoGenericMime || isInTotoDSSE(layer.MediaType)) &&
|
||||||
|
layer.Annotations["in-toto.io/predicate-type"] == "https://spdx.dev/Document" {
|
||||||
_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, layer)
|
_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, layer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -292,6 +301,12 @@ func (l *loader) scanSBOM(ctx context.Context, fetcher remotes.Fetcher, r *resul
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dt, err = decodeDSSE(dt, layer.MediaType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var spdx struct {
|
var spdx struct {
|
||||||
Predicate interface{} `json:"predicate"`
|
Predicate interface{} `json:"predicate"`
|
||||||
}
|
}
|
||||||
@ -318,7 +333,7 @@ type provenanceStub struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *loader) scanProvenance(ctx context.Context, fetcher remotes.Fetcher, r *result, refs []digest.Digest, as *asset) error {
|
func (l *loader) scanProvenance(ctx context.Context, fetcher remotes.Fetcher, r *result, refs []digest.Digest, as *asset) error {
|
||||||
ctx = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.in-toto+json", "intoto")
|
ctx = withIntotoMediaTypes(ctx)
|
||||||
as.deferredProvenance = func() (*provenanceStub, error) {
|
as.deferredProvenance = func() (*provenanceStub, error) {
|
||||||
var provenance *provenanceStub
|
var provenance *provenanceStub
|
||||||
for _, dgst := range refs {
|
for _, dgst := range refs {
|
||||||
@ -327,7 +342,8 @@ func (l *loader) scanProvenance(ctx context.Context, fetcher remotes.Fetcher, r
|
|||||||
return nil, errors.Errorf("referenced image %s not found", dgst)
|
return nil, errors.Errorf("referenced image %s not found", dgst)
|
||||||
}
|
}
|
||||||
for _, layer := range mfst.manifest.Layers {
|
for _, layer := range mfst.manifest.Layers {
|
||||||
if layer.MediaType == "application/vnd.in-toto+json" && strings.HasPrefix(layer.Annotations["in-toto.io/predicate-type"], "https://slsa.dev/provenance/") {
|
if (layer.MediaType == inTotoGenericMime || isInTotoDSSE(layer.MediaType)) &&
|
||||||
|
strings.HasPrefix(layer.Annotations["in-toto.io/predicate-type"], "https://slsa.dev/provenance/") {
|
||||||
_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, layer)
|
_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, layer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -336,6 +352,12 @@ func (l *loader) scanProvenance(ctx context.Context, fetcher remotes.Fetcher, r
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dt, err = decodeDSSE(dt, layer.MediaType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var slsa struct {
|
var slsa struct {
|
||||||
Predicate interface{} `json:"predicate"`
|
Predicate interface{} `json:"predicate"`
|
||||||
}
|
}
|
||||||
@ -415,3 +437,36 @@ func (r *result) SBOM() (map[string]sbomStub, error) {
|
|||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isInTotoDSSE(mime string) bool {
|
||||||
|
isDSSE, _ := regexp.MatchString("application/vnd\\.in-toto\\..*\\+dsse", mime)
|
||||||
|
|
||||||
|
return isDSSE
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeDSSE(dt []byte, mime string) ([]byte, error) {
|
||||||
|
if isInTotoDSSE(mime) {
|
||||||
|
var dsse struct {
|
||||||
|
Payload string `json:"payload"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(dt, &dsse); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
decoded, err := base64.StdEncoding.DecodeString(dsse.Payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dt = decoded
|
||||||
|
}
|
||||||
|
|
||||||
|
return dt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func withIntotoMediaTypes(ctx context.Context) context.Context {
|
||||||
|
for _, mime := range []string{inTotoGenericMime, inTotoSPDXDSSEMime, inTotoProvenanceDSSEMime} {
|
||||||
|
ctx = remotes.WithMediaTypeKeyPrefix(ctx, mime, "intoto")
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user