Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions pkg/download_s3_archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@ import (
"github.com/qovery/qovery-cli/utils"
)

var uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
var uuidWithTimestampRegex = regexp.MustCompile(`^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-\d+$`)
const uuidPattern = `[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`

// An archive is stored under a key made of a uuid, optionally followed by a numeric id.
// Execution ids reach us with a Unix timestamp appended on top of that key. Only a
// trailing 10 digit segment is a timestamp: a shorter one, such as the "-1211" in
// "<uuid>-1211-1791383662", is part of the key itself and must be kept.
var executionIdWithTimestampRegex = regexp.MustCompile(`^(` + uuidPattern + `(?:-\d+)?)-\d{10}$`)
Comment thread
erebe marked this conversation as resolved.
var executionIdRegex = regexp.MustCompile(`^` + uuidPattern + `(?:-\d+)?$`)

type ArchiveTagsResponse struct {
Key string
Expand All @@ -30,15 +36,29 @@ type ArchiveResponse struct {
Tags []ArchiveTagsResponse
}

// normalizeExecutionId returns the key the archive is stored under, and whether the id
// is a shape we recognise. A trailing 10 digit Unix timestamp is dropped; any shorter
// numeric suffix belongs to the key and is kept.
func normalizeExecutionId(executionId string) (string, bool) {
if matches := executionIdWithTimestampRegex.FindStringSubmatch(executionId); matches != nil {
return matches[1], true
}

return executionId, executionIdRegex.MatchString(executionId)
}

func DownloadS3Archive(executionId string, directory string) {
if matches := uuidWithTimestampRegex.FindStringSubmatch(executionId); matches != nil {
log.Warnf("Execution id '%s' contains a timestamp suffix, stripping it automatically", executionId)
executionId = matches[1]
} else if !uuidRegex.MatchString(executionId) {
log.Errorf("Invalid execution id format: '%s'. Expected a UUID (e.g. xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)", executionId)
normalizedId, ok := normalizeExecutionId(executionId)
if !ok {
log.Errorf("Invalid execution id format: '%s'. Expected '<uuid>' or '<uuid>-<id>', optionally followed by a '-<timestamp>'", executionId)
return
}

if normalizedId != executionId {
log.Warnf("Execution id '%s' ends with a timestamp, stripping it to '%s'", executionId, normalizedId)
executionId = normalizedId
}

fileName := executionId + ".tgz"
res := download(utils.GetAdminUrl()+"/getS3ArchiveObject", fileName)

Expand Down
77 changes: 77 additions & 0 deletions pkg/download_s3_archive_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package pkg

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestNormalizeExecutionId(t *testing.T) {
tests := []struct {
name string
input string
want string
valid bool
}{
{
name: "timestamp trailing a suffixed key is stripped",
input: "0781cf11-05c2-4844-8f4e-d72f73a37bfa-1211-1791383662",
want: "0781cf11-05c2-4844-8f4e-d72f73a37bfa-1211",
valid: true,
},
{
name: "a lone trailing timestamp is stripped down to the bare uuid",
input: "ef83256b-5df5-40f0-87a2-a30b62998836-1791386238",
want: "ef83256b-5df5-40f0-87a2-a30b62998836",
valid: true,
},
{
name: "a suffix shorter than a timestamp is part of the key",
input: "0781cf11-05c2-4844-8f4e-d72f73a37bfa-1211",
want: "0781cf11-05c2-4844-8f4e-d72f73a37bfa-1211",
valid: true,
},
{
name: "a bare uuid is kept",
input: "0781cf11-05c2-4844-8f4e-d72f73a37bfa",
want: "0781cf11-05c2-4844-8f4e-d72f73a37bfa",
valid: true,
},
{
name: "not a uuid",
input: "not-an-execution-id",
valid: false,
},
{
name: "uuid with a non numeric suffix",
input: "0781cf11-05c2-4844-8f4e-d72f73a37bfa-abc",
valid: false,
},
{
name: "uuid with an uppercase hex digit",
input: "0781CF11-05c2-4844-8f4e-d72f73a37bfa-1211",
valid: false,
},
{
name: "a nine digit suffix is not a timestamp and is kept",
input: "0781cf11-05c2-4844-8f4e-d72f73a37bfa-123456789",
want: "0781cf11-05c2-4844-8f4e-d72f73a37bfa-123456789",
valid: true,
},
{
name: "more suffixes than we know how to read",
input: "0781cf11-05c2-4844-8f4e-d72f73a37bfa-1211-1791383662-42",
valid: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, ok := normalizeExecutionId(tt.input)
assert.Equal(t, tt.valid, ok)
if tt.valid {
assert.Equal(t, tt.want, got)
}
})
}
}
Loading