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
57 changes: 57 additions & 0 deletions artifactory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, "")
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1175,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=
Expand All @@ -1187,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=
Expand Down
34 changes: 32 additions & 2 deletions utils/cliutils/utils.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package cliutils

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -474,6 +476,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 {
Expand Down Expand Up @@ -643,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 {
Expand All @@ -658,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")
Expand Down
Loading