Skip to content

Commit d55d754

Browse files
committed
UUID parsing to include pre-pended shard ID
Signed-off-by: Lily Sturmann <lsturman@redhat.com>
1 parent 63ad05f commit d55d754

File tree

4 files changed

+120
-5
lines changed

4 files changed

+120
-5
lines changed

cmd/rekor-cli/app/get.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/spf13/viper"
3131

3232
"github.com/sigstore/rekor/cmd/rekor-cli/app/format"
33+
"github.com/sigstore/rekor/cmd/rekor-cli/app/sharding"
3334
"github.com/sigstore/rekor/pkg/client"
3435
"github.com/sigstore/rekor/pkg/generated/client/entries"
3536
"github.com/sigstore/rekor/pkg/generated/models"
@@ -110,15 +111,21 @@ var getCmd = &cobra.Command{
110111
if uuid != "" {
111112
params := entries.NewGetLogEntryByUUIDParams()
112113
params.SetTimeout(viper.GetDuration("timeout"))
113-
params.EntryUUID = uuid
114+
if len(uuid) == sharding.UUIDLen {
115+
params.EntryUUID = uuid
116+
} else if len(uuid) == sharding.FullIDLen {
117+
params.EntryUUID = uuid[sharding.FullIDLen-sharding.UUIDLen:]
118+
} else {
119+
return nil, fmt.Errorf("invalid UUID length: %v", len(uuid))
120+
}
114121

115122
resp, err := rekorClient.Entries.GetLogEntryByUUID(params)
116123
if err != nil {
117124
return nil, err
118125
}
119126

120127
for k, entry := range resp.Payload {
121-
if k != uuid {
128+
if k != params.EntryUUID {
122129
continue
123130
}
124131

cmd/rekor-cli/app/pflags.go

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"strings"
2323
"time"
2424

25+
"github.com/sigstore/rekor/cmd/rekor-cli/app/sharding"
2526
"github.com/sigstore/rekor/pkg/pki"
2627
"github.com/sigstore/rekor/pkg/util"
2728

@@ -56,8 +57,8 @@ var pflagValueFuncMap map[FlagType]newPFlagValueFunc
5657
func initializePFlagMap() {
5758
pflagValueFuncMap = map[FlagType]newPFlagValueFunc{
5859
uuidFlag: func() pflag.Value {
59-
// this corresponds to the merkle leaf hash of entries, which is represented by a 64 character hexadecimal string
60-
return valueFactory(uuidFlag, validateString("required,len=64,hexadecimal"), "")
60+
// this corresponds to the merkle leaf hash of entries, which is represented by a 64 character hexadecimal string, prepended by the 6-digit shard ID and '-' separator
61+
return valueFactory(uuidFlag, validateFullID, "")
6162
},
6263
shaFlag: func() pflag.Value {
6364
// this validates a valid sha256 checksum which is optionally prefixed with 'sha256:'
@@ -190,6 +191,53 @@ func validateFileOrURL(v string) error {
190191
return valGen().Set(v)
191192
}
192193

194+
// validateFullID ensures the FullID is composed of a valid shardID, separator character, and UUID
195+
func validateFullID(v string) error {
196+
if len(v) == sharding.FullIDLen {
197+
198+
// validate separator
199+
if string(v[sharding.ShardIDLen]) != sharding.FullIDSeparator {
200+
return fmt.Errorf("unexpected separator char in fullID: %v", v[sharding.ShardIDLen])
201+
}
202+
203+
// validate the ShardID
204+
shardID := v[:sharding.ShardIDLen]
205+
shardIDTag := "required," + "len=" + fmt.Sprintf("%v", sharding.ShardIDLen) + ",number"
206+
shardIDStringValidatorFunc := validateString(shardIDTag)
207+
shardIDErr := shardIDStringValidatorFunc(shardID)
208+
209+
if shardIDErr != nil {
210+
return fmt.Errorf("invalid shardID: %v", shardID)
211+
}
212+
213+
// validate the UUID
214+
UUID := v[sharding.FullIDLen-sharding.UUIDLen:]
215+
UUIDTag := "required," + "len=" + fmt.Sprintf("%v", sharding.UUIDLen) + ",hexadecimal"
216+
UUIDStringValidatorFunc := validateString(UUIDTag)
217+
UUIDErr := UUIDStringValidatorFunc(UUID)
218+
219+
if UUIDErr != nil {
220+
return fmt.Errorf("invalid uuid: %v", UUID)
221+
}
222+
223+
return nil
224+
225+
} else if len(v) == sharding.UUIDLen {
226+
// indicates older UUID format is being used without pre-pended shardID
227+
UUIDStringValidatorFunc := validateString("required,len=64,hexadecimal")
228+
UUIDErr := UUIDStringValidatorFunc(v)
229+
230+
if UUIDErr != nil {
231+
return fmt.Errorf("invalid uuid: %v", v)
232+
}
233+
234+
return nil
235+
236+
}
237+
238+
return fmt.Errorf("fullID len error, expected %v but got %v", sharding.FullIDLen, len(v))
239+
}
240+
193241
// validateLogIndex ensures that the supplied string is a valid log index (integer >= 0)
194242
func validateLogIndex(v string) error {
195243
i, err := strconv.Atoi(v)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 sharding
17+
18+
import (
19+
"fmt"
20+
)
21+
22+
// A FullID refers to a specific artifact's ID and is made of two components,
23+
// the ShardID and the UUID, separated by a character, the FullIDSeparator.
24+
// The ShardID is in human-readable decimal and refers to the specific log or
25+
// shard where the artifact can be found. The UUID refers to the hex-encoded
26+
// merkle leaf hash from trillian for the specific artifact.
27+
28+
const ShardIDMax = 999999
29+
const FullIDSeparator = "-"
30+
31+
const ShardIDLen = 6
32+
const UUIDLen = 64
33+
const SeparatorLen = len(FullIDSeparator)
34+
const FullIDLen = ShardIDLen + UUIDLen + SeparatorLen
35+
36+
// A ShardID is a number with specific properties, including
37+
// its representation as a six-digit string.
38+
type ShardID struct {
39+
ShardIDInt uint32
40+
ShardIDString string
41+
}
42+
43+
// Create a 6-digit string from shardID
44+
func IntToString(i uint32) string {
45+
return fmt.Sprintf("%06d", i)
46+
}
47+
48+
// Create default values
49+
func NewCurrent() ShardID {
50+
return ShardID{
51+
ShardIDInt: CurrentShardID,
52+
ShardIDString: IntToString(CurrentShardID)}
53+
}
54+
55+
// TODO: The shardID will be part of the state and will be updated. Store it in state.go?
56+
// TODO: Add a check that the CurrentShardID cannot be updated beyond 999,999
57+
58+
var CurrentShardID uint32 = 0

pkg/api/entries.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"google.golang.org/genproto/googleapis/rpc/code"
3737
"google.golang.org/grpc/codes"
3838

39+
"github.com/sigstore/rekor/cmd/rekor-cli/app/sharding"
3940
"github.com/sigstore/rekor/pkg/generated/models"
4041
"github.com/sigstore/rekor/pkg/generated/restapi/operations/entries"
4142
"github.com/sigstore/rekor/pkg/log"
@@ -183,7 +184,8 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl
183184
metricNewEntries.Inc()
184185

185186
queuedLeaf := resp.getAddResult.QueuedLeaf.Leaf
186-
uuid := hex.EncodeToString(queuedLeaf.GetMerkleLeafHash())
187+
shardID := sharding.NewCurrent()
188+
uuid := shardID.ShardIDString + sharding.FullIDSeparator + hex.EncodeToString(queuedLeaf.GetMerkleLeafHash())
187189

188190
logEntryAnon := models.LogEntryAnon{
189191
LogID: swag.String(api.pubkeyHash),

0 commit comments

Comments
 (0)