From 2a57762cc1c256d3fcab0e369f7ff148e51e8440 Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Wed, 23 Oct 2024 13:45:10 -0400 Subject: [PATCH 01/10] initial support for application/x-sigstore-tle responses Signed-off-by: Bob Callaway --- go.mod | 1 + openapi.yaml | 9 ++ pkg/client/rekor_client.go | 2 + .../client/entries/entries_client.go | 30 +++- .../restapi/configure_rekor_server.go | 4 + pkg/generated/restapi/doc.go | 1 + pkg/generated/restapi/embedded_spec.go | 24 +++ .../restapi/operations/rekor_server_api.go | 11 ++ pkg/tle/e2e_test.go | 147 ++++++++++++++++++ pkg/tle/tle.go | 53 +++++++ pkg/util/util.go | 17 +- 11 files changed, 294 insertions(+), 5 deletions(-) create mode 100644 pkg/tle/e2e_test.go diff --git a/go.mod b/go.mod index 2207b1574..9c04a71e9 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,7 @@ require ( github.com/go-redis/redismock/v9 v9.2.0 github.com/go-sql-driver/mysql v1.8.1 github.com/golang/mock v1.6.0 + github.com/golang/protobuf v1.5.4 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-retryablehttp v0.7.7 github.com/jmoiron/sqlx v1.4.0 diff --git a/openapi.yaml b/openapi.yaml index 1a8a7c145..54ca6f8da 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -187,6 +187,9 @@ paths: required: true minimum: 0 description: specifies the index of the entry in the transparency log to be retrieved + produces: + - application/json + - application/x-sigstore-tle responses: 200: description: the entry in the transparency log requested along with an inclusion proof @@ -211,6 +214,9 @@ paths: required: true pattern: '^([0-9a-fA-F]{64}|[0-9a-fA-F]{80})$' description: the UUID of the entry for which the inclusion proof information should be returned + produces: + - application/json + - application/x-sigstore-tle responses: 200: description: Information needed for a client to compute the inclusion proof @@ -233,6 +239,9 @@ paths: required: true schema: $ref: '#/definitions/SearchLogQuery' + produces: + - application/json + - application/x-sigstore-tle responses: 200: description: Returns zero or more entries from the transparency log, according to how many were included in request query diff --git a/pkg/client/rekor_client.go b/pkg/client/rekor_client.go index 470ca5eaa..01fda50a6 100644 --- a/pkg/client/rekor_client.go +++ b/pkg/client/rekor_client.go @@ -64,7 +64,9 @@ func GetRekorClient(rekorServerURL string, opts ...Option) (*client.Rekor, error rt := httptransport.NewWithClient(url.Host, url.Path, []string{url.Scheme}, httpClient) rt.Consumers["application/json"] = runtime.JSONConsumer() rt.Consumers["application/x-pem-file"] = runtime.TextConsumer() + rt.Consumers["application/x-sigstore-transparency-log-entry"] = runtime.JSONConsumer() rt.Producers["application/json"] = runtime.JSONProducer() + rt.DefaultMediaType = "application/json" registry := strfmt.Default registry.Add("signedCheckpoint", &util.SignedNote{}, util.SignedCheckpointValidator) diff --git a/pkg/generated/client/entries/entries_client.go b/pkg/generated/client/entries/entries_client.go index 259b38eeb..a9a92c6cd 100644 --- a/pkg/generated/client/entries/entries_client.go +++ b/pkg/generated/client/entries/entries_client.go @@ -68,6 +68,30 @@ type Client struct { // ClientOption may be used to customize the behavior of Client methods. type ClientOption func(*runtime.ClientOperation) +// This client is generated with a few options you might find useful for your swagger spec. +// +// Feel free to add you own set of options. + +// WithAccept allows the client to force the Accept header +// to negotiate a specific Producer from the server. +// +// You may use this option to set arbitrary extensions to your MIME media type. +func WithAccept(mime string) ClientOption { + return func(r *runtime.ClientOperation) { + r.ProducesMediaTypes = []string{mime} + } +} + +// WithAcceptApplicationJSON sets the Accept header to "application/json". +func WithAcceptApplicationJSON(r *runtime.ClientOperation) { + r.ProducesMediaTypes = []string{"application/json"} +} + +// WithAcceptApplicationxSigstoreTle sets the Accept header to "application/x-sigstore-tle". +func WithAcceptApplicationxSigstoreTle(r *runtime.ClientOperation) { + r.ProducesMediaTypes = []string{"application/x-sigstore-tle"} +} + // ClientService is the interface for Client methods type ClientService interface { CreateLogEntry(params *CreateLogEntryParams, opts ...ClientOption) (*CreateLogEntryCreated, error) @@ -132,7 +156,7 @@ func (a *Client) GetLogEntryByIndex(params *GetLogEntryByIndexParams, opts ...Cl ID: "getLogEntryByIndex", Method: "GET", PathPattern: "/api/v1/log/entries", - ProducesMediaTypes: []string{"application/json"}, + ProducesMediaTypes: []string{"application/json", "application/x-sigstore-tle"}, ConsumesMediaTypes: []string{"application/json"}, Schemes: []string{"http"}, Params: params, @@ -171,7 +195,7 @@ func (a *Client) GetLogEntryByUUID(params *GetLogEntryByUUIDParams, opts ...Clie ID: "getLogEntryByUUID", Method: "GET", PathPattern: "/api/v1/log/entries/{entryUUID}", - ProducesMediaTypes: []string{"application/json"}, + ProducesMediaTypes: []string{"application/json", "application/x-sigstore-tle"}, ConsumesMediaTypes: []string{"application/json"}, Schemes: []string{"http"}, Params: params, @@ -208,7 +232,7 @@ func (a *Client) SearchLogQuery(params *SearchLogQueryParams, opts ...ClientOpti ID: "searchLogQuery", Method: "POST", PathPattern: "/api/v1/log/entries/retrieve", - ProducesMediaTypes: []string{"application/json"}, + ProducesMediaTypes: []string{"application/json", "application/x-sigstore-tle"}, ConsumesMediaTypes: []string{"application/json"}, Schemes: []string{"http"}, Params: params, diff --git a/pkg/generated/restapi/configure_rekor_server.go b/pkg/generated/restapi/configure_rekor_server.go index e6c5097ff..5bd4e4429 100644 --- a/pkg/generated/restapi/configure_rekor_server.go +++ b/pkg/generated/restapi/configure_rekor_server.go @@ -46,6 +46,7 @@ import ( "github.com/sigstore/rekor/pkg/generated/restapi/operations/pubkey" "github.com/sigstore/rekor/pkg/generated/restapi/operations/tlog" "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/tle" "github.com/sigstore/rekor/pkg/util" "golang.org/x/exp/slices" @@ -88,6 +89,7 @@ func configureAPI(api *operations.RekorServerAPI) http.Handler { api.JSONProducer = runtime.JSONProducer() api.ApplicationXPemFileProducer = runtime.TextProducer() + api.ApplicationXSigstoreTleProducer = tle.TLEProducer{} // disable all endpoints to start api.IndexSearchIndexHandler = index.SearchIndexHandlerFunc(pkgapi.SearchIndexNotImplementedHandler) @@ -159,6 +161,8 @@ func configureAPI(api *operations.RekorServerAPI) http.Handler { api.ServerShutdown = func() { pkgapi.StopAPI() } + // this causes the order of producers in openapi.yaml to be enforced + api.SetDefaultProduces("") return setupGlobalMiddleware(api.Serve(setupMiddlewares)) } diff --git a/pkg/generated/restapi/doc.go b/pkg/generated/restapi/doc.go index b274e9c3b..91c72e71a 100644 --- a/pkg/generated/restapi/doc.go +++ b/pkg/generated/restapi/doc.go @@ -29,6 +29,7 @@ // // Produces: // - application/x-pem-file +// - application/x-sigstore-tle // - application/json // // swagger:meta diff --git a/pkg/generated/restapi/embedded_spec.go b/pkg/generated/restapi/embedded_spec.go index 4b77cc0fa..6361ed0ae 100644 --- a/pkg/generated/restapi/embedded_spec.go +++ b/pkg/generated/restapi/embedded_spec.go @@ -123,6 +123,10 @@ func init() { }, "/api/v1/log/entries": { "get": { + "produces": [ + "application/json", + "application/x-sigstore-tle" + ], "tags": [ "entries" ], @@ -201,6 +205,10 @@ func init() { }, "/api/v1/log/entries/retrieve": { "post": { + "produces": [ + "application/json", + "application/x-sigstore-tle" + ], "tags": [ "entries" ], @@ -241,6 +249,10 @@ func init() { "/api/v1/log/entries/{entryUUID}": { "get": { "description": "Returns the entry, root hash, tree size, and a list of hashes that can be used to calculate proof of an entry being included in the transparency log", + "produces": [ + "application/json", + "application/x-sigstore-tle" + ], "tags": [ "entries" ], @@ -1058,6 +1070,10 @@ func init() { }, "/api/v1/log/entries": { "get": { + "produces": [ + "application/json", + "application/x-sigstore-tle" + ], "tags": [ "entries" ], @@ -1155,6 +1171,10 @@ func init() { }, "/api/v1/log/entries/retrieve": { "post": { + "produces": [ + "application/json", + "application/x-sigstore-tle" + ], "tags": [ "entries" ], @@ -1204,6 +1224,10 @@ func init() { "/api/v1/log/entries/{entryUUID}": { "get": { "description": "Returns the entry, root hash, tree size, and a list of hashes that can be used to calculate proof of an entry being included in the transparency log", + "produces": [ + "application/json", + "application/x-sigstore-tle" + ], "tags": [ "entries" ], diff --git a/pkg/generated/restapi/operations/rekor_server_api.go b/pkg/generated/restapi/operations/rekor_server_api.go index 1fccb33bc..ef061e4bb 100644 --- a/pkg/generated/restapi/operations/rekor_server_api.go +++ b/pkg/generated/restapi/operations/rekor_server_api.go @@ -65,6 +65,9 @@ func NewRekorServerAPI(spec *loads.Document) *RekorServerAPI { ApplicationXPemFileProducer: runtime.ProducerFunc(func(w io.Writer, data interface{}) error { return errors.NotImplemented("applicationXPemFile producer has not yet been implemented") }), + ApplicationXSigstoreTleProducer: runtime.ProducerFunc(func(w io.Writer, data interface{}) error { + return errors.NotImplemented("applicationXSigstoreTle producer has not yet been implemented") + }), JSONProducer: runtime.JSONProducer(), EntriesCreateLogEntryHandler: entries.CreateLogEntryHandlerFunc(func(params entries.CreateLogEntryParams) middleware.Responder { @@ -126,6 +129,9 @@ type RekorServerAPI struct { // ApplicationXPemFileProducer registers a producer for the following mime types: // - application/x-pem-file ApplicationXPemFileProducer runtime.Producer + // ApplicationXSigstoreTleProducer registers a producer for the following mime types: + // - application/x-sigstore-tle + ApplicationXSigstoreTleProducer runtime.Producer // JSONProducer registers a producer for the following mime types: // - application/json JSONProducer runtime.Producer @@ -222,6 +228,9 @@ func (o *RekorServerAPI) Validate() error { if o.ApplicationXPemFileProducer == nil { unregistered = append(unregistered, "ApplicationXPemFileProducer") } + if o.ApplicationXSigstoreTleProducer == nil { + unregistered = append(unregistered, "ApplicationXSigstoreTleProducer") + } if o.JSONProducer == nil { unregistered = append(unregistered, "JSONProducer") } @@ -298,6 +307,8 @@ func (o *RekorServerAPI) ProducersFor(mediaTypes []string) map[string]runtime.Pr switch mt { case "application/x-pem-file": result["application/x-pem-file"] = o.ApplicationXPemFileProducer + case "application/x-sigstore-tle": + result["application/x-sigstore-tle"] = o.ApplicationXSigstoreTleProducer case "application/json": result["application/json"] = o.JSONProducer } diff --git a/pkg/tle/e2e_test.go b/pkg/tle/e2e_test.go new file mode 100644 index 000000000..260baf574 --- /dev/null +++ b/pkg/tle/e2e_test.go @@ -0,0 +1,147 @@ +// +// Copyright 2022 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. + +//go:build e2e +// +build e2e + +package tle + +import ( + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "strings" + "testing" + + "google.golang.org/protobuf/encoding/protojson" + + rekor_pb "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1" + "github.com/sigstore/rekor/pkg/pki/x509" + "github.com/sigstore/rekor/pkg/sharding" + "github.com/sigstore/rekor/pkg/tle" + "github.com/sigstore/rekor/pkg/util" +) + +func TestAcceptTLE(t *testing.T) { + td := t.TempDir() + artifactPath := filepath.Join(td, "artifact") + sigPath := filepath.Join(td, "signature") + certPath := filepath.Join(td, "cert.pem") + pubKeyPath := filepath.Join(td, "key.pem") + + x509.CreatedX509SignedArtifact(t, artifactPath, sigPath) + + if err := os.WriteFile(certPath, []byte(x509.RSACert), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(pubKeyPath, []byte(x509.PubKey), 0o644); err != nil { + t.Fatal(err) + } + + // upload so we have at least one entry in the log + out := util.RunCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath, + "--public-key", certPath, "--pki-format", "x509") + util.OutputContains(t, out, "Created entry at") + + // fetch via log UUID + uuid, err := sharding.GetUUIDFromIDString(util.GetUUIDFromUploadOutput(t, out)) + if err != nil { + t.Error(err) + } + client := &http.Client{} + req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/v1/log/entries/%s", util.RekorServer(), uuid), nil) + if err != nil { + t.Fatal(err) + } + req.Header.Add("Accept", tle.TLEMediaType) + resp, err := client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + + if err := parseResponseAsTLE(t, resp); err != nil { + t.Fatal(err) + } + + // fetch via log index + index := int64(util.GetLogIndexFromUploadOutput(t, out)) + + req2, err := http.NewRequest("GET", fmt.Sprintf("%s/api/v1/log/entries?logIndex=%d", util.RekorServer(), index), nil) + if err != nil { + t.Fatal(err) + } + req2.Header.Add("Accept", tle.TLEMediaType) + resp2, err := client.Do(req2) + if err != nil { + t.Fatal(err) + } + defer resp2.Body.Close() + + if err := parseResponseAsTLE(t, resp2); err != nil { + t.Fatal(err) + } + // fetch via search + searchJSON := fmt.Sprintf("{ \"logIndexes\": [%d] }", index) + req3, err := http.NewRequest("POST", fmt.Sprintf("%s/api/v1/log/entries/retrieve", util.RekorServer()), strings.NewReader(searchJSON)) + if err != nil { + t.Fatal(err) + } + req3.Header.Add("Accept", tle.TLEMediaType) + resp3, err := client.Do(req3) + if err != nil { + t.Fatal(err) + } + defer resp3.Body.Close() + + if err := parseResponseAsTLEArray(t, resp3); err != nil { + t.Fatal(err) + } +} + +func parseResponseAsTLE(t *testing.T, resp *http.Response) error { + t.Helper() + ctHeader := resp.Header.Get("Content-Type") + if ctHeader != tle.TLEMediaType { + return fmt.Errorf("wrong Content-Type header received; expected '%s', got %s", tle.TLEMediaType, ctHeader) + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + msg := &rekor_pb.TransparencyLogEntry{} + return protojson.Unmarshal(bodyBytes, msg) +} + +func parseResponseAsTLEArray(t *testing.T, resp *http.Response) error { + t.Helper() + ctHeader := resp.Header.Get("Content-Type") + if ctHeader != tle.TLEMediaType { + return fmt.Errorf("wrong Content-Type header received; expected '%s', got %s", tle.TLEMediaType, ctHeader) + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + var entries []*rekor_pb.TransparencyLogEntry + + return protojson.Unmarshal(bodyBytes, &entries) +} diff --git a/pkg/tle/tle.go b/pkg/tle/tle.go index 2e51f5bcc..d04ffd4de 100644 --- a/pkg/tle/tle.go +++ b/pkg/tle/tle.go @@ -19,6 +19,7 @@ import ( "encoding/base64" "encoding/hex" "fmt" + "io" "github.com/go-openapi/runtime" rekor_pb_common "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" @@ -28,6 +29,8 @@ import ( "google.golang.org/protobuf/encoding/protojson" ) +const TLEMediaType = "application/x-sigstore-tle" + // GenerateTransparencyLogEntry returns a sigstore/protobuf-specs compliant message containing a // TransparencyLogEntry as defined at https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_rekor.proto func GenerateTransparencyLogEntry(anon models.LogEntryAnon) (*rekor_pb.TransparencyLogEntry, error) { @@ -104,3 +107,53 @@ func GenerateTransparencyLogEntry(anon models.LogEntryAnon) (*rekor_pb.Transpare func MarshalTLEToJSON(tle *rekor_pb.TransparencyLogEntry) ([]byte, error) { return protojson.Marshal(tle) } + +type TLEProducer struct{} + +func (t TLEProducer) Produce(w io.Writer, input interface{}) error { + switch i := input.(type) { + case models.LogEntry: + var entry models.LogEntryAnon + for _, e := range i { + entry = e + } + tle, err := GenerateTransparencyLogEntry(entry) + if err != nil { + return err + } + tleBytes, err := MarshalTLEToJSON(tle) + if err != nil { + return err + } + if _, err = io.Copy(w, bytes.NewReader(tleBytes)); err != nil { + return err + } + case []models.LogEntry: + buf := &bytes.Buffer{} + if _, err := buf.Write([]byte("[")); err != nil { + return err + } + for _, entry := range i { + if err := t.Produce(buf, entry); err != nil { + return err + } + if _, err := buf.Write([]byte(",")); err != nil { + return err + } + } + if _, err := buf.Write([]byte("]")); err != nil { + return err + } + if _, err := io.Copy(w, buf); err != nil { + return err + } + } + return nil +} + +type TLEConsumer struct{} + +func (t TLEConsumer) Consume(r io.Reader, output interface{}) error { + + return nil +} diff --git a/pkg/util/util.go b/pkg/util/util.go index 78c1a0f51..37e5c6750 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -27,6 +27,7 @@ import ( "os/exec" "path" "path/filepath" + "strconv" "strings" "testing" "time" @@ -324,10 +325,10 @@ func RunCliErr(t *testing.T, arg ...string) string { } func rekorServerFlag() string { - return fmt.Sprintf("--rekor_server=%s", rekorServer()) + return fmt.Sprintf("--rekor_server=%s", RekorServer()) } -func rekorServer() string { +func RekorServer() string { if s := os.Getenv("REKOR_SERVER"); s != "" { return s } @@ -444,3 +445,15 @@ func SetupTestData(t *testing.T) { out := RunCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath) OutputContains(t, out, "Created entry at") } + +func GetLogIndexFromUploadOutput(t *testing.T, out string) int { + t.Helper() + // Output looks like "Created entry at index X, available at $URL/UUID", so grab the index X: + split := strings.Split(strings.TrimSpace(out), ",") + ss := strings.Split(split[0], " ") + i, err := strconv.Atoi(ss[len(ss)-1]) + if err != nil { + t.Fatal(err) + } + return i +} From ece39f0ba5cc6b2df4da7108796b9505c94c4824 Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Mon, 28 Oct 2024 07:09:37 -0400 Subject: [PATCH 02/10] initial consumer Signed-off-by: Bob Callaway --- pkg/tle/e2e_test.go | 30 ++++++++++++++++++++---------- pkg/tle/tle.go | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/pkg/tle/e2e_test.go b/pkg/tle/e2e_test.go index 260baf574..e60c595a8 100644 --- a/pkg/tle/e2e_test.go +++ b/pkg/tle/e2e_test.go @@ -19,6 +19,7 @@ package tle import ( + "encoding/json" "fmt" "io" "net/http" @@ -32,7 +33,6 @@ import ( rekor_pb "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1" "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/sharding" - "github.com/sigstore/rekor/pkg/tle" "github.com/sigstore/rekor/pkg/util" ) @@ -67,7 +67,7 @@ func TestAcceptTLE(t *testing.T) { if err != nil { t.Fatal(err) } - req.Header.Add("Accept", tle.TLEMediaType) + req.Header.Add("Accept", TLEMediaType) resp, err := client.Do(req) if err != nil { t.Fatal(err) @@ -85,7 +85,7 @@ func TestAcceptTLE(t *testing.T) { if err != nil { t.Fatal(err) } - req2.Header.Add("Accept", tle.TLEMediaType) + req2.Header.Add("Accept", TLEMediaType) resp2, err := client.Do(req2) if err != nil { t.Fatal(err) @@ -101,7 +101,7 @@ func TestAcceptTLE(t *testing.T) { if err != nil { t.Fatal(err) } - req3.Header.Add("Accept", tle.TLEMediaType) + req3.Header.Add("Accept", TLEMediaType) resp3, err := client.Do(req3) if err != nil { t.Fatal(err) @@ -116,8 +116,8 @@ func TestAcceptTLE(t *testing.T) { func parseResponseAsTLE(t *testing.T, resp *http.Response) error { t.Helper() ctHeader := resp.Header.Get("Content-Type") - if ctHeader != tle.TLEMediaType { - return fmt.Errorf("wrong Content-Type header received; expected '%s', got %s", tle.TLEMediaType, ctHeader) + if ctHeader != TLEMediaType { + return fmt.Errorf("wrong Content-Type header received; expected '%s', got %s", TLEMediaType, ctHeader) } bodyBytes, err := io.ReadAll(resp.Body) @@ -132,8 +132,8 @@ func parseResponseAsTLE(t *testing.T, resp *http.Response) error { func parseResponseAsTLEArray(t *testing.T, resp *http.Response) error { t.Helper() ctHeader := resp.Header.Get("Content-Type") - if ctHeader != tle.TLEMediaType { - return fmt.Errorf("wrong Content-Type header received; expected '%s', got %s", tle.TLEMediaType, ctHeader) + if ctHeader != TLEMediaType { + return fmt.Errorf("wrong Content-Type header received; expected '%s', got %s", TLEMediaType, ctHeader) } bodyBytes, err := io.ReadAll(resp.Body) @@ -141,7 +141,17 @@ func parseResponseAsTLEArray(t *testing.T, resp *http.Response) error { return err } - var entries []*rekor_pb.TransparencyLogEntry + var jsonArray []json.RawMessage + if err := json.Unmarshal(bodyBytes, &jsonArray); err != nil { + return fmt.Errorf("expected array: %w", err) + } + + for _, element := range jsonArray { + msg := &rekor_pb.TransparencyLogEntry{} + if err := protojson.Unmarshal(element, msg); err != nil { + return fmt.Errorf("parsing element: %w", err) + } + } - return protojson.Unmarshal(bodyBytes, &entries) + return nil } diff --git a/pkg/tle/tle.go b/pkg/tle/tle.go index d04ffd4de..39f10cc33 100644 --- a/pkg/tle/tle.go +++ b/pkg/tle/tle.go @@ -18,6 +18,8 @@ import ( "bytes" "encoding/base64" "encoding/hex" + "encoding/json" + "errors" "fmt" "io" @@ -147,6 +149,8 @@ func (t TLEProducer) Produce(w io.Writer, input interface{}) error { if _, err := io.Copy(w, buf); err != nil { return err } + default: + return errors.New("unexpected type of input") } return nil } @@ -154,6 +158,41 @@ func (t TLEProducer) Produce(w io.Writer, input interface{}) error { type TLEConsumer struct{} func (t TLEConsumer) Consume(r io.Reader, output interface{}) error { + tleBytes, err := io.ReadAll(r) + if err != nil { + return err + } - return nil + decoder := json.NewDecoder(bytes.NewReader(tleBytes)) + token, err := decoder.Token() + if err != nil { + return err + } + + switch token { + case json.Delim('['): + // this is a JSON array, let's check output type to ensure its []rekor_pb.TransparencyLogEntry + var jsonArray []json.RawMessage + if err := json.Unmarshal(tleBytes, &jsonArray); err != nil { + return fmt.Errorf("expected array: %w", err) + } + var result []*rekor_pb.TransparencyLogEntry + for _, element := range jsonArray { + msg := &rekor_pb.TransparencyLogEntry{} + if err := protojson.Unmarshal(element, msg); err != nil { + return fmt.Errorf("parsing element: %w", err) + } + result = append(result, msg) + } + output = &result + return nil + case json.Delim('{'): + // this is a JSON object, let's check output type to ensure its rekor_pb.TransparencyLogEntry + msg := output.(*rekor_pb.TransparencyLogEntry) + if err := protojson.Unmarshal(tleBytes, msg); err != nil { + return fmt.Errorf("parsing element: %w", err) + } + return nil + } + return errors.New("unexpected value") } From 908c5d4536bb582050204e7aed926ea9ac88ea97 Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Mon, 28 Oct 2024 16:35:12 -0400 Subject: [PATCH 03/10] fix tests Signed-off-by: Bob Callaway --- e2e-test.sh | 3 ++- pkg/client/rekor_client.go | 3 ++- pkg/generated/restapi/configure_rekor_server.go | 1 + pkg/tle/e2e_test.go | 5 +++-- pkg/tle/tle.go | 10 ++++++---- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/e2e-test.sh b/e2e-test.sh index 48f35e862..fe9c80ded 100755 --- a/e2e-test.sh +++ b/e2e-test.sh @@ -31,7 +31,7 @@ docker build -t gcp-pubsub-emulator -f Dockerfile.pubsub-emulator . docker kill $(docker ps -q) || true echo "starting services" -${docker_compose} up -d --build +${docker_compose} up -d --build --force-recreate echo "building CLI and server" # set the path to the root of the repo @@ -70,6 +70,7 @@ if ${docker_compose} logs --no-color | grep -q "panic: runtime error:" ; then exit 1 fi +exit 0 echo "generating code coverage" ${docker_compose} restart rekor-server diff --git a/pkg/client/rekor_client.go b/pkg/client/rekor_client.go index 01fda50a6..0ed6cf95b 100644 --- a/pkg/client/rekor_client.go +++ b/pkg/client/rekor_client.go @@ -26,6 +26,7 @@ import ( "github.com/hashicorp/go-cleanhttp" retryablehttp "github.com/hashicorp/go-retryablehttp" "github.com/sigstore/rekor/pkg/generated/client" + "github.com/sigstore/rekor/pkg/tle" "github.com/sigstore/rekor/pkg/util" ) @@ -64,7 +65,7 @@ func GetRekorClient(rekorServerURL string, opts ...Option) (*client.Rekor, error rt := httptransport.NewWithClient(url.Host, url.Path, []string{url.Scheme}, httpClient) rt.Consumers["application/json"] = runtime.JSONConsumer() rt.Consumers["application/x-pem-file"] = runtime.TextConsumer() - rt.Consumers["application/x-sigstore-transparency-log-entry"] = runtime.JSONConsumer() + rt.Consumers[tle.TLEMediaType] = tle.TLEConsumer{} rt.Producers["application/json"] = runtime.JSONProducer() rt.DefaultMediaType = "application/json" diff --git a/pkg/generated/restapi/configure_rekor_server.go b/pkg/generated/restapi/configure_rekor_server.go index 5bd4e4429..f4bc80bf5 100644 --- a/pkg/generated/restapi/configure_rekor_server.go +++ b/pkg/generated/restapi/configure_rekor_server.go @@ -163,6 +163,7 @@ func configureAPI(api *operations.RekorServerAPI) http.Handler { } // this causes the order of producers in openapi.yaml to be enforced api.SetDefaultProduces("") + api.RegisterProducer("*/*", runtime.JSONProducer()) return setupGlobalMiddleware(api.Serve(setupMiddlewares)) } diff --git a/pkg/tle/e2e_test.go b/pkg/tle/e2e_test.go index e60c595a8..983e63abb 100644 --- a/pkg/tle/e2e_test.go +++ b/pkg/tle/e2e_test.go @@ -102,6 +102,7 @@ func TestAcceptTLE(t *testing.T) { t.Fatal(err) } req3.Header.Add("Accept", TLEMediaType) + req3.Header.Add("Content-Type", "application/json") resp3, err := client.Do(req3) if err != nil { t.Fatal(err) @@ -117,7 +118,7 @@ func parseResponseAsTLE(t *testing.T, resp *http.Response) error { t.Helper() ctHeader := resp.Header.Get("Content-Type") if ctHeader != TLEMediaType { - return fmt.Errorf("wrong Content-Type header received; expected '%s', got %s", TLEMediaType, ctHeader) + return fmt.Errorf("wrong Content-Type header received; expected '%s', got '%s'", TLEMediaType, ctHeader) } bodyBytes, err := io.ReadAll(resp.Body) @@ -133,7 +134,7 @@ func parseResponseAsTLEArray(t *testing.T, resp *http.Response) error { t.Helper() ctHeader := resp.Header.Get("Content-Type") if ctHeader != TLEMediaType { - return fmt.Errorf("wrong Content-Type header received; expected '%s', got %s", TLEMediaType, ctHeader) + return fmt.Errorf("wrong Content-Type header received; expected '%s', got '%s'", TLEMediaType, ctHeader) } bodyBytes, err := io.ReadAll(resp.Body) diff --git a/pkg/tle/tle.go b/pkg/tle/tle.go index 39f10cc33..596d3a7ff 100644 --- a/pkg/tle/tle.go +++ b/pkg/tle/tle.go @@ -135,11 +135,13 @@ func (t TLEProducer) Produce(w io.Writer, input interface{}) error { if _, err := buf.Write([]byte("[")); err != nil { return err } - for _, entry := range i { - if err := t.Produce(buf, entry); err != nil { - return err + for num, entry := range i { + if num != 0 { + if _, err := buf.Write([]byte(",")); err != nil { + return err + } } - if _, err := buf.Write([]byte(",")); err != nil { + if err := t.Produce(buf, entry); err != nil { return err } } From d114d57f444610c9408664bac42280297b252d36 Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Wed, 30 Oct 2024 15:07:41 -0400 Subject: [PATCH 04/10] fix consumer and add test Signed-off-by: Bob Callaway --- go.mod | 1 - pkg/client/rekor_client.go | 2 +- .../restapi/configure_rekor_server.go | 5 +- pkg/tle/e2e_test.go | 20 +++++++ pkg/tle/tle.go | 57 +++++++++++++++++-- 5 files changed, 74 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 9c04a71e9..2207b1574 100644 --- a/go.mod +++ b/go.mod @@ -58,7 +58,6 @@ require ( github.com/go-redis/redismock/v9 v9.2.0 github.com/go-sql-driver/mysql v1.8.1 github.com/golang/mock v1.6.0 - github.com/golang/protobuf v1.5.4 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-retryablehttp v0.7.7 github.com/jmoiron/sqlx v1.4.0 diff --git a/pkg/client/rekor_client.go b/pkg/client/rekor_client.go index 0ed6cf95b..fd7ca4813 100644 --- a/pkg/client/rekor_client.go +++ b/pkg/client/rekor_client.go @@ -65,7 +65,7 @@ func GetRekorClient(rekorServerURL string, opts ...Option) (*client.Rekor, error rt := httptransport.NewWithClient(url.Host, url.Path, []string{url.Scheme}, httpClient) rt.Consumers["application/json"] = runtime.JSONConsumer() rt.Consumers["application/x-pem-file"] = runtime.TextConsumer() - rt.Consumers[tle.TLEMediaType] = tle.TLEConsumer{} + rt.Consumers[tle.TLEMediaType] = &tle.TLEConsumer{} rt.Producers["application/json"] = runtime.JSONProducer() rt.DefaultMediaType = "application/json" diff --git a/pkg/generated/restapi/configure_rekor_server.go b/pkg/generated/restapi/configure_rekor_server.go index f4bc80bf5..833d266cb 100644 --- a/pkg/generated/restapi/configure_rekor_server.go +++ b/pkg/generated/restapi/configure_rekor_server.go @@ -161,9 +161,8 @@ func configureAPI(api *operations.RekorServerAPI) http.Handler { api.ServerShutdown = func() { pkgapi.StopAPI() } - // this causes the order of producers in openapi.yaml to be enforced - api.SetDefaultProduces("") - api.RegisterProducer("*/*", runtime.JSONProducer()) + // the trailing space is intentional to cause checking to fail inside go-openapi but ordering to be enforced from openapi.yaml + api.SetDefaultProduces("application/json ") return setupGlobalMiddleware(api.Serve(setupMiddlewares)) } diff --git a/pkg/tle/e2e_test.go b/pkg/tle/e2e_test.go index 983e63abb..6a56bbed0 100644 --- a/pkg/tle/e2e_test.go +++ b/pkg/tle/e2e_test.go @@ -112,6 +112,26 @@ func TestAcceptTLE(t *testing.T) { if err := parseResponseAsTLEArray(t, resp3); err != nil { t.Fatal(err) } + + // test getting an entry 1000 times using a vague accept header, and ensure that we always return application/json to those request + for j := range 1000 { + req4, err := http.NewRequest("GET", fmt.Sprintf("%s/api/v1/log/entries/%s", util.RekorServer(), uuid), nil) + if err != nil { + t.Fatal(err) + } + // set Accept on every-other call to help get coverage on different scenarios + if j%2 == 0 { + req4.Header.Add("Accept", "*/*") //explicitly accept anything + } + respIter, err := client.Do(req4) + if err != nil { + t.Fatal(err) + } + defer respIter.Body.Close() + if ctHeader := respIter.Header.Get("Content-Type"); ctHeader != "application/json" { + t.Fatalf("unexpected response 'Content-Type' header received: expected 'application/json', got '%s'", ctHeader) + } + } } func parseResponseAsTLE(t *testing.T, resp *http.Response) error { diff --git a/pkg/tle/tle.go b/pkg/tle/tle.go index 596d3a7ff..abaea20bc 100644 --- a/pkg/tle/tle.go +++ b/pkg/tle/tle.go @@ -24,10 +24,12 @@ import ( "io" "github.com/go-openapi/runtime" + "github.com/go-openapi/swag" rekor_pb_common "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" rekor_pb "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/types" + "github.com/transparency-dev/merkle/rfc6962" "google.golang.org/protobuf/encoding/protojson" ) @@ -110,6 +112,36 @@ func MarshalTLEToJSON(tle *rekor_pb.TransparencyLogEntry) ([]byte, error) { return protojson.Marshal(tle) } +func GenerateLogEntry(tle *rekor_pb.TransparencyLogEntry) *models.LogEntry { + if tle == nil { + return nil + } + + entryUUID := hex.EncodeToString(rfc6962.DefaultHasher.HashLeaf(tle.CanonicalizedBody)) + inclusionProofHashes := []string{} + for _, hash := range tle.InclusionProof.Hashes { + inclusionProofHashes = append(inclusionProofHashes, hex.EncodeToString(hash)) + } + return &models.LogEntry{ + entryUUID: models.LogEntryAnon{ + Body: tle.CanonicalizedBody, + IntegratedTime: swag.Int64(tle.IntegratedTime), + LogID: swag.String(tle.LogId.String()), + LogIndex: swag.Int64(tle.LogIndex), + Verification: &models.LogEntryAnonVerification{ + InclusionProof: &models.InclusionProof{ + Checkpoint: swag.String(tle.InclusionProof.Checkpoint.String()), + Hashes: inclusionProofHashes, + LogIndex: swag.Int64(tle.LogIndex), + RootHash: swag.String(hex.EncodeToString(tle.InclusionProof.RootHash)), + TreeSize: swag.Int64(tle.InclusionProof.TreeSize), + }, + SignedEntryTimestamp: tle.InclusionPromise.SignedEntryTimestamp, + }, + }, + } +} + type TLEProducer struct{} func (t TLEProducer) Produce(w io.Writer, input interface{}) error { @@ -178,23 +210,36 @@ func (t TLEConsumer) Consume(r io.Reader, output interface{}) error { if err := json.Unmarshal(tleBytes, &jsonArray); err != nil { return fmt.Errorf("expected array: %w", err) } - var result []*rekor_pb.TransparencyLogEntry for _, element := range jsonArray { msg := &rekor_pb.TransparencyLogEntry{} if err := protojson.Unmarshal(element, msg); err != nil { return fmt.Errorf("parsing element: %w", err) } - result = append(result, msg) + if result, ok := output.([]models.LogEntry); ok { + logEntry := GenerateLogEntry(msg) + result = append(result, *logEntry) + } else if result, ok := output.([]*rekor_pb.TransparencyLogEntry); ok { + result = append(result, msg) + } else { + return errors.New("unsupported conversion") + } } - output = &result return nil case json.Delim('{'): // this is a JSON object, let's check output type to ensure its rekor_pb.TransparencyLogEntry - msg := output.(*rekor_pb.TransparencyLogEntry) - if err := protojson.Unmarshal(tleBytes, msg); err != nil { + tle := &rekor_pb.TransparencyLogEntry{} + if err := protojson.Unmarshal(tleBytes, tle); err != nil { return fmt.Errorf("parsing element: %w", err) } - return nil + if _, ok := output.(*rekor_pb.TransparencyLogEntry); ok { + output = tle + return nil + } else if _, ok := output.(*models.LogEntry); ok { + output = GenerateLogEntry(tle) + return nil + } else { + return errors.New("unsupported conversion") + } } return errors.New("unexpected value") } From 22886760b611389b0c0d1a2aae80bab92f969888 Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Wed, 30 Oct 2024 19:29:04 -0400 Subject: [PATCH 05/10] backout temp changes Signed-off-by: Bob Callaway --- e2e-test.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/e2e-test.sh b/e2e-test.sh index fe9c80ded..48f35e862 100755 --- a/e2e-test.sh +++ b/e2e-test.sh @@ -31,7 +31,7 @@ docker build -t gcp-pubsub-emulator -f Dockerfile.pubsub-emulator . docker kill $(docker ps -q) || true echo "starting services" -${docker_compose} up -d --build --force-recreate +${docker_compose} up -d --build echo "building CLI and server" # set the path to the root of the repo @@ -70,7 +70,6 @@ if ${docker_compose} logs --no-color | grep -q "panic: runtime error:" ; then exit 1 fi -exit 0 echo "generating code coverage" ${docker_compose} restart rekor-server From ae72b9da41124979f9321f04bd1866a29b51cb12 Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Thu, 31 Oct 2024 18:36:45 -0400 Subject: [PATCH 06/10] lint and test fixes Signed-off-by: Bob Callaway --- pkg/client/rekor_client.go | 2 +- .../restapi/configure_rekor_server.go | 2 +- pkg/tle/tle.go | 30 +++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/client/rekor_client.go b/pkg/client/rekor_client.go index fd7ca4813..2ed00c0e4 100644 --- a/pkg/client/rekor_client.go +++ b/pkg/client/rekor_client.go @@ -65,7 +65,7 @@ func GetRekorClient(rekorServerURL string, opts ...Option) (*client.Rekor, error rt := httptransport.NewWithClient(url.Host, url.Path, []string{url.Scheme}, httpClient) rt.Consumers["application/json"] = runtime.JSONConsumer() rt.Consumers["application/x-pem-file"] = runtime.TextConsumer() - rt.Consumers[tle.TLEMediaType] = &tle.TLEConsumer{} + rt.Consumers[tle.TLEMediaType] = &tle.Consumer{} rt.Producers["application/json"] = runtime.JSONProducer() rt.DefaultMediaType = "application/json" diff --git a/pkg/generated/restapi/configure_rekor_server.go b/pkg/generated/restapi/configure_rekor_server.go index 833d266cb..2d119656b 100644 --- a/pkg/generated/restapi/configure_rekor_server.go +++ b/pkg/generated/restapi/configure_rekor_server.go @@ -89,7 +89,7 @@ func configureAPI(api *operations.RekorServerAPI) http.Handler { api.JSONProducer = runtime.JSONProducer() api.ApplicationXPemFileProducer = runtime.TextProducer() - api.ApplicationXSigstoreTleProducer = tle.TLEProducer{} + api.ApplicationXSigstoreTleProducer = &tle.Producer{} // disable all endpoints to start api.IndexSearchIndexHandler = index.SearchIndexHandlerFunc(pkgapi.SearchIndexNotImplementedHandler) diff --git a/pkg/tle/tle.go b/pkg/tle/tle.go index abaea20bc..e0a20639d 100644 --- a/pkg/tle/tle.go +++ b/pkg/tle/tle.go @@ -112,7 +112,7 @@ func MarshalTLEToJSON(tle *rekor_pb.TransparencyLogEntry) ([]byte, error) { return protojson.Marshal(tle) } -func GenerateLogEntry(tle *rekor_pb.TransparencyLogEntry) *models.LogEntry { +func GenerateLogEntry(tle *rekor_pb.TransparencyLogEntry) models.LogEntry { if tle == nil { return nil } @@ -120,9 +120,9 @@ func GenerateLogEntry(tle *rekor_pb.TransparencyLogEntry) *models.LogEntry { entryUUID := hex.EncodeToString(rfc6962.DefaultHasher.HashLeaf(tle.CanonicalizedBody)) inclusionProofHashes := []string{} for _, hash := range tle.InclusionProof.Hashes { - inclusionProofHashes = append(inclusionProofHashes, hex.EncodeToString(hash)) + inclusionProofHashes = append(inclusionProofHashes, base64.StdEncoding.EncodeToString(hash)) } - return &models.LogEntry{ + return models.LogEntry{ entryUUID: models.LogEntryAnon{ Body: tle.CanonicalizedBody, IntegratedTime: swag.Int64(tle.IntegratedTime), @@ -142,9 +142,9 @@ func GenerateLogEntry(tle *rekor_pb.TransparencyLogEntry) *models.LogEntry { } } -type TLEProducer struct{} +type Producer struct{} -func (t TLEProducer) Produce(w io.Writer, input interface{}) error { +func (t Producer) Produce(w io.Writer, input interface{}) error { switch i := input.(type) { case models.LogEntry: var entry models.LogEntryAnon @@ -189,9 +189,9 @@ func (t TLEProducer) Produce(w io.Writer, input interface{}) error { return nil } -type TLEConsumer struct{} +type Consumer struct{} -func (t TLEConsumer) Consume(r io.Reader, output interface{}) error { +func (t Consumer) Consume(r io.Reader, output interface{}) error { tleBytes, err := io.ReadAll(r) if err != nil { return err @@ -215,11 +215,11 @@ func (t TLEConsumer) Consume(r io.Reader, output interface{}) error { if err := protojson.Unmarshal(element, msg); err != nil { return fmt.Errorf("parsing element: %w", err) } - if result, ok := output.([]models.LogEntry); ok { + if result, ok := output.(*[]models.LogEntry); ok { logEntry := GenerateLogEntry(msg) - result = append(result, *logEntry) - } else if result, ok := output.([]*rekor_pb.TransparencyLogEntry); ok { - result = append(result, msg) + *result = append(*result, logEntry) + } else if result, ok := output.(*[]*rekor_pb.TransparencyLogEntry); ok { + *result = append(*result, msg) } else { return errors.New("unsupported conversion") } @@ -231,11 +231,11 @@ func (t TLEConsumer) Consume(r io.Reader, output interface{}) error { if err := protojson.Unmarshal(tleBytes, tle); err != nil { return fmt.Errorf("parsing element: %w", err) } - if _, ok := output.(*rekor_pb.TransparencyLogEntry); ok { - output = tle + if result, ok := output.(**rekor_pb.TransparencyLogEntry); ok { + *result = tle return nil - } else if _, ok := output.(*models.LogEntry); ok { - output = GenerateLogEntry(tle) + } else if result, ok := output.(*models.LogEntry); ok { + *result = GenerateLogEntry(tle) return nil } else { return errors.New("unsupported conversion") From 15611349fdb1097aa6c9254621497ac01e84dc75 Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Sat, 2 Nov 2024 17:52:41 -0400 Subject: [PATCH 07/10] base64 encode body Signed-off-by: Bob Callaway --- pkg/tle/tle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tle/tle.go b/pkg/tle/tle.go index e0a20639d..2ce2bac5d 100644 --- a/pkg/tle/tle.go +++ b/pkg/tle/tle.go @@ -124,7 +124,7 @@ func GenerateLogEntry(tle *rekor_pb.TransparencyLogEntry) models.LogEntry { } return models.LogEntry{ entryUUID: models.LogEntryAnon{ - Body: tle.CanonicalizedBody, + Body: base64.StdEncoding.EncodeToString(tle.CanonicalizedBody), IntegratedTime: swag.Int64(tle.IntegratedTime), LogID: swag.String(tle.LogId.String()), LogIndex: swag.Int64(tle.LogIndex), From 1be87c235c40f64ecea9de0cf4acece2a628c8a2 Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Sat, 2 Nov 2024 19:06:49 -0400 Subject: [PATCH 08/10] pass hex strings Signed-off-by: Bob Callaway --- pkg/tle/tle.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/tle/tle.go b/pkg/tle/tle.go index 2ce2bac5d..5467484e9 100644 --- a/pkg/tle/tle.go +++ b/pkg/tle/tle.go @@ -117,16 +117,17 @@ func GenerateLogEntry(tle *rekor_pb.TransparencyLogEntry) models.LogEntry { return nil } + //TODO: do we have the information to prefix the tree ID onto this? entryUUID := hex.EncodeToString(rfc6962.DefaultHasher.HashLeaf(tle.CanonicalizedBody)) inclusionProofHashes := []string{} for _, hash := range tle.InclusionProof.Hashes { - inclusionProofHashes = append(inclusionProofHashes, base64.StdEncoding.EncodeToString(hash)) + inclusionProofHashes = append(inclusionProofHashes, hex.EncodeToString(hash)) } return models.LogEntry{ entryUUID: models.LogEntryAnon{ Body: base64.StdEncoding.EncodeToString(tle.CanonicalizedBody), IntegratedTime: swag.Int64(tle.IntegratedTime), - LogID: swag.String(tle.LogId.String()), + LogID: swag.String(hex.EncodeToString(tle.LogId.KeyId)), LogIndex: swag.Int64(tle.LogIndex), Verification: &models.LogEntryAnonVerification{ InclusionProof: &models.InclusionProof{ From 8f41e931969ed42acd09132f04d4181a462bc2f7 Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Sat, 2 Nov 2024 19:23:53 -0400 Subject: [PATCH 09/10] wrap SET Signed-off-by: Bob Callaway --- pkg/tle/tle.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/tle/tle.go b/pkg/tle/tle.go index 5467484e9..62964f68c 100644 --- a/pkg/tle/tle.go +++ b/pkg/tle/tle.go @@ -24,6 +24,7 @@ import ( "io" "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" rekor_pb_common "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" rekor_pb "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1" @@ -137,7 +138,7 @@ func GenerateLogEntry(tle *rekor_pb.TransparencyLogEntry) models.LogEntry { RootHash: swag.String(hex.EncodeToString(tle.InclusionProof.RootHash)), TreeSize: swag.Int64(tle.InclusionProof.TreeSize), }, - SignedEntryTimestamp: tle.InclusionPromise.SignedEntryTimestamp, + SignedEntryTimestamp: strfmt.Base64(tle.InclusionPromise.SignedEntryTimestamp), }, }, } From 535289d409d7fbbb2dc001e724bf45a167f3beb6 Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Sun, 3 Nov 2024 07:17:20 -0500 Subject: [PATCH 10/10] use envelope for checkpoint Signed-off-by: Bob Callaway --- pkg/tle/tle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tle/tle.go b/pkg/tle/tle.go index 62964f68c..1068f9096 100644 --- a/pkg/tle/tle.go +++ b/pkg/tle/tle.go @@ -132,7 +132,7 @@ func GenerateLogEntry(tle *rekor_pb.TransparencyLogEntry) models.LogEntry { LogIndex: swag.Int64(tle.LogIndex), Verification: &models.LogEntryAnonVerification{ InclusionProof: &models.InclusionProof{ - Checkpoint: swag.String(tle.InclusionProof.Checkpoint.String()), + Checkpoint: swag.String(tle.InclusionProof.Checkpoint.GetEnvelope()), Hashes: inclusionProofHashes, LogIndex: swag.Int64(tle.LogIndex), RootHash: swag.String(hex.EncodeToString(tle.InclusionProof.RootHash)),