mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 09:17:49 +08:00
inspect: lazily load attestation data
Delay loading the attestation data immediately, and only compute it upon request. We do this using a deferred function which allows to define the computation in the same place as before, but perform the computation later. With this patch, we ensure that the attestation data is only pulled from the remote if it is actually referenced in the format string - otherwise, we can skip it, for improved performance. Signed-off-by: Justin Chadwell <me@jedevc.com>
This commit is contained in:
parent
19291d900e
commit
78d8b926db
@ -49,6 +49,9 @@ type asset struct {
|
|||||||
config *ocispec.Image
|
config *ocispec.Image
|
||||||
sbom *sbomStub
|
sbom *sbomStub
|
||||||
provenance *provenanceStub
|
provenance *provenanceStub
|
||||||
|
|
||||||
|
deferredSbom func() (*sbomStub, error)
|
||||||
|
deferredProvenance func() (*provenanceStub, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type result struct {
|
type result struct {
|
||||||
@ -261,36 +264,40 @@ 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 = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.in-toto+json", "intoto")
|
||||||
for _, dgst := range refs {
|
as.deferredSbom = func() (*sbomStub, error) {
|
||||||
mfst, ok := r.manifests[dgst]
|
var sbom *sbomStub
|
||||||
if !ok {
|
for _, dgst := range refs {
|
||||||
return errors.Errorf("referenced image %s not found", dgst)
|
mfst, ok := r.manifests[dgst]
|
||||||
}
|
if !ok {
|
||||||
for _, layer := range mfst.manifest.Layers {
|
return nil, errors.Errorf("referenced image %s not found", dgst)
|
||||||
if layer.MediaType == "application/vnd.in-toto+json" && layer.Annotations["in-toto.io/predicate-type"] == "https://spdx.dev/Document" {
|
}
|
||||||
_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, layer)
|
for _, layer := range mfst.manifest.Layers {
|
||||||
if err != nil {
|
if layer.MediaType == "application/vnd.in-toto+json" && layer.Annotations["in-toto.io/predicate-type"] == "https://spdx.dev/Document" {
|
||||||
return err
|
_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, layer)
|
||||||
}
|
if err != nil {
|
||||||
dt, err := content.ReadBlob(ctx, l.cache, layer)
|
return nil, err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
dt, err := content.ReadBlob(ctx, l.cache, layer)
|
||||||
}
|
if err != nil {
|
||||||
var spdx struct {
|
return nil, err
|
||||||
Predicate interface{} `json:"predicate"`
|
}
|
||||||
}
|
var spdx struct {
|
||||||
if err := json.Unmarshal(dt, &spdx); err != nil {
|
Predicate interface{} `json:"predicate"`
|
||||||
return err
|
}
|
||||||
}
|
if err := json.Unmarshal(dt, &spdx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if as.sbom == nil {
|
if sbom == nil {
|
||||||
as.sbom = &sbomStub{}
|
sbom = &sbomStub{}
|
||||||
as.sbom.SPDX = spdx.Predicate
|
sbom.SPDX = spdx.Predicate
|
||||||
} else {
|
} else {
|
||||||
as.sbom.AdditionalSPDXs = append(as.sbom.AdditionalSPDXs, spdx.Predicate)
|
sbom.AdditionalSPDXs = append(sbom.AdditionalSPDXs, spdx.Predicate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return sbom, nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -301,33 +308,37 @@ 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 = remotes.WithMediaTypeKeyPrefix(ctx, "application/vnd.in-toto+json", "intoto")
|
||||||
for _, dgst := range refs {
|
as.deferredProvenance = func() (*provenanceStub, error) {
|
||||||
mfst, ok := r.manifests[dgst]
|
var provenance *provenanceStub
|
||||||
if !ok {
|
for _, dgst := range refs {
|
||||||
return errors.Errorf("referenced image %s not found", dgst)
|
mfst, ok := r.manifests[dgst]
|
||||||
}
|
if !ok {
|
||||||
for _, layer := range mfst.manifest.Layers {
|
return nil, errors.Errorf("referenced image %s not found", dgst)
|
||||||
if layer.MediaType == "application/vnd.in-toto+json" && strings.HasPrefix(layer.Annotations["in-toto.io/predicate-type"], "https://slsa.dev/provenance/") {
|
}
|
||||||
_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, layer)
|
for _, layer := range mfst.manifest.Layers {
|
||||||
if err != nil {
|
if layer.MediaType == "application/vnd.in-toto+json" && strings.HasPrefix(layer.Annotations["in-toto.io/predicate-type"], "https://slsa.dev/provenance/") {
|
||||||
return err
|
_, err := remotes.FetchHandler(l.cache, fetcher)(ctx, layer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dt, err := content.ReadBlob(ctx, l.cache, layer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var slsa struct {
|
||||||
|
Predicate interface{} `json:"predicate"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(dt, &slsa); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
provenance = &provenanceStub{
|
||||||
|
SLSA: slsa.Predicate,
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
dt, err := content.ReadBlob(ctx, l.cache, layer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var slsa struct {
|
|
||||||
Predicate interface{} `json:"predicate"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(dt, &slsa); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
as.provenance = &provenanceStub{
|
|
||||||
SLSA: slsa.Predicate,
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return provenance, nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -346,30 +357,50 @@ func (r *result) Configs() map[string]*ocispec.Image {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *result) Provenance() map[string]provenanceStub {
|
func (r *result) Provenance() (map[string]provenanceStub, error) {
|
||||||
if len(r.assets) == 0 {
|
if len(r.assets) == 0 {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
res := make(map[string]provenanceStub)
|
res := make(map[string]provenanceStub)
|
||||||
for p, a := range r.assets {
|
for p, a := range r.assets {
|
||||||
if a.provenance == nil {
|
if a.deferredProvenance == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if a.provenance == nil {
|
||||||
|
provenance, err := a.deferredProvenance()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if provenance == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
a.provenance = provenance
|
||||||
|
}
|
||||||
res[p] = *a.provenance
|
res[p] = *a.provenance
|
||||||
}
|
}
|
||||||
return res
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *result) SBOM() map[string]sbomStub {
|
func (r *result) SBOM() (map[string]sbomStub, error) {
|
||||||
if len(r.assets) == 0 {
|
if len(r.assets) == 0 {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
res := make(map[string]sbomStub)
|
res := make(map[string]sbomStub)
|
||||||
for p, a := range r.assets {
|
for p, a := range r.assets {
|
||||||
if a.sbom == nil {
|
if a.deferredSbom == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if a.sbom == nil {
|
||||||
|
sbom, err := a.deferredSbom()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if sbom == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
a.sbom = sbom
|
||||||
|
}
|
||||||
res[p] = *a.sbom
|
res[p] = *a.sbom
|
||||||
}
|
}
|
||||||
return res
|
return res, nil
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,10 @@ type tplInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (inp tplInput) SBOM() (sbomStub, error) {
|
func (inp tplInput) SBOM() (sbomStub, error) {
|
||||||
sbom := inp.result.SBOM()
|
sbom, err := inp.result.SBOM()
|
||||||
|
if err != nil {
|
||||||
|
return sbomStub{}, nil
|
||||||
|
}
|
||||||
for _, v := range sbom {
|
for _, v := range sbom {
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
@ -221,7 +224,10 @@ func (inp tplInput) SBOM() (sbomStub, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (inp tplInput) Provenance() (provenanceStub, error) {
|
func (inp tplInput) Provenance() (provenanceStub, error) {
|
||||||
provenance := inp.result.Provenance()
|
provenance, err := inp.result.Provenance()
|
||||||
|
if err != nil {
|
||||||
|
return provenanceStub{}, nil
|
||||||
|
}
|
||||||
for _, v := range provenance {
|
for _, v := range provenance {
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
@ -237,9 +243,9 @@ type tplInputs struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (inp tplInputs) SBOM() (map[string]sbomStub, error) {
|
func (inp tplInputs) SBOM() (map[string]sbomStub, error) {
|
||||||
return inp.result.SBOM(), nil
|
return inp.result.SBOM()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inp tplInputs) Provenance() (map[string]provenanceStub, error) {
|
func (inp tplInputs) Provenance() (map[string]provenanceStub, error) {
|
||||||
return inp.result.Provenance(), nil
|
return inp.result.Provenance()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user