From 90ac4b169c069aa4232019657196355c660be8ec Mon Sep 17 00:00:00 2001 From: William Gill Date: Fri, 17 Apr 2026 09:18:49 -0500 Subject: [PATCH] =?UTF-8?q?ci:=20fix=20first=20CI=20run=20=E2=80=94=20tidy?= =?UTF-8?q?,=20gofmt,=20ordering=20test,=20govulncheck=20pin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ids: TestIDsAreTimeOrdered asserted strict lexicographic ordering of back-to-back UUIDv7s, but the sub-ms tail is random and not required to be monotonic. Sleep between samples so each ID lands in a distinct millisecond — the property that actually gives Postgres index locality on (org_id, id desc). - go.mod/go.sum: run go mod tidy. keyfunc/v3, prometheus/client_golang and testcontainers-go/modules/postgres are imported directly and should not be marked // indirect; also drops stale sum entries. - gofmt -w across 12 files flagged by the lint job. - security.yml: pin govulncheck to v1.2.0. @latest triggers a proxy lookup every run, which is the step that hung for 16m on the Gitea runner. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitea/workflows/security.yml | 5 ++- go.mod | 6 ++-- go.sum | 42 ++++++++++++++----------- internal/app/anchorage/app.go | 10 +++--- internal/app/anchorage/nodeid.go | 2 -- internal/pkg/auth/oidc_test.go | 1 - internal/pkg/ids/ids_test.go | 13 +++++--- internal/pkg/ipfs/rpc/client.go | 4 +-- internal/pkg/openapi/admin.go | 4 +-- internal/pkg/openapi/session.go | 1 - internal/pkg/openapi/tokens.go | 6 ++-- internal/pkg/scheduler/rebalance.go | 2 +- internal/pkg/store/memstore/memstore.go | 18 ++++++----- internal/pkg/store/postgres/store.go | 12 +++---- internal/pkg/store/store.go | 30 +++++++++--------- internal/pkg/wsserver/hub.go | 4 +-- 16 files changed, 85 insertions(+), 75 deletions(-) diff --git a/.gitea/workflows/security.yml b/.gitea/workflows/security.yml index 437a9f8..f71326e 100644 --- a/.gitea/workflows/security.yml +++ b/.gitea/workflows/security.yml @@ -19,7 +19,10 @@ jobs: go-version: '1.26' - name: Install govulncheck - run: go install golang.org/x/vuln/cmd/govulncheck@latest + # Pinned rather than @latest: @latest forces a proxy lookup every + # run, which is the step that hung for 16m on the Gitea runner. + # Bump this line when a new govulncheck release is wanted. + run: go install golang.org/x/vuln/cmd/govulncheck@v1.2.0 - name: Run govulncheck run: govulncheck ./... diff --git a/go.mod b/go.mod index 5b8f5ec..c024554 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module anchorage go 1.26.2 require ( + github.com/MicahParks/keyfunc/v3 v3.8.0 github.com/danielgtaylor/huma/v2 v2.37.3 github.com/dgraph-io/ristretto/v2 v2.4.0 github.com/gofiber/contrib/websocket v1.3.4 @@ -12,8 +13,10 @@ require ( github.com/jackc/pgx/v5 v5.9.1 github.com/nats-io/nats-server/v2 v2.12.7 github.com/nats-io/nats.go v1.51.0 + github.com/prometheus/client_golang v1.23.2 github.com/spf13/cobra v1.10.2 github.com/spf13/viper v1.21.0 + github.com/testcontainers/testcontainers-go/modules/postgres v0.42.0 github.com/zeebo/xxh3 v1.1.0 go.jetify.com/typeid v1.3.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 @@ -23,7 +26,6 @@ require ( dario.cat/mergo v1.0.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/MicahParks/jwkset v0.11.0 // indirect - github.com/MicahParks/keyfunc/v3 v3.8.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/antithesishq/antithesis-sdk-go v0.6.0-default-no-op // indirect @@ -84,7 +86,6 @@ require ( github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.66.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect @@ -99,7 +100,6 @@ require ( github.com/stretchr/testify v1.11.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/testcontainers/testcontainers-go v0.42.0 // indirect - github.com/testcontainers/testcontainers-go/modules/postgres v0.42.0 // indirect github.com/tinylib/msgp v1.2.5 // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/numcpus v0.11.0 // indirect diff --git a/go.sum b/go.sum index 3c365cc..0d2372a 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= -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/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/MicahParks/jwkset v0.11.0 h1:yc0zG+jCvZpWgFDFmvs8/8jqqVBG9oyIbmBtmjOhoyQ= @@ -33,6 +33,8 @@ github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7np github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/danielgtaylor/huma/v2 v2.37.3 h1:6Av0Vj45Vk5lDxRVfoO2iPlEdvCvwLc7pl5nbqGOkYM= github.com/danielgtaylor/huma/v2 v2.37.3/go.mod h1:OeHHtCEAaNiuVbAVdYu4IQ0UOmnb4x3yMUOShNlZ53g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -48,8 +50,6 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -90,8 +90,8 @@ github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArs github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -114,6 +114,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -126,6 +128,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ= github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= +github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 h1:KGuD/pM2JpL9FAYvBrnBBeENKZNh6eNtjqytV6TYjnk= github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= @@ -144,8 +148,6 @@ github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= -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/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -164,8 +166,6 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 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 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= @@ -212,6 +212,8 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -244,24 +246,22 @@ github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= go.jetify.com/typeid v1.3.0 h1:fuWV7oxO4mSsgpxwhaVpFXgt0IfjogR29p+XAjDCVKY= go.jetify.com/typeid v1.3.0/go.mod h1:CtVGyt2+TSp4Rq5+ARLvGsJqdNypKBAC6INQ9TLPlmk= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c= go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ= go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0= go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= @@ -279,6 +279,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= @@ -296,3 +298,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= +pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= diff --git a/internal/app/anchorage/app.go b/internal/app/anchorage/app.go index de9b3f8..acb7858 100644 --- a/internal/app/anchorage/app.go +++ b/internal/app/anchorage/app.go @@ -25,16 +25,16 @@ import ( "anchorage/internal/pkg/ipfs/rpc" "anchorage/internal/pkg/leader" "anchorage/internal/pkg/logging" - "anchorage/internal/pkg/metrics" "anchorage/internal/pkg/maintenance" + "anchorage/internal/pkg/metrics" embeddednats "anchorage/internal/pkg/nats" - "anchorage/internal/pkg/store/postgres" "anchorage/internal/pkg/node" "anchorage/internal/pkg/openapi" "anchorage/internal/pkg/pin" "anchorage/internal/pkg/scheduler" "anchorage/internal/pkg/store" "anchorage/internal/pkg/store/memstore" + "anchorage/internal/pkg/store/postgres" "anchorage/internal/pkg/token" "anchorage/internal/pkg/wsserver" ) @@ -72,7 +72,6 @@ type App struct { // have returned. The leader-gated workers are tracked separately // via leaderWG. lifecycleWG sync.WaitGroup - } // New builds the full app from a config.Config. @@ -102,8 +101,8 @@ func New(ctx context.Context, cfg *config.Config) (*App, error) { // A missing DSN is a valid dev-mode choice; production operators // must set one. var ( - s store.Store - pgPool *pgxpool.Pool + s store.Store + pgPool *pgxpool.Pool ) if cfg.Postgres.DSN != "" { pool, err := postgres.NewPool(ctx, postgres.PoolConfig{ @@ -558,4 +557,3 @@ func (a *App) Close(ctx context.Context) { a.PGPool.Close() } } - diff --git a/internal/app/anchorage/nodeid.go b/internal/app/anchorage/nodeid.go index dc214c2..dc35f26 100644 --- a/internal/app/anchorage/nodeid.go +++ b/internal/app/anchorage/nodeid.go @@ -11,7 +11,6 @@ import ( "anchorage/internal/pkg/ids" ) - // resolveStableNodeID returns the node's TypeID, loading it from // StateDir/node.id on disk if present, otherwise generating a fresh one // and persisting it. This keeps the cluster identity stable across @@ -59,4 +58,3 @@ func resolveStableNodeID(rawID, stateDir string) (nodeID ids.NodeID, displayName slog.Info("anchorage: generated stable node id", "node_id", id.String(), "path", path) return id, displayName, nil } - diff --git a/internal/pkg/auth/oidc_test.go b/internal/pkg/auth/oidc_test.go index 266d111..9bee013 100644 --- a/internal/pkg/auth/oidc_test.go +++ b/internal/pkg/auth/oidc_test.go @@ -224,4 +224,3 @@ func TestDisplayNameFallbacks(t *testing.T) { } } } - diff --git a/internal/pkg/ids/ids_test.go b/internal/pkg/ids/ids_test.go index a2a64dd..28e421a 100644 --- a/internal/pkg/ids/ids_test.go +++ b/internal/pkg/ids/ids_test.go @@ -3,6 +3,7 @@ package ids_test import ( "strings" "testing" + "time" "anchorage/internal/pkg/ids" ) @@ -93,11 +94,15 @@ func TestIDsAreUniquePerCall(t *testing.T) { } func TestIDsAreTimeOrdered(t *testing.T) { - // UUIDv7 is time-ordered, so later-generated IDs should sort after - // earlier ones lexicographically. This is the property that gives - // Postgres index locality on (org_id, id desc). + // UUIDv7 is time-ordered at millisecond granularity; the sub-ms + // tail is random and not required to be monotonic, so back-to-back + // calls in the same millisecond can sort in either direction. The + // property we actually rely on for Postgres index locality on + // (org_id, id desc) is that IDs separated by >=1ms sort in + // generation order — so sleep between samples. prev := ids.MustNewPin().String() - for i := 0; i < 32; i++ { + for i := 0; i < 8; i++ { + time.Sleep(2 * time.Millisecond) next := ids.MustNewPin().String() if next <= prev { t.Fatalf("UUIDv7 ordering violated: %q followed %q", next, prev) diff --git a/internal/pkg/ipfs/rpc/client.go b/internal/pkg/ipfs/rpc/client.go index 1b45338..94ce211 100644 --- a/internal/pkg/ipfs/rpc/client.go +++ b/internal/pkg/ipfs/rpc/client.go @@ -21,8 +21,8 @@ import ( // Client is a Kubo RPC client. type Client struct { - base *url.URL - hc *http.Client + base *url.URL + hc *http.Client } // Options configures a Client. diff --git a/internal/pkg/openapi/admin.go b/internal/pkg/openapi/admin.go index 12686e2..e28d734 100644 --- a/internal/pkg/openapi/admin.go +++ b/internal/pkg/openapi/admin.go @@ -369,8 +369,8 @@ func RegisterAdmin(api huma.API, deps AdminDeps) { } type rebalanceResp struct { Body struct { - Applied bool `json:"applied"` - Moves []scheduler.PlannedMove `json:"moves"` + Applied bool `json:"applied"` + Moves []scheduler.PlannedMove `json:"moves"` } } huma.Register(api, huma.Operation{ diff --git a/internal/pkg/openapi/session.go b/internal/pkg/openapi/session.go index d317026..892c201 100644 --- a/internal/pkg/openapi/session.go +++ b/internal/pkg/openapi/session.go @@ -303,4 +303,3 @@ func userBody(u *store.User) userBodyT { IsSysadmin: u.IsSysadmin, } } - diff --git a/internal/pkg/openapi/tokens.go b/internal/pkg/openapi/tokens.go index 28fd548..a72b79a 100644 --- a/internal/pkg/openapi/tokens.go +++ b/internal/pkg/openapi/tokens.go @@ -36,9 +36,9 @@ func RegisterTokens(api huma.API, deps TokenDeps) { Security: []map[string][]string{{"accessToken": {}}}, }, func(ctx context.Context, in *struct { Body struct { - Label string `json:"label" minLength:"1" maxLength:"128"` - Scopes []string `json:"scopes,omitempty"` - TTLHours int `json:"ttl_hours,omitempty" minimum:"1"` + Label string `json:"label" minLength:"1" maxLength:"128"` + Scopes []string `json:"scopes,omitempty"` + TTLHours int `json:"ttl_hours,omitempty" minimum:"1"` } }) (*struct { Body struct { diff --git a/internal/pkg/scheduler/rebalance.go b/internal/pkg/scheduler/rebalance.go index eeed8fe..1be47cf 100644 --- a/internal/pkg/scheduler/rebalance.go +++ b/internal/pkg/scheduler/rebalance.go @@ -20,7 +20,7 @@ type PlannedMove struct { RequestID string `json:"request_id"` FromNode string `json:"from_node"` ToNode string `json:"to_node"` - Reason string `json:"reason"` // "down" | "drain" + Reason string `json:"reason"` // "down" | "drain" NewFence int64 `json:"new_fence,omitempty"` // populated after apply } diff --git a/internal/pkg/store/memstore/memstore.go b/internal/pkg/store/memstore/memstore.go index 114d756..7c53470 100644 --- a/internal/pkg/store/memstore/memstore.go +++ b/internal/pkg/store/memstore/memstore.go @@ -56,14 +56,16 @@ func New() *Store { // ---- store.Store root ----------------------------------------------------- -func (s *Store) Orgs() store.OrgStore { return orgStore{s} } -func (s *Store) Users() store.UserStore { return userStore{s} } -func (s *Store) Memberships() store.MembershipStore { return memStore{s} } -func (s *Store) Tokens() store.TokenStore { return tokenStore{s} } -func (s *Store) Nodes() store.NodeStore { return nodeStore{s} } -func (s *Store) Pins() store.PinStore { return pinStore{s} } -func (s *Store) Audit() store.AuditStore { return auditStore{s} } -func (s *Store) WithOrgContext(ctx context.Context, _ ids.OrgID) (context.Context, error) { return ctx, nil } +func (s *Store) Orgs() store.OrgStore { return orgStore{s} } +func (s *Store) Users() store.UserStore { return userStore{s} } +func (s *Store) Memberships() store.MembershipStore { return memStore{s} } +func (s *Store) Tokens() store.TokenStore { return tokenStore{s} } +func (s *Store) Nodes() store.NodeStore { return nodeStore{s} } +func (s *Store) Pins() store.PinStore { return pinStore{s} } +func (s *Store) Audit() store.AuditStore { return auditStore{s} } +func (s *Store) WithOrgContext(ctx context.Context, _ ids.OrgID) (context.Context, error) { + return ctx, nil +} // Tx in a memstore is a no-op — the same Store is passed back and the // context is forwarded unchanged. Real Postgres implementations open a diff --git a/internal/pkg/store/postgres/store.go b/internal/pkg/store/postgres/store.go index e9433c3..ad5e1cd 100644 --- a/internal/pkg/store/postgres/store.go +++ b/internal/pkg/store/postgres/store.go @@ -737,13 +737,13 @@ func (a auditStore) List(ctx context.Context, orgID ids.OrgID, limit, offset int out := []*store.AuditEntry{} for rows.Next() { var ( - id int64 - org ids.OrgID - actorUser ids.UserID - actorTokenJti *string + id int64 + org ids.OrgID + actorUser ids.UserID + actorTokenJti *string action, target, result string - detail []byte - created pgtype.Timestamptz + detail []byte + created pgtype.Timestamptz ) if err := rows.Scan(&id, &org, &actorUser, &actorTokenJti, &action, &target, &result, &detail, &created); err != nil { return nil, err diff --git a/internal/pkg/store/store.go b/internal/pkg/store/store.go index ac1327b..5ee7013 100644 --- a/internal/pkg/store/store.go +++ b/internal/pkg/store/store.go @@ -88,12 +88,12 @@ type UserStore interface { // Membership pairs a user with an org + role. type Membership struct { - OrgID ids.OrgID - UserID ids.UserID - Role string // "orgadmin" | "member" - OrgSlug string // populated by List*, empty on raw gets - OrgName string - Created time.Time + OrgID ids.OrgID + UserID ids.UserID + Role string // "orgadmin" | "member" + OrgSlug string // populated by List*, empty on raw gets + OrgName string + Created time.Time } // Role constants. @@ -217,15 +217,15 @@ type Placement struct { // Before and After are both inclusive of their endpoint semantics: // `after <= created < before`. type PinFilter struct { - CIDs []string - Name string - Match string - Status []string - Before *time.Time - After *time.Time - Meta map[string]any - Limit int - Offset int + CIDs []string + Name string + Match string + Status []string + Before *time.Time + After *time.Time + Meta map[string]any + Limit int + Offset int } // PinStore manages pins and their placements + refcounts. diff --git a/internal/pkg/wsserver/hub.go b/internal/pkg/wsserver/hub.go index 98623ba..d53a94c 100644 --- a/internal/pkg/wsserver/hub.go +++ b/internal/pkg/wsserver/hub.go @@ -22,8 +22,8 @@ import ( type Hub struct { nc *nats.Conn - mu sync.Mutex - conns map[*websocket.Conn]*clientFilter + mu sync.Mutex + conns map[*websocket.Conn]*clientFilter } type clientFilter struct {