diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml index 2ff05b2..cbe09a8 100644 --- a/.github/workflows/build-test.yaml +++ b/.github/workflows/build-test.yaml @@ -11,7 +11,7 @@ on: # yamllint disable-line rule:truthy types: - "checks_requested" env: - GO_VERSION: "~1.20.7" + GO_VERSION: "~1.21.1" jobs: paths-filter: runs-on: "ubuntu-latest" diff --git a/Dockerfile b/Dockerfile index 5124612..c63b98b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM golang:1.20-alpine3.18 AS builder +FROM --platform=$BUILDPLATFORM golang:1.21.1-alpine3.18 AS builder ARG TARGETOS TARGETARCH WORKDIR /go/src/spicedb-kubeapi-proxy diff --git a/e2e/go.mod b/e2e/go.mod index 3bb3e69..0011bf8 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -1,6 +1,8 @@ module github.com/authzed/spicedb-kubeapi-proxy/e2e -go 1.20 +go 1.21 + +toolchain go1.21.0 replace github.com/authzed/spicedb-kubeapi-proxy => ../ @@ -53,6 +55,7 @@ require ( github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/creasty/defaults v1.7.0 // indirect + github.com/cschleiden/go-workflows v0.16.2 // indirect github.com/dalzilio/rudd v1.1.1-0.20230806153452-9e08a6ea8170 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlmiddlecote/sqlstats v1.0.2 // indirect @@ -69,6 +72,7 @@ require ( github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zerologr v1.2.3 // indirect @@ -111,23 +115,22 @@ require ( github.com/jackc/pgx-zerolog v0.0.0-20230315001418-f978528409eb // indirect github.com/jackc/pgx/v5 v5.4.2 // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jellydator/ttlcache/v3 v3.0.0 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/jzelinskie/cobrautil/v2 v2.0.0-20230714172849-80717639cec5 // indirect github.com/jzelinskie/stringz v0.0.2 // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.16.7 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lthibault/jitterbug v2.0.0+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/marusama/semaphore/v2 v2.5.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-sqlite3 v1.14.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/microsoft/durabletask-go v0.3.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/sys/mountinfo v0.6.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -147,7 +150,6 @@ require ( github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.0 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rs/cors v1.9.0 // indirect github.com/rs/zerolog v1.29.1 // indirect github.com/scylladb/go-set v1.0.2 // indirect @@ -159,6 +161,7 @@ require ( github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace // indirect github.com/spf13/viper v1.16.0 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect github.com/stretchr/testify v1.8.4 // indirect github.com/subosito/gotenv v1.4.2 // indirect go.etcd.io/etcd/api/v3 v3.5.9 // indirect @@ -221,16 +224,6 @@ require ( k8s.io/mount-utils v0.0.0 // indirect k8s.io/pod-security-admission v0.0.0 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect - lukechampine.com/uint128 v1.2.0 // indirect - modernc.org/cc/v3 v3.40.0 // indirect - modernc.org/ccgo/v3 v3.16.13 // indirect - modernc.org/libc v1.22.5 // indirect - modernc.org/mathutil v1.5.0 // indirect - modernc.org/memory v1.5.0 // indirect - modernc.org/opt v0.1.3 // indirect - modernc.org/sqlite v1.22.1 // indirect - modernc.org/strutil v1.1.3 // indirect - modernc.org/token v1.0.1 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect diff --git a/e2e/go.sum b/e2e/go.sum index aee69f0..3da8014 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -53,6 +53,7 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/IBM/pgxpoolprometheus v1.1.1 h1:xkWNUe87TIuBj/ypdSiDgNYktsuM7MoZCT8a+kjhh2s= @@ -60,9 +61,11 @@ github.com/IBM/pgxpoolprometheus v1.1.1/go.mod h1:GFJDkHbidFfB2APbhBTSy2X4PKH3bL github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -119,6 +122,7 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= +github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= @@ -129,6 +133,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA= github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= +github.com/cschleiden/go-workflows v0.16.2 h1:rRKAJ/HdMFUAcZoJYJ/o7kH7Yvn9Zs3zKtSSzVQUVkk= +github.com/cschleiden/go-workflows v0.16.2/go.mod h1:uH7DoncdkBSk5U/azOSf6Yn32Or5KlSv15RoMQze4i0= github.com/dalzilio/rudd v1.1.1-0.20230806153452-9e08a6ea8170 h1:bHEN1z3EOO/IXHTQ8ZcmGoW4gTJt+mSrH2Sd458uo0E= github.com/dalzilio/rudd v1.1.1-0.20230806153452-9e08a6ea8170/go.mod h1:IxPC4Bdi3WqUwyGBMgLrWWGx67aRtUAZmOZrkIr7qaM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -139,11 +145,15 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dlmiddlecote/sqlstats v1.0.2 h1:gSU11YN23D/iY50A2zVYwgXgy072khatTsIW6UPjUtI= github.com/dlmiddlecote/sqlstats v1.0.2/go.mod h1:0CWaIh/Th+z2aI6Q9Jpfg/o21zmGxWhbByHgQSCUQvY= github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc= +github.com/docker/cli v24.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= +github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -177,9 +187,12 @@ github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0C github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -217,8 +230,10 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= +github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -254,6 +269,7 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/cel-go v0.16.0 h1:DG9YQ8nFCFXAs/FDDwBxmL1tpKNrdlGUM9U3537bX/Y= github.com/google/cel-go v0.16.0/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -297,6 +313,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -308,6 +325,7 @@ github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56 github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5 h1:3IZOAnD058zZllQTZNBioTlrzrBG/IjpiZ133IEtusM= @@ -330,6 +348,7 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= @@ -356,10 +375,13 @@ github.com/jackc/pgx/v5 v5.4.2 h1:u1gmGDwbdRUZiwisBm/Ky2M14uQyUP65bG8+20nnyrg= github.com/jackc/pgx/v5 v5.4.2/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jellydator/ttlcache/v3 v3.0.0 h1:zmFhqrB/4sKiEiJHhtseJsNRE32IMVmJSs4++4gaQO4= +github.com/jellydator/ttlcache/v3 v3.0.0/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -373,8 +395,6 @@ github.com/jzelinskie/cobrautil/v2 v2.0.0-20230714172849-80717639cec5 h1:X7vo4fE github.com/jzelinskie/cobrautil/v2 v2.0.0-20230714172849-80717639cec5/go.mod h1:954benQgK9Oi403yRaIot4TgRM0dDLKrBj48K7J8NZg= github.com/jzelinskie/stringz v0.0.2 h1:OSjMEYvz8tjhovgZ/6cGcPID736ubeukr35mu6RYAmg= github.com/jzelinskie/stringz v0.0.2/go.mod h1:hHYbgxJuNLRw91CmpuFsYEOyQqpDVFg8pvEh23vy4P0= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= @@ -385,6 +405,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -399,8 +420,6 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM= -github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -410,16 +429,16 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/microsoft/durabletask-go v0.3.0 h1:n3DE/SwI9sebft3vG0QcD7ioxqy15VJMzv3HOry8dJk= -github.com/microsoft/durabletask-go v0.3.0/go.mod h1:t3u0iRvIadT1y4MD5cUG0mbTOqgANT6IFcLogv7o0M0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -441,11 +460,14 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= +github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.8 h1:zICRlc+C1XzivLc3nzE+cbJV4LIi8tib6YG0MqC6OqA= +github.com/opencontainers/runc v1.1.8/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= +github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= @@ -481,12 +503,10 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -504,7 +524,9 @@ github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= @@ -539,10 +561,15 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -550,16 +577,21 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= go.etcd.io/etcd/client/v2 v2.305.9 h1:YZ2OLi0OvR0H75AcgSUajjd5uqKDKocQUqROTG11jIo= +go.etcd.io/etcd/client/v2 v2.305.9/go.mod h1:0NBdNx9wbxtEQLwAQtrDHwx58m02vXpDcgSYI2seohQ= go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= go.etcd.io/etcd/pkg/v3 v3.5.9 h1:6R2jg/aWd/zB9+9JxmijDKStGJAPFsX3e6BeJkMi6eQ= +go.etcd.io/etcd/pkg/v3 v3.5.9/go.mod h1:BZl0SAShQFk0IpLWR78T/+pyt8AruMHhTNNX73hkNVY= go.etcd.io/etcd/raft/v3 v3.5.9 h1:ZZ1GIHoUlHsn0QVqiRysAm3/81Xx7+i2d7nSdWxlOiI= +go.etcd.io/etcd/raft/v3 v3.5.9/go.mod h1:WnFkqzFdZua4LVlVXQEGhmooLeyS7mqzS4Pf4BCVqXg= go.etcd.io/etcd/server/v3 v3.5.9 h1:vomEmmxeztLtS5OEH7d0hBAg4cjVIu9wXuNzUZx2ZA0= +go.etcd.io/etcd/server/v3 v3.5.9/go.mod h1:GgI1fQClQCFIzuVjlvdbMxNbnISt90gdfYyqiAIt65g= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -604,6 +636,7 @@ go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0 go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -861,6 +894,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= +gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -1024,6 +1058,7 @@ k8s.io/component-helpers v0.28.0/go.mod h1:i7hJ/oFhZImqUWwjLFG/yGkLpJ3KFoirY2DLY k8s.io/controller-manager v0.28.0 h1:55rmyzwEOnhAZLsuDdDHwVT2sGzkleFY0SqZFKsLN5U= k8s.io/controller-manager v0.28.0/go.mod h1:WrABGmrpEWBap27eu533RpW5lBnVT5K+u2oc2bDwcmU= k8s.io/csi-translation-lib v0.28.0 h1:X3Kr5aHvH4xutNg4pgdc6RP0h3FOlJGDeui5CLfBeO4= +k8s.io/csi-translation-lib v0.28.0/go.mod h1:HvnmmGZoTobqMU4MD3yQFJ4U4Dq3PxnCfVbJUjky3K0= k8s.io/dynamic-resource-allocation v0.28.0 h1:LQjb8kRQcvorEHlJVfHLSGued8taykmqROMGozMpHsY= k8s.io/dynamic-resource-allocation v0.28.0/go.mod h1:x8xyQvoo22hfBEZlKt3nqkzfoTcMOJxiD9mSgDgrd2w= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= @@ -1042,30 +1077,6 @@ k8s.io/pod-security-admission v0.28.0 h1:Vz8XTjMAKHQFZv9Q4GdmO59CUtelkPPDRJTy/WT k8s.io/pod-security-admission v0.28.0/go.mod h1:hABVUcP7SRALDvESOK+RYIAWc9uZ5I1eSdcUwsOYTU8= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= -modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= -modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= -modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= -modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= -modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= -modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= -modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.22.1 h1:P2+Dhp5FR1RlVRkQ3dDfCiv3Ok8XPxqpe70IjYVA9oE= -modernc.org/sqlite v1.22.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= -modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= -modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= -modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/e2e/proxy_test.go b/e2e/proxy_test.go index 87d14ca..ec0e4af 100644 --- a/e2e/proxy_test.go +++ b/e2e/proxy_test.go @@ -113,7 +113,7 @@ var _ = Describe("Proxy", func() { Expect(chaniList).To(ContainElement(chaniNamespace)) }) - It("cleans up dual writes on kube failures", func(ctx context.Context) { + It("recovers when there are kube failures", func(ctx context.Context) { // paul creates his namespace Expect(CreateNamespace(ctx, paulClient, paulNamespace)).To(Succeed()) @@ -125,21 +125,22 @@ var _ = Describe("Proxy", func() { } else { failpoints.EnableFailPoint("panicKubeWrite", 1) } - Expect(CreateNamespace(ctx, chaniClient, chaniNamespace)).ToNot(BeNil()) + // Chani's write panics, but is retried + Expect(CreateNamespace(ctx, chaniClient, chaniNamespace)).To(Succeed()) - // paul creates chani's namespace - Expect(CreateNamespace(ctx, paulClient, chaniNamespace)).To(Succeed()) + // paul isn't able to create chanis namespace + Expect(CreateNamespace(ctx, paulClient, chaniNamespace)).ToNot(BeNil()) - // paul can get both namespaces + // paul can only get his namespace Expect(GetNamespace(ctx, paulClient, paulNamespace)).To(Succeed()) - Expect(GetNamespace(ctx, paulClient, chaniNamespace)).To(Succeed()) + Expect(GetNamespace(ctx, paulClient, chaniNamespace)).ToNot(BeNil()) - // chani can't get her namespace - this indicates the spicedb write was rolled back - // from the failed dual write above - Expect(k8serrors.IsNotFound(GetNamespace(ctx, chaniClient, chaniNamespace))).To(BeTrue()) + // chani can get her namespace - this indicates the workflow was retried and eventually succeeded + Expect(GetNamespace(ctx, chaniClient, paulNamespace)).ToNot(BeNil()) + Expect(GetNamespace(ctx, chaniClient, chaniNamespace)).To(Succeed()) }) - It("recovers dual writes when kube write succeeds but crashes", func(ctx context.Context) { + It("recovers when kube write succeeds but crashes", func(ctx context.Context) { // paul creates his namespace Expect(CreateNamespace(ctx, paulClient, paulNamespace)).To(Succeed()) @@ -179,34 +180,30 @@ var _ = Describe("Proxy", func() { Expect(k8serrors.IsNotFound(GetNamespace(ctx, chaniClient, chaniNamespace))).To(BeTrue()) }) - It("recovers dual writes when there are spicedb write failures", func(ctx context.Context) { + It("recovers when there are spicedb write failures", func(ctx context.Context) { // paul creates his namespace Expect(CreateNamespace(ctx, paulClient, paulNamespace)).To(Succeed()) - // make spicedb write crash on chani's namespace write + // make spicedb write crash on chani's namespace write, eventually succeeds failpoints.EnableFailPoint("panicWriteSpiceDB", 1) - Expect(CreateNamespace(ctx, chaniClient, chaniNamespace)).ToNot(BeNil()) + Expect(CreateNamespace(ctx, chaniClient, chaniNamespace)).To(Succeed()) - // paul creates chani's namespace so that the namespace exists - Expect(CreateNamespace(ctx, paulClient, chaniNamespace)).To(Succeed()) + // paul is unable to create chani's namespace as it's already claimed + Expect(CreateNamespace(ctx, paulClient, chaniNamespace)).ToNot(BeNil()) - // check that chani can't get her namespace, indirectly showing - // that the spicedb write was rolled back - Expect(k8serrors.IsNotFound(GetNamespace(ctx, chaniClient, chaniNamespace))).To(BeTrue()) + // Check Chani is able to get namespace + Expect(GetNamespace(ctx, chaniClient, chaniNamespace)).To(Succeed()) - // confirm the relationship doesn't exist + // confirm the relationship exists Expect(len(GetAllTuples(ctx, &v1.RelationshipFilter{ ResourceType: "namespace", OptionalResourceId: chaniNamespace, OptionalRelation: "creator", OptionalSubjectFilter: &v1.SubjectFilter{SubjectType: "user", OptionalSubjectId: "chani"}, - }))).To(BeZero()) - - // confirm paul can get the namespace - Expect(GetNamespace(ctx, paulClient, chaniNamespace)).To(Succeed()) + }))).ToNot(BeZero()) }) - It("recovers dual writes when spicedb write succeeds but crashes", func(ctx context.Context) { + It("recovers when spicedb write succeeds but crashes", func(ctx context.Context) { // paul creates his namespace Expect(CreateNamespace(ctx, paulClient, paulNamespace)).To(Succeed()) diff --git a/go.mod b/go.mod index 9e42ed9..85fdced 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,17 @@ module github.com/authzed/spicedb-kubeapi-proxy -go 1.20 +go 1.21 + +toolchain go1.21.0 require ( github.com/authzed/authzed-go v0.9.1-0.20230810180432-2fb0fd4c66dd github.com/authzed/grpcutil v0.0.0-20230703173955-bdd0ac3f16a5 github.com/authzed/spicedb v1.24.1-0.20230821163419-e4bb3adfd50b github.com/cespare/xxhash/v2 v2.2.0 + github.com/cschleiden/go-workflows v0.16.2 github.com/dustin/go-humanize v1.0.1 github.com/google/uuid v1.3.0 - github.com/microsoft/durabletask-go v0.3.0 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace github.com/stretchr/testify v1.8.4 @@ -22,6 +24,8 @@ require ( k8s.io/kubernetes v1.28.0 ) +replace github.com/cschleiden/go-workflows => github.com/vroldanbet/go-workflows v0.0.0-20230918124723-368160933470 + require ( buf.build/gen/go/gogo/protobuf/protocolbuffers/go v1.31.0-20210810001428-4df00b267f94.1 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect @@ -76,6 +80,7 @@ require ( github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.2.4 // indirect @@ -114,6 +119,7 @@ require ( github.com/jackc/pgx-zerolog v0.0.0-20230315001418-f978528409eb // indirect github.com/jackc/pgx/v5 v5.4.2 // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jellydator/ttlcache/v3 v3.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/jzelinskie/cobrautil/v2 v2.0.0-20230714172849-80717639cec5 // indirect @@ -125,7 +131,6 @@ require ( github.com/lthibault/jitterbug v2.0.0+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/marusama/semaphore/v2 v2.5.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect @@ -160,6 +165,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/viper v1.16.0 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect go.etcd.io/etcd/api/v3 v3.5.9 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect @@ -217,11 +223,11 @@ require ( lukechampine.com/uint128 v1.2.0 // indirect modernc.org/cc/v3 v3.40.0 // indirect modernc.org/ccgo/v3 v3.16.13 // indirect - modernc.org/libc v1.22.5 // indirect + modernc.org/libc v1.24.1 // indirect modernc.org/mathutil v1.5.0 // indirect - modernc.org/memory v1.5.0 // indirect + modernc.org/memory v1.6.0 // indirect modernc.org/opt v0.1.3 // indirect - modernc.org/sqlite v1.22.1 // indirect + modernc.org/sqlite v1.25.0 // indirect modernc.org/strutil v1.1.3 // indirect modernc.org/token v1.0.1 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 // indirect diff --git a/go.sum b/go.sum index 50b632c..64a7408 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,7 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/IBM/pgxpoolprometheus v1.1.1 h1:xkWNUe87TIuBj/ypdSiDgNYktsuM7MoZCT8a+kjhh2s= @@ -60,9 +61,11 @@ github.com/IBM/pgxpoolprometheus v1.1.1/go.mod h1:GFJDkHbidFfB2APbhBTSy2X4PKH3bL github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -119,6 +122,7 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= +github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= @@ -139,11 +143,15 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dlmiddlecote/sqlstats v1.0.2 h1:gSU11YN23D/iY50A2zVYwgXgy072khatTsIW6UPjUtI= github.com/dlmiddlecote/sqlstats v1.0.2/go.mod h1:0CWaIh/Th+z2aI6Q9Jpfg/o21zmGxWhbByHgQSCUQvY= github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc= +github.com/docker/cli v24.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= +github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -167,6 +175,7 @@ github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7 github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exaring/otelpgx v0.5.0 h1:XA8F1rWSyOleizQ8PlzZ3nYggIg4fwaVzFAJii0d5RE= github.com/exaring/otelpgx v0.5.0/go.mod h1:a3fAXoYxYGCID+2WHKNe9eoDIiWl01SCc26KtdTMVYk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= @@ -176,9 +185,12 @@ github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0C github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -210,13 +222,16 @@ github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrt github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= +github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -252,6 +267,7 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/cel-go v0.16.0 h1:DG9YQ8nFCFXAs/FDDwBxmL1tpKNrdlGUM9U3537bX/Y= github.com/google/cel-go v0.16.0/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -290,10 +306,12 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 h1:2XF1Vzq06X+inNqgJ9tRnGuw+ZVCB3FazXODD6JE1R8= +github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -305,6 +323,7 @@ github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56 github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5 h1:3IZOAnD058zZllQTZNBioTlrzrBG/IjpiZ133IEtusM= @@ -327,6 +346,7 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= @@ -353,9 +373,12 @@ github.com/jackc/pgx/v5 v5.4.2 h1:u1gmGDwbdRUZiwisBm/Ky2M14uQyUP65bG8+20nnyrg= github.com/jackc/pgx/v5 v5.4.2/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jellydator/ttlcache/v3 v3.0.0 h1:zmFhqrB/4sKiEiJHhtseJsNRE32IMVmJSs4++4gaQO4= +github.com/jellydator/ttlcache/v3 v3.0.0/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -381,6 +404,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -395,8 +419,6 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM= -github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -406,16 +428,16 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/microsoft/durabletask-go v0.3.0 h1:n3DE/SwI9sebft3vG0QcD7ioxqy15VJMzv3HOry8dJk= -github.com/microsoft/durabletask-go v0.3.0/go.mod h1:t3u0iRvIadT1y4MD5cUG0mbTOqgANT6IFcLogv7o0M0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -431,15 +453,20 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79 h1:Dmx8g2747UTVPzSkmohk84S3g/uWqd6+f4SSLPhLcfA= github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79/go.mod h1:E26fwEtRNigBfFfHDWsklmo0T7Ixbg0XXgck+Hq4O9k= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= +github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= +github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.8 h1:zICRlc+C1XzivLc3nzE+cbJV4LIi8tib6YG0MqC6OqA= +github.com/opencontainers/runc v1.1.8/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= +github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= @@ -481,6 +508,7 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -498,7 +526,9 @@ github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= @@ -533,10 +563,17 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= +github.com/vroldanbet/go-workflows v0.0.0-20230918124723-368160933470 h1:WdvVQpO50vgrqrjTEYK0X0rUQgbLkAorA/NXzNGQav8= +github.com/vroldanbet/go-workflows v0.0.0-20230918124723-368160933470/go.mod h1:ZOjusEe+7EAODZLR5PyvciQunZi7D9ebwlzaU+nqU/8= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -544,16 +581,21 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= go.etcd.io/etcd/client/v2 v2.305.9 h1:YZ2OLi0OvR0H75AcgSUajjd5uqKDKocQUqROTG11jIo= +go.etcd.io/etcd/client/v2 v2.305.9/go.mod h1:0NBdNx9wbxtEQLwAQtrDHwx58m02vXpDcgSYI2seohQ= go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= go.etcd.io/etcd/pkg/v3 v3.5.9 h1:6R2jg/aWd/zB9+9JxmijDKStGJAPFsX3e6BeJkMi6eQ= +go.etcd.io/etcd/pkg/v3 v3.5.9/go.mod h1:BZl0SAShQFk0IpLWR78T/+pyt8AruMHhTNNX73hkNVY= go.etcd.io/etcd/raft/v3 v3.5.9 h1:ZZ1GIHoUlHsn0QVqiRysAm3/81Xx7+i2d7nSdWxlOiI= +go.etcd.io/etcd/raft/v3 v3.5.9/go.mod h1:WnFkqzFdZua4LVlVXQEGhmooLeyS7mqzS4Pf4BCVqXg= go.etcd.io/etcd/server/v3 v3.5.9 h1:vomEmmxeztLtS5OEH7d0hBAg4cjVIu9wXuNzUZx2ZA0= +go.etcd.io/etcd/server/v3 v3.5.9/go.mod h1:GgI1fQClQCFIzuVjlvdbMxNbnISt90gdfYyqiAIt65g= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -598,6 +640,7 @@ go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0 go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -855,6 +898,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= +gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -1018,6 +1062,7 @@ k8s.io/component-helpers v0.28.0/go.mod h1:i7hJ/oFhZImqUWwjLFG/yGkLpJ3KFoirY2DLY k8s.io/controller-manager v0.28.0 h1:55rmyzwEOnhAZLsuDdDHwVT2sGzkleFY0SqZFKsLN5U= k8s.io/controller-manager v0.28.0/go.mod h1:WrABGmrpEWBap27eu533RpW5lBnVT5K+u2oc2bDwcmU= k8s.io/csi-translation-lib v0.28.0 h1:X3Kr5aHvH4xutNg4pgdc6RP0h3FOlJGDeui5CLfBeO4= +k8s.io/csi-translation-lib v0.28.0/go.mod h1:HvnmmGZoTobqMU4MD3yQFJ4U4Dq3PxnCfVbJUjky3K0= k8s.io/dynamic-resource-allocation v0.28.0 h1:LQjb8kRQcvorEHlJVfHLSGued8taykmqROMGozMpHsY= k8s.io/dynamic-resource-allocation v0.28.0/go.mod h1:x8xyQvoo22hfBEZlKt3nqkzfoTcMOJxiD9mSgDgrd2w= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= @@ -1043,23 +1088,27 @@ modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= -modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= -modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= +modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= +modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.22.1 h1:P2+Dhp5FR1RlVRkQ3dDfCiv3Ok8XPxqpe70IjYVA9oE= -modernc.org/sqlite v1.22.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= +modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA= +modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= +modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c= modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= +modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/pkg/proxy/authz.go b/pkg/proxy/authz.go index 86cb82a..68477d7 100644 --- a/pkg/proxy/authz.go +++ b/pkg/proxy/authz.go @@ -14,6 +14,8 @@ import ( "github.com/authzed/spicedb-kubeapi-proxy/pkg/proxy/distributedtx" v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" + "github.com/cschleiden/go-workflows/client" + "github.com/google/uuid" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -25,13 +27,10 @@ import ( "k8s.io/apiserver/pkg/endpoints/request" ) -func WithAuthorization(handler, failed http.Handler, permissionsClient v1.PermissionsServiceClient, watchClient v1.WatchServiceClient, scheduler distributedtx.TaskScheduler, lockMode *string) (http.Handler, error) { - if *lockMode == "" { - return nil, fmt.Errorf("lock mode is undefined") - } - - if !(*lockMode == distributedtx.StrategyPessimisticWriteToSpiceDBAndKube || *lockMode == distributedtx.StrategyOptimisticWriteToSpiceDBAndKube) { - return nil, fmt.Errorf("unexpected lock mode: %s", *lockMode) +func WithAuthorization(handler, failed http.Handler, permissionsClient v1.PermissionsServiceClient, watchClient v1.WatchServiceClient, workflowClient client.Client, lockMode *string) (http.Handler, error) { + workflow, err := distributedtx.WorkflowForLockMode(*lockMode) + if err != nil { + return nil, err } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { @@ -74,7 +73,9 @@ func WithAuthorization(handler, failed http.Handler, permissionsClient v1.Permis return } - id, err := scheduler.Schedule(ctx, *lockMode, &distributedtx.CreateObjInput{ + id, err := workflowClient.CreateWorkflowInstance(ctx, client.WorkflowInstanceOptions{ + InstanceID: uuid.NewString(), + }, workflow, &distributedtx.CreateObjInput{ RequestInfo: requestInfo, UserInfo: userInfo.(*user.DefaultInfo), ObjectMeta: &pom.ObjectMeta, @@ -85,7 +86,8 @@ func WithAuthorization(handler, failed http.Handler, permissionsClient v1.Permis failed.ServeHTTP(w, req) return } - metadata, err := scheduler.WaitForCompletion(ctx, id) + + resp, err := client.GetWorkflowResult[distributedtx.KubeResp](ctx, workflowClient, id, distributedtx.DefaultWorkflowTimeout) if err != nil { fmt.Println(err) failed.ServeHTTP(w, req) @@ -102,14 +104,8 @@ func WithAuthorization(handler, failed http.Handler, permissionsClient v1.Permis })) close(allowed) - var resp distributedtx.KubeResp - if err := json.Unmarshal(metadata.SerializedOutput, &resp); err != nil { - fmt.Println(err) - failed.ServeHTTP(w, req) - return - } // this can happen if there are un-recoverable failures in the - // durable fn execution + // workflow execution if resp.Body == nil { failed.ServeHTTP(w, req) return diff --git a/pkg/proxy/distributedtx/activity.go b/pkg/proxy/distributedtx/activity.go new file mode 100644 index 0000000..4be8f2e --- /dev/null +++ b/pkg/proxy/distributedtx/activity.go @@ -0,0 +1,88 @@ +package distributedtx + +import ( + "context" + + v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/client-go/rest" + + "github.com/authzed/spicedb-kubeapi-proxy/pkg/failpoints" +) + +type KubeReqInput struct { + RequestInfo *request.RequestInfo + ObjectMeta *metav1.ObjectMeta + Body []byte +} + +type KubeResp struct { + Body []byte + ContentType string + StatusCode int + Err k8serrors.StatusError +} + +type ActivityHandler struct { + PermissionClient v1.PermissionsServiceClient + KubeClient rest.Interface +} + +// WriteToSpiceDB writes relationships to spicedb and returns any errors. +func (h *ActivityHandler) WriteToSpiceDB(ctx context.Context, input *v1.WriteRelationshipsRequest) (*v1.WriteRelationshipsResponse, error) { + failpoints.FailPoint("panicWriteSpiceDB") + out, err := h.PermissionClient.WriteRelationships(ctx, input) + failpoints.FailPoint("panicSpiceDBReadResp") + return out, err +} + +// WriteToKube performs a Kube API Server POST, specified in a KubeReqInput +func (h *ActivityHandler) WriteToKube(ctx context.Context, req *KubeReqInput) (*KubeResp, error) { + failpoints.FailPoint("panicKubeWrite") + + kreq := h.KubeClient.Post().RequestURI(req.RequestInfo.Path).Body(req.Body) + if len(req.RequestInfo.Namespace) > 0 { + kreq = kreq.Namespace(req.RequestInfo.Namespace) + } + + res := kreq.Do(ctx) + + failpoints.FailPoint("panicKubeReadResp") + + resp := KubeResp{} + body, err := res.Raw() + var nonKerr error + if kerr, ok := err.(*k8serrors.StatusError); ok { + resp.Err = *kerr + resp.StatusCode = int(kerr.Status().Code) + } else { + nonKerr = err + res.StatusCode(&resp.StatusCode) + } + + resp.Body = body + res.ContentType(&resp.ContentType) + + return &resp, nonKerr +} + +func (h *ActivityHandler) CheckKubeResource(ctx context.Context, req *KubeReqInput) (bool, error) { + // TODO: this is somewhat janky + uri := req.RequestInfo.Path + "/" + req.ObjectMeta.GetName() + res := h.KubeClient.Get().RequestURI(uri).Do(ctx) + err := res.Error() + if err == nil { + return true, nil // resource found + } + + if k8serrors.IsNotFound(err) { + return false, nil // resource does not exist + } + + return false, err // some other kube or network error; we can't tell +} + +// just used to be able to reference methods for activity invocations +var activityHandler ActivityHandler diff --git a/pkg/proxy/distributedtx/activity_test.go b/pkg/proxy/distributedtx/activity_test.go new file mode 100644 index 0000000..f35c84a --- /dev/null +++ b/pkg/proxy/distributedtx/activity_test.go @@ -0,0 +1,104 @@ +package distributedtx + +import ( + "bytes" + "context" + "io" + "net/http" + "testing" + + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/client-go/rest/fake" +) + +type testRoundTripper struct { + *testing.T + expectedPath string + status int +} + +func (trt testRoundTripper) roundtripper(request *http.Request) (*http.Response, error) { + require.Equal(trt, trt.expectedPath, request.URL.Path) + header := http.Header{} + header.Set("Content-Type", runtime.ContentTypeJSON) + if request.Body == nil { + request.Body = http.NoBody + } + body, err := io.ReadAll(request.Body) + if err != nil { + return nil, err + } + resp := &http.Response{ + Header: header, + StatusCode: trt.status, + Body: io.NopCloser(bytes.NewReader(body)), + } + return resp, nil +} + +func (trt testRoundTripper) toKubeClient() *fake.RESTClient { + return &fake.RESTClient{ + Client: fake.CreateHTTPClient(trt.roundtripper), + NegotiatedSerializer: &serializer.CodecFactory{}, + } +} + +func TestWriteToKube(t *testing.T) { + trt := testRoundTripper{T: t, expectedPath: "/my_way/namespaces/ns", status: http.StatusCreated} + ah := ActivityHandler{KubeClient: trt.toKubeClient()} + + resp, err := ah.WriteToKube(context.Background(), &KubeReqInput{ + RequestInfo: &request.RequestInfo{Path: "my_way", Namespace: "ns"}, + ObjectMeta: &metav1.ObjectMeta{Name: "my_object_meta"}, + Body: []byte(`{"hi":"bye"}`), + }) + + require.NoError(t, err) + require.Equal(t, `{"hi":"bye"}`, string(resp.Body)) + require.Equal(t, http.StatusCreated, resp.StatusCode) +} + +func TestWriteToKubeError(t *testing.T) { + trt := testRoundTripper{T: t, expectedPath: "/my_way/namespaces/ns", status: http.StatusInternalServerError} + ah := ActivityHandler{KubeClient: trt.toKubeClient()} + + resp, err := ah.WriteToKube(context.Background(), &KubeReqInput{ + RequestInfo: &request.RequestInfo{Path: "my_way", Namespace: "ns"}, + ObjectMeta: &metav1.ObjectMeta{Name: "my_object_meta"}, + Body: []byte(`{"hi":"bye"}`), + }) + + require.NoError(t, err) + require.Nil(t, resp.Body) + require.Error(t, &resp.Err) + require.Equal(t, http.StatusInternalServerError, resp.StatusCode) +} + +func TestCheckKubeResource(t *testing.T) { + trt := testRoundTripper{T: t, expectedPath: "/a_path/object_name", status: http.StatusOK} + ah := ActivityHandler{KubeClient: trt.toKubeClient()} + + exists, err := ah.CheckKubeResource(context.Background(), &KubeReqInput{ + RequestInfo: &request.RequestInfo{Path: "a_path", Namespace: "ns1"}, + ObjectMeta: &metav1.ObjectMeta{Name: "object_name"}, + }) + + require.NoError(t, err) + require.True(t, exists) +} + +func TestCheckKubeResourceError(t *testing.T) { + trt := testRoundTripper{T: t, expectedPath: "/a_path/object_name", status: http.StatusInternalServerError} + ah := ActivityHandler{KubeClient: trt.toKubeClient()} + + _, err := ah.CheckKubeResource(context.Background(), &KubeReqInput{ + RequestInfo: &request.RequestInfo{Path: "a_path", Namespace: "ns1"}, + ObjectMeta: &metav1.ObjectMeta{Name: "object_name"}, + }) + + require.Error(t, err) +} diff --git a/pkg/proxy/distributedtx/client.go b/pkg/proxy/distributedtx/client.go new file mode 100644 index 0000000..3369fa3 --- /dev/null +++ b/pkg/proxy/distributedtx/client.go @@ -0,0 +1,70 @@ +package distributedtx + +import ( + "context" + + v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" + "github.com/cschleiden/go-workflows/backend" + "github.com/cschleiden/go-workflows/backend/sqlite" + "github.com/cschleiden/go-workflows/client" + "github.com/cschleiden/go-workflows/worker" + "k8s.io/client-go/rest" + "k8s.io/klog/v2" +) + +func SetupWithMemoryBackend(ctx context.Context, permissionClient v1.PermissionsServiceClient, kubeClient rest.Interface) (client.Client, *Worker, error) { + ctx = klog.NewContext(ctx, klog.FromContext(ctx).WithValues("backend", "sqlite-memory")) + return SetupWithBackend(ctx, permissionClient, kubeClient, sqlite.NewInMemoryBackend()) +} + +func SetupWithSQLiteBackend(ctx context.Context, permissionClient v1.PermissionsServiceClient, kubeClient rest.Interface, sqlitePath string) (client.Client, *Worker, error) { + if sqlitePath == "" { + return SetupWithMemoryBackend(ctx, permissionClient, kubeClient) + } + + ctx = klog.NewContext(ctx, klog.FromContext(ctx).WithValues("backend", "sqlite-file")) + return SetupWithBackend(ctx, permissionClient, kubeClient, sqlite.NewSqliteBackend(sqlitePath)) +} + +func SetupWithBackend(ctx context.Context, permissionClient v1.PermissionsServiceClient, kubeClient rest.Interface, backend backend.Backend) (client.Client, *Worker, error) { + klog.FromContext(ctx).Info("starting workflow engine") + txHandler := ActivityHandler{ + PermissionClient: permissionClient, + KubeClient: kubeClient, + } + + w := worker.New(backend, &worker.DefaultWorkerOptions) + + if err := w.RegisterWorkflow(PessimisticWriteToSpiceDBAndKube); err != nil { + return nil, nil, err + } + if err := w.RegisterWorkflow(OptimisticWriteToSpiceDBAndKube); err != nil { + return nil, nil, err + } + if err := w.RegisterActivity(txHandler.WriteToKube); err != nil { + return nil, nil, err + } + if err := w.RegisterActivity(txHandler.CheckKubeResource); err != nil { + return nil, nil, err + } + if err := w.RegisterActivity(txHandler.WriteToSpiceDB); err != nil { + return nil, nil, err + } + + return client.New(backend), &Worker{worker: w}, nil +} + +type Worker struct { + worker worker.Worker + shutdownFunc func() +} + +func (w *Worker) Start(ctx context.Context) error { + ctx, w.shutdownFunc = context.WithCancel(ctx) + return w.worker.Start(ctx) +} + +func (w *Worker) Shutdown(_ context.Context) error { + w.shutdownFunc() + return w.worker.WaitForCompletion() +} diff --git a/pkg/proxy/distributedtx/tasks.go b/pkg/proxy/distributedtx/tasks.go deleted file mode 100644 index 1c6ed4a..0000000 --- a/pkg/proxy/distributedtx/tasks.go +++ /dev/null @@ -1,106 +0,0 @@ -package distributedtx - -import ( - "context" - - v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/client-go/rest" - - "github.com/authzed/spicedb-kubeapi-proxy/pkg/failpoints" -) - -type ExecutionInput interface { - GetInput(resultPtr any) error -} - -type ExecutionContext interface { - ExecutionInput - Context() context.Context -} - -type IdentifiableExecutionInput interface { - ExecutionInput - ID() string -} - -type CreateObjInput struct { - RequestInfo *request.RequestInfo - UserInfo *user.DefaultInfo - ObjectMeta *metav1.ObjectMeta - Body []byte -} - -type KubeReqInput struct { - RequestInfo *request.RequestInfo - ObjectMeta *metav1.ObjectMeta - Body []byte -} - -type KubeResp struct { - Body []byte - ContentType string - StatusCode int - Err k8serrors.StatusError -} - -type Handler struct { - PermissionClient v1.PermissionsServiceClient - KubeClient rest.Interface -} - -// WriteToSpiceDB writes relationships to spicedb and returns any errors. -func (h *Handler) WriteToSpiceDB(ctx ExecutionContext) (any, error) { - var req v1.WriteRelationshipsRequest - if err := ctx.GetInput(&req); err != nil { - return nil, err - } - failpoints.FailPoint("panicWriteSpiceDB") - out, err := h.PermissionClient.WriteRelationships(ctx.Context(), &req) - failpoints.FailPoint("panicSpiceDBReadResp") - return out, err -} - -// WriteToKube peforms a Kube API Server POST, specified in a KubeReqInput propagated via the task.ActivityContext arg -func (h *Handler) WriteToKube(ctx ExecutionContext) (any, error) { - var req KubeReqInput - if err := ctx.GetInput(&req); err != nil { - return nil, err - } - - failpoints.FailPoint("panicKubeWrite") - - kreq := h.KubeClient.Post(). - RequestURI(req.RequestInfo.Path). - Body(req.Body) - if len(req.RequestInfo.Namespace) > 0 { - kreq = kreq.Namespace(req.RequestInfo.Namespace) - } - res := kreq.Do(ctx.Context()) - - failpoints.FailPoint("panicKubeReadResp") - - resp := KubeResp{} - body, err := res.Raw() - if kerr, ok := err.(*k8serrors.StatusError); ok { - resp.Err = *kerr - } - resp.Body = body - res.StatusCode(&resp.StatusCode) - res.ContentType(&resp.ContentType) - return resp, nil -} - -func (h *Handler) CheckKube(ctx ExecutionContext) (any, error) { - var req KubeReqInput - if err := ctx.GetInput(&req); err != nil { - return nil, err - } - - // TODO: this is somewhat janky - res := h.KubeClient.Get().RequestURI(req.RequestInfo.Path + "/" + req.ObjectMeta.GetName()).Do(ctx.Context()) - return !k8serrors.IsNotFound(res.Error()), nil -} diff --git a/pkg/proxy/distributedtx/workflows.go b/pkg/proxy/distributedtx/workflow.go similarity index 58% rename from pkg/proxy/distributedtx/workflows.go rename to pkg/proxy/distributedtx/workflow.go index 7d98eb3..1402cd6 100644 --- a/pkg/proxy/distributedtx/workflows.go +++ b/pkg/proxy/distributedtx/workflow.go @@ -1,13 +1,16 @@ package distributedtx import ( - "context" "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apiserver/pkg/authentication/user" + "k8s.io/apiserver/pkg/endpoints/request" "net/http" "time" v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" "github.com/cespare/xxhash/v2" + "github.com/cschleiden/go-workflows/workflow" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/json" @@ -22,9 +25,7 @@ const ( DefaultLockMode = StrategyPessimisticWriteToSpiceDBAndKube StrategyOptimisticWriteToSpiceDBAndKube = "OptimisticWriteToSpiceDBAndKube" StrategyPessimisticWriteToSpiceDBAndKube = "PessimisticWriteToSpiceDBAndKube" - WriteToSpiceDB = "WriteToSpiceDBActivity" - WriteToKube = "WriteToKubeActivity" - CheckKube = "CheckKubeActivity" + DefaultWorkflowTimeout = time.Second * 30 ) var KubeBackoff = wait.Backoff{ @@ -34,22 +35,33 @@ var KubeBackoff = wait.Backoff{ Steps: MaxKubeAttempts, } -type TaskExecutor interface { - Call(name string, arg any) Task +type CreateObjInput struct { + RequestInfo *request.RequestInfo + UserInfo *user.DefaultInfo + ObjectMeta *metav1.ObjectMeta + Body []byte } -type TaskScheduler interface { - Schedule(ctx context.Context, orchestrator string, opts ...any) (string, error) - WaitForCompletion(ctx context.Context, id string) (*OrchestrationResult, error) -} +func (input *CreateObjInput) validate() error { + if input.UserInfo.GetName() == "" { + return fmt.Errorf("missing user info in CreateObjectInput") + } + + if input.ObjectMeta.Name == "" { + return fmt.Errorf("missing object meta in CreateObjectInput") + } + + // TODO more validation -type OrchestrationResult struct { - SerializedOutput []byte - Err string + return nil } -type Task interface { - Await(v any) error +func (input *CreateObjInput) toKubeReqInput() *KubeReqInput { + return &KubeReqInput{ + RequestInfo: input.RequestInfo, + ObjectMeta: input.ObjectMeta, + Body: input.Body, + } } type RollbackRelationships []*v1.Relationship @@ -64,7 +76,7 @@ func (r *RollbackRelationships) WithRels(relationships ...*v1.Relationship) *Rol return r } -func (r *RollbackRelationships) Cleanup(executor TaskExecutor) { +func (r *RollbackRelationships) Cleanup(ctx workflow.Context) { updates := make([]*v1.RelationshipUpdate, 0, len(*r)) for _, rel := range *r { rel := rel @@ -73,12 +85,14 @@ func (r *RollbackRelationships) Cleanup(executor TaskExecutor) { Relationship: rel, }) } - // TODO: Should this be a separate workflow? + for { - var delResp v1.WriteRelationshipsResponse - if err := executor.Call(WriteToSpiceDB, &v1.WriteRelationshipsRequest{ - Updates: updates, - }).Await(&delResp); err != nil { + f := workflow.ExecuteActivity[*v1.WriteRelationshipsResponse](ctx, + workflow.DefaultActivityOptions, + activityHandler.WriteToSpiceDB, + &v1.WriteRelationshipsRequest{Updates: updates}) + + if _, err := f.Get(ctx); err != nil { fmt.Println("error deleting lock tuple", err) continue } @@ -90,64 +104,48 @@ func (r *RollbackRelationships) Cleanup(executor TaskExecutor) { // PessimisticWriteToSpiceDBAndKube ensures that a write exists in both SpiceDB // and kube, or neither, using locks. It prevents multiple users from writing // the same object/fields at the same time -func PessimisticWriteToSpiceDBAndKube(ctx IdentifiableExecutionInput, executor TaskExecutor) (any, error) { - var input CreateObjInput - if err := ctx.GetInput(&input); err != nil { - return nil, err - } - - if err := validateInput(input); err != nil { +func PessimisticWriteToSpiceDBAndKube(ctx workflow.Context, input *CreateObjInput) (*KubeResp, error) { + if err := input.validate(); err != nil { return nil, fmt.Errorf("invalid input to PessimisticWriteToSpiceDBAndKube: %w", err) } + instance := workflow.WorkflowInstance(ctx) // this is hardcoded for namespaces for now; should be configurable and // come from the workflow input - spiceDBRelationship := SpiceDBNamespaceRel(input) - clusterRelationship := SpiceDBClusterRel(input) - lockTuple := LockRel(input, ctx.ID()) + resourceRel := SpiceDBNamespaceRel(input) + clusterRel := SpiceDBClusterRel(input) + resourceLockRel := ResourceLockRel(input, instance.InstanceID) // tuples to remove when the workflow is complete. // in some cases we will roll back the input, in all cases we remove // the lock when complete. - rollback := NewRollbackRelationships(lockTuple) - - var resp v1.WriteRelationshipsResponse - if err := executor.Call(WriteToSpiceDB, &v1.WriteRelationshipsRequest{ - OptionalPreconditions: []*v1.Precondition{{ - Operation: v1.Precondition_OPERATION_MUST_NOT_MATCH, - Filter: &v1.RelationshipFilter{ - ResourceType: lockResourceType, - OptionalResourceId: lockTuple.Resource.ObjectId, - OptionalRelation: lockRelationName, - OptionalSubjectFilter: &v1.SubjectFilter{SubjectType: workflowResourceType}, - }, - }, { - Operation: v1.Precondition_OPERATION_MUST_NOT_MATCH, - Filter: &v1.RelationshipFilter{ - ResourceType: clusterRelationship.Resource.ObjectType, - OptionalResourceId: clusterRelationship.Resource.ObjectId, - OptionalRelation: clusterRelationship.Relation, - OptionalSubjectFilter: &v1.SubjectFilter{ - SubjectType: clusterRelationship.Subject.Object.ObjectType, - OptionalSubjectId: clusterRelationship.Subject.Object.ObjectType, - }, - }, - }}, + rollback := NewRollbackRelationships(resourceLockRel) + + arg := &v1.WriteRelationshipsRequest{ + OptionalPreconditions: []*v1.Precondition{ + resourceLockDoesNotExist(resourceLockRel), + clusterLockDoesNotExist(clusterRel), + }, Updates: []*v1.RelationshipUpdate{{ Operation: v1.RelationshipUpdate_OPERATION_TOUCH, - Relationship: spiceDBRelationship, + Relationship: resourceRel, }, { Operation: v1.RelationshipUpdate_OPERATION_TOUCH, - Relationship: lockTuple, + Relationship: resourceLockRel, }, { Operation: v1.RelationshipUpdate_OPERATION_TOUCH, - Relationship: clusterRelationship, - }}, - }).Await(&resp); err != nil { + Relationship: clusterRel, + }}} + + _, err := workflow.ExecuteActivity[*v1.WriteRelationshipsResponse](ctx, + workflow.DefaultActivityOptions, + activityHandler.WriteToSpiceDB, + arg).Get(ctx) + if err != nil { // request failed for some reason fmt.Println("spicedb write failed", err) - rollback.WithRels(spiceDBRelationship, clusterRelationship).Cleanup(executor) + rollback.WithRels(resourceRel, clusterRel).Cleanup(ctx) // if the spicedb write fails, report it as a kube conflict error // we return this for any error, not just lock conflicts, so that the @@ -165,14 +163,13 @@ func PessimisticWriteToSpiceDBAndKube(ctx IdentifiableExecutionInput, executor T } for i := 0; i <= MaxKubeAttempts; i++ { // Attempt to write to kube - var out KubeResp - if err := executor.Call(WriteToKube, &KubeReqInput{ - RequestInfo: input.RequestInfo, - ObjectMeta: input.ObjectMeta, - Body: input.Body, - }).Await(&out); err != nil { + out, err := workflow.ExecuteActivity[*KubeResp](ctx, + workflow.DefaultActivityOptions, + activityHandler.WriteToKube, + input.toKubeReqInput()).Get(ctx) + if err != nil { // didn't get a response from kube, try again - fmt.Println("kube write failed", err, out) + fmt.Println("kube write failed", err) time.Sleep(backoff.Step()) continue } @@ -184,38 +181,26 @@ func PessimisticWriteToSpiceDBAndKube(ctx IdentifiableExecutionInput, executor T } if out.StatusCode == http.StatusConflict || out.StatusCode == http.StatusCreated { - rollback.Cleanup(executor) + rollback.Cleanup(ctx) return out, nil } // some other status code is some other type of error, remove // the original tuple and the lock tuple - rollback.WithRels(spiceDBRelationship, clusterRelationship).Cleanup(executor) + rollback.WithRels(resourceRel, clusterRel).Cleanup(ctx) return out, nil } - rollback.WithRels(spiceDBRelationship, clusterRelationship).Cleanup(executor) - return nil, fmt.Errorf("failed to communicate with kubernetes after %d attempts", MaxKubeAttempts) -} -func validateInput(input CreateObjInput) error { - if input.UserInfo.GetName() == "" { - return fmt.Errorf("missing user info in CreateObjectInput") - } - - if input.ObjectMeta.Name == "" { - return fmt.Errorf("missing object meta in CreateObjectInput") - } - - return nil + rollback.WithRels(resourceRel, clusterRel).Cleanup(ctx) + return nil, fmt.Errorf("failed to communicate with kubernetes after %d attempts", MaxKubeAttempts) } // OptimisticWriteToSpiceDBAndKube ensures that a write exists in both SpiceDB and kube, // or neither. It attempts to perform the writes and rolls back if errors are // encountered, leaving the user to retry on write conflicts. -func OptimisticWriteToSpiceDBAndKube(ctx IdentifiableExecutionInput, executor TaskExecutor) (any, error) { - var input CreateObjInput - if err := ctx.GetInput(&input); err != nil { - return nil, err +func OptimisticWriteToSpiceDBAndKube(ctx workflow.Context, input *CreateObjInput) (*KubeResp, error) { + if err := input.validate(); err != nil { + return nil, fmt.Errorf("invalid input to PessimisticWriteToSpiceDBAndKube: %w", err) } // TODO: this could optionally use dry-run to preflight the kube request @@ -226,8 +211,7 @@ func OptimisticWriteToSpiceDBAndKube(ctx IdentifiableExecutionInput, executor Ta clusterRelationship := SpiceDBClusterRel(input) rollback := NewRollbackRelationships(spiceDBRelationship, clusterRelationship) - var resp v1.WriteRelationshipsResponse - if err := executor.Call(WriteToSpiceDB, &v1.WriteRelationshipsRequest{ + arg := &v1.WriteRelationshipsRequest{ Updates: []*v1.RelationshipUpdate{{ Operation: v1.RelationshipUpdate_OPERATION_CREATE, Relationship: spiceDBRelationship, @@ -235,44 +219,47 @@ func OptimisticWriteToSpiceDBAndKube(ctx IdentifiableExecutionInput, executor Ta Operation: v1.RelationshipUpdate_OPERATION_CREATE, Relationship: clusterRelationship, }}, - }).Await(&resp); err != nil { - rollback.Cleanup(executor) - fmt.Println("WRITE ERR", err) + } + _, err := workflow.ExecuteActivity[*v1.WriteRelationshipsResponse](ctx, + workflow.DefaultActivityOptions, + activityHandler.WriteToSpiceDB, + arg).Get(ctx) + if err != nil { + rollback.Cleanup(ctx) + fmt.Println("SpiceDB WRITE ERR", err) // report spicedb write errors as conflicts return KubeConflict(err, input), nil } - var out KubeResp - if err := executor.Call(WriteToKube, &KubeReqInput{ - RequestInfo: input.RequestInfo, - ObjectMeta: input.ObjectMeta, - Body: input.Body, - }).Await(&out); err != nil { + out, err := workflow.ExecuteActivity[*KubeResp](ctx, + workflow.DefaultActivityOptions, + activityHandler.WriteToKube, + input.toKubeReqInput()).Get(ctx) + if err != nil { // if there's an error, might need to roll back the spicedb write - // check if object exists - we might have failed the write task but - // succeeded in writing to kube - var exists bool - if err := executor.Call(CheckKube, &KubeReqInput{ - RequestInfo: input.RequestInfo, - ObjectMeta: input.ObjectMeta, - Body: input.Body, - }).Await(&exists); err != nil { + // check if object exists - the activity may have failed, but the write to Kube could have succeeded + exists, err := workflow.ExecuteActivity[bool](ctx, + workflow.DefaultActivityOptions, + activityHandler.CheckKubeResource, + input.toKubeReqInput()).Get(ctx) + if err != nil { return nil, err } // if the object doesn't exist, clean up the spicedb write if !exists { - rollback.Cleanup(executor) + rollback.Cleanup(ctx) return nil, err } } + return out, nil } -// LockRel generates a relationship representing a worfklow's lock over a +// ResourceLockRel generates a relationship representing a worfklow's lock over a // specific resource in kube. -func LockRel(input CreateObjInput, id string) *v1.Relationship { +func ResourceLockRel(input *CreateObjInput, workflowID string) *v1.Relationship { lockKey := input.RequestInfo.Path + "/" + input.ObjectMeta.GetName() + "/" + input.RequestInfo.Verb lockHash := fmt.Sprintf("%x", xxhash.Sum64String(lockKey)) return &v1.Relationship{ @@ -284,7 +271,7 @@ func LockRel(input CreateObjInput, id string) *v1.Relationship { Subject: &v1.SubjectReference{ Object: &v1.ObjectReference{ ObjectType: workflowResourceType, - ObjectId: id, + ObjectId: workflowID, }, }, } @@ -293,7 +280,7 @@ func LockRel(input CreateObjInput, id string) *v1.Relationship { // SpiceDBNamespaceRel returns a tuple to write when creating a namespace. // This is hardcoded for namespaces for now; should be configurable and // come from the workflow input -func SpiceDBNamespaceRel(input CreateObjInput) *v1.Relationship { +func SpiceDBNamespaceRel(input *CreateObjInput) *v1.Relationship { return &v1.Relationship{ Resource: &v1.ObjectReference{ ObjectType: "namespace", @@ -312,7 +299,7 @@ func SpiceDBNamespaceRel(input CreateObjInput) *v1.Relationship { // SpiceDBClusterRel returns a tuple to write when creating a namespace. // This is hardcoded for namespaces for now; should be configurable and // come from the workflow input -func SpiceDBClusterRel(input CreateObjInput) *v1.Relationship { +func SpiceDBClusterRel(input *CreateObjInput) *v1.Relationship { return &v1.Relationship{ Resource: &v1.ObjectReference{ ObjectType: "namespace", @@ -330,7 +317,7 @@ func SpiceDBClusterRel(input CreateObjInput) *v1.Relationship { // KubeConflict wraps an error and turns it into a standard kube conflict // response. -func KubeConflict(err error, input CreateObjInput) KubeResp { +func KubeConflict(err error, input *CreateObjInput) *KubeResp { var out KubeResp statusError := k8serrors.NewConflict(schema.GroupResource{ Group: input.RequestInfo.APIGroup, @@ -339,5 +326,49 @@ func KubeConflict(err error, input CreateObjInput) KubeResp { out.StatusCode = http.StatusConflict out.Err = *statusError out.Body, _ = json.Marshal(statusError) - return out + return &out +} + +func resourceLockDoesNotExist(lockRel *v1.Relationship) *v1.Precondition { + return &v1.Precondition{ + Operation: v1.Precondition_OPERATION_MUST_NOT_MATCH, + Filter: &v1.RelationshipFilter{ + ResourceType: lockResourceType, + OptionalResourceId: lockRel.Resource.ObjectId, + OptionalRelation: lockRelationName, + OptionalSubjectFilter: &v1.SubjectFilter{SubjectType: workflowResourceType}, + }, + } +} + +func clusterLockDoesNotExist(clusterRelationship *v1.Relationship) *v1.Precondition { + return &v1.Precondition{ + Operation: v1.Precondition_OPERATION_MUST_NOT_MATCH, + Filter: &v1.RelationshipFilter{ + ResourceType: clusterRelationship.Resource.ObjectType, + OptionalResourceId: clusterRelationship.Resource.ObjectId, + OptionalRelation: clusterRelationship.Relation, + OptionalSubjectFilter: &v1.SubjectFilter{ + SubjectType: clusterRelationship.Subject.Object.ObjectType, + OptionalSubjectId: clusterRelationship.Subject.Object.ObjectType, + }, + }, + } +} + +func WorkflowForLockMode(lockMode string) (any, error) { + if lockMode == "" { + return nil, fmt.Errorf("lock mode is undefined") + } + + if !(lockMode == StrategyPessimisticWriteToSpiceDBAndKube || lockMode == StrategyOptimisticWriteToSpiceDBAndKube) { + return nil, fmt.Errorf("unexpected lock mode: %s", lockMode) + } + + f := PessimisticWriteToSpiceDBAndKube + if lockMode == StrategyOptimisticWriteToSpiceDBAndKube { + f = OptimisticWriteToSpiceDBAndKube + } + + return f, nil } diff --git a/pkg/proxy/distributedtx/workflow_test.go b/pkg/proxy/distributedtx/workflow_test.go new file mode 100644 index 0000000..fdfd157 --- /dev/null +++ b/pkg/proxy/distributedtx/workflow_test.go @@ -0,0 +1,106 @@ +package distributedtx + +import ( + "context" + "io" + "net/http" + "strings" + "testing" + + "github.com/authzed/spicedb-kubeapi-proxy/pkg/spicedb" + + v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" + "github.com/cschleiden/go-workflows/client" + "github.com/cschleiden/go-workflows/workflow" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apiserver/pkg/authentication/user" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/client-go/rest/fake" +) + +func TestWorkflow(t *testing.T) { + for name, workflowFunc := range map[string]func(ctx workflow.Context, input *CreateObjInput) (*KubeResp, error){ + StrategyPessimisticWriteToSpiceDBAndKube: PessimisticWriteToSpiceDBAndKube, + StrategyOptimisticWriteToSpiceDBAndKube: OptimisticWriteToSpiceDBAndKube, + } { + t.Run(name, func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + srv, err := spicedb.NewServer(ctx) + require.NoError(t, err) + go func() { + require.NoError(t, srv.Run(ctx)) + }() + + dialCtx, err := srv.GRPCDialContext(ctx) + require.NoError(t, err) + + psc := v1.NewPermissionsServiceClient(dialCtx) + + kubeClient := &fake.RESTClient{ + Client: fake.CreateHTTPClient(func(request *http.Request) (*http.Response, error) { + header := http.Header{} + header.Set("Content-Type", runtime.ContentTypeJSON) + resp := &http.Response{ + Header: header, + StatusCode: http.StatusCreated, + Body: io.NopCloser(strings.NewReader(`{"hi":"myfriend"}`)), + } + return resp, nil + }), + NegotiatedSerializer: &serializer.CodecFactory{}, + } + + require.NoError(t, err) + workflowClient, worker, err := SetupWithMemoryBackend(ctx, psc, kubeClient) + require.NoError(t, err) + require.NoError(t, worker.Start(ctx)) + defer func() { + require.NoError(t, worker.Shutdown(ctx)) + }() + + id, err := workflowClient.CreateWorkflowInstance(ctx, client.WorkflowInstanceOptions{ + InstanceID: uuid.NewString(), + }, workflowFunc, &CreateObjInput{ + RequestInfo: &request.RequestInfo{}, + UserInfo: &user.DefaultInfo{Name: "janedoe"}, + ObjectMeta: &metav1.ObjectMeta{Name: "my_object_meta"}, + Body: []byte("{}"), + }) + require.NoError(t, err) + + resp, err := client.GetWorkflowResult[KubeResp](ctx, workflowClient, id, DefaultWorkflowTimeout) + require.NoError(t, err) + require.NotNil(t, resp) + require.Empty(t, resp.Err, "workflow returned error: %s", resp.Err) + require.Equal(t, `{"hi":"myfriend"}`, string(resp.Body)) + require.Equal(t, http.StatusCreated, resp.StatusCode) + require.Equal(t, runtime.ContentTypeJSON, resp.ContentType) + + cpr, err := psc.CheckPermission(ctx, &v1.CheckPermissionRequest{ + Consistency: &v1.Consistency{ + Requirement: &v1.Consistency_FullyConsistent{FullyConsistent: true}, + }, + Resource: &v1.ObjectReference{ + ObjectType: "namespace", + ObjectId: "my_object_meta", + }, + Permission: "view", + Subject: &v1.SubjectReference{ + Object: &v1.ObjectReference{ + ObjectType: "user", + ObjectId: "janedoe", + }, + }, + }) + require.NoError(t, err) + require.Equal(t, v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION, cpr.Permissionship) + }) + } + +} diff --git a/pkg/proxy/durabletask/durabletask.go b/pkg/proxy/durabletask/durabletask.go deleted file mode 100644 index 0792710..0000000 --- a/pkg/proxy/durabletask/durabletask.go +++ /dev/null @@ -1,131 +0,0 @@ -package durabletask - -import ( - "context" - - "github.com/authzed/spicedb-kubeapi-proxy/pkg/proxy/distributedtx" - - v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" - "github.com/microsoft/durabletask-go/api" - "github.com/microsoft/durabletask-go/backend" - "github.com/microsoft/durabletask-go/backend/sqlite" - "github.com/microsoft/durabletask-go/task" - "k8s.io/client-go/rest" -) - -const MemorySQLite = "" - -type TaskWorker interface { - Start(context.Context) error - Shutdown(context.Context) error -} - -func Setup(permissionClient v1.PermissionsServiceClient, kubeClient rest.Interface, sqlitePath string) (distributedtx.TaskScheduler, TaskWorker, error) { - h := TaskHandler{distributedtx.Handler{PermissionClient: permissionClient, KubeClient: kubeClient}} - - // durabletask - stores planned dual writes in a sqlite db - logger := backend.DefaultLogger() - r := task.NewTaskRegistry() - if err := r.AddOrchestratorN(distributedtx.StrategyPessimisticWriteToSpiceDBAndKube, PessimisticWriteToSpiceDBAndKube); err != nil { - return nil, nil, err - } - if err := r.AddOrchestratorN(distributedtx.StrategyOptimisticWriteToSpiceDBAndKube, OptimisticWriteToSpiceDBAndKube); err != nil { - return nil, nil, err - } - if err := r.AddActivityN(distributedtx.WriteToSpiceDB, h.WriteToSpiceDB); err != nil { - return nil, nil, err - } - if err := r.AddActivityN(distributedtx.WriteToKube, h.WriteToKube); err != nil { - return nil, nil, err - } - if err := r.AddActivityN(distributedtx.CheckKube, h.CheckKube); err != nil { - return nil, nil, err - } - - // note: can use the in-memory sqlite provider by specifying "" - be := sqlite.NewSqliteBackend(sqlite.NewSqliteOptions(sqlitePath), logger) - executor := task.NewTaskExecutor(r) - orchestrationWorker := backend.NewOrchestrationWorker(be, executor, logger) - activityWorker := backend.NewActivityTaskWorker(be, executor, logger) - worker := backend.NewTaskHubWorker(be, orchestrationWorker, activityWorker, logger) - - taskScheduler := TaskScheduler{ - taskHubClient: backend.NewTaskHubClient(be), - } - return taskScheduler, worker, nil -} - -func PessimisticWriteToSpiceDBAndKube(ctx *task.OrchestrationContext) (any, error) { - ec := ExecutionContext{ctx: ctx} - return distributedtx.PessimisticWriteToSpiceDBAndKube(ec, ec) -} - -func OptimisticWriteToSpiceDBAndKube(ctx *task.OrchestrationContext) (any, error) { - ec := ExecutionContext{ctx: ctx} - return distributedtx.OptimisticWriteToSpiceDBAndKube(ec, ec) -} - -type ExecutionContext struct { - ctx *task.OrchestrationContext -} - -func (e ExecutionContext) Call(name string, arg any) distributedtx.Task { - return e.ctx.CallActivity(name, task.WithActivityInput(arg)) -} - -func (e ExecutionContext) GetInput(resultPtr any) error { - return e.ctx.GetInput(resultPtr) -} - -func (e ExecutionContext) ID() string { - return string(e.ctx.ID) -} - -type TaskScheduler struct { - taskHubClient backend.TaskHubClient -} - -func (t TaskScheduler) Schedule(ctx context.Context, orchestrator string, opts ...any) (string, error) { - var orchestrationOpts []api.NewOrchestrationOptions - for _, opt := range opts { - orchestrationOpts = append(orchestrationOpts, api.WithInput(opt)) - } - - instanceID, err := t.taskHubClient.ScheduleNewOrchestration(ctx, orchestrator, orchestrationOpts...) - if err != nil { - return string(instanceID), err - } - - return string(instanceID), nil -} - -func (t TaskScheduler) WaitForCompletion(ctx context.Context, id string) (*distributedtx.OrchestrationResult, error) { - metadata, err := t.taskHubClient.WaitForOrchestrationCompletion(ctx, api.InstanceID(id)) - if err != nil { - return nil, err - } - var errMsg string - if metadata.FailureDetails != nil { - errMsg = metadata.FailureDetails.ErrorMessage - } - return &distributedtx.OrchestrationResult{ - SerializedOutput: []byte(metadata.SerializedOutput), - Err: errMsg, - }, nil -} - -type TaskHandler struct { - distributedtx.Handler -} - -func (th TaskHandler) WriteToSpiceDB(ctx task.ActivityContext) (any, error) { - return th.Handler.WriteToSpiceDB(ctx) -} - -func (th TaskHandler) WriteToKube(ctx task.ActivityContext) (any, error) { - return th.Handler.WriteToKube(ctx) -} - -func (th TaskHandler) CheckKube(ctx task.ActivityContext) (any, error) { - return th.Handler.CheckKube(ctx) -} diff --git a/pkg/proxy/durabletask/durabletask_test.go b/pkg/proxy/durabletask/durabletask_test.go deleted file mode 100644 index 9010a33..0000000 --- a/pkg/proxy/durabletask/durabletask_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package durabletask - -import ( - "context" - "io" - "net/http" - "strings" - "testing" - - "github.com/authzed/spicedb-kubeapi-proxy/pkg/proxy/distributedtx" - "github.com/authzed/spicedb-kubeapi-proxy/pkg/spicedb" - - v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/client-go/rest/fake" -) - -func TestDurableTask(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - srv, err := spicedb.NewServer(ctx) - require.NoError(t, err) - go func() { - require.NoError(t, srv.Run(ctx)) - }() - - dialCtx, err := srv.GRPCDialContext(ctx) - require.NoError(t, err) - - psc := v1.NewPermissionsServiceClient(dialCtx) - - kubeClient := &fake.RESTClient{ - Client: fake.CreateHTTPClient(func(request *http.Request) (*http.Response, error) { - header := http.Header{} - header.Set("Content-Type", runtime.ContentTypeJSON) - resp := &http.Response{ - Header: header, - StatusCode: http.StatusCreated, - Body: io.NopCloser(strings.NewReader("{}")), - } - return resp, nil - }), - NegotiatedSerializer: &serializer.CodecFactory{}, - } - - scheduler, worker, err := Setup(psc, kubeClient, MemorySQLite) - require.NoError(t, err) - require.NoError(t, worker.Start(ctx)) - defer func() { - require.NoError(t, worker.Shutdown(ctx)) - }() - - id, err := scheduler.Schedule(ctx, distributedtx.DefaultLockMode, &distributedtx.CreateObjInput{ - RequestInfo: &request.RequestInfo{}, - UserInfo: &user.DefaultInfo{Name: "janedoe"}, - ObjectMeta: &metav1.ObjectMeta{Name: "my_object_meta"}, - Body: []byte("{}"), - }) - require.NoError(t, err) - - metadata, err := scheduler.WaitForCompletion(ctx, id) - require.NoError(t, err) - require.Empty(t, metadata.Err, "workflow returned error: %s", metadata.Err) - - resp, err := psc.CheckPermission(ctx, &v1.CheckPermissionRequest{ - Consistency: &v1.Consistency{ - Requirement: &v1.Consistency_FullyConsistent{FullyConsistent: true}, - }, - Resource: &v1.ObjectReference{ - ObjectType: "namespace", - ObjectId: "my_object_meta", - }, - Permission: "view", - Subject: &v1.SubjectReference{ - Object: &v1.ObjectReference{ - ObjectType: "user", - ObjectId: "janedoe", - }, - }, - }) - require.NoError(t, err) - require.Equal(t, v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION, resp.Permissionship) -} diff --git a/pkg/proxy/options.go b/pkg/proxy/options.go index bc76f2b..29e870e 100644 --- a/pkg/proxy/options.go +++ b/pkg/proxy/options.go @@ -29,8 +29,9 @@ import ( ) const ( - defaultDurableTaskDatabasePath = "/tmp/dtx.sqlite" - EmbeddedSpiceDBEndpoint = "embedded://" + defaultWorkflowDatabasePath = "/tmp/dtx.sqlite" + EmbeddedSpiceDBEndpoint = "embedded://" + defaultDialerTimeout = 5 * time.Second ) type Options struct { @@ -55,8 +56,8 @@ type Options struct { skipVerifyCA bool token string - DurableTaskDatabasePath string - LockMode string + WorkflowDatabasePath string + LockMode string } func NewOptions() *Options { @@ -75,7 +76,7 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { o.SecureServing.AddFlags(fs) o.Authentication.AddFlags(fs) logsv1.AddFlags(o.Logs, fs) - fs.StringVar(&o.DurableTaskDatabasePath, "durabletask-database-path", defaultDurableTaskDatabasePath, "Path for the file representing the SQLite database used for the durable task engine.") + fs.StringVar(&o.WorkflowDatabasePath, "workflow-database-path", defaultWorkflowDatabasePath, "Path for the file representing the SQLite database used for the workflow engine.") fs.StringVar(&o.BackendKubeconfigPath, "backend-kubeconfig", o.BackendKubeconfigPath, "The path to the kubeconfig to proxy connections to. It should authenticate the user with cluster-admin permission.") fs.StringVar(&o.SpiceDBEndpoint, "spicedb-endpoint", "localhost:50051", "Defines the endpoint endpoint to the SpiceDB authorizing proxy operations. if embedded:// is specified, an in memory ephemeral instance created.") fs.BoolVar(&o.insecure, "spicedb-insecure", false, "If set to true uses the insecure transport configuration for gRPC. Set to false by default.") @@ -165,7 +166,7 @@ func (o *Options) Complete(ctx context.Context) error { } opts = append(opts, grpc.WithConnectParams(grpc.ConnectParams{Backoff: backoff.DefaultConfig})) - timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + timeoutCtx, cancel := context.WithTimeout(ctx, defaultDialerTimeout) defer cancel() conn, err = grpc.DialContext(timeoutCtx, o.SpiceDBEndpoint, opts...) if err != nil { diff --git a/pkg/proxy/server.go b/pkg/proxy/server.go index c35c78d..9372cf7 100644 --- a/pkg/proxy/server.go +++ b/pkg/proxy/server.go @@ -11,7 +11,6 @@ import ( "time" "github.com/authzed/spicedb-kubeapi-proxy/pkg/proxy/distributedtx" - "github.com/authzed/spicedb-kubeapi-proxy/pkg/proxy/durabletask" v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -31,10 +30,10 @@ import ( ) type Server struct { - opts Options - Handler http.Handler - TaskWorker durabletask.TaskWorker - KubeClient *kubernetes.Clientset + opts Options + Handler http.Handler + WorkflowWorker *distributedtx.Worker + KubeClient *kubernetes.Clientset // LockMode references the name of the workflow to run for dual writes // This is very temporary, and should be replaced with per-request @@ -42,15 +41,12 @@ type Server struct { LockMode string } -var defaultDistributedTransactionProvider = durabletask.Setup - func NewServer(ctx context.Context, o Options) (*Server, error) { s := &Server{ opts: o, LockMode: distributedtx.DefaultLockMode, } - klog.FromContext(ctx).Info("starting durable task engine") restConfig, err := clientcmd.NewDefaultClientConfig(*s.opts.BackendConfig, nil).ClientConfig() if err != nil { return nil, err @@ -112,13 +108,16 @@ func NewServer(ctx context.Context, o Options) (*Server, error) { codecs := serializer.NewCodecFactory(scheme) failHandler := genericapifilters.Unauthorized(codecs) - scheduler, worker, err := defaultDistributedTransactionProvider(s.opts.PermissionsClient, s.KubeClient.RESTClient(), durabletask.MemorySQLite) + workflowClient, worker, err := distributedtx.SetupWithSQLiteBackend(ctx, + s.opts.PermissionsClient, + s.KubeClient.RESTClient(), + o.WorkflowDatabasePath) if err != nil { return nil, fmt.Errorf("failed to initialize distributed transaction handling: %w", err) } - s.TaskWorker = worker + s.WorkflowWorker = worker - handler, err := WithAuthorization(clusterProxy, failHandler, o.PermissionsClient, o.WatchClient, scheduler, &s.LockMode) + handler, err := WithAuthorization(clusterProxy, failHandler, o.PermissionsClient, o.WatchClient, workflowClient, &s.LockMode) if err != nil { return nil, fmt.Errorf("unable to create authorization handler: %w", err) } @@ -156,12 +155,12 @@ func (s *Server) Run(ctx context.Context) error { } go func() { - if err := s.TaskWorker.Start(ctx); err != nil { - klog.FromContext(ctx).Error(err, "failed to run durable task worker") + if err := s.WorkflowWorker.Start(ctx); err != nil { + klog.FromContext(ctx).Error(err, "failed to run workflow worker") cancel() return } - klog.FromContext(ctx).Info("task hub worker started") + klog.FromContext(ctx).Info("workflow worker started") }() doneCh, _, err := s.opts.ServingInfo.Serve(s.Handler, time.Second*60, ctx.Done()) if err != nil { @@ -172,7 +171,7 @@ func (s *Server) Run(ctx context.Context) error { ctx, cancel = context.WithTimeout(context.Background(), 1*time.Minute) defer cancel() - if err := s.TaskWorker.Shutdown(ctx); err != nil { + if err := s.WorkflowWorker.Shutdown(ctx); err != nil { return err } return nil