Skip to content

Commit 6e7d788

Browse files
authored
Merge pull request #1936 from bruce-szalwinski-he/fix/destination-validation-bug
fix: correct destination validation logic to detect all conflicts
2 parents 21005da + fc5bd78 commit 6e7d788

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed

config/config.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,18 @@ func parseDestinationRuleForFile(conf *configFile, filePath string, kmsEncryptio
508508
}
509509

510510
var dest publish.Destination
511-
if dRule.S3Bucket != "" && dRule.GCSBucket != "" && dRule.VaultPath != "" {
511+
destinationCount := 0
512+
if dRule.S3Bucket != "" {
513+
destinationCount++
514+
}
515+
if dRule.GCSBucket != "" {
516+
destinationCount++
517+
}
518+
if dRule.VaultPath != "" {
519+
destinationCount++
520+
}
521+
522+
if destinationCount > 1 {
512523
return nil, fmt.Errorf("error loading config: more than one destinations were found in a single destination rule, you can only use one per rule")
513524
}
514525
if dRule.S3Bucket != "" {

config/config_test.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,3 +755,127 @@ creation_rules:
755755
assert.Equal(t, 1, keyTypeCounts["gcp_kms"])
756756
assert.Equal(t, 1, keyTypeCounts["hc_vault"])
757757
}
758+
759+
// Test configurations with multiple destinations should fail
760+
var sampleConfigWithS3GCSConflict = []byte(`
761+
destination_rules:
762+
- path_regex: '^test/.*'
763+
s3_bucket: 'my-s3-bucket'
764+
s3_prefix: 'sops/'
765+
gcs_bucket: 'my-gcs-bucket'
766+
gcs_prefix: 'sops/'
767+
recreation_rule:
768+
kms: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
769+
`)
770+
771+
var sampleConfigWithS3VaultConflict = []byte(`
772+
destination_rules:
773+
- path_regex: '^test/.*'
774+
s3_bucket: 'my-s3-bucket'
775+
s3_prefix: 'sops/'
776+
vault_path: 'secret/sops'
777+
vault_address: 'https://vault.example.com'
778+
recreation_rule:
779+
kms: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
780+
`)
781+
782+
var sampleConfigWithGCSVaultConflict = []byte(`
783+
destination_rules:
784+
- path_regex: '^test/.*'
785+
gcs_bucket: 'my-gcs-bucket'
786+
gcs_prefix: 'sops/'
787+
vault_path: 'secret/sops'
788+
vault_address: 'https://vault.example.com'
789+
recreation_rule:
790+
kms: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
791+
`)
792+
793+
var sampleConfigWithAllThreeDestinations = []byte(`
794+
destination_rules:
795+
- path_regex: '^test/.*'
796+
s3_bucket: 'my-s3-bucket'
797+
s3_prefix: 'sops/'
798+
gcs_bucket: 'my-gcs-bucket'
799+
gcs_prefix: 'sops/'
800+
vault_path: 'secret/sops'
801+
vault_address: 'https://vault.example.com'
802+
recreation_rule:
803+
kms: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
804+
`)
805+
806+
func TestDestinationValidationS3GCSConflict(t *testing.T) {
807+
_, err := parseDestinationRuleForFile(parseConfigFile(sampleConfigWithS3GCSConflict, t), "test/secrets.yaml", nil)
808+
assert.NotNil(t, err, "Expected error when both S3 and GCS destinations are specified")
809+
if err != nil {
810+
assert.Contains(t, err.Error(), "more than one destinations were found")
811+
}
812+
}
813+
814+
func TestDestinationValidationS3VaultConflict(t *testing.T) {
815+
_, err := parseDestinationRuleForFile(parseConfigFile(sampleConfigWithS3VaultConflict, t), "test/secrets.yaml", nil)
816+
assert.NotNil(t, err, "Expected error when both S3 and Vault destinations are specified")
817+
if err != nil {
818+
assert.Contains(t, err.Error(), "more than one destinations were found")
819+
}
820+
}
821+
822+
func TestDestinationValidationGCSVaultConflict(t *testing.T) {
823+
_, err := parseDestinationRuleForFile(parseConfigFile(sampleConfigWithGCSVaultConflict, t), "test/secrets.yaml", nil)
824+
assert.NotNil(t, err, "Expected error when both GCS and Vault destinations are specified")
825+
if err != nil {
826+
assert.Contains(t, err.Error(), "more than one destinations were found")
827+
}
828+
}
829+
830+
func TestDestinationValidationAllThreeDestinationsConflict(t *testing.T) {
831+
_, err := parseDestinationRuleForFile(parseConfigFile(sampleConfigWithAllThreeDestinations, t), "test/secrets.yaml", nil)
832+
assert.NotNil(t, err, "Expected error when all three destinations are specified")
833+
if err != nil {
834+
assert.Contains(t, err.Error(), "more than one destinations were found")
835+
}
836+
}
837+
838+
func TestDestinationValidationSingleS3Destination(t *testing.T) {
839+
validS3Config := []byte(`
840+
destination_rules:
841+
- path_regex: '^test/.*'
842+
s3_bucket: 'my-s3-bucket'
843+
s3_prefix: 'sops/'
844+
recreation_rule:
845+
kms: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
846+
`)
847+
conf, err := parseDestinationRuleForFile(parseConfigFile(validS3Config, t), "test/secrets.yaml", nil)
848+
assert.Nil(t, err)
849+
assert.NotNil(t, conf.Destination)
850+
assert.Contains(t, conf.Destination.Path("secrets.yaml"), "s3://my-s3-bucket/sops/secrets.yaml")
851+
}
852+
853+
func TestDestinationValidationSingleGCSDestination(t *testing.T) {
854+
validGCSConfig := []byte(`
855+
destination_rules:
856+
- path_regex: '^test/.*'
857+
gcs_bucket: 'my-gcs-bucket'
858+
gcs_prefix: 'sops/'
859+
recreation_rule:
860+
kms: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
861+
`)
862+
conf, err := parseDestinationRuleForFile(parseConfigFile(validGCSConfig, t), "test/secrets.yaml", nil)
863+
assert.Nil(t, err)
864+
assert.NotNil(t, conf.Destination)
865+
assert.Contains(t, conf.Destination.Path("secrets.yaml"), "gcs://my-gcs-bucket/sops/secrets.yaml")
866+
}
867+
868+
func TestDestinationValidationSingleVaultDestination(t *testing.T) {
869+
validVaultConfig := []byte(`
870+
destination_rules:
871+
- path_regex: '^test/.*'
872+
vault_path: 'secret/sops'
873+
vault_address: 'https://vault.example.com'
874+
recreation_rule:
875+
kms: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
876+
`)
877+
conf, err := parseDestinationRuleForFile(parseConfigFile(validVaultConfig, t), "test/secrets.yaml", nil)
878+
assert.Nil(t, err)
879+
assert.NotNil(t, conf.Destination)
880+
assert.Contains(t, conf.Destination.Path("secrets.yaml"), "https://vault.example.com/v1/secret/data/secret/sops/secrets.yaml")
881+
}

0 commit comments

Comments
 (0)