Skip to content

Commit 8d3f9a7

Browse files
committed
Restrict/warn overridding of pre/post definitions in tests and requires a manual flag
1 parent d9fbf9d commit 8d3f9a7

File tree

7 files changed

+431
-1
lines changed

7 files changed

+431
-1
lines changed

pkg/api/types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,10 @@ type MultiStageTestConfiguration struct {
12321232
// NodeArchitectureOverrides is a map that allows overriding the node architecture for specific steps
12331233
// that exist in the Pre, Test and Post steps. The key is the name of the step and the value is the architecture.
12341234
NodeArchitectureOverrides NodeArchitectureOverrides `json:"node_architecture_overrides,omitempty"`
1235+
// AllowPrePostStepOverrides must be set to true when a test configuration overrides the pre or post steps
1236+
// from a workflow. This is a safety mechanism to prevent accidental overriding of critical setup and
1237+
// teardown steps that could cause resource leaks.
1238+
AllowPrePostStepOverrides *bool `json:"allow_pre_post_step_overrides,omitempty"`
12351239
}
12361240

12371241
type NodeArchitectureOverrides map[string]NodeArchitecture

pkg/api/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/registry/resolver.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func NewResolver(stepsByName ReferenceByName, chainsByName ChainByName, workflow
6868

6969
func (r *registry) Resolve(name string, config api.MultiStageTestConfiguration) (api.MultiStageTestConfigurationLiteral, error) {
7070
var overridden [][]api.TestStep
71+
7172
if config.Workflow != nil {
7273
var errs []error
7374
overridden, errs = r.mergeWorkflow(&config)
@@ -103,6 +104,7 @@ func (r *registry) mergeWorkflow(config *api.MultiStageTestConfiguration) ([][]a
103104
} else {
104105
overridden = append(overridden, workflow.Post)
105106
}
107+
106108
config.Environment = mergeEnvironments(workflow.Environment, config.Environment)
107109
config.Dependencies = mergeDependencies(workflow.Dependencies, config.Dependencies)
108110
config.DependencyOverrides = mergeDependencyOverrides(workflow.DependencyOverrides, config.DependencyOverrides)
@@ -410,7 +412,7 @@ func ResolveConfig(resolver Resolver, config api.ReleaseBuildConfiguration) (api
410412

411413
resolvedConfig, err := resolver.Resolve(step.As, *step.MultiStageTestConfiguration)
412414
if err != nil {
413-
return api.ReleaseBuildConfiguration{}, fmt.Errorf("Failed resolve MultiStageTestConfiguration: %w", err)
415+
return api.ReleaseBuildConfiguration{}, fmt.Errorf("failed to resolve MultiStageTestConfiguration: %w", err)
414416
}
415417
step.MultiStageTestConfigurationLiteral = &resolvedConfig
416418
// remove old multi stage config

pkg/validation/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ type Validator struct {
2020
validClusterClaimOwners api.ClusterClaimOwnersMap
2121
// hasTrapCache avoids redundant regexp searches on step commands.
2222
hasTrapCache map[string]bool
23+
// workflowsByName holds workflows for pre/post override validation
24+
workflowsByName map[string]api.MultiStageTestConfiguration
2325
}
2426

2527
// NewValidator creates an object that optimizes bulk validations.
@@ -36,6 +38,13 @@ func NewValidator(profiles api.ClusterProfilesMap, clusterClaimOwners api.Cluste
3638
return ret
3739
}
3840

41+
// NewValidatorWithWorkflows creates a validator with workflow information for pre/post override validation.
42+
func NewValidatorWithWorkflows(profiles api.ClusterProfilesMap, clusterClaimOwners api.ClusterClaimOwnersMap, workflowsByName map[string]api.MultiStageTestConfiguration) Validator {
43+
ret := NewValidator(profiles, clusterClaimOwners)
44+
ret.workflowsByName = workflowsByName
45+
return ret
46+
}
47+
3948
func newSingleUseValidator() Validator {
4049
return Validator{}
4150
}

pkg/validation/test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,35 @@ func validateTestStepDependencies(config *api.ReleaseBuildConfiguration) []error
428428
return errs
429429
}
430430

431+
// validateWorkflowOverrides validates that tests properly acknowledge when they override workflow pre/post steps
432+
func (v *Validator) validateWorkflowOverrides(config api.MultiStageTestConfiguration) error {
433+
if config.Workflow == nil {
434+
return nil
435+
}
436+
437+
workflow, ok := v.workflowsByName[*config.Workflow]
438+
if !ok {
439+
// This will be caught by mergeWorkflow, no need to duplicate the error
440+
return nil
441+
}
442+
443+
hasPreOverride := len(config.Pre) > 0 && len(workflow.Pre) > 0
444+
hasPostOverride := len(config.Post) > 0 && len(workflow.Post) > 0
445+
446+
if (hasPreOverride || hasPostOverride) && (config.AllowPrePostStepOverrides == nil || !*config.AllowPrePostStepOverrides) {
447+
var overriddenSections []string
448+
if hasPreOverride {
449+
overriddenSections = append(overriddenSections, "pre")
450+
}
451+
if hasPostOverride {
452+
overriddenSections = append(overriddenSections, "post")
453+
}
454+
return fmt.Errorf("test configuration overrides %s steps from workflow %q but does not have 'allow_pre_post_step_overrides: true' set. This flag is required to prevent accidental overriding of critical setup and teardown steps that could cause resource leaks", strings.Join(overriddenSections, " and "), *config.Workflow)
455+
}
456+
457+
return nil
458+
}
459+
431460
func (v *Validator) validateClusterProfile(fieldRoot string, p api.ClusterProfile, metadata *api.Metadata) []error {
432461
if v.validClusterProfiles != nil {
433462
if _, ok := v.validClusterProfiles[p]; ok {
@@ -602,6 +631,13 @@ func (v *Validator) validateTestConfigurationType(
602631
if testConfig.NodeArchitecture != nil {
603632
validationErrors = append(validationErrors, validateNodeArchitecture(fieldRoot, *testConfig.NodeArchitecture))
604633
}
634+
635+
// Validate workflow overrides if workflow registry is available
636+
if v.workflowsByName != nil {
637+
if err := v.validateWorkflowOverrides(*testConfig); err != nil {
638+
validationErrors = append(validationErrors, err)
639+
}
640+
}
605641
validationErrors = append(validationErrors, v.validateTestSteps(context.addField("pre"), testStagePre, testConfig.Pre, claimRelease)...)
606642
validationErrors = append(validationErrors, v.validateTestSteps(context.addField("test"), testStageTest, testConfig.Test, claimRelease)...)
607643
validationErrors = append(validationErrors, v.validateTestSteps(context.addField("post"), testStagePost, testConfig.Post, claimRelease)...)

0 commit comments

Comments
 (0)