Skip to content

Commit

Permalink
fix e2e test
Browse files Browse the repository at this point in the history
  • Loading branch information
elchead committed Sep 18, 2023
1 parent 040fac6 commit c302658
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 37 deletions.
48 changes: 34 additions & 14 deletions internal/api/attestationconfigapi/cli/e2e/test.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -28,47 +28,67 @@ tmpdir=$(mktemp -d)
readonly tmpdir
registerExitHandler "rm -rf $tmpdir"

# the high version numbers ensure that it's newer than the current latest value
readonly claim_path="$tmpdir/maaClaim.json"
cat << EOF > "$claim_path"
{
"x-ms-isolation-tee": {
"x-ms-sevsnpvm-tee-svn": 1,
"x-ms-sevsnpvm-snpfw-svn": 9,
"x-ms-sevsnpvm-microcode-svn": 116,
"x-ms-sevsnpvm-bootloader-svn": 4
"x-ms-sevsnpvm-tee-svn": 255,
"x-ms-sevsnpvm-snpfw-svn": 255,
"x-ms-sevsnpvm-microcode-svn": 255,
"x-ms-sevsnpvm-bootloader-svn": 255
}
}
EOF

readonly date="2023-02-02-03-04"
# has an older version
readonly older_claim_path="$tmpdir/maaClaimOld.json"
cat << EOF > "$older_claim_path"
{
"x-ms-isolation-tee": {
"x-ms-sevsnpvm-tee-svn": 255,
"x-ms-sevsnpvm-snpfw-svn": 255,
"x-ms-sevsnpvm-microcode-svn": 254,
"x-ms-sevsnpvm-bootloader-svn": 255
}
}
EOF

# report 3 versions with different dates to fill the reporter cache
readonly date_yet_older="2023-02-01-03-04"
${configapi_cli} --maa-claims-path "$older_claim_path" --upload-date "$date_yet_older" --region "$region" --bucket "$bucket" --distribution "$distribution"
readonly date_older="2023-02-02-03-04"
${configapi_cli} --maa-claims-path "$older_claim_path" --upload-date "$date_older" --region "$region" --bucket "$bucket" --distribution "$distribution"
readonly date="2023-02-03-03-04"
${configapi_cli} --maa-claims-path "$claim_path" --upload-date "$date" --region "$region" --bucket "$bucket" --distribution "$distribution"

# expect that the older version was expected as new latest version
baseurl="https://d33dzgxuwsgbpw.cloudfront.net/constellation/v1/attestation/azure-sev-snp"
if ! curl -fsSL ${baseurl}/${date}.json > /dev/null; then
echo "Checking for uploaded version file constellation/v1/attestation/azure-sev-snp/${date}.json: request returned ${?}"
if ! curl -fsSL ${baseurl}/${date_yet_older}.json > /dev/null; then
echo "Checking for uploaded version file constellation/v1/attestation/azure-sev-snp/${date_yet_older}.json: request returned ${?}"
exit 1
fi

if ! curl -fsSL ${baseurl}/${date}.json.sig > /dev/null; then
echo "Checking for uploaded version signature file constellation/v1/attestation/azure-sev-snp/${date}.json.sig: request returned ${?}"
if ! curl -fsSL ${baseurl}/${date_yet_older}.json.sig > /dev/null; then
echo "Checking for uploaded version signature file constellation/v1/attestation/azure-sev-snp/${date_yet_older}.json.sig: request returned ${?}"
exit 1
fi

if ! curl -fsSL ${baseurl}/list > /dev/null; then
echo "Checking for uploaded list file constellation/v1/attestation/azure-sev-snp/list: request returned ${?}"
exit 1
fi
${configapi_cli} delete --version "$date" --region "$region" --bucket "$bucket" --distribution "$distribution"
${configapi_cli} delete --version "$date_yet_older" --region "$region" --bucket "$bucket" --distribution "$distribution"

# Omit -f to check for 404. We want to check that a file was deleted, therefore we expect the query to fail.
http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null ${baseurl}/${date}.json)
http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null ${baseurl}/${date_yet_older}.json)
if [[ $http_code -ne 404 ]]; then
echo "Expected HTTP code 404 for: constellation/v1/attestation/azure-sev-snp/${date}.json, but got ${http_code}"
echo "Expected HTTP code 404 for: constellation/v1/attestation/azure-sev-snp/${date_yet_older}.json, but got ${http_code}"
exit 1
fi
# Omit -f to check for 404. We want to check that a file was deleted, therefore we expect the query to fail.
http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null ${baseurl}/${date}.json.sig)
http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null ${baseurl}/${date_yet_older}.json.sig)
if [[ $http_code -ne 404 ]]; then
echo "Expected HTTP code 404 for: constellation/v1/attestation/azure-sev-snp/${date}.json, but got ${http_code}"
echo "Expected HTTP code 404 for: constellation/v1/attestation/azure-sev-snp/${date_yet_older}.json, but got ${http_code}"
exit 1
fi
4 changes: 3 additions & 1 deletion internal/api/attestationconfigapi/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Notice that there is no synchronization on API operations. // TODO(elchead): wha
*/
package main

