Skip to content

Commit 6a90df7

Browse files
committed
Merge remote-tracking branch 'origin/dev'
2 parents f88345c + dd3599a commit 6a90df7

File tree

22 files changed

+819
-68
lines changed

22 files changed

+819
-68
lines changed

.github/workflows/tests.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,27 @@ jobs:
8282
- name: ${{ matrix.suite }} tests
8383
run: go test -v github.com/jfrog/jfrog-client-go/tests --timeout 0 --test.${{ matrix.suite }} --rt.url=${{ secrets.PLATFORM_URL }}/artifactory --ds.url=${{ secrets.PLATFORM_URL }}/distribution --xr.url=${{ secrets.PLATFORM_URL }}/xray --xsc.url=${{ secrets.PLATFORM_URL }}/xsc --access.url=${{ secrets.PLATFORM_URL }}/access --rt.user=${{ secrets.PLATFORM_USER }} --rt.password=${{ secrets.PLATFORM_PASSWORD }} --access.token=${{ secrets.PLATFORM_ADMIN_TOKEN }} --ci.runId=${{ runner.os }}-${{ matrix.suite }}
8484

85+
JFrog-Client-Go-Catalog-Tests:
86+
name: ${{ matrix.suite }} ${{ matrix.os }}
87+
needs: Pretest
88+
strategy:
89+
fail-fast: false
90+
matrix:
91+
suite: [ catalog ]
92+
os: [ ubuntu, windows, macos ]
93+
runs-on: ${{ matrix.os }}-latest
94+
steps:
95+
- name: Checkout code
96+
uses: actions/checkout@v4
97+
with:
98+
ref: ${{ github.event.pull_request.head.sha }}
99+
100+
- name: Setup Go with cache
101+
uses: jfrog/.github/actions/install-go-with-cache@main
102+
103+
- name: catalog tests
104+
run: go test -v github.com/jfrog/jfrog-client-go/tests --timeout 0 --test.${{ matrix.suite }} --ci.runId=${{ runner.os }}-${{ matrix.suite }}
105+
85106
JFrog-Client-Go-Repositories-Tests:
86107
needs: Pretest
87108
name: repositories ubuntu-latest

