mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-30 18:17:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			371 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			371 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) HashiCorp, Inc.
 | |
| // SPDX-License-Identifier: MPL-2.0
 | |
| 
 | |
| package automatedrotationutil
 | |
| 
 | |
| import (
 | |
| 	"reflect"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/hashicorp/vault/sdk/framework"
 | |
| )
 | |
| 
 | |
| var schemaMap = map[string]*framework.FieldSchema{
 | |
| 	"rotation_schedule": {
 | |
| 		Type:        framework.TypeString,
 | |
| 		Description: "CRON-style string that will define the schedule on which rotations should occur. Mutually exclusive with rotation_period",
 | |
| 	},
 | |
| 	"rotation_window": {
 | |
| 		Type:        framework.TypeDurationSecond,
 | |
| 		Description: "Specifies the amount of time in which the rotation is allowed to occur starting from a given rotation_schedule",
 | |
| 	},
 | |
| 	"rotation_period": {
 | |
| 		Type:        framework.TypeDurationSecond,
 | |
| 		Description: "TTL for automatic credential rotation of the given username. Mutually exclusive with rotation_schedule",
 | |
| 	},
 | |
| 	"disable_automated_rotation": {
 | |
| 		Type:        framework.TypeBool,
 | |
| 		Description: "If set to true, will deregister all registered rotation jobs from the RotationManager for the plugin.",
 | |
| 	},
 | |
| }
 | |
| 
 | |
