Skip to content

Commit 48a7097

Browse files
authored
Add GitHub Actions summary for the create evidence command (#112)
1 parent d5a26e5 commit 48a7097

20 files changed

+773
-84
lines changed

evidence/create/create_base.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,22 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7+
evidenceUtils "github.com/jfrog/jfrog-cli-artifactory/evidence/utils"
78
"os"
89
"strings"
910

10-
"github.com/jfrog/jfrog-cli-artifactory/evidence/sign"
11+
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/commandsummary"
1112

12-
"github.com/jfrog/gofrog/log"
1313
"github.com/jfrog/jfrog-cli-artifactory/evidence/cryptox"
1414
"github.com/jfrog/jfrog-cli-artifactory/evidence/dsse"
1515
"github.com/jfrog/jfrog-cli-artifactory/evidence/intoto"
1616
"github.com/jfrog/jfrog-cli-artifactory/evidence/model"
17+
"github.com/jfrog/jfrog-cli-artifactory/evidence/sign"
1718
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
1819
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
1920
"github.com/jfrog/jfrog-client-go/artifactory"
2021
evidenceService "github.com/jfrog/jfrog-client-go/evidence/services"
21-
clientlog "github.com/jfrog/jfrog-client-go/utils/log"
22+
"github.com/jfrog/jfrog-client-go/utils/log"
2223
)
2324

