diff --git a/layer.go b/layer.go index 502d536..d4b0050 100644 --- a/layer.go +++ b/layer.go @@ -22,6 +22,7 @@ import ( "os" "path/filepath" "reflect" + "time" "github.com/BurntSushi/toml" "github.com/heroku/color" @@ -118,7 +119,37 @@ func (l *LayerContributor) checkIfMetadataMatches(layer libcnb.Layer) (map[strin l.Logger.Debugf("Expected metadata: %+v", expected) l.Logger.Debugf("Actual metadata: %+v", layer.Metadata) - return expected, reflect.DeepEqual(expected, layer.Metadata), nil + match, err := l.Equals(expected,layer.Metadata) + if err != nil { + return map[string]interface{}{}, false, fmt.Errorf("unable to compare metadata\n%w", err) + } + return expected, match, nil +} + +func (l *LayerContributor) Equals(expectedM map[string]interface{}, layerM map[string]interface{}) (bool, error) { + if dep, ok := expectedM["dependency"].(map[string]interface{}); ok { + for k, v := range dep { + if k == "deprecation_date" { + deprecationDate := v.(time.Time).Truncate(time.Second).In(time.UTC) + dep["deprecation_date"] = deprecationDate + break + } + } + } + if dep, ok := layerM["dependency"].(map[string]interface{}); ok { + for k, v := range dep { + if k == "deprecation_date" { + deprecationDate, err := time.Parse(time.RFC3339, v.(string)) + if err != nil { + return false, fmt.Errorf("unable to parse deprecation_date %s", v.(string)) + } + deprecationDate = deprecationDate.Truncate(time.Second).In(time.UTC) + dep["deprecation_date"] = deprecationDate + break + } + } + } + return reflect.DeepEqual(expectedM, layerM), nil } func (l *LayerContributor) checkIfLayerRestored(layer libcnb.Layer) (bool, error) { diff --git a/layer_test.go b/layer_test.go index 62bf3c1..3c9d775 100644 --- a/layer_test.go +++ b/layer_test.go @@ -503,6 +503,107 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { Expect(called).To(BeFalse()) }) + it("does not call function with non-matching deprecation_date format", func() { + dependency = libpak.BuildpackDependency{ + ID: "test-id", + Name: "test-name", + Version: "1.1.1", + URI: fmt.Sprintf("%s/test-path", server.URL()), + SHA256: "576dd8416de5619ea001d9662291d62444d1292a38e96956bc4651c01f14bca1", + Stacks: []string{"test-stack"}, + Licenses: []libpak.BuildpackDependencyLicense{ + { + Type: "test-type", + URI: "test-uri", + }, + }, + CPEs: []string{"cpe:2.3:a:some:jre:11.0.2:*:*:*:*:*:*:*"}, + PURL: "pkg:generic/some-java11@11.0.2?arch=amd64", + DeprecationDate: dependency.DeprecationDate, // parsed as '2021-04-01 00:00:00 +0000 UTC' + } + dlc.ExpectedMetadata = map[string]interface{}{ "dependency":dependency} + + layer.Metadata = map[string]interface{}{ "dependency": map[string]interface{}{ + "id": dependency.ID, + "name": dependency.Name, + "version": dependency.Version, + "uri": dependency.URI, + "sha256": dependency.SHA256, + "stacks": []interface{}{dependency.Stacks[0]}, + "licenses": []map[string]interface{}{ + { + "type": dependency.Licenses[0].Type, + "uri": dependency.Licenses[0].URI, + }, + }, + "cpes": []interface{}{"cpe:2.3:a:some:jre:11.0.2:*:*:*:*:*:*:*"}, + "purl": "pkg:generic/some-java11@11.0.2?arch=amd64", + "deprecation_date": "2021-04-01T00:00:00Z", // does not match without truncation + }} + + var called bool + + _, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + defer artifact.Close() + + called = true + return layer, nil + }) + Expect(err).NotTo(HaveOccurred()) + + Expect(called).To(BeFalse()) + }) + + it("does not call function with missing deprecation_date", func() { + dependency = libpak.BuildpackDependency{ + ID: "test-id", + Name: "test-name", + Version: "1.1.1", + URI: fmt.Sprintf("%s/test-path", server.URL()), + SHA256: "576dd8416de5619ea001d9662291d62444d1292a38e96956bc4651c01f14bca1", + Stacks: []string{"test-stack"}, + Licenses: []libpak.BuildpackDependencyLicense{ + { + Type: "test-type", + URI: "test-uri", + }, + }, + CPEs: []string{"cpe:2.3:a:some:jre:11.0.2:*:*:*:*:*:*:*"}, + PURL: "pkg:generic/some-java11@11.0.2?arch=amd64", + } + dlc.ExpectedMetadata = map[string]interface{}{ "dependency":dependency} + + layer.Metadata = map[string]interface{}{ "dependency": map[string]interface{}{ + "id": dependency.ID, + "name": dependency.Name, + "version": dependency.Version, + "uri": dependency.URI, + "sha256": dependency.SHA256, + "stacks": []interface{}{dependency.Stacks[0]}, + "licenses": []map[string]interface{}{ + { + "type": dependency.Licenses[0].Type, + "uri": dependency.Licenses[0].URI, + }, + }, + "cpes": []interface{}{"cpe:2.3:a:some:jre:11.0.2:*:*:*:*:*:*:*"}, + "purl": "pkg:generic/some-java11@11.0.2?arch=amd64", + "deprecation_date": "0001-01-01T00:00:00Z", + }} + + var called bool + + _, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + defer artifact.Close() + + called = true + return layer, nil + }) + Expect(err).NotTo(HaveOccurred()) + + Expect(called).To(BeFalse()) + }) + it("returns function error", func() { server.AppendHandlers(ghttp.RespondWith(http.StatusOK, "test-fixture"))