Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit48e2cb8

Browse files
committed
fix: validate that parameter names are unique
1 parent7ec16cf commit48e2cb8

File tree

4 files changed

+115
-0
lines changed

4 files changed

+115
-0
lines changed

‎coderd/util/slice/slice.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package slice
22

3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
38
// SameElements returns true if the 2 lists have the same elements in any
49
// order.
510
funcSameElements[Tcomparable](a []T,b []T)bool {
@@ -67,3 +72,16 @@ func OverlapCompare[T any](a []T, b []T, equal func(a, b T) bool) bool {
6772
funcNew[Tany](items...T) []T {
6873
returnitems
6974
}
75+
76+
// JoinWithConjunction joins a slice of strings with commas except for the last
77+
// two which are joined with "and".
78+
funcJoinWithConjunction(s []string)string {
79+
last:=len(s)-1
80+
iflast==0 {
81+
returns[last]
82+
}
83+
returnfmt.Sprintf("%s and %s",
84+
strings.Join(s[:last],", "),
85+
s[last],
86+
)
87+
}

‎coderd/util/slice/slice_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ func TestOverlap(t *testing.T) {
8383
)
8484
}
8585

86+
funcTestJoinWithConjunction(t*testing.T) {
87+
t.Parallel()
88+
require.Equal(t,"foo",slice.JoinWithConjunction([]string{"foo"}))
89+
require.Equal(t,"foo and bar",slice.JoinWithConjunction([]string{"foo","bar"}))
90+
require.Equal(t,"foo, bar and baz",slice.JoinWithConjunction([]string{"foo","bar","baz"}))
91+
}
92+
8693
funcassertSetOverlaps[Tcomparable](t*testing.T,overlapbool,a []T,b []T) {
8794
t.Helper()
8895
for_,e:=rangea {

‎provisioner/terraform/resources.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package terraform
22

33
import (
4+
"fmt"
45
"strings"
56

67
"github.com/awalterschulze/gographviz"
@@ -10,6 +11,7 @@ import (
1011

1112
"github.com/coder/terraform-provider-coder/provider"
1213

14+
"github.com/coder/coder/coderd/util/slice"
1315
"github.com/coder/coder/provisioner"
1416
"github.com/coder/coder/provisionersdk/proto"
1517
)
@@ -462,6 +464,7 @@ func ConvertState(modules []*tfjson.StateModule, rawGraph string, rawParameterNa
462464
}
463465
}
464466

467+
varduplicatedNames []string
465468
parameters:=make([]*proto.RichParameter,0)
466469
for_,resource:=rangeorderedRichParametersResources(tfResourcesRichParameters,rawParameterNames) {
467470
varparam provider.Parameter
@@ -525,9 +528,32 @@ func ConvertState(modules []*tfjson.StateModule, rawGraph string, rawParameterNa
525528
})
526529
}
527530
}
531+
532+
// Check if this parameter duplicates an existing parameter.
533+
formattedName:=fmt.Sprintf("%q",protoParam.Name)
534+
if!slice.Contains(duplicatedNames,formattedName)&&
535+
slice.ContainsCompare(parameters,protoParam,func(a,b*proto.RichParameter)bool {
536+
returna.Name==b.Name
537+
}) {
538+
duplicatedNames=append(duplicatedNames,formattedName)
539+
}
540+
528541
parameters=append(parameters,protoParam)
529542
}
530543

544+
// Enforce that parameters must be uniquely named.
545+
iflen(duplicatedNames)>0 {
546+
s:=""
547+
iflen(duplicatedNames)==1 {
548+
s="s"
549+
}
550+
returnnil,xerrors.Errorf(
551+
"coder_parameter names must be unique but %s appear%s multiple times",
552+
slice.JoinWithConjunction(duplicatedNames),
553+
s,
554+
)
555+
}
556+
531557
// A map is used to ensure we don't have duplicates!
532558
gitAuthProvidersMap:=map[string]struct{}{}
533559
for_,tfResources:=rangetfResourcesByLabel {

‎provisioner/terraform/resources_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package terraform_test
22

33
import (
44
"encoding/json"
5+
"fmt"
56
"os"
67
"path/filepath"
78
"runtime"
@@ -575,6 +576,69 @@ func TestAppSlugValidation(t *testing.T) {
575576
require.ErrorContains(t,err,"duplicate app slug")
576577
}
577578

579+
funcTestParameterValidation(t*testing.T) {
580+
t.Parallel()
581+
582+
// nolint:dogsled
583+
_,filename,_,_:=runtime.Caller(0)
584+
585+
// Load the rich-parameters state file and edit it.
586+
dir:=filepath.Join(filepath.Dir(filename),"testdata","rich-parameters")
587+
tfPlanRaw,err:=os.ReadFile(filepath.Join(dir,"rich-parameters.tfplan.json"))
588+
require.NoError(t,err)
589+
vartfPlan tfjson.Plan
590+
err=json.Unmarshal(tfPlanRaw,&tfPlan)
591+
require.NoError(t,err)
592+
tfPlanGraph,err:=os.ReadFile(filepath.Join(dir,"rich-parameters.tfplan.dot"))
593+
require.NoError(t,err)
594+
595+
// Change all names to be identical.
596+
varnames []string
597+
for_,resource:=rangetfPlan.PriorState.Values.RootModule.Resources {
598+
ifresource.Type=="coder_parameter" {
599+
resource.AttributeValues["name"]="identical"
600+
names=append(names,resource.Name)
601+
}
602+
}
603+
604+
state,err:=terraform.ConvertState([]*tfjson.StateModule{tfPlan.PriorState.Values.RootModule},string(tfPlanGraph),names)
605+
require.Nil(t,state)
606+
require.Error(t,err)
607+
require.ErrorContains(t,err,"coder_parameter names must be unique but\"identical\" appears multiple times")
608+
609+
// Make two sets of identical names.
610+
count:=0
611+
names=nil
612+
for_,resource:=rangetfPlan.PriorState.Values.RootModule.Resources {
613+
ifresource.Type=="coder_parameter" {
614+
resource.AttributeValues["name"]=fmt.Sprintf("identical-%d",count%2)
615+
names=append(names,resource.Name)
616+
count++
617+
}
618+
}
619+
620+
state,err=terraform.ConvertState([]*tfjson.StateModule{tfPlan.PriorState.Values.RootModule},string(tfPlanGraph),names)
621+
require.Nil(t,state)
622+
require.Error(t,err)
623+
require.ErrorContains(t,err,"coder_parameter names must be unique but\"identical-0\" and\"identical-1\" appear multiple times")
624+
625+
// Once more with three sets.
626+
count=0
627+
names=nil
628+
for_,resource:=rangetfPlan.PriorState.Values.RootModule.Resources {
629+
ifresource.Type=="coder_parameter" {
630+
resource.AttributeValues["name"]=fmt.Sprintf("identical-%d",count%3)
631+
names=append(names,resource.Name)
632+
count++
633+
}
634+
}
635+
636+
state,err=terraform.ConvertState([]*tfjson.StateModule{tfPlan.PriorState.Values.RootModule},string(tfPlanGraph),names)
637+
require.Nil(t,state)
638+
require.Error(t,err)
639+
require.ErrorContains(t,err,"coder_parameter names must be unique but\"identical-0\",\"identical-1\" and\"identical-2\" appear multiple times")
640+
}
641+
578642
funcTestInstanceTypeAssociation(t*testing.T) {
579643
t.Parallel()
580644
typetcstruct {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp