Skip to content

Commit

Permalink
Implement text marshaling for ID/TrustDomain types (#180)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Harding <[email protected]>
  • Loading branch information
azdagron authored Feb 28, 2022
1 parent 73bc825 commit 40dfa55
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 0 deletions.
24 changes: 24 additions & 0 deletions v2/spiffeid/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,27 @@ func (id ID) ReplaceSegments(segments ...string) (ID, error) {
id.path = path
return id, nil
}

// MarshalText returns a text representation of the ID. If the ID is the zero
// value, nil is returned.
func (id ID) MarshalText() ([]byte, error) {
if id.IsZero() {
return nil, nil
}
return []byte(id.String()), nil
}

// UnmarshalText decodes a text representation of the ID. If the text is empty,
// the ID is set to the zero value.
func (id *ID) UnmarshalText(text []byte) error {
if len(text) == 0 {
*id = ID{}
return nil
}
unmarshaled, err := FromString(string(text))
if err != nil {
return err
}
*id = unmarshaled
return nil
}
35 changes: 35 additions & 0 deletions v2/spiffeid/id_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package spiffeid_test

import (
"encoding/json"
"fmt"
"net/url"
"testing"
Expand Down Expand Up @@ -426,6 +427,40 @@ func TestIDIsZero(t *testing.T) {
assert.False(t, td.ID().IsZero())
}

func TestIDTextMarshaler(t *testing.T) {
var s struct {
ID spiffeid.ID `json:"id"`
}

marshaled, err := json.Marshal(s)
require.NoError(t, err)
require.JSONEq(t, `{"id": ""}`, string(marshaled))

s.ID = spiffeid.RequireFromString("spiffe://trustdomain/path")

marshaled, err = json.Marshal(s)
require.NoError(t, err)
require.JSONEq(t, `{"id": "spiffe://trustdomain/path"}`, string(marshaled))
}

func TestIDTextUnmarshaler(t *testing.T) {
var s struct {
ID spiffeid.ID `json:"id"`
}

err := json.Unmarshal([]byte(`{"id": ""}`), &s)
require.NoError(t, err)
require.Zero(t, s.ID)

err = json.Unmarshal([]byte(`{"id": "BAD"}`), &s)
require.EqualError(t, err, "scheme is missing or invalid")
require.Zero(t, s.ID)

err = json.Unmarshal([]byte(`{"id": "spiffe://trustdomain/path"}`), &s)
require.NoError(t, err)
require.Equal(t, "spiffe://trustdomain/path", s.ID.String())
}

func assertIDEqual(t *testing.T, id spiffeid.ID, expectTD spiffeid.TrustDomain, expectPath string) {
assert.Equal(t, expectTD, id.TrustDomain(), "unexpected trust domain")
assert.Equal(t, expectPath, id.Path(), "unexpected path")
Expand Down
25 changes: 25 additions & 0 deletions v2/spiffeid/trustdomain.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,31 @@ func (td TrustDomain) Compare(other TrustDomain) int {
return strings.Compare(td.name, other.name)
}

// MarshalText returns a text representation of the trust domain. If the trust
// domain is the zero value, nil is returned.
func (td TrustDomain) MarshalText() ([]byte, error) {
if td.IsZero() {
return nil, nil
}
return []byte(td.String()), nil
}

// UnmarshalText decodes a text representation of the trust domain. If the text
// is empty, the trust domain is set to the zero value.
func (td *TrustDomain) UnmarshalText(text []byte) error {
if len(text) == 0 {
*td = TrustDomain{}
return nil
}

unmarshaled, err := TrustDomainFromString(string(text))
if err != nil {
return err
}
*td = unmarshaled
return nil
}

func isValidTrustDomainChar(c uint8) bool {
switch {
case c >= 'a' && c <= 'z':
Expand Down
35 changes: 35 additions & 0 deletions v2/spiffeid/trustdomain_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package spiffeid_test

import (
"encoding/json"
"fmt"
"net/url"
"testing"
Expand Down Expand Up @@ -131,3 +132,37 @@ func TestTrustDomainCompare(t *testing.T) {
assert.Equal(t, 0, a.Compare(a))
assert.Equal(t, 1, b.Compare(a))
}

func TestTrustDomainTextMarshaler(t *testing.T) {
var s struct {
TrustDomain spiffeid.TrustDomain `json:"trustDomain"`
}

marshaled, err := json.Marshal(s)
require.NoError(t, err)
require.JSONEq(t, `{"trustDomain": ""}`, string(marshaled))

s.TrustDomain = spiffeid.RequireTrustDomainFromString("trustdomain")

marshaled, err = json.Marshal(s)
require.NoError(t, err)
require.JSONEq(t, `{"trustDomain": "trustdomain"}`, string(marshaled))
}

func TestTrustDomainTextUnmarshaler(t *testing.T) {
var s struct {
TrustDomain spiffeid.TrustDomain `json:"trustDomain"`
}

err := json.Unmarshal([]byte(`{"trustDomain": ""}`), &s)
require.NoError(t, err)
require.Zero(t, s.TrustDomain)

err = json.Unmarshal([]byte(`{"trustDomain": "BAD"}`), &s)
require.EqualError(t, err, "trust domain characters are limited to lowercase letters, numbers, dots, dashes, and underscores")
require.Zero(t, s.TrustDomain)

err = json.Unmarshal([]byte(`{"trustDomain": "trustdomain"}`), &s)
require.NoError(t, err)
require.Equal(t, "trustdomain", s.TrustDomain.String())
}

0 comments on commit 40dfa55

Please sign in to comment.