Skip to content

Commit

Permalink
Create package evidence using cli (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
osaidwtd authored Aug 12, 2024
1 parent abe2d4e commit fa7f868
Show file tree
Hide file tree
Showing 15 changed files with 387 additions and 55 deletions.
4 changes: 2 additions & 2 deletions evidence/cli/command_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (ebc *evidenceBuildCommand) CreateEvidence(ctx *components.Context, serverD
ebc.ctx.GetStringFlagValue(predicate),
ebc.ctx.GetStringFlagValue(predicateType),
ebc.ctx.GetStringFlagValue(key),
ebc.ctx.GetStringFlagValue(keyId),
ebc.ctx.GetStringFlagValue(keyAlias),
ebc.ctx.GetStringFlagValue(project),
ebc.ctx.GetStringFlagValue(buildName),
ebc.ctx.GetStringFlagValue(buildNumber))
Expand All @@ -39,7 +39,7 @@ func (ebc *evidenceBuildCommand) CreateEvidence(ctx *components.Context, serverD

func (ebc *evidenceBuildCommand) validateEvidenceBuildContext(ctx *components.Context) error {
if !ctx.IsFlagSet(buildNumber) || assertValueProvided(ctx, buildNumber) != nil {
return errorutils.CheckErrorf("'buildNumber' is a mandatory field for creating a Release Bundle evidence: --%s", buildNumber)
return errorutils.CheckErrorf("--%s is a mandatory field for creating a Release Bundle evidence", buildNumber)
}
return nil
}
3 changes: 3 additions & 0 deletions evidence/cli/command_cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func createEvidence(ctx *components.Context) error {
command = NewEvidenceReleaseBundleCommand(ctx, execFunc)
case buildName:
command = NewEvidenceBuildCommand(ctx, execFunc)
case packageName:
command = NewEvidencePackageCommand(ctx, execFunc)
default:
return errors.New("unsupported subject")
}
Expand Down Expand Up @@ -109,6 +111,7 @@ func evidenceDetailsByFlags(ctx *components.Context) (*coreConfig.ServerDetails,
func platformToEvidenceUrls(rtDetails *coreConfig.ServerDetails) {
rtDetails.ArtifactoryUrl = utils.AddTrailingSlashIfNeeded(rtDetails.Url) + "artifactory/"
rtDetails.EvidenceUrl = utils.AddTrailingSlashIfNeeded(rtDetails.Url) + "evidence/"
rtDetails.MetadataUrl = utils.AddTrailingSlashIfNeeded(rtDetails.Url) + "metadata/"
}

func assertValueProvided(c *components.Context, fieldName string) error {
Expand Down
37 changes: 37 additions & 0 deletions evidence/cli/command_cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,43 @@ func TestCreateEvidence_Context(t *testing.T) {
},
expectErr: false,
},
{
name: "ValidContext - Package",
flags: []components.Flag{
setDefaultValue(predicate, predicate),
setDefaultValue(predicateType, "InToto"),
setDefaultValue(key, "PGP"),
setDefaultValue(packageName, packageName),
setDefaultValue(packageVersion, packageVersion),
setDefaultValue(packageRepoName, packageRepoName),
setDefaultValue("url", "url"),
},
expectErr: false,
},
{
name: "InvalidContext - Missing package version",
flags: []components.Flag{
setDefaultValue(predicate, predicate),
setDefaultValue(predicateType, "InToto"),
setDefaultValue(key, "PGP"),
setDefaultValue(packageName, packageName),
setDefaultValue(packageRepoName, packageRepoName),
setDefaultValue("url", "url"),
},
expectErr: true,
},
{
name: "InvalidContext - Missing package repository key",
flags: []components.Flag{
setDefaultValue(predicate, predicate),
setDefaultValue(predicateType, "InToto"),
setDefaultValue(key, "PGP"),
setDefaultValue(packageName, packageName),
setDefaultValue(packageVersion, packageVersion),
setDefaultValue("url", "url"),
},
expectErr: true,
},
}

for _, tt := range tests {
Expand Down
2 changes: 1 addition & 1 deletion evidence/cli/command_custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (ecc *evidenceCustomCommand) CreateEvidence(_ *components.Context, serverDe
ecc.ctx.GetStringFlagValue(predicate),
ecc.ctx.GetStringFlagValue(predicateType),
ecc.ctx.GetStringFlagValue(key),
ecc.ctx.GetStringFlagValue(keyId),
ecc.ctx.GetStringFlagValue(keyAlias),
ecc.ctx.GetStringFlagValue(subjectRepoPath),
ecc.ctx.GetStringFlagValue(subjectSha256))
return ecc.execute(createCmd)
Expand Down
48 changes: 48 additions & 0 deletions evidence/cli/command_package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package cli

import (
"github.com/jfrog/jfrog-cli-artifactory/evidence"
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
)

type evidencePackageCommand struct {
ctx *components.Context
execute execCommandFunc
}

func NewEvidencePackageCommand(ctx *components.Context, execute execCommandFunc) EvidenceCommands {
return &evidencePackageCommand{
ctx: ctx,
execute: execute,
}
}

func (epc *evidencePackageCommand) CreateEvidence(ctx *components.Context, serverDetails *coreConfig.ServerDetails) error {
err := epc.validateEvidencePackageContext(ctx)
if err != nil {
return err
}

createCmd := evidence.NewCreateEvidencePackage(
serverDetails,
epc.ctx.GetStringFlagValue(predicate),
epc.ctx.GetStringFlagValue(predicateType),
epc.ctx.GetStringFlagValue(key),
epc.ctx.GetStringFlagValue(keyAlias),
epc.ctx.GetStringFlagValue(packageName),
epc.ctx.GetStringFlagValue(packageVersion),
epc.ctx.GetStringFlagValue(packageRepoName))
return epc.execute(createCmd)
}

func (epc *evidencePackageCommand) validateEvidencePackageContext(ctx *components.Context) error {
if !ctx.IsFlagSet(packageVersion) || assertValueProvided(ctx, packageVersion) != nil {
return errorutils.CheckErrorf("--%s is a mandatory field for creating a Package evidence", packageVersion)
}
if !ctx.IsFlagSet(packageRepoName) || assertValueProvided(ctx, packageRepoName) != nil {
return errorutils.CheckErrorf("--%s is a mandatory field for creating a Package evidence", packageRepoName)
}
return nil
}
4 changes: 2 additions & 2 deletions evidence/cli/command_relesae_bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (erc *evidenceReleaseBundleCommand) CreateEvidence(ctx *components.Context,
erc.ctx.GetStringFlagValue(predicate),
erc.ctx.GetStringFlagValue(predicateType),
erc.ctx.GetStringFlagValue(key),
erc.ctx.GetStringFlagValue(keyId),
erc.ctx.GetStringFlagValue(keyAlias),
erc.ctx.GetStringFlagValue(project),
erc.ctx.GetStringFlagValue(releaseBundle),
erc.ctx.GetStringFlagValue(releaseBundleVersion))
Expand All @@ -39,7 +39,7 @@ func (erc *evidenceReleaseBundleCommand) CreateEvidence(ctx *components.Context,

func (erc *evidenceReleaseBundleCommand) validateEvidenceReleaseBundleContext(ctx *components.Context) error {
if !ctx.IsFlagSet(releaseBundleVersion) || assertValueProvided(ctx, releaseBundleVersion) != nil {
return errorutils.CheckErrorf("'releaseBundleVersion' is a mandatory field for creating a Release Bundle evidence: --%s", releaseBundleVersion)
return errorutils.CheckErrorf("--%s is a mandatory field for creating a Release Bundle evidence", releaseBundleVersion)
}
return nil
}
15 changes: 12 additions & 3 deletions evidence/cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@ const (
releaseBundleVersion = "release-bundle-version"
buildName = "build-name"
buildNumber = "build-number"
packageName = "package-name"
packageVersion = "package-version"
packageRepoName = "package-repo-name"

// Unique evidence flags
predicate = "predicate"
predicateType = "predicate-type"
subjectRepoPath = "subject-repo-path"
subjectSha256 = "subject-sha256"
key = "key"
keyId = "key-name"
keyAlias = "key-alias"
)

// Flag keys mapped to their corresponding components.Flag definition.
Expand All @@ -48,13 +51,16 @@ var flagsMap = map[string]components.Flag{
releaseBundleVersion: components.NewStringFlag(releaseBundleVersion, "Release Bundle version.", func(f *components.StringFlag) { f.Mandatory = false }),
buildName: components.NewStringFlag(buildName, "Build name.", func(f *components.StringFlag) { f.Mandatory = false }),
buildNumber: components.NewStringFlag(buildNumber, "Build number.", func(f *components.StringFlag) { f.Mandatory = false }),
packageName: components.NewStringFlag(packageName, "Package name.", func(f *components.StringFlag) { f.Mandatory = false }),
packageVersion: components.NewStringFlag(packageVersion, "Package version.", func(f *components.StringFlag) { f.Mandatory = false }),
packageRepoName: components.NewStringFlag(packageRepoName, "Package repository Name.", func(f *components.StringFlag) { f.Mandatory = false }),

predicate: components.NewStringFlag(predicate, "Path to the predicate, arbitrary JSON.", func(f *components.StringFlag) { f.Mandatory = true }),
predicateType: components.NewStringFlag(predicateType, "Type of the predicate.", func(f *components.StringFlag) { f.Mandatory = true }),
subjectRepoPath: components.NewStringFlag(subjectRepoPath, "Full path to some subject' location.", func(f *components.StringFlag) { f.Mandatory = false }),
subjectSha256: components.NewStringFlag(subjectSha256, "Subject checksum sha256.", func(f *components.StringFlag) { f.Mandatory = false }),
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 = true }),
keyId: components.NewStringFlag(keyId, "KeyId", func(f *components.StringFlag) { f.Mandatory = false }),
keyAlias: components.NewStringFlag(keyAlias, "Key alias", func(f *components.StringFlag) { f.Mandatory = false }),
}

var commandFlags = map[string][]string{
Expand All @@ -69,12 +75,15 @@ var commandFlags = map[string][]string{
releaseBundleVersion,
buildName,
buildNumber,
packageName,
packageVersion,
packageRepoName,
predicate,
predicateType,
subjectRepoPath,
subjectSha256,
key,
keyId,
keyAlias,
},
}

Expand Down
1 change: 1 addition & 0 deletions evidence/cli/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ var subjectTypes = []string{
subjectRepoPath,
releaseBundle,
buildName,
packageName,
}
9 changes: 9 additions & 0 deletions evidence/create_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ func (c *createEvidenceBase) createArtifactoryClient() (artifactory.ArtifactoryS
return utils.CreateUploadServiceManager(c.serverDetails, 1, 0, 0, false, nil)
}

func (c *createEvidenceBase) getFileChecksum(path string, artifactoryClient artifactory.ArtifactoryServicesManager) (string, error) {
res, err := artifactoryClient.FileInfo(path)
if err != nil {
log.Warn(fmt.Sprintf("file path '%s' does not exist.", path))
return "", err
}
return res.Checksums.Sha256, nil
}

func createAndSignEnvelope(payloadJson []byte, key string, keyId string) (*dsse.Envelope, error) {
// Load private key from file if ec.key is not a path to a file then try to load it as a key
keyFile := []byte(key)
Expand Down
129 changes: 129 additions & 0 deletions evidence/create_package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package evidence

import (
"encoding/json"
"fmt"
"github.com/jfrog/jfrog-cli-artifactory/evidence/model"
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/artifactory"
"github.com/jfrog/jfrog-client-go/artifactory/services"
"github.com/jfrog/jfrog-client-go/metadata"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/log"
)

const leadArtifactQueryTemplate = `{
"query": "{versions(filter: {packageId: \"%s\", name: \"%s\", repositoriesIn: [{name: \"%s\"}]}) { edges { node { repos { name leadFilePath } } } } }"
}`

type createEvidencePackage struct {
createEvidenceBase
packageName string
packageVersion string
packageRepoName string
}

func NewCreateEvidencePackage(serverDetails *coreConfig.ServerDetails, predicateFilePath, predicateType, key, keyId, packageName,
packageVersion, packageRepoName string) Command {
return &createEvidencePackage{
createEvidenceBase: createEvidenceBase{
serverDetails: serverDetails,
predicateFilePath: predicateFilePath,
predicateType: predicateType,
key: key,
keyId: keyId,
},
packageName: packageName,
packageVersion: packageVersion,
packageRepoName: packageRepoName,
}
}

func (c *createEvidencePackage) CommandName() string {
return "create-package-evidence"
}

func (c *createEvidencePackage) ServerDetails() (*config.ServerDetails, error) {
return c.serverDetails, nil
}

func (c *createEvidencePackage) Run() error {
artifactoryClient, err := c.createArtifactoryClient()
if err != nil {
log.Error("failed to create Artifactory client", err)
return err
}
metadataClient, err := utils.CreateMetadataServiceManager(c.serverDetails, false)
if err != nil {
return err
}

packageType, err := c.getPackageType(artifactoryClient)
if err != nil {
return err
}

leadArtifact, err := c.getPackageVersionLeadArtifact(packageType, metadataClient)
if err != nil {
return err
}
leadArtifactPath := c.buildLeadArtifactPath(leadArtifact)
leadArtifactChecksum, err := c.getFileChecksum(leadArtifactPath, artifactoryClient)
if err != nil {
return err
}
envelope, err := c.createEnvelope(leadArtifactPath, leadArtifactChecksum)
if err != nil {
return err
}
err = c.uploadEvidence(envelope, leadArtifactPath)
if err != nil {
return err
}

return nil
}

func (c *createEvidencePackage) getPackageType(artifactoryClient artifactory.ArtifactoryServicesManager) (string, error) {
var request services.RepositoryDetails
err := artifactoryClient.GetRepository(c.packageRepoName, &request)
if err != nil {
return "", errorutils.CheckErrorf("No such package: %s/%s", c.packageRepoName, c.packageVersion)
}
return request.PackageType, nil
}

func (c *createEvidencePackage) getPackageVersionLeadArtifact(packageType string, metadataClient metadata.Manager) (string, error) {
body, err := metadataClient.GraphqlQuery(c.createQuery(packageType))
if err != nil {
return "", err
}

res := &model.MetadataResponse{}
err = json.Unmarshal(body, res)
if err != nil {
return "", err
}
if len(res.Data.Versions.Edges) == 0 {
return "", errorutils.CheckErrorf("No such package: %s/%s", c.packageRepoName, c.packageVersion)
}

// Fetch the leadFilePath based on repoName
for _, repo := range res.Data.Versions.Edges[0].Node.Repos {
if repo.Name == c.packageRepoName {
return repo.LeadFilePath, nil
}
}
return "", errorutils.CheckErrorf("Can't find lead artifact of pacakge: %s/%s", c.packageRepoName, c.packageVersion)
}

func (c *createEvidencePackage) createQuery(packageType string) []byte {
packageId := packageType + "://" + c.packageName
return []byte(fmt.Sprintf(leadArtifactQueryTemplate, packageId, c.packageVersion, c.packageRepoName))
}

func (c *createEvidencePackage) buildLeadArtifactPath(leadArtifact string) string {
return fmt.Sprintf("%s/%s", c.packageRepoName, leadArtifact)
}
Loading

0 comments on commit fa7f868

Please sign in to comment.