Skip to content

Commit

Permalink
Add client for Evidence service
Browse files Browse the repository at this point in the history
  • Loading branch information
davidlesfrog committed May 29, 2024
1 parent 145a579 commit 55101b7
Show file tree
Hide file tree
Showing 7 changed files with 297 additions and 0 deletions.
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,20 @@
- [Export Release Bundle](#export-release-bundle)
- [Import Release Bundle](#import-release-bundle)
- [Remote Delete Release Bundle](#remote-delete-release-bundle)
- [Lifecycle APIs](#lifecycle-apis)
- [Creating Lifecycle Service Manager](#creating-lifeCycle-service-manager)
- [Creating Lifecycle Details](#creating-lifeCycle-details)
- [Creating Lifecycle Service Config](#creating-lifeCycle-service-config)
- [Creating New Lifecycle Service Manager](#creating-new-lifeCycle-service-manager)
- [Using Lifecycle Services](#using-lifeCycle-services)
- [Creating a Release Bundle From AQL](#creating-a-release-bundle-from-aql)
- [Evidence APIs](#evidence-apis)
- [Creating Evidence Service Manager](#creating-evidence-service-manager)
- [Creating Evidence Details](#creating-evidence-details)
- [Creating Evidence Service Config](#creating-evidence-service-config)
- [Creating New Evidence Service Manager](#creating-new-evidence-service-manager)
- [Using Evidence Services](#using-evidence-services)
- [Uploda Evidence](#upload-evidence)

## General

Expand Down Expand Up @@ -2754,3 +2768,48 @@ dryRun := true

resp, err := serviceManager.RemoteDeleteReleaseBundle(params, dryRun)
```
## Evidence APIs
### Creating Evidence Service Manager
#### Creating Evidence Details
```go
evdDetails := auth.NewEvidenceDetails()
evdDetails.SetUrl("http://localhost:8081/evidence")
evdDetails.SetAccessToken("access-token")
// if client certificates are required
evdDetails.SetClientCertPath("path/to/.cer")
evdDetails.SetClientCertKeyPath("path/to/.key")
```
#### Creating Evidence Service Config
```go
serviceConfig, err := config.NewConfigBuilder().
SetServiceDetails(evdDetails).
SetCertificatesPath(evdDetails.GetClientCertPath()).
// Optionally overwrite the default HTTP retries, which is set to 3.
SetHttpRetries(3).
Build()
```
#### Creating New Evidence Service Manager
```go
evidenceManager, err := evidence.New(serviceConfig)
```
### Using Evidence Services
#### Upload Evidence
```go
envelopeBytes := []byte("envelope")

evidenceDetails := evidenceService.EvidenceDetails{
SubjectUri: "subjectUri",
DSSEFileRaw: &envelopeBytes,
}
body, err = evideceManager.UploadEvidence(evidenceDetails)
```
17 changes: 17 additions & 0 deletions evidence/auth/evidencedetails.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package auth

import (
"github.com/jfrog/jfrog-client-go/auth"
)

func NewEvidenceDetails() auth.ServiceDetails {
return &evidenceDetails{}
}

type evidenceDetails struct {
auth.CommonConfigFields
}

func (rt *evidenceDetails) GetVersion() (string, error) {
panic("Failed: Method is not implemented")
}
59 changes: 59 additions & 0 deletions evidence/evidence_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package evidence

import (
"encoding/json"
artifactoryAuth "github.com/jfrog/jfrog-client-go/artifactory/auth"
evidence "github.com/jfrog/jfrog-client-go/evidence/services"
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"testing"
)

var dsseRaw = []byte("someData")

var evidenceData = evidence.EvidenceDetails{
SubjectUri: "someUri",
DSSEFileRaw: &dsseRaw,
}

func TestEvidenceServicesManager_UploadEvidence(t *testing.T) {
handlerFunc, requestNum := createDefaultHandlerFunc(t)

mockServer, evdService := createMockServer(t, handlerFunc)
defer mockServer.Close()

_, err := evdService.UploadEvidence(evidenceData)
assert.NoError(t, err)
assert.Equal(t, 0, *requestNum)
}

func createMockServer(t *testing.T, testHandler http.HandlerFunc) (*httptest.Server, *evidence.EvidenceService) {
testServer := httptest.NewServer(testHandler)

rtDetails := artifactoryAuth.NewArtifactoryDetails()
rtDetails.SetUrl(testServer.URL + "/")

client, err := jfroghttpclient.JfrogClientBuilder().Build()
assert.NoError(t, err)
return testServer, evidence.NewEvidenceService(rtDetails, client)
}

func createDefaultHandlerFunc(t *testing.T) (http.HandlerFunc, *int) {
requestNum := 0
return func(w http.ResponseWriter, r *http.Request) {
if r.RequestURI == "/api/v1/subject" {
w.WriteHeader(http.StatusOK)
requestNum++
writeMockStatusResponse(t, w, dsseRaw)
}
}, &requestNum
}

func writeMockStatusResponse(t *testing.T, w http.ResponseWriter, payload []byte) {
content, err := json.Marshal(payload)
assert.NoError(t, err)
_, err = w.Write(content)
assert.NoError(t, err)
}
41 changes: 41 additions & 0 deletions evidence/manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package evidence

import (
"github.com/jfrog/jfrog-client-go/config"
"github.com/jfrog/jfrog-client-go/evidence/services"
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient"
)

type EvidenceServicesManager struct {
client *jfroghttpclient.JfrogHttpClient
config config.Config
}

func New(config config.Config) (*EvidenceServicesManager, error) {
details := config.GetServiceDetails()
var err error
manager := &EvidenceServicesManager{config: config}
manager.client, err = jfroghttpclient.JfrogClientBuilder().
SetCertificatesPath(config.GetCertificatesPath()).
SetInsecureTls(config.IsInsecureTls()).
SetClientCertPath(details.GetClientCertPath()).
SetClientCertKeyPath(details.GetClientCertKeyPath()).
AppendPreRequestInterceptor(details.RunPreRequestFunctions).
SetContext(config.GetContext()).
SetDialTimeout(config.GetDialTimeout()).
SetOverallRequestTimeout(config.GetOverallRequestTimeout()).
SetRetries(config.GetHttpRetries()).
SetRetryWaitMilliSecs(config.GetHttpRetryWaitMilliSecs()).
Build()

return manager, err
}

func (esm *EvidenceServicesManager) Client() *jfroghttpclient.JfrogHttpClient {
return esm.client
}

func (esm *EvidenceServicesManager) UploadEvidence(evidenceDetails services.EvidenceDetails) ([]byte, error) {
evidenceService := services.NewEvidenceService(esm.config.GetServiceDetails(), esm.client)
return evidenceService.UploadEvidence(evidenceDetails)
}
43 changes: 43 additions & 0 deletions evidence/services/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package services

import "path"

const (
evidenceCreateAPI = "api/v1/subject"
)

type createEvidenceOperation struct {
evidenceBody EvidenceCreationBody
}

func (c *createEvidenceOperation) getOperationRestApi() string {
return path.Join(evidenceCreateAPI, c.evidenceBody.SubjectUri)
}

func (c *createEvidenceOperation) getRequestBody() *[]byte {
return c.evidenceBody.DSSEFileRaw
}

func (c *createEvidenceOperation) getOperationSuccessfulMsg() string {
return "Evidence is successfully created"
}

func (rbs *EvidenceService) UploadEvidence(evidenceDetails EvidenceDetails) ([]byte, error) {
operation := createEvidenceOperation{
evidenceBody: EvidenceCreationBody{
EvidenceDetails: evidenceDetails,
},
}
body, err := rbs.doOperation(&operation)
return body, err
}

type SourceBuildDetails struct {
BuildName string
BuildNumber string
ProjectKey string
}

type EvidenceCreationBody struct {
EvidenceDetails
}
52 changes: 52 additions & 0 deletions evidence/services/operation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package services

import (
rtUtils "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
"github.com/jfrog/jfrog-client-go/auth"
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"net/http"
"net/url"
)

type EvidenceService struct {
client *jfroghttpclient.JfrogHttpClient
evidenceDetails *auth.ServiceDetails
}

func NewEvidenceService(evidenceDetails auth.ServiceDetails, client *jfroghttpclient.JfrogHttpClient) *EvidenceService {
return &EvidenceService{evidenceDetails: &evidenceDetails, client: client}
}

func (es *EvidenceService) GetEvidenceDetails() auth.ServiceDetails {
return *es.evidenceDetails
}

type EvidenceOperation interface {
getOperationRestApi() string
getRequestBody() *[]byte
getOperationSuccessfulMsg() string
}

func (es *EvidenceService) doOperation(operation EvidenceOperation) ([]byte, error) {
u := url.URL{Path: operation.getOperationRestApi()}
requestFullUrl, err := url.Parse(es.GetEvidenceDetails().GetUrl() + u.String())
if err != nil {
return []byte{}, errorutils.CheckError(err)
}

httpClientDetails := es.GetEvidenceDetails().CreateHttpClientDetails()
rtUtils.SetContentType("application/json", &httpClientDetails.Headers)

resp, body, err := es.client.SendPost(requestFullUrl.String(), *operation.getRequestBody(), &httpClientDetails)
if err != nil {
return []byte{}, err
}

return body, errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK, http.StatusCreated)
}

type EvidenceDetails struct {
SubjectUri string `json:"subject_uri"`
DSSEFileRaw *[]byte `json:"dsse_file_raw"`
}
26 changes: 26 additions & 0 deletions tests/timeout_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package tests

import (
"github.com/jfrog/jfrog-client-go/evidence"
"github.com/jfrog/jfrog-client-go/evidence/services"
"net/http"
"net/http/httptest"
"testing"
Expand All @@ -18,6 +20,7 @@ import (

distributionAuth "github.com/jfrog/jfrog-client-go/distribution/auth"
distributionServices "github.com/jfrog/jfrog-client-go/distribution/services"
evidenceAuth "github.com/jfrog/jfrog-client-go/evidence/auth"
lifecycleAuth "github.com/jfrog/jfrog-client-go/lifecycle/auth"
lifecycleServices "github.com/jfrog/jfrog-client-go/lifecycle/services"
pipelinesAuth "github.com/jfrog/jfrog-client-go/pipelines/auth"
Expand All @@ -44,6 +47,7 @@ func TestTimeout(t *testing.T) {
t.Run("testLifecycleTimeout", testLifecycleTimeout)
t.Run("testPipelinesTimeout", testPipelinesTimeout)
t.Run("testXrayTimeout", testXrayTimeout)
t.Run("testEvidenceTimeout", testEvidenceTimeout)
}

func testAccessTimeout(t *testing.T) {
Expand Down Expand Up @@ -110,6 +114,28 @@ func testLifecycleTimeout(t *testing.T) {
assert.ErrorContains(t, err, "context deadline exceeded")
}

func testEvidenceTimeout(t *testing.T) {
// Create mock server
url, cleanup := createSleepyRequestServer()
defer cleanup()

// Create services manager configuring to work with the mock server
details := evidenceAuth.NewEvidenceDetails()
details.SetUrl(url)
servicesManager, err := evidence.New(createServiceConfigWithTimeout(t, details))
assert.NoError(t, err)

dsseFile := []byte("dsse file")
serviceDetails := services.EvidenceDetails{
SubjectUri: "repository/path/to/file.txt",
DSSEFileRaw: &dsseFile,
}

// Expect timeout
_, err = servicesManager.UploadEvidence(serviceDetails)
assert.ErrorContains(t, err, "context deadline exceeded")
}

func testPipelinesTimeout(t *testing.T) {
// Create mock server
url, cleanup := createSleepyRequestServer()
Expand Down

0 comments on commit 55101b7

Please sign in to comment.