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
4 changes: 4 additions & 0 deletions .github/workflows/frogbot-scan-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ jobs:
# "frogbot" GitHub environment can approve the pull request to be scanned.
environment: frogbot
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}

- name: Setup Go with cache
uses: jfrog/.github/actions/install-go-with-cache@main

Expand Down
6 changes: 5 additions & 1 deletion evidence/cli/command/application/command_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ func (eac *evidenceApplicationCommand) CreateEvidence(ctx *components.Context, s
eac.ctx.GetStringFlagValue(flags.ApplicationKey),
eac.ctx.GetStringFlagValue(flags.ApplicationVersion),
eac.ctx.GetStringFlagValue(flags.ProviderId),
eac.ctx.GetStringFlagValue(flags.Integration))
eac.ctx.GetStringFlagValue(flags.Integration),
eac.ctx.GetStringFlagValue(flags.AttachLocal),
eac.ctx.GetStringFlagValue(flags.AttachArtifactoryTempPath),
eac.ctx.GetStringFlagValue(flags.AttachArtifactoryPath),
)
return eac.execute(createCmd)
}

Expand Down
6 changes: 5 additions & 1 deletion evidence/cli/command/artifacts/command_custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ func (ecc *evidenceCustomCommand) CreateEvidence(_ *components.Context, serverDe
ecc.ctx.GetStringFlagValue(flags.SubjectSha256),
ecc.ctx.GetStringFlagValue(flags.SigstoreBundle),
ecc.ctx.GetStringFlagValue(flags.ProviderId),
ecc.ctx.GetStringFlagValue(flags.Integration))
ecc.ctx.GetStringFlagValue(flags.Integration),
ecc.ctx.GetStringFlagValue(flags.AttachLocal),
ecc.ctx.GetStringFlagValue(flags.AttachArtifactoryTempPath),
ecc.ctx.GetStringFlagValue(flags.AttachArtifactoryPath),
)
return ecc.execute(createCmd)
}

Expand Down
6 changes: 5 additions & 1 deletion evidence/cli/command/build/command_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ func (ebc *evidenceBuildCommand) CreateEvidence(ctx *components.Context, serverD
ebc.ctx.GetStringFlagValue(flags.BuildName),
ebc.ctx.GetStringFlagValue(flags.BuildNumber),
ebc.ctx.GetStringFlagValue(flags.ProviderId),
ebc.ctx.GetStringFlagValue(flags.Integration))
ebc.ctx.GetStringFlagValue(flags.Integration),
ebc.ctx.GetStringFlagValue(flags.AttachLocal),
ebc.ctx.GetStringFlagValue(flags.AttachArtifactoryTempPath),
ebc.ctx.GetStringFlagValue(flags.AttachArtifactoryPath),
)
return ebc.execute(createCmd)
}

Expand Down
53 changes: 50 additions & 3 deletions evidence/cli/command/command_cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package command
import (
"errors"
"fmt"
"os"
"slices"
"strings"

"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/application"
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/artifacts"
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/build"
Expand All @@ -12,9 +16,7 @@ import (
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/package"
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/releasebundle"
commandUtils "github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/utils"
"os"
"slices"
"strings"
evdConfig "github.com/jfrog/jfrog-cli-evidence/evidence/config"

commonCliUtils "github.com/jfrog/jfrog-cli-core/v2/common/cliutils"
"github.com/jfrog/jfrog-cli-core/v2/common/commands"
Expand Down Expand Up @@ -192,6 +194,9 @@ func validateCreateEvidenceCommonContext(ctx *components.Context) error {
if err := validateSigstoreBundleArgsConflicts(ctx); err != nil {
return err
}
if ctx.GetStringFlagValue(flags.AttachLocal) != "" || ctx.GetStringFlagValue(flags.AttachArtifactoryPath) != "" {
return errorutils.CheckErrorf("attachments are supported only for in-toto flow and cannot be used with --%s", flags.SigstoreBundle)
}
return nil
}

Expand Down Expand Up @@ -234,6 +239,39 @@ func validateCreateEvidenceCommonContext(ctx *components.Context) error {
if !ctx.IsFlagSet(flags.KeyAlias) {
setKeyAliasIfProvided(ctx, flags.KeyAlias)
}
if err := validateAttachmentFlags(ctx); err != nil {
return err
}
return nil
}

func validateAttachmentFlags(ctx *components.Context) error {
attachLocal := ctx.GetStringFlagValue(flags.AttachLocal)
attachArtifactoryPath := ctx.GetStringFlagValue(flags.AttachArtifactoryPath)
attachArtifactoryTempPath := ctx.GetStringFlagValue(flags.AttachArtifactoryTempPath)

if attachLocal != "" && attachArtifactoryPath != "" {
return errorutils.CheckErrorf("exactly one of --%s or --%s can be used", flags.AttachLocal, flags.AttachArtifactoryPath)
}

if attachArtifactoryTempPath != "" && attachLocal == "" {
return errorutils.CheckErrorf("--%s can be used only with --%s", flags.AttachArtifactoryTempPath, flags.AttachLocal)
}

if attachLocal != "" && attachArtifactoryTempPath == "" {
defaultTarget := evdConfig.ResolveAttachmentArtifactoryTempPath()
if defaultTarget == "" {
return errorutils.CheckErrorf("--%s is required with --%s (or set %s / %s)", flags.AttachArtifactoryTempPath, flags.AttachLocal, evdConfig.EnvAttachmentArtifactoryTempPath, evdConfig.KeyAttachmentArtifactoryTempPath)
}
ctx.AddStringFlag(flags.AttachArtifactoryTempPath, defaultTarget)
}

if attachLocal != "" && ctx.IsFlagSet(flags.AttachArtifactoryTempPath) {
if err := evdConfig.PersistAttachmentArtifactoryTempPath(ctx.GetStringFlagValue(flags.AttachArtifactoryTempPath)); err != nil {
log.Warn("error persisting attachment artifactory temp path:", err)
return nil
}
}
return nil
}

Expand All @@ -252,6 +290,15 @@ func validateSigstoreBundleArgsConflicts(ctx *components.Context) error {
if ctx.IsFlagSet(flags.PredicateType) && ctx.GetStringFlagValue(flags.PredicateType) != "" {
conflictingParams = append(conflictingParams, "--"+flags.PredicateType)
}
if ctx.IsFlagSet(flags.AttachLocal) && ctx.GetStringFlagValue(flags.AttachLocal) != "" {
conflictingParams = append(conflictingParams, "--"+flags.AttachLocal)
}
if ctx.IsFlagSet(flags.AttachArtifactoryTempPath) && ctx.GetStringFlagValue(flags.AttachArtifactoryTempPath) != "" {
conflictingParams = append(conflictingParams, "--"+flags.AttachArtifactoryTempPath)
}
if ctx.IsFlagSet(flags.AttachArtifactoryPath) && ctx.GetStringFlagValue(flags.AttachArtifactoryPath) != "" {
conflictingParams = append(conflictingParams, "--"+flags.AttachArtifactoryPath)
}

if len(conflictingParams) > 0 {
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, ", "))
Expand Down
55 changes: 51 additions & 4 deletions evidence/cli/command/command_cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/flags"
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/command/utils"
"github.com/jfrog/jfrog-cli-evidence/evidence/cli/test"
evdConfig "github.com/jfrog/jfrog-cli-evidence/evidence/config"
"os"
"testing"

Expand Down Expand Up @@ -32,10 +33,10 @@ func TestCreateEvidence_Context(t *testing.T) {
// Set up test environment variables for this test suite only
originalServerID := os.Getenv("JFROG_CLI_SERVER_ID")
originalURL := os.Getenv("JFROG_CLI_URL")

_ = os.Setenv("JFROG_CLI_SERVER_ID", "test-server")
_ = os.Setenv("JFROG_CLI_URL", "https://test.jfrog.io")

defer func() {
if originalServerID != "" {
_ = os.Setenv("JFROG_CLI_SERVER_ID", originalServerID)
Expand Down Expand Up @@ -259,10 +260,10 @@ func TestVerifyEvidence_Context(t *testing.T) {
// Set up test environment variables for this test suite only
originalServerID := os.Getenv("JFROG_CLI_SERVER_ID")
originalURL := os.Getenv("JFROG_CLI_URL")

_ = os.Setenv("JFROG_CLI_SERVER_ID", "test-server")
_ = os.Setenv("JFROG_CLI_URL", "https://test.jfrog.io")

defer func() {
if originalServerID != "" {
_ = os.Setenv("JFROG_CLI_SERVER_ID", originalServerID)
Expand Down Expand Up @@ -831,3 +832,49 @@ func TestValidateSonarQubeRequirements(t *testing.T) {
})
}
}

func TestValidateCreateEvidenceCommonContext_Attachments(t *testing.T) {
app := cli.NewApp()
app.Commands = []cli.Command{{Name: "create"}}
ctx := cli.NewContext(app, &flag.FlagSet{}, nil)

t.Run("local and artifactory conflict", func(t *testing.T) {
c, err := components.ConvertContext(ctx,
test.SetDefaultValue(flags.SubjectRepoPath, "repo/path/file"),
test.SetDefaultValue(flags.Predicate, "/tmp/p.json"),
test.SetDefaultValue(flags.PredicateType, "ptype"),
test.SetDefaultValue(flags.Key, "k"),
test.SetDefaultValue(flags.AttachLocal, "/tmp/a.txt"),
test.SetDefaultValue(flags.AttachArtifactoryPath, "repo/other/a.txt"),
)
assert.NoError(t, err)
assert.Error(t, validateCreateEvidenceCommonContext(c))
})

t.Run("temp target from env", func(t *testing.T) {
assert.NoError(t, os.Setenv(evdConfig.EnvAttachmentArtifactoryTempPath, "repo/tmp/"))
defer func() { _ = os.Unsetenv(evdConfig.EnvAttachmentArtifactoryTempPath) }()
c, err := components.ConvertContext(ctx,
test.SetDefaultValue(flags.SubjectRepoPath, "repo/path/file"),
test.SetDefaultValue(flags.Predicate, "/tmp/p.json"),
test.SetDefaultValue(flags.PredicateType, "ptype"),
test.SetDefaultValue(flags.Key, "k"),
test.SetDefaultValue(flags.AttachLocal, "/tmp/a.txt"),
)
assert.NoError(t, err)
assert.NoError(t, validateCreateEvidenceCommonContext(c))
assert.Equal(t, "repo/tmp/", c.GetStringFlagValue(flags.AttachArtifactoryTempPath))
})

t.Run("temp target without local", func(t *testing.T) {
c, err := components.ConvertContext(ctx,
test.SetDefaultValue(flags.SubjectRepoPath, "repo/path/file"),
test.SetDefaultValue(flags.Predicate, "/tmp/p.json"),
test.SetDefaultValue(flags.PredicateType, "ptype"),
test.SetDefaultValue(flags.Key, "k"),
test.SetDefaultValue(flags.AttachArtifactoryTempPath, "repo/tmp/"),
)
assert.NoError(t, err)
assert.Error(t, validateCreateEvidenceCommonContext(c))
})
}
61 changes: 35 additions & 26 deletions evidence/cli/command/flags/command_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,26 @@ const (
ApplicationKey = "application-key"
ApplicationVersion = "application-version"

Predicate = "predicate"
PredicateType = "predicate-type"
IncludePredicate = "include-predicate"
Markdown = "markdown"
SubjectRepoPath = "subject-repo-path"
SubjectSha256 = "subject-sha256"
Key = "key"
KeyAlias = "key-alias"
ProviderId = "provider-id"
PublicKeys = "public-keys"
UseArtifactoryKeys = "use-artifactory-keys"
Integration = "integration"
SigstoreBundle = "sigstore-bundle"
ArtifactsLimit = "artifacts-limit"
UploadPublicKey = "upload-public-key"
KeyFilePath = "key-file-path"
KeyFileName = "key-file-name"
Predicate = "predicate"
PredicateType = "predicate-type"
IncludePredicate = "include-predicate"
Markdown = "markdown"
SubjectRepoPath = "subject-repo-path"
SubjectSha256 = "subject-sha256"
Key = "key"
KeyAlias = "key-alias"
ProviderId = "provider-id"
PublicKeys = "public-keys"
UseArtifactoryKeys = "use-artifactory-keys"
Integration = "integration"
SigstoreBundle = "sigstore-bundle"
AttachLocal = "attach-local"
AttachArtifactoryTempPath = "attach-artifactory-temp-path"
AttachArtifactoryPath = "attach-artifactory-path"
ArtifactsLimit = "artifacts-limit"
UploadPublicKey = "upload-public-key"
KeyFilePath = "key-file-path"
KeyFileName = "key-file-name"
)

// Flag keys mapped to their corresponding components.Flag definition.
Expand Down Expand Up @@ -82,15 +85,18 @@ var flagsMap = map[string]components.Flag{
Key: components.NewStringFlag(Key, "Path to a private key that will sign the DSSE. Supported keys: 'ecdsa','rsa' and 'ed25519'.", func(f *components.StringFlag) { f.Mandatory = false }),
KeyAlias: components.NewStringFlag(KeyAlias, "Key alias", func(f *components.StringFlag) { f.Mandatory = false }),

ProviderId: components.NewStringFlag(ProviderId, "Provider ID for the evidence.", func(f *components.StringFlag) { f.Mandatory = false }),
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 }),
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 }),
UseArtifactoryKeys: components.NewBoolFlag(UseArtifactoryKeys, "Use Artifactory keys for verification. When enabled, the verify command retrieves keys from Artifactory.", components.WithBoolDefaultValueFalse()),
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 }),
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 }),
UploadPublicKey: components.NewBoolFlag(UploadPublicKey, "Upload the generated public key to JFrog platform trusted keys. Requires server connection.", components.WithBoolDefaultValueTrue()),
KeyFilePath: components.NewStringFlag(KeyFilePath, "Directory path for key files. Creates the directory if it doesn't exist. Defaults to current directory.", func(f *components.StringFlag) { f.Mandatory = false }),
KeyFileName: components.NewStringFlag(KeyFileName, "Base name for key files (without extension). Private key will be saved as <name>.key and public key as <name>.pub. Defaults to 'evidence'.", func(f *components.StringFlag) { f.Mandatory = false }),
ProviderId: components.NewStringFlag(ProviderId, "Provider ID for the evidence.", func(f *components.StringFlag) { f.Mandatory = false }),
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 }),
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 }),
AttachLocal: components.NewStringFlag(AttachLocal, "Path to a local file to attach to created evidence. Incompatible with --"+AttachArtifactoryPath+".", func(f *components.StringFlag) { f.Mandatory = false }),
AttachArtifactoryTempPath: components.NewStringFlag(AttachArtifactoryTempPath, "Temporary Artifactory upload path for --"+AttachLocal+" in format <repo/path[/name]>. Use trailing slash for directory targets. Can also be set via env var EVIDENCE_ATTACHMENT_ARTIFACTORY_TEMP_PATH or config key attachment.artifactoryTempPath. Once provided, the value is persisted for subsequent runs.", func(f *components.StringFlag) { f.Mandatory = false }),
AttachArtifactoryPath: components.NewStringFlag(AttachArtifactoryPath, "Existing Artifactory file path to attach in format <repo/path>.", func(f *components.StringFlag) { f.Mandatory = false }),
UseArtifactoryKeys: components.NewBoolFlag(UseArtifactoryKeys, "Use Artifactory keys for verification. When enabled, the verify command retrieves keys from Artifactory.", components.WithBoolDefaultValueFalse()),
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 }),
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 }),
UploadPublicKey: components.NewBoolFlag(UploadPublicKey, "Upload the generated public key to JFrog platform trusted keys. Requires server connection.", components.WithBoolDefaultValueTrue()),
KeyFilePath: components.NewStringFlag(KeyFilePath, "Directory path for key files. Creates the directory if it doesn't exist. Defaults to current directory.", func(f *components.StringFlag) { f.Mandatory = false }),
KeyFileName: components.NewStringFlag(KeyFileName, "Base name for key files (without extension). Private key will be saved as <name>.key and public key as <name>.pub. Defaults to 'evidence'.", func(f *components.StringFlag) { f.Mandatory = false }),
}

var commandFlags = map[string][]string{
Expand Down Expand Up @@ -120,6 +126,9 @@ var commandFlags = map[string][]string{
ProviderId,
Integration,
SigstoreBundle,
AttachLocal,
AttachArtifactoryTempPath,
AttachArtifactoryPath,
},
VerifyEvidence: {
Url,
Expand Down
6 changes: 5 additions & 1 deletion evidence/cli/command/github/command_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ func (ebc *evidenceGitHubCommand) CreateEvidence(ctx *components.Context, server
ebc.ctx.GetStringFlagValue(flags.Project),
ebc.ctx.GetStringFlagValue(flags.BuildName),
ebc.ctx.GetStringFlagValue(flags.BuildNumber),
ebc.ctx.GetStringFlagValue(flags.TypeFlag))
ebc.ctx.GetStringFlagValue(flags.TypeFlag),
ebc.ctx.GetStringFlagValue(flags.AttachLocal),
ebc.ctx.GetStringFlagValue(flags.AttachArtifactoryTempPath),
ebc.ctx.GetStringFlagValue(flags.AttachArtifactoryPath),
)
return ebc.execute(createCmd)
}

Expand Down
6 changes: 5 additions & 1 deletion evidence/cli/command/package/command_package.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ func (epc *evidencePackageCommand) CreateEvidence(ctx *components.Context, serve
epc.ctx.GetStringFlagValue(flags.PackageVersion),
epc.ctx.GetStringFlagValue(flags.PackageRepoName),
epc.ctx.GetStringFlagValue(flags.ProviderId),
epc.ctx.GetStringFlagValue(flags.Integration))
epc.ctx.GetStringFlagValue(flags.Integration),
epc.ctx.GetStringFlagValue(flags.AttachLocal),
epc.ctx.GetStringFlagValue(flags.AttachArtifactoryTempPath),
epc.ctx.GetStringFlagValue(flags.AttachArtifactoryPath),
)
return epc.execute(createCmd)
}

Expand Down
6 changes: 5 additions & 1 deletion evidence/cli/command/releasebundle/command_release_bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ func (erc *evidenceReleaseBundleCommand) CreateEvidence(ctx *components.Context,
erc.ctx.GetStringFlagValue(flags.ReleaseBundle),
erc.ctx.GetStringFlagValue(flags.ReleaseBundleVersion),
erc.ctx.GetStringFlagValue(flags.ProviderId),
erc.ctx.GetStringFlagValue(flags.Integration))
erc.ctx.GetStringFlagValue(flags.Integration),
erc.ctx.GetStringFlagValue(flags.AttachLocal),
erc.ctx.GetStringFlagValue(flags.AttachArtifactoryTempPath),
erc.ctx.GetStringFlagValue(flags.AttachArtifactoryPath),
)
return erc.execute(createCmd)
}

Expand Down
2 changes: 1 addition & 1 deletion evidence/cli/docs/create/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package create
import "github.com/jfrog/jfrog-cli-core/v2/plugins/components"

func GetDescription() string {
return " Create a custom evidence and save it to a repository. Add a predicate, predicate-type, repo-path, key, and key-name."
return " Create a custom evidence and save it to a repository. Add a predicate, predicate-type, repo-path, key, key-name and attachments."
}

func GetArguments() []components.Argument {
Expand Down
Loading
Loading