Skip to content

Commit

Permalink
feat: add resourceid package
Browse files Browse the repository at this point in the history
Forklifted from incubator repo, contains validation for user-settable
IDs and default implementation of system-generated IDs.
  • Loading branch information
odsod committed Dec 27, 2020
1 parent cca7f61 commit 75a3c2d
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.15

require (
github.com/golang/protobuf v1.4.3 // indirect
github.com/google/uuid v1.1.2
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d
google.golang.org/protobuf v1.25.0
gotest.tools/v3 v3.0.3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
Expand Down
8 changes: 8 additions & 0 deletions resourceid/systemgenerated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package resourceid

import "github.com/google/uuid"

// NewSystemGenerated returns a new system-generated resource ID.
func NewSystemGenerated() string {
return uuid.New().String()
}
15 changes: 15 additions & 0 deletions resourceid/systemgenerated_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package resourceid

import (
"regexp"
"testing"

"gotest.tools/v3/assert"
"gotest.tools/v3/assert/cmp"
)

func TestNewSystemGenerated(t *testing.T) {
t.Parallel()
const uuidV4Regexp = `^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`
assert.Assert(t, cmp.Regexp(regexp.MustCompile(uuidV4Regexp), NewSystemGenerated()))
}
48 changes: 48 additions & 0 deletions resourceid/usersettable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package resourceid

import (
"fmt"

"github.com/google/uuid"
)

// ValidateUserSettable validates a user-settable resource ID.
//
// From https://google.aip.dev/122#resource-id-segments:
//
// User-settable resource IDs should conform to RFC-1034,which restricts to letters, numbers, and hyphen, with a 63
// character maximum. Additionally, user-settable resource IDs should restrict letters to lower-case.
//
// User-settable IDs should not be permitted to be a UUID (or any value that syntactically appears to be a UUID).
//
// See also: https://google.aip.dev/133#user-specified-ids
func ValidateUserSettable(id string) error {
if len(id) < 4 || 63 < len(id) {
return fmt.Errorf("user-settable ID must be between 4 and 63 characters")
}
if id[0] == '-' {
return fmt.Errorf("user-settable ID must not start with a hyphen")
}
if _, err := uuid.Parse(id); err == nil {
return fmt.Errorf("user-settable ID must not be a valid UUIDv4")
}
for position, character := range id {
switch character {
case
// numbers
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
// hyphen
'-',
// lower-case
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z':
default:
return fmt.Errorf(
"user-settable ID must only contain lowercase, numbers and hyphens (got: '%c' in position %d)",
character,
position,
)
}
}
return nil
}
33 changes: 33 additions & 0 deletions resourceid/usersettable_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package resourceid

import (
"testing"

"gotest.tools/v3/assert"
)

func TestValidateUserSettable(t *testing.T) {
t.Parallel()
for _, tt := range []struct {
id string
errorContains string
}{
{id: "abcd"},
{id: "abcd-efgh-1234"},
{id: "abc", errorContains: "must be between 4 and 63 characters"},
{id: "-abc", errorContains: "must not start with a hyphen"},
{id: "daf1cb3e-f33b-43f1-81cc-e65fda51efa5", errorContains: "must not be a valid UUIDv4"},
{id: "abcd/efgh", errorContains: "must only contain lowercase, numbers and hyphens"},
} {
tt := tt
t.Run(tt.id, func(t *testing.T) {
t.Parallel()
err := ValidateUserSettable(tt.id)
if tt.errorContains != "" {
assert.ErrorContains(t, err, tt.errorContains)
} else {
assert.NilError(t, err)
}
})
}
}

0 comments on commit 75a3c2d

Please sign in to comment.