diff --git a/README.md b/README.md index 44c68e0a2..be7c192f9 100644 --- a/README.md +++ b/README.md @@ -424,6 +424,8 @@ params.SplitCount = 10 // The minimum file size in MiB required to attempt a multi-part upload. // MinSplitSize default value: 200 params.MinSplitSize = 100 +// The upload chunk size in MiB that can be concurrently uploaded during a multi-part upload. +params.ChunkSize = 5 // The min file size in bytes for "checksum deploy". // "Checksum deploy" is the action of calculating the file checksum locally, before // the upload, and skipping the actual file transfer if the file already diff --git a/artifactory/services/download.go b/artifactory/services/download.go index 61bf3242c..4a2d73ed9 100644 --- a/artifactory/services/download.go +++ b/artifactory/services/download.go @@ -389,7 +389,7 @@ func (ds *DownloadService) downloadFile(downloadFileDetails *httpclient.Download return err } - log.Debug(logMsgPrefix, "Artifactory response:", resp.Status) + log.Debug(logMsgPrefix+"Artifactory response:", resp.Status) return errorutils.CheckResponseStatus(resp, http.StatusOK) } @@ -468,7 +468,7 @@ func createLocalSymlink(localPath, localFileName, symlinkArtifact string, symlin if errorutils.CheckError(err) != nil { return err } - log.Debug(logMsgPrefix, "Creating symlink file.") + log.Debug(logMsgPrefix + "Creating symlink file.") return nil } @@ -537,7 +537,7 @@ func (ds *DownloadService) downloadFileIfNeeded(downloadPath, localPath, localFi return e } if isEqual { - log.Debug(logMsgPrefix, "File already exists locally.") + log.Debug(logMsgPrefix + "File already exists locally.") if ds.Progress != nil { ds.Progress.IncrementGeneralProgress() } diff --git a/artifactory/services/upload.go b/artifactory/services/upload.go index 0fbd9a077..53fefb4a8 100644 --- a/artifactory/services/upload.go +++ b/artifactory/services/upload.go @@ -619,7 +619,8 @@ func (us *UploadService) doUpload(artifact UploadData, targetUrlWithProps, logMs return } if shouldTryMultipart { - if err = us.MultipartUpload.UploadFileConcurrently(artifact.Artifact.LocalPath, artifact.Artifact.TargetPath, fileInfo.Size(), details.Checksum.Sha1, us.Progress, uploadParams.SplitCount); err != nil { + if err = us.MultipartUpload.UploadFileConcurrently(artifact.Artifact.LocalPath, artifact.Artifact.TargetPath, + fileInfo.Size(), details.Checksum.Sha1, us.Progress, uploadParams.SplitCount, uploadParams.ChunkSize); err != nil { return } // Once the file is uploaded to the storage, we finalize the multipart upload by performing a checksum deployment to save the file in Artifactory. @@ -664,7 +665,7 @@ func logUploadResponse(logMsgPrefix string, resp *http.Response, body []byte, ch } else { strChecksumDeployed = "" } - log.Debug(logMsgPrefix, "Artifactory response:", resp.Status, strChecksumDeployed) + log.Debug(logMsgPrefix+"Artifactory response:", resp.Status, strChecksumDeployed) } } @@ -709,6 +710,7 @@ type UploadParams struct { MinChecksumDeploy int64 MinSplitSize int64 SplitCount int + ChunkSize int64 ChecksumsCalcEnabled bool Archive string // When using the 'archive' option for upload, we can control the target path inside the uploaded archive using placeholders. This operation determines the TargetPathInArchive value. @@ -716,7 +718,8 @@ type UploadParams struct { } func NewUploadParams() UploadParams { - return UploadParams{CommonParams: &utils.CommonParams{}, MinChecksumDeploy: DefaultMinChecksumDeploy, ChecksumsCalcEnabled: true, MinSplitSize: defaultUploadMinSplit, SplitCount: defaultUploadSplitCount} + return UploadParams{CommonParams: &utils.CommonParams{}, MinChecksumDeploy: DefaultMinChecksumDeploy, + ChecksumsCalcEnabled: true, MinSplitSize: defaultUploadMinSplit, SplitCount: defaultUploadSplitCount, ChunkSize: utils.DefaultUploadChunkSize} } func DeepCopyUploadParams(params *UploadParams) UploadParams { diff --git a/artifactory/services/utils/multipartupload.go b/artifactory/services/utils/multipartupload.go index b212ea845..b9d7b9880 100644 --- a/artifactory/services/utils/multipartupload.go +++ b/artifactory/services/utils/multipartupload.go @@ -54,7 +54,7 @@ const ( // Sizes and limits constants MaxMultipartUploadFileSize = SizeTiB * 5 - uploadPartSize int64 = SizeMiB * 20 + DefaultUploadChunkSize int64 = SizeMiB * 20 // Retries and polling constants retriesInterval = time.Second * 5 @@ -122,13 +122,14 @@ type getConfigResponse struct { Supported bool `json:"supported,omitempty"` } -func (mu *MultipartUpload) UploadFileConcurrently(localPath, targetPath string, fileSize int64, sha1 string, progress ioutils.ProgressMgr, splitCount int) (err error) { +func (mu *MultipartUpload) UploadFileConcurrently(localPath, targetPath string, fileSize int64, sha1 string, + progress ioutils.ProgressMgr, splitCount int, chunkSize int64) (err error) { repoAndPath := strings.SplitN(targetPath, "/", 2) repoKey := repoAndPath[0] repoPath := repoAndPath[1] logMsgPrefix := fmt.Sprintf("[Multipart upload %s] ", repoPath) - token, err := mu.createMultipartUpload(repoKey, repoPath, calculatePartSize(fileSize, 0)) + token, err := mu.createMultipartUpload(repoKey, repoPath, calculatePartSize(fileSize, 0, chunkSize)) if err != nil { return } @@ -154,7 +155,7 @@ func (mu *MultipartUpload) UploadFileConcurrently(localPath, targetPath string, } }() - if err = mu.uploadPartsConcurrently(logMsgPrefix, fileSize, splitCount, localPath, progressReader, multipartUploadClient); err != nil { + if err = mu.uploadPartsConcurrently(logMsgPrefix, fileSize, chunkSize, splitCount, localPath, progressReader, multipartUploadClient); err != nil { return } @@ -175,9 +176,9 @@ func (mu *MultipartUpload) UploadFileConcurrently(localPath, targetPath string, return mu.completeAndPollForStatus(logMsgPrefix, uint(mu.client.GetHttpClient().GetRetries())+1, sha1, multipartUploadClient, progressReader) } -func (mu *MultipartUpload) uploadPartsConcurrently(logMsgPrefix string, fileSize int64, splitCount int, localPath string, progressReader ioutils.Progress, multipartUploadClient *httputils.HttpClientDetails) (err error) { - numberOfParts := calculateNumberOfParts(fileSize) - log.Info(fmt.Sprintf("%sSplitting file to %d parts, using %d working threads for uploading...", logMsgPrefix, numberOfParts, splitCount)) +func (mu *MultipartUpload) uploadPartsConcurrently(logMsgPrefix string, fileSize, chunkSize int64, splitCount int, localPath string, progressReader ioutils.Progress, multipartUploadClient *httputils.HttpClientDetails) (err error) { + numberOfParts := calculateNumberOfParts(fileSize, chunkSize) + log.Info(fmt.Sprintf("%sSplitting file to %d parts of %s each, using %d working threads for uploading...", logMsgPrefix, numberOfParts, ConvertIntToStorageSizeString(chunkSize), splitCount)) producerConsumer := parallel.NewRunner(splitCount, uint(numberOfParts), false) wg := new(sync.WaitGroup) @@ -186,7 +187,7 @@ func (mu *MultipartUpload) uploadPartsConcurrently(logMsgPrefix string, fileSize attemptsAllowed.Add(uint64(numberOfParts) * uint64(mu.client.GetHttpClient().GetRetries())) go func() { for i := 0; i < int(numberOfParts); i++ { - if err = mu.produceUploadTask(producerConsumer, logMsgPrefix, localPath, fileSize, numberOfParts, int64(i), progressReader, multipartUploadClient, attemptsAllowed, wg); err != nil { + if err = mu.produceUploadTask(producerConsumer, logMsgPrefix, localPath, fileSize, numberOfParts, int64(i), chunkSize, progressReader, multipartUploadClient, attemptsAllowed, wg); err != nil { return } } @@ -202,9 +203,9 @@ func (mu *MultipartUpload) uploadPartsConcurrently(logMsgPrefix string, fileSize return } -func (mu *MultipartUpload) produceUploadTask(producerConsumer parallel.Runner, logMsgPrefix, localPath string, fileSize, numberOfParts, partId int64, progressReader ioutils.Progress, multipartUploadClient *httputils.HttpClientDetails, attemptsAllowed *atomic.Uint64, wg *sync.WaitGroup) (retErr error) { +func (mu *MultipartUpload) produceUploadTask(producerConsumer parallel.Runner, logMsgPrefix, localPath string, fileSize, numberOfParts, partId, chunkSize int64, progressReader ioutils.Progress, multipartUploadClient *httputils.HttpClientDetails, attemptsAllowed *atomic.Uint64, wg *sync.WaitGroup) (retErr error) { _, retErr = producerConsumer.AddTaskWithError(func(int) error { - uploadErr := mu.uploadPart(logMsgPrefix, localPath, fileSize, partId, progressReader, multipartUploadClient) + uploadErr := mu.uploadPart(logMsgPrefix, localPath, fileSize, partId, chunkSize, progressReader, multipartUploadClient) if uploadErr == nil { log.Info(fmt.Sprintf("%sCompleted uploading part %d/%d", logMsgPrefix, partId+1, numberOfParts)) wg.Done() @@ -220,14 +221,14 @@ func (mu *MultipartUpload) produceUploadTask(producerConsumer parallel.Runner, l // Sleep before trying again time.Sleep(retriesInterval) - if err := mu.produceUploadTask(producerConsumer, logMsgPrefix, localPath, fileSize, numberOfParts, partId, progressReader, multipartUploadClient, attemptsAllowed, wg); err != nil { + if err := mu.produceUploadTask(producerConsumer, logMsgPrefix, localPath, fileSize, numberOfParts, partId, chunkSize, progressReader, multipartUploadClient, attemptsAllowed, wg); err != nil { retErr = err } }) return } -func (mu *MultipartUpload) uploadPart(logMsgPrefix, localPath string, fileSize, partId int64, progressReader ioutils.Progress, multipartUploadClient *httputils.HttpClientDetails) (err error) { +func (mu *MultipartUpload) uploadPart(logMsgPrefix, localPath string, fileSize, partId, chunkSize int64, progressReader ioutils.Progress, multipartUploadClient *httputils.HttpClientDetails) (err error) { file, err := os.Open(localPath) if err != nil { return errorutils.CheckError(err) @@ -235,10 +236,10 @@ func (mu *MultipartUpload) uploadPart(logMsgPrefix, localPath string, fileSize, defer func() { err = errors.Join(err, errorutils.CheckError(file.Close())) }() - if _, err = file.Seek(partId*uploadPartSize, io.SeekStart); err != nil { + if _, err = file.Seek(partId*chunkSize, io.SeekStart); err != nil { return errorutils.CheckError(err) } - partSize := calculatePartSize(fileSize, partId) + partSize := calculatePartSize(fileSize, partId, chunkSize) limitReader := io.LimitReader(file, partSize) limitReader = bufio.NewReader(limitReader) @@ -402,21 +403,22 @@ func (mu *MultipartUpload) abort(logMsgPrefix string, multipartUploadClient *htt return errorutils.CheckResponseStatusWithBody(resp, body, http.StatusNoContent) } -// Calculates the part size based on the file size and the part number. +// Calculates the part size based on the file size, the part number and the requested chunk size. // fileSize - the file size // partNumber - the current part number -func calculatePartSize(fileSize int64, partNumber int64) int64 { - partOffset := partNumber * uploadPartSize - if partOffset+uploadPartSize > fileSize { +// requestedChunkSize - chunk size requested by the user, or default. +func calculatePartSize(fileSize, partNumber, requestedChunkSize int64) int64 { + partOffset := partNumber * requestedChunkSize + if partOffset+requestedChunkSize > fileSize { return fileSize - partOffset } - return uploadPartSize + return requestedChunkSize } -// Calculates the number of parts based on the file size and the default part size. +// Calculates the number of parts based on the file size and the requested chunks size. // fileSize - the file size -func calculateNumberOfParts(fileSize int64) int64 { - return (fileSize + uploadPartSize - 1) / uploadPartSize +func calculateNumberOfParts(fileSize, chunkSize int64) int64 { + return (fileSize + chunkSize - 1) / chunkSize } func parseMultipartUploadStatus(status statusResponse) (shouldKeepPolling, shouldRerunComplete bool, err error) { diff --git a/artifactory/services/utils/multipartupload_test.go b/artifactory/services/utils/multipartupload_test.go index 6f8fd2cc9..fd43b0a98 100644 --- a/artifactory/services/utils/multipartupload_test.go +++ b/artifactory/services/utils/multipartupload_test.go @@ -109,7 +109,7 @@ func TestUploadPartsConcurrentlyTooManyAttempts(t *testing.T) { defer cleanUp() // Write something to the file - buf := make([]byte, uploadPartSize*3) + buf := make([]byte, DefaultUploadChunkSize*3) _, err := rand.Read(buf) assert.NoError(t, err) _, err = tempFile.Write(buf) @@ -146,7 +146,7 @@ func TestUploadPartsConcurrentlyTooManyAttempts(t *testing.T) { // Execute uploadPartsConcurrently fileSize := int64(len(buf)) - err = multipartUpload.uploadPartsConcurrently("", fileSize, splitCount, tempFile.Name(), nil, &httputils.HttpClientDetails{}) + err = multipartUpload.uploadPartsConcurrently("", fileSize, DefaultUploadChunkSize, splitCount, tempFile.Name(), nil, &httputils.HttpClientDetails{}) assert.ErrorIs(t, err, errTooManyAttempts) } @@ -285,19 +285,19 @@ var calculatePartSizeProvider = []struct { partNumber int64 expectedPartSize int64 }{ - {uploadPartSize - 1, 0, uploadPartSize - 1}, - {uploadPartSize, 0, uploadPartSize}, - {uploadPartSize + 1, 0, uploadPartSize}, + {DefaultUploadChunkSize - 1, 0, DefaultUploadChunkSize - 1}, + {DefaultUploadChunkSize, 0, DefaultUploadChunkSize}, + {DefaultUploadChunkSize + 1, 0, DefaultUploadChunkSize}, - {uploadPartSize*2 - 1, 1, uploadPartSize - 1}, - {uploadPartSize * 2, 1, uploadPartSize}, - {uploadPartSize*2 + 1, 1, uploadPartSize}, + {DefaultUploadChunkSize*2 - 1, 1, DefaultUploadChunkSize - 1}, + {DefaultUploadChunkSize * 2, 1, DefaultUploadChunkSize}, + {DefaultUploadChunkSize*2 + 1, 1, DefaultUploadChunkSize}, } func TestCalculatePartSize(t *testing.T) { for _, testCase := range calculatePartSizeProvider { t.Run(fmt.Sprintf("fileSize: %d partNumber: %d", testCase.fileSize, testCase.partNumber), func(t *testing.T) { - assert.Equal(t, testCase.expectedPartSize, calculatePartSize(testCase.fileSize, testCase.partNumber)) + assert.Equal(t, testCase.expectedPartSize, calculatePartSize(testCase.fileSize, testCase.partNumber, DefaultUploadChunkSize)) }) } } @@ -308,19 +308,19 @@ var calculateNumberOfPartsProvider = []struct { }{ {0, 0}, {1, 1}, - {uploadPartSize - 1, 1}, - {uploadPartSize, 1}, - {uploadPartSize + 1, 2}, + {DefaultUploadChunkSize - 1, 1}, + {DefaultUploadChunkSize, 1}, + {DefaultUploadChunkSize + 1, 2}, - {uploadPartSize*2 - 1, 2}, - {uploadPartSize * 2, 2}, - {uploadPartSize*2 + 1, 3}, + {DefaultUploadChunkSize*2 - 1, 2}, + {DefaultUploadChunkSize * 2, 2}, + {DefaultUploadChunkSize*2 + 1, 3}, } func TestCalculateNumberOfParts(t *testing.T) { for _, testCase := range calculateNumberOfPartsProvider { t.Run(fmt.Sprintf("fileSize: %d", testCase.fileSize), func(t *testing.T) { - assert.Equal(t, testCase.expectedNumberOfParts, calculateNumberOfParts(testCase.fileSize)) + assert.Equal(t, testCase.expectedNumberOfParts, calculateNumberOfParts(testCase.fileSize, DefaultUploadChunkSize)) }) } } diff --git a/artifactory/services/utils/storageutils.go b/artifactory/services/utils/storageutils.go index 8d29d1b7d..3cf22e799 100644 --- a/artifactory/services/utils/storageutils.go +++ b/artifactory/services/utils/storageutils.go @@ -3,6 +3,7 @@ package utils import ( "encoding/json" "errors" + "fmt" ) const ( @@ -126,3 +127,24 @@ type FileStoreSummary struct { UsedSpace string `json:"usedSpace,omitempty"` FreeSpace string `json:"freeSpace,omitempty"` } + +func ConvertIntToStorageSizeString(num int64) string { + if num > SizeTiB { + newNum := float64(num) / float64(SizeTiB) + stringNum := fmt.Sprintf("%.1f", newNum) + return stringNum + "TB" + } + if num > SizeGiB { + newNum := float64(num) / float64(SizeGiB) + stringNum := fmt.Sprintf("%.1f", newNum) + return stringNum + "GB" + } + if num > SizeMiB { + newNum := float64(num) / float64(SizeMiB) + stringNum := fmt.Sprintf("%.1f", newNum) + return stringNum + "MB" + } + newNum := float64(num) / float64(SizeKib) + stringNum := fmt.Sprintf("%.1f", newNum) + return stringNum + "KB" +} diff --git a/artifactory/services/utils/storageutils_test.go b/artifactory/services/utils/storageutils_test.go index 22d7f4e4b..35599077a 100644 --- a/artifactory/services/utils/storageutils_test.go +++ b/artifactory/services/utils/storageutils_test.go @@ -34,3 +34,21 @@ func buildFakeStorageInfo() StorageInfo { FileStoreSummary: FileStoreSummary{}, } } + +func TestConvertIntToStorageSizeString(t *testing.T) { + tests := []struct { + num int + output string + }{ + {12546, "12.3KB"}, + {148576, "145.1KB"}, + {2587985, "2.5MB"}, + {12896547, "12.3MB"}, + {12896547785, "12.0GB"}, + {5248965785422365, "4773.9TB"}, + } + + for _, test := range tests { + assert.Equal(t, test.output, ConvertIntToStorageSizeString(int64(test.num))) + } +} diff --git a/auth/authutils.go b/auth/authutils.go index ffebe88e3..c0e95ef16 100644 --- a/auth/authutils.go +++ b/auth/authutils.go @@ -102,12 +102,17 @@ func ExtractUsernameFromAccessToken(token string) (username string) { } // Extract username from subject. - usernameStartIndex := strings.LastIndex(tokenPayload.Subject, "/") - if usernameStartIndex < 0 { - err = errorutils.CheckErrorf("couldn't extract username from access-token's subject: %s", tokenPayload.Subject) - return + if strings.HasPrefix(tokenPayload.Subject, "jfrt@") || strings.Contains(tokenPayload.Subject, "/users/") { + usernameStartIndex := strings.LastIndex(tokenPayload.Subject, "/") + if usernameStartIndex < 0 { + err = errorutils.CheckErrorf("couldn't extract username from access-token's subject: %s", tokenPayload.Subject) + return + } + username = tokenPayload.Subject[usernameStartIndex+1:] + } else { + // OICD token for groups scope + username = tokenPayload.Subject } - username = tokenPayload.Subject[usernameStartIndex+1:] if username == "" { err = errorutils.CheckErrorf("empty username extracted from access-token's subject: %s", tokenPayload.Subject) } diff --git a/auth/authutils_test.go b/auth/authutils_test.go index 570396ef3..c0adeb9dc 100644 --- a/auth/authutils_test.go +++ b/auth/authutils_test.go @@ -3,6 +3,8 @@ package auth import ( "testing" + "github.com/jfrog/jfrog-client-go/utils/log" + "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/stretchr/testify/assert" ) @@ -15,6 +17,8 @@ var ( token3 = "eyJ2ZXIiOiIyIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYiLCJraWQiOiJIcnU2VHctZk1yOTV3dy12TDNjV3ZBVjJ3Qm9FSHpHdGlwUEFwOE1JdDljIn0" // #nosec G101 token4 = "eyJ2ZXIiOiIyIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYiLCJraWQiOiJsS0NYXzFvaTBQbTZGdF9XRklkejZLZ1g4U0FULUdOY0lJWXRjTC1KM084In0.eyJzdWIiOiJqZmZlQDAwMFwvdXNlcnNcL3RlbXB1c2VyIiwic2NwIjoiYXBwbGllZC1wZXJtaXNzaW9uc1wvYWRtaW4gYXBpOioiLCJhdWQiOlsiamZydEAqIiwiamZtZEAqIiwiamZldnRAKiIsImpmYWNAKiJdLCJpc3MiOiJqZmZlQDAwMCIsImV4cCI6MTYxNjQ4OTU4NSwiaWF0IjoxNjE2NDg1OTg1LCJqdGkiOiI0OTBlYWEzOS1mMzYxLTQxYjAtOTA5Ni1kNjg5NmQ0ZWQ3YjEifQ.J5P8Pu5tqEjgnLFLEoCdh1LJHWiMmEHht95v0EFuixwO-osq7sfXua_UCGBkKbmqVSGKew9kl_LTcbq_uMe281_5q2yYxT74iqc2wQ1K0uovEUeIU6E65oi70JwUWUwcF3sNJ2gFatnvgSu-2Kv6m-DtSIW36WS3Mh8uMZQ19ob4fmueVmMFyQsp0EEG6xFYeOK6SB8OUd0gAd_XvXiSRuF0eLabhKmXM2pVBLYfd2KIMlkFckEOGGOzeglvA62xmP4Ik7UsF487NAo0LeS_Pd79owr0jtgTYkCTrLlFhUzUMDVmD_LsCMyf_S4CJxhwkCRhhy9SYSs1WPgknL3--w" + // #nosec G101 + token5 = "eyJ2ZXIiOiIyIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYiLCJraWQiOiJDRlVIRER4UXZaM1VNWEZxS0ZWUlFiOEFROEd6VWxSZkZJMEt4TmIzdk1jIn0.eyJzdWIiOiJ5YWhhdi90ZXN0LXJlcG8iLCJzY3AiOiJhcHBsaWVkLXBlcm1pc3Npb25zL2dyb3VwczpcImFkbWluLWdyb3VwXCIsIiwiYXVkIjoiKkAqIiwiaXNzIjoiamZhY0AwMWdnbXFxcDc0MzZuOTB3d3I4Ym5nMXp5OSIsImV4cCI6MTcxNTE4MzA3MiwiaWF0IjoxNzE1MTgzMDEyLCJqdGkiOiJmN2IxMmIzMi0xMmNkLTQ1Y2ItYWZjYS1iNTYyMjc2YjY0YmQifQ.I6df8E0_1t7uYzSQkiQBNh9GIGyr541rIRQ8BDD401N4DV98dWsqACmdlYTOAaxn_el4Lz7_OaK0GnVNGf9hiZz9QKaXbe-HnL9jG-TobpOlyhkc6iBpnizuZ9T9YiveCG_NgDMWn5syiZ912t6PuZqNN2JmwswqfE9QDm6xCH8fu7h0Rs1qDNkahtgQvO99e5d7LnuOS9VfkXBxLDZ5AeUbd89zmujgDB4hMXB3J-dQ3QxGHRPS_KUo7sf7lRvn4PydYkhbhrhg6GP6ss6rMmEJM5v8azMTrkLwksoCWtK9YpD5S70f7AoE5U5j5BttZ0S5dPGagKWZJiA1egna-w" ) func TestExtractUsernameFromAccessToken(t *testing.T) { @@ -27,7 +31,13 @@ func TestExtractUsernameFromAccessToken(t *testing.T) { {"", token2, true}, {"", token3, true}, {"tempuser", token4, false}, + {"yahav/test-repo", token5, false}, } + // Discard output logging to prevent negative logs + previousLog := tests.RedirectLogOutputToNil() + defer func() { + log.SetLogger(previousLog) + }() for _, testCase := range testCases { username := ExtractUsernameFromAccessToken(testCase.inputToken) @@ -46,6 +56,7 @@ func TestExtractSubjectFromAccessToken(t *testing.T) { {"jfrt@001c3gffhg2e8w6149e3a2q0w97", token2, false}, {"", token3, true}, {"jffe@000/users/tempuser", token4, false}, + {"yahav/test-repo", token5, false}, } for _, testCase := range testCases { diff --git a/go.mod b/go.mod index 47e55ed4f..f0feb0acf 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/ProtonMail/go-crypto v1.0.0 github.com/buger/jsonparser v1.1.1 github.com/forPelevin/gomoji v1.2.0 - github.com/go-git/go-git/v5 v5.11.0 + github.com/go-git/go-git/v5 v5.12.0 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/gookit/color v1.5.4 github.com/jfrog/archiver/v3 v3.6.0 @@ -14,9 +14,9 @@ require ( github.com/jfrog/gofrog v1.7.1 github.com/stretchr/testify v1.9.0 github.com/xanzy/ssh-agent v0.3.3 - golang.org/x/crypto v0.21.0 - golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 - golang.org/x/term v0.18.0 + golang.org/x/crypto v0.23.0 + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 + golang.org/x/term v0.20.0 ) require ( @@ -26,7 +26,7 @@ require ( github.com/andybalholm/brotli v1.1.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dsnet/compress v0.0.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect @@ -42,18 +42,18 @@ require ( github.com/nwaples/rardecode v1.1.3 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.3 // indirect - github.com/sergi/go-diff v1.1.0 // indirect - github.com/skeema/knownhosts v1.2.1 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect + github.com/skeema/knownhosts v1.2.2 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect - golang.org/x/mod v0.16.0 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/tools v0.19.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/tools v0.21.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index e8d6cd45e..ca5deea59 100644 --- a/go.sum +++ b/go.sum @@ -21,9 +21,8 @@ github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBS github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= @@ -32,14 +31,14 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/forPelevin/gomoji v1.2.0 h1:9k4WVSSkE1ARO/BWywxgEUBvR/jMnao6EZzrql5nxJ8= github.com/forPelevin/gomoji v1.2.0/go.mod h1:8+Z3KNGkdslmeGZBC3tCrwMrcPy5GRzAD+gL9NAwMXg= -github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -83,17 +82,16 @@ github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= -github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -118,14 +116,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc= -golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -133,13 +131,13 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -154,15 +152,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -170,13 +168,13 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -184,6 +182,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/http/httpclient/client.go b/http/httpclient/client.go index 658bd7f6e..b101be52c 100644 --- a/http/httpclient/client.go +++ b/http/httpclient/client.go @@ -36,8 +36,14 @@ type HttpClient struct { const ( apiKeyPrefix = "AKCp8" apiKeyMinimalLength = 73 + uberTraceIdHeader = "uber-trace-id" ) +// If set, the Uber Trace ID header will be attached to every request. +// This allows users to easily identify which logs on the server side are related to requests sent from this client. +// Should be set using SetUberTraceIdToken. +var uberTraceIdToken string + func IsApiKey(key string) bool { return strings.HasPrefix(key, apiKeyPrefix) && len(key) >= apiKeyMinimalLength } @@ -171,6 +177,7 @@ func (jc *HttpClient) doRequest(req *http.Request, content []byte, followRedirec setAuthentication(req, httpClientsDetails) addUserAgentHeader(req) copyHeaders(httpClientsDetails, req) + addUberTraceIdHeaderIfSet(req) if !followRedirect || (followRedirect && req.Method == http.MethodPost) { jc.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { @@ -220,6 +227,21 @@ func copyHeaders(httpClientsDetails httputils.HttpClientDetails, req *http.Reque } } +// Generate an Uber Trace ID token that will be attached to every request. +// Format of the header: {trace-id}:{span-id}:{parent-span-id}:{flags} +// We set the trace-id and span-id to the same value, and the rest to 0. +func SetUberTraceIdToken(traceIdToken string) { + uberTraceIdToken = fmt.Sprintf("%s:%s:0:0", traceIdToken, traceIdToken) +} + +// If a trace ID is set, this function will attach the Uber Trace ID header to every request. +func addUberTraceIdHeaderIfSet(req *http.Request) { + if uberTraceIdToken == "" { + return + } + req.Header.Set(uberTraceIdHeader, uberTraceIdToken) +} + func setRequestHeaders(httpClientsDetails httputils.HttpClientDetails, size int64, req *http.Request) { copyHeaders(httpClientsDetails, req) length := strconv.FormatInt(size, 10) diff --git a/lifecycle/services/status.go b/lifecycle/services/status.go index a763da5c8..9aeed788e 100644 --- a/lifecycle/services/status.go +++ b/lifecycle/services/status.go @@ -34,6 +34,7 @@ const ( Failed RbStatus = "FAILED" Rejected RbStatus = "REJECTED" Deleting RbStatus = "DELETING" + Started RbStatus = "STARTED" ) func (rbs *ReleaseBundlesService) GetReleaseBundleCreationStatus(rbDetails ReleaseBundleDetails, projectKey string, sync bool) (ReleaseBundleStatusResponse, error) { @@ -128,7 +129,7 @@ func (rbs *ReleaseBundlesService) waitForRbOperationCompletion(restApi, projectK return true, nil, err } switch rbStatusResponse.Status { - case Pending, Processing: + case Pending, Processing, Started: return false, nil, nil case Completed, Rejected, Failed, Deleting: return true, responseBody, nil diff --git a/tests/artifactorymultipartupload_test.go b/tests/artifactorymultipartupload_test.go index 78a4fe11a..6529d2424 100644 --- a/tests/artifactorymultipartupload_test.go +++ b/tests/artifactorymultipartupload_test.go @@ -79,6 +79,7 @@ func createBigFile(t *testing.T) (bigFile *os.File, cleanUp func()) { assert.NoError(t, err) cleanUp = func() { + assert.NoError(t, bigFile.Close()) assert.NoError(t, os.Remove(bigFile.Name())) } diff --git a/utils/utils.go b/utils/utils.go index 8156f25a5..f756ecf59 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -28,7 +28,7 @@ import ( const ( Development = "development" Agent = "jfrog-client-go" - Version = "1.40.1" + Version = "1.40.2" ) type MinVersionProduct string diff --git a/xray/services/report.go b/xray/services/report.go index 194b9ecdf..ee387f8ed 100644 --- a/xray/services/report.go +++ b/xray/services/report.go @@ -152,8 +152,8 @@ type LicensesFilter struct { type ViolationsFilter struct { Type string `json:"type,omitempty"` - WatchNames string `json:"watch_names,omitempty"` - WatchPatterns string `json:"watch_patterns,omitempty"` + WatchNames []string `json:"watch_names,omitempty"` + WatchPatterns []string `json:"watch_patterns,omitempty"` Component string `json:"component,omitempty"` Artifact string `json:"artifact,omitempty"` PolicyNames []string `json:"policy_names,omitempty"` diff --git a/xray/services/utils/graph.go b/xray/services/utils/graph.go index f4d09a485..58d7640b0 100644 --- a/xray/services/utils/graph.go +++ b/xray/services/utils/graph.go @@ -32,6 +32,8 @@ type OtherComponentIds struct { type GraphNode struct { // Node parent (for internal use) Parent *GraphNode `json:"-"` + // The "classifier" attribute in a Maven pom.xml specifies an additional qualifier for a dependency + Classifier *string `json:"-"` // Node file types (tar, jar, zip, pom) Types *[]string `json:"-"` Id string `json:"component_id,omitempty"`