🧪 test: add JWT secret rotation BDD scenarios and step implementations #12

Merged
arcodange merged 72 commits from feature/jwt-secret-rotation into main 2026-04-11 17:56:47 +02:00
4 changed files with 62 additions and 61 deletions
Showing only changes of commit 168efd3e99 - Show all commits

View File

@@ -23,7 +23,7 @@ Feature: JWT Secret Retention Policy
And the retention factor is 3.0
When I add a new JWT secret
Then the secret should expire after 6 hours
And the retention period should be calculated as "2h × 3.0 = 6h"
And the retention period should be 6 hours
Scenario: Maximum retention period enforcement
Given the JWT TTL is set to 72 hours

View File

@@ -8,6 +8,7 @@ import (
"dance-lessons-coach/pkg/bdd/testserver"
"github.com/cucumber/godog"
"github.com/golang-jwt/jwt/v5"
)
@@ -182,7 +183,7 @@ func (s *AuthSteps) theRegistrationShouldBeSuccessful() error {
func (s *AuthSteps) iShouldBeAbleToAuthenticateWithTheNewCredentials() error {
// This is the same as regular authentication
return nil
return godog.ErrPending
}
func (s *AuthSteps) iAmAuthenticatedAsAdmin() error {
@@ -212,7 +213,7 @@ func (s *AuthSteps) thePasswordResetShouldBeAllowed() error {
func (s *AuthSteps) theUserShouldBeFlaggedForPasswordReset() error {
// This is verified by the password reset request being successful
return nil
return godog.ErrPending
}
func (s *AuthSteps) iCompletePasswordResetForWithNewPassword(username, password string) error {
@@ -251,7 +252,7 @@ func (s *AuthSteps) thePasswordResetShouldBeSuccessful() error {
func (s *AuthSteps) iShouldBeAbleToAuthenticateWithTheNewPassword() error {
// This is the same as regular authentication
return nil
return godog.ErrPending
}
func (s *AuthSteps) thePasswordResetShouldFail() error {

View File

@@ -33,19 +33,25 @@ func (s *JWTRetentionSteps) theServerIsRunningWithJWTSecretRetentionConfigured()
func (s *JWTRetentionSteps) theDefaultJWTTTLIsHours(hours int) error {
// This would verify the default TTL configuration
// For now, we'll just verify server is running
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theRetentionFactorIs(factor float64) error {
// This would set the retention factor
// For now, we'll store it for reference
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theMaximumRetentionIsHours(hours int) error {
// This would set the maximum retention
// For now, we'll store it for reference
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theRetentionPeriodShouldBeHours(hours int) error {
// This would verify the retention period calculation
// For now, we'll just verify server is running
return godog.ErrPending
}
// Secret Management Steps
@@ -69,13 +75,13 @@ func (s *JWTRetentionSteps) iAddASecondaryJWTSecretWithHourExpiration(hours int)
func (s *JWTRetentionSteps) iWaitForTheRetentionPeriodToElapse() error {
// Simulate waiting for retention period
// In real implementation, this would actually wait or mock time
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theExpiredSecondarySecretShouldBeAutomaticallyRemoved() error {
// Verify the secondary secret is no longer valid
// Try to authenticate with it - should fail
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) thePrimarySecretShouldRemainActive() error {
@@ -87,42 +93,36 @@ func (s *JWTRetentionSteps) thePrimarySecretShouldRemainActive() error {
func (s *JWTRetentionSteps) iShouldSeeCleanupEventInLogs() error {
// Check logs for cleanup events
// In real implementation, this would verify log output
return nil
return godog.ErrPending
}
// Retention Calculation Steps
func (s *JWTRetentionSteps) theJWTTTLIsSetToHours(hours int) error {
// Set JWT TTL
return nil
}
func (s *JWTRetentionSteps) theRetentionPeriodShouldBeCalculatedAs(formula string) error {
// Verify retention period calculation
// Parse formula and validate
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theRetentionPeriodShouldBeCappedAtHours(hours int) error {
// Verify maximum retention enforcement
return nil
return godog.ErrPending
}
// Cleanup Frequency Steps
func (s *JWTRetentionSteps) theCleanupIntervalIsSetToMinutes(minutes int) error {
// Set cleanup interval
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) itShouldBeRemovedWithinMinutes(minutes int) error {
// Verify timely removal
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) iShouldSeeCleanupEventsEveryMinutes(minutes int) error {
// Verify regular cleanup events
return nil
return godog.ErrPending
}
// Token Validation Steps
@@ -152,7 +152,7 @@ func (s *JWTRetentionSteps) iReceiveAValidJWTTokenSignedWithCurrentSecret() erro
func (s *JWTRetentionSteps) iWaitForTheSecretToExpire() error {
// Simulate waiting for secret expiration
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) iTryToValidateTheExpiredToken() error {
@@ -193,34 +193,34 @@ func (s *JWTRetentionSteps) iTryToStartTheServer() error {
func (s *JWTRetentionSteps) iShouldReceiveConfigurationValidationError() error {
// Verify validation error
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theErrorShouldMention(message string) error {
// Verify error message content
return nil
return godog.ErrPending
}
// Metrics Steps
func (s *JWTRetentionSteps) iHaveEnabledPrometheusMetrics() error {
// Enable metrics in configuration
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) iShouldSeeMetricIncrement(metric string) error {
// Verify metric was incremented
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) iShouldSeeMetricDecrease(metric string) error {
// Verify metric was decremented
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) iShouldSeeHistogramUpdate(metric string) error {
// Verify histogram was updated
return nil
return godog.ErrPending
}
// Logging Steps
@@ -251,58 +251,58 @@ func (s *JWTRetentionSteps) theLogsShouldShowMaskedSecret(masked string) error {
func (s *JWTRetentionSteps) theLogsShouldNotExposeTheFullSecret() error {
// Verify no full secret exposure
return nil
return godog.ErrPending
}
// Performance Steps
func (s *JWTRetentionSteps) iHaveJWTSecrets(count int) error {
// Simulate having many secrets
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) ofThemAreExpired(expiredCount int) error {
// Simulate expired secrets
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) itShouldCompleteWithinMilliseconds(ms int) error {
// Verify performance
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andNotImpactServerPerformance() error {
// Verify no performance impact
return nil
return godog.ErrPending
}
// Configuration Management Steps
func (s *JWTRetentionSteps) iSetCleanupIntervalToHours(hours int) error {
// Set very high cleanup interval (effectively disabled)
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theyShouldNotBeAutomaticallyRemoved() error {
// Verify no automatic cleanup
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andManualCleanupShouldStillBePossible() error {
// Verify manual cleanup still works
return nil
return godog.ErrPending
}
// Edge Case Steps
func (s *JWTRetentionSteps) theRetentionPeriodShouldBeHour() error {
// Verify 1-hour retention
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theSecretShouldExpireAfterHour() error {
// Verify expiration timing
return nil
return godog.ErrPending
}
// Validation Steps
@@ -336,61 +336,61 @@ func (s *JWTRetentionSteps) theErrorShouldMentionMinimumCharacters() error {
func (s *JWTRetentionSteps) theCleanupJobEncountersAnError() error {
// Simulate cleanup error
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) itShouldLogTheError() error {
// Verify error logging
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andContinueWithRemainingSecrets() error {
// Verify continuation
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andNotCrashTheCleanupProcess() error {
// Verify process doesn't crash
return nil
return godog.ErrPending
}
// Configuration Reload Steps
func (s *JWTRetentionSteps) theServerIsRunningWithDefaultRetentionSettings() error {
// Verify default settings
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) iUpdateTheRetentionFactorViaConfiguration() error {
// Update configuration
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theNewSettingsShouldTakeEffectImmediately() error {
// Verify immediate effect
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andExistingSecretsShouldBeReevaluated() error {
// Verify reevaluation
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andCleanupShouldUseNewRetentionPeriods() error {
// Verify new periods used
return nil
return godog.ErrPending
}
// Audit Trail Steps
func (s *JWTRetentionSteps) iEnableAuditLogging() error {
// Enable audit logging
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) iShouldSeeAuditLogEntryWithEventType(eventType string) error {
// Verify audit log entry
return nil
return godog.ErrPending
}
// Token Refresh Steps
@@ -413,17 +413,17 @@ func (s *JWTRetentionSteps) iRefreshMyTokenDuringRetentionPeriod() error {
func (s *JWTRetentionSteps) iShouldReceiveNewTokenB() error {
// Verify new token received
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andTokenAShouldStillBeValidUntilRetentionExpires() error {
// Verify old token still works
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andBothTokensShouldWorkConcurrently() error {
// Verify concurrent validity
return nil
return godog.ErrPending
}
// Emergency Rotation Steps
@@ -437,17 +437,17 @@ func (s *JWTRetentionSteps) iRotateToANewPrimarySecret() error {
func (s *JWTRetentionSteps) oldTokensShouldBeInvalidatedImmediately() error {
// Verify immediate invalidation
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andNewTokensShouldUseTheEmergencySecret() error {
// Verify new tokens use emergency secret
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andCleanupShouldRemoveCompromisedSecrets() error {
// Verify compromised secrets removed
return nil
return godog.ErrPending
}
// Additional missing steps for JWT retention
@@ -639,25 +639,25 @@ func (s *JWTRetentionSteps) whenTheSecretIsRemovedByCleanup() error {
func (s *JWTRetentionSteps) iHaveMonitoringConfigured() error {
// Configure monitoring
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theCleanupJobFailsRepeatedly() error {
// Simulate repeated failures
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) iShouldReceiveAlertNotification() error {
// Verify alert received
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) theAlertShouldIncludeErrorDetails() error {
// Verify error details included
return nil
return godog.ErrPending
}
func (s *JWTRetentionSteps) andSuggestRemediationSteps() error {
// Verify remediation suggestions
return nil
return godog.ErrPending
}

View File

@@ -106,8 +106,8 @@ func InitializeAllSteps(ctx *godog.ScenarioContext, client *testserver.Client) {
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 retention period should be (\d+) hours$`, sc.jwtRetentionSteps.theRetentionPeriodShouldBeHours)
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)