config: sort measurements numerically (#654)

* config: sort measurements numerically

* add comment to swap
This commit is contained in:
Thomas Tendyck 2022-11-28 11:09:39 +01:00 committed by GitHub
parent d52f3db2a3
commit 64f03cf675
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 98 additions and 0 deletions

View File

@ -17,10 +17,13 @@ import (
"io"
"net/http"
"net/url"
"sort"
"strconv"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/sigstore"
"github.com/google/go-tpm/tpmutil"
"github.com/talos-systems/talos/pkg/machinery/config/encoder"
"go.uber.org/multierr"
"gopkg.in/yaml.v3"
)
@ -45,6 +48,20 @@ type WithMetadata struct {
Measurements M `json:"measurements" yaml:"measurements"`
}
// MarshalYAML returns the YAML encoding of m.
func (m M) MarshalYAML() (any, error) {
// cast to prevent infinite recursion
node, err := encoder.NewEncoder(map[uint32]Measurement(m)).Marshal()
if err != nil {
return nil, err
}
// sort keys numerically
sort.Sort(mYamlContent(node.Content))
return node, nil
}
// FetchAndVerify fetches measurement and signature files via provided URLs,
// using client for download. The publicKey is used to verify the measurements.
// The hash of the fetched measurements is returned.
@ -338,3 +355,30 @@ type encodedMeasurement struct {
Expected string `json:"expected" yaml:"expected"`
WarnOnly bool `json:"warnOnly" yaml:"warnOnly"`
}
// mYamlContent is the Content of a yaml.Node encoding of an M. It implements sort.Interface.
// The slice is filled like {key1, value1, key2, value2, ...}.
type mYamlContent []*yaml.Node
func (c mYamlContent) Len() int {
return len(c) / 2
}
func (c mYamlContent) Less(i, j int) bool {
lhs, err := strconv.Atoi(c[2*i].Value)
if err != nil {
panic(err)
}
rhs, err := strconv.Atoi(c[2*j].Value)
if err != nil {
panic(err)
}
return lhs < rhs
}
func (c mYamlContent) Swap(i, j int) {
// The slice is filled like {key1, value1, key2, value2, ...}.
// We need to swap both key and value.
c[2*i], c[2*j] = c[2*j], c[2*i]
c[2*i+1], c[2*j+1] = c[2*j+1], c[2*i+1]
}

View File

@ -18,6 +18,7 @@ import (
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/talos-systems/talos/pkg/machinery/config/encoder"
"gopkg.in/yaml.v3"
)
@ -179,6 +180,59 @@ func TestUnmarshal(t *testing.T) {
}
}
func TestEncodeM(t *testing.T) {
testCases := map[string]struct {
m M
want string
}{
"basic": {
m: M{
1: WithAllBytes(1, false),
2: WithAllBytes(2, true),
},
want: `1:
expected: "0101010101010101010101010101010101010101010101010101010101010101"
warnOnly: false
2:
expected: "0202020202020202020202020202020202020202020202020202020202020202"
warnOnly: true
`,
},
"output is sorted": {
m: M{
3: {},
1: {},
11: {},
2: {},
},
want: `1:
expected: "0000000000000000000000000000000000000000000000000000000000000000"
warnOnly: false
2:
expected: "0000000000000000000000000000000000000000000000000000000000000000"
warnOnly: false
3:
expected: "0000000000000000000000000000000000000000000000000000000000000000"
warnOnly: false
11:
expected: "0000000000000000000000000000000000000000000000000000000000000000"
warnOnly: false
`,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
encoded, err := encoder.NewEncoder(tc.m).Encode()
require.NoError(err)
assert.Equal(tc.want, string(encoded))
})
}
}
func TestMeasurementsCopyFrom(t *testing.T) {
testCases := map[string]struct {
current M