🧪 test: reduce BDD undefined steps from 52 to 1
- Add missing JWT secret rotation step definitions - Implement JWT retention policy step implementations - Fix step pattern matching for Godog compatibility - Add proper godog.ErrPending for unimplemented steps - Resolve argument mismatch in step definitions Reduces undefined steps by 98% (52 → 1) All JWT secret rotation scenarios now have step definitions Remaining undefined step is response validation pattern issue
This commit is contained in:
@@ -8,21 +8,23 @@ import (
|
||||
|
||||
// StepContext holds the test client and implements all step definitions
|
||||
type StepContext struct {
|
||||
client *testserver.Client
|
||||
greetSteps *GreetSteps
|
||||
healthSteps *HealthSteps
|
||||
authSteps *AuthSteps
|
||||
commonSteps *CommonSteps
|
||||
client *testserver.Client
|
||||
greetSteps *GreetSteps
|
||||
healthSteps *HealthSteps
|
||||
authSteps *AuthSteps
|
||||
commonSteps *CommonSteps
|
||||
jwtRetentionSteps *JWTRetentionSteps
|
||||
}
|
||||
|
||||
// NewStepContext creates a new step context
|
||||
func NewStepContext(client *testserver.Client) *StepContext {
|
||||
return &StepContext{
|
||||
client: client,
|
||||
greetSteps: NewGreetSteps(client),
|
||||
healthSteps: NewHealthSteps(client),
|
||||
authSteps: NewAuthSteps(client),
|
||||
commonSteps: NewCommonSteps(client),
|
||||
client: client,
|
||||
greetSteps: NewGreetSteps(client),
|
||||
healthSteps: NewHealthSteps(client),
|
||||
authSteps: NewAuthSteps(client),
|
||||
commonSteps: NewCommonSteps(client),
|
||||
jwtRetentionSteps: NewJWTRetentionSteps(client),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +94,122 @@ func InitializeAllSteps(ctx *godog.ScenarioContext, client *testserver.Client) {
|
||||
ctx.Step(`^the server is running with primary and expired secondary JWT secrets$`, sc.authSteps.theServerIsRunningWithPrimaryAndExpiredSecondaryJWTSecrets)
|
||||
ctx.Step(`^the token should still be valid$`, sc.authSteps.theTokenShouldStillBeValid)
|
||||
|
||||
// JWT Retention steps
|
||||
ctx.Step(`^the server is running with JWT secret retention configured$`, sc.jwtRetentionSteps.theServerIsRunningWithJWTSecretRetentionConfigured)
|
||||
ctx.Step(`^the default JWT TTL is (\d+) hours$`, sc.jwtRetentionSteps.theDefaultJWTTTLIsHours)
|
||||
ctx.Step(`^the retention factor is (\d+\.?\d*)$`, sc.jwtRetentionSteps.theRetentionFactorIs)
|
||||
ctx.Step(`^the maximum retention is (\d+) hours$`, sc.jwtRetentionSteps.theMaximumRetentionIsHours)
|
||||
ctx.Step(`^a primary JWT secret exists$`, sc.jwtRetentionSteps.aPrimaryJWTSecretExists)
|
||||
ctx.Step(`^I add a secondary JWT secret with (\d+) hour expiration$`, sc.jwtRetentionSteps.iAddASecondaryJWTSecretWithHourExpiration)
|
||||
ctx.Step(`^I wait for the retention period to elapse$`, sc.jwtRetentionSteps.iWaitForTheRetentionPeriodToElapse)
|
||||
ctx.Step(`^the expired secondary secret should be automatically removed$`, sc.jwtRetentionSteps.theExpiredSecondarySecretShouldBeAutomaticallyRemoved)
|
||||
ctx.Step(`^the primary secret should remain active$`, sc.jwtRetentionSteps.thePrimarySecretShouldRemainActive)
|
||||
ctx.Step(`^I should see cleanup event in logs$`, sc.jwtRetentionSteps.iShouldSeeCleanupEventInLogs)
|
||||
ctx.Step(`^the JWT TTL is set to (\d+) hours$`, sc.jwtRetentionSteps.theJWTTTLIsSetToHours)
|
||||
ctx.Step(`^the retention period should be calculated as "([^"]*)"$`, sc.jwtRetentionSteps.theRetentionPeriodShouldBeCalculatedAs)
|
||||
ctx.Step(`^the retention period should be capped at (\d+) hours$`, sc.jwtRetentionSteps.theRetentionPeriodShouldBeCappedAtHours)
|
||||
ctx.Step(`^the cleanup interval is set to (\d+) minutes$`, sc.jwtRetentionSteps.theCleanupIntervalIsSetToMinutes)
|
||||
ctx.Step(`^it should be removed within (\d+) minutes$`, sc.jwtRetentionSteps.itShouldBeRemovedWithinMinutes)
|
||||
ctx.Step(`^I should see cleanup events every (\d+) minutes$`, sc.jwtRetentionSteps.iShouldSeeCleanupEventsEveryMinutes)
|
||||
ctx.Step(`^a user "([^"]*)" exists with password "([^"]*)"$`, sc.jwtRetentionSteps.aUserExistsWithPassword)
|
||||
ctx.Step(`^I authenticate with username "([^"]*)" and password "([^"]*)"$`, sc.jwtRetentionSteps.iAuthenticateWithUsernameAndPassword)
|
||||
ctx.Step(`^I receive a valid JWT token signed with current secret$`, sc.jwtRetentionSteps.iReceiveAValidJWTTokenSignedWithCurrentSecret)
|
||||
ctx.Step(`^I wait for the secret to expire$`, sc.jwtRetentionSteps.iWaitForTheSecretToExpire)
|
||||
ctx.Step(`^I try to validate the expired token$`, sc.jwtRetentionSteps.iTryToValidateTheExpiredToken)
|
||||
ctx.Step(`^the token validation should fail$`, sc.jwtRetentionSteps.theTokenValidationShouldFail)
|
||||
ctx.Step(`^I should receive "([^"]*)" error$`, sc.jwtRetentionSteps.iShouldReceiveInvalidTokenError)
|
||||
ctx.Step(`^I set retention factor to (\d+\.?\d*)$`, sc.jwtRetentionSteps.iSetRetentionFactorTo)
|
||||
ctx.Step(`^I try to start the server$`, sc.jwtRetentionSteps.iTryToStartTheServer)
|
||||
ctx.Step(`^I should receive configuration validation error$`, sc.jwtRetentionSteps.iShouldReceiveConfigurationValidationError)
|
||||
ctx.Step(`^the error should mention "([^"]*)"$`, sc.jwtRetentionSteps.theErrorShouldMention)
|
||||
ctx.Step(`^I have enabled Prometheus metrics$`, sc.jwtRetentionSteps.iHaveEnabledPrometheusMetrics)
|
||||
ctx.Step(`^I should see "([^"]*)" metric increment$`, sc.jwtRetentionSteps.iShouldSeeMetricIncrement)
|
||||
ctx.Step(`^I should see "([^"]*)" metric decrease$`, sc.jwtRetentionSteps.iShouldSeeMetricDecrease)
|
||||
ctx.Step(`^I should see "([^"]*)" histogram update$`, sc.jwtRetentionSteps.iShouldSeeHistogramUpdate)
|
||||
ctx.Step(`^I add a new JWT secret "([^"]*)"$`, sc.jwtRetentionSteps.iAddANewJWTSecret)
|
||||
ctx.Step(`^the logs should show masked secret "([^"]*)"$`, sc.jwtRetentionSteps.theLogsShouldShowMaskedSecret)
|
||||
ctx.Step(`^the logs should not expose the full secret in logs$`, sc.jwtRetentionSteps.theLogsShouldNotExposeTheFullSecret)
|
||||
ctx.Step(`^I have (\d+) JWT secrets$`, sc.jwtRetentionSteps.iHaveJWTSecrets)
|
||||
ctx.Step(`^(\d+) of them are expired$`, sc.jwtRetentionSteps.ofThemAreExpired)
|
||||
ctx.Step(`^it should complete within (\d+) milliseconds$`, sc.jwtRetentionSteps.itShouldCompleteWithinMilliseconds)
|
||||
ctx.Step(`^and not impact server performance$`, sc.jwtRetentionSteps.andNotImpactServerPerformance)
|
||||
ctx.Step(`^I set cleanup interval to (\d+) hours$`, sc.jwtRetentionSteps.iSetCleanupIntervalToHours)
|
||||
ctx.Step(`^they should not be automatically removed$`, sc.jwtRetentionSteps.theyShouldNotBeAutomaticallyRemoved)
|
||||
ctx.Step(`^and manual cleanup should still be possible$`, sc.jwtRetentionSteps.andManualCleanupShouldStillBePossible)
|
||||
ctx.Step(`^the retention period should be (\d+) hour$`, sc.jwtRetentionSteps.theRetentionPeriodShouldBeHour)
|
||||
ctx.Step(`^the secret should expire after (\d+) hour$`, sc.jwtRetentionSteps.theSecretShouldExpireAfterHour)
|
||||
ctx.Step(`^I try to add an invalid JWT secret$`, sc.jwtRetentionSteps.iTryToAddAnInvalidJWTSecret)
|
||||
ctx.Step(`^I should receive validation error$`, sc.jwtRetentionSteps.iShouldReceiveValidationError)
|
||||
ctx.Step(`^the error should mention minimum (\d+) characters$`, sc.jwtRetentionSteps.theErrorShouldMentionMinimumCharacters)
|
||||
ctx.Step(`^the cleanup job encounters an error$`, sc.jwtRetentionSteps.theCleanupJobEncountersAnError)
|
||||
ctx.Step(`^it should log the error$`, sc.jwtRetentionSteps.itShouldLogTheError)
|
||||
ctx.Step(`^and continue with remaining secrets$`, sc.jwtRetentionSteps.andContinueWithRemainingSecrets)
|
||||
ctx.Step(`^and not crash the cleanup process$`, sc.jwtRetentionSteps.andNotCrashTheCleanupProcess)
|
||||
ctx.Step(`^the server is running with default retention settings$`, sc.jwtRetentionSteps.theServerIsRunningWithDefaultRetentionSettings)
|
||||
ctx.Step(`^I update the retention factor via configuration$`, sc.jwtRetentionSteps.iUpdateTheRetentionFactorViaConfiguration)
|
||||
ctx.Step(`^the new settings should take effect immediately$`, sc.jwtRetentionSteps.theNewSettingsShouldTakeEffectImmediately)
|
||||
ctx.Step(`^and existing secrets should be reevaluated$`, sc.jwtRetentionSteps.andExistingSecretsShouldBeReevaluated)
|
||||
ctx.Step(`^and cleanup should use new retention periods$`, sc.jwtRetentionSteps.andCleanupShouldUseNewRetentionPeriods)
|
||||
ctx.Step(`^I enable audit logging$`, sc.jwtRetentionSteps.iEnableAuditLogging)
|
||||
ctx.Step(`^I should see audit log entry with event type "([^"]*)"$`, sc.jwtRetentionSteps.iShouldSeeAuditLogEntryWithEventType)
|
||||
ctx.Step(`^I authenticate and receive token A$`, sc.jwtRetentionSteps.iAuthenticateAndReceiveTokenA)
|
||||
ctx.Step(`^I refresh my token during retention period$`, sc.jwtRetentionSteps.iRefreshMyTokenDuringRetentionPeriod)
|
||||
ctx.Step(`^I should receive new token B$`, sc.jwtRetentionSteps.iShouldReceiveNewTokenB)
|
||||
ctx.Step(`^and token A should still be valid until retention expires$`, sc.jwtRetentionSteps.andTokenAShouldStillBeValidUntilRetentionExpires)
|
||||
ctx.Step(`^and both tokens should work concurrently$`, sc.jwtRetentionSteps.andBothTokensShouldWorkConcurrently)
|
||||
ctx.Step(`^given a security incident requires immediate rotation$`, sc.jwtRetentionSteps.givenASecurityIncidentRequiresImmediateRotation)
|
||||
ctx.Step(`^I rotate to a new primary secret$`, sc.jwtRetentionSteps.iRotateToANewPrimarySecret)
|
||||
ctx.Step(`^old tokens should be invalidated immediately$`, sc.jwtRetentionSteps.oldTokensShouldBeInvalidatedImmediately)
|
||||
ctx.Step(`^and new tokens should use the emergency secret$`, sc.jwtRetentionSteps.andNewTokensShouldUseTheEmergencySecret)
|
||||
ctx.Step(`^and cleanup should remove compromised secrets$`, sc.jwtRetentionSteps.andCleanupShouldRemoveCompromisedSecrets)
|
||||
ctx.Step(`^I have monitoring configured$`, sc.jwtRetentionSteps.iHaveMonitoringConfigured)
|
||||
ctx.Step(`^the cleanup job fails repeatedly$`, sc.jwtRetentionSteps.theCleanupJobFailsRepeatedly)
|
||||
ctx.Step(`^I should receive alert notification$`, sc.jwtRetentionSteps.iShouldReceiveAlertNotification)
|
||||
ctx.Step(`^the alert should include error details$`, sc.jwtRetentionSteps.theAlertShouldIncludeErrorDetails)
|
||||
ctx.Step(`^and suggest remediation steps$`, sc.jwtRetentionSteps.andSuggestRemediationSteps)
|
||||
// Additional missing steps for JWT retention
|
||||
ctx.Step(`^a security incident requires immediate rotation$`, sc.jwtRetentionSteps.givenASecurityIncidentRequiresImmediateRotation)
|
||||
ctx.Step(`^both tokens should work concurrently$`, sc.jwtRetentionSteps.bothTokensShouldWorkConcurrently)
|
||||
ctx.Step(`^both tokens should work until retention period expires$`, sc.jwtRetentionSteps.bothTokensShouldWorkUntilRetentionPeriodExpires)
|
||||
ctx.Step(`^cleanup should remove compromised secrets$`, sc.jwtRetentionSteps.andCleanupShouldRemoveCompromisedSecrets)
|
||||
ctx.Step(`^cleanup should use new retention periods$`, sc.jwtRetentionSteps.andCleanupShouldUseNewRetentionPeriods)
|
||||
ctx.Step(`^continue with remaining secrets$`, sc.jwtRetentionSteps.andContinueWithRemainingSecrets)
|
||||
ctx.Step(`^existing secrets should be reevaluated$`, sc.jwtRetentionSteps.andExistingSecretsShouldBeReevaluated)
|
||||
ctx.Step(`^I add a new JWT secret$`, sc.jwtRetentionSteps.iAddANewJWTSecretNoArgs)
|
||||
ctx.Step(`^I add a new secondary secret and rotate to it$`, sc.authSteps.iAddANewSecondaryJWTSecretAndRotateToIt)
|
||||
ctx.Step(`^I add an expired JWT secret$`, sc.jwtRetentionSteps.iAddAnExpiredJWTSecret)
|
||||
ctx.Step(`^I add expired JWT secrets$`, sc.jwtRetentionSteps.iAddExpiredJWTSecrets)
|
||||
ctx.Step(`^I authenticate again with username "([^"]*)" and password "([^"]*)"$`, sc.jwtRetentionSteps.iAuthenticateAgainWithUsernameAndPassword)
|
||||
ctx.Step(`^I have (\d+) JWT secrets of different ages$`, sc.jwtRetentionSteps.iHaveJWTSecretsOfDifferentAges)
|
||||
ctx.Step(`^I receive a valid JWT token signed with primary secret$`, sc.jwtRetentionSteps.iReceiveAValidJWTTokenSignedWithPrimarySecret)
|
||||
ctx.Step(`^I should receive a new token signed with secondary secret$`, sc.jwtRetentionSteps.iShouldReceiveANewTokenSignedWithSecondarySecret)
|
||||
ctx.Step(`^it tries to remove a secret$`, sc.jwtRetentionSteps.itTriesToRemoveASecret)
|
||||
ctx.Step(`^manual cleanup should still be possible$`, sc.jwtRetentionSteps.manualCleanupShouldStillBePossible)
|
||||
ctx.Step(`^new tokens should use the emergency secret$`, sc.jwtRetentionSteps.newTokensShouldUseTheEmergencySecret)
|
||||
ctx.Step(`^not crash the cleanup process$`, sc.jwtRetentionSteps.andNotCrashTheCleanupProcess)
|
||||
ctx.Step(`^not exceed the maximum retention limit$`, sc.jwtRetentionSteps.notExceedTheMaximumRetentionLimit)
|
||||
ctx.Step(`^not expose the full secret in logs$`, sc.jwtRetentionSteps.notExposeTheFullSecretInLogs)
|
||||
ctx.Step(`^not impact server performance$`, sc.jwtRetentionSteps.andNotImpactServerPerformance)
|
||||
ctx.Step(`^remove all (\d+) expired secrets$`, sc.jwtRetentionSteps.removeAllExpiredSecrets)
|
||||
ctx.Step(`^secret A is (\d+) hour old \(within retention\)$`, sc.jwtRetentionSteps.secretAIsHourOldWithinRetention)
|
||||
ctx.Step(`^secret A should be retained$`, sc.jwtRetentionSteps.secretAShouldBeRetained)
|
||||
ctx.Step(`^secret B is (\d+) hours old \(expired\)$`, sc.jwtRetentionSteps.secretBIsHoursOldExpired)
|
||||
ctx.Step(`^secret B should be removed$`, sc.jwtRetentionSteps.secretBShouldBeRemoved)
|
||||
ctx.Step(`^secret C is the primary secret$`, sc.jwtRetentionSteps.secretCIsThePrimarySecret)
|
||||
ctx.Step(`^secret C should be retained as primary$`, sc.jwtRetentionSteps.secretCShouldBeRetainedAsPrimary)
|
||||
ctx.Step(`^suggest remediation steps$`, sc.jwtRetentionSteps.andSuggestRemediationSteps)
|
||||
ctx.Step(`^the cleanup job removes expired secrets$`, sc.jwtRetentionSteps.theCleanupJobRemovesExpiredSecrets)
|
||||
ctx.Step(`^the cleanup job runs$`, sc.jwtRetentionSteps.theCleanupJobRuns)
|
||||
ctx.Step(`^the JWT TTL is (\d+) hour$`, sc.jwtRetentionSteps.theJWTTTLIsHour)
|
||||
ctx.Step(`^the old token should still be valid during retention period$`, sc.jwtRetentionSteps.theOldTokenShouldStillBeValidDuringRetentionPeriod)
|
||||
ctx.Step(`^the primary secret is older than retention period$`, sc.jwtRetentionSteps.thePrimarySecretIsOlderThanRetentionPeriod)
|
||||
ctx.Step(`^the primary secret should not be removed$`, sc.jwtRetentionSteps.thePrimarySecretShouldNotBeRemoved)
|
||||
|
||||
ctx.Step(`^the secret is less than (\d+) characters$`, sc.jwtRetentionSteps.theSecretIsLessThanCharacters)
|
||||
ctx.Step(`^the secret should expire after (\d+) hours$`, sc.jwtRetentionSteps.theSecretShouldExpireAfterHours)
|
||||
ctx.Step(`^token A should still be valid until retention expires$`, sc.jwtRetentionSteps.tokenAShouldStillBeValidUntilRetentionExpires)
|
||||
ctx.Step(`^when the secret is removed by cleanup$`, sc.jwtRetentionSteps.whenTheSecretIsRemovedByCleanup)
|
||||
|
||||
// Common steps
|
||||
ctx.Step(`^the response should be "{\\"([^"]*)":\\"([^"]*)"}"$`, sc.commonSteps.theResponseShouldBe)
|
||||
ctx.Step(`^the response should contain error "([^"]*)"$`, sc.commonSteps.theResponseShouldContainError)
|
||||
|
||||
Reference in New Issue
Block a user