From 2746b6ded3f7bf2ea6f8d17dca028c415078bb91 Mon Sep 17 00:00:00 2001 From: Martin Hutchinson Date: Tue, 30 Sep 2025 11:23:45 +0000 Subject: [PATCH] Witness support on SumDB proxy Binaries now support a flag specifiying the number of witness sigs required to be served on the checkpoint. This is implemented as an option on the library. This will allow developers to test out witnessing support in client tooling, before sumdb supports it natively. --- sumdb/cmd/proxy.go | 13 ++++++------- sumdb/proxy.go | 23 +++++++++++++++++++++-- vindex/cmd/sumdb/main.go | 4 +++- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/sumdb/cmd/proxy.go b/sumdb/cmd/proxy.go index e58c71a..ebaa80b 100644 --- a/sumdb/cmd/proxy.go +++ b/sumdb/cmd/proxy.go @@ -26,19 +26,18 @@ import ( ) var ( - listen = flag.String("listen", ":8089", "Address to set up HTTP server listening on") -) - -const ( - upstreamBase = "https://sum.golang.org" + listen = flag.String("listen", ":8089", "Address to set up HTTP server listening on") + witnessSigs = flag.Uint("witnesses", 0, "Number of witness signatures required on a checkpoint. Setting this will pull checkpoints from the transparency-dev prod distributor.") ) func main() { klog.InitFlags(nil) flag.Parse() - proxy := sumdb.NewProxy(sumdb.ProxyOpts{}) - klog.Infof("Proxying tlog-tiles API to %s on %s", upstreamBase, *listen) + proxy := sumdb.NewProxy(sumdb.ProxyOpts{ + WitnessSigs: *witnessSigs, + }) + klog.Infof("tlog-tiles API listening on %s", *listen) if err := http.ListenAndServe(*listen, proxy); err != nil { klog.Fatalf("ListenAndServe: %v", err) } diff --git a/sumdb/proxy.go b/sumdb/proxy.go index b1fe943..6d6f611 100644 --- a/sumdb/proxy.go +++ b/sumdb/proxy.go @@ -31,13 +31,23 @@ import ( ) const ( - upstreamBase = "https://sum.golang.org" + upstreamBase = "https://sum.golang.org" + distributorBase = "https://api.transparency.dev/" + distributorCheckpointPathFmt = "/distributor/v0/logs/a32d071739c062f4973f1db8cc1069f517428d77105962b285bbf918c4062591/checkpoint.%d" ) type ProxyOpts struct { // PathPrefix should be set if the proxy is hosted not at "/". // Any path beyond this should be set here, so that it can be stripped. PathPrefix string + + // WitnessSigs should be set to ensure that a given number of witness signatures + // are available. If this is left at the default of 0, then we proxy to the + // latest checkpoint from SumDB. If this is set to a positive number, then we + // request the latest checkpoint with that number of sigs from the checkpoint + // distributor. + // https://github.com/transparency-dev/distributor/ + WitnessSigs uint } func NewProxy(opts ProxyOpts) *httputil.ReverseProxy { @@ -45,6 +55,10 @@ func NewProxy(opts ProxyOpts) *httputil.ReverseProxy { if err != nil { klog.Fatalf("Failed to parse upstream URL %q: %v", upstreamBase, err) } + distributor, err := url.Parse(distributorBase) + if err != nil { + klog.Fatalf("Failed to parse distributor URL %q: %v", distributorBase, err) + } prefix, _ := strings.CutSuffix(opts.PathPrefix, "/") @@ -60,7 +74,12 @@ func NewProxy(opts ProxyOpts) *httputil.ReverseProxy { klog.V(2).Infof("Request for %s", inPath) if inPath == "/checkpoint" { - r.Out.URL.Path = "/latest" + if opts.WitnessSigs == 0 { + r.Out.URL.Path = "/latest" + return + } + r.SetURL(distributor) + r.Out.URL.Path = fmt.Sprintf(distributorCheckpointPathFmt, opts.WitnessSigs) } else if strings.HasPrefix(inPath, tlogEntriesPrefix) { o := strings.TrimPrefix(inPath, tlogEntriesPrefix) r.Out.URL.Path = fmt.Sprintf("%s%s", sumDBTileDataPrefix, o) diff --git a/vindex/cmd/sumdb/main.go b/vindex/cmd/sumdb/main.go index 6a58b0b..6ff4c4f 100644 --- a/vindex/cmd/sumdb/main.go +++ b/vindex/cmd/sumdb/main.go @@ -47,6 +47,7 @@ var ( outputLogPrivKeyFile = flag.String("output_log_private_key_path", "", "Location of private key file. If unset, uses the contents of the OUTPUT_LOG_PRIVATE_KEY environment variable.") storageDir = flag.String("storage_dir", "", "Root directory in which to store the data for the demo. This will create subdirectories for the Output Log, and allocate space to store the verifiable map persistence.") persistIndex = flag.Bool("persist_index", false, "Set to true to use a disk-based implementation of the verifiable index. This can be slow, but useful in situations where memory is constrained.") + witnessSigs = flag.Uint("witnesses", 0, "Number of witness signatures required on the SumDB checkpoint. Setting this will pull checkpoints from the transparency-dev prod distributor.") listen = flag.String("listen", ":8088", "Address to set up HTTP server listening on") ) @@ -106,7 +107,8 @@ func run(ctx context.Context) error { return err } sumProxy := sumdb.NewProxy(sumdb.ProxyOpts{ - PathPrefix: "/inputlog/", + PathPrefix: "/inputlog/", + WitnessSigs: *witnessSigs, }) outputLog, outputCloser := outputLogOrDie(ctx, outputLogDir)