// TODO: separate reporter and upload CLI to ease manual upload or use force flag?

import (
"encoding/json"
"errors"
Expand Down Expand Up @@ -133,7 +135,7 @@ func runCmd(cmd *cobra.Command, _ []string) (retErr error) {
if err := reporter.ReportAzureSEVSNPVersion(ctx, inputVersion, flags.uploadDate); err != nil {
return fmt.Errorf("reporting version: %w", err)
}
if err := reporter.UpdateLatestVersion(ctx, latestAPIVersion); err != nil {
if err := reporter.UpdateLatestVersion(ctx, latestAPIVersion, flags.uploadDate); err != nil {
return fmt.Errorf("updating latest version: %w", err)
}

Expand Down
43 changes: 23 additions & 20 deletions internal/api/attestationconfigapi/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
)

// cachedVersionsSubDir is the subdirectory in the bucket where the cached versions are stored.
// TODO(elchead): store in a different directory so that it is not mirrored to the CDN?
const cachedVersionsSubDir = "cached-versions"

// timeFrameForCachedVersions defines the time frame for reported versions which are considered to define the latest version.
Expand All @@ -33,6 +34,7 @@ var reportVersionDir = path.Join(attestationURLPath, variant.AzureSEVSNP{}.Strin
type Reporter struct {
// Client is the client to the config api.
*Client
// s3client: but no cache invalidation for upload -> new client
}

// ReportAzureSEVSNPVersion uploads the latest observed version numbers of the Azure SEVSNP. This version is used to later report the latest version numbers to the API.
Expand All @@ -45,7 +47,7 @@ func (r Reporter) ReportAzureSEVSNPVersion(ctx context.Context, version AzureSEV
return res.Execute(ctx, r.s3Client)
}

func (r Reporter) listReportedVersions(ctx context.Context, timeFrame time.Duration) ([]string, error) {
func (r Reporter) listReportedVersions(ctx context.Context, timeFrame time.Duration, now time.Time) ([]string, error) {
list, err := r.s3Client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{
Bucket: aws.String(r.bucketID),
Prefix: aws.String(reportVersionDir),
Expand All @@ -60,18 +62,18 @@ func (r Reporter) listReportedVersions(ctx context.Context, timeFrame time.Durat
dates = append(dates, fileName[:len(fileName)-5])
}
}
return filterDatesWithinTime(dates, time.Now(), timeFrame), nil
return filterDatesWithinTime(dates, now, timeFrame), nil
}

// UpdateLatestVersion checks the reported version values
// and updates the latest version of the Azure SEVSNP in the API if there is an update .
func (r Reporter) UpdateLatestVersion(ctx context.Context, latestAPIVersion AzureSEVSNPVersion) error {
func (r Reporter) UpdateLatestVersion(ctx context.Context, latestAPIVersion AzureSEVSNPVersion, now time.Time) error {
// get the reported version values of the last 3 weeks
versionDates, err := r.listReportedVersions(ctx, timeFrameForCachedVersions)
versionDates, err := r.listReportedVersions(ctx, timeFrameForCachedVersions, now)
if err != nil {
return fmt.Errorf("list reported versions: %w", err)
}
r.s3Client.Logger.Infof("Found %d reported versions in the last %s", len(versionDates), timeFrameForCachedVersions.String())
r.s3Client.Logger.Infof("Found %v reported versions in the last %s since %s", versionDates, timeFrameForCachedVersions.String(), now.String())
if len(versionDates) < 3 {
r.s3Client.Logger.Infof("Skipping version update since only %s out of 3 expected versions are found in the cache within the last %d days",
len(versionDates), int(timeFrameForCachedVersions.Hours()/24))
Expand All @@ -83,7 +85,7 @@ func (r Reporter) UpdateLatestVersion(ctx context.Context, latestAPIVersion Azur
return fmt.Errorf("get minimal version: %w", err)
}
r.s3Client.Logger.Infof("Found minimal version: %+v with date: %s", *minVersion, minDate)
shouldUpdateAPI, err := isInputNewerThanLatestAPI(*minVersion, latestAPIVersion)
shouldUpdateAPI, err := isInputNewerThanOtherVersion(*minVersion, latestAPIVersion)
if err == nil && shouldUpdateAPI {
r.s3Client.Logger.Infof("Input version: %+v is newer than latest API version: %+v", *minVersion, latestAPIVersion)
// upload minVersion to the API
Expand Down Expand Up @@ -115,9 +117,9 @@ func (r Reporter) findMinVersion(ctx context.Context, versionDates []string) (*A
minimalVersion = &obj.AzureSEVSNPVersion
minimalDate = date
} else {
shouldUpdateMinimal, err := isInputNewerThanLatestAPI(*minimalVersion, obj.AzureSEVSNPVersion)
shouldUpdateMinimal, err := isInputNewerThanOtherVersion(*minimalVersion, obj.AzureSEVSNPVersion)
if err != nil {
return nil, "", fmt.Errorf("comparing versions: %w", err)
continue
}
if shouldUpdateMinimal {
minimalVersion = &obj.AzureSEVSNPVersion
Expand All @@ -135,29 +137,30 @@ func filterDatesWithinTime(dates []string, now time.Time, timeFrame time.Duratio
if err != nil {
continue
}
if now.Sub(t) <= timeFrame {
fmt.Println(now, " t ", t, " sub ", now.Sub(t))
if now.Sub(t) >= 0 && now.Sub(t) <= timeFrame {
datesWithinTimeFrame = append(datesWithinTimeFrame, date)
}
}
return datesWithinTimeFrame
}

// isInputNewerThanLatestAPI compares all version fields with the latest API version and returns true if any input field is newer.
func isInputNewerThanLatestAPI(input, latest AzureSEVSNPVersion) (bool, error) {
if input == latest {
// isInputNewerThanOtherVersion compares all version fields and returns true if any input field is newer.
func isInputNewerThanOtherVersion(input, other AzureSEVSNPVersion) (bool, error) {
if input == other {
return false, nil
}
if input.TEE < latest.TEE {
return false, fmt.Errorf("input TEE version: %d is older than latest API version: %d", input.TEE, latest.TEE)
if input.TEE < other.TEE {
return false, fmt.Errorf("input TEE version: %d is older than latest API version: %d", input.TEE, other.TEE)
}
if input.SNP < latest.SNP {
return false, fmt.Errorf("input SNP version: %d is older than latest API version: %d", input.SNP, latest.SNP)
if input.SNP < other.SNP {
return false, fmt.Errorf("input SNP version: %d is older than latest API version: %d", input.SNP, other.SNP)
}
if input.Microcode < latest.Microcode {
return false, fmt.Errorf("input Microcode version: %d is older than latest API version: %d", input.Microcode, latest.Microcode)
if input.Microcode < other.Microcode {
return false, fmt.Errorf("input Microcode version: %d is older than latest API version: %d", input.Microcode, other.Microcode)
}
if input.Bootloader < latest.Bootloader {
return false, fmt.Errorf("input Bootloader version: %d is older than latest API version: %d", input.Bootloader, latest.Bootloader)
if input.Bootloader < other.Bootloader {
return false, fmt.Errorf("input Bootloader version: %d is older than latest API version: %d", input.Bootloader, other.Bootloader)
}
return true, nil
}
Expand Down
16 changes: 15 additions & 1 deletion internal/api/attestationconfigapi/reporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,17 @@ func TestFilterDatesWithinTime(t *testing.T) {
testCases := map[string]struct {
timeFrame time.Duration
expectedDates []string
customDates *[]string
}{
"all dates within 3 days": {
timeFrame: time.Hour * 24 * 3,
expectedDates: []string{"2022-01-06-00-00", "2022-01-07-00-00", "2022-01-08-00-00"},
},
"ignore dates newer than now": {
timeFrame: time.Hour * 24 * 3,
customDates: toPtr(append(dates, "2023-01-09-00-00")),
expectedDates: []string{"2022-01-06-00-00", "2022-01-07-00-00", "2022-01-08-00-00"},
},
"no dates within time frame": {
timeFrame: time.Hour,
expectedDates: nil,
Expand All @@ -43,12 +49,20 @@ func TestFilterDatesWithinTime(t *testing.T) {

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
dates := dates
if tc.customDates != nil {
dates = *tc.customDates
}
filteredDates := filterDatesWithinTime(dates, now, tc.timeFrame)
assert.Equal(t, tc.expectedDates, filteredDates)
})
}
}

func toPtr[T any](v T) *T {
return &v
}

func TestIsInputNewerThanLatestAPI(t *testing.T) {
newTestCfg := func() AzureSEVSNPVersion {
return AzureSEVSNPVersion{
Expand Down Expand Up @@ -100,7 +114,7 @@ func TestIsInputNewerThanLatestAPI(t *testing.T) {
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
isNewer, err := isInputNewerThanLatestAPI(tc.input, tc.latest)
isNewer, err := isInputNewerThanOtherVersion(tc.input, tc.latest)
assert := assert.New(t)
if tc.errMsg != "" {
assert.EqualError(err, tc.errMsg)
Expand Down
1 change: 0 additions & 1 deletion internal/staticupload/staticupload.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ func New(ctx context.Context, config Config, log *logger.Logger) (*Client, Close
}
s3Client := s3.NewFromConfig(cfg)
uploadClient := s3manager.NewUploader(s3Client)

cdnClient := cloudfront.NewFromConfig(cfg)

client := &Client{
Expand Down

0 comments on commit c302658

Please sign in to comment.