Skip to content

Commit 0013026

Browse files
committed
Support evidence attachment in jf evd create command
1 parent d9ee947 commit 0013026

35 files changed

Lines changed: 1311 additions & 190 deletions

evidence/cli/command/application/command_application.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ func (eac *evidenceApplicationCommand) CreateEvidence(ctx *components.Context, s
3838
eac.ctx.GetStringFlagValue(flags.ApplicationKey),
3939
eac.ctx.GetStringFlagValue(flags.ApplicationVersion),
4040
eac.ctx.GetStringFlagValue(flags.ProviderId),
41-
eac.ctx.GetStringFlagValue(flags.Integration))
41+
eac.ctx.GetStringFlagValue(flags.Integration),
42+
eac.ctx.GetStringFlagValue(flags.AttachLocal),
43+
eac.ctx.GetStringFlagValue(flags.AttachTempTarget),
44+
eac.ctx.GetStringFlagValue(flags.AttachArtifactory),
45+
)
4246
return eac.execute(createCmd)
4347
}
4448

evidence/cli/command/artifacts/command_custom.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ func (ecc *evidenceCustomCommand) CreateEvidence(_ *components.Context, serverDe
4242
ecc.ctx.GetStringFlagValue(flags.SubjectSha256),
4343
ecc.ctx.GetStringFlagValue(flags.SigstoreBundle),
4444
ecc.ctx.GetStringFlagValue(flags.ProviderId),
45-
ecc.ctx.GetStringFlagValue(flags.Integration))
45+
ecc.ctx.GetStringFlagValue(flags.Integration),
46+
ecc.ctx.GetStringFlagValue(flags.AttachLocal),
47+
ecc.ctx.GetStringFlagValue(flags.AttachTempTarget),
48+
ecc.ctx.GetStringFlagValue(flags.AttachArtifactory),
49+
)
4650
return ecc.execute(createCmd)
4751
}
4852

evidence/cli/command/build/command_build.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ func (ebc *evidenceBuildCommand) CreateEvidence(ctx *components.Context, serverD
4040
ebc.ctx.GetStringFlagValue(flags.BuildName),
4141
ebc.ctx.GetStringFlagValue(flags.BuildNumber),
4242
ebc.ctx.GetStringFlagValue(flags.ProviderId),
43-
ebc.ctx.GetStringFlagValue(flags.Integration))
43+
ebc.ctx.GetStringFlagValue(flags.Integration),
44+
ebc.ctx.GetStringFlagValue(flags.AttachLocal),
45+
ebc.ctx.GetStringFlagValue(flags.AttachTempTarget),
46+
ebc.ctx.GetStringFlagValue(flags.AttachArtifactory),
47+
)
4448
return ebc.execute(createCmd)
4549
}
4650

evidence/cli/command/command_cli.go

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ package command
33
import (
44
"errors"
55
"fmt"
6+
"os"
7+
"slices"
8+
"strings"
9+
610
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/application"
711
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/artifacts"
812
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/build"
@@ -12,9 +16,7 @@ import (
1216
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/package"
1317
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/releasebundle"
1418
commandUtils "github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/utils"
15-
"os"
16-
"slices"
17-
"strings"
19+
evdConfig "github.com/jfrog/jfrog-cli-evidence/evidence/config"
1820

1921
commonCliUtils "github.com/jfrog/jfrog-cli-core/v2/common/cliutils"
2022
"github.com/jfrog/jfrog-cli-core/v2/common/commands"
@@ -192,6 +194,9 @@ func validateCreateEvidenceCommonContext(ctx *components.Context) error {
192194
if err := validateSigstoreBundleArgsConflicts(ctx); err != nil {
193195
return err
194196
}
197+
if ctx.GetStringFlagValue(flags.AttachLocal) != "" || ctx.GetStringFlagValue(flags.AttachArtifactory) != "" {
198+
return errorutils.CheckErrorf("attachments are supported only for in-toto flow and cannot be used with --%s", flags.SigstoreBundle)
199+
}
195200
return nil
196201
}
197202

@@ -234,6 +239,39 @@ func validateCreateEvidenceCommonContext(ctx *components.Context) error {
234239
if !ctx.IsFlagSet(flags.KeyAlias) {
235240
setKeyAliasIfProvided(ctx, flags.KeyAlias)
236241
}
242+
if err := validateAttachmentFlags(ctx); err != nil {
243+
return err
244+
}
245+
return nil
246+
}
247+
248+
func validateAttachmentFlags(ctx *components.Context) error {
249+
attachLocal := ctx.GetStringFlagValue(flags.AttachLocal)
250+
attachArtifactory := ctx.GetStringFlagValue(flags.AttachArtifactory)
251+
attachTempTarget := ctx.GetStringFlagValue(flags.AttachTempTarget)
252+
253+
if attachLocal != "" && attachArtifactory != "" {
254+
return errorutils.CheckErrorf("exactly one of --%s or --%s can be used", flags.AttachLocal, flags.AttachArtifactory)
255+
}
256+
257+
if attachTempTarget != "" && attachLocal == "" {
258+
return errorutils.CheckErrorf("--%s can be used only with --%s", flags.AttachTempTarget, flags.AttachLocal)
259+
}
260+
261+
if attachLocal != "" && attachTempTarget == "" {
262+
defaultTarget := evdConfig.ResolveAttachmentTempTarget()
263+
if defaultTarget == "" {
264+
return errorutils.CheckErrorf("--%s is required with --%s (or set %s / %s)", flags.AttachTempTarget, flags.AttachLocal, "EVIDENCE_ATTACHMENT_TEMP_TARGET", "attachment.tempTarget")
265+
}
266+
ctx.AddStringFlag(flags.AttachTempTarget, defaultTarget)
267+
}
268+
269+
if attachLocal != "" && ctx.IsFlagSet(flags.AttachTempTarget) {
270+
if err := evdConfig.PersistAttachmentTempTarget(ctx.GetStringFlagValue(flags.AttachTempTarget)); err != nil {
271+
log.Warn("error persisting attachment temp target: %w", err)
272+
return nil
273+
}
274+
}
237275
return nil
238276
}
239277

@@ -252,6 +290,15 @@ func validateSigstoreBundleArgsConflicts(ctx *components.Context) error {
252290
if ctx.IsFlagSet(flags.PredicateType) && ctx.GetStringFlagValue(flags.PredicateType) != "" {
253291
conflictingParams = append(conflictingParams, "--"+flags.PredicateType)
254292
}
293+
if ctx.IsFlagSet(flags.AttachLocal) && ctx.GetStringFlagValue(flags.AttachLocal) != "" {
294+
conflictingParams = append(conflictingParams, "--"+flags.AttachLocal)
295+
}
296+
if ctx.IsFlagSet(flags.AttachTempTarget) && ctx.GetStringFlagValue(flags.AttachTempTarget) != "" {
297+
conflictingParams = append(conflictingParams, "--"+flags.AttachTempTarget)
298+
}
299+
if ctx.IsFlagSet(flags.AttachArtifactory) && ctx.GetStringFlagValue(flags.AttachArtifactory) != "" {
300+
conflictingParams = append(conflictingParams, "--"+flags.AttachArtifactory)
301+
}
255302

256303
if len(conflictingParams) > 0 {
257304
return errorutils.CheckErrorf("The following parameters cannot be used with --%s: %s. These values are extracted from the bundle itself:", flags.SigstoreBundle, strings.Join(conflictingParams, ", "))

evidence/cli/command/command_cli_test.go

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ func TestCreateEvidence_Context(t *testing.T) {
3232
// Set up test environment variables for this test suite only
3333
originalServerID := os.Getenv("JFROG_CLI_SERVER_ID")
3434
originalURL := os.Getenv("JFROG_CLI_URL")
35-
35+
3636
_ = os.Setenv("JFROG_CLI_SERVER_ID", "test-server")
3737
_ = os.Setenv("JFROG_CLI_URL", "https://test.jfrog.io")
38-
38+
3939
defer func() {
4040
if originalServerID != "" {
4141
_ = os.Setenv("JFROG_CLI_SERVER_ID", originalServerID)
@@ -259,10 +259,10 @@ func TestVerifyEvidence_Context(t *testing.T) {
259259
// Set up test environment variables for this test suite only
260260
originalServerID := os.Getenv("JFROG_CLI_SERVER_ID")
261261
originalURL := os.Getenv("JFROG_CLI_URL")
262-
262+
263263
_ = os.Setenv("JFROG_CLI_SERVER_ID", "test-server")
264264
_ = os.Setenv("JFROG_CLI_URL", "https://test.jfrog.io")
265-
265+
266266
defer func() {
267267
if originalServerID != "" {
268268
_ = os.Setenv("JFROG_CLI_SERVER_ID", originalServerID)
@@ -831,3 +831,49 @@ func TestValidateSonarQubeRequirements(t *testing.T) {
831831
})
832832
}
833833
}
834+
835+
func TestValidateCreateEvidenceCommonContext_Attachments(t *testing.T) {
836+
app := cli.NewApp()
837+
app.Commands = []cli.Command{{Name: "create"}}
838+
ctx := cli.NewContext(app, &flag.FlagSet{}, nil)
839+
840+
t.Run("local and artifactory conflict", func(t *testing.T) {
841+
c, err := components.ConvertContext(ctx,
842+
test.SetDefaultValue(flags.SubjectRepoPath, "repo/path/file"),
843+
test.SetDefaultValue(flags.Predicate, "/tmp/p.json"),
844+
test.SetDefaultValue(flags.PredicateType, "ptype"),
845+
test.SetDefaultValue(flags.Key, "k"),
846+
test.SetDefaultValue(flags.AttachLocal, "/tmp/a.txt"),
847+
test.SetDefaultValue(flags.AttachArtifactory, "repo/other/a.txt"),
848+
)
849+
assert.NoError(t, err)
850+
assert.Error(t, validateCreateEvidenceCommonContext(c))
851+
})
852+
853+
t.Run("temp target from env", func(t *testing.T) {
854+
assert.NoError(t, os.Setenv("EVIDENCE_ATTACHMENT_TEMP_TARGET", "repo/tmp/"))
855+
defer func() { _ = os.Unsetenv("EVIDENCE_ATTACHMENT_TEMP_TARGET") }()
856+
c, err := components.ConvertContext(ctx,
857+
test.SetDefaultValue(flags.SubjectRepoPath, "repo/path/file"),
858+
test.SetDefaultValue(flags.Predicate, "/tmp/p.json"),
859+
test.SetDefaultValue(flags.PredicateType, "ptype"),
860+
test.SetDefaultValue(flags.Key, "k"),
861+
test.SetDefaultValue(flags.AttachLocal, "/tmp/a.txt"),
862+
)
863+
assert.NoError(t, err)
864+
assert.NoError(t, validateCreateEvidenceCommonContext(c))
865+
assert.Equal(t, "repo/tmp/", c.GetStringFlagValue(flags.AttachTempTarget))
866+
})
867+
868+
t.Run("temp target without local", func(t *testing.T) {
869+
c, err := components.ConvertContext(ctx,
870+
test.SetDefaultValue(flags.SubjectRepoPath, "repo/path/file"),
871+
test.SetDefaultValue(flags.Predicate, "/tmp/p.json"),
872+
test.SetDefaultValue(flags.PredicateType, "ptype"),
873+
test.SetDefaultValue(flags.Key, "k"),
874+
test.SetDefaultValue(flags.AttachTempTarget, "repo/tmp/"),
875+
)
876+
assert.NoError(t, err)
877+
assert.Error(t, validateCreateEvidenceCommonContext(c))
878+
})
879+
}

evidence/cli/command/flags/command_flags.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ const (
4545
UseArtifactoryKeys = "use-artifactory-keys"
4646
Integration = "integration"
4747
SigstoreBundle = "sigstore-bundle"
48+
AttachLocal = "attach-local"
49+
AttachTempTarget = "attach-temp-target"
50+
AttachArtifactory = "attach-artifactory"
4851
ArtifactsLimit = "artifacts-limit"
4952
UploadPublicKey = "upload-public-key"
5053
KeyFilePath = "key-file-path"
@@ -85,6 +88,9 @@ var flagsMap = map[string]components.Flag{
8588
ProviderId: components.NewStringFlag(ProviderId, "Provider ID for the evidence.", func(f *components.StringFlag) { f.Mandatory = false }),
8689
PublicKeys: components.NewStringFlag(PublicKeys, "Array of paths to public keys for signatures verification with \";\" separator. Supported keys: 'ecdsa','rsa' and 'ed25519'.", func(f *components.StringFlag) { f.Mandatory = false }),
8790
SigstoreBundle: components.NewStringFlag(SigstoreBundle, "Path to a Sigstore bundle file with a pre-signed DSSE envelope. Incompatible with --"+Key+", --"+KeyAlias+", --"+Predicate+", --"+PredicateType+" and --"+SubjectSha256+".", func(f *components.StringFlag) { f.Mandatory = false }),
91+
AttachLocal: components.NewStringFlag(AttachLocal, "Path to a local file to attach to created evidence. Incompatible with --"+AttachArtifactory+".", func(f *components.StringFlag) { f.Mandatory = false }),
92+
AttachTempTarget: components.NewStringFlag(AttachTempTarget, "Temporary upload target for --"+AttachLocal+" in format <repo/path[/name]>. Use trailing slash for directory targets.", func(f *components.StringFlag) { f.Mandatory = false }),
93+
AttachArtifactory: components.NewStringFlag(AttachArtifactory, "Existing Artifactory file path to attach in format <repo/path>.", func(f *components.StringFlag) { f.Mandatory = false }),
8894
UseArtifactoryKeys: components.NewBoolFlag(UseArtifactoryKeys, "Use Artifactory keys for verification. When enabled, the verify command retrieves keys from Artifactory.", components.WithBoolDefaultValueFalse()),
8995
ArtifactsLimit: components.NewStringFlag(ArtifactsLimit, "The number of artifacts in a release bundle to be included in the evidences file. The default value is 1000 artifacts", func(f *components.StringFlag) { f.Mandatory = false }),
9096
Integration: components.NewStringFlag(Integration, "Specify an integration to automatically generate the Predicate. Supported: 'sonar'. When using 'sonar', the 'SONAR_TOKEN' or 'SONARQUBE_TOKEN' environment variable must be set.", func(f *components.StringFlag) { f.Mandatory = false }),
@@ -120,6 +126,9 @@ var commandFlags = map[string][]string{
120126
ProviderId,
121127
Integration,
122128
SigstoreBundle,
129+
AttachLocal,
130+
AttachTempTarget,
131+
AttachArtifactory,
123132
},
124133
VerifyEvidence: {
125134
Url,

evidence/cli/command/github/command_github.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ func (ebc *evidenceGitHubCommand) CreateEvidence(ctx *components.Context, server
4343
ebc.ctx.GetStringFlagValue(flags.Project),
4444
ebc.ctx.GetStringFlagValue(flags.BuildName),
4545
ebc.ctx.GetStringFlagValue(flags.BuildNumber),
46-
ebc.ctx.GetStringFlagValue(flags.TypeFlag))
46+
ebc.ctx.GetStringFlagValue(flags.TypeFlag),
47+
ebc.ctx.GetStringFlagValue(flags.AttachLocal),
48+
ebc.ctx.GetStringFlagValue(flags.AttachTempTarget),
49+
ebc.ctx.GetStringFlagValue(flags.AttachArtifactory),
50+
)
4751
return ebc.execute(createCmd)
4852
}
4953

evidence/cli/command/package/command_package.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ func (epc *evidencePackageCommand) CreateEvidence(ctx *components.Context, serve
4040
epc.ctx.GetStringFlagValue(flags.PackageVersion),
4141
epc.ctx.GetStringFlagValue(flags.PackageRepoName),
4242
epc.ctx.GetStringFlagValue(flags.ProviderId),
43-
epc.ctx.GetStringFlagValue(flags.Integration))
43+
epc.ctx.GetStringFlagValue(flags.Integration),
44+
epc.ctx.GetStringFlagValue(flags.AttachLocal),
45+
epc.ctx.GetStringFlagValue(flags.AttachTempTarget),
46+
epc.ctx.GetStringFlagValue(flags.AttachArtifactory),
47+
)
4448
return epc.execute(createCmd)
4549
}
4650

evidence/cli/command/releasebundle/command_release_bundle.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ func (erc *evidenceReleaseBundleCommand) CreateEvidence(ctx *components.Context,
4242
erc.ctx.GetStringFlagValue(flags.ReleaseBundle),
4343
erc.ctx.GetStringFlagValue(flags.ReleaseBundleVersion),
4444
erc.ctx.GetStringFlagValue(flags.ProviderId),
45-
erc.ctx.GetStringFlagValue(flags.Integration))
45+
erc.ctx.GetStringFlagValue(flags.Integration),
46+
erc.ctx.GetStringFlagValue(flags.AttachLocal),
47+
erc.ctx.GetStringFlagValue(flags.AttachTempTarget),
48+
erc.ctx.GetStringFlagValue(flags.AttachArtifactory),
49+
)
4650
return erc.execute(createCmd)
4751
}
4852

0 commit comments

Comments
 (0)