README.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2850,6 +2850,92 @@ source := CreateFromReleaseBundlesSource{ReleaseBundles: []ReleaseBundleSource{
28502850
serviceManager.CreateReleaseBundleFromBundles(rbDetails, params, signingKeyName, source)
28512851
```
28522852
2853+
#### Creating a Release Bundle From Packages
2854+
2855+
```go
2856+
rbDetails := ReleaseBundleDetails{"rbName", "rbVersion"}
2857+
queryParams := CommonOptionalQueryParams{}
2858+
queryParams.ProjectKey = "project"
2859+
queryParams.Async = true
2860+
2861+
// The GPG/RSA key-pair name given in Artifactory.
2862+
signingKeyName = "key-pair"
2863+
2864+
source := CreateFromPackagesSource{Packages: []PackageSource{
2865+
{
2866+
PackageName: "name",
2867+
PackageVersion: "version",
2868+
PackageType: "type",
2869+
RepositoryKey: "repokey",
2870+
},
2871+
}}
2872+
serviceManager.CreateReleaseBundleFromPackages(rbDetails, params, signingKeyName, source)
2873+
```
2874+
2875+
#### Creating a Release Bundle From Multiple Sources
2876+
2877+
```go
2878+
rbDetails := ReleaseBundleDetails{"rbName", "rbVersion"}
2879+
queryParams := CommonOptionalQueryParams{}
2880+
queryParams.ProjectKey = "project"
2881+
queryParams.Async = true
2882+
2883+
// The GPG/RSA key-pair name given in Artifactory.
2884+
signingKeyName = "key-pair"
2885+
2886+
sources := [] RbSource{
2887+
{
2888+
SourceType: "builds",
2889+
Builds: []BuildSource{
2890+
{
2891+
BuildName: "name",
2892+
BuildNumber: "number",
2893+
// Optional:
2894+
BuildRepository: "artifactory-build-info",
2895+
},
2896+
}
2897+
},
2898+
{
2899+
SourceType: "release_bundles",
2900+
ReleaseBundles: []ReleaseBundleSource{
2901+
{
2902+
ReleaseBundleName: "name",
2903+
ReleaseBundleVersion: "version",
2904+
ProjectKey: "default",
2905+
},
2906+
}
2907+
},
2908+
{
2909+
SourceType: "artifacts",
2910+
Artifacts: []ArtifactSource{
2911+
{
2912+
Path: "repo/path/file",
2913+
Sha256: "3e3deb6628658a48cf0d280a2210211f9d977ec2e10a4619b95d5fb85cb10450",
2914+
},
2915+
}
2916+
},
2917+
{
2918+
SourceType: "packages",
2919+
Packages: []PackageSource{
2920+
{
2921+
PackageName: "name",
2922+
PackageVersion: "version",
2923+
PackageType: "type",
2924+
RepositoryKey: "repokey"
2925+
},
2926+
}
2927+
},
2928+
{
2929+
SourceType: "aql",
2930+
Aql: {
2931+
`items.find({"repo": "my-repo","path": ".","name": "a2.in"})`
2932+
}
2933+
},
2934+
}
2935+
2936+
serviceManager.CreateReleaseBundlesFromMultipleSources(rbDetails, params, signingKeyName, sources)
2937+
```
2938+
28532939
#### Promoting a Release Bundle
28542940
28552941
```go
@@ -3094,6 +3180,7 @@ envelopeBytes := []byte("envelope")
30943180
evidenceDetails := evidenceService.EvidenceDetails{
30953181
SubjectUri: "subjectUri",
30963182
DSSEFileRaw: &envelopeBytes,
3183+
ProviderId: "someProviderId",
30973184
}
30983185
body, err = evideceManager.UploadEvidence(evidenceDetails)
30993186
```

access/services/accesstoken.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,31 @@ type CreateTokenParams struct {
3232
Description string `json:"description,omitempty"`
3333
}
3434

35+
type VcsCommit struct {
36+
VcsUrl string `json:"vcs_url,omitempty"`
37+
Branch string `json:"branch,omitempty"`
38+
Revision string `json:"revision,omitempty"`
39+
}
40+
41+
type Context struct {
42+
VcsCommit *VcsCommit `json:"vcs_commit,omitempty"`
43+
}
44+
3545
type CreateOidcTokenParams struct {
36-
GrantType string `json:"grant_type,omitempty"`
37-
SubjectTokenType string `json:"subject_token_type,omitempty"`
38-
OidcTokenID string `json:"subject_token,omitempty"`
39-
ProviderName string `json:"provider_name,omitempty"`
40-
ProjectKey string `json:"project_key,omitempty"`
41-
JobId string `json:"job_id,omitempty"`
42-
RunId string `json:"run_id,omitempty"`
43-
Repo string `json:"repo,omitempty"`
44-
ApplicationKey string `json:"application_key,omitempty"`
45-
Audience string `json:"audience,omitempty"`
46-
ProviderType string `json:"provider_type,omitempty"`
47-
IdentityMappingName string `json:"identity_mapping_name,omitempty"`
48-
IncludeReferenceToken *bool `json:"include_reference_token,omitempty"`
46+
GrantType string `json:"grant_type,omitempty"`
47+
SubjectTokenType string `json:"subject_token_type,omitempty"`
48+
OidcTokenID string `json:"subject_token,omitempty"`
49+
ProviderName string `json:"provider_name,omitempty"`
50+
ProjectKey string `json:"project_key,omitempty"`
51+
JobId string `json:"job_id,omitempty"`
52+
RunId string `json:"run_id,omitempty"`
53+
Repo string `json:"repo,omitempty"`
54+
ApplicationKey string `json:"application_key,omitempty"`
55+
Audience string `json:"audience,omitempty"`
56+
ProviderType string `json:"provider_type,omitempty"`
57+
IdentityMappingName string `json:"identity_mapping_name,omitempty"`
58+
IncludeReferenceToken *bool `json:"include_reference_token,omitempty"`
59+
Context *Context `json:"context,omitempty"`
4960
}
5061

5162
func NewCreateTokenParams(params CreateTokenParams) CreateTokenParams {

artifactory/services/promote.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func (ps *PromoteService) BuildPromote(promotionParams PromotionParams) error {
7676
if err != nil {
7777
return err
7878
}
79-
79+
8080
if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil {
8181
return err
8282
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package catalog
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"os"
7+
"testing"
8+
9+
"github.com/CycloneDX/cyclonedx-go"
10+
"github.com/jfrog/jfrog-client-go/utils/log"
11+
"github.com/jfrog/jfrog-client-go/utils/tests"
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
type MockServerParams struct {
16+
EnrichedVuln []cyclonedx.Vulnerability
17+
Alive bool
18+
}
19+
20+
func StartCatalogMockServerWithParams(t *testing.T, params MockServerParams) int {
21+
handlers := tests.HttpServerHandlers{}
22+
23+
handlers["/"] = http.NotFound
24+
// Version handlers (version is not available in Catalog, so we use ping endpoint)
25+
handlers["/catalog/api/v1/system/ping"] = catalogGetVersionHandlerFunc(t, params)
26+
// Enrich handlers
27+
handlers["/catalog/api/v1/beta/cyclonedx/enrich"] = catalogEnrichHandler(t, params)
28+
29+
port, err := tests.StartHttpServer(handlers)
30+
if err != nil {
31+
log.Error(err)
32+
os.Exit(1)
33+
}
34+
return port
35+
}
36+
37+
func catalogGetVersionHandlerFunc(t *testing.T, params MockServerParams) func(w http.ResponseWriter, r *http.Request) {
38+
version := "1.0.0"
39+
return func(w http.ResponseWriter, r *http.Request) {
40+
if !params.Alive {
41+
http.Error(w, "Catalog service is not available", http.StatusServiceUnavailable)
42+
return
43+
}
44+
if r.Method == http.MethodGet {
45+
_, err := fmt.Fprint(w, version)
46+
assert.NoError(t, err)
47+
return
48+
}
49+
http.Error(w, "Invalid catalog request", http.StatusBadRequest)
50+
}
51+
}
52+
53+
func catalogEnrichHandler(t *testing.T, params MockServerParams) func(w http.ResponseWriter, r *http.Request) {
54+
return func(w http.ResponseWriter, r *http.Request) {
55+
if !params.Alive {
56+
http.Error(w, "Catalog service is not available", http.StatusServiceUnavailable)
57+
return
58+
}
59+
if r.Method == http.MethodPost {
60+
// Read the BOM from the request body
61+
bom := cyclonedx.NewBOM()
62+
assert.NoError(t, cyclonedx.NewBOMDecoder(r.Body, cyclonedx.BOMFileFormatJSON).Decode(bom))
63+
// Enrich the BOM with vulnerabilities
64+
for _, vuln := range params.EnrichedVuln {
65+
if bom.Vulnerabilities == nil {
66+
bom.Vulnerabilities = &[]cyclonedx.Vulnerability{}
67+
}
68+
*bom.Vulnerabilities = append(*bom.Vulnerabilities, vuln)
69+
}
70+
// Encode the enriched BOM to JSON format and write it to the response
71+
writer := cyclonedx.NewBOMEncoder(w, cyclonedx.BOMFileFormatJSON)
72+
err := writer.Encode(bom)
73+
assert.NoError(t, err)
74+
return
75+
}
76+
http.Error(w, "Invalid enrich request", http.StatusBadRequest)
77+
}
78+
}

catalog/auth/catalogdetails.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package auth
2+
3+
import (
4+
"github.com/jfrog/jfrog-client-go/auth"
5+
"github.com/jfrog/jfrog-client-go/catalog"
6+
"github.com/jfrog/jfrog-client-go/config"
7+
"github.com/jfrog/jfrog-client-go/utils/log"
8+
)
9+
10+
// NewCatalogDetails creates a struct of the Catalog details
11+
func NewCatalogDetails() *catalogDetails {
12+
return &catalogDetails{}
13+
}
14+
15+
type catalogDetails struct {
16+
auth.CommonConfigFields
17+
}
18+
19+
func (cs *catalogDetails) GetVersion() (string, error) {
20+
var err error
21+
if cs.Version == "" {
22+
cs.Version, err = cs.getCatalogVersion()
23+
if err != nil {
24+
return "", err
25+
}
26+
log.Debug("JFrog Catalog version is:", cs.Version)
27+
}
28+
return cs.Version, nil
29+
}
30+
31+
func (ds *catalogDetails) getCatalogVersion() (string, error) {
32+
cd := auth.ServiceDetails(ds)
33+
serviceConfig, err := config.NewConfigBuilder().
34+
SetServiceDetails(cd).
35+
SetCertificatesPath(cd.GetClientCertPath()).
36+
Build()
37+
if err != nil {
38+
return "", err
39+
}
40+
cm, err := catalog.New(serviceConfig)
41+
if cm != nil {
42+
return "", err
43+
}
44+
return cm.GetVersion()
45+
}

catalog/manager.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package catalog
2+
3+
import (
4+
"github.com/CycloneDX/cyclonedx-go"
5+
"github.com/jfrog/jfrog-client-go/auth"
6+
"github.com/jfrog/jfrog-client-go/catalog/services"
7+
"github.com/jfrog/jfrog-client-go/config"
8+
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient"
9+
)
10+
11+
// CatalogServicesManager defines the http client and general configuration
12+
type CatalogServicesManager struct {
13+
client *jfroghttpclient.JfrogHttpClient
14+
config config.Config
15+
// Global reference to the provided project key, used for API endpoints that require it for authentication
16+
scopeProjectKey string
17+
}
18+
19+
// New creates a service manager to interact with Catalog
20+
func New(config config.Config) (*CatalogServicesManager, error) {
21+
details := config.GetServiceDetails()
22+
var err error
23+
manager := &CatalogServicesManager{config: config}
24+
manager.client, err = buildJFrogHttpClient(config, details)
25+
return manager, err
26+
}
27+
28+
func buildJFrogHttpClient(config config.Config, authDetails auth.ServiceDetails) (*jfroghttpclient.JfrogHttpClient, error) {
29+
return jfroghttpclient.JfrogClientBuilder().
30+
SetCertificatesPath(config.GetCertificatesPath()).
31+
SetInsecureTls(config.IsInsecureTls()).
32+
SetContext(config.GetContext()).
33+
SetDialTimeout(config.GetDialTimeout()).
34+
SetOverallRequestTimeout(config.GetOverallRequestTimeout()).
35+
SetClientCertPath(authDetails.GetClientCertPath()).
36+
SetClientCertKeyPath(authDetails.GetClientCertKeyPath()).
37+
AppendPreRequestInterceptor(authDetails.RunPreRequestFunctions).
38+
SetRetries(config.GetHttpRetries()).
39+
SetRetryWaitMilliSecs(config.GetHttpRetryWaitMilliSecs()).
40+
Build()
41+
}
42+
43+
func (cm *CatalogServicesManager) SetProjectKey(projectKey string) *CatalogServicesManager {
44+
cm.scopeProjectKey = projectKey
45+
return cm
46+
}
47+
48+
// GetVersion will return the Catalog version
49+
func (cm *CatalogServicesManager) GetVersion() (string, error) {
50+
versionService := services.NewVersionService(cm.client)
51+
versionService.CatalogDetails = cm.config.GetServiceDetails()
52+
return versionService.GetVersion()
53+
}
54+
55+
// Enrich will enrich the CycloneDX BOM with additional security information
56+
func (cm *CatalogServicesManager) Enrich(bom *cyclonedx.BOM) (*cyclonedx.BOM, error) {
57+
enrichService := services.NewEnrichService(cm.client)
58+
enrichService.CatalogDetails = cm.config.GetServiceDetails()
59+
enrichService.ScopeProjectKey = cm.scopeProjectKey
60+
return enrichService.Enrich(bom)
61+
}

0 commit comments

Comments
 (0)