diff --git a/indexer/controller/coalesce.go b/indexer/controller/coalesce.go index d7c1e0afc..95af0fc41 100644 --- a/indexer/controller/coalesce.go +++ b/indexer/controller/coalesce.go @@ -128,7 +128,7 @@ func MergeSR(source *claircore.IndexReport, merge []*claircore.IndexReport) *cla } for k, v := range ir.Files { - source.Files[k] = v + source.Files[k] = append(source.Files[k], v...) } } return source diff --git a/indexer/controller/controller.go b/indexer/controller/controller.go index a39103582..a37b6b51e 100644 --- a/indexer/controller/controller.go +++ b/indexer/controller/controller.go @@ -41,7 +41,7 @@ func New(options *indexer.Options) *Controller { Environments: map[string][]*claircore.Environment{}, Distributions: map[string]*claircore.Distribution{}, Repositories: map[string]*claircore.Repository{}, - Files: map[string]claircore.File{}, + Files: map[string][]claircore.File{}, } s := &Controller{ diff --git a/indexreport.go b/indexreport.go index cf3e8ba37..4e7628e3c 100644 --- a/indexreport.go +++ b/indexreport.go @@ -34,7 +34,7 @@ type IndexReport struct { // an error string in the case the index did not succeed Err string `json:"err"` // Files doesn't end up in the json report but needs to be available at post-coalesce - Files map[string]File `json:"-"` + Files map[string][]File `json:"-"` } // IndexRecords returns a list of IndexRecords derived from the IndexReport diff --git a/whiteout/coalescer.go b/whiteout/coalescer.go index 0e7a3cac0..4e2c5fba5 100644 --- a/whiteout/coalescer.go +++ b/whiteout/coalescer.go @@ -14,9 +14,9 @@ func (c *coalescer) Coalesce(ctx context.Context, layerArtifacts []*indexer.Laye for _, l := range layerArtifacts { for _, f := range l.Files { if ir.Files == nil { - ir.Files = make(map[string]claircore.File) + ir.Files = make(map[string][]claircore.File) } - ir.Files[l.Hash.String()] = f + ir.Files[l.Hash.String()] = append(ir.Files[l.Hash.String()], f) } } return ir, nil diff --git a/whiteout/resolver.go b/whiteout/resolver.go index d98cac5f1..e05f42ea0 100644 --- a/whiteout/resolver.go +++ b/whiteout/resolver.go @@ -32,19 +32,21 @@ func (r *Resolver) Resolve(ctx context.Context, ir *claircore.IndexReport, layer packageLayer = ir.Environments[pkgID][i].IntroducedIn.String() } } - for fileLayer, f := range ir.Files { - // Check if it's a whiteout file, if it applies to the package's - // filepath and if the layer the whiteout file came from came after. - // The spec states: "Whiteout files MUST only apply to resources in - // lower/parent layers" hence why we don't check if they're in the same - // layer. - if f.Kind == claircore.FileKindWhiteout && ls.isChildOf(fileLayer, packageLayer) && fileIsDeleted(pkg.Filepath, f.Path) { - packageDeleted = true - zlog.Debug(ctx). - Str("package name", pkg.Name). - Str("package file", pkg.Filepath). - Str("whiteout file", f.Path). - Msg("package determined to be deleted") + for fileLayer, fs := range ir.Files { + for _, f := range fs { + // Check if it's a whiteout file, if it applies to the package's + // filepath and if the layer the whiteout file came from came after. + // The spec states: "Whiteout files MUST only apply to resources in + // lower/parent layers" hence why we don't check if they're in the same + // layer. + if f.Kind == claircore.FileKindWhiteout && ls.isChildOf(fileLayer, packageLayer) && fileIsDeleted(pkg.Filepath, f.Path) { + packageDeleted = true + zlog.Debug(ctx). + Str("package name", pkg.Name). + Str("package file", pkg.Filepath). + Str("whiteout file", f.Path). + Msg("package determined to be deleted") + } } } if !packageDeleted { diff --git a/whiteout/resolver_test.go b/whiteout/resolver_test.go index 0212435ad..5412c7fcf 100644 --- a/whiteout/resolver_test.go +++ b/whiteout/resolver_test.go @@ -51,10 +51,12 @@ func TestResolver(t *testing.T) { "1": {{IntroducedIn: firstLayerHash}}, "2": {{IntroducedIn: firstLayerHash}}, }, - Files: map[string]claircore.File{ + Files: map[string][]claircore.File{ secondLayerHash.String(): { - Path: "a/path/to/some/file/site-packages/.wh.a_package", - Kind: claircore.FileKindWhiteout, + { + Path: "a/path/to/some/file/site-packages/.wh.a_package", + Kind: claircore.FileKindWhiteout, + }, }, }, }, @@ -82,18 +84,20 @@ func TestResolver(t *testing.T) { "1": {{IntroducedIn: firstLayerHash}}, "2": {{IntroducedIn: firstLayerHash}}, }, - Files: map[string]claircore.File{ + Files: map[string][]claircore.File{ secondLayerHash.String(): { - Path: "a/path/to/some/different_file/site-packages/.wh.a_package", - Kind: claircore.FileKindWhiteout, - }, - secondLayerHash.String(): { - Path: "a/path/to/some/different_file/.wh.site-packages", - Kind: claircore.FileKindWhiteout, - }, - secondLayerHash.String(): { - Path: "a/path/to/some/.wh.different_file", - Kind: claircore.FileKindWhiteout, + { + Path: "a/path/to/some/different_file/site-packages/.wh.a_package", + Kind: claircore.FileKindWhiteout, + }, + { + Path: "a/path/to/some/different_file/.wh.site-packages", + Kind: claircore.FileKindWhiteout, + }, + { + Path: "a/path/to/some/.wh.different_file", + Kind: claircore.FileKindWhiteout, + }, }, }, }, @@ -121,10 +125,12 @@ func TestResolver(t *testing.T) { "1": {{IntroducedIn: firstLayerHash}}, "2": {{IntroducedIn: firstLayerHash}}, }, - Files: map[string]claircore.File{ + Files: map[string][]claircore.File{ secondLayerHash.String(): { - Path: "a/path/to/some/file/.wh.site-packages", - Kind: claircore.FileKindWhiteout, + { + Path: "a/path/to/some/file/.wh.site-packages", + Kind: claircore.FileKindWhiteout, + }, }, }, }, @@ -152,10 +158,12 @@ func TestResolver(t *testing.T) { "1": {{IntroducedIn: firstLayerHash}}, "2": {{IntroducedIn: firstLayerHash}}, }, - Files: map[string]claircore.File{ - firstLayerHash.String(): { // whiteout is in the same layer as packages - Path: "a/path/to/some/file/site-packages/.wh.b_package", - Kind: claircore.FileKindWhiteout, + Files: map[string][]claircore.File{ + firstLayerHash.String(): { + { // whiteout is in the same layer as packages + Path: "a/path/to/some/file/site-packages/.wh.b_package", + Kind: claircore.FileKindWhiteout, + }, }, }, }, @@ -183,10 +191,12 @@ func TestResolver(t *testing.T) { "1": {{IntroducedIn: firstLayerHash}}, "2": {{IntroducedIn: firstLayerHash}}, }, - Files: map[string]claircore.File{ + Files: map[string][]claircore.File{ secondLayerHash.String(): { - Path: "a/path/to/some/file/site/.wh..wh..opq", - Kind: claircore.FileKindWhiteout, + { + Path: "a/path/to/some/file/site/.wh..wh..opq", + Kind: claircore.FileKindWhiteout, + }, }, }, }, @@ -214,10 +224,12 @@ func TestResolver(t *testing.T) { "1": {{IntroducedIn: firstLayerHash}}, "2": {{IntroducedIn: firstLayerHash}}, }, - Files: map[string]claircore.File{ + Files: map[string][]claircore.File{ secondLayerHash.String(): { - Path: "a/path/to/some/file/site-packages/.wh..wh..opq", - Kind: claircore.FileKindWhiteout, + { + Path: "a/path/to/some/file/site-packages/.wh..wh..opq", + Kind: claircore.FileKindWhiteout, + }, }, }, }, @@ -240,10 +252,12 @@ func TestResolver(t *testing.T) { Environments: map[string][]*claircore.Environment{ "1": {{IntroducedIn: firstLayerHash}, {IntroducedIn: thirdLayerHash}}, }, - Files: map[string]claircore.File{ - secondLayerHash.String(): { // whiteout is sandwiched - Path: "a/path/to/some/file/site-packages/.wh.a_package", - Kind: claircore.FileKindWhiteout, + Files: map[string][]claircore.File{ + secondLayerHash.String(): { + { // whiteout is sandwiched + Path: "a/path/to/some/file/site-packages/.wh.a_package", + Kind: claircore.FileKindWhiteout, + }, }, }, }, @@ -255,6 +269,38 @@ func TestResolver(t *testing.T) { LenPackage: 1, LenEnvs: 1, }, + { + Name: "Multiple whiteout files", + Report: &claircore.IndexReport{ + Packages: map[string]*claircore.Package{ + "1": { + Name: "something interesting", + Filepath: "a/path/to/some/file/site-packages/a_package/METADATA", + }, + }, + Environments: map[string][]*claircore.Environment{ + "1": {{IntroducedIn: firstLayerHash}}, + }, + Files: map[string][]claircore.File{ + secondLayerHash.String(): { + { + Path: "a/path/to/some/file/site-packages/.wh.a_package", + Kind: claircore.FileKindWhiteout, + }, + { // non interesting whiteout + Path: "another/path/to/some/file/site-packages/.wh.a_package", + Kind: claircore.FileKindWhiteout, + }, + }, + }, + }, + Layers: []*claircore.Layer{ + {Hash: firstLayerHash}, + {Hash: secondLayerHash}, + }, + LenPackage: 0, + LenEnvs: 0, + }, } r := &Resolver{}