diff --git a/internal/api/attestationconfigapi/cli/delete.go b/internal/api/attestationconfigapi/cli/delete.go index 35f585e64e9..55c9a7f12c4 100644 --- a/internal/api/attestationconfigapi/cli/delete.go +++ b/internal/api/attestationconfigapi/cli/delete.go @@ -9,11 +9,10 @@ import ( "context" "errors" "fmt" - "os" + "github.com/aws/aws-sdk-go-v2/service/s3" + s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi" "github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/staticupload" @@ -108,40 +107,46 @@ func runRecursiveDelete(cmd *cobra.Command, _ []string) (retErr error) { return fmt.Errorf("getting bucket: %w", err) } - sess, err := session.NewSession(&aws.Config{ - Region: aws.String(region), - }) + distribution, err := cmd.Flags().GetString("distribution") if err != nil { - return + return fmt.Errorf("getting distribution: %w", err) } - // Create an S3 client. - svc := s3.New(sess) - + log := logger.New(logger.PlainLog, zap.DebugLevel).Named("attestationconfigapi") + client, closeFn, err := staticupload.New(cmd.Context(), staticupload.Config{ + Bucket: bucket, + Region: region, + DistributionID: distribution, + }, log) + if err != nil { + return fmt.Errorf("create static upload client: %w", err) + } + defer func() { + err := closeFn(cmd.Context()) + if err != nil { + retErr = errors.Join(retErr, fmt.Errorf("failed to close client: %w", err)) + } + }() path := "constellation/v1/attestation/azure-sev-snp" - // List all objects in the path. - resp, err := svc.ListObjectsV2(&s3.ListObjectsV2Input{ + resp, err := client.ListObjectsV2(cmd.Context(), &s3.ListObjectsV2Input{ Bucket: aws.String(bucket), Prefix: aws.String(path), }) if err != nil { - fmt.Println("Error listing objects:", err) - os.Exit(1) + return err } // Delete all objects in the path. - var keys []*s3.ObjectIdentifier - for _, obj := range resp.Contents { - keys = append(keys, &s3.ObjectIdentifier{ - Key: obj.Key, - }) + objIDs := make([]s3types.ObjectIdentifier, len(resp.Contents)) + for i, obj := range resp.Contents { + objIDs[i] = s3types.ObjectIdentifier{Key: obj.Key} } - if len(keys) > 0 { - _, err = svc.DeleteObjects(&s3.DeleteObjectsInput{ + if len(objIDs) > 0 { + _, err = client.DeleteObjects(cmd.Context(), &s3.DeleteObjectsInput{ Bucket: aws.String(bucket), - Delete: &s3.Delete{ - Objects: keys, - Quiet: aws.Bool(true), + Delete: &s3types.Delete{ + Objects: objIDs, + Quiet: true, }, }) if err != nil { diff --git a/internal/api/attestationconfigapi/cli/main.go b/internal/api/attestationconfigapi/cli/main.go index c1a02f2ad7c..8c149ac6eba 100644 --- a/internal/api/attestationconfigapi/cli/main.go +++ b/internal/api/attestationconfigapi/cli/main.go @@ -115,12 +115,6 @@ func runCmd(cmd *cobra.Command, _ []string) (retErr error) { inputVersion := maaTCB.ToAzureSEVSNPVersion() log.Infof("Input version: %+v", inputVersion) - latestAPIVersionAPI, err := attestationconfigapi.NewFetcherWithCustomCDN("https://d33dzgxuwsgbpw.cloudfront.net").FetchAzureSEVSNPVersionLatest(ctx) - if err != nil { - return fmt.Errorf("fetching latest version: %w", err) - } - latestAPIVersion := latestAPIVersionAPI.AzureSEVSNPVersion - client, clientClose, err := attestationconfigapi.NewClient(ctx, cfg, []byte(cosignPwd), []byte(privateKey), false, log) defer func() { err := clientClose(cmd.Context()) @@ -135,6 +129,16 @@ func runCmd(cmd *cobra.Command, _ []string) (retErr error) { if err != nil { return fmt.Errorf("creating client: %w", err) } + + latestAPIVersionAPI, err := attestationconfigapi.NewFetcherWithCustomCDN("https://d33dzgxuwsgbpw.cloudfront.net").FetchAzureSEVSNPVersionLatest(ctx) + if err != nil { + if errors.Is(err, attestationconfigapi.ErrNoVersionsFound) && flags.force { + log.Infof("No versions found in API, but assuming that we are uploading the first version.\n") + } else { + return fmt.Errorf("fetching latest version: %w", err) + } + } + latestAPIVersion := latestAPIVersionAPI.AzureSEVSNPVersion if err := client.UploadAzureSEVSNPVersionLatest(ctx, inputVersion, latestAPIVersion, flags.uploadDate, flags.force); err != nil { if errors.Is(err, attestationconfigapi.ErrNoNewerVersion) { log.Infof("Input version: %+v is not newer than latest API version: %+v", inputVersion, latestAPIVersion) diff --git a/internal/api/attestationconfigapi/fetcher.go b/internal/api/attestationconfigapi/fetcher.go index f7ffaa41d9d..800cda8316d 100644 --- a/internal/api/attestationconfigapi/fetcher.go +++ b/internal/api/attestationconfigapi/fetcher.go @@ -8,6 +8,7 @@ package attestationconfigapi import ( "context" + "errors" "fmt" apifetcher "github.com/edgelesssys/constellation/v2/internal/api/fetcher" @@ -17,6 +18,9 @@ import ( const cosignPublicKey = constants.CosignPublicKeyReleases +// ErrNoVersionsFound is returned if no versions are found. +var ErrNoVersionsFound = errors.New("no versions found") + // Fetcher fetches config API resources without authentication. type Fetcher interface { FetchAzureSEVSNPVersion(ctx context.Context, azureVersion AzureSEVSNPVersionAPI) (AzureSEVSNPVersionAPI, error) @@ -75,10 +79,10 @@ func (f *fetcher) FetchAzureSEVSNPVersionLatest(ctx context.Context) (res AzureS var list AzureSEVSNPVersionList list, err = f.FetchAzureSEVSNPVersionList(ctx, list) if err != nil { - return res, fmt.Errorf("fetching versions list: %w", err) + return res, ErrNoVersionsFound } if len(list) < 1 { - return res, fmt.Errorf("no versions found") + return res, ErrNoVersionsFound } getVersionRequest := AzureSEVSNPVersionAPI{ Version: list[0], // latest version is first in list