| func TestParseAutomatedRotationFields(t *testing.T) {
 | |
| 	tests := []struct {
 | |
| 		name           string
 | |
| 		data           *framework.FieldData
 | |
| 		expectedParams *AutomatedRotationParams
 | |
| 		initialParams  *AutomatedRotationParams
 | |
| 		expectedError  string
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "basic",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_schedule": "*/15 * * * *",
 | |
| 					"rotation_window":   60,
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "*/15 * * * *",
 | |
| 				RotationWindow:           60 * time.Second,
 | |
| 				RotationPeriod:           0,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "mutually-exclusive",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_schedule": "*/15 * * * *",
 | |
| 					"rotation_period":   15,
 | |
| 					"rotation_window":   60,
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedError: ErrRotationMutuallyExclusiveFields.Error(),
 | |
| 		},
 | |
| 		{
 | |
| 			name: "bad-schedule",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_schedule": "random string",
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedError: "failed to parse provided rotation_schedule",
 | |
| 		},
 | |
| 		{
 | |
| 			name: "incompatible-fields",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_period": 15,
 | |
| 					"rotation_window": 60,
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedError: "rotation_window does not apply to period",
 | |
| 		},
 | |
| 		{
 | |
| 			name: "window-without-schedule",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_window": 60,
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedError: "cannot use rotation_window without rotation_schedule",
 | |
| 		},
 | |
| 		{
 | |
| 			name: "rotation-period-duration-seconds",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_period": "2m",
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "",
 | |
| 				RotationWindow:           0,
 | |
| 				RotationPeriod:           120 * time.Second,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "rotation-window-duration-seconds",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_window":   "12h",
 | |
| 					"rotation_schedule": "* */2 * * *",
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "* */2 * * *",
 | |
| 				RotationWindow:           12 * time.Hour,
 | |
| 				RotationPeriod:           0,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "period-and-window-ok",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_window": 0,
 | |
| 					"rotation_period": 10,
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "",
 | |
| 				RotationWindow:           0,
 | |
| 				RotationPeriod:           10 * time.Second,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "period-and-window-ok-strings",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_schedule": "* */2 * * *",
 | |
| 					"rotation_window":   "5h",
 | |
| 					"rotation_period":   "",
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "* */2 * * *",
 | |
| 				RotationWindow:           5 * time.Hour,
 | |
| 				RotationPeriod:           0,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "period-and-schedule-ok",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_schedule": "",
 | |
| 					"rotation_window":   "",
 | |
| 					"rotation_period":   "2m",
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "",
 | |
| 				RotationWindow:           0,
 | |
| 				RotationPeriod:           2 * time.Minute,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "zero-out-schedule-and-window-set-period",
 | |
| 			data: &framework.FieldData{
 | |
| 				Raw: map[string]interface{}{
 | |
| 					"rotation_schedule": "",
 | |
| 					"rotation_window":   "",
 | |
| 					"rotation_period":   "2m",
 | |
| 				},
 | |
| 				Schema: schemaMap,
 | |
| 			},
 | |
| 			expectedParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "",
 | |
| 				RotationWindow:           0,
 | |
| 				RotationPeriod:           2 * time.Minute,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 			initialParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "*/1 * * * *",
 | |
| 				RotationWindow:           30 * time.Second,
 | |
| 				RotationPeriod:           0,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			p := &AutomatedRotationParams{}
 | |
| 			if tt.initialParams != nil {
 | |
| 				p = tt.initialParams
 | |
| 			}
 | |
| 			err := p.ParseAutomatedRotationFields(tt.data)
 | |
| 			if err != nil {
 | |
| 				if tt.expectedError == "" {
 | |
| 					t.Errorf("expected no error but received an error: %s", err)
 | |
| 				}
 | |
| 				if !strings.Contains(err.Error(), tt.expectedError) {
 | |
| 					t.Errorf("ParseAutomatedRotationFields() error = %v, expected %s", err, tt.expectedError)
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if err == nil && !reflect.DeepEqual(tt.expectedParams, p) {
 | |
| 				t.Errorf("ParseAutomatedRotationFields() error comparing params; got %v, expected %v", p, tt.expectedParams)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestPopulateAutomatedRotationData(t *testing.T) {
 | |
| 	tests := []struct {
 | |
| 		name        string
 | |
| 		inputParams *AutomatedRotationParams
 | |
| 		expected    map[string]interface{}
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "basic",
 | |
| 			expected: map[string]interface{}{
 | |
| 				"rotation_schedule":          "*/15 * * * *",
 | |
| 				"rotation_window":            time.Duration(60).Seconds(),
 | |
| 				"rotation_period":            time.Duration(0).Seconds(),
 | |
| 				"disable_automated_rotation": false,
 | |
| 			},
 | |
| 			inputParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "*/15 * * * *",
 | |
| 				RotationWindow:           60,
 | |
| 				RotationPeriod:           0,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			m := make(map[string]interface{})
 | |
| 
 | |
| 			tt.inputParams.PopulateAutomatedRotationData(m)
 | |
| 
 | |
| 			if !reflect.DeepEqual(m, tt.expected) {
 | |
| 				t.Errorf("PopulateAutomatedRotationData() error comparing values; got %v, expected %v", m, tt.expected)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestShouldRegisterRotationJob(t *testing.T) {
 | |
| 	tests := []struct {
 | |
| 		name        string
 | |
| 		inputParams *AutomatedRotationParams
 | |
| 		expected    bool
 | |
| 	}{
 | |
| 		{
 | |
| 			name:     "false",
 | |
| 			expected: false,
 | |
| 			inputParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "",
 | |
| 				RotationWindow:           60,
 | |
| 				RotationPeriod:           0,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:     "true-schedule",
 | |
| 			expected: true,
 | |
| 			inputParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "*/15 * * * *",
 | |
| 				RotationWindow:           0,
 | |
| 				RotationPeriod:           0,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:     "true-period",
 | |
| 			expected: true,
 | |
| 			inputParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "",
 | |
| 				RotationWindow:           0,
 | |
| 				RotationPeriod:           5,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			out := tt.inputParams.ShouldRegisterRotationJob()
 | |
| 			if out != tt.expected {
 | |
| 				t.Errorf("ShouldRegisterRotationJob() output = %v, expected: %v", out, tt.expected)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestShouldDeregisterRotationJob(t *testing.T) {
 | |
| 	tests := []struct {
 | |
| 		name        string
 | |
| 		inputParams *AutomatedRotationParams
 | |
| 		expected    bool
 | |
| 	}{
 | |
| 		{
 | |
| 			name:     "zero out schedule and period",
 | |
| 			expected: true,
 | |
| 			inputParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "",
 | |
| 				RotationWindow:           60,
 | |
| 				RotationPeriod:           0,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:     "false-schedule set",
 | |
| 			expected: false,
 | |
| 			inputParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "*/15 * * * *",
 | |
| 				RotationWindow:           0,
 | |
| 				RotationPeriod:           0,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:     "false-period set",
 | |
| 			expected: false,
 | |
| 			inputParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "",
 | |
| 				RotationWindow:           0,
 | |
| 				RotationPeriod:           5,
 | |
| 				DisableAutomatedRotation: false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:     "true-disable set",
 | |
| 			expected: true,
 | |
| 			inputParams: &AutomatedRotationParams{
 | |
| 				RotationSchedule:         "*/15 * * * *",
 | |
| 				RotationWindow:           0,
 | |
| 				RotationPeriod:           0,
 | |
| 				DisableAutomatedRotation: true,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			out := tt.inputParams.ShouldDeregisterRotationJob()
 | |
| 			if out != tt.expected {
 | |
| 				t.Errorf("ShouldRegisterRotationJob() output = %v, expected: %v", out, tt.expected)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | 
