Skip to content

Commit 53d71cd

Browse files
authored
Improve separation between type implementations and CLI code (sigstore#339)
* Refactor PKI factory and add type checking This allows for more DRY addition of new PKI types, and stricter type checking. This also allows for simpler enumeration of supported PKI formats which will be used in further updates to simplify the CLI codebase. Signed-off-by: Bob Callaway <bob.callaway@gmail.com> * revamp CLI flags; support different versions for upload Signed-off-by: Bob Callaway <bob.callaway@gmail.com> * Add Alpine Package type This adds support for the alpine package format used by Alpine Linux, which is the concatenation of three tgz files (signature, control data, and then the actual package files). Signed-off-by: Bob Callaway <bob.callaway@gmail.com> * use shaFlag for --artifact-hash Signed-off-by: Bob Callaway <bob.callaway@gmail.com> * change arg type to PKIFormat Signed-off-by: Bob Callaway <bob.callaway@gmail.com> * defer type-specific validation logic to type code (instead of in CLI); also use CliLogger throughout CLI Signed-off-by: Bob Callaway <bob.callaway@gmail.com> * refactor factory code Signed-off-by: Bob Callaway <bob.callaway@gmail.com> * review comments Signed-off-by: Bob Callaway <bob.callaway@gmail.com>
1 parent e63fe71 commit 53d71cd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1399
-1195
lines changed

cmd/rekor-cli/app/format/wrap.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ package format
1818
import (
1919
"encoding/json"
2020
"fmt"
21-
"log"
2221

22+
"github.com/sigstore/rekor/pkg/log"
2323
"github.com/spf13/cobra"
2424
"github.com/spf13/viper"
2525
)
@@ -32,7 +32,7 @@ func WrapCmd(f formatCmd) CobraCmd {
3232
return func(cmd *cobra.Command, args []string) {
3333
obj, err := f(args)
3434
if err != nil {
35-
log.Fatal(err)
35+
log.CliLogger.Fatal(err)
3636
}
3737

3838
// TODO: add flags to control output formatting (JSON, plaintext, etc.)
@@ -53,7 +53,7 @@ func WrapCmd(f formatCmd) CobraCmd {
5353
func toJSON(i interface{}) string {
5454
b, err := json.Marshal(i)
5555
if err != nil {
56-
log.Fatal(err)
56+
log.CliLogger.Fatal(err)
5757
}
5858
return string(b)
5959
}

cmd/rekor-cli/app/get.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ var getCmd = &cobra.Command{
7474
PreRun: func(cmd *cobra.Command, args []string) {
7575
// these are bound here so that they are not overwritten by other commands
7676
if err := viper.BindPFlags(cmd.Flags()); err != nil {
77-
log.Logger.Fatal("Error initializing cmd line args: ", err)
77+
log.CliLogger.Fatal("Error initializing cmd line args: ", err)
7878
}
7979
},
8080
Run: format.WrapCmd(func(args []string) (interface{}, error) {
@@ -161,11 +161,12 @@ func parseEntry(uuid string, e models.LogEntryAnon) (interface{}, error) {
161161
}
162162

163163
func init() {
164+
initializePFlagMap()
164165
if err := addUUIDPFlags(getCmd, false); err != nil {
165-
log.Logger.Fatal("Error parsing cmd line args:", err)
166+
log.CliLogger.Fatal("Error parsing cmd line args: ", err)
166167
}
167168
if err := addLogIndexFlag(getCmd, false); err != nil {
168-
log.Logger.Fatal("Error parsing cmd line args:", err)
169+
log.CliLogger.Fatal("Error parsing cmd line args: ", err)
169170
}
170171

171172
rootCmd.AddCommand(getCmd)

cmd/rekor-cli/app/log_info.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,5 +153,6 @@ var logInfoCmd = &cobra.Command{
153153
}
154154

155155
func init() {
156+
initializePFlagMap()
156157
rootCmd.AddCommand(logInfoCmd)
157158
}

cmd/rekor-cli/app/log_proof.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ var logProofCmd = &cobra.Command{
9898
}
9999

100100
func init() {
101+
initializePFlagMap()
101102
logProofCmd.Flags().Uint64("first-size", 1, "the size of the log where the proof should begin")
102103
logProofCmd.Flags().Uint64("last-size", 0, "the size of the log where the proof should end")
103104
if err := logProofCmd.MarkFlagRequired("last-size"); err != nil {

cmd/rekor-cli/app/pflag_groups.go

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
//
2+
// Copyright 2021 The Sigstore Authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package app
17+
18+
import (
19+
"errors"
20+
"fmt"
21+
"net/url"
22+
"strings"
23+
24+
"github.com/sigstore/rekor/pkg/pki"
25+
"github.com/sigstore/rekor/pkg/types"
26+
"github.com/spf13/cobra"
27+
"github.com/spf13/viper"
28+
)
29+
30+
// addFlagToCmd adds the specified command of a specified type to the command's flag set
31+
func addFlagToCmd(cmd *cobra.Command, required bool, flagType FlagType, flag, desc string) error {
32+
cmd.Flags().Var(NewFlagValue(flagType, ""), flag, desc)
33+
if required {
34+
return cmd.MarkFlagRequired(flag)
35+
}
36+
return nil
37+
}
38+
39+
// addLogIndexFlag adds the "log-index" command to the command's flag set
40+
func addLogIndexFlag(cmd *cobra.Command, required bool) error {
41+
return addFlagToCmd(cmd, required, logIndexFlag, "log-index", "the index of the entry in the transparency log")
42+
}
43+
44+
// addUUIDPFlags adds the "uuid" command to the command's flag set
45+
func addUUIDPFlags(cmd *cobra.Command, required bool) error {
46+
return addFlagToCmd(cmd, required, uuidFlag, "uuid", "UUID of entry in transparency log (if known)")
47+
}
48+
49+
func addArtifactPFlags(cmd *cobra.Command) error {
50+
flags := map[string]struct {
51+
flagType FlagType
52+
desc string
53+
required bool
54+
}{
55+
"signature": {
56+
fileOrURLFlag,
57+
"path or URL to detached signature file",
58+
false,
59+
},
60+
"type": {
61+
typeFlag,
62+
fmt.Sprintf("type of entry expressed as type(:version)?; supported types = %v", types.ListImplementedTypes()),
63+
false,
64+
},
65+
"pki-format": {
66+
pkiFormatFlag,
67+
fmt.Sprintf("format of the signature and/or public key; options = %v", pki.SupportedFormats()),
68+
false,
69+
},
70+
"public-key": {
71+
fileOrURLFlag,
72+
"path or URL to public key file",
73+
false,
74+
},
75+
"artifact": {
76+
fileOrURLFlag,
77+
"path or URL to artifact file",
78+
false,
79+
},
80+
"artifact-hash": {
81+
shaFlag,
82+
"hex encoded SHA256 hash of artifact (when using URL)",
83+
false,
84+
},
85+
"entry": {
86+
fileOrURLFlag,
87+
"path or URL to pre-formatted entry file",
88+
false,
89+
},
90+
}
91+
92+
for flag, flagVal := range flags {
93+
if err := addFlagToCmd(cmd, flagVal.required, flagVal.flagType, flag, flagVal.desc); err != nil {
94+
return err
95+
}
96+
}
97+
98+
return nil
99+
}
100+
101+
func validateArtifactPFlags(uuidValid, indexValid bool) error {
102+
uuidGiven := false
103+
if uuidValid && viper.GetString("uuid") != "" {
104+
uuidGiven = true
105+
}
106+
indexGiven := false
107+
if indexValid && viper.GetString("log-index") != "" {
108+
indexGiven = true
109+
}
110+
111+
// if neither --entry or --artifact were given, then a reference to a uuid or index is needed
112+
if viper.GetString("entry") == "" && viper.GetString("artifact") == "" {
113+
if (uuidGiven && uuidValid) || (indexGiven && indexValid) {
114+
return nil
115+
}
116+
return errors.New("either 'entry' or 'artifact' must be specified")
117+
}
118+
119+
return nil
120+
}
121+
122+
func CreatePropsFromPflags() *types.ArtifactProperties {
123+
props := &types.ArtifactProperties{}
124+
125+
artifactString := viper.GetString("artifact")
126+
if artifactString != "" {
127+
if isURL(artifactString) {
128+
props.ArtifactPath, _ = url.Parse(artifactString)
129+
} else {
130+
props.ArtifactPath = &url.URL{Path: artifactString}
131+
}
132+
}
133+
134+
props.ArtifactHash = viper.GetString("artifact-hash")
135+
136+
signatureString := viper.GetString("signature")
137+
if signatureString != "" {
138+
if isURL(signatureString) {
139+
props.SignaturePath, _ = url.Parse(signatureString)
140+
} else {
141+
props.SignaturePath = &url.URL{Path: signatureString}
142+
}
143+
}
144+
145+
publicKeyString := viper.GetString("public-key")
146+
if publicKeyString != "" {
147+
if isURL(publicKeyString) {
148+
props.PublicKeyPath, _ = url.Parse(publicKeyString)
149+
} else {
150+
props.PublicKeyPath = &url.URL{Path: publicKeyString}
151+
}
152+
}
153+
154+
props.PKIFormat = viper.GetString("pki-format")
155+
156+
return props
157+
}
158+
159+
//TODO: add tests for this
160+
func ParseTypeFlag(typeStr string) (string, string, error) {
161+
// typeStr can come in as:
162+
// type -> use default version for this kind
163+
// type:version_string -> attempt to use specified version string
164+
165+
typeStrings := strings.SplitN(typeStr, ":", 2)
166+
if _, ok := types.TypeMap.Load(typeStrings[0]); !ok {
167+
return "", "", fmt.Errorf("unknown type %v", typeStrings[0])
168+
}
169+
170+
switch len(typeStrings) {
171+
case 1:
172+
return typeStrings[0], "", nil
173+
case 2:
174+
return typeStrings[0], typeStrings[1], nil
175+
}
176+
return "", "", errors.New("malformed type string")
177+
}

0 commit comments

Comments
 (0)