2425
type createEvidenceBase struct {
@@ -149,10 +150,10 @@ func (c *createEvidenceBase) setMarkdown(statement *intoto.Statement) error {
149150
return nil
150151
}
151152

152-
func (c *createEvidenceBase) uploadEvidence(evidencePayload []byte, repoPath string) error {
153+
func (c *createEvidenceBase) uploadEvidence(evidencePayload []byte, repoPath string) (*model.CreateResponse, error) {
153154
evidenceManager, err := utils.CreateEvidenceServiceManager(c.serverDetails, false)
154155
if err != nil {
155-
return err
156+
return nil, err
156157
}
157158

158159
evidenceDetails := evidenceService.EvidenceDetails{
@@ -161,23 +162,36 @@ func (c *createEvidenceBase) uploadEvidence(evidencePayload []byte, repoPath str
161162
DSSEFileRaw: evidencePayload,
162163
ProviderId: c.providerId,
163164
}
164-
clientlog.Debug("Uploading evidence for subject:", repoPath)
165+
log.Debug("Uploading evidence for subject:", repoPath)
165166
body, err := evidenceManager.UploadEvidence(evidenceDetails)
166167
if err != nil {
167-
return err
168+
return nil, err
168169
}
169170

170171
createResponse := &model.CreateResponse{}
171172
err = json.Unmarshal(body, createResponse)
172173
if err != nil {
173-
return err
174+
return nil, err
174175
}
175176
if createResponse.Verified {
176-
clientlog.Info("Evidence successfully created and verified")
177+
log.Info("Evidence successfully created and verified")
178+
} else {
179+
log.Info("Evidence successfully created but not verified due to missing/invalid public key")
180+
}
181+
return createResponse, nil
182+
}
183+
184+
func (c *createEvidenceBase) recordEvidenceSummary(summaryData commandsummary.EvidenceSummaryData) error {
185+
if !evidenceUtils.IsRunningUnderGitHubAction() {
177186
return nil
178187
}
179-
clientlog.Info("Evidence successfully created but not verified due to missing/invalid public key")
180-
return nil
188+
189+
evidenceSummary, err := commandsummary.NewEvidenceSummary()
190+
if err != nil {
191+
return err
192+
}
193+
194+
return evidenceSummary.Record(summaryData)
181195
}
182196

183197
func (c *createEvidenceBase) createArtifactoryClient() (artifactory.ArtifactoryServicesManager, error) {

evidence/create/create_base_test.go

Lines changed: 162 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ import (
1010

1111
"github.com/jfrog/jfrog-cli-artifactory/evidence/dsse"
1212
"github.com/jfrog/jfrog-cli-artifactory/evidence/intoto"
13+
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/commandsummary"
1314
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
15+
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
1416
"github.com/jfrog/jfrog-client-go/evidence/services"
1517
"github.com/jfrog/jfrog-client-go/utils/errorutils"
16-
clientlog "github.com/jfrog/jfrog-client-go/utils/log"
18+
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
19+
"github.com/jfrog/jfrog-client-go/utils/log"
1720
"github.com/stretchr/testify/assert"
1821
)
1922

@@ -32,9 +35,9 @@ func (m *MockEvidenceServiceManager) UploadEvidence(details services.EvidenceDet
3235

3336
func TestUploadEvidence_ErrorHandling(t *testing.T) {
3437
// Save the current log level and set it to DEBUG for testing
35-
originalLogLevel := clientlog.GetLogger().GetLogLevel()
36-
clientlog.SetLogger(clientlog.NewLogger(clientlog.DEBUG, nil))
37-
defer clientlog.SetLogger(clientlog.NewLogger(originalLogLevel, nil))
38+
originalLogLevel := log.GetLogger().GetLogLevel()
39+
log.SetLogger(log.NewLogger(log.DEBUG, nil))
40+
defer log.SetLogger(log.NewLogger(originalLogLevel, nil))
3841

3942
tests := []struct {
4043
name string
@@ -99,7 +102,7 @@ func TestUploadEvidence_ErrorHandling(t *testing.T) {
99102
func (c *createEvidenceBase) handleUploadError(err error, repoPath string) error {
100103
errStr := err.Error()
101104
if strings.Contains(errStr, "400") || strings.Contains(errStr, "404") {
102-
clientlog.Debug("Server response error:", err.Error())
105+
log.Debug("Server response error:", err.Error())
103106
return errorutils.CheckErrorf("Subject '%s' is invalid or not found. Please ensure the subject exists and follows the correct format: <repo>/<path>/<name> or <repo>/<name>", repoPath)
104107
}
105108
return err
@@ -166,3 +169,157 @@ func TestCreateAndSignEnvelope(t *testing.T) {
166169
})
167170
}
168171
}
172+
func TestCreateEvidenceBase_RecordEvidenceSummaryIfInGitHubActions_NotInGitHub(t *testing.T) {
173+
assert.NoError(t, os.Unsetenv("GITHUB_ACTIONS"))
174+
175+
base := &createEvidenceBase{
176+
predicateType: "https://slsa.dev/provenance/v1",
177+
providerId: "test-provider",
178+
}
179+
180+
summaryData := commandsummary.EvidenceSummaryData{
181+
Subject: "/test/subject",
182+
Verified: true,
183+
PredicateType: base.predicateType,
184+
}
185+
err := base.recordEvidenceSummary(summaryData)
186+
assert.NoError(t, err)
187+
}
188+
189+
func TestCreateEvidenceBase_RecordEvidenceSummaryIfInGitHubActions_GitHubCommiter(t *testing.T) {
190+
tempDir, err := fileutils.CreateTempDir()
191+
assert.NoError(t, err)
192+
defer func() {
193+
assert.NoError(t, fileutils.RemoveTempDir(tempDir))
194+
}()
195+
196+
assert.NoError(t, os.Setenv("GITHUB_ACTIONS", "true"))
197+
assert.NoError(t, os.Setenv(coreutils.SummaryOutputDirPathEnv, tempDir))
198+
defer func() {
199+
assert.NoError(t, os.Unsetenv("GITHUB_ACTIONS"))
200+
assert.NoError(t, os.Unsetenv(coreutils.SummaryOutputDirPathEnv))
201+
}()
202+
203+
base := &createEvidenceBase{
204+
predicateType: "https://slsa.dev/provenance/v1",
205+
providerId: "test-provider",
206+
flagType: "gh-commiter",
207+
}
208+
209+
summaryData := commandsummary.EvidenceSummaryData{
210+
Subject: "/test/subject",
211+
Verified: true,
212+
PredicateType: base.predicateType,
213+
}
214+
err = base.recordEvidenceSummary(summaryData)
215+
assert.NoError(t, err)
216+
}
217+
218+
func TestCreateEvidenceBase_RecordEvidenceSummaryIfInGitHubActions_Success(t *testing.T) {
219+
tempDir, err := fileutils.CreateTempDir()
220+
assert.NoError(t, err)
221+
defer func() {
222+
assert.NoError(t, fileutils.RemoveTempDir(tempDir))
223+
}()
224+
225+
assert.NoError(t, os.Setenv("GITHUB_ACTIONS", "true"))
226+
assert.NoError(t, os.Setenv(coreutils.SummaryOutputDirPathEnv, tempDir))
227+
defer func() {
228+
assert.NoError(t, os.Unsetenv("GITHUB_ACTIONS"))
229+
assert.NoError(t, os.Unsetenv(coreutils.SummaryOutputDirPathEnv))
230+
}()
231+
232+
base := &createEvidenceBase{
233+
predicateType: "https://slsa.dev/provenance/v1",
234+
providerId: "test-provider",
235+
flagType: "other",
236+
}
237+
238+
summaryData := commandsummary.EvidenceSummaryData{
239+
Subject: "/docker-cosign-test/hello-world",
240+
Verified: true,
241+
PredicateType: base.predicateType,
242+
}
243+
err = base.recordEvidenceSummary(summaryData)
244+
assert.NoError(t, err)
245+
}
246+
247+
func TestCreateEvidenceBase_RecordEvidenceSummaryIfInGitHubActions_NoSummaryEnv(t *testing.T) {
248+
assert.NoError(t, os.Setenv("GITHUB_ACTIONS", "true"))
249+
assert.NoError(t, os.Unsetenv(coreutils.SummaryOutputDirPathEnv))
250+
defer func() {
251+
assert.NoError(t, os.Unsetenv("GITHUB_ACTIONS"))
252+
}()
253+
254+
base := &createEvidenceBase{
255+
predicateType: "https://slsa.dev/provenance/v1",
256+
providerId: "test-provider",
257+
flagType: "other",
258+
}
259+
260+
summaryData := commandsummary.EvidenceSummaryData{
261+
Subject: "/test/subject",
262+
Verified: true,
263+
PredicateType: base.predicateType,
264+
}
265+
err := base.recordEvidenceSummary(summaryData)
266+
assert.Error(t, err)
267+
}
268+
269+
func TestCreateEvidenceBase_RecordEvidenceSummaryIfInGitHubActions_Verified(t *testing.T) {
270+
tempDir, err := fileutils.CreateTempDir()
271+
assert.NoError(t, err)
272+
defer func() {
273+
assert.NoError(t, fileutils.RemoveTempDir(tempDir))
274+
}()
275+
276+
assert.NoError(t, os.Setenv("GITHUB_ACTIONS", "true"))
277+
assert.NoError(t, os.Setenv(coreutils.SummaryOutputDirPathEnv, tempDir))
278+
defer func() {
279+
assert.NoError(t, os.Unsetenv("GITHUB_ACTIONS"))
280+
assert.NoError(t, os.Unsetenv(coreutils.SummaryOutputDirPathEnv))
281+
}()
282+
283+
base := &createEvidenceBase{
284+
predicateType: "https://slsa.dev/provenance/v1",
285+
providerId: "test-provider",
286+
flagType: "other",
287+
}
288+
289+
summaryData := commandsummary.EvidenceSummaryData{
290+
Subject: "/docker-cosign-test/hello-world",
291+
Verified: true,
292+
PredicateType: base.predicateType,
293+
}
294+
err = base.recordEvidenceSummary(summaryData)
295+
assert.NoError(t, err)
296+
}
297+
298+
func TestCreateEvidenceBase_RecordEvidenceSummaryIfInGitHubActions_NotVerified(t *testing.T) {
299+
tempDir, err := fileutils.CreateTempDir()
300+
assert.NoError(t, err)
301+
defer func() {
302+
assert.NoError(t, fileutils.RemoveTempDir(tempDir))
303+
}()
304+
305+
assert.NoError(t, os.Setenv("GITHUB_ACTIONS", "true"))
306+
assert.NoError(t, os.Setenv(coreutils.SummaryOutputDirPathEnv, tempDir))
307+
defer func() {
308+
assert.NoError(t, os.Unsetenv("GITHUB_ACTIONS"))
309+
assert.NoError(t, os.Unsetenv(coreutils.SummaryOutputDirPathEnv))
310+
}()
311+
312+
base := &createEvidenceBase{
313+
predicateType: "",
314+
providerId: "test-provider",
315+
flagType: "other",
316+
}
317+
318+
summaryData := commandsummary.EvidenceSummaryData{
319+
Subject: "/test-repo/artifact",
320+
Verified: false,
321+
PredicateType: base.predicateType,
322+
}
323+
err = base.recordEvidenceSummary(summaryData)
324+
assert.NoError(t, err)
325+
}

evidence/create/create_build.go

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package create
33
import (
44
"errors"
55
"fmt"
6+
"github.com/jfrog/jfrog-cli-artifactory/evidence/model"
7+
8+
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/commandsummary"
69

710
"github.com/jfrog/jfrog-cli-artifactory/evidence"
811
"github.com/jfrog/jfrog-cli-artifactory/evidence/utils"
@@ -51,28 +54,31 @@ func (c *createEvidenceBuild) Run() error {
5154
log.Error("failed to create Artifactory client", err)
5255
return err
5356
}
54-
subject, sha256, err := c.buildBuildInfoSubjectPath(artifactoryClient)
57+
58+
timestamp, err := getBuildLatestTimestamp(c.buildName, c.buildNumber, c.project, artifactoryClient)
59+
if err != nil {
60+
return err
61+
}
62+
63+
subject, sha256, err := c.buildBuildInfoSubjectPath(artifactoryClient, timestamp)
5564
if err != nil {
5665
return err
5766
}
5867
envelope, err := c.createEnvelope(subject, sha256)
5968
if err != nil {
6069
return err
6170
}
62-
err = c.uploadEvidence(envelope, subject)
71+
72+
response, err := c.uploadEvidence(envelope, subject)
6373
if err != nil {
6474
return err
6575
}
76+
c.recordSummary(subject, sha256, response, timestamp)
6677

6778
return nil
6879
}
6980

70-
func (c *createEvidenceBuild) buildBuildInfoSubjectPath(artifactoryClient artifactory.ArtifactoryServicesManager) (string, string, error) {
71-
timestamp, err := getBuildLatestTimestamp(c.buildName, c.buildNumber, c.project, artifactoryClient)
72-
if err != nil {
73-
return "", "", err
74-
}
75-
81+
func (c *createEvidenceBuild) buildBuildInfoSubjectPath(artifactoryClient artifactory.ArtifactoryServicesManager, timestamp string) (string, string, error) {
7682
repoKey := utils.BuildBuildInfoRepoKey(c.project)
7783
buildInfoPath := buildBuildInfoPath(repoKey, c.buildName, c.buildNumber, timestamp)
7884
buildInfoChecksum, err := getBuildInfoPathChecksum(buildInfoPath, artifactoryClient)
@@ -82,6 +88,28 @@ func (c *createEvidenceBuild) buildBuildInfoSubjectPath(artifactoryClient artifa
8288
return buildInfoPath, buildInfoChecksum, nil
8389
}
8490

91+
func (c *createEvidenceBuild) recordSummary(subject string, sha256 string, response *model.CreateResponse, timestamp string) {
92+
displayName := fmt.Sprintf("%s %s", c.buildName, c.buildNumber)
93+
commandSummary := commandsummary.EvidenceSummaryData{
94+
Subject: subject,
95+
SubjectSha256: sha256,
96+
PredicateType: c.predicateType,
97+
PredicateSlug: response.PredicateSlug,
98+
Verified: response.Verified,
99+
DisplayName: displayName,
100+
SubjectType: commandsummary.SubjectTypeBuild,
101+
BuildName: c.buildName,
102+
BuildNumber: c.buildNumber,
103+
BuildTimestamp: timestamp,
104+
RepoKey: utils.BuildBuildInfoRepoKey(c.project),
105+
}
106+
107+
err := c.recordEvidenceSummary(commandSummary)
108+
if err != nil {
109+
log.Warn("Failed to record evidence summary:", err.Error())
110+
}
111+
}
112+
85113
func getBuildLatestTimestamp(name string, number string, project string, artifactoryClient artifactory.ArtifactoryServicesManager) (string, error) {
86114
buildInfo := services.BuildInfoParams{
87115
BuildName: name,

0 commit comments

Comments
 (0)