From 1bc5c37294fe621ac79c05689925d8e481f8f28d Mon Sep 17 00:00:00 2001 From: agrasth Date: Tue, 2 Dec 2025 14:28:52 +0530 Subject: [PATCH 1/4] Fix for 'include' flag with spec file Use public Include field for direct assignment. Point to local jfrog-cli-core for development. --- utils/cliutils/utils.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/utils/cliutils/utils.go b/utils/cliutils/utils.go index fb391b77c..bcde7d1a1 100644 --- a/utils/cliutils/utils.go +++ b/utils/cliutils/utils.go @@ -474,6 +474,13 @@ func OverrideFieldsIfSet(spec *speccore.File, c *cli.Context) { overrideStringIfSet(&spec.Symlinks, c, "symlinks") overrideStringIfSet(&spec.Transitive, c, "transitive") overrideStringIfSet(&spec.PublicGpgKey, c, "gpg-key") + overrideIncludeIfSet(spec, c) +} + +func overrideIncludeIfSet(spec *speccore.File, c *cli.Context) { + if c.IsSet("include") { + spec.Include = strings.Split(c.String("include"), ";") + } } func CreateConfigCmd(c *cli.Context, confType project.ProjectType) error { From c655be54ff73401ec5139e7d2866a16d75218e04 Mon Sep 17 00:00:00 2001 From: agrasth Date: Tue, 2 Dec 2025 14:29:00 +0530 Subject: [PATCH 2/4] Add e2e test for 'include' flag with spec file --- artifactory_test.go | 57 +++++++++++++++++++++++++++++++++++++++++++++ go.sum | 2 ++ 2 files changed, 59 insertions(+) diff --git a/artifactory_test.go b/artifactory_test.go index 7f87e7586..33104cb8c 100644 --- a/artifactory_test.go +++ b/artifactory_test.go @@ -5341,6 +5341,63 @@ func TestArtifactorySearchProps(t *testing.T) { cleanArtifactoryTest() } +// Test that the --include flag works correctly with spec files +func TestArtifactorySearchIncludeWithSpec(t *testing.T) { + initArtifactoryTest(t, "") + + // Upload files + specFile, err := tests.CreateSpec(tests.SplitUploadSpecA) + assert.NoError(t, err) + runRt(t, "upload", "--spec="+specFile, "--recursive", "--flat=false") + + // Test 1: Search with spec WITHOUT --include flag (should return all fields) + searchSpecBuilder := spec.NewBuilder().Pattern(tests.RtRepo1 + "/*").Recursive(true) + searchCmd := generic.NewSearchCommand() + searchCmd.SetServerDetails(serverDetails).SetSpec(searchSpecBuilder.BuildSpec()) + reader, err := searchCmd.Search() + assert.NoError(t, err) + + foundWithAllFields := false + for resultItem := new(utils.SearchResult); reader.NextRecord(resultItem) == nil; resultItem = new(utils.SearchResult) { + // Check that we have all default fields (type, size, sha1, etc.) + if resultItem.Type != "" && resultItem.Size > 0 && resultItem.Sha1 != "" { + foundWithAllFields = true + break + } + } + assert.True(t, foundWithAllFields, "Search without --include should return all fields") + readerCloseAndAssert(t, reader) + + // Test 2: Search with spec WITH --include flag using spec builder (simulating CLI flag) + searchSpecBuilder = spec.NewBuilder().Pattern(tests.RtRepo1 + "/*").Recursive(true).Include([]string{"size", "created"}) + searchCmd = generic.NewSearchCommand() + searchCmd.SetServerDetails(serverDetails).SetSpec(searchSpecBuilder.BuildSpec()) + reader, err = searchCmd.Search() + assert.NoError(t, err) + + // Verify limited fields are returned + var resultItems []utils.SearchResult + readerNoDate, err := utils.SearchResultNoDate(reader) + assert.NoError(t, err) + for resultItem := new(utils.SearchResult); readerNoDate.NextRecord(resultItem) == nil; resultItem = new(utils.SearchResult) { + resultItems = append(resultItems, *resultItem) + // Verify that size and created are present (when include is used) + // Note: path, name, repo are always included as base fields + assert.NotEmpty(t, resultItem.Path, "Path should always be present") + // Check that we have the requested field + if resultItem.Size > 0 { + // Size was requested, should be present + assert.Greater(t, resultItem.Size, int64(0), "Size should be present when included") + } + } + assert.Greater(t, len(resultItems), 0, "Should find at least one artifact") + readerGetErrorAndAssert(t, readerNoDate) + readerCloseAndAssert(t, readerNoDate) + + // Cleanup + cleanArtifactoryTest() +} + // Remove not to be deleted dirs from delete command from path to delete. func TestArtifactoryDeleteExcludeProps(t *testing.T) { initArtifactoryTest(t, "") diff --git a/go.sum b/go.sum index ee813c408..01bf2a26b 100644 --- a/go.sum +++ b/go.sum @@ -672,6 +672,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= +github.com/agrasth/jfrog-cli-core/v2 v2.0.0-20251202090349-0dfaccba76c6 h1:PPjm3+uAwhH4O47f0Ofs9Y6Win/3DBMPKDf5LU6w9d4= +github.com/agrasth/jfrog-cli-core/v2 v2.0.0-20251202090349-0dfaccba76c6/go.mod h1:d9aADumiyjCBvZLffp8wldvP9XFHxcvk2PoOSUYms2g= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= From cc873dc6dc4b3613312bb4c51da38edf5666afd6 Mon Sep 17 00:00:00 2001 From: agrasth Date: Tue, 9 Dec 2025 23:10:54 +0530 Subject: [PATCH 3/4] fix: address unsafe deserialization vulnerability in GitHub API response handling - Use json.Decoder with DisallowUnknownFields for safer deserialization - Add validation for version tag format to ensure it matches semantic versioning - Add 10MB size limit to HTTP response body to prevent potential DoS attacks - Addresses Frogbot SAST finding for go-unsafe-deserialization --- utils/cliutils/utils.go | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/utils/cliutils/utils.go b/utils/cliutils/utils.go index bcde7d1a1..0cf5a6d89 100644 --- a/utils/cliutils/utils.go +++ b/utils/cliutils/utils.go @@ -1,6 +1,7 @@ package cliutils import ( + "bytes" "encoding/json" "errors" "fmt" @@ -8,6 +9,7 @@ import ( "net/http" "os" "path/filepath" + "regexp" "strconv" "strings" "time" @@ -650,11 +652,21 @@ func getLatestCliVersionFromGithubAPI() (githubVersionInfo githubResponse, err e if err != nil { return } - err = json.Unmarshal(body, &githubVersionInfo) + // Use json.Decoder with DisallowUnknownFields for safer deserialization + decoder := json.NewDecoder(bytes.NewReader(body)) + decoder.DisallowUnknownFields() + if err = decoder.Decode(&githubVersionInfo); err != nil { + return + } + // Validate the received version tag format + if !isValidVersionTag(githubVersionInfo.TagName) { + err = errors.New("invalid version tag format received from GitHub API") + } return } func doHttpRequest(client *http.Client, req *http.Request) (resp *http.Response, body []byte, err error) { + const maxResponseSize = 10 * 1024 * 1024 // 10MB limit req.Close = true resp, err = client.Do(req) if errorutils.CheckError(err) != nil { @@ -665,10 +677,21 @@ func doHttpRequest(client *http.Client, req *http.Request) (resp *http.Response, err = errors.Join(err, errorutils.CheckError(resp.Body.Close())) } }() - body, err = io.ReadAll(resp.Body) + // Limit response body size to prevent potential DoS + body, err = io.ReadAll(io.LimitReader(resp.Body, maxResponseSize)) return resp, body, errorutils.CheckError(err) } +// isValidVersionTag validates that the version tag follows semantic versioning format +func isValidVersionTag(tag string) bool { + if tag == "" { + return false + } + // Validate semantic versioning format (v1.2.3 or 1.2.3) + matched, _ := regexp.MatchString(`^v?\d+\.\d+\.\d+`, tag) + return matched +} + // Get project key from flag or environment variable func GetProject(c *cli.Context) string { projectKey := c.String("project") From 079e81ee01e19778f6c995dcbd2660591c7aa6e6 Mon Sep 17 00:00:00 2001 From: agrasth Date: Wed, 10 Dec 2025 12:33:41 +0530 Subject: [PATCH 4/4] Updated dependency --- go.mod | 4 ++-- go.sum | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index d1a4d26b5..e5e367e03 100644 --- a/go.mod +++ b/go.mod @@ -16,10 +16,10 @@ require ( github.com/docker/docker v28.5.2+incompatible github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/jfrog/archiver/v3 v3.6.1 - github.com/jfrog/build-info-go v1.12.5-0.20251209120002-025bda5ff78b + github.com/jfrog/build-info-go v1.12.5-0.20251209031413-f5f0e93dc8db github.com/jfrog/gofrog v1.7.6 github.com/jfrog/jfrog-cli-application v1.0.2-0.20251208114900-b3cc968c8e3d - github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20251209121625-98f7b22a08c1 + github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20251210074251-c15fabe27f7f github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20251210085744-f8481d179ac5 github.com/jfrog/jfrog-cli-evidence v0.8.3-0.20251204144808-73fa744851c0 github.com/jfrog/jfrog-cli-platform-services v1.10.1-0.20251205121610-171eb9b0000e diff --git a/go.sum b/go.sum index 01bf2a26b..40f9c6798 100644 --- a/go.sum +++ b/go.sum @@ -672,8 +672,6 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= -github.com/agrasth/jfrog-cli-core/v2 v2.0.0-20251202090349-0dfaccba76c6 h1:PPjm3+uAwhH4O47f0Ofs9Y6Win/3DBMPKDf5LU6w9d4= -github.com/agrasth/jfrog-cli-core/v2 v2.0.0-20251202090349-0dfaccba76c6/go.mod h1:d9aADumiyjCBvZLffp8wldvP9XFHxcvk2PoOSUYms2g= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -1177,8 +1175,8 @@ github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4= github.com/jfrog/archiver/v3 v3.6.1 h1:LOxnkw9pOn45DzCbZNFV6K0+6dCsQ0L8mR3ZcujO5eI= github.com/jfrog/archiver/v3 v3.6.1/go.mod h1:VgR+3WZS4N+i9FaDwLZbq+jeU4B4zctXL+gL4EMzfLw= -github.com/jfrog/build-info-go v1.12.5-0.20251209120002-025bda5ff78b h1:wf8u5g84GW8ZYsM59UGk+1vvcUOCaP75NiGZeOatkC8= -github.com/jfrog/build-info-go v1.12.5-0.20251209120002-025bda5ff78b/go.mod h1:9W4U440fdTHwW1HiB/R0VQvz/5q8ZHsms9MWcq+JrdY= +github.com/jfrog/build-info-go v1.12.5-0.20251209031413-f5f0e93dc8db h1:5q4hUqZVl7Xt+R+ono5lDH1/lkvV1spnfDtp0VtJqlo= +github.com/jfrog/build-info-go v1.12.5-0.20251209031413-f5f0e93dc8db/go.mod h1:9W4U440fdTHwW1HiB/R0VQvz/5q8ZHsms9MWcq+JrdY= github.com/jfrog/froggit-go v1.20.6 h1:Xp7+LlEh0m1KGrQstb+u0aGfjRUtv1eh9xQBV3571jQ= github.com/jfrog/froggit-go v1.20.6/go.mod h1:obSG1SlsWjktkuqmKtpq7MNTTL63e0ot+ucTnlOMV88= github.com/jfrog/go-mockhttp v0.3.1 h1:/wac8v4GMZx62viZmv4wazB5GNKs+GxawuS1u3maJH8= @@ -1189,8 +1187,8 @@ github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYL github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w= github.com/jfrog/jfrog-cli-application v1.0.2-0.20251208114900-b3cc968c8e3d h1:0o6tj4nPP9uCscyfPbKBUcCaIYof42irwii6XsBB8zM= github.com/jfrog/jfrog-cli-application v1.0.2-0.20251208114900-b3cc968c8e3d/go.mod h1:xum2HquWO5uExa/A7MQs3TgJJVEeoqTR+6Z4mfBr1Xw= -github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20251209121625-98f7b22a08c1 h1:vT9QWrwW6pJPcHewSVsDWWoCHq+Nt3UqnEaJjyMqFMU= -github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20251209121625-98f7b22a08c1/go.mod h1:b/Sf+FOjWwoQOZ00r+fXMbDqpts8L0q1lMNgS5cofAs= +github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20251210074251-c15fabe27f7f h1:aoYtLX8ImiaYmStWeTXllidkMy1Hpet/TGOjicf1WhU= +github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20251210074251-c15fabe27f7f/go.mod h1:wKTWZqomaLxrHuvVF4iryZ8V4rn6h2y09jbuOBVRQUY= github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20251210085744-f8481d179ac5 h1:GYE67ubwl+ZRw3CcXFUi49EwwQp6k+qS8sX0QuHDHO8= github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20251210085744-f8481d179ac5/go.mod h1:BMoGi2rG0udCCeaghqlNgiW3fTmT+TNnfTnBoWFYgcg= github.com/jfrog/jfrog-cli-evidence v0.8.3-0.20251204144808-73fa744851c0 h1:8S1vE1PeVtrzWkKL0N39cX6XLLNV0It+f6xjRKjw7Ug=