diff --git a/internal/api/attestationconfigapi/BUILD.bazel b/internal/api/attestationconfigapi/BUILD.bazel index 5db942eb3..39f3bf5a3 100644 --- a/internal/api/attestationconfigapi/BUILD.bazel +++ b/internal/api/attestationconfigapi/BUILD.bazel @@ -5,31 +5,23 @@ go_library( name = "attestationconfigapi", srcs = [ "attestationconfigapi.go", - "client.go", "fetcher.go", - "reporter.go", "snp.go", ], importpath = "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi", visibility = ["//:__subpackages__"], deps = [ - "//internal/api/client", "//internal/api/fetcher", "//internal/attestation/variant", "//internal/constants", "//internal/sigstore", - "//internal/staticupload", - "@com_github_aws_aws_sdk_go//aws", - "@com_github_aws_aws_sdk_go_v2_service_s3//:s3", ], ) go_test( name = "attestationconfigapi_test", srcs = [ - "client_test.go", "fetcher_test.go", - "reporter_test.go", "snp_test.go", ], embed = [":attestationconfigapi"], diff --git a/internal/api/attestationconfigapi/cli/BUILD.bazel b/internal/api/attestationconfigapi/cli/BUILD.bazel index 1d2fe3ae6..8378b0d03 100644 --- a/internal/api/attestationconfigapi/cli/BUILD.bazel +++ b/internal/api/attestationconfigapi/cli/BUILD.bazel @@ -19,6 +19,7 @@ go_library( visibility = ["//visibility:private"], deps = [ "//internal/api/attestationconfigapi", + "//internal/api/attestationconfigapi/cli/client", "//internal/attestation/variant", "//internal/cloud/cloudprovider", "//internal/constants", diff --git a/internal/api/attestationconfigapi/cli/client/BUILD.bazel b/internal/api/attestationconfigapi/cli/client/BUILD.bazel new file mode 100644 index 000000000..cacb2f05d --- /dev/null +++ b/internal/api/attestationconfigapi/cli/client/BUILD.bazel @@ -0,0 +1,35 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("//bazel/go:go_test.bzl", "go_test") + +go_library( + name = "client", + srcs = [ + "client.go", + "reporter.go", + ], + importpath = "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi/cli/client", + visibility = ["//:__subpackages__"], + deps = [ + "//internal/api/attestationconfigapi", + "//internal/api/client", + "//internal/attestation/variant", + "//internal/sigstore", + "//internal/staticupload", + "@com_github_aws_aws_sdk_go//aws", + "@com_github_aws_aws_sdk_go_v2_service_s3//:s3", + ], +) + +go_test( + name = "client_test", + srcs = [ + "client_test.go", + "reporter_test.go", + ], + embed = [":client"], + deps = [ + "//internal/api/attestationconfigapi", + "//internal/attestation/variant", + "@com_github_stretchr_testify//assert", + ], +) diff --git a/internal/api/attestationconfigapi/client.go b/internal/api/attestationconfigapi/cli/client/client.go similarity index 66% rename from internal/api/attestationconfigapi/client.go rename to internal/api/attestationconfigapi/cli/client/client.go index 11b27eae0..476ea22d5 100644 --- a/internal/api/attestationconfigapi/client.go +++ b/internal/api/attestationconfigapi/cli/client/client.go @@ -3,7 +3,12 @@ Copyright (c) Edgeless Systems GmbH SPDX-License-Identifier: AGPL-3.0-only */ -package attestationconfigapi + +/* +package client contains code to manage CVM versions in Constellation's CDN API. +It is used to upload and delete "latest" versions for AMD SEV-SNP and Intel TDX. +*/ +package client import ( "context" @@ -12,6 +17,7 @@ import ( "log/slog" "time" + "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi" apiclient "github.com/edgelesssys/constellation/v2/internal/api/client" "github.com/edgelesssys/constellation/v2/internal/attestation/variant" "github.com/edgelesssys/constellation/v2/internal/sigstore" @@ -31,8 +37,8 @@ type Client struct { cacheWindowSize int } -// NewClient returns a new Client. -func NewClient(ctx context.Context, cfg staticupload.Config, cosignPwd, privateKey []byte, dryRun bool, versionWindowSize int, log *slog.Logger) (*Client, apiclient.CloseFunc, error) { +// New returns a new Client. +func New(ctx context.Context, cfg staticupload.Config, cosignPwd, privateKey []byte, dryRun bool, versionWindowSize int, log *slog.Logger) (*Client, apiclient.CloseFunc, error) { s3Client, clientClose, err := apiclient.NewClient(ctx, cfg.Region, cfg.Bucket, cfg.DistributionID, dryRun, log) if err != nil { return nil, nil, fmt.Errorf("failed to create s3 storage: %w", err) @@ -49,7 +55,7 @@ func NewClient(ctx context.Context, cfg staticupload.Config, cosignPwd, privateK } // uploadSEVSNPVersion uploads the latest version numbers of the SEVSNP. Then version name is the UTC timestamp of the date. The /list entry stores the version name + .json suffix. -func (a Client) uploadSEVSNPVersion(ctx context.Context, attestation variant.Variant, version SEVSNPVersion, date time.Time) error { +func (a Client) uploadSEVSNPVersion(ctx context.Context, attestation variant.Variant, version attestationconfigapi.SEVSNPVersion, date time.Time) error { versions, err := a.List(ctx, attestation) if err != nil { return fmt.Errorf("fetch version list: %w", err) @@ -74,32 +80,32 @@ func (a Client) DeleteSEVSNPVersion(ctx context.Context, attestation variant.Var } // List returns the list of versions for the given attestation variant. -func (a Client) List(ctx context.Context, attestation variant.Variant) (SEVSNPVersionList, error) { +func (a Client) List(ctx context.Context, attestation variant.Variant) (attestationconfigapi.SEVSNPVersionList, error) { if !attestation.Equal(variant.AzureSEVSNP{}) && !attestation.Equal(variant.AWSSEVSNP{}) && !attestation.Equal(variant.GCPSEVSNP{}) { - return SEVSNPVersionList{}, fmt.Errorf("unsupported attestation variant: %s", attestation) + return attestationconfigapi.SEVSNPVersionList{}, fmt.Errorf("unsupported attestation variant: %s", attestation) } - versions, err := apiclient.Fetch(ctx, a.s3Client, SEVSNPVersionList{variant: attestation}) + versions, err := apiclient.Fetch(ctx, a.s3Client, attestationconfigapi.SEVSNPVersionList{Variant: attestation}) if err != nil { var notFoundErr *apiclient.NotFoundError if errors.As(err, ¬FoundErr) { - return SEVSNPVersionList{variant: attestation}, nil + return attestationconfigapi.SEVSNPVersionList{Variant: attestation}, nil } - return SEVSNPVersionList{}, err + return attestationconfigapi.SEVSNPVersionList{}, err } - versions.variant = attestation + versions.Variant = attestation return versions, nil } -func (a Client) deleteSEVSNPVersion(versions SEVSNPVersionList, versionStr string) (ops []crudCmd, err error) { +func (a Client) deleteSEVSNPVersion(versions attestationconfigapi.SEVSNPVersionList, versionStr string) (ops []crudCmd, err error) { versionStr = versionStr + ".json" ops = append(ops, deleteCmd{ - apiObject: SEVSNPVersionAPI{ - Variant: versions.variant, + apiObject: attestationconfigapi.SEVSNPVersionAPI{ + Variant: versions.Variant, Version: versionStr, }, }) @@ -115,8 +121,8 @@ func (a Client) deleteSEVSNPVersion(versions SEVSNPVersionList, versionStr strin return ops, nil } -func (a Client) constructUploadCmd(attestation variant.Variant, version SEVSNPVersion, versionNames SEVSNPVersionList, date time.Time) []crudCmd { - if !attestation.Equal(versionNames.variant) { +func (a Client) constructUploadCmd(attestation variant.Variant, version attestationconfigapi.SEVSNPVersion, versionNames attestationconfigapi.SEVSNPVersionList, date time.Time) []crudCmd { + if !attestation.Equal(versionNames.Variant) { return nil } @@ -124,11 +130,11 @@ func (a Client) constructUploadCmd(attestation variant.Variant, version SEVSNPVe var res []crudCmd res = append(res, putCmd{ - apiObject: SEVSNPVersionAPI{Version: dateStr, Variant: attestation, SEVSNPVersion: version}, + apiObject: attestationconfigapi.SEVSNPVersionAPI{Version: dateStr, Variant: attestation, SEVSNPVersion: version}, signer: a.signer, }) - versionNames.addVersion(dateStr) + versionNames.AddVersion(dateStr) res = append(res, putCmd{ apiObject: versionNames, @@ -138,19 +144,19 @@ func (a Client) constructUploadCmd(attestation variant.Variant, version SEVSNPVe return res } -func removeVersion(list SEVSNPVersionList, versionStr string) (removedVersions SEVSNPVersionList, err error) { - versions := list.List() +func removeVersion(list attestationconfigapi.SEVSNPVersionList, versionStr string) (removedVersions attestationconfigapi.SEVSNPVersionList, err error) { + versions := list.List for i, v := range versions { if v == versionStr { if i == len(versions)-1 { - removedVersions = SEVSNPVersionList{list: versions[:i], variant: list.variant} + removedVersions = attestationconfigapi.SEVSNPVersionList{List: versions[:i], Variant: list.Variant} } else { - removedVersions = SEVSNPVersionList{list: append(versions[:i], versions[i+1:]...), variant: list.variant} + removedVersions = attestationconfigapi.SEVSNPVersionList{List: append(versions[:i], versions[i+1:]...), Variant: list.Variant} } return removedVersions, nil } } - return SEVSNPVersionList{}, fmt.Errorf("version %s not found in list %v", versionStr, versions) + return attestationconfigapi.SEVSNPVersionList{}, fmt.Errorf("version %s not found in list %v", versionStr, versions) } type crudCmd interface { diff --git a/internal/api/attestationconfigapi/client_test.go b/internal/api/attestationconfigapi/cli/client/client_test.go similarity index 56% rename from internal/api/attestationconfigapi/client_test.go rename to internal/api/attestationconfigapi/cli/client/client_test.go index 9cae1bc5a..77059b27b 100644 --- a/internal/api/attestationconfigapi/client_test.go +++ b/internal/api/attestationconfigapi/cli/client/client_test.go @@ -3,12 +3,13 @@ Copyright (c) Edgeless Systems GmbH SPDX-License-Identifier: AGPL-3.0-only */ -package attestationconfigapi +package client import ( "testing" "time" + "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi" "github.com/edgelesssys/constellation/v2/internal/attestation/variant" "github.com/stretchr/testify/assert" ) @@ -18,13 +19,13 @@ func TestUploadAzureSEVSNP(t *testing.T) { bucketID: "bucket", signer: fakeSigner{}, } - version := SEVSNPVersion{} + version := attestationconfigapi.SEVSNPVersion{} date := time.Date(2023, 1, 1, 1, 1, 1, 1, time.UTC) - ops := sut.constructUploadCmd(variant.AzureSEVSNP{}, version, SEVSNPVersionList{list: []string{"2021-01-01-01-01.json", "2019-01-01-01-01.json"}, variant: variant.AzureSEVSNP{}}, date) + ops := sut.constructUploadCmd(variant.AzureSEVSNP{}, version, attestationconfigapi.SEVSNPVersionList{List: []string{"2021-01-01-01-01.json", "2019-01-01-01-01.json"}, Variant: variant.AzureSEVSNP{}}, date) dateStr := "2023-01-01-01-01.json" assert := assert.New(t) assert.Contains(ops, putCmd{ - apiObject: SEVSNPVersionAPI{ + apiObject: attestationconfigapi.SEVSNPVersionAPI{ Variant: variant.AzureSEVSNP{}, Version: dateStr, SEVSNPVersion: version, @@ -32,7 +33,7 @@ func TestUploadAzureSEVSNP(t *testing.T) { signer: fakeSigner{}, }) assert.Contains(ops, putCmd{ - apiObject: SEVSNPVersionList{variant: variant.AzureSEVSNP{}, list: []string{"2023-01-01-01-01.json", "2021-01-01-01-01.json", "2019-01-01-01-01.json"}}, + apiObject: attestationconfigapi.SEVSNPVersionList{Variant: variant.AzureSEVSNP{}, List: []string{"2023-01-01-01-01.json", "2021-01-01-01-01.json", "2019-01-01-01-01.json"}}, signer: fakeSigner{}, }) } @@ -41,20 +42,20 @@ func TestDeleteAzureSEVSNPVersions(t *testing.T) { sut := Client{ bucketID: "bucket", } - versions := SEVSNPVersionList{list: []string{"2023-01-01.json", "2021-01-01.json", "2019-01-01.json"}} + versions := attestationconfigapi.SEVSNPVersionList{List: []string{"2023-01-01.json", "2021-01-01.json", "2019-01-01.json"}} ops, err := sut.deleteSEVSNPVersion(versions, "2021-01-01") assert := assert.New(t) assert.NoError(err) assert.Contains(ops, deleteCmd{ - apiObject: SEVSNPVersionAPI{ + apiObject: attestationconfigapi.SEVSNPVersionAPI{ Version: "2021-01-01.json", }, }) assert.Contains(ops, putCmd{ - apiObject: SEVSNPVersionList{list: []string{"2023-01-01.json", "2019-01-01.json"}}, + apiObject: attestationconfigapi.SEVSNPVersionList{List: []string{"2023-01-01.json", "2019-01-01.json"}}, }) } diff --git a/internal/api/attestationconfigapi/reporter.go b/internal/api/attestationconfigapi/cli/client/reporter.go similarity index 88% rename from internal/api/attestationconfigapi/reporter.go rename to internal/api/attestationconfigapi/cli/client/reporter.go index 72a980347..cc0f9b5ed 100644 --- a/internal/api/attestationconfigapi/reporter.go +++ b/internal/api/attestationconfigapi/cli/client/reporter.go @@ -4,12 +4,7 @@ Copyright (c) Edgeless Systems GmbH SPDX-License-Identifier: AGPL-3.0-only */ -/* -The reporter contains the logic to determine a latest version for SEVSNP based on cached version values observed on CVM instances. -Some code in this file (e.g. listing cached files) does not rely on dedicated API objects and instead uses the AWS SDK directly, -for no other reason than original development speed. -*/ -package attestationconfigapi +package client import ( "context" @@ -23,6 +18,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go/aws" + "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi" "github.com/edgelesssys/constellation/v2/internal/api/client" "github.com/edgelesssys/constellation/v2/internal/attestation/variant" ) @@ -34,7 +30,7 @@ const cachedVersionsSubDir = "cached-versions" var ErrNoNewerVersion = errors.New("input version is not newer than latest API version") func reportVersionDir(attestation variant.Variant) string { - return path.Join(AttestationURLPath, attestation.String(), cachedVersionsSubDir) + return path.Join(attestationconfigapi.AttestationURLPath, attestation.String(), cachedVersionsSubDir) } // UploadSEVSNPVersionLatest saves the given version to the cache, determines the smallest @@ -42,7 +38,7 @@ func reportVersionDir(attestation variant.Variant) string { // the latest version in the API if there is an update. // force can be used to bypass the validation logic against the cached versions. func (c Client) UploadSEVSNPVersionLatest(ctx context.Context, attestation variant.Variant, inputVersion, - latestAPIVersion SEVSNPVersion, now time.Time, force bool, + latestAPIVersion attestationconfigapi.SEVSNPVersion, now time.Time, force bool, ) error { if err := c.cacheSEVSNPVersion(ctx, attestation, inputVersion, now); err != nil { return fmt.Errorf("reporting version: %w", err) @@ -84,7 +80,7 @@ func (c Client) UploadSEVSNPVersionLatest(ctx context.Context, attestation varia } // cacheSEVSNPVersion uploads the latest observed version numbers of the SEVSNP. This version is used to later report the latest version numbers to the API. -func (c Client) cacheSEVSNPVersion(ctx context.Context, attestation variant.Variant, version SEVSNPVersion, date time.Time) error { +func (c Client) cacheSEVSNPVersion(ctx context.Context, attestation variant.Variant, version attestationconfigapi.SEVSNPVersion, date time.Time) error { dateStr := date.Format(VersionFormat) + ".json" res := putCmd{ apiObject: reportedSEVSNPVersionAPI{Version: dateStr, variant: attestation, SEVSNPVersion: version}, @@ -112,8 +108,8 @@ func (c Client) listCachedVersions(ctx context.Context, attestation variant.Vari } // findMinVersion finds the minimal version of the given version dates among the latest values in the version window size. -func (c Client) findMinVersion(ctx context.Context, attesation variant.Variant, versionDates []string) (SEVSNPVersion, string, error) { - var minimalVersion *SEVSNPVersion +func (c Client) findMinVersion(ctx context.Context, attesation variant.Variant, versionDates []string) (attestationconfigapi.SEVSNPVersion, string, error) { + var minimalVersion *attestationconfigapi.SEVSNPVersion var minimalDate string sort.Sort(sort.Reverse(sort.StringSlice(versionDates))) // sort in reverse order to slice the latest versions versionDates = versionDates[:c.cacheWindowSize] @@ -121,7 +117,7 @@ func (c Client) findMinVersion(ctx context.Context, attesation variant.Variant, for _, date := range versionDates { obj, err := client.Fetch(ctx, c.s3Client, reportedSEVSNPVersionAPI{Version: date + ".json", variant: attesation}) if err != nil { - return SEVSNPVersion{}, "", fmt.Errorf("get object: %w", err) + return attestationconfigapi.SEVSNPVersion{}, "", fmt.Errorf("get object: %w", err) } // Need to set this explicitly as the variant is not part of the marshalled JSON. obj.variant = attesation @@ -144,7 +140,7 @@ func (c Client) findMinVersion(ctx context.Context, attesation variant.Variant, } // isInputNewerThanOtherVersion compares all version fields and returns true if any input field is newer. -func isInputNewerThanOtherVersion(input, other SEVSNPVersion) (bool, error) { +func isInputNewerThanOtherVersion(input, other attestationconfigapi.SEVSNPVersion) (bool, error) { if input == other { return false, nil } @@ -167,7 +163,7 @@ func isInputNewerThanOtherVersion(input, other SEVSNPVersion) (bool, error) { type reportedSEVSNPVersionAPI struct { Version string `json:"-"` variant variant.Variant `json:"-"` - SEVSNPVersion + attestationconfigapi.SEVSNPVersion } // JSONPath returns the path to the JSON file for the request to the config api. diff --git a/internal/api/attestationconfigapi/reporter_test.go b/internal/api/attestationconfigapi/cli/client/reporter_test.go similarity index 71% rename from internal/api/attestationconfigapi/reporter_test.go rename to internal/api/attestationconfigapi/cli/client/reporter_test.go index ea37d2d2f..f3bc9a4ff 100644 --- a/internal/api/attestationconfigapi/reporter_test.go +++ b/internal/api/attestationconfigapi/cli/client/reporter_test.go @@ -2,17 +2,18 @@ Copyright (c) Edgeless Systems GmbH SPDX-License-Identifier: AGPL-3.0-only */ -package attestationconfigapi +package client import ( "testing" + "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi" "github.com/stretchr/testify/assert" ) func TestIsInputNewerThanLatestAPI(t *testing.T) { - newTestCfg := func() SEVSNPVersion { - return SEVSNPVersion{ + newTestCfg := func() attestationconfigapi.SEVSNPVersion { + return attestationconfigapi.SEVSNPVersion{ Microcode: 93, TEE: 0, SNP: 6, @@ -21,13 +22,13 @@ func TestIsInputNewerThanLatestAPI(t *testing.T) { } testCases := map[string]struct { - latest SEVSNPVersion - input SEVSNPVersion + latest attestationconfigapi.SEVSNPVersion + input attestationconfigapi.SEVSNPVersion expect bool errMsg string }{ "input is older than latest": { - input: func(c SEVSNPVersion) SEVSNPVersion { + input: func(c attestationconfigapi.SEVSNPVersion) attestationconfigapi.SEVSNPVersion { c.Microcode-- return c }(newTestCfg()), @@ -36,7 +37,7 @@ func TestIsInputNewerThanLatestAPI(t *testing.T) { errMsg: "input Microcode version: 92 is older than latest API version: 93", }, "input has greater and smaller version field than latest": { - input: func(c SEVSNPVersion) SEVSNPVersion { + input: func(c attestationconfigapi.SEVSNPVersion) attestationconfigapi.SEVSNPVersion { c.Microcode++ c.Bootloader-- return c @@ -46,7 +47,7 @@ func TestIsInputNewerThanLatestAPI(t *testing.T) { errMsg: "input Bootloader version: 1 is older than latest API version: 2", }, "input is newer than latest": { - input: func(c SEVSNPVersion) SEVSNPVersion { + input: func(c attestationconfigapi.SEVSNPVersion) attestationconfigapi.SEVSNPVersion { c.TEE++ return c }(newTestCfg()), diff --git a/internal/api/attestationconfigapi/cli/delete.go b/internal/api/attestationconfigapi/cli/delete.go index daf457415..aa3947337 100644 --- a/internal/api/attestationconfigapi/cli/delete.go +++ b/internal/api/attestationconfigapi/cli/delete.go @@ -16,6 +16,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi" + "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi/cli/client" "github.com/edgelesssys/constellation/v2/internal/attestation/variant" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/logger" @@ -62,7 +63,7 @@ func runDelete(cmd *cobra.Command, args []string) (retErr error) { Region: deleteCfg.region, DistributionID: deleteCfg.distribution, } - client, clientClose, err := attestationconfigapi.NewClient(cmd.Context(), cfg, + client, clientClose, err := client.New(cmd.Context(), cfg, []byte(cosignPwd), []byte(privateKey), false, 1, log) if err != nil { return fmt.Errorf("create attestation client: %w", err) @@ -170,7 +171,7 @@ func newDeleteConfig(cmd *cobra.Command, args [3]string) (deleteConfig, error) { }, nil } -func deleteEntry(ctx context.Context, attvar variant.Variant, client *attestationconfigapi.Client, cfg deleteConfig) error { +func deleteEntry(ctx context.Context, attvar variant.Variant, client *client.Client, cfg deleteConfig) error { if cfg.kind != snpReport { return fmt.Errorf("kind %s not supported", cfg.kind) } diff --git a/internal/api/attestationconfigapi/cli/upload.go b/internal/api/attestationconfigapi/cli/upload.go index 98303cae2..f29351207 100644 --- a/internal/api/attestationconfigapi/cli/upload.go +++ b/internal/api/attestationconfigapi/cli/upload.go @@ -14,6 +14,7 @@ import ( "time" "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi" + "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi/cli/client" "github.com/edgelesssys/constellation/v2/internal/attestation/variant" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/file" @@ -68,18 +69,15 @@ func runUpload(cmd *cobra.Command, args []string) (retErr error) { return fmt.Errorf("parsing cli flags: %w", err) } - client, clientClose, err := attestationconfigapi.NewClient( - ctx, + client, clientClose, err := client.New(ctx, staticupload.Config{ Bucket: uploadCfg.bucket, Region: uploadCfg.region, DistributionID: uploadCfg.distribution, }, - []byte(cosignPwd), - []byte(privateKey), - false, - uploadCfg.cacheWindowSize, - log) + []byte(cosignPwd), []byte(privateKey), + false, uploadCfg.cacheWindowSize, log, + ) defer func() { err := clientClose(cmd.Context()) @@ -109,7 +107,7 @@ func runUpload(cmd *cobra.Command, args []string) (retErr error) { func uploadReport(ctx context.Context, attestation variant.Variant, - client *attestationconfigapi.Client, + apiClient *client.Client, cfg uploadConfig, fs file.Handler, log *slog.Logger, @@ -137,8 +135,8 @@ func uploadReport(ctx context.Context, } latestAPIVersion := latestAPIVersionAPI.SEVSNPVersion - if err := client.UploadSEVSNPVersionLatest(ctx, attestation, inputVersion, latestAPIVersion, cfg.uploadDate, cfg.force); err != nil { - if errors.Is(err, attestationconfigapi.ErrNoNewerVersion) { + if err := apiClient.UploadSEVSNPVersionLatest(ctx, attestation, inputVersion, latestAPIVersion, cfg.uploadDate, cfg.force); err != nil { + if errors.Is(err, client.ErrNoNewerVersion) { log.Info(fmt.Sprintf("Input version: %+v is not newer than latest API version: %+v", inputVersion, latestAPIVersion)) return nil } @@ -178,7 +176,7 @@ func newConfig(cmd *cobra.Command, args [3]string) (uploadConfig, error) { } uploadDate := time.Now() if dateStr != "" { - uploadDate, err = time.Parse(attestationconfigapi.VersionFormat, dateStr) + uploadDate, err = time.Parse(client.VersionFormat, dateStr) if err != nil { return uploadConfig{}, fmt.Errorf("parsing date: %w", err) } diff --git a/internal/api/attestationconfigapi/cli/validargs.go b/internal/api/attestationconfigapi/cli/validargs.go index 033aaa0a3..22a11ac21 100644 --- a/internal/api/attestationconfigapi/cli/validargs.go +++ b/internal/api/attestationconfigapi/cli/validargs.go @@ -39,13 +39,14 @@ const ( // unknown is the default objectKind and does nothing. unknown objectKind = "unknown-kind" snpReport objectKind = "snp-report" + tdxReport objectKind = "tdx-report" guestFirmware objectKind = "guest-firmware" ) func kindFromString(s string) objectKind { lower := strings.ToLower(s) switch objectKind(lower) { - case snpReport, guestFirmware: + case snpReport, guestFirmware, tdxReport: return objectKind(lower) default: return unknown diff --git a/internal/api/attestationconfigapi/fetcher.go b/internal/api/attestationconfigapi/fetcher.go index a54e3ebc7..4d54758f6 100644 --- a/internal/api/attestationconfigapi/fetcher.go +++ b/internal/api/attestationconfigapi/fetcher.go @@ -74,7 +74,7 @@ func (f *fetcher) FetchSEVSNPVersionList(ctx context.Context, list SEVSNPVersion } // Need to set this explicitly as the variant is not part of the marshalled JSON. - fetchedList.variant = list.variant + fetchedList.Variant = list.Variant return fetchedList, nil } @@ -94,13 +94,13 @@ func (f *fetcher) FetchSEVSNPVersion(ctx context.Context, version SEVSNPVersionA // FetchSEVSNPVersionLatest returns the latest versions of the given type. func (f *fetcher) FetchSEVSNPVersionLatest(ctx context.Context, attesation variant.Variant) (res SEVSNPVersionAPI, err error) { - list, err := f.FetchSEVSNPVersionList(ctx, SEVSNPVersionList{variant: attesation}) + list, err := f.FetchSEVSNPVersionList(ctx, SEVSNPVersionList{Variant: attesation}) if err != nil { return res, ErrNoVersionsFound } getVersionRequest := SEVSNPVersionAPI{ - Version: list.List()[0], // latest version is first in list + Version: list.List[0], // latest version is first in list Variant: attesation, } res, err = f.FetchSEVSNPVersion(ctx, getVersionRequest) diff --git a/internal/api/attestationconfigapi/snp.go b/internal/api/attestationconfigapi/snp.go index a0f92700b..a98fae5f9 100644 --- a/internal/api/attestationconfigapi/snp.go +++ b/internal/api/attestationconfigapi/snp.go @@ -64,26 +64,23 @@ func (i SEVSNPVersionAPI) Validate() error { // Once we switch to v2 of the API we could embed the variant in the object and remove some code from fetcher & client. // That would remove the possibility of some fetcher/client code forgetting to set the variant. type SEVSNPVersionList struct { - variant variant.Variant - list []string + Variant variant.Variant + List []string } // MarshalJSON marshals the i's list property to JSON. func (i SEVSNPVersionList) MarshalJSON() ([]byte, error) { - return json.Marshal(i.list) + return json.Marshal(i.List) } // UnmarshalJSON unmarshals a list of strings into i's list property. func (i *SEVSNPVersionList) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &i.list) + return json.Unmarshal(data, &i.List) } -// List returns i's list property. -func (i SEVSNPVersionList) List() []string { return i.list } - // JSONPath returns the path to the JSON file for the request to the config api. func (i SEVSNPVersionList) JSONPath() string { - return path.Join(AttestationURLPath, i.variant.String(), "list") + return path.Join(AttestationURLPath, i.Variant.String(), "list") } // ValidateRequest is a NoOp as there is no input. @@ -93,20 +90,20 @@ func (i SEVSNPVersionList) ValidateRequest() error { // SortReverse sorts the list of versions in reverse order. func (i *SEVSNPVersionList) SortReverse() { - sort.Sort(sort.Reverse(sort.StringSlice(i.list))) + sort.Sort(sort.Reverse(sort.StringSlice(i.List))) } -// addVersion adds new to i's list and sorts the element in descending order. -func (i *SEVSNPVersionList) addVersion(new string) { - i.list = append(i.list, new) - i.list = variant.RemoveDuplicate(i.list) +// AddVersion adds new to i's list and sorts the element in descending order. +func (i *SEVSNPVersionList) AddVersion(new string) { + i.List = append(i.List, new) + i.List = variant.RemoveDuplicate(i.List) i.SortReverse() } // Validate validates the response. func (i SEVSNPVersionList) Validate() error { - if len(i.list) < 1 { + if len(i.List) < 1 { return fmt.Errorf("no versions found in /list") } return nil diff --git a/internal/api/attestationconfigapi/snp_test.go b/internal/api/attestationconfigapi/snp_test.go index 2fe3ea8c9..da2f09cfa 100644 --- a/internal/api/attestationconfigapi/snp_test.go +++ b/internal/api/attestationconfigapi/snp_test.go @@ -21,16 +21,16 @@ func TestSEVSNPVersionListMarshalUnmarshalJSON(t *testing.T) { wantDiff bool }{ "success": { - input: SEVSNPVersionList{list: []string{"v1", "v2"}}, - output: SEVSNPVersionList{list: []string{"v1", "v2"}}, + input: SEVSNPVersionList{List: []string{"v1", "v2"}}, + output: SEVSNPVersionList{List: []string{"v1", "v2"}}, }, "variant is lost": { - input: SEVSNPVersionList{list: []string{"v1", "v2"}, variant: variant.AzureSEVSNP{}}, - output: SEVSNPVersionList{list: []string{"v1", "v2"}}, + input: SEVSNPVersionList{List: []string{"v1", "v2"}, Variant: variant.AzureSEVSNP{}}, + output: SEVSNPVersionList{List: []string{"v1", "v2"}}, }, "wrong order": { - input: SEVSNPVersionList{list: []string{"v1", "v2"}}, - output: SEVSNPVersionList{list: []string{"v2", "v1"}}, + input: SEVSNPVersionList{List: []string{"v1", "v2"}}, + output: SEVSNPVersionList{List: []string{"v2", "v1"}}, wantDiff: true, }, } @@ -68,10 +68,10 @@ func TestSEVSNPVersionListAddVersion(t *testing.T) { for name, tc := range tests { t.Run(name, func(t *testing.T) { - v := SEVSNPVersionList{list: tc.versions} - v.addVersion(tc.new) + v := SEVSNPVersionList{List: tc.versions} + v.AddVersion(tc.new) - assert.Equal(t, tc.expected, v.list) + assert.Equal(t, tc.expected, v.List) }) } }