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

Improve separation between type implementations and CLI code #339

Merged
merged 12 commits into from
Jul 14, 2021
Merged
6 changes: 3 additions & 3 deletions cmd/rekor-cli/app/format/wrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ package format
import (
"encoding/json"
"fmt"
"log"

"github.com/sigstore/rekor/pkg/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
Expand All @@ -32,7 +32,7 @@ func WrapCmd(f formatCmd) CobraCmd {
return func(cmd *cobra.Command, args []string) {
obj, err := f(args)
if err != nil {
log.Fatal(err)
log.CliLogger.Fatal(err)
}

// TODO: add flags to control output formatting (JSON, plaintext, etc.)
Expand All @@ -53,7 +53,7 @@ func WrapCmd(f formatCmd) CobraCmd {
func toJSON(i interface{}) string {
b, err := json.Marshal(i)
if err != nil {
log.Fatal(err)
log.CliLogger.Fatal(err)
}
return string(b)
}
7 changes: 4 additions & 3 deletions cmd/rekor-cli/app/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ var getCmd = &cobra.Command{
PreRun: func(cmd *cobra.Command, args []string) {
// these are bound here so that they are not overwritten by other commands
if err := viper.BindPFlags(cmd.Flags()); err != nil {
log.Logger.Fatal("Error initializing cmd line args: ", err)
log.CliLogger.Fatal("Error initializing cmd line args: ", err)
}
},
Run: format.WrapCmd(func(args []string) (interface{}, error) {
Expand Down Expand Up @@ -161,11 +161,12 @@ func parseEntry(uuid string, e models.LogEntryAnon) (interface{}, error) {
}

func init() {
initializePFlagMap()
if err := addUUIDPFlags(getCmd, false); err != nil {
log.Logger.Fatal("Error parsing cmd line args:", err)
log.CliLogger.Fatal("Error parsing cmd line args: ", err)
}
if err := addLogIndexFlag(getCmd, false); err != nil {
log.Logger.Fatal("Error parsing cmd line args:", err)
log.CliLogger.Fatal("Error parsing cmd line args: ", err)
}

rootCmd.AddCommand(getCmd)
Expand Down
1 change: 1 addition & 0 deletions cmd/rekor-cli/app/log_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,5 +153,6 @@ var logInfoCmd = &cobra.Command{
}

func init() {
initializePFlagMap()
rootCmd.AddCommand(logInfoCmd)
}
1 change: 1 addition & 0 deletions cmd/rekor-cli/app/log_proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ var logProofCmd = &cobra.Command{
}

func init() {
initializePFlagMap()
logProofCmd.Flags().Uint64("first-size", 1, "the size of the log where the proof should begin")
logProofCmd.Flags().Uint64("last-size", 0, "the size of the log where the proof should end")
if err := logProofCmd.MarkFlagRequired("last-size"); err != nil {
Expand Down
175 changes: 175 additions & 0 deletions cmd/rekor-cli/app/pflag_groups.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
//
// Copyright 2021 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package app

import (
"errors"
"fmt"
"net/url"
"strings"

"github.com/sigstore/rekor/pkg/pki"
"github.com/sigstore/rekor/pkg/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// addFlagToCmd adds the
bobcallaway marked this conversation as resolved.
Show resolved Hide resolved
func addFlagToCmd(cmd *cobra.Command, required bool, flagType FlagType, flag, desc string) error {
cmd.Flags().Var(NewFlagValue(flagType, ""), flag, desc)
if required {
return cmd.MarkFlagRequired(flag)
}
return nil
}

func addLogIndexFlag(cmd *cobra.Command, required bool) error {
return addFlagToCmd(cmd, required, logIndexFlag, "log-index", "the index of the entry in the transparency log")
}

func addUUIDPFlags(cmd *cobra.Command, required bool) error {
return addFlagToCmd(cmd, required, uuidFlag, "uuid", "UUID of entry in transparency log (if known)")
}

func addArtifactPFlags(cmd *cobra.Command) error {
flags := map[string]struct {
flagType FlagType
desc string
required bool
}{
"signature": {
fileOrURLFlag,
"path or URL to detached signature file",
false,
},
"type": {
typeFlag,
fmt.Sprintf("type of entry expressed as type(:version)?; supported types = %v", types.ListImplementedTypes()),
false,
},
"pki-format": {
pkiFormatFlag,
fmt.Sprintf("format of the signature and/or public key; options = %v", pki.SupportedFormats()),
false,
},
"public-key": {
fileOrURLFlag,
"path or URL to public key file",
false,
},
"artifact": {
fileOrURLFlag,
"path or URL to artifact file",
false,
},
"artifact-hash": {
shaFlag,
"hex encoded SHA256 hash of artifact (when using URL)",
false,
},
"entry": {
fileOrURLFlag,
"path or URL to pre-formatted entry file",
false,
},
}

for flag, flagVal := range flags {
if err := addFlagToCmd(cmd, flagVal.required, flagVal.flagType, flag, flagVal.desc); err != nil {
return err
}
}

return nil
}

func validateArtifactPFlags(uuidValid, indexValid bool) error {
uuidGiven := false
if uuidValid && viper.GetString("uuid") != "" {
uuidGiven = true
}
indexGiven := false
if indexValid && viper.GetString("log-index") != "" {
indexGiven = true
}

// if neither --entry or --artifact were given, then a reference to a uuid or index is needed
if viper.GetString("entry") == "" && viper.GetString("artifact") == "" {
if (uuidGiven && uuidValid) || (indexGiven && indexValid) {
return nil
}
return errors.New("either 'entry' or 'artifact' must be specified")
}

return nil
}

func CreatePropsFromPflags() *types.ArtifactProperties {
props := &types.ArtifactProperties{}

artifactString := viper.GetString("artifact")
if artifactString != "" {
if IsURL(artifactString) {
props.ArtifactPath, _ = url.Parse(artifactString)
} else {
props.ArtifactPath = &url.URL{Path: artifactString}
}
}

props.ArtifactHash = viper.GetString("artifact-hash")

signatureString := viper.GetString("signature")
if signatureString != "" {
if IsURL(signatureString) {
props.SignaturePath, _ = url.Parse(signatureString)
} else {
props.SignaturePath = &url.URL{Path: signatureString}
}
}

publicKeyString := viper.GetString("public-key")
if publicKeyString != "" {
if IsURL(publicKeyString) {
props.PublicKeyPath, _ = url.Parse(publicKeyString)
} else {
props.PublicKeyPath = &url.URL{Path: publicKeyString}
}
}

props.PKIFormat = viper.GetString("pki-format")

return props
}

//TODO: add tests for this
func ParseTypeFlag(typeStr string) (string, string, error) {
// typeStr can come in as:
// type -> use default version for this kind
// type:version_string -> attempt to use specified version string

typeStrings := strings.SplitN(typeStr, ":", 2)
if _, ok := types.TypeMap.Load(typeStrings[0]); !ok {
return "", "", fmt.Errorf("unknown type %v", typeStrings[0])
}

switch len(typeStrings) {
case 1:
return typeStrings[0], "", nil
case 2:
return typeStrings[0], typeStrings[1], nil
}
return "", "", errors.New("malformed type string")
}
Loading