From a8605d7294e8010834ecccd21a8f641ed8666f0b Mon Sep 17 00:00:00 2001 From: Moritz Sanft <58110325+msanft@users.noreply.github.com> Date: Tue, 17 Oct 2023 10:35:54 +0200 Subject: [PATCH] cli: use custom byte-slice marshalling for state file (#2460) * custom byte slice marshalling Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * byte slice compatibility Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * other byte slice compat test Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add missing dep Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * export byte type alias Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * regenerate exported type Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * test marshal and unmarshal together Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> --------- Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> --- bazel/toolchains/go_module_deps.bzl | 4 +- cli/internal/state/BUILD.bazel | 2 + cli/internal/state/state.go | 35 +++++++- cli/internal/state/state_doc.go | 4 +- cli/internal/state/state_test.go | 93 ++++++++++++++++++++ cli/internal/terraform/BUILD.bazel | 1 + cli/internal/terraform/terraform_test.go | 3 +- go.mod | 2 +- go.sum | 4 +- hack/go.mod | 2 +- hack/go.sum | 4 +- operators/constellation-node-operator/go.mod | 2 +- operators/constellation-node-operator/go.sum | 4 +- 13 files changed, 144 insertions(+), 16 deletions(-) diff --git a/bazel/toolchains/go_module_deps.bzl b/bazel/toolchains/go_module_deps.bzl index 1df2a8b47..2d7683cee 100644 --- a/bazel/toolchains/go_module_deps.bzl +++ b/bazel/toolchains/go_module_deps.bzl @@ -7401,8 +7401,8 @@ def go_dependencies(): build_file_generation = "on", build_file_proto_mode = "disable_global", importpath = "golang.org/x/net", - sum = "h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=", - version = "v0.17.0", + sum = "h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos=", + version = "v0.16.0", ) go_repository( name = "org_golang_x_oauth2", diff --git a/cli/internal/state/BUILD.bazel b/cli/internal/state/BUILD.bazel index 5d5e62607..55613a0f1 100644 --- a/cli/internal/state/BUILD.bazel +++ b/cli/internal/state/BUILD.bazel @@ -26,5 +26,7 @@ go_test( "@com_github_siderolabs_talos_pkg_machinery//config/encoder", "@com_github_spf13_afero//:afero", "@com_github_stretchr_testify//assert", + "@com_github_stretchr_testify//require", + "@in_gopkg_yaml_v3//:yaml_v3", ], ) diff --git a/cli/internal/state/state.go b/cli/internal/state/state.go index e1283d4a2..14bbb59cc 100644 --- a/cli/internal/state/state.go +++ b/cli/internal/state/state.go @@ -13,6 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only package state import ( + "encoding/hex" "fmt" "dario.cat/mergo" @@ -63,7 +64,7 @@ type ClusterValues struct { OwnerID string `yaml:"ownerID"` // description: | // Salt used to generate the ClusterID on the bootstrapping node. - MeasurementSalt []byte `yaml:"measurementSalt"` + MeasurementSalt HexBytes `yaml:"measurementSalt"` } // Infrastructure describe the state related to the cloud resources of the cluster. @@ -76,7 +77,7 @@ type Infrastructure struct { ClusterEndpoint string `yaml:"clusterEndpoint"` // description: | // Secret used to authenticate the bootstrapping node. - InitSecret []byte `yaml:"initSecret"` + InitSecret HexBytes `yaml:"initSecret"` // description: | // List of Subject Alternative Names (SANs) to add to the Kubernetes API server certificate. // If no SANs should be added, this field can be left empty. @@ -164,3 +165,33 @@ func (s *State) Merge(other *State) (*State, error) { } return s, nil } + +// HexBytes is a byte slice that is marshalled to and from a hex string. +type HexBytes []byte + +// UnmarshalYAML implements the yaml.Unmarshaler interface. +func (h *HexBytes) UnmarshalYAML(unmarshal func(any) error) error { + var hexString string + if err := unmarshal(&hexString); err != nil { + // TODO(msanft): Remove with v2.14.0 + // fall back to unmarshalling as a byte slice for backwards compatibility + var oldHexBytes []byte + if err := unmarshal(&oldHexBytes); err != nil { + return fmt.Errorf("unmarshalling hex bytes: %w", err) + } + hexString = hex.EncodeToString(oldHexBytes) + } + + bytes, err := hex.DecodeString(hexString) + if err != nil { + return fmt.Errorf("decoding hex bytes: %w", err) + } + + *h = bytes + return nil +} + +// MarshalYAML implements the yaml.Marshaler interface. +func (h HexBytes) MarshalYAML() (any, error) { + return hex.EncodeToString(h), nil +} diff --git a/cli/internal/state/state_doc.go b/cli/internal/state/state_doc.go index c57088ac3..ff9455e98 100644 --- a/cli/internal/state/state_doc.go +++ b/cli/internal/state/state_doc.go @@ -60,7 +60,7 @@ func init() { ClusterValuesDoc.Fields[1].Description = "Unique identifier of the owner of the cluster." ClusterValuesDoc.Fields[1].Comments[encoder.LineComment] = "Unique identifier of the owner of the cluster." ClusterValuesDoc.Fields[2].Name = "measurementSalt" - ClusterValuesDoc.Fields[2].Type = "[]byte" + ClusterValuesDoc.Fields[2].Type = "HexBytes" ClusterValuesDoc.Fields[2].Note = "" ClusterValuesDoc.Fields[2].Description = "Salt used to generate the ClusterID on the bootstrapping node." ClusterValuesDoc.Fields[2].Comments[encoder.LineComment] = "Salt used to generate the ClusterID on the bootstrapping node." @@ -86,7 +86,7 @@ func init() { InfrastructureDoc.Fields[1].Description = "Endpoint the cluster can be reached at." InfrastructureDoc.Fields[1].Comments[encoder.LineComment] = "Endpoint the cluster can be reached at." InfrastructureDoc.Fields[2].Name = "initSecret" - InfrastructureDoc.Fields[2].Type = "[]byte" + InfrastructureDoc.Fields[2].Type = "HexBytes" InfrastructureDoc.Fields[2].Note = "" InfrastructureDoc.Fields[2].Description = "Secret used to authenticate the bootstrapping node." InfrastructureDoc.Fields[2].Comments[encoder.LineComment] = "Secret used to authenticate the bootstrapping node." diff --git a/cli/internal/state/state_test.go b/cli/internal/state/state_test.go index 96311977e..891b031eb 100644 --- a/cli/internal/state/state_test.go +++ b/cli/internal/state/state_test.go @@ -14,6 +14,8 @@ import ( "github.com/siderolabs/talos/pkg/machinery/config/encoder" "github.com/spf13/afero" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" ) var defaultState = &State{ @@ -326,3 +328,94 @@ func TestMerge(t *testing.T) { }) } } + +func TestMarshalHexBytes(t *testing.T) { + testCases := map[string]struct { + in HexBytes + expected string + wantErr bool + }{ + "success": { + in: []byte{0xab, 0xcd, 0xef}, + expected: "abcdef\n", + }, + "empty": { + in: []byte{}, + expected: "\"\"\n", + }, + "nil": { + in: nil, + expected: "\"\"\n", + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + + actual, err := yaml.Marshal(tc.in) + + if tc.wantErr { + assert.Error(err) + } else { + assert.NoError(err) + assert.Equal(tc.expected, string(actual)) + } + }) + } +} + +func TestUnmarshalHexBytes(t *testing.T) { + testCases := map[string]struct { + in string + expected HexBytes + wantErr bool + }{ + "success": { + in: "abcdef", + expected: []byte{0xab, 0xcd, 0xef}, + }, + "empty": { + in: "", + expected: nil, + }, + "byte slice compat": { + in: "[0xab, 0xcd, 0xef]", + expected: []byte{0xab, 0xcd, 0xef}, + }, + "byte slice compat 2": { + in: "[00, 12, 34]", + expected: []byte{0x00, 0x0c, 0x22}, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + + var actual HexBytes + err := yaml.Unmarshal([]byte(tc.in), &actual) + + if tc.wantErr { + assert.Error(err) + } else { + assert.NoError(err) + assert.Equal(tc.expected, actual) + } + }) + } +} + +func TestMarshalUnmarshalHexBytes(t *testing.T) { + in := HexBytes{0xab, 0xcd, 0xef} + expected := "abcdef\n" + + actual, err := yaml.Marshal(in) + require.NoError(t, err) + assert.Equal(t, expected, string(actual)) + + var actual2 HexBytes + err = yaml.Unmarshal(actual, &actual2) + require.NoError(t, err) + assert.Equal(t, in, actual2) +} diff --git a/cli/internal/terraform/BUILD.bazel b/cli/internal/terraform/BUILD.bazel index 56e999818..2078d35b9 100644 --- a/cli/internal/terraform/BUILD.bazel +++ b/cli/internal/terraform/BUILD.bazel @@ -106,6 +106,7 @@ go_test( ], embed = [":terraform"], deps = [ + "//cli/internal/state", "//internal/cloud/cloudprovider", "//internal/constants", "//internal/file", diff --git a/cli/internal/terraform/terraform_test.go b/cli/internal/terraform/terraform_test.go index dd9a94be3..09e91d300 100644 --- a/cli/internal/terraform/terraform_test.go +++ b/cli/internal/terraform/terraform_test.go @@ -16,6 +16,7 @@ import ( "strings" "testing" + "github.com/edgelesssys/constellation/v2/cli/internal/state" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/file" @@ -477,7 +478,7 @@ func TestCreateCluster(t *testing.T) { } assert.NoError(err) assert.Equal("192.0.2.100", infraState.ClusterEndpoint) - assert.Equal([]byte("initSecret"), infraState.InitSecret) + assert.Equal(state.HexBytes("initSecret"), infraState.InitSecret) assert.Equal("12345abc", infraState.UID) if tc.provider == cloudprovider.Azure { assert.Equal(tc.expectedAttestationURL, infraState.Azure.AttestationURL) diff --git a/go.mod b/go.mod index d781a3ffc..fdb46dd7b 100644 --- a/go.mod +++ b/go.mod @@ -322,7 +322,7 @@ require ( go.starlark.net v0.0.0-20220223235035-243c74974e97 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/net v0.16.0 // indirect golang.org/x/oauth2 v0.9.0 // indirect golang.org/x/sync v0.4.0 // indirect golang.org/x/term v0.13.0 // indirect diff --git a/go.sum b/go.sum index 991f8e083..432dee836 100644 --- a/go.sum +++ b/go.sum @@ -1274,8 +1274,8 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/hack/go.mod b/hack/go.mod index bacd4e3da..8de51c9d0 100644 --- a/hack/go.mod +++ b/hack/go.mod @@ -274,7 +274,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/net v0.16.0 // indirect golang.org/x/oauth2 v0.9.0 // indirect golang.org/x/sync v0.4.0 // indirect golang.org/x/sys v0.13.0 // indirect diff --git a/hack/go.sum b/hack/go.sum index 138c43573..89b131113 100644 --- a/hack/go.sum +++ b/hack/go.sum @@ -1215,8 +1215,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/operators/constellation-node-operator/go.mod b/operators/constellation-node-operator/go.mod index d0447ef47..c759b924b 100644 --- a/operators/constellation-node-operator/go.mod +++ b/operators/constellation-node-operator/go.mod @@ -106,7 +106,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/net v0.16.0 // indirect golang.org/x/oauth2 v0.9.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect diff --git a/operators/constellation-node-operator/go.sum b/operators/constellation-node-operator/go.sum index 0b7f0e575..4e4cd9355 100644 --- a/operators/constellation-node-operator/go.sum +++ b/operators/constellation-node-operator/go.sum @@ -435,8 +435,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=