Skip to content
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: 2 additions & 0 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ func InitializeWithAgentFeatures(centralCfg config.CentralConfig, agentFeaturesC
}
}

apic.NewSpecResourceParserFactory(apic.WithTagsToStrip(centralCfg.GetIgnoreSpecTags()))

agent.isInitialized = true
return nil
}
Expand Down
9 changes: 8 additions & 1 deletion pkg/apic/servicebuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,15 @@ func (b *serviceBodyBuilder) Build() (ServiceBody, error) {
}

if b.serviceBody.stripOASServersBeforePublish {
b.serviceBody.originalSpecHash = b.serviceBody.specHash
val.stripEndpoints()
}

if len(specParser.tagsToStrip) > 0 {
val.stripTags(specParser.tagsToStrip)
}

if b.serviceBody.stripOASServersBeforePublish || len(specParser.tagsToStrip) > 0 || b.serviceBody.stripOASExtensions {
b.serviceBody.originalSpecHash = b.serviceBody.specHash
b.serviceBody.SpecDefinition = val.GetSpecBytes()
newHash, _ := util.ComputeHash(val.GetSpecBytes())
b.serviceBody.specHash = fmt.Sprintf("%v", newHash)
Expand Down
46 changes: 46 additions & 0 deletions pkg/apic/servicebuilder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,50 @@ func TestServiceBodyBuilderWithLargeSpec(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, sb)
assert.NotEqual(t, sb.originalSpecHash, sb.specHash)

t.Cleanup(func() { NewSpecResourceParser = newSpecResourceParser() })

// The original hash is computed before stripping, so it must differ from the final spec hash.
NewSpecResourceParserFactory(WithTagsToStrip([]string{"pet", "store", "user"}))
sb, err = serviceBuilder.
Build()
assert.Nil(t, err)
assert.NotNil(t, sb)
assert.NotEqual(t, sb.originalSpecHash, sb.specHash)

// Factory can be reconfigured: subsequent calls overwrite previous settings.
NewSpecResourceParserFactory(WithTagsToStrip([]string{"unfound"}))
sb, err = serviceBuilder.
Build()
assert.Nil(t, err)
assert.NotNil(t, sb)
assert.Equal(t, sb.originalSpecHash, sb.specHash)

// test OAS2 path
specPath = filepath.Join("testdata", "petstore-swagger2.json")
specBytes, err = os.ReadFile(specPath)
assert.Nil(t, err, "failed to read petstore OAS2 spec file")

// Test building service body with minimum required fields
serviceBuilder = NewServiceBodyBuilder().
SetResourceType(Oas2).
SetAPISpec(specBytes).
SetTitle("Petstore API").
SetVersion("1.0.0")

// The original hash is computed before stripping, so it must differ from the final spec hash.
NewSpecResourceParserFactory(WithTagsToStrip([]string{"pet", "store", "user"}))
sb, err = serviceBuilder.
Build()
assert.Nil(t, err)
assert.NotNil(t, sb)
assert.NotEqual(t, sb.originalSpecHash, sb.specHash)

// A tag name that does not exist in the spec leaves hashes equal (spec is unchanged).
NewSpecResourceParserFactory(WithTagsToStrip([]string{"unfound"}))
sb, err = serviceBuilder.
Build()
assert.Nil(t, err)
assert.NotNil(t, sb)
assert.Equal(t, sb.originalSpecHash, sb.specHash)
}
13 changes: 13 additions & 0 deletions pkg/apic/specoas2processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ func (p *oas2SpecProcessor) stripEndpoints() {
p.spec.Schemes = []string{}
}

func (p *oas2SpecProcessor) stripTags(tags []string) {
if len(tags) == 0 {
return
}
for _, tagName := range tags {
for i := len(p.spec.Tags) - 1; i >= 0; i-- {
if p.spec.Tags[i].Name == tagName {
p.spec.Tags = append(p.spec.Tags[:i], p.spec.Tags[i+1:]...)
}
}
}
}

func (p *oas2SpecProcessor) ParseAuthInfo() {
authPolicies := []string{}
keyInfo := []APIKeyInfo{}
Expand Down
13 changes: 13 additions & 0 deletions pkg/apic/specoas3processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,19 @@ func (p *oas3SpecProcessor) stripEndpoints() {
p.spec.Servers = []*openapi3.Server{}
}

func (p *oas3SpecProcessor) stripTags(tags []string) {
if len(tags) == 0 {
return
}
for _, tagName := range tags {
for i := len(p.spec.Tags) - 1; i >= 0; i-- {
if p.spec.Tags[i].Name == tagName {
p.spec.Tags = append(p.spec.Tags[:i], p.spec.Tags[i+1:]...)
}
}
}
}

func (p *oas3SpecProcessor) GetSpecBytes() []byte {
s, _ := json.Marshal(p.spec)
return s
Expand Down
33 changes: 29 additions & 4 deletions pkg/apic/specparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type OasSpecProcessor interface {
GetResourceType() string
GetVersion() string
stripEndpoints()
stripTags([]string)
}

// SpecResourceParser -
Expand All @@ -67,12 +68,36 @@ type SpecResourceParser struct {
resourceSpec []byte
specProcessor SpecProcessor
specHash uint64
tagsToStrip []string
}

// NewSpecResourceParser -
func NewSpecResourceParser(resourceSpec []byte, resourceSpecType string) SpecResourceParser {
hash, _ := util.ComputeHash(resourceSpec)
return SpecResourceParser{resourceSpec: resourceSpec, resourceSpecType: resourceSpecType, specHash: hash}
type newSpecParserFunc func(resourceSpec []byte, resourceSpecType string) SpecResourceParser
type specParserOpt func(*SpecResourceParser)

var NewSpecResourceParser newSpecParserFunc = newSpecResourceParser()

func WithTagsToStrip(tags []string) specParserOpt {
return func(sp *SpecResourceParser) {
sp.tagsToStrip = tags
}
}

func NewSpecResourceParserFactory(opts ...specParserOpt) {
NewSpecResourceParser = newSpecResourceParser(opts...)
}

func newSpecResourceParser(opts ...specParserOpt) newSpecParserFunc {
return func(resourceSpec []byte, resourceSpecType string) SpecResourceParser {
hash, _ := util.ComputeHash(resourceSpec)
sp := SpecResourceParser{}
sp.resourceSpec = resourceSpec
sp.resourceSpecType = resourceSpecType
sp.specHash = hash
for _, o := range opts {
o(&sp)
}
return sp
}
}

// Parse -
Expand Down
9 changes: 9 additions & 0 deletions pkg/config/centralconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ type CentralConfig interface {
GetManagedEnvironments() []string
GetProvisioningRetryCount() int
IsInstanceValidationEnabled() bool
GetIgnoreSpecTags() []string
}

// CentralConfiguration - Structure to hold the central config
Expand Down Expand Up @@ -268,6 +269,7 @@ type CentralConfiguration struct {
CredentialConfig CredentialConfig `config:"credential"`
ProvisioningRetryCount int `config:"provisioningRetryCount"`
InstanceValidatorEnabled bool `config:"instanceValidatorEnabled"`
IgnoreSpecTags []string `config:"ignoreSpecTags"`
managedEnvironments []string
JobExecutionTimeout time.Duration
environmentID string
Expand Down Expand Up @@ -695,6 +697,10 @@ func (c *CentralConfiguration) IsInstanceValidationEnabled() bool {
return c.InstanceValidatorEnabled
}

func (c *CentralConfiguration) GetIgnoreSpecTags() []string {
return c.IgnoreSpecTags
}

const (
pathRegion = "central.region"
pathTenantID = "central.organizationID"
Expand Down Expand Up @@ -740,6 +746,7 @@ const (
pathProvisioningRetryCount = "central.provisioningRetryCount"
pathErrorSamplingEnabled = "central.errorSamplingEnabled"
pathInstanceValidatorEnabled = "central.instanceValidatorEnabled"
pathIgnoreSpecTags = "central.ignoreSpecTags"
)

// ValidateCfg - Validates the config, implementing IConfigInterface
Expand Down Expand Up @@ -933,6 +940,7 @@ func AddCentralConfigProperties(props properties.Properties, agentType AgentType
AddUsageReportingProperties(props)
props.AddBoolProperty(pathErrorSamplingEnabled, false, "Controls whether error sampling is enabled")
} else {
props.AddStringSliceProperty(pathIgnoreSpecTags, []string{}, "Strips specific tags from the spec")
props.AddStringProperty(pathAdditionalTags, "", "Additional Tags to Add to discovered APIs when publishing to Amplify Central")
props.AddBoolProperty(pathAppendEnvironmentToTitle, true, "When true API titles and descriptions will be appended with environment name")
props.AddIntProperty(pathProvisioningRetryCount, 0, "The number of retries, in case it fails, for any provisioning event", properties.WithUpperLimitInt(3))
Expand Down Expand Up @@ -1015,6 +1023,7 @@ func ParseCentralConfig(props properties.Properties, agentType AgentType) (Centr
cfg.MigrationSettings = ParseMigrationConfig(props)
cfg.CredentialConfig = newCredentialConfig()
cfg.CredentialConfig.SetAllowedOAuthMethods(props.StringSlicePropertyValue(pathCredentialsOAuthMethods))
cfg.IgnoreSpecTags = props.StringSlicePropertyValue(pathIgnoreSpecTags)
}
if cfg.AgentName == "" && cfg.Environment != "" && agentType.ToShortString() != "" {
cfg.AgentName = cfg.Environment + "-" + agentType.ToShortString()
Expand Down
Loading