mirror of
https://github.com/anchore/syft.git
synced 2026-10-30 22:12:28 +01:00
The image source provider now reads images with `image.WithLazyLayerSquashes`: the image squash is built during the read, and each lower layer's squash only when something reads it. A squashed scan never does, so it skips a full file tree copy per layer. - squashed scans: faster, much less memory on images with many layers - `scan`/`attest` with all-layers or deep-squashed stay eager (an internal ctx flag), since eager squashing overlaps with fetching and indexing and is faster when every layer gets read - library callers going through `syft.GetSource` get lazy for every scope, since the scope isn't known when the image is read. All-layers is still correct, just slower - no public API change Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
77 lines
2.5 KiB
Go
77 lines
2.5 KiB
Go
package stereoscopesource
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/google/go-containerregistry/pkg/name"
|
|
"github.com/google/go-containerregistry/pkg/v1/random"
|
|
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/anchore/stereoscope"
|
|
"github.com/anchore/stereoscope/pkg/filetree"
|
|
"github.com/anchore/stereoscope/pkg/image"
|
|
"github.com/anchore/syft/internal"
|
|
"github.com/anchore/syft/syft/source"
|
|
)
|
|
|
|
func Test_stereoscopeImageSourceProvider_layerSquashes(t *testing.T) {
|
|
img, err := random.Image(1024, 3)
|
|
require.NoError(t, err)
|
|
tag, err := name.NewTag("localhost/layer-squashes:latest")
|
|
require.NoError(t, err)
|
|
archive := filepath.Join(t.TempDir(), "image.tar")
|
|
require.NoError(t, tarball.WriteToFile(archive, tag, img))
|
|
|
|
provide := func(t *testing.T, ctx context.Context) *stereoscopeImageSource {
|
|
providers := Providers(ProviderConfig{
|
|
StereoscopeImageProviderConfig: stereoscope.ImageProviderConfig{UserInput: archive},
|
|
})
|
|
for _, p := range providers {
|
|
if p.Value.Name() != image.DockerTarballSource {
|
|
continue
|
|
}
|
|
src, err := p.Value.Provide(ctx)
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { require.NoError(t, src.Close()) })
|
|
return src.(*stereoscopeImageSource)
|
|
}
|
|
t.Fatalf("no %s provider", image.DockerTarballSource)
|
|
return nil
|
|
}
|
|
|
|
lazy := provide(t, context.Background())
|
|
eager := provide(t, internal.WithEagerLayerSquashes(context.Background()))
|
|
|
|
// lower layers are built on first use unless eager was asked for, the top is the image squash either way
|
|
require.Len(t, lazy.image.Layers, 3)
|
|
for idx := range lazy.image.Layers {
|
|
_, isTree := lazy.image.Layers[idx].SquashedTree.(*filetree.FileTree)
|
|
assert.Equalf(t, idx == 2, isTree, "lazy layer %d", idx)
|
|
assert.IsTypef(t, &filetree.FileTree{}, eager.image.Layers[idx].SquashedTree, "eager layer %d", idx)
|
|
}
|
|
|
|
// every scope sees the same files either way
|
|
for _, scope := range []source.Scope{source.SquashedScope, source.AllLayersScope, source.DeepSquashedScope} {
|
|
t.Run(string(scope), func(t *testing.T) {
|
|
files := func(src *stereoscopeImageSource) []string {
|
|
res, err := src.FileResolver(scope)
|
|
require.NoError(t, err)
|
|
locs, err := res.FilesByGlob("**/*")
|
|
require.NoError(t, err)
|
|
var out []string
|
|
for _, l := range locs {
|
|
out = append(out, l.RealPath+"@"+l.FileSystemID)
|
|
}
|
|
return out
|
|
}
|
|
want := files(eager)
|
|
require.NotEmpty(t, want)
|
|
assert.ElementsMatch(t, want, files(lazy))
|
|
})
|
|
}
|
|
}
|