Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes to create new evidence #4

Merged
merged 1 commit into from
Jun 2, 2024
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
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
SHELL := /bin/bash

.DEFAULT_GOAL = build

GOCMD = go
GOOS = $(shell go env GOOS)
GOARCH = $(shell go env GOARCH)

utest:
$(GOCMD) list ./... | grep "evidence" | grep -v "/${MODULE_NAME}/service/test" | xargs $(GOCMD) test $(TEST_TAGS) -timeout=1m -count=1 $(TEST_ARGS)

test: utest
60 changes: 9 additions & 51 deletions evidence/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ package cli
import (
"errors"
"github.com/jfrog/jfrog-cli-artifactory/evidence"
"github.com/jfrog/jfrog-cli-artifactory/evidence/cli/docs/attest"
"github.com/jfrog/jfrog-cli-artifactory/evidence/cli/docs/verify"
"github.com/jfrog/jfrog-cli-artifactory/evidence/cli/docs/create"
commonCliUtils "github.com/jfrog/jfrog-cli-core/v2/common/cliutils"
"github.com/jfrog/jfrog-cli-core/v2/common/commands"
pluginsCommon "github.com/jfrog/jfrog-cli-core/v2/plugins/common"
Expand All @@ -18,26 +17,18 @@ func GetCommands() []components.Command {
return []components.Command{
{
Name: "create-evidence",
Aliases: []string{"attest", "att"},
Aliases: []string{"create"},
Flags: GetCommandFlags(CreateEvidence),
Description: attest.GetDescription(),
Arguments: attest.GetArguments(),
Description: create.GetDescription(),
Arguments: create.GetArguments(),
Action: createEvidence,
},
{
Name: "verify-evidence",
Aliases: []string{"verify", "v"},
Flags: GetCommandFlags(VerifyEvidence),
Description: verify.GetDescription(),
Arguments: verify.GetArguments(),
Action: verifyEvidence,
},
}
}

func platformToEvidenceUrls(rtDetails *coreConfig.ServerDetails) {
rtDetails.ArtifactoryUrl = utils.AddTrailingSlashIfNeeded(rtDetails.Url) + "artifactory/"
rtDetails.LifecycleUrl = utils.AddTrailingSlashIfNeeded(rtDetails.Url) + "lifecycle/"
rtDetails.EvidenceUrl = utils.AddTrailingSlashIfNeeded(rtDetails.Url) + "evidence/"
}

func createEvidence(c *components.Context) error {
Expand All @@ -54,45 +45,12 @@ func createEvidence(c *components.Context) error {
SetServerDetails(artifactoryClient).
SetPredicateFilePath(c.GetStringFlagValue(EvdPredicate)).
SetPredicateType(c.GetStringFlagValue(EvdPredicateType)).
SetSubjects(c.GetStringFlagValue(EvdSubjects)).
SetSubject(c.GetStringFlagValue(EvdSubject)).
SetKey(c.GetStringFlagValue(EvdKey)).
SetKeyId(c.GetStringFlagValue(EvdKeyId)).
SetEvidenceName(c.GetStringFlagValue(EvdName)).
SetOverride(c.GetBoolFlagValue(EvdOverride))
SetKeyId(c.GetStringFlagValue(EvdKeyId))
return commands.Exec(createCmd)
}

func verifyEvidence(c *components.Context) error {
if err := validateVerifyEvidenceContext(c); err != nil {
return err
}

artifactoryClient, err := evidenceDetailsByFlags(c)
if err != nil {
return err
}

verifyCmd := evidence.NewEvidenceVerifyCommand().
SetServerDetails(artifactoryClient).
SetKey(c.GetStringFlagValue(EvdKey)).
SetEvidenceName(c.GetStringFlagValue(EvdName))
return commands.Exec(verifyCmd)
}

func validateVerifyEvidenceContext(c *components.Context) error {
if show, err := pluginsCommon.ShowCmdHelpIfNeeded(c, c.Arguments); show || err != nil {
return err
}
if !c.IsFlagSet(EvdKey) || assertValueProvided(c, EvdKey) != nil {
return errorutils.CheckErrorf("'key' is a mandatory field for creating a custom evidence: --%s", EvdKey)
}
if !c.IsFlagSet(EvdName) || assertValueProvided(c, EvdName) != nil {
return errorutils.CheckErrorf("'key' is a mandatory field for creating a custom evidence: --%s", EvdName)
}

return nil
}

func evidenceDetailsByFlags(c *components.Context) (*coreConfig.ServerDetails, error) {
artifactoryClient, err := pluginsCommon.CreateServerDetailsWithConfigOffer(c, true, commonCliUtils.Platform)
if err != nil {
Expand Down Expand Up @@ -120,8 +78,8 @@ func validateCreateEvidenceContext(c *components.Context) error {
if !c.IsFlagSet(EvdPredicateType) || assertValueProvided(c, EvdPredicateType) != nil {
return errorutils.CheckErrorf("'predicate' is a mandatory field for creating a custom evidence: --%s", EvdPredicateType)
}
if !c.IsFlagSet(EvdSubjects) || assertValueProvided(c, EvdSubjects) != nil {
return errorutils.CheckErrorf("'subjects' is a mandatory field for creating a custom evidence: --%s", EvdSubjects)
if !c.IsFlagSet(EvdSubject) || assertValueProvided(c, EvdSubject) != nil {
return errorutils.CheckErrorf("'subjects' is a mandatory field for creating a custom evidence: --%s", EvdSubject)
}
if !c.IsFlagSet(EvdKey) || assertValueProvided(c, EvdKey) != nil {
return errorutils.CheckErrorf("'key' is a mandatory field for creating a custom evidence: --%s", EvdKey)
Expand Down
11 changes: 0 additions & 11 deletions evidence/cli/docs/attest/help.go

This file was deleted.

17 changes: 17 additions & 0 deletions evidence/cli/docs/create/help.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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, subject, key, and key-name."
}

func GetArguments() []components.Argument {
return []components.Argument{
{Name: "predicate", Optional: false, Description: "Path to the predicate, arbitrary JSON."},
{Name: "predicate-type", Optional: false, Description: "Type of the predicate."},
{Name: "subject", Optional: false, Description: "Full path to some subjects' location, an artifact."},
{Name: "key", Optional: false, Description: "Path to a private key that will sign the DSSE. Supported keys: 'ecdsa','rsa' and 'ed25519'."},
{Name: "key-name", Optional: true, Description: "Keyid."},
}
}
11 changes: 0 additions & 11 deletions evidence/cli/docs/verify/help.go

This file was deleted.

36 changes: 14 additions & 22 deletions evidence/cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
const (
// Evidence commands keys
CreateEvidence = "create-evidence"
VerifyEvidence = "verify"
)

const (
Expand All @@ -23,37 +22,30 @@ const (
evidencePrefix = "evd-"
EvdPredicate = "predicate"
EvdPredicateType = "predicate-type"
EvdSubjects = "subjects"
EvdSubject = "subject"
EvdKey = "key"
EvdKeyId = "key-name"
EvdName = "name"
EvdOverride = "override"
)

// Security Flag keys mapped to their corresponding components.Flag definition.
// Flag keys mapped to their corresponding components.Flag definition.
var flagsMap = map[string]components.Flag{
// Common commands flags
ServerId: components.NewStringFlag(ServerId, "Server ID configured using the config command."),
url: components.NewStringFlag(url, "JFrog Platform URL."),
user: components.NewStringFlag(user, "JFrog username."),
password: components.NewStringFlag(password, "JFrog password."),
accessToken: components.NewStringFlag(accessToken, "JFrog access token."),

EvdPredicate: components.NewStringFlag(EvdPredicate, "[Mandatory] Path for a file containing the predicate. The file should contain a valid JSON predicate."),
EvdPredicateType: components.NewStringFlag(EvdPredicateType, "[Mandatory] The type of the predicate."),
EvdSubjects: components.NewStringFlag(EvdSubjects, "[Mandatory] Path for a file containing the subject."),
EvdKey: components.NewStringFlag(EvdKey, "[Mandatory] Path for a key pair (pk, puk)."),
EvdKeyId: components.NewStringFlag(EvdKeyId, "[Optional] KeyId"),
EvdName: components.NewStringFlag(EvdName, "[Optional] The name of the evidence to be created."),
EvdOverride: components.NewBoolFlag(EvdOverride, "[Default: false] Set to true to override evidence, if exists, in Artifactory."),
ServerId: components.NewStringFlag(ServerId, "Server ID configured using the config command.", func(f *components.StringFlag) { f.Mandatory = false }),
url: components.NewStringFlag(url, "JFrog Platform URL.", func(f *components.StringFlag) { f.Mandatory = false }),
user: components.NewStringFlag(user, "JFrog username.", func(f *components.StringFlag) { f.Mandatory = false }),
password: components.NewStringFlag(password, "JFrog password.", func(f *components.StringFlag) { f.Mandatory = false }),
accessToken: components.NewStringFlag(accessToken, "JFrog access token.", func(f *components.StringFlag) { f.Mandatory = false }),

EvdPredicate: components.NewStringFlag(EvdPredicate, "Path for a file containing the predicate. The file should contain a valid JSON predicate.", func(f *components.StringFlag) { f.Mandatory = true }),
EvdPredicateType: components.NewStringFlag(EvdPredicateType, "The type of the predicate.", func(f *components.StringFlag) { f.Mandatory = true }),
EvdSubject: components.NewStringFlag(EvdSubject, "Path for a file containing the subject.", func(f *components.StringFlag) { f.Mandatory = true }),
EvdKey: components.NewStringFlag(EvdKey, "Private key.", func(f *components.StringFlag) { f.Mandatory = true }),
EvdKeyId: components.NewStringFlag(EvdKeyId, "KeyId", func(f *components.StringFlag) { f.Mandatory = false }),
}

var commandFlags = map[string][]string{
CreateEvidence: {
url, user, password, accessToken, ServerId, EvdPredicate, EvdPredicateType, EvdSubjects, EvdKey, EvdKeyId, EvdName, EvdOverride,
},
VerifyEvidence: {
EvdKey, EvdName,
url, user, password, accessToken, ServerId,
},
}

Expand Down
99 changes: 19 additions & 80 deletions evidence/attest.go → evidence/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,21 @@ import (
"github.com/jfrog/jfrog-cli-artifactory/evidence/cryptox"
"github.com/jfrog/jfrog-cli-artifactory/evidence/dsse"
"github.com/jfrog/jfrog-cli-artifactory/evidence/intoto"
"github.com/jfrog/jfrog-client-go/artifactory"
"os"
"strings"

"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/artifactory/services"
rtServicesUtils "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
evidenceService "github.com/jfrog/jfrog-client-go/evidence/services"
clientlog "github.com/jfrog/jfrog-client-go/utils/log"
"os"
"strings"
)

type EvidenceCreateCommand struct {
serverDetails *config.ServerDetails
predicateFilePath string
predicateType string
subjects string
subject string
key string
keyId string
evidenceName string
override bool
}

func NewEvidenceCreateCommand() *EvidenceCreateCommand {
Expand All @@ -48,8 +42,8 @@ func (ec *EvidenceCreateCommand) SetPredicateType(predicateType string) *Evidenc
return ec
}

func (ec *EvidenceCreateCommand) SetSubjects(subjects string) *EvidenceCreateCommand {
ec.subjects = subjects
func (ec *EvidenceCreateCommand) SetSubject(subject string) *EvidenceCreateCommand {
ec.subject = subject
return ec
}

Expand All @@ -63,16 +57,6 @@ func (ec *EvidenceCreateCommand) SetKeyId(keyId string) *EvidenceCreateCommand {
return ec
}

func (ec *EvidenceCreateCommand) SetEvidenceName(evidenceName string) *EvidenceCreateCommand {
ec.evidenceName = evidenceName
return ec
}

func (ec *EvidenceCreateCommand) SetOverride(override bool) *EvidenceCreateCommand {
ec.override = override
return ec
}

func (ec *EvidenceCreateCommand) CommandName() string {
return "create-evidence"
}
Expand All @@ -98,8 +82,9 @@ func (ec *EvidenceCreateCommand) Run() error {
return err
}

intotoStatement := intoto.NewStatement(predicate, ec.predicateType)
err = intotoStatement.SetSubject(servicesManager, ec.subjects)
// Create intoto statement
intotoStatement := intoto.NewStatement(predicate, ec.predicateType, ec.serverDetails.User)
err = intotoStatement.SetSubject(servicesManager, ec.subject)
if err != nil {
return err
}
Expand All @@ -118,10 +103,8 @@ func (ec *EvidenceCreateCommand) Run() error {
if err != nil {
return err
}
// If keyId is provided, use it to the single key in the privateKeys slice
if ec.keyId != "" {
privateKey.KeyID = ec.keyId
}

privateKey.KeyID = ec.keyId

signers, err := createSigners(privateKey)
if err != nil {
Expand All @@ -140,70 +123,26 @@ func (ec *EvidenceCreateCommand) Run() error {
return err
}

// create tmp dir for create evidencecore file and save dsse there
tempDirPath, err := fileutils.CreateTempDir()
if err != nil {
return err
}
// Cleanup the temp working directory at the end.
defer func() {
err = errors.Join(err, fileutils.RemoveTempDir(tempDirPath))
}()

// Create the evidence file.
evdName := "/evidence.json.evd"
if ec.evidenceName != "" {
evdName = "/" + ec.evidenceName + ".json.evd"
}
localEvidenceFilePath := tempDirPath + evdName
evidenceFile, err := os.Create(localEvidenceFilePath)
if err != nil {
return err
}
defer func() {
err = errors.Join(err, errorutils.CheckError(evidenceFile.Close()))
}()

// Encode signedEnvelope into a byte slice
envelopeBytes, err := json.Marshal(signedEnvelope)
if err != nil {
return err
}

// Write the encoded byte slice to the file
_, err = evidenceFile.Write(envelopeBytes)
evidenceManager, err := utils.CreateEvidenceServiceManager(serverDetails, false)
if err != nil {
return err
}

// Verify if the file already exists in artifactory
rtEvidencePath := strings.Split(intotoStatement.Subject[0].Uri, "/")
err = ec.shouldOverrideExistingEvidence(rtEvidencePath, evdName, servicesManager)
evidenceDetails := evidenceService.EvidenceDetails{
SubjectUri: strings.Split(ec.subject, "@")[0],
DSSEFileRaw: envelopeBytes,
}
_, err = evidenceManager.UploadEvidence(evidenceDetails)
if err != nil {
return err
}

// Upload evidencecore file to artifactory
commonParams := rtServicesUtils.CommonParams{
Pattern: localEvidenceFilePath,
Target: rtEvidencePath[0] + "/",
}
var uploadParamsArray []services.UploadParams
uploadParamsArray = append(uploadParamsArray, services.UploadParams{
CommonParams: &commonParams,
Flat: true,
})
_, _, err = servicesManager.UploadFiles(uploadParamsArray...)

return err
}

func (ec *EvidenceCreateCommand) shouldOverrideExistingEvidence(rtEvidencePath []string, evdName string, servicesManager artifactory.ArtifactoryServicesManager) error {
filePath := strings.Join(rtEvidencePath[:len(rtEvidencePath)-1], "/") + evdName
remoteFile, _ := servicesManager.FileInfo(filePath)
if remoteFile != nil && !ec.override {
return errors.New("file is already exists, use --override to override")
}
clientlog.Output("Evidence is successfully created")
return nil
}

Expand Down
1 change: 0 additions & 1 deletion evidence/cryptox/ecdsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ func TestECDSASignerVerifierWithMetablockFileAndPEMKey(t *testing.T) {
assert.NoError(t, json.Unmarshal(metadataBytes, &mb))

assert.Equal(t, "304502201fbb03c0937504182a48c66f9218bdcb2e99a07ada273e92e5e543867f98c8d7022100dbfa7bbf74fd76d76c1d08676419cba85bbd81dfb000f3ac6a786693ddc508f5", mb.Signatures[0].Sig)
assert.Equal(t, sv.keyID, mb.Signatures[0].KeyID)

encodedBytes, err := cjson.EncodeCanonical(mb.Signed)
if err != nil {
Expand Down
1 change: 0 additions & 1 deletion evidence/cryptox/ed25519_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ func TestED25519SignerVerifierWithMetablockFileAndPEMKey(t *testing.T) {
}

assert.Equal(t, "4c8b7605a9195d4ddba54493bbb5257a9836c1d16056a027fd77e97b95a4f3e36f8bc3c9c9960387d68187760b3072a30c44f992c5bf8f7497c303a3b0a32403", mb.Signatures[0].Sig)
assert.Equal(t, sv.keyID, mb.Signatures[0].KeyID)

encodedBytes, err := cjson.EncodeCanonical(mb.Signed)
if err != nil {
Expand Down
Loading
Loading