Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: do not collate sunset paths #351

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
APP:=vervet
GO_BIN=$(shell pwd)/.bin/go

SHELL:=env PATH=$(GO_BIN):$(PATH) $(SHELL)
SHELL:=env PATH="$(GO_BIN):$(PATH)" $(SHELL)

GOCI_LINT_V?=v1.54.2

Expand Down
23 changes: 23 additions & 0 deletions internal/storage/collator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"net/url"
"sort"
"time"

"github.com/getkin/kin-openapi/openapi3"
"github.com/rs/zerolog/log"
Expand Down Expand Up @@ -99,6 +100,23 @@ func (c *Collator) Add(service string, revision ContentRevision) {
}
}

func isPathSunsetEligible(pathItem *openapi3.PathItem) bool {
currentDate := time.Now()
for _, operation := range pathItem.Operations() {
if sunsetDateStr, ok := operation.Extensions["x-snyk-sunset-eligible"]; ok {
sunsetDate, err := time.Parse("2006-01-02", sunsetDateStr.(string)[:10])
if err != nil {
log.Error().Err(err).Msg("invalid sunset date format")
continue
}
if currentDate.After(sunsetDate) {
return true
}
}
}
return false
}

// Collate processes added service revisions to collate unified versions and OpenAPI specs for each version.
func (c *Collator) Collate() (map[vervet.Version]openapi3.T, error) {
specs := make(map[vervet.Version]openapi3.T)
Expand Down Expand Up @@ -126,6 +144,11 @@ func (c *Collator) Collate() (map[vervet.Version]openapi3.T, error) {
collatorMergeError.WithLabelValues(version.String()).Inc()
return nil, err
}
for path, pathItem := range spec.Paths {
if isPathSunsetEligible(pathItem) {
delete(spec.Paths, path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change does need a feature flag/pivot date check

}
}
if err := vervet.RemoveElements(spec, c.excludePatterns); err != nil {
log.Error().Err(err).Msgf("could not merge revision for version %s", version)
collatorMergeError.WithLabelValues(version.String()).Inc()
Expand Down
165 changes: 165 additions & 0 deletions internal/storage/collator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,171 @@ paths:
description: Get OpenAPI at version
`

const serviceDSpecWithMixedSunset = `
openapi: 3.0.0
info:
title: ServiceD API
version: 0.0.0
tags:
- name: example
description: service d example
paths:
/sunset:
get:
x-snyk-sunset-eligible: 2023-01-01
summary: Sunset endpoint
responses:
'200':
description: An empty response
/notsunset:
get:
summary: Not Sunset endpoint
responses:
'200':
description: An empty response
/latersunset:
get:
x-snyk-sunset-eligible: 2025-01-01
summary: Later Sunset endpoint
responses:
'200':
description: An empty response
`

func TestCollator_Collate_MixedSunset(t *testing.T) {
c := qt.New(t)

v20230101_ga := vervet.Version{
Date: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
Stability: vervet.StabilityGA,
}

collator, err := storage.NewCollator()
c.Assert(err, qt.IsNil)

collator.Add("service-d", storage.ContentRevision{
Version: v20230101_ga,
Blob: []byte(serviceDSpecWithMixedSunset),
})

specs, err := collator.Collate()
c.Assert(err, qt.IsNil)

// Assert that the sunset endpoint is not present in the collated specs
_, exists := specs[v20230101_ga].Paths["/sunset"]
c.Assert(exists, qt.IsFalse)

// Assert that the not sunset endpoint is still present
_, exists = specs[v20230101_ga].Paths["/notsunset"]
c.Assert(exists, qt.IsTrue)

// Assert that the later sunset endpoint is still present
_, exists = specs[v20230101_ga].Paths["/latersunset"]
c.Assert(exists, qt.IsTrue)
}

const serviceDSpecAllSunset = `
openapi: 3.0.0
info:
title: ServiceD API
version: 0.0.0
tags:
- name: example
description: service d example
paths:
/sunset1:
get:
x-snyk-sunset-eligible: 2023-01-01
summary: Sunset endpoint 1
responses:
'200':
description: An empty response
/sunset2:
get:
x-snyk-sunset-eligible: 2022-12-31
summary: Sunset endpoint 2
responses:
'200':
description: An empty response
`

func TestCollator_Collate_AllSunset(t *testing.T) {
c := qt.New(t)

v20230101_ga := vervet.Version{
Date: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
Stability: vervet.StabilityGA,
}

collator, err := storage.NewCollator()
c.Assert(err, qt.IsNil)

collator.Add("service-d", storage.ContentRevision{
Version: v20230101_ga,
Blob: []byte(serviceDSpecAllSunset),
})

specs, err := collator.Collate()
c.Assert(err, qt.IsNil)

// Assert that all sunset endpoints are not present in the collated specs
_, exists := specs[v20230101_ga].Paths["/sunset1"]
c.Assert(exists, qt.IsFalse)

_, exists = specs[v20230101_ga].Paths["/sunset2"]
c.Assert(exists, qt.IsFalse)
}

const serviceDSpecNoSunset = `
openapi: 3.0.0
info:
title: ServiceD API
version: 0.0.0
tags:
- name: example
description: service d example
paths:
/active1:
get:
summary: Active endpoint 1
responses:
'200':
description: An empty response
/active2:
get:
summary: Active endpoint 2
responses:
'200':
description: An empty response
`

func TestCollator_Collate_NoSunset(t *testing.T) {
c := qt.New(t)

v20230101_ga := vervet.Version{
Date: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
Stability: vervet.StabilityGA,
}

collator, err := storage.NewCollator()
c.Assert(err, qt.IsNil)

collator.Add("service-d", storage.ContentRevision{
Version: v20230101_ga,
Blob: []byte(serviceDSpecNoSunset),
})

specs, err := collator.Collate()
c.Assert(err, qt.IsNil)

// Assert that all active endpoints are still present in the collated specs
_, exists := specs[v20230101_ga].Paths["/active1"]
c.Assert(exists, qt.IsTrue)

_, exists = specs[v20230101_ga].Paths["/active2"]
c.Assert(exists, qt.IsTrue)
}

func TestCollator_Collate(t *testing.T) {
c := qt.New(t)

Expand Down