Skip to content
Snippets Groups Projects
Unverified Commit caf126d6 authored by priyawadhwa's avatar priyawadhwa Committed by GitHub
Browse files

Update loginfo API endpoint to return information about inactive shards (#738)


* Update loginfo to return info about inactive shards

This also updates `rekor-cli` to verify inactive shards if they exist. It also updates the sharding integration test to run loginfo and store state based on TreeID if available.

Signed-off-by: default avatarPriya Wadhwa <priya@chainguard.dev>

* Fix typo

Signed-off-by: default avatarPriya Wadhwa <priya@chainguard.dev>

* specify resp code in error

Signed-off-by: default avatarPriya Wadhwa <priya@chainguard.dev>
parent 9b3ded9b
No related branches found
No related tags found
No related merge requests found
Showing
with 1010 additions and 23 deletions
......@@ -21,14 +21,15 @@ import (
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"time"
"github.com/go-openapi/swag"
"github.com/google/trillian/merkle/logverifier"
"github.com/google/trillian/merkle/rfc6962"
"github.com/pkg/errors"
rclient "github.com/sigstore/rekor/pkg/generated/client"
"github.com/sigstore/rekor/pkg/generated/models"
"github.com/spf13/cobra"
"github.com/spf13/viper"
......@@ -81,13 +82,20 @@ var logInfoCmd = &cobra.Command{
logInfo := result.GetPayload()
// Verify inactive shards
if err := verifyInactiveTrees(rekorClient, serverURL, logInfo.InactiveShards); err != nil {
return nil, err
}
// Verify the active tree
sth := util.SignedCheckpoint{}
signedTreeHead := swag.StringValue(logInfo.SignedTreeHead)
if err := sth.UnmarshalText([]byte(signedTreeHead)); err != nil {
return nil, err
}
treeID := swag.StringValue(logInfo.TreeID)
if err := verifyTree(rekorClient, signedTreeHead, serverURL); err != nil {
if err := verifyTree(rekorClient, signedTreeHead, serverURL, treeID); err != nil {
return nil, err
}
......@@ -101,8 +109,27 @@ var logInfoCmd = &cobra.Command{
}),
}
func verifyTree(rekorClient *rclient.Rekor, signedTreeHead, serverURL string) error {
func verifyInactiveTrees(rekorClient *rclient.Rekor, serverURL string, inactiveShards []*models.InactiveShardLogInfo) error {
if inactiveShards == nil {
return nil
}
log.CliLogger.Infof("Validating inactive shards...")
for _, shard := range inactiveShards {
signedTreeHead := swag.StringValue(shard.SignedTreeHead)
treeID := swag.StringValue(shard.TreeID)
if err := verifyTree(rekorClient, signedTreeHead, serverURL, treeID); err != nil {
return errors.Wrapf(err, "verifying inactive shard with ID %s", treeID)
}
}
log.CliLogger.Infof("Successfully validated inactive shards")
return nil
}
func verifyTree(rekorClient *rclient.Rekor, signedTreeHead, serverURL, treeID string) error {
oldState := state.Load(serverURL)
if treeID != "" {
oldState = state.Load(treeID)
}
sth := util.SignedCheckpoint{}
if err := sth.UnmarshalText([]byte(signedTreeHead)); err != nil {
return err
......@@ -115,11 +142,16 @@ func verifyTree(rekorClient *rclient.Rekor, signedTreeHead, serverURL string) er
return errors.New("signature on tree head did not verify")
}
if err := proveConsistency(rekorClient, oldState, sth); err != nil {
if err := proveConsistency(rekorClient, oldState, sth, treeID); err != nil {
return err
}
if viper.GetBool("store_tree_state") {
if treeID != "" {
if err := state.Dump(treeID, &sth); err != nil {
log.CliLogger.Infof("Unable to store previous state: %v", err)
}
}
if err := state.Dump(serverURL, &sth); err != nil {
log.CliLogger.Infof("Unable to store previous state: %v", err)
}
......@@ -127,7 +159,7 @@ func verifyTree(rekorClient *rclient.Rekor, signedTreeHead, serverURL string) er
return nil
}
func proveConsistency(rekorClient *rclient.Rekor, oldState *util.SignedCheckpoint, sth util.SignedCheckpoint) error {
func proveConsistency(rekorClient *rclient.Rekor, oldState *util.SignedCheckpoint, sth util.SignedCheckpoint, treeID string) error {
if oldState == nil {
log.CliLogger.Infof("No previous log state stored, unable to prove consistency")
return nil
......@@ -140,6 +172,7 @@ func proveConsistency(rekorClient *rclient.Rekor, oldState *util.SignedCheckpoin
firstSize := int64(persistedSize)
params.FirstSize = &firstSize
params.LastSize = int64(sth.Size)
params.TreeID = &treeID
proof, err := rekorClient.Tlog.GetLogProof(params)
if err != nil {
return err
......
......@@ -27,7 +27,7 @@ import (
type persistedState map[string]*util.SignedCheckpoint
func Dump(url string, sth *util.SignedCheckpoint) error {
func Dump(key string, sth *util.SignedCheckpoint) error {
rekorDir, err := getRekorDir()
if err != nil {
return err
......@@ -38,7 +38,7 @@ func Dump(url string, sth *util.SignedCheckpoint) error {
if state == nil {
state = make(persistedState)
}
state[url] = sth
state[key] = sth
b, err := json.Marshal(&state)
if err != nil {
......@@ -67,9 +67,9 @@ func loadStateFile() persistedState {
return result
}
func Load(url string) *util.SignedCheckpoint {
func Load(key string) *util.SignedCheckpoint {
if state := loadStateFile(); state != nil {
return state[url]
return state[key]
}
return nil
}
......
......@@ -572,6 +572,35 @@ definitions:
minItems: 1
LogInfo:
type: object
properties:
rootHash:
type: string
description: The current hash value stored at the root of the merkle tree
pattern: '^[0-9a-fA-F]{64}$'
treeSize:
type: integer
description: The current number of nodes in the merkle tree
minimum: 1
signedTreeHead:
type: string
format: signedCheckpoint
description: The current signed tree head
treeID:
type: string
description: The current treeID
pattern: '^[0-9]+$'
inactiveShards:
type: array
items:
$ref: '#/definitions/InactiveShardLogInfo'
required:
- rootHash
- treeSize
- signedTreeHead
- treeID
InactiveShardLogInfo:
type: object
properties:
rootHash:
......
......@@ -49,6 +49,7 @@ const (
failedToGenerateTimestampResponse = "Error generating timestamp response"
sthGenerateError = "Error generating signed tree head"
unsupportedPKIFormat = "The PKI format requested is not supported by this server"
unexpectedInactiveShardError = "Unexpected error communicating with inactive shard"
)
func errorMsg(message string, code int) *models.Error {
......
......@@ -16,6 +16,7 @@
package api
import (
"context"
"encoding/hex"
"fmt"
"net/http"
......@@ -39,6 +40,20 @@ import (
func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder {
tc := NewTrillianClient(params.HTTPRequest.Context())
// for each inactive shard, get the loginfo
var inactiveShards []*models.InactiveShardLogInfo
for _, shard := range tc.ranges.GetRanges() {
if shard.TreeID == tc.ranges.ActiveTreeID() {
break
}
// Get details for this inactive shard
is, err := inactiveShardLogInfo(params.HTTPRequest.Context(), shard.TreeID)
if err != nil {
return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("inactive shard error: %w", err), unexpectedInactiveShardError)
}
inactiveShards = append(inactiveShards, is)
}
resp := tc.getLatest(0)
if resp.status != codes.OK {
return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianCommunicationError)
......@@ -80,6 +95,7 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder {
TreeSize: &treeSize,
SignedTreeHead: &scString,
TreeID: stringPointer(fmt.Sprintf("%d", tc.logID)),
InactiveShards: inactiveShards,
}
return tlog.NewGetLogInfoOK().WithPayload(&logInfo)
......@@ -136,3 +152,47 @@ func GetLogProofHandler(params tlog.GetLogProofParams) middleware.Responder {
return tlog.NewGetLogProofOK().WithPayload(&consistencyProof)
}
func inactiveShardLogInfo(ctx context.Context, tid int64) (*models.InactiveShardLogInfo, error) {
tc := NewTrillianClientFromTreeID(ctx, tid)
resp := tc.getLatest(0)
if resp.status != codes.OK {
return nil, fmt.Errorf("resp code is %d", resp.status)
}
result := resp.getLatestResult
root := &types.LogRootV1{}
if err := root.UnmarshalBinary(result.SignedLogRoot.LogRoot); err != nil {
return nil, err
}
hashString := hex.EncodeToString(root.RootHash)
treeSize := int64(root.TreeSize)
sth, err := util.CreateSignedCheckpoint(util.Checkpoint{
Origin: "Rekor",
Size: root.TreeSize,
Hash: root.RootHash,
})
if err != nil {
return nil, err
}
sth.SetTimestamp(uint64(time.Now().UnixNano()))
// sign the log root ourselves to get the log root signature
if _, err := sth.Sign(viper.GetString("rekor_server.hostname"), api.signer, options.WithContext(ctx)); err != nil {
return nil, err
}
scBytes, err := sth.SignedNote.MarshalText()
if err != nil {
return nil, err
}
m := models.InactiveShardLogInfo{
RootHash: &hashString,
TreeSize: &treeSize,
TreeID: stringPointer(fmt.Sprintf("%d", tid)),
SignedTreeHead: stringPointer(string(scBytes)),
}
return &m, nil
}
......@@ -25,6 +25,7 @@ import (
"github.com/google/trillian/merkle/rfc6962"
"github.com/pkg/errors"
"github.com/sigstore/rekor/pkg/log"
"github.com/sigstore/rekor/pkg/sharding"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
......@@ -37,6 +38,7 @@ import (
type TrillianClient struct {
client trillian.TrillianLogClient
ranges sharding.LogRanges
logID int64
context context.Context
}
......@@ -44,6 +46,7 @@ type TrillianClient struct {
func NewTrillianClient(ctx context.Context) TrillianClient {
return TrillianClient{
client: api.logClient,
ranges: api.logRanges,
logID: api.logID,
context: ctx,
}
......
// Code generated by go-swagger; DO NOT EDIT.
//
// 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 tlog
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewGetInactiveLogInfoParams creates a new GetInactiveLogInfoParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewGetInactiveLogInfoParams() *GetInactiveLogInfoParams {
return &GetInactiveLogInfoParams{
timeout: cr.DefaultTimeout,
}
}
// NewGetInactiveLogInfoParamsWithTimeout creates a new GetInactiveLogInfoParams object
// with the ability to set a timeout on a request.
func NewGetInactiveLogInfoParamsWithTimeout(timeout time.Duration) *GetInactiveLogInfoParams {
return &GetInactiveLogInfoParams{
timeout: timeout,
}
}
// NewGetInactiveLogInfoParamsWithContext creates a new GetInactiveLogInfoParams object
// with the ability to set a context for a request.
func NewGetInactiveLogInfoParamsWithContext(ctx context.Context) *GetInactiveLogInfoParams {
return &GetInactiveLogInfoParams{
Context: ctx,
}
}
// NewGetInactiveLogInfoParamsWithHTTPClient creates a new GetInactiveLogInfoParams object
// with the ability to set a custom HTTPClient for a request.
func NewGetInactiveLogInfoParamsWithHTTPClient(client *http.Client) *GetInactiveLogInfoParams {
return &GetInactiveLogInfoParams{
HTTPClient: client,
}
}
/* GetInactiveLogInfoParams contains all the parameters to send to the API endpoint
for the get inactive log info operation.
Typically these are written to a http.Request.
*/
type GetInactiveLogInfoParams struct {
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the get inactive log info params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetInactiveLogInfoParams) WithDefaults() *GetInactiveLogInfoParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the get inactive log info params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *GetInactiveLogInfoParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the get inactive log info params
func (o *GetInactiveLogInfoParams) WithTimeout(timeout time.Duration) *GetInactiveLogInfoParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the get inactive log info params
func (o *GetInactiveLogInfoParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the get inactive log info params
func (o *GetInactiveLogInfoParams) WithContext(ctx context.Context) *GetInactiveLogInfoParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the get inactive log info params
func (o *GetInactiveLogInfoParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the get inactive log info params
func (o *GetInactiveLogInfoParams) WithHTTPClient(client *http.Client) *GetInactiveLogInfoParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the get inactive log info params
func (o *GetInactiveLogInfoParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WriteToRequest writes these params to a swagger request
func (o *GetInactiveLogInfoParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// Code generated by go-swagger; DO NOT EDIT.
//
// 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 tlog
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"github.com/sigstore/rekor/pkg/generated/models"
)
// GetInactiveLogInfoReader is a Reader for the GetInactiveLogInfo structure.
type GetInactiveLogInfoReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *GetInactiveLogInfoReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewGetInactiveLogInfoOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
result := NewGetInactiveLogInfoDefault(response.Code())
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
if response.Code()/100 == 2 {
return result, nil
}
return nil, result
}
}
// NewGetInactiveLogInfoOK creates a GetInactiveLogInfoOK with default headers values
func NewGetInactiveLogInfoOK() *GetInactiveLogInfoOK {
return &GetInactiveLogInfoOK{}
}
/* GetInactiveLogInfoOK describes a response with status code 200, with default header values.
A JSON object with the root hash and tree size as properties
*/
type GetInactiveLogInfoOK struct {
Payload []*models.LogInfo
}
func (o *GetInactiveLogInfoOK) Error() string {
return fmt.Sprintf("[GET /api/v1/log/inactive][%d] getInactiveLogInfoOK %+v", 200, o.Payload)
}
func (o *GetInactiveLogInfoOK) GetPayload() []*models.LogInfo {
return o.Payload
}
func (o *GetInactiveLogInfoOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewGetInactiveLogInfoDefault creates a GetInactiveLogInfoDefault with default headers values
func NewGetInactiveLogInfoDefault(code int) *GetInactiveLogInfoDefault {
return &GetInactiveLogInfoDefault{
_statusCode: code,
}
}
/* GetInactiveLogInfoDefault describes a response with status code -1, with default header values.
There was an internal error in the server while processing the request
*/
type GetInactiveLogInfoDefault struct {
_statusCode int
Payload *models.Error
}
// Code gets the status code for the get inactive log info default response
func (o *GetInactiveLogInfoDefault) Code() int {
return o._statusCode
}
func (o *GetInactiveLogInfoDefault) Error() string {
return fmt.Sprintf("[GET /api/v1/log/inactive][%d] getInactiveLogInfo default %+v", o._statusCode, o.Payload)
}
func (o *GetInactiveLogInfoDefault) GetPayload() *models.Error {
return o.Payload
}
func (o *GetInactiveLogInfoDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.Error)
// response payload
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// Code generated by go-swagger; DO NOT EDIT.
//
// 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 models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// InactiveShardLogInfo inactive shard log info
//
// swagger:model InactiveShardLogInfo
type InactiveShardLogInfo struct {
// The current hash value stored at the root of the merkle tree
// Required: true
// Pattern: ^[0-9a-fA-F]{64}$
RootHash *string `json:"rootHash"`
// The current signed tree head
// Required: true
SignedTreeHead *string `json:"signedTreeHead"`
// The current treeID
// Required: true
// Pattern: ^[0-9]+$
TreeID *string `json:"treeID"`
// The current number of nodes in the merkle tree
// Required: true
// Minimum: 1
TreeSize *int64 `json:"treeSize"`
}
// Validate validates this inactive shard log info
func (m *InactiveShardLogInfo) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateRootHash(formats); err != nil {
res = append(res, err)
}
if err := m.validateSignedTreeHead(formats); err != nil {
res = append(res, err)
}
if err := m.validateTreeID(formats); err != nil {
res = append(res, err)
}
if err := m.validateTreeSize(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *InactiveShardLogInfo) validateRootHash(formats strfmt.Registry) error {
if err := validate.Required("rootHash", "body", m.RootHash); err != nil {
return err
}
if err := validate.Pattern("rootHash", "body", *m.RootHash, `^[0-9a-fA-F]{64}$`); err != nil {
return err
}
return nil
}
func (m *InactiveShardLogInfo) validateSignedTreeHead(formats strfmt.Registry) error {
if err := validate.Required("signedTreeHead", "body", m.SignedTreeHead); err != nil {
return err
}
return nil
}
func (m *InactiveShardLogInfo) validateTreeID(formats strfmt.Registry) error {
if err := validate.Required("treeID", "body", m.TreeID); err != nil {
return err
}
if err := validate.Pattern("treeID", "body", *m.TreeID, `^[0-9]+$`); err != nil {
return err
}
return nil
}
func (m *InactiveShardLogInfo) validateTreeSize(formats strfmt.Registry) error {
if err := validate.Required("treeSize", "body", m.TreeSize); err != nil {
return err
}
if err := validate.MinimumInt("treeSize", "body", *m.TreeSize, 1, false); err != nil {
return err
}
return nil
}
// ContextValidate validates this inactive shard log info based on context it is used
func (m *InactiveShardLogInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *InactiveShardLogInfo) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *InactiveShardLogInfo) UnmarshalBinary(b []byte) error {
var res InactiveShardLogInfo
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
......@@ -23,6 +23,7 @@ package models
import (
"context"
"strconv"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
......@@ -35,6 +36,9 @@ import (
// swagger:model LogInfo
type LogInfo struct {
// inactive shards
InactiveShards []*InactiveShardLogInfo `json:"inactiveShards"`
// The current hash value stored at the root of the merkle tree
// Required: true
// Pattern: ^[0-9a-fA-F]{64}$
......@@ -59,6 +63,10 @@ type LogInfo struct {
func (m *LogInfo) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateInactiveShards(formats); err != nil {
res = append(res, err)
}
if err := m.validateRootHash(formats); err != nil {
res = append(res, err)
}
......@@ -81,6 +89,32 @@ func (m *LogInfo) Validate(formats strfmt.Registry) error {
return nil
}
func (m *LogInfo) validateInactiveShards(formats strfmt.Registry) error {
if swag.IsZero(m.InactiveShards) { // not required
return nil
}
for i := 0; i < len(m.InactiveShards); i++ {
if swag.IsZero(m.InactiveShards[i]) { // not required
continue
}
if m.InactiveShards[i] != nil {
if err := m.InactiveShards[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("inactiveShards" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("inactiveShards" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *LogInfo) validateRootHash(formats strfmt.Registry) error {
if err := validate.Required("rootHash", "body", m.RootHash); err != nil {
......@@ -129,8 +163,37 @@ func (m *LogInfo) validateTreeSize(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this log info based on context it is used
// ContextValidate validate this log info based on the context it is used
func (m *LogInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateInactiveShards(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *LogInfo) contextValidateInactiveShards(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.InactiveShards); i++ {
if m.InactiveShards[i] != nil {
if err := m.InactiveShards[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("inactiveShards" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("inactiveShards" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
......
// Code generated by go-swagger; DO NOT EDIT.
//
// 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 tlog
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
)
// GetInactiveLogInfoHandlerFunc turns a function with the right signature into a get inactive log info handler
type GetInactiveLogInfoHandlerFunc func(GetInactiveLogInfoParams) middleware.Responder
// Handle executing the request and returning a response
func (fn GetInactiveLogInfoHandlerFunc) Handle(params GetInactiveLogInfoParams) middleware.Responder {
return fn(params)
}
// GetInactiveLogInfoHandler interface for that can handle valid get inactive log info params
type GetInactiveLogInfoHandler interface {
Handle(GetInactiveLogInfoParams) middleware.Responder
}
// NewGetInactiveLogInfo creates a new http.Handler for the get inactive log info operation
func NewGetInactiveLogInfo(ctx *middleware.Context, handler GetInactiveLogInfoHandler) *GetInactiveLogInfo {
return &GetInactiveLogInfo{Context: ctx, Handler: handler}
}
/* GetInactiveLogInfo swagger:route GET /api/v1/log/inactive tlog getInactiveLogInfo
Get information about the inactive shards of the transparency log
Returns information about the merkle tree for inactive shards of the log
*/
type GetInactiveLogInfo struct {
Context *middleware.Context
Handler GetInactiveLogInfoHandler
}
func (o *GetInactiveLogInfo) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewGetInactiveLogInfoParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}
// Code generated by go-swagger; DO NOT EDIT.
//
// 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 tlog
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
)
// NewGetInactiveLogInfoParams creates a new GetInactiveLogInfoParams object
//
// There are no default values defined in the spec.
func NewGetInactiveLogInfoParams() GetInactiveLogInfoParams {
return GetInactiveLogInfoParams{}
}
// GetInactiveLogInfoParams contains all the bound params for the get inactive log info operation
// typically these are obtained from a http.Request
//
// swagger:parameters getInactiveLogInfo
type GetInactiveLogInfoParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewGetInactiveLogInfoParams() beforehand.
func (o *GetInactiveLogInfoParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// Code generated by go-swagger; DO NOT EDIT.
//
// 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 tlog
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/sigstore/rekor/pkg/generated/models"
)
// GetInactiveLogInfoOKCode is the HTTP code returned for type GetInactiveLogInfoOK
const GetInactiveLogInfoOKCode int = 200
/*GetInactiveLogInfoOK A JSON object with the root hash and tree size as properties
swagger:response getInactiveLogInfoOK
*/
type GetInactiveLogInfoOK struct {
/*
In: Body
*/
Payload []*models.LogInfo `json:"body,omitempty"`
}
// NewGetInactiveLogInfoOK creates GetInactiveLogInfoOK with default headers values
func NewGetInactiveLogInfoOK() *GetInactiveLogInfoOK {
return &GetInactiveLogInfoOK{}
}
// WithPayload adds the payload to the get inactive log info o k response
func (o *GetInactiveLogInfoOK) WithPayload(payload []*models.LogInfo) *GetInactiveLogInfoOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get inactive log info o k response
func (o *GetInactiveLogInfoOK) SetPayload(payload []*models.LogInfo) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetInactiveLogInfoOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
payload := o.Payload
if payload == nil {
// return empty array
payload = make([]*models.LogInfo, 0, 50)
}
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
/*GetInactiveLogInfoDefault There was an internal error in the server while processing the request
swagger:response getInactiveLogInfoDefault
*/
type GetInactiveLogInfoDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
}
// NewGetInactiveLogInfoDefault creates GetInactiveLogInfoDefault with default headers values
func NewGetInactiveLogInfoDefault(code int) *GetInactiveLogInfoDefault {
if code <= 0 {
code = 500
}
return &GetInactiveLogInfoDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the get inactive log info default response
func (o *GetInactiveLogInfoDefault) WithStatusCode(code int) *GetInactiveLogInfoDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the get inactive log info default response
func (o *GetInactiveLogInfoDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the get inactive log info default response
func (o *GetInactiveLogInfoDefault) WithPayload(payload *models.Error) *GetInactiveLogInfoDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get inactive log info default response
func (o *GetInactiveLogInfoDefault) SetPayload(payload *models.Error) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetInactiveLogInfoDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
// Code generated by go-swagger; DO NOT EDIT.
//
// 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 tlog
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
)
// GetInactiveLogInfoURL generates an URL for the get inactive log info operation
type GetInactiveLogInfoURL struct {
_basePath string
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *GetInactiveLogInfoURL) WithBasePath(bp string) *GetInactiveLogInfoURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *GetInactiveLogInfoURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *GetInactiveLogInfoURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/api/v1/log/inactive"
_basePath := o._basePath
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *GetInactiveLogInfoURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *GetInactiveLogInfoURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *GetInactiveLogInfoURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on GetInactiveLogInfoURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on GetInactiveLogInfoURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *GetInactiveLogInfoURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}
......@@ -65,19 +65,23 @@ done
echo
# rekor-cli loginfo should work
$REKOR_CLI loginfo --rekor_server http://localhost:3000 --store_tree_state=false
INITIAL_TREE_ID=$($REKOR_CLI loginfo --rekor_server http://localhost:3000 --format json --store_tree_state=false | jq -r .TreeID)
echo "Initial Tree ID is $INITIAL_TREE_ID"
# Add some things to the tlog :)
cd tests
pushd tests
$REKOR_CLI upload --artifact test_file.txt --signature test_file.sig --public-key test_public_key.key --rekor_server http://localhost:3000
cd sharding-testdata
popd
# Make sure we can prove consistency
$REKOR_CLI loginfo --rekor_server http://localhost:3000
# Add 2 more entries to the log
pushd tests/sharding-testdata
$REKOR_CLI upload --artifact file1 --signature file1.sig --pki-format=x509 --public-key=ec_public.pem --rekor_server http://localhost:3000
$REKOR_CLI upload --artifact file2 --signature file2.sig --pki-format=x509 --public-key=ec_public.pem --rekor_server http://localhost:3000
cd ../..
popd
INITIAL_TREE_ID=$($REKOR_CLI loginfo --rekor_server http://localhost:3000 --format json | jq -r .TreeID)
echo "Initial Tree ID is $INITIAL_TREE_ID"
# Make sure we have three entries in the log
check_log_index 2
......@@ -90,7 +94,7 @@ SHARD_TREE_ID=$(createtree --admin_server localhost:8090)
echo "the new shard ID is $SHARD_TREE_ID"
# Once more
$REKOR_CLI loginfo --rekor_server http://localhost:3000 --store_tree_state=false
$REKOR_CLI loginfo --rekor_server http://localhost:3000
# Spin down the rekor server
echo "stopping the rekor server..."
......@@ -143,11 +147,10 @@ EOF
docker-compose -f $COMPOSE_FILE up -d
sleep 15
# TODO: priyawadhwa@ remove --store_tree_state=false once $REKOR_CLI loginfo is aware of shards
$REKOR_CLI loginfo --rekor_server http://localhost:3000 --store_tree_state=false
$REKOR_CLI loginfo --rekor_server http://localhost:3000
# Make sure we are pointing to the new tree now
TREE_ID=$($REKOR_CLI loginfo --rekor_server http://localhost:3000 --format json --store_tree_state=false)
TREE_ID=$($REKOR_CLI loginfo --rekor_server http://localhost:3000 --format json)
# Check that the SHARD_TREE_ID is a substring of the `$REKOR_CLI loginfo` output
if [[ "$TREE_ID" == *"$SHARD_TREE_ID"* ]]; then
echo "Rekor server is now pointing to the new shard"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment