Skip to content

Commit

Permalink
fix: Add check for duplicate metadata keys (#49)
Browse files Browse the repository at this point in the history
* fix: Add check for duplicate metadata keys

Fixes coder/coder#3721.

* Update internal/provider/provider.go

Co-authored-by: David Wahler <david@coder.com>

Co-authored-by: David Wahler <david@coder.com>
  • Loading branch information
kylecarbs and dwahler authored Sep 13, 2022
1 parent 779f999 commit 00d1ef6
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 5 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
github.com/hashicorp/terraform-plugin-sdk/v2 v2.20.0
github.com/stretchr/testify v1.8.0
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
)

require (
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
Expand Down
18 changes: 13 additions & 5 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package provider

import (
"context"
"errors"
"fmt"
"net/url"
"os"
Expand All @@ -16,6 +15,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"golang.org/x/xerrors"
)

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

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

var resultItems []interface{}
itemKeys := map[string]struct{}{}
for _, item := range items {
key := valueAsString(item.GetAttr("key"))
_, exists := itemKeys[key]
if exists {
return nil, xerrors.Errorf("duplicate metadata key %q", key)
}
itemKeys[key] = struct{}{}
resultItem := map[string]interface{}{
"key": valueAsString(item.GetAttr("key")),
"key": key,
"value": valueAsString(item.GetAttr("value")),
"sensitive": valueAsBool(item.GetAttr("sensitive")),
}
Expand All @@ -532,9 +539,10 @@ func populateIsNull(resourceData *schema.ResourceData) (result interface{}, err
return resultItems, nil
}

// valueAsString takes a cty.Value that may be a string or null, and converts it to either a Go string
// valueAsString takes a cty.Value that may be a string or null, and converts it to a Go string,
// which will be empty if the input value was null.
// or a nil interface{}
func valueAsString(value cty.Value) interface{} {
func valueAsString(value cty.Value) string {
if value.IsNull() {
return ""
}
Expand Down
36 changes: 36 additions & 0 deletions internal/provider/provider_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package provider_test

import (
"regexp"
"runtime"
"testing"

Expand Down Expand Up @@ -324,3 +325,38 @@ func TestMetadata(t *testing.T) {
}},
})
}

func TestMetadataDuplicateKeys(t *testing.T) {
t.Parallel()
prov := provider.New()
resource.Test(t, resource.TestCase{
Providers: map[string]*schema.Provider{
"coder": prov,
},
IsUnitTest: true,
Steps: []resource.TestStep{{
Config: `
provider "coder" {
}
resource "coder_agent" "dev" {
os = "linux"
arch = "amd64"
}
resource "coder_metadata" "agent" {
resource_id = coder_agent.dev.id
hide = true
icon = "/icons/storage.svg"
item {
key = "foo"
value = "bar"
}
item {
key = "foo"
value = "bar"
}
}
`,
ExpectError: regexp.MustCompile("duplicate metadata key"),
}},
})
}

0 comments on commit 00d1ef6

Please sign in to comment.