Skip to content

Commit 00d1ef6

Browse files
kylecarbsdwahler
andauthored
fix: Add check for duplicate metadata keys (#49)
* fix: Add check for duplicate metadata keys Fixes coder/coder#3721. * Update internal/provider/provider.go Co-authored-by: David Wahler <[email protected]> Co-authored-by: David Wahler <[email protected]>
1 parent 779f999 commit 00d1ef6

File tree

4 files changed

+51
-5
lines changed

4 files changed

+51
-5
lines changed

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
88
github.com/hashicorp/terraform-plugin-sdk/v2 v2.20.0
99
github.com/stretchr/testify v1.8.0
10+
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
1011
)
1112

1213
require (

go.sum

+1
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc
336336
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
337337
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
338338
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
339+
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
339340
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
340341
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
341342
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=

internal/provider/provider.go

+13-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package provider
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76
"net/url"
87
"os"
@@ -16,6 +15,7 @@ import (
1615
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1716
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1817
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
18+
"golang.org/x/xerrors"
1919
)
2020

2121
type config struct {
@@ -509,17 +509,24 @@ func populateIsNull(resourceData *schema.ResourceData) (result interface{}, err
509509
// The cty package reports type mismatches by panicking
510510
defer func() {
511511
if r := recover(); r != nil {
512-
err = errors.New(fmt.Sprintf("panic while handling coder_metadata: %#v", r))
512+
err = xerrors.Errorf("panic while handling coder_metadata: %#v", r)
513513
}
514514
}()
515515

516516
rawPlan := resourceData.GetRawPlan()
517517
items := rawPlan.GetAttr("item").AsValueSlice()
518518

519519
var resultItems []interface{}
520+
itemKeys := map[string]struct{}{}
520521
for _, item := range items {
522+
key := valueAsString(item.GetAttr("key"))
523+
_, exists := itemKeys[key]
524+
if exists {
525+
return nil, xerrors.Errorf("duplicate metadata key %q", key)
526+
}
527+
itemKeys[key] = struct{}{}
521528
resultItem := map[string]interface{}{
522-
"key": valueAsString(item.GetAttr("key")),
529+
"key": key,
523530
"value": valueAsString(item.GetAttr("value")),
524531
"sensitive": valueAsBool(item.GetAttr("sensitive")),
525532
}
@@ -532,9 +539,10 @@ func populateIsNull(resourceData *schema.ResourceData) (result interface{}, err
532539
return resultItems, nil
533540
}
534541

535-
// valueAsString takes a cty.Value that may be a string or null, and converts it to either a Go string
542+
// valueAsString takes a cty.Value that may be a string or null, and converts it to a Go string,
543+
// which will be empty if the input value was null.
536544
// or a nil interface{}
537-
func valueAsString(value cty.Value) interface{} {
545+
func valueAsString(value cty.Value) string {
538546
if value.IsNull() {
539547
return ""
540548
}

internal/provider/provider_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package provider_test
22

33
import (
4+
"regexp"
45
"runtime"
56
"testing"
67

@@ -324,3 +325,38 @@ func TestMetadata(t *testing.T) {
324325
}},
325326
})
326327
}
328+
329+
func TestMetadataDuplicateKeys(t *testing.T) {
330+
t.Parallel()
331+
prov := provider.New()
332+
resource.Test(t, resource.TestCase{
333+
Providers: map[string]*schema.Provider{
334+
"coder": prov,
335+
},
336+
IsUnitTest: true,
337+
Steps: []resource.TestStep{{
338+
Config: `
339+
provider "coder" {
340+
}
341+
resource "coder_agent" "dev" {
342+
os = "linux"
343+
arch = "amd64"
344+
}
345+
resource "coder_metadata" "agent" {
346+
resource_id = coder_agent.dev.id
347+
hide = true
348+
icon = "/icons/storage.svg"
349+
item {
350+
key = "foo"
351+
value = "bar"
352+
}
353+
item {
354+
key = "foo"
355+
value = "bar"
356+
}
357+
}
358+
`,
359+
ExpectError: regexp.MustCompile("duplicate metadata key"),
360+
}},
361+
})
362+
}

0 commit comments

Comments
